diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7c3964cbe5..0ec34cb736 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,18 +1,34 @@ - + + ./tests/ ./tests/Bootstrap.php + + src/ diff --git a/src/Annotations/EnumType.php b/src/Annotations/EnumType.php index 77f624bd6e..e83431fbaf 100644 --- a/src/Annotations/EnumType.php +++ b/src/Annotations/EnumType.php @@ -20,11 +20,8 @@ #[Attribute(Attribute::TARGET_CLASS)] class EnumType { - /** @var string|null */ - private $name; - - /** @var bool */ - private $useValues; + private string|null $name; + private bool $useValues; /** @param mixed[] $attributes */ public function __construct(array $attributes = [], string|null $name = null, bool|null $useValues = null) diff --git a/src/Annotations/ExtendType.php b/src/Annotations/ExtendType.php index 609c141138..55831b23ea 100644 --- a/src/Annotations/ExtendType.php +++ b/src/Annotations/ExtendType.php @@ -19,13 +19,15 @@ class ExtendType { /** @var class-string|null */ - private $class; - /** @var string|null */ - private $name; + private string|null $class; + private string|null $name; /** @param mixed[] $attributes */ - public function __construct(array $attributes = [], string|null $class = null, string|null $name = null) - { + public function __construct( + array $attributes = [], + string|null $class = null, + string|null $name = null, + ) { $className = isset($attributes['class']) ? ltrim($attributes['class'], '\\') : null; $className = $className ?? $class; if ($className !== null && ! class_exists($className) && ! interface_exists($className)) { diff --git a/src/Annotations/Factory.php b/src/Annotations/Factory.php index 9d617e4744..6032d8dddb 100644 --- a/src/Annotations/Factory.php +++ b/src/Annotations/Factory.php @@ -13,10 +13,8 @@ #[Attribute(Attribute::TARGET_METHOD)] class Factory { - /** @var string|null */ - private $name; - /** @var bool */ - private $default; + private string|null $name; + private bool $default; /** @param mixed[] $attributes */ public function __construct(array $attributes = [], string|null $name = null, bool|null $default = null) diff --git a/src/Annotations/FailWith.php b/src/Annotations/FailWith.php index 9e87eb0d80..b647908ae2 100644 --- a/src/Annotations/FailWith.php +++ b/src/Annotations/FailWith.php @@ -15,10 +15,8 @@ class FailWith implements MiddlewareAnnotationInterface { /** * The default value to use if the right is not enforced. - * - * @var mixed */ - private $value; + private mixed $value; /** @throws BadMethodCallException */ public function __construct(mixed $values = [], mixed $value = '__fail__with__magic__key__') diff --git a/src/Annotations/Field.php b/src/Annotations/Field.php index 12712bd6e8..82044c5d29 100644 --- a/src/Annotations/Field.php +++ b/src/Annotations/Field.php @@ -13,28 +13,31 @@ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] class Field extends AbstractRequest { - /** @var string|null */ - private $prefetchMethod; + private string|null $prefetchMethod; /** * Input/Output type names for which this fields should be applied to. * * @var string[]|null */ - private $for = null; + private array|null $for = null; - /** @var string|null */ - private $description; - - /** @var string|null */ - private $inputType; + private string|null $description; + private string|null $inputType; /** * @param mixed[] $attributes * @param string|string[] $for */ - public function __construct(array $attributes = [], string|null $name = null, string|null $outputType = null, string|null $prefetchMethod = null, string|array|null $for = null, string|null $description = null, string|null $inputType = null) - { + public function __construct( + array $attributes = [], + string|null $name = null, + string|null $outputType = null, + string|null $prefetchMethod = null, + string|array|null $for = null, + string|null $description = null, + string|null $inputType = null, + ) { parent::__construct($attributes, $name, $outputType); $this->prefetchMethod = $prefetchMethod ?? $attributes['prefetchMethod'] ?? null; diff --git a/src/Annotations/MagicField.php b/src/Annotations/MagicField.php index 650143ff2e..306bddd92c 100644 --- a/src/Annotations/MagicField.php +++ b/src/Annotations/MagicField.php @@ -16,44 +16,56 @@ #[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] class MagicField implements SourceFieldInterface { - /** @var string */ - private $name; + private string $name; + private string|null $outputType; + private string|null $phpType; + private string|null $description; + private string|null $sourceName; - /** @var string|null */ - private $outputType; - - /** @var string|null */ - private $phpType; - - /** @var string|null */ - private $description; - - /** @var string|null */ - private $sourceName; - - /** @var MiddlewareAnnotations */ - private $middlewareAnnotations; + private MiddlewareAnnotations $middlewareAnnotations; /** @var array */ - private $parameterAnnotations; + private array $parameterAnnotations; /** * @param mixed[] $attributes * @param array $annotations */ - public function __construct(array $attributes = [], string|null $name = null, string|null $outputType = null, string|null $phpType = null, string|null $description = null, string|null $sourceName = null, array $annotations = []) - { - $this->name = $attributes['name'] ?? $name; + public function __construct( + array $attributes = [], + string|null $name = null, + string|null $outputType = null, + string|null $phpType = null, + string|null $description = null, + string|null $sourceName = null, + array $annotations = [], + ) { + $name = $attributes['name'] ?? $name; + if (! $name) { + throw new BadMethodCallException( + 'The #[MagicField] attribute must be passed a name. For instance: #[MagicField(name: "phone")]', + ); + } + + $this->name = $name; $this->outputType = $attributes['outputType'] ?? $outputType ?? null; $this->phpType = $attributes['phpType'] ?? $phpType ?? null; $this->description = $attributes['description'] ?? $description ?? null; $this->sourceName = $attributes['sourceName'] ?? $sourceName ?? null; - if (! $this->name || (! $this->outputType && ! $this->phpType)) { - throw new BadMethodCallException('The #[MagicField] attribute must be passed a name and an output type or a php type. For instance: "#[MagicField(name: \'phone\', outputType: \'String!\')]" or "#[MagicField(name: \'phone\', phpType: \'string\')]"'); + if (! $this->outputType && ! $this->phpType) { + throw new BadMethodCallException( + "The #[MagicField] attribute must be passed an output type or a php type. + For instance: #[MagicField(name: 'phone', outputType: 'String!')] + or #[MagicField(name: 'phone', phpType: 'string')]", + ); } if (isset($this->outputType) && $this->phpType) { - throw new BadMethodCallException('In a #[MagicField] attribute, you cannot use the outputType and the phpType at the same time. For instance: "#[MagicField(name: \'phone\', outputType: \'String!\')]" or "#[MagicField(name: \'phone\', phpType: \'string\')]"'); + throw new BadMethodCallException( + "In a #[MagicField] attribute, you cannot use the outputType and the phpType at the + same time. For instance: #[MagicField(name: 'phone', outputType: 'String!')] + or #[MagicField(name: 'phone', phpType: 'string')]", + ); } $middlewareAnnotations = []; $parameterAnnotations = []; @@ -67,13 +79,18 @@ public function __construct(array $attributes = [], string|null $name = null, st } elseif ($annotation instanceof ParameterAnnotationInterface) { $parameterAnnotations[$annotation->getTarget()][] = $annotation; } else { - throw new BadMethodCallException('The #[MagicField] attribute\'s "annotations" attribute must be passed an array of annotations implementing either MiddlewareAnnotationInterface or ParameterAnnotationInterface."'); + throw new BadMethodCallException( + "The #[MagicField] attribute's 'annotation' attribute must be passed an array + of annotations implementing either MiddlewareAnnotationInterface or + ParameterAnnotationInterface.", + ); } } $this->middlewareAnnotations = new MiddlewareAnnotations($middlewareAnnotations); - $this->parameterAnnotations = array_map(static function (array $parameterAnnotationsForAttribute): ParameterAnnotations { - return new ParameterAnnotations($parameterAnnotationsForAttribute); - }, $parameterAnnotations); + $this->parameterAnnotations = array_map( + static fn (array $parameterAnnotationsForAttribute): ParameterAnnotations => new ParameterAnnotations($parameterAnnotationsForAttribute), + $parameterAnnotations, + ); } /** diff --git a/src/Annotations/Right.php b/src/Annotations/Right.php index d14597a326..63f5a5b380 100644 --- a/src/Annotations/Right.php +++ b/src/Annotations/Right.php @@ -12,8 +12,7 @@ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] class Right implements MiddlewareAnnotationInterface { - /** @var string */ - private $name; + private string $name; /** * @param array|string $name diff --git a/src/Annotations/Security.php b/src/Annotations/Security.php index 6e334e3e45..13db0c93db 100644 --- a/src/Annotations/Security.php +++ b/src/Annotations/Security.php @@ -13,33 +13,35 @@ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] class Security implements MiddlewareAnnotationInterface { - /** @var string */ - private $expression; - /** @var mixed */ - private $failWith; - /** @var bool */ - private $failWithIsSet = false; - /** @var int */ - private $statusCode; - /** @var string */ - private $message; + private string $expression; + private mixed $failWith; + private bool $failWithIsSet = false; + private int $statusCode; + private string $message; /** * @param array|string $data data array managed by the Doctrine Annotations library or the expression * * @throws BadMethodCallException */ - public function __construct(array|string $data = [], string|null $expression = null, mixed $failWith = '__fail__with__magic__key__', string|null $message = null, int|null $statusCode = null) - { + public function __construct( + array|string $data = [], + string|null $expression = null, + mixed $failWith = '__fail__with__magic__key__', + string|null $message = null, + int|null $statusCode = null, + ) { if (is_string($data)) { $data = ['expression' => $data]; } - $this->expression = $data['value'] ?? $data['expression'] ?? $expression; - if (! $this->expression) { + $expression = $data['value'] ?? $data['expression'] ?? $expression; + if (! $expression) { throw new BadMethodCallException('The #[Security] attribute must be passed an expression. For instance: "#[Security("is_granted(\'CAN_EDIT_STUFF\')")]"'); } + $this->expression = $expression; + if (array_key_exists('failWith', $data)) { $this->failWith = $data['failWith']; $this->failWithIsSet = true; diff --git a/tests/AnnotationReaderTest.php b/tests/AnnotationReaderTest.php index f7493dead9..36e1a1f220 100644 --- a/tests/AnnotationReaderTest.php +++ b/tests/AnnotationReaderTest.php @@ -9,15 +9,12 @@ use ReflectionMethod; use TheCodingMachine\GraphQLite\Annotations\Autowire; use TheCodingMachine\GraphQLite\Annotations\Exceptions\ClassNotFoundException; -use TheCodingMachine\GraphQLite\Annotations\Exceptions\InvalidParameterException; use TheCodingMachine\GraphQLite\Annotations\Field; use TheCodingMachine\GraphQLite\Annotations\Security; use TheCodingMachine\GraphQLite\Annotations\Type; use TheCodingMachine\GraphQLite\Fixtures\Annotations\ClassWithInvalidClassAnnotation; use TheCodingMachine\GraphQLite\Fixtures\Annotations\ClassWithInvalidExtendTypeAnnotation; use TheCodingMachine\GraphQLite\Fixtures\Annotations\ClassWithInvalidTypeAnnotation; -use TheCodingMachine\GraphQLite\Fixtures\Annotations\ClassWithTargetMethodParameterAnnotation; -use TheCodingMachine\GraphQLite\Fixtures\Annotations\TargetMethodParameterAnnotation; use TheCodingMachine\GraphQLite\Fixtures\Attributes\TestType; class AnnotationReaderTest extends TestCase @@ -26,7 +23,10 @@ public function testBadAnnotation(): void { $annotationReader = new AnnotationReader(); - $type = $annotationReader->getTypeAnnotation(new ReflectionClass(ClassWithInvalidClassAnnotation::class)); + $type = $annotationReader->getTypeAnnotation( + new ReflectionClass(ClassWithInvalidClassAnnotation::class), + ); + $this->assertNull($type); } @@ -34,14 +34,20 @@ public function testSmellyAnnotation(): void { $annotationReader = new AnnotationReader(); - $this->assertNull($annotationReader->getTypeAnnotation(new ReflectionClass(ClassWithInvalidTypeAnnotation::class))); + $this->assertNull($annotationReader->getTypeAnnotation( + new ReflectionClass(ClassWithInvalidTypeAnnotation::class)), + ); } public function testGetAnnotationsWithBadAnnotation(): void { $annotationReader = new AnnotationReader(); - $types = $annotationReader->getClassAnnotations(new ReflectionClass(ClassWithInvalidClassAnnotation::class), Type::class); + $types = $annotationReader->getClassAnnotations( + new ReflectionClass(ClassWithInvalidClassAnnotation::class), + Type::class, + ); + $this->assertSame([], $types); } @@ -49,7 +55,10 @@ public function testMethodWithBadAnnotation(): void { $annotationReader = new AnnotationReader(); - $type = $annotationReader->getRequestAnnotation(new ReflectionMethod(ClassWithInvalidClassAnnotation::class, 'testMethod'), Field::class); + $type = $annotationReader->getRequestAnnotation( + new ReflectionMethod(ClassWithInvalidClassAnnotation::class, 'testMethod'), + Field::class, + ); $this->assertNull($type); } @@ -59,14 +68,20 @@ public function testExtendAnnotationException(): void $this->expectException(ClassNotFoundException::class); $this->expectExceptionMessage("Could not autoload class 'foo' defined in #[ExtendType] attribute of class 'TheCodingMachine\GraphQLite\Fixtures\Annotations\ClassWithInvalidExtendTypeAnnotation'"); - $annotationReader->getExtendTypeAnnotation(new ReflectionClass(ClassWithInvalidExtendTypeAnnotation::class)); + $annotationReader->getExtendTypeAnnotation( + new ReflectionClass(ClassWithInvalidExtendTypeAnnotation::class), + ); } public function testMethodsWithBadAnnotation(): void { $annotationReader = new AnnotationReader(); - $type = $annotationReader->getMethodAnnotations(new ReflectionMethod(ClassWithInvalidClassAnnotation::class, 'testMethod'), Field::class); + $type = $annotationReader->getMethodAnnotations( + new ReflectionMethod(ClassWithInvalidClassAnnotation::class, 'testMethod'), + Field::class, + ); + $this->assertSame([], $type); } @@ -102,7 +117,11 @@ public function testPhp8AttributeMethodAnnotation(): void { $annotationReader = new AnnotationReader(); - $type = $annotationReader->getRequestAnnotation(new ReflectionMethod(TestType::class, 'getField'), Field::class); + $type = $annotationReader->getRequestAnnotation( + new ReflectionMethod(TestType::class, 'getField'), + Field::class, + ); + $this->assertInstanceOf(Field::class, $type); } @@ -110,7 +129,9 @@ public function testPhp8AttributeMethodAnnotations(): void { $annotationReader = new AnnotationReader(); - $middlewareAnnotations = $annotationReader->getMiddlewareAnnotations(new ReflectionMethod(TestType::class, 'getField')); + $middlewareAnnotations = $annotationReader->getMiddlewareAnnotations( + new ReflectionMethod(TestType::class, 'getField'), + ); /** @var Security[] $securitys */ $securitys = $middlewareAnnotations->getAnnotationsByType(Security::class); @@ -124,34 +145,14 @@ public function testPhp8AttributeParameterAnnotations(): void { $annotationReader = new AnnotationReader(); - $parameterAnnotations = $annotationReader->getParameterAnnotationsPerParameter((new ReflectionMethod(self::class, 'method1'))->getParameters()); - - $this->assertInstanceOf(Autowire::class, $parameterAnnotations['dao']->getAnnotationByType(Autowire::class)); - } - - /** - * This functionality can be dropped with next major release (8.0) with added explicit deprecations before release. - */ - public function testPhp8AttributeParameterAnnotationsForTargetMethod(): void - { - $annotationReader = new AnnotationReader(); - - $parameterAnnotations = $annotationReader->getParameterAnnotationsPerParameter((new ReflectionMethod(ClassWithTargetMethodParameterAnnotation::class, 'method'))->getParameters()); - - $this->assertInstanceOf(TargetMethodParameterAnnotation::class, $parameterAnnotations['bar']->getAnnotationByType(TargetMethodParameterAnnotation::class)); - } - - /** - * This functionality can be dropped with next major release (8.0) with added explicit deprecations before release. - */ - public function testPhp8AttributeParameterAnnotationsForTargetMethodWithInvalidTargetParameter(): void - { - $annotationReader = new AnnotationReader(); - - $this->expectException(InvalidParameterException::class); - $this->expectExceptionMessage('Parameter "unexistent" declared in annotation "TheCodingMachine\GraphQLite\Fixtures\Annotations\TargetMethodParameterAnnotation" of method "TheCodingMachine\GraphQLite\Fixtures\Annotations\ClassWithTargetMethodParameterAnnotation::methodWithInvalidAnnotation()" does not exist.'); + $parameterAnnotations = $annotationReader->getParameterAnnotationsPerParameter( + (new ReflectionMethod(self::class, 'method1'))->getParameters(), + ); - $annotationReader->getParameterAnnotationsPerParameter((new ReflectionMethod(ClassWithTargetMethodParameterAnnotation::class, 'methodWithInvalidAnnotation'))->getParameters()); + $this->assertInstanceOf( + Autowire::class, + $parameterAnnotations['dao']->getAnnotationByType(Autowire::class), + ); } /** @noinspection PhpUnusedPrivateMethodInspection Used in {@see testPhp8AttributeParameterAnnotations} */ diff --git a/tests/Annotations/SecurityTest.php b/tests/Annotations/SecurityTest.php index a35275092f..3f82ae129d 100644 --- a/tests/Annotations/SecurityTest.php +++ b/tests/Annotations/SecurityTest.php @@ -4,8 +4,6 @@ use BadMethodCallException; use PHPUnit\Framework\TestCase; -use stdClass; -use TypeError; class SecurityTest extends TestCase { diff --git a/tests/Fixtures/Annotations/ClassWithTargetMethodParameterAnnotation.php b/tests/Fixtures/Annotations/ClassWithTargetMethodParameterAnnotation.php deleted file mode 100644 index 6830f2bbdf..0000000000 --- a/tests/Fixtures/Annotations/ClassWithTargetMethodParameterAnnotation.php +++ /dev/null @@ -1,21 +0,0 @@ -target; - } -}