diff --git a/composer.json b/composer.json index e482e16693..5f89d4d2be 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,6 @@ "require": { "php": ">=8.1", "ext-json": "*", - "doctrine/annotations": "^1.14 || ^2.0", "composer/package-versions-deprecated": "^1.8", "phpdocumentor/reflection-docblock": "^4.3 || ^5.0", "phpdocumentor/type-resolver": "^1.4", diff --git a/src/AnnotationReader.php b/src/AnnotationReader.php index a65d15ac10..e5aacbe39f 100644 --- a/src/AnnotationReader.php +++ b/src/AnnotationReader.php @@ -4,14 +4,10 @@ namespace TheCodingMachine\GraphQLite; -use Doctrine\Common\Annotations\AnnotationException; -use Doctrine\Common\Annotations\Reader; -use InvalidArgumentException; use ReflectionClass; use ReflectionMethod; use ReflectionParameter; use ReflectionProperty; -use RuntimeException; use TheCodingMachine\GraphQLite\Annotations\AbstractRequest; use TheCodingMachine\GraphQLite\Annotations\Decorate; use TheCodingMachine\GraphQLite\Annotations\EnumType; @@ -33,27 +29,14 @@ use function array_key_exists; use function array_map; use function array_merge; -use function array_values; use function assert; use function count; use function get_class; -use function in_array; use function is_a; use function reset; -use function str_contains; -use function str_starts_with; -use function strrpos; -use function substr; class AnnotationReader { - // In this mode, no exceptions will be thrown for incorrect annotations (unless the name of the annotation we are looking for is part of the docblock) - public const LAX_MODE = 'LAX_MODE'; - - // In this mode, exceptions will be thrown for any incorrect annotations. - public const STRICT_MODE = 'STRICT_MODE'; - - /** @var array */ private array $methodAnnotationCache = []; @@ -63,15 +46,8 @@ class AnnotationReader /** @var array> */ private array $propertyAnnotationsCache = []; - /** - * @param string $mode One of self::LAX_MODE or self::STRICT_MODE. If true, no exceptions will be thrown for incorrect annotations in code coming from the "vendor/" directory. - * @param array $strictNamespaces Classes in those namespaces MUST have valid annotations (otherwise, an error is thrown). - */ - public function __construct(private readonly Reader $reader, private readonly string $mode = self::STRICT_MODE, private readonly array $strictNamespaces = []) + public function __construct() { - if (! in_array($mode, [self::LAX_MODE, self::STRICT_MODE], true)) { - throw new InvalidArgumentException('The mode passed must be one of AnnotationReader::LAX_MODE, AnnotationReader::STRICT_MODE'); - } } /** @@ -82,38 +58,26 @@ public function __construct(private readonly Reader $reader, private readonly st * * @return T|null * - * @throws AnnotationException * @throws ClassNotFoundException * * @template T of object */ private function getClassAnnotation(ReflectionClass $refClass, string $annotationClass): object|null { - try { - $attribute = $refClass->getAttributes($annotationClass)[0] ?? null; - if ($attribute) { - $instance = $attribute->newInstance(); - assert($instance instanceof $annotationClass); - return $instance; - } - $type = $this->reader->getClassAnnotation($refClass, $annotationClass); - assert($type === null || $type instanceof $annotationClass); - return $type; - } catch (AnnotationException $e) { - return match ($this->mode) { - self::STRICT_MODE=> throw $e, - self::LAX_MODE=>$this->isErrorImportant($annotationClass, $refClass->getDocComment() ?: '', $refClass->getName()) ? throw $e : null, - default=>throw new RuntimeException("Unexpected mode '" . $this->mode . "'.") // @codeCoverageIgnore - }; + $attribute = $refClass->getAttributes($annotationClass)[0] ?? null; + if ($attribute) { + $instance = $attribute->newInstance(); + assert($instance instanceof $annotationClass); + return $instance; } + + return null; } /** * Returns a method annotation and handles correctly errors. * * @param class-string $annotationClass - * - * @throws AnnotationException */ private function getMethodAnnotation(ReflectionMethod $refMethod, string $annotationClass): object|null { @@ -122,35 +86,12 @@ private function getMethodAnnotation(ReflectionMethod $refMethod, string $annota return $this->methodAnnotationCache[$cacheKey]; } - try { - $attribute = $refMethod->getAttributes($annotationClass)[0] ?? null; - if ($attribute) { - return $this->methodAnnotationCache[$cacheKey] = $attribute->newInstance(); - } - - return $this->methodAnnotationCache[$cacheKey] = $this->reader->getMethodAnnotation($refMethod, $annotationClass); - } catch (AnnotationException $e) { - return match ($this->mode) { - self::STRICT_MODE=> throw $e, - self::LAX_MODE=>$this->isErrorImportant($annotationClass, $refMethod->getDocComment() ?: '', $refMethod->getName()) ? throw $e : null, - default=>throw new RuntimeException("Unexpected mode '" . $this->mode . "'.") // @codeCoverageIgnore - }; + $attribute = $refMethod->getAttributes($annotationClass)[0] ?? null; + if ($attribute) { + return $this->methodAnnotationCache[$cacheKey] = $attribute->newInstance(); } - } - /** - * Returns true if the annotation class name is part of the docblock comment. - */ - private function isErrorImportant(string $annotationClass, string $docComment, string $className): bool - { - foreach ($this->strictNamespaces as $strictNamespace) { - if (str_starts_with($className, $strictNamespace)) { - return true; - } - } - $shortAnnotationClass = substr($annotationClass, strrpos($annotationClass, '\\') + 1); - - return str_contains($docComment, '@' . $shortAnnotationClass); + return $this->methodAnnotationCache[$cacheKey] = null; } /** @@ -161,8 +102,6 @@ private function isErrorImportant(string $annotationClass, string $docComment, s * * @return A[] * - * @throws AnnotationException - * * @template T of object * @template A of object */ @@ -170,39 +109,21 @@ public function getClassAnnotations(ReflectionClass $refClass, string $annotatio { $toAddAnnotations = []; do { - try { - $allAnnotations = $this->reader->getClassAnnotations($refClass); - $toAddAnnotations[] = array_filter($allAnnotations, static function ($annotation) use ($annotationClass): bool { - return $annotation instanceof $annotationClass; - }); - - /** @var A[] $attributes */ - $attributes = array_map( - static function ($attribute) { - return $attribute->newInstance(); - }, - array_filter($refClass->getAttributes(), static function ($annotation) use ($annotationClass): bool { - return is_a($annotation->getName(), $annotationClass, true); - }), - ); - - $toAddAnnotations[] = $attributes; - } catch (AnnotationException $e) { - if ($this->mode === self::STRICT_MODE) { - throw $e; - } - - if ( - ($this->mode === self::LAX_MODE) - && $this->isErrorImportant($annotationClass, $refClass->getDocComment() ?: '', $refClass->getName()) - ) { - throw $e; - } - } + /** @var A[] $attributes */ + $attributes = array_map( + static function ($attribute) { + return $attribute->newInstance(); + }, + array_filter($refClass->getAttributes(), static function ($annotation) use ($annotationClass): bool { + return is_a($annotation->getName(), $annotationClass, true); + }), + ); + + $toAddAnnotations[] = $attributes; $refClass = $refClass->getParentClass(); } while ($inherited && $refClass); - if (! empty($toAddAnnotations)) { + if (count($toAddAnnotations) > 0) { return array_merge(...$toAddAnnotations); } @@ -212,6 +133,8 @@ static function ($attribute) { /** * @param ReflectionClass $refClass * + * @throws ClassNotFoundException + * * @template T of object */ public function getTypeAnnotation(ReflectionClass $refClass): TypeInterface|null @@ -234,7 +157,7 @@ public function getTypeAnnotation(ReflectionClass $refClass): TypeInterface|null * * @return array * - * @throws AnnotationException + * @throws ClassNotFoundException * * @template T of object */ @@ -256,6 +179,8 @@ public function getInputAnnotations(ReflectionClass $refClass): array /** * @param ReflectionClass $refClass * + * @throws ClassNotFoundException + * * @template T of object */ public function getExtendTypeAnnotation(ReflectionClass $refClass): ExtendType|null @@ -314,34 +239,12 @@ public function getDecorateAnnotation(ReflectionMethod $refMethod): Decorate|nul return $decorateAnnotation; } - /** - * Only used in unit tests/ - * - * @deprecated Use getParameterAnnotationsPerParameter instead - * - * @throws AnnotationException - */ - public function getParameterAnnotations(ReflectionParameter $refParameter): ParameterAnnotations - { - $method = $refParameter->getDeclaringFunction(); - assert($method instanceof ReflectionMethod); - /** @var ParameterAnnotationInterface[] $parameterAnnotations */ - $parameterAnnotations = $this->getMethodAnnotations($method, ParameterAnnotationInterface::class); - $name = $refParameter->getName(); - - $filteredAnnotations = array_values(array_filter($parameterAnnotations, static function (ParameterAnnotationInterface $parameterAnnotation) use ($name) { - return $parameterAnnotation->getTarget() === $name; - })); - - return new ParameterAnnotations($filteredAnnotations); - } - /** * @param ReflectionParameter[] $refParameters * * @return array * - * @throws AnnotationException + * @throws InvalidParameterException */ public function getParameterAnnotationsPerParameter(array $refParameters): array { @@ -398,7 +301,6 @@ static function (array $parameterAnnotations): ParameterAnnotations { ); } - /** @throws AnnotationException */ public function getMiddlewareAnnotations(ReflectionMethod|ReflectionProperty $reflection): MiddlewareAnnotations { if ($reflection instanceof ReflectionMethod) { @@ -417,47 +319,31 @@ public function getMiddlewareAnnotations(ReflectionMethod|ReflectionProperty $re * * @return array * - * @throws AnnotationException - * * @template T of object */ public function getMethodAnnotations(ReflectionMethod $refMethod, string $annotationClass): array { $cacheKey = $refMethod->getDeclaringClass()->getName() . '::' . $refMethod->getName() . '_s_' . $annotationClass; if (isset($this->methodAnnotationsCache[$cacheKey])) { - return $this->methodAnnotationsCache[$cacheKey]; - } - - $toAddAnnotations = []; - try { - $allAnnotations = $this->reader->getMethodAnnotations($refMethod); - $toAddAnnotations = array_filter($allAnnotations, static function ($annotation) use ($annotationClass): bool { - return $annotation instanceof $annotationClass; - }); - $attributes = $refMethod->getAttributes(); - $toAddAnnotations = [ - ...$toAddAnnotations, - ...array_map( - static function ($attribute) { - return $attribute->newInstance(); - }, - array_filter($attributes, static function ($annotation) use ($annotationClass): bool { - return is_a($annotation->getName(), $annotationClass, true); - }), - ), - ]; - } catch (AnnotationException $e) { - if ($this->mode === self::STRICT_MODE) { - throw $e; - } + /** @var array $annotations */ + $annotations = $this->methodAnnotationsCache[$cacheKey]; - if ($this->mode === self::LAX_MODE) { - if ($this->isErrorImportant($annotationClass, $refMethod->getDocComment() ?: '', $refMethod->getDeclaringClass()->getName())) { - throw $e; - } - } + return $annotations; } + $attributes = $refMethod->getAttributes(); + /** @var array $toAddAnnotations */ + $toAddAnnotations = [ + ...array_map( + static function ($attribute) { + return $attribute->newInstance(); + }, + array_filter($attributes, static function ($annotation) use ($annotationClass): bool { + return is_a($annotation->getName(), $annotationClass, true); + }), + ), + ]; + $this->methodAnnotationsCache[$cacheKey] = $toAddAnnotations; return $toAddAnnotations; @@ -470,8 +356,6 @@ static function ($attribute) { * * @return array * - * @throws AnnotationException - * * @template T of object */ public function getPropertyAnnotations(ReflectionProperty $refProperty, string $annotationClass): array @@ -484,35 +368,18 @@ public function getPropertyAnnotations(ReflectionProperty $refProperty, string $ return $annotations; } - $toAddAnnotations = []; - try { - $allAnnotations = $this->reader->getPropertyAnnotations($refProperty); - $toAddAnnotations = array_filter($allAnnotations, static function ($annotation) use ($annotationClass): bool { - return $annotation instanceof $annotationClass; - }); - $attributes = $refProperty->getAttributes(); - $toAddAnnotations = [ - ...$toAddAnnotations, - ...array_map( - static function ($attribute) { - return $attribute->newInstance(); - }, - array_filter($attributes, static function ($annotation) use ($annotationClass): bool { - return is_a($annotation->getName(), $annotationClass, true); - }), - ), - ]; - } catch (AnnotationException $e) { - if ($this->mode === self::STRICT_MODE) { - throw $e; - } - - if ($this->mode === self::LAX_MODE) { - if ($this->isErrorImportant($annotationClass, $refProperty->getDocComment() ?: '', $refProperty->getDeclaringClass()->getName())) { - throw $e; - } - } - } + $attributes = $refProperty->getAttributes(); + /** @var array $toAddAnnotations */ + $toAddAnnotations = [ + ...array_map( + static function ($attribute) { + return $attribute->newInstance(); + }, + array_filter($attributes, static function ($annotation) use ($annotationClass): bool { + return is_a($annotation->getName(), $annotationClass, true); + }), + ), + ]; $this->propertyAnnotationsCache[$cacheKey] = $toAddAnnotations; diff --git a/src/Annotations/Autowire.php b/src/Annotations/Autowire.php index 5974b96a6d..554b44f4ab 100644 --- a/src/Annotations/Autowire.php +++ b/src/Annotations/Autowire.php @@ -11,33 +11,28 @@ use function ltrim; /** - * Use this annotation to autowire a service from the container into a given parameter of a field/query/mutation. - * - * @Annotation - * @Target({"METHOD", "ANNOTATION"}) - * @Attributes({ - * @Attribute("for", type = "string"), - * @Attribute("identifier", type = "string") - * }) + * Use this attribute to autowire a service from the container into a given parameter of a field/query/mutation. */ #[Attribute(Attribute::TARGET_PARAMETER)] class Autowire implements ParameterAnnotationInterface { - /** @var string|null */ - private $for; - /** @var string|null */ - private $identifier; - - /** @param array|string $identifier */ - public function __construct(array|string $identifier = []) + private string|null $for = null; + private string|null $identifier = null; + + /** @param array|string $params */ + public function __construct( + array|string $params = [], + string|null $for = null, + string|null $identifier = null, + ) { - $values = $identifier; + $values = $params; if (is_string($values)) { $this->identifier = $values; } else { - $this->identifier = $values['identifier'] ?? $values['value'] ?? null; - if (isset($values['for'])) { - $this->for = ltrim($values['for'], '$'); + $this->identifier = $identifier ?? $values['identifier'] ?? $values['value'] ?? null; + if (isset($values['for']) || $for !== null) { + $this->for = ltrim($for ?? $values['for'], '$'); } } } @@ -45,7 +40,7 @@ public function __construct(array|string $identifier = []) public function getTarget(): string { if ($this->for === null) { - throw new BadMethodCallException('The @Autowire annotation must be passed a target. For instance: "@Autowire(for="$myService")"'); + throw new BadMethodCallException('The #[Autowire] attribute must be passed a target. For instance: "#[Autowire(for: "$myService")]"'); } return $this->for; } diff --git a/src/Annotations/Decorate.php b/src/Annotations/Decorate.php index ce9bc3b30f..a7ed1e36dc 100644 --- a/src/Annotations/Decorate.php +++ b/src/Annotations/Decorate.php @@ -10,20 +10,13 @@ use function is_string; /** - * Methods with this annotation are decorating an input type when the input type is resolved. + * Methods with this attribute are decorating an input type when the input type is resolved. * This is meant to be used only when the input type is provided by a third-party library and you want to modify it. - * - * @Annotation - * @Target({"METHOD"}) - * @Attributes({ - * @Attribute("inputTypeName", type = "string"), - * }) */ #[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] class Decorate { - /** @var string */ - private $inputTypeName; + private string $inputTypeName; /** * @param array|string $inputTypeName @@ -36,7 +29,7 @@ public function __construct(array|string $inputTypeName = []) if (is_string($values)) { $this->inputTypeName = $values; } elseif (! isset($values['value']) && ! isset($values['inputTypeName'])) { - throw new BadMethodCallException('The @Decorate annotation must be passed an input type. For instance: "@Decorate("MyInputType")"'); + throw new BadMethodCallException('The #[Decorate] attribute must be passed an input type. For instance: "#[Decorate("MyInputType")]"'); } else { $this->inputTypeName = $values['value'] ?? $values['inputTypeName']; } diff --git a/src/Annotations/Exceptions/ClassNotFoundException.php b/src/Annotations/Exceptions/ClassNotFoundException.php index 6cd1f9d6e4..aaa472e07a 100644 --- a/src/Annotations/Exceptions/ClassNotFoundException.php +++ b/src/Annotations/Exceptions/ClassNotFoundException.php @@ -17,11 +17,11 @@ public static function couldNotFindClass(string $className): self public static function wrapException(self $e, string $className): self { - return new self($e->getMessage() . " defined in @Type annotation of class '" . $className . "'"); + return new self($e->getMessage() . " defined in #[Type] attribute of class '" . $className . "'"); } public static function wrapExceptionForExtendTag(self $e, string $className): self { - return new self($e->getMessage() . " defined in @ExtendType annotation of class '" . $className . "'"); + return new self($e->getMessage() . " defined in #[ExtendType] attribute of class '" . $className . "'"); } } diff --git a/src/Annotations/Exceptions/InvalidParameterException.php b/src/Annotations/Exceptions/InvalidParameterException.php index 91d31a7ad0..7070232933 100644 --- a/src/Annotations/Exceptions/InvalidParameterException.php +++ b/src/Annotations/Exceptions/InvalidParameterException.php @@ -13,11 +13,11 @@ class InvalidParameterException extends BadMethodCallException { public static function parameterNotFound(string $parameter, string $annotationClass, ReflectionMethod $reflectionMethod): self { - return new self(sprintf('Parameter "%s" declared in annotation "%s" of method "%s::%s()" does not exist.', $parameter, $annotationClass, $reflectionMethod->getDeclaringClass()->getName(), $reflectionMethod->getName())); + return new self(sprintf('Parameter "%s" declared in attribute "%s" of method "%s::%s()" does not exist.', $parameter, $annotationClass, $reflectionMethod->getDeclaringClass()->getName(), $reflectionMethod->getName())); } public static function parameterNotFoundFromSourceField(string $parameter, string $annotationClass, ReflectionMethod $reflectionMethod): self { - return new self(sprintf('Could not find parameter "%s" declared in annotation "%s". This annotation is itself declared in a SourceField annotation targeting resolver "%s::%s()".', $parameter, $annotationClass, $reflectionMethod->getDeclaringClass()->getName(), $reflectionMethod->getName())); + return new self(sprintf('Could not find parameter "%s" declared in annotation "%s". This annotation is itself declared in a SourceField attribute targeting resolver "%s::%s()".', $parameter, $annotationClass, $reflectionMethod->getDeclaringClass()->getName(), $reflectionMethod->getName())); } } diff --git a/src/Annotations/ExtendType.php b/src/Annotations/ExtendType.php index 40592090fd..609c141138 100644 --- a/src/Annotations/ExtendType.php +++ b/src/Annotations/ExtendType.php @@ -13,14 +13,7 @@ use function ltrim; /** - * The ExtendType annotation must be put in a GraphQL type class docblock and is used to add additional fields to the underlying PHP class. - * - * @Annotation - * @Target({"CLASS"}) - * @Attributes({ - * @Attribute("class", type = "string"), - * @Attribute("name", type = "string"), - * }) + * The ExtendType attribute must be put in a GraphQL type class docblock and is used to add additional fields to the underlying PHP class. */ #[Attribute(Attribute::TARGET_CLASS)] class ExtendType @@ -41,7 +34,7 @@ public function __construct(array $attributes = [], string|null $class = null, s $this->name = $name ?? $attributes['name'] ?? null; $this->class = $className; if (! $this->class && ! $this->name) { - throw new BadMethodCallException('In annotation @ExtendType, missing one of the compulsory parameter "class" or "name".'); + throw new BadMethodCallException('In attribute #[ExtendType], missing one of the compulsory parameter "class" or "name".'); } } diff --git a/src/Annotations/Factory.php b/src/Annotations/Factory.php index 457eb087ed..9d617e4744 100644 --- a/src/Annotations/Factory.php +++ b/src/Annotations/Factory.php @@ -9,13 +9,6 @@ /** * Factories are methods used to declare GraphQL input types. - * - * @Annotation - * @Target({"METHOD"}) - * @Attributes({ - * @Attribute("name", type = "string"), - * @Attribute("default", type = "bool") - * }) */ #[Attribute(Attribute::TARGET_METHOD)] class Factory @@ -33,7 +26,7 @@ public function __construct(array $attributes = [], string|null $name = null, bo $this->default = $default ?? $attributes['default'] ?? ! isset($attributes['name']); if ($this->name === null && $this->default === false) { - throw new GraphQLRuntimeException('A @Factory that has "default=false" attribute must be given a name (i.e. add a name="FooBarInput" attribute).'); + throw new GraphQLRuntimeException('A #[Factory] that has "default=false" attribute must be given a name (i.e. add a name="FooBarInput" attribute).'); } } diff --git a/src/Annotations/FailWith.php b/src/Annotations/FailWith.php index 7e153a5e50..9e87eb0d80 100644 --- a/src/Annotations/FailWith.php +++ b/src/Annotations/FailWith.php @@ -10,14 +10,6 @@ use function array_key_exists; use function is_array; -/** - * @Annotation - * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) - * @Attributes({ - * @Attribute("value", type = "mixed"), - * @Attribute("mode", type = "string") - * }) - */ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD)] class FailWith implements MiddlewareAnnotationInterface { @@ -35,8 +27,10 @@ public function __construct(mixed $values = [], mixed $value = '__fail__with__ma $this->value = $value; } elseif (is_array($values) && array_key_exists('value', $values)) { $this->value = $values['value']; + } elseif (! is_array($values)) { + $this->value = $values; } else { - throw new BadMethodCallException('The @FailWith annotation must be passed a defaultValue. For instance: "@FailWith(null)"'); + throw new BadMethodCallException('The #[FailWith] attribute must be passed a defaultValue. For instance: "#[FailWith(null)]"'); } } diff --git a/src/Annotations/Field.php b/src/Annotations/Field.php index 8e4112c535..12712bd6e8 100644 --- a/src/Annotations/Field.php +++ b/src/Annotations/Field.php @@ -10,18 +10,6 @@ use const E_USER_DEPRECATED; -/** - * @Annotation - * @Target({"PROPERTY", "METHOD"}) - * @Attributes({ - * @Attribute("name", type = "string"), - * @Attribute("outputType", type = "string"), - * @Attribute("prefetchMethod", type = "string"), - * @Attribute("for", type = "string[]"), - * @Attribute("description", type = "string"), - * @Attribute("inputType", type = "string"), - * }) - */ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] class Field extends AbstractRequest { diff --git a/src/Annotations/HideIfUnauthorized.php b/src/Annotations/HideIfUnauthorized.php index 98727c7655..505ab18262 100644 --- a/src/Annotations/HideIfUnauthorized.php +++ b/src/Annotations/HideIfUnauthorized.php @@ -7,11 +7,8 @@ use Attribute; /** - * Fields/Queries/Mutations annotated with this annotation will be hidden from the schema if the user is not logged + * Fields/Queries/Mutations annotated with this attribute will be hidden from the schema if the user is not logged * or has no right associated. - * - * @Annotation - * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) */ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD)] class HideIfUnauthorized implements MiddlewareAnnotationInterface diff --git a/src/Annotations/HideParameter.php b/src/Annotations/HideParameter.php index 2c14fe4f7a..33c1328b8e 100644 --- a/src/Annotations/HideParameter.php +++ b/src/Annotations/HideParameter.php @@ -10,35 +10,28 @@ use function ltrim; /** - * Use this annotation to tell GraphQLite to ignore a parameter and not expose it as an input parameter. + * Use this attribute to tell GraphQLite to ignore a parameter and not expose it as an input parameter. * This is only possible if the parameter has a default value. - * - * @Annotation - * @Target({"METHOD", "ANNOTATION"}) - * @Attributes({ - * @Attribute("for", type = "string") - * }) */ #[Attribute(Attribute::TARGET_PARAMETER)] class HideParameter implements ParameterAnnotationInterface { - /** @var string */ - private $for; + private string|null $for = null; /** @param array $values */ - public function __construct(array $values = []) + public function __construct(array $values = [], string|null $for = null) { - if (! isset($values['for'])) { + if (! isset($values['for']) && $for === null) { return; } - $this->for = ltrim($values['for'], '$'); + $this->for = ltrim($for ?? $values['for'], '$'); } public function getTarget(): string { if ($this->for === null) { - throw new BadMethodCallException('The @HideParameter annotation must be passed a target. For instance: "@HideParameter(for="$myParameterToHide")"'); + throw new BadMethodCallException('The #[HideParameter] attribute must be passed a target. For instance: "#[HideParameter(for: "$myParameterToHide")]"'); } return $this->for; } diff --git a/src/Annotations/InjectUser.php b/src/Annotations/InjectUser.php index 7d050b3c52..a7e27fe913 100644 --- a/src/Annotations/InjectUser.php +++ b/src/Annotations/InjectUser.php @@ -10,14 +10,8 @@ use function ltrim; /** - * Use this annotation to tell GraphQLite to inject the current logged user as an input parameter. + * Use this attribute to tell GraphQLite to inject the current logged user as an input parameter. * If the parameter is not nullable, the user MUST be logged to access the resource. - * - * @Annotation - * @Target({"METHOD", "ANNOTATION"}) - * @Attributes({ - * @Attribute("for", type = "string") - * }) */ #[Attribute(Attribute::TARGET_PARAMETER)] class InjectUser implements ParameterAnnotationInterface @@ -26,7 +20,7 @@ class InjectUser implements ParameterAnnotationInterface private $for; /** @param array $values */ - public function __construct(array $values = []) + public function __construct(array|null $values = []) { if (! isset($values['for'])) { return; @@ -38,7 +32,7 @@ public function __construct(array $values = []) public function getTarget(): string { if ($this->for === null) { - throw new BadMethodCallException('The @InjectUser annotation must be passed a target. For instance: "@InjectUser(for="$user")"'); + throw new BadMethodCallException('The #[InjectUser] attribute must be passed a target. For instance: "#[InjectUser(for: "$user")]"'); } return $this->for; } diff --git a/src/Annotations/Input.php b/src/Annotations/Input.php index abe22a97d7..31066500a6 100644 --- a/src/Annotations/Input.php +++ b/src/Annotations/Input.php @@ -8,17 +8,8 @@ use RuntimeException; /** - * The Input annotation must be put in a GraphQL input type class docblock and is used to map to the underlying PHP class + * The Input attribute must be put in a GraphQL input type class docblock and is used to map to the underlying PHP class * this is exposed via this input type. - * - * @Annotation - * @Target({"CLASS"}) - * @Attributes({ - * @Attribute("name", type = "string"), - * @Attribute("default", type = "bool"), - * @Attribute("description", type = "string"), - * @Attribute("update", type = "bool"), - * }) */ #[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] class Input implements TypeInterface @@ -56,16 +47,16 @@ public function __construct( public function getClass(): string { if ($this->class === null) { - throw new RuntimeException('Empty class for @Input annotation. You MUST create the Input annotation object using the GraphQLite AnnotationReader'); + throw new RuntimeException('Empty class for #[Input] attribute. You MUST create the Input attribute object using the GraphQLite AnnotationReader'); } return $this->class; } - /** @param class-string $class */ - public function setClass(string $class): void + /** @param class-string $className */ + public function setClass(string $className): void { - $this->class = $class; + $this->class = $className; } /** @@ -103,7 +94,7 @@ public function isUpdate(): bool /** * By default there isn't support for defining the type outside - * This is used by the @Type annotation with the "external" attribute. + * This is used by the #[Type] attribute with the "external" attribute. */ public function isSelfType(): bool { diff --git a/src/Annotations/Logged.php b/src/Annotations/Logged.php index e802dcd29d..b71400a8b7 100644 --- a/src/Annotations/Logged.php +++ b/src/Annotations/Logged.php @@ -6,10 +6,6 @@ use Attribute; -/** - * @Annotation - * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) - */ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD)] class Logged implements MiddlewareAnnotationInterface { diff --git a/src/Annotations/MagicField.php b/src/Annotations/MagicField.php index da0aff9979..650143ff2e 100644 --- a/src/Annotations/MagicField.php +++ b/src/Annotations/MagicField.php @@ -12,15 +12,6 @@ /** * SourceFields are fields that are directly source from the base object into GraphQL. - * - * @Annotation - * @Target({"CLASS"}) - * @Attributes({ - * @Attribute("name", type = "string"), - * @Attribute("outputType", type = "string"), - * @Attribute("phpType", type = "string"), - * @Attribute("annotations", type = "mixed"), - * }) */ #[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] class MagicField implements SourceFieldInterface @@ -59,10 +50,10 @@ public function __construct(array $attributes = [], string|null $name = null, st $this->sourceName = $attributes['sourceName'] ?? $sourceName ?? null; if (! $this->name || (! $this->outputType && ! $this->phpType)) { - throw new BadMethodCallException('The @MagicField annotation 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\')"'); + 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 (isset($this->outputType) && $this->phpType) { - throw new BadMethodCallException('In a @MagicField annotation, 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 = []; @@ -76,7 +67,7 @@ public function __construct(array $attributes = [], string|null $name = null, st } elseif ($annotation instanceof ParameterAnnotationInterface) { $parameterAnnotations[$annotation->getTarget()][] = $annotation; } else { - throw new BadMethodCallException('The @MagicField annotation\'s "annotations" attribute must be passed an array of annotations implementing either MiddlewareAnnotationInterface or ParameterAnnotationInterface."'); + throw new BadMethodCallException('The #[MagicField] attribute\'s "annotations" attribute must be passed an array of annotations implementing either MiddlewareAnnotationInterface or ParameterAnnotationInterface."'); } } $this->middlewareAnnotations = new MiddlewareAnnotations($middlewareAnnotations); diff --git a/src/Annotations/Mutation.php b/src/Annotations/Mutation.php index 060ee146b2..39db2aa594 100644 --- a/src/Annotations/Mutation.php +++ b/src/Annotations/Mutation.php @@ -6,13 +6,6 @@ use Attribute; -/** - * @Annotation - * @Target({"METHOD"}) - * @Attributes({ - * @Attribute("outputType", type = "string"), - * }) - */ #[Attribute(Attribute::TARGET_METHOD)] class Mutation extends AbstractRequest { diff --git a/src/Annotations/Query.php b/src/Annotations/Query.php index 99ac7a3a5d..8213ae5e10 100644 --- a/src/Annotations/Query.php +++ b/src/Annotations/Query.php @@ -6,13 +6,6 @@ use Attribute; -/** - * @Annotation - * @Target({"METHOD"}) - * @Attributes({ - * @Attribute("outputType", type = "string"), - * }) - */ #[Attribute(Attribute::TARGET_METHOD)] class Query extends AbstractRequest { diff --git a/src/Annotations/Right.php b/src/Annotations/Right.php index b58f8ebac0..d14597a326 100644 --- a/src/Annotations/Right.php +++ b/src/Annotations/Right.php @@ -9,13 +9,6 @@ use function is_string; -/** - * @Annotation - * @Target({"PROPERTY", "ANNOTATION", "METHOD"}) - * @Attributes({ - * @Attribute("name", type = "string"), - * }) - */ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] class Right implements MiddlewareAnnotationInterface { @@ -34,7 +27,7 @@ public function __construct(array|string $name = []) $data = ['name' => $data]; } if (! isset($data['value']) && ! isset($data['name'])) { - throw new BadMethodCallException('The @Right annotation must be passed a right name. For instance: "@Right(\'my_right\')"'); + throw new BadMethodCallException('The #[Right] attribute must be passed a right name. For instance: "#[Right(\'my_right\')]"'); } $this->name = $data['value'] ?? $data['name']; } diff --git a/src/Annotations/Security.php b/src/Annotations/Security.php index 22381f3312..c41c396f60 100644 --- a/src/Annotations/Security.php +++ b/src/Annotations/Security.php @@ -14,16 +14,6 @@ use function is_string; use function sprintf; -/** - * @Annotation - * @Target({"PROPERTY", "ANNOTATION", "METHOD"}) - * @Attributes({ - * @Attribute("expression", type = "string"), - * @Attribute("failWith", type = "mixed"), - * @Attribute("statusCode", type = "int"), - * @Attribute("message", type = "string"), - * }) - */ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] class Security implements MiddlewareAnnotationInterface { @@ -53,7 +43,7 @@ public function __construct(array|string $data = [], string|null $expression = n $this->expression = $data['value'] ?? $data['expression'] ?? $expression; if (! $this->expression) { - throw new BadMethodCallException('The @Security annotation must be passed an expression. For instance: "@Security("is_granted(\'CAN_EDIT_STUFF\')")"'); + throw new BadMethodCallException('The #[Security] attribute must be passed an expression. For instance: "#[Security("is_granted(\'CAN_EDIT_STUFF\')")]"'); } if (array_key_exists('failWith', $data)) { @@ -66,7 +56,7 @@ public function __construct(array|string $data = [], string|null $expression = n $this->message = $message ?? $data['message'] ?? 'Access denied.'; $this->statusCode = $statusCode ?? $data['statusCode'] ?? 403; if ($this->failWithIsSet === true && (($message || isset($data['message'])) || ($statusCode || isset($data['statusCode'])))) { - throw new BadMethodCallException('A @Security annotation that has "failWith" attribute set cannot have a message or a statusCode attribute.'); + throw new BadMethodCallException('A #[Security] attribute that has "failWith" attribute set cannot have a message or a statusCode attribute.'); } } diff --git a/src/Annotations/SourceField.php b/src/Annotations/SourceField.php index 492101d85d..cc5ceb6ad1 100644 --- a/src/Annotations/SourceField.php +++ b/src/Annotations/SourceField.php @@ -12,15 +12,6 @@ /** * SourceFields are fields that are directly source from the base object into GraphQL. - * - * @Annotation - * @Target({"CLASS"}) - * @Attributes({ - * @Attribute("name", type = "string"), - * @Attribute("outputType", type = "string"), - * @Attribute("phpType", type = "string"), - * @Attribute("annotations", type = "mixed"), - * }) */ #[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] class SourceField implements SourceFieldInterface @@ -48,7 +39,7 @@ public function __construct(array $attributes = [], string|null $name = null, st { $name = $name ?? $attributes['name'] ?? null; if ($name === null) { - throw new BadMethodCallException('The @SourceField annotation must be passed a name. For instance: "@SourceField(name=\'phone\')"'); + throw new BadMethodCallException('The #[SourceField] attribute must be passed a name. For instance: "#[SourceField(name: \'phone\')]"'); } $this->name = $name; @@ -58,7 +49,7 @@ public function __construct(array $attributes = [], string|null $name = null, st $this->sourceName = $sourceName ?? $attributes['sourceName'] ?? null; if ($this->outputType && $this->phpType) { - throw new BadMethodCallException('In a @SourceField annotation, you cannot use the outputType and the phpType at the same time. For instance: "@SourceField(name=\'phone\', outputType=\'String!\')" or "@SourceField(name=\'phone\', phpType=\'string\')"'); + throw new BadMethodCallException('In a #[SourceField] attribute, you cannot use the outputType and the phpType at the same time. For instance: "#[SourceField(name: \'phone\', outputType: \'String!\')]" or "#[SourceField(name: \'phone\', phpType: \'string\')]"'); } $middlewareAnnotations = []; $parameterAnnotations = []; @@ -72,7 +63,7 @@ public function __construct(array $attributes = [], string|null $name = null, st } elseif ($annotation instanceof ParameterAnnotationInterface) { $parameterAnnotations[$annotation->getTarget()][] = $annotation; } else { - throw new BadMethodCallException('The @SourceField annotation\'s "annotations" attribute must be passed an array of annotations implementing either MiddlewareAnnotationInterface or ParameterAnnotationInterface."'); + throw new BadMethodCallException('The #[SourceField] attribute\'s "annotations" attribute must be passed an array of annotations implementing either MiddlewareAnnotationInterface or ParameterAnnotationInterface."'); } } $this->middlewareAnnotations = new MiddlewareAnnotations($middlewareAnnotations); diff --git a/src/Annotations/Subscription.php b/src/Annotations/Subscription.php index 1d5fce3b15..7da35e9661 100644 --- a/src/Annotations/Subscription.php +++ b/src/Annotations/Subscription.php @@ -6,13 +6,6 @@ use Attribute; -/** - * @Annotation - * @Target({"METHOD"}) - * @Attributes({ - * @Attribute("outputType", type = "string"), - * }) - */ #[Attribute(Attribute::TARGET_METHOD)] class Subscription extends AbstractRequest { diff --git a/src/Annotations/Type.php b/src/Annotations/Type.php index 0505eec76f..f8465782a5 100644 --- a/src/Annotations/Type.php +++ b/src/Annotations/Type.php @@ -14,39 +14,25 @@ use function ltrim; /** - * The Type annotation must be put in a GraphQL type class docblock and is used to map to the underlying PHP class + * The Type attribute must be put in a GraphQL type class attribute and is used to map to the underlying PHP class * this is exposed via this type. - * - * @Annotation - * @Target({"CLASS"}) - * @Attributes({ - * @Attribute("class", type = "string"), - * @Attribute("name", type = "string"), - * @Attribute("default", type = "bool"), - * @Attribute("external", type = "bool"), - * }) */ #[Attribute(Attribute::TARGET_CLASS)] class Type implements TypeInterface { /** @var class-string|null */ - private $class; + private string|null $class = null; - /** @var string|null */ - private $name; + private string|null $name = null; - /** @var bool */ - private $default; + private bool $default = true; /** - * Is the class having the annotation a GraphQL type itself? - * - * @var bool + * Is the class having the attribute a GraphQL type itself? */ - private $selfType = false; + private bool $selfType = false; - /** @var bool */ - private $useEnumValues = false; + private bool $useEnumValues = false; /** * @param mixed[] $attributes @@ -89,27 +75,27 @@ public function __construct( public function getClass(): string { if ($this->class === null) { - throw new RuntimeException('Empty class for @Type annotation. You MUST create the Type annotation object using the GraphQLite AnnotationReader'); + throw new RuntimeException('Empty class for #[Type] attribute. You MUST create the Type attribute object using the GraphQLite AnnotationReader'); } return $this->class; } - public function setClass(string $class): void + public function setClass(string $className): void { - $class = ltrim($class, '\\'); - $isInterface = interface_exists($class); - if (! class_exists($class) && ! $isInterface) { - throw ClassNotFoundException::couldNotFindClass($class); + $className = ltrim($className, '\\'); + $isInterface = interface_exists($className); + if (! class_exists($className) && ! $isInterface) { + throw ClassNotFoundException::couldNotFindClass($className); } - $this->class = $class; + $this->class = $className; if (! $isInterface) { return; } if ($this->default === false) { - throw new GraphQLRuntimeException('Problem in annotation @Type for interface "' . $class . '": you cannot use the default="false" attribute on interfaces'); + throw new GraphQLRuntimeException('Problem in attribute #[Type] for interface "' . $className . '": you cannot use the default="false" attribute on interfaces'); } } diff --git a/src/Annotations/UseInputType.php b/src/Annotations/UseInputType.php index 248270762b..6463d4ea1a 100644 --- a/src/Annotations/UseInputType.php +++ b/src/Annotations/UseInputType.php @@ -11,36 +11,30 @@ use function ltrim; /** - * Use this annotation to force using a specific input type for an input argument. - * - * @Annotation - * @Target({"METHOD", "ANNOTATION"}) - * @Attributes({ - * @Attribute("for", type = "string"), - * @Attribute("inputType", type = "string"), - * }) + * Use this attribute to force using a specific input type for an input argument. */ #[Attribute(Attribute::TARGET_PARAMETER)] class UseInputType implements ParameterAnnotationInterface { - /** @var string|null */ - private $for; - /** @var string */ - private $inputType; + private string|null $for = null; + private string $inputType; /** * @param array|string $inputType * * @throws BadMethodCallException */ - public function __construct(array|string $inputType = []) + public function __construct(array|string $inputType = [], string|null $for = null) { $values = $inputType; if (is_string($values)) { $values = ['inputType' => $values]; } + if (is_string($for) && $for !== '') { + $values['for'] = $for; + } if (! isset($values['inputType'])) { - throw new BadMethodCallException('The @UseInputType annotation must be passed an input type. For instance: #[UseInputType("MyInputType")]'); + throw new BadMethodCallException('The #[UseInputType] attribute must be passed an input type. For instance: #[UseInputType("MyInputType")]'); } $this->inputType = $values['inputType']; if (! isset($values['for'])) { @@ -53,7 +47,7 @@ public function __construct(array|string $inputType = []) public function getTarget(): string { if ($this->for === null) { - throw new BadMethodCallException('The @UseInputType annotation must be passed a target and an input type. For instance: #[UseInputType("MyInputType")]'); + throw new BadMethodCallException('The #[UseInputType] attribute must be passed a target and an input type. For instance: #[UseInputType("MyInputType")]'); } return $this->for; } diff --git a/src/FieldsBuilder.php b/src/FieldsBuilder.php index 2681f740e5..dd0e58c37c 100644 --- a/src/FieldsBuilder.php +++ b/src/FieldsBuilder.php @@ -4,7 +4,6 @@ namespace TheCodingMachine\GraphQLite; -use Doctrine\Common\Annotations\AnnotationException; use GraphQL\Type\Definition\FieldDefinition; use GraphQL\Type\Definition\InputType; use GraphQL\Type\Definition\NonNull; @@ -105,6 +104,10 @@ public function __construct( * @return array * * @throws ReflectionException + * @throws CannotMapTypeExceptionInterface + * @throws InvalidArgumentException + * + * @phpstan-ignore-next-line - simple-cache < 2.0 issue */ public function getQueries(object $controller): array { @@ -115,6 +118,10 @@ public function getQueries(object $controller): array * @return array * * @throws ReflectionException + * @throws CannotMapTypeExceptionInterface + * @throws InvalidArgumentException + * + * @phpstan-ignore-next-line - simple-cache < 2.0 issue */ public function getMutations(object $controller): array { @@ -125,13 +132,25 @@ public function getMutations(object $controller): array * @return array * * @throws ReflectionException + * @throws CannotMapTypeExceptionInterface + * @throws InvalidArgumentException + * + * @phpstan-ignore-next-line - simple-cache < 2.0 issue */ public function getSubscriptions(object $controller): array { return $this->getFieldsByAnnotations($controller, Subscription::class, false); } - /** @return array QueryField indexed by name. */ + /** + * @return array QueryField indexed by name. + * + * @throws ReflectionException + * @throws CannotMapTypeExceptionInterface + * @throws InvalidArgumentException + * + * @phpstan-ignore-next-line - simple-cache < 2.0 issue + */ public function getFields(object $controller, string|null $typeName = null): array { $fieldAnnotations = $this->getFieldsByAnnotations($controller, Annotations\Field::class, true, $typeName); @@ -159,8 +178,11 @@ public function getFields(object $controller, string|null $typeName = null): arr * * @return array * - * @throws AnnotationException * @throws ReflectionException + * @throws CannotMapTypeExceptionInterface + * @throws InvalidArgumentException + * + * @phpstan-ignore-next-line - simple-cache < 2.0 issue */ public function getInputFields(string $className, string $inputName, bool $isUpdate = false): array { @@ -247,6 +269,12 @@ public function getInputFields(string $className, string $inputName, bool $isUpd * @param class-string $className * * @return array QueryField indexed by name. + * + * @throws ReflectionException + * @throws CannotMapTypeExceptionInterface + * @throws InvalidArgumentException + * + * @phpstan-ignore-next-line - simple-cache < 2.0 issue */ public function getSelfFields(string $className, string|null $typeName = null): array { @@ -259,7 +287,6 @@ public function getSelfFields(string $className, string|null $typeName = null): $refClass = new ReflectionClass($className); - /** @var SourceFieldInterface[] $sourceFields */ $sourceFields = $this->annotationReader->getSourceFields($refClass); $fieldsFromSourceFields = $this->getQueryFieldsFromSourceFields($sourceFields, $refClass); @@ -277,6 +304,8 @@ public function getSelfFields(string $className, string|null $typeName = null): * @param int $skip Skip first N parameters if those are passed in externally * * @return array Returns an array of parameters. + * + * @throws InvalidArgumentException */ public function getParameters(ReflectionMethod $refMethod, int $skip = 0): array { @@ -292,6 +321,8 @@ public function getParameters(ReflectionMethod $refMethod, int $skip = 0): array * @param ReflectionMethod $refMethod A method annotated with a Decorate annotation. * * @return array Returns an array of parameters. + * + * @throws InvalidArgumentException */ public function getParametersForDecorator(ReflectionMethod $refMethod): array { @@ -308,6 +339,10 @@ public function getParametersForDecorator(ReflectionMethod $refMethod): array * @return array * * @throws ReflectionException + * @throws CannotMapTypeExceptionInterface + * @throws InvalidArgumentException + * + * @phpstan-ignore-next-line - simple-cache < 2.0 issue */ private function getFieldsByAnnotations($controller, string $annotationName, bool $injectSource, string|null $typeName = null): array { @@ -387,7 +422,10 @@ private function getFieldsByAnnotations($controller, string $annotationName, boo * * @return array * - * @throws AnnotationException + * @throws InvalidArgumentException + * @throws CannotMapTypeExceptionInterface + * + * @phpstan-ignore-next-line - simple-cache < 2.0 issue */ private function getFieldsByMethodAnnotations( string|object $controller, @@ -500,7 +538,10 @@ public function handle(QueryFieldDescriptor $fieldDescriptor): FieldDefinition|n * * @return array * - * @throws AnnotationException + * @throws InvalidArgumentException + * @throws CannotMapTypeException + * + * @phpstan-ignore-next-line - simple-cache < 2.0 issue */ private function getFieldsByPropertyAnnotations( string|object $controller, @@ -589,9 +630,12 @@ public function handle(QueryFieldDescriptor $fieldDescriptor): FieldDefinition|n * * @return FieldDefinition[] * - * @throws CannotMapTypeException * @throws CannotMapTypeExceptionInterface * @throws ReflectionException + * @throws FieldNotFoundException + * @throws InvalidArgumentException + * + * @phpstan-ignore-next-line - simple-cache < 2.0 issue */ private function getQueryFieldsFromSourceFields( array $sourceFields, @@ -744,7 +788,11 @@ private function getMagicGetMethodFromSourceClassOrProxy( return $sourceRefClass->getMethod($magicGet); } - /** @param ReflectionClass $refClass */ + /** + * @param ReflectionClass $refClass + * + * @throws CannotMapTypeExceptionInterface + */ private function resolveOutputType( string $outputType, ReflectionClass $refClass, @@ -759,7 +807,11 @@ private function resolveOutputType( } } - /** @param ReflectionClass $refClass */ + /** + * @param ReflectionClass $refClass + * + * @throws CannotMapTypeExceptionInterface + */ private function resolvePhpType( string $phpTypeStr, ReflectionClass $refClass, @@ -781,6 +833,9 @@ private function resolvePhpType( /** * @param ReflectionClass $reflectionClass * + * @throws ReflectionException + * @throws FieldNotFoundException + * * @template T of object */ private function getMethodFromPropertyName( @@ -804,6 +859,8 @@ private function getMethodFromPropertyName( * @param ReflectionParameter[] $refParameters * * @return array + * + * @throws InvalidParameterException */ private function mapParameters( array $refParameters, @@ -814,6 +871,7 @@ private function mapParameters( if (empty($refParameters)) { return []; } + $args = []; $additionalParameterAnnotations = $sourceField?->getParameterAnnotations() ?? []; @@ -933,11 +991,14 @@ private function getPrefetchParameter( * Gets input fields by class method annotations. * * @param class-string $annotationName - * @param array $defaultProperties + * @param array $defaultProperties * * @return array * - * @throws AnnotationException + * @throws CannotMapTypeExceptionInterface + * @throws InvalidArgumentException + * + * @phpstan-ignore-next-line - simple-cache < 2.0 issue */ private function getInputFieldsByMethodAnnotations( string|object $controller, @@ -1039,11 +1100,14 @@ public function handle(InputFieldDescriptor $inputFieldDescriptor): InputField|n * Gets input fields by class property annotations. * * @param class-string $annotationName - * @param array $defaultProperties + * @param array $defaultProperties * * @return array * - * @throws AnnotationException + * @throws InvalidArgumentException + * @throws CannotMapTypeException + * + * @phpstan-ignore-next-line - simple-cache < 2.0 issue */ private function getInputFieldsByPropertyAnnotations( string|object $controller, @@ -1088,10 +1152,10 @@ private function getInputFieldsByPropertyAnnotations( assert($type instanceof InputType); $forConstructorHydration = in_array($name, $constructerParameters); $resolver = $forConstructorHydration - ? new SourceConstructorParameterResolver( - $refProperty->getDeclaringClass()->getName(), - $refProperty->getName(), - ) + ? new SourceConstructorParameterResolver( + $refProperty->getDeclaringClass()->getName(), + $refProperty->getName(), + ) : new SourceInputPropertyResolver($refProperty); // setters and properties diff --git a/src/SchemaFactory.php b/src/SchemaFactory.php index 04e4bfa6ba..a4c2bd2c6d 100644 --- a/src/SchemaFactory.php +++ b/src/SchemaFactory.php @@ -4,15 +4,11 @@ namespace TheCodingMachine\GraphQLite; -use Doctrine\Common\Annotations\AnnotationReader as DoctrineAnnotationReader; -use Doctrine\Common\Annotations\PsrCachedReader; -use Doctrine\Common\Annotations\Reader; use GraphQL\Type\SchemaConfig; use Kcs\ClassFinder\Finder\ComposerFinder; use Kcs\ClassFinder\Finder\FinderInterface; use MyCLabs\Enum\Enum; use PackageVersions\Versions; -use Psr\Cache\CacheItemPoolInterface; use Psr\Container\ContainerInterface; use Psr\SimpleCache\CacheInterface; use Symfony\Component\Cache\Adapter\Psr16Adapter; @@ -100,8 +96,6 @@ class SchemaFactory /** @var ParameterMiddlewareInterface[] */ private array $parameterMiddlewares = []; - private Reader|null $doctrineAnnotationReader = null; - private AuthenticationServiceInterface|null $authenticationService = null; private AuthorizationServiceInterface|null $authorizationService = null; @@ -126,7 +120,7 @@ class SchemaFactory private string $cacheNamespace; - public function __construct(private CacheInterface $cache, private ContainerInterface $container) + public function __construct(private readonly CacheInterface $cache, private readonly ContainerInterface $container) { $this->cacheNamespace = substr(md5(Versions::getVersion('thecodingmachine/graphqlite')), 0, 8); } @@ -211,23 +205,6 @@ public function addParameterMiddleware(ParameterMiddlewareInterface $parameterMi return $this; } - /** @deprecated Use PHP8 Attributes instead */ - public function setDoctrineAnnotationReader(Reader $annotationReader): self - { - $this->doctrineAnnotationReader = $annotationReader; - - return $this; - } - - /** - * Returns a cached Doctrine annotation reader. - * Note: we cannot get the annotation reader service in the container as we are in a compiler pass. - */ - private function getDoctrineAnnotationReader(CacheItemPoolInterface $cache): Reader - { - return $this->doctrineAnnotationReader ?? new PsrCachedReader(new DoctrineAnnotationReader(), $cache, true); - } - public function setAuthenticationService(AuthenticationServiceInterface $authenticationService): self { $this->authenticationService = $authenticationService; @@ -336,7 +313,7 @@ public function setExpressionLanguage(ExpressionLanguage $expressionLanguage): s public function createSchema(): Schema { $symfonyCache = new Psr16Adapter($this->cache, $this->cacheNamespace); - $annotationReader = new AnnotationReader($this->getDoctrineAnnotationReader($symfonyCache), AnnotationReader::LAX_MODE); + $annotationReader = new AnnotationReader(); $authenticationService = $this->authenticationService ?: new FailAuthenticationService(); $authorizationService = $this->authorizationService ?: new FailAuthorizationService(); $typeResolver = new TypeResolver(); diff --git a/src/Types/TypeResolver.php b/src/Types/TypeResolver.php index 5edb635a01..9e6e095837 100644 --- a/src/Types/TypeResolver.php +++ b/src/Types/TypeResolver.php @@ -12,6 +12,7 @@ use GraphQL\Type\Definition\WrappingType; use GraphQL\Type\Schema; use GraphQL\Utils\AST; +use JsonException; use RuntimeException; use TheCodingMachine\GraphQLite\Mappers\CannotMapTypeException; use TheCodingMachine\GraphQLite\Mappers\CannotMapTypeExceptionInterface; @@ -30,7 +31,7 @@ public function registerSchema(Schema $schema): void $this->schema = $schema; } - /** @throws CannotMapTypeExceptionInterface */ + /** @throws CannotMapTypeExceptionInterface|JsonException */ public function mapNameToType(string $typeName): Type { if ($this->schema === null) { diff --git a/tests/AbstractQueryProvider.php b/tests/AbstractQueryProvider.php index 37ca186cce..129068079c 100644 --- a/tests/AbstractQueryProvider.php +++ b/tests/AbstractQueryProvider.php @@ -1,14 +1,15 @@ [ 'test' => Type::string(), ], - ], function ($source, $args) { + ], static function ($source, $args) { return new TestObject($args['test']); }); } @@ -123,29 +122,18 @@ protected function getTypeMapper() $arrayAdapter = new ArrayAdapter(); $arrayAdapter->setLogger(new ExceptionLogger()); - $this->typeMapper = new RecursiveTypeMapper(new class($this->getTestObjectType(), $this->getTestObjectType2(), $this->getInputTestObjectType()/*, $this->getInputTestObjectType2()*/ - ) implements TypeMapperInterface { - /** - * @var ObjectType - */ + $this->typeMapper = new RecursiveTypeMapper(new class ($this->getTestObjectType(), $this->getTestObjectType2(), $this->getInputTestObjectType()/*, $this->getInputTestObjectType2()*/) implements TypeMapperInterface { + /** @var ObjectType */ private $testObjectType; - /** - * @var ObjectType - */ + /** @var ObjectType */ private $testObjectType2; - /** - * @var InputObjectType - */ + /** @var InputObjectType */ private $inputTestObjectType; - /** - * @var InputObjectType - */ - public function __construct( - ObjectType $testObjectType, - ObjectType $testObjectType2, - InputObjectType $inputTestObjectType + ObjectType $testObjectType, + ObjectType $testObjectType2, + InputObjectType $inputTestObjectType, ) { $this->testObjectType = $testObjectType; @@ -153,7 +141,7 @@ public function __construct( $this->inputTestObjectType = $inputTestObjectType; } - public function mapClassToType(string $className, ?OutputType $subType): MutableInterface + public function mapClassToType(string $className, OutputType|null $subType): MutableInterface { if ($className === TestObject::class) { return $this->testObjectType; @@ -234,7 +222,6 @@ public function decorateInputTypeForName(string $typeName, ResolvableMutableInpu { throw CannotMapTypeException::createForDecorateName($typeName, $type); } - }, new NamingStrategy(), new Psr16Cache($arrayAdapter), $this->getTypeRegistry(), $this->getAnnotationReader()); } return $this->typeMapper; @@ -264,7 +251,7 @@ protected function buildAutoWiringContainer(ContainerInterface $container): Basi protected function getAnnotationReader(): AnnotationReader { if ($this->annotationReader === null) { - $this->annotationReader = new AnnotationReader(new DoctrineAnnotationReader()); + $this->annotationReader = new AnnotationReader(); } return $this->annotationReader; } @@ -297,18 +284,20 @@ protected function buildFieldsBuilder(): FieldsBuilder $fieldMiddlewarePipe = new FieldMiddlewarePipe(); $fieldMiddlewarePipe->pipe(new AuthorizationFieldMiddleware( new VoidAuthenticationService(), - new VoidAuthorizationService() + new VoidAuthorizationService(), )); $expressionLanguage = new ExpressionLanguage( new Psr16Adapter($psr16Cache), - [new SecurityExpressionLanguageProvider()] + [new SecurityExpressionLanguageProvider()], ); $fieldMiddlewarePipe->pipe( - new SecurityFieldMiddleware($expressionLanguage, + new SecurityFieldMiddleware( + $expressionLanguage, new VoidAuthenticationService(), - new VoidAuthorizationService()) + new VoidAuthorizationService(), + ), ); $inputFieldMiddlewarePipe = new InputFieldMiddlewarePipe(); @@ -323,7 +312,7 @@ protected function buildFieldsBuilder(): FieldsBuilder $this->buildRootTypeMapper(), $parameterMiddlewarePipe, $fieldMiddlewarePipe, - $inputFieldMiddlewarePipe + $inputFieldMiddlewarePipe, ); $parameterizedCallableResolver = new ParameterizedCallableResolver($fieldsBuilder, $container); @@ -354,7 +343,7 @@ protected function buildRootTypeMapper(): RootTypeMapperInterface $rootTypeMapper = new BaseTypeMapper( $errorRootTypeMapper, $this->getTypeMapper(), - $topRootTypeMapper + $topRootTypeMapper, ); // Annotation support - deprecated @@ -362,14 +351,14 @@ protected function buildRootTypeMapper(): RootTypeMapperInterface $rootTypeMapper, $this->getAnnotationReader(), $arrayAdapter, - [] + [], ); $rootTypeMapper = new EnumTypeMapper( $rootTypeMapper, $this->getAnnotationReader(), $arrayAdapter, - [] + [], ); $rootTypeMapper = new CompoundTypeMapper( @@ -377,7 +366,7 @@ protected function buildRootTypeMapper(): RootTypeMapperInterface $topRootTypeMapper, new NamingStrategy(), $this->getTypeRegistry(), - $this->getTypeMapper() + $this->getTypeMapper(), ); $rootTypeMapper = new IteratorTypeMapper($rootTypeMapper, $topRootTypeMapper); @@ -407,7 +396,7 @@ protected function getTypeGenerator(): TypeGenerator $this->getTypeRegistry(), $this->getRegistry(), $this->getTypeMapper(), - $this->getFieldsBuilder() + $this->getFieldsBuilder(), ); return $this->typeGenerator; @@ -421,7 +410,7 @@ protected function getInputTypeGenerator(): InputTypeGenerator $this->inputTypeGenerator = new InputTypeGenerator( $this->getInputTypeUtils(), - $this->getFieldsBuilder() + $this->getFieldsBuilder(), ); return $this->inputTypeGenerator; @@ -432,7 +421,7 @@ protected function getInputTypeUtils(): InputTypeUtils if ($this->inputTypeUtils === null) { $this->inputTypeUtils = new InputTypeUtils( $this->getAnnotationReader(), - new NamingStrategy() + new NamingStrategy(), ); } return $this->inputTypeUtils; @@ -442,7 +431,7 @@ protected function getTypeResolver(): TypeResolver { if ($this->typeResolver === null) { $this->typeResolver = new TypeResolver(); - $this->typeResolver->registerSchema(new \GraphQL\Type\Schema([])); + $this->typeResolver->registerSchema(new Schema([])); } return $this->typeResolver; } diff --git a/tests/AnnotationReaderTest.php b/tests/AnnotationReaderTest.php index a476222c27..0ec8f2158e 100644 --- a/tests/AnnotationReaderTest.php +++ b/tests/AnnotationReaderTest.php @@ -1,14 +1,13 @@ expectException(InvalidArgumentException::class); - new AnnotationReader(new DoctrineAnnotationReader(), 'foo'); - } - - public function testStrictMode(): void + public function testBadAnnotation(): void { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::STRICT_MODE, []); - - $this->expectException(AnnotationException::class); - $annotationReader->getTypeAnnotation(new ReflectionClass(ClassWithInvalidClassAnnotation::class)); - } - - public function testLaxModeWithBadAnnotation(): void - { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::LAX_MODE, []); + $annotationReader = new AnnotationReader(); $type = $annotationReader->getTypeAnnotation(new ReflectionClass(ClassWithInvalidClassAnnotation::class)); $this->assertNull($type); } - public function testLaxModeWithSmellyAnnotation(): void + public function testSmellyAnnotation(): void { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::LAX_MODE, []); + $annotationReader = new AnnotationReader(); - $this->expectException(AnnotationException::class); - $annotationReader->getTypeAnnotation(new ReflectionClass(ClassWithInvalidTypeAnnotation::class)); + $this->assertNull($annotationReader->getTypeAnnotation(new ReflectionClass(ClassWithInvalidTypeAnnotation::class))); } - public function testLaxModeWithBadAnnotationAndStrictNamespace(): void + public function testGetAnnotationsWithBadAnnotation(): void { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::LAX_MODE, ['TheCodingMachine\\GraphQLite\\Fixtures']); - - $this->expectException(AnnotationException::class); - $annotationReader->getTypeAnnotation(new ReflectionClass(ClassWithInvalidClassAnnotation::class)); - } - - public function testGetAnnotationsStrictMode(): void - { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::STRICT_MODE, []); - - $this->expectException(AnnotationException::class); - $annotationReader->getClassAnnotations(new ReflectionClass(ClassWithInvalidClassAnnotation::class), Type::class); - } - - public function testGetAnnotationsLaxModeWithBadAnnotation(): void - { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::LAX_MODE, []); + $annotationReader = new AnnotationReader(); $types = $annotationReader->getClassAnnotations(new ReflectionClass(ClassWithInvalidClassAnnotation::class), Type::class); $this->assertSame([], $types); } - public function testGetAnnotationsLaxModeWithSmellyAnnotation(): void - { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::LAX_MODE, []); - - $this->expectException(AnnotationException::class); - $annotationReader->getClassAnnotations(new ReflectionClass(ClassWithInvalidTypeAnnotation::class), Type::class); - } - - public function testGetAnnotationsLaxModeWithBadAnnotationAndStrictNamespace(): void - { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::LAX_MODE, ['TheCodingMachine\\GraphQLite\\Fixtures']); - - $this->expectException(AnnotationException::class); - $annotationReader->getClassAnnotations(new ReflectionClass(ClassWithInvalidClassAnnotation::class), Type::class); - } - - public function testMethodStrictMode(): void + public function testMethodWithBadAnnotation(): void { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::STRICT_MODE, []); - - $this->expectException(AnnotationException::class); - $annotationReader->getRequestAnnotation(new ReflectionMethod(ClassWithInvalidClassAnnotation::class, 'testMethod'), Field::class); - } - - public function testMethodLaxModeWithBadAnnotation(): void - { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::LAX_MODE, []); + $annotationReader = new AnnotationReader(); $type = $annotationReader->getRequestAnnotation(new ReflectionMethod(ClassWithInvalidClassAnnotation::class, 'testMethod'), Field::class); $this->assertNull($type); } - public function testMethodLaxModeWithSmellyAnnotation(): void - { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::LAX_MODE, []); - - $this->expectException(AnnotationException::class); - $annotationReader->getRequestAnnotation(new ReflectionMethod(ClassWithInvalidTypeAnnotation::class, 'testMethod'), Field::class); - } - public function testExtendAnnotationException(): void { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::STRICT_MODE, []); + $annotationReader = new AnnotationReader(); $this->expectException(ClassNotFoundException::class); - $this->expectExceptionMessage("Could not autoload class 'foo' defined in @ExtendType annotation of class 'TheCodingMachine\GraphQLite\Fixtures\Annotations\ClassWithInvalidExtendTypeAnnotation'"); + $this->expectExceptionMessage("Could not autoload class 'foo' defined in #[ExtendType] attribute of class 'TheCodingMachine\GraphQLite\Fixtures\Annotations\ClassWithInvalidExtendTypeAnnotation'"); $annotationReader->getExtendTypeAnnotation(new ReflectionClass(ClassWithInvalidExtendTypeAnnotation::class)); } - public function testMethodsStrictMode(): void - { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::STRICT_MODE, []); - - $this->expectException(AnnotationException::class); - $annotationReader->getMethodAnnotations(new ReflectionMethod(ClassWithInvalidClassAnnotation::class, 'testMethod'), Field::class); - } - - public function testMethodsLaxModeWithBadAnnotation(): void + public function testMethodsWithBadAnnotation(): void { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::LAX_MODE, []); + $annotationReader = new AnnotationReader(); $type = $annotationReader->getMethodAnnotations(new ReflectionMethod(ClassWithInvalidClassAnnotation::class, 'testMethod'), Field::class); $this->assertSame([], $type); } - public function testGetMethodsAnnotationsLaxModeWithBadAnnotationAndStrictNamespace(): void - { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader(), AnnotationReader::LAX_MODE, ['TheCodingMachine\\GraphQLite\\Fixtures']); - - $this->expectException(AnnotationException::class); - $annotationReader->getMethodAnnotations(new ReflectionMethod(ClassWithInvalidClassAnnotation::class, 'testMethod'), Type::class); - } - public function testEmptyGetParameterAnnotations(): void { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader()); + $annotationReader = new AnnotationReader(); $this->assertEmpty($annotationReader->getParameterAnnotationsPerParameter([])); } public function testPhp8AttributeClassAnnotation(): void { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader()); + $annotationReader = new AnnotationReader(); $type = $annotationReader->getTypeAnnotation(new ReflectionClass(TestType::class)); $this->assertSame(TestType::class, $type->getClass()); @@ -168,7 +88,7 @@ public function testPhp8AttributeClassAnnotation(): void public function testPhp8AttributeClassAnnotations(): void { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader()); + $annotationReader = new AnnotationReader(); $types = $annotationReader->getSourceFields(new ReflectionClass(TestType::class)); @@ -177,7 +97,7 @@ public function testPhp8AttributeClassAnnotations(): void public function testPhp8AttributeMethodAnnotation(): void { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader()); + $annotationReader = new AnnotationReader(); $type = $annotationReader->getRequestAnnotation(new ReflectionMethod(TestType::class, 'getField'), Field::class); $this->assertInstanceOf(Field::class, $type); @@ -185,7 +105,7 @@ public function testPhp8AttributeMethodAnnotation(): void public function testPhp8AttributeMethodAnnotations(): void { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader()); + $annotationReader = new AnnotationReader(); $middlewareAnnotations = $annotationReader->getMiddlewareAnnotations(new ReflectionMethod(TestType::class, 'getField')); @@ -199,16 +119,16 @@ public function testPhp8AttributeMethodAnnotations(): void public function testPhp8AttributeParameterAnnotations(): void { - $annotationReader = new AnnotationReader(new DoctrineAnnotationReader()); + $annotationReader = new AnnotationReader(); - $parameterAnnotations = $annotationReader->getParameterAnnotationsPerParameter((new ReflectionMethod(__CLASS__, 'method1'))->getParameters()); + $parameterAnnotations = $annotationReader->getParameterAnnotationsPerParameter((new ReflectionMethod(self::class, 'method1'))->getParameters()); $this->assertInstanceOf(Autowire::class, $parameterAnnotations['dao']->getAnnotationByType(Autowire::class)); } private function method1( #[Autowire('myService')] - $dao + $dao, ): void { } } diff --git a/tests/Annotations/AutowireTest.php b/tests/Annotations/AutowireTest.php index acc8883e4f..9c68ffa332 100644 --- a/tests/Annotations/AutowireTest.php +++ b/tests/Annotations/AutowireTest.php @@ -11,7 +11,7 @@ class AutowireTest extends TestCase public function testException(): void { $this->expectException(BadMethodCallException::class); - $this->expectExceptionMessage('The @Autowire annotation must be passed a target. For instance: "@Autowire(for="$myService")"'); + $this->expectExceptionMessage('The #[Autowire] attribute must be passed a target. For instance: "#[Autowire(for: "$myService")]"'); (new Autowire([]))->getTarget(); } } diff --git a/tests/Annotations/DecorateTest.php b/tests/Annotations/DecorateTest.php index 083fff18d1..3015edbd4d 100644 --- a/tests/Annotations/DecorateTest.php +++ b/tests/Annotations/DecorateTest.php @@ -12,7 +12,7 @@ class DecorateTest extends TestCase public function testException(): void { $this->expectException(BadMethodCallException::class); - $this->expectExceptionMessage('The @Decorate annotation must be passed an input type. For instance: "@Decorate("MyInputType")"'); + $this->expectExceptionMessage('The #[Decorate] attribute must be passed an input type. For instance: "#[Decorate("MyInputType")]"'); new Decorate([]); } diff --git a/tests/Annotations/ExtendTypeTest.php b/tests/Annotations/ExtendTypeTest.php index 5530d7fa99..ab0d7627a3 100644 --- a/tests/Annotations/ExtendTypeTest.php +++ b/tests/Annotations/ExtendTypeTest.php @@ -11,7 +11,7 @@ class ExtendTypeTest extends TestCase public function testException(): void { $this->expectException(BadMethodCallException::class); - $this->expectExceptionMessage('In annotation @ExtendType, missing one of the compulsory parameter "class" or "name".'); + $this->expectExceptionMessage('In attribute #[ExtendType], missing one of the compulsory parameter "class" or "name".'); new ExtendType([]); } } diff --git a/tests/Annotations/FailWithTest.php b/tests/Annotations/FailWithTest.php index 79842c7029..468c9d73c7 100644 --- a/tests/Annotations/FailWithTest.php +++ b/tests/Annotations/FailWithTest.php @@ -12,7 +12,7 @@ class FailWithTest extends TestCase public function testException(): void { $this->expectException(BadMethodCallException::class); - $this->expectExceptionMessage('The @FailWith annotation must be passed a defaultValue. For instance: "@FailWith(null)"'); + $this->expectExceptionMessage('The #[FailWith] attribute must be passed a defaultValue. For instance: "#[FailWith(null)]"'); new FailWith([]); } diff --git a/tests/Annotations/RightTest.php b/tests/Annotations/RightTest.php index 4ca7fa86ed..0040e1061d 100644 --- a/tests/Annotations/RightTest.php +++ b/tests/Annotations/RightTest.php @@ -12,7 +12,7 @@ class RightTest extends TestCase public function testException(): void { $this->expectException(BadMethodCallException::class); - $this->expectExceptionMessage('The @Right annotation must be passed a right name. For instance: "@Right(\'my_right\')"'); + $this->expectExceptionMessage('The #[Right] attribute must be passed a right name. For instance: "#[Right(\'my_right\')]"'); new Right([]); } diff --git a/tests/Annotations/SecurityTest.php b/tests/Annotations/SecurityTest.php index 8ddafb5468..a35275092f 100644 --- a/tests/Annotations/SecurityTest.php +++ b/tests/Annotations/SecurityTest.php @@ -13,14 +13,14 @@ class SecurityTest extends TestCase public function testBadParams(): void { $this->expectException(BadMethodCallException::class); - $this->expectExceptionMessage('The @Security annotation must be passed an expression. For instance: "@Security("is_granted(\'CAN_EDIT_STUFF\')")"'); + $this->expectExceptionMessage('The #[Security] attribute must be passed an expression. For instance: "#[Security("is_granted(\'CAN_EDIT_STUFF\')")]"'); new Security([]); } public function testIncompatibleParams(): void { $this->expectException(BadMethodCallException::class); - $this->expectExceptionMessage('A @Security annotation that has "failWith" attribute set cannot have a message or a statusCode attribute.'); + $this->expectExceptionMessage('A #[Security] attribute that has "failWith" attribute set cannot have a message or a statusCode attribute.'); new Security(['expression'=>'foo', 'failWith'=>null, 'statusCode'=>500]); } } diff --git a/tests/Annotations/TypeTest.php b/tests/Annotations/TypeTest.php index a3909844b2..486befd85a 100644 --- a/tests/Annotations/TypeTest.php +++ b/tests/Annotations/TypeTest.php @@ -13,7 +13,7 @@ public function testException(): void { $type = new Type([]); $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('Empty class for @Type annotation. You MUST create the Type annotation object using the GraphQLite AnnotationReader'); + $this->expectExceptionMessage('Empty class for #[Type] attribute. You MUST create the Type attribute object using the GraphQLite AnnotationReader'); $type->getClass(); } @@ -27,7 +27,7 @@ public function testException2() { $type = new Type(['default'=>false]); $this->expectException(GraphQLRuntimeException::class); - $this->expectExceptionMessage('Problem in annotation @Type for interface "TheCodingMachine\GraphQLite\Fixtures\AnnotatedInterfaces\Types\FooInterface": you cannot use the default="false" attribute on interfaces'); + $this->expectExceptionMessage('Problem in attribute #[Type] for interface "TheCodingMachine\GraphQLite\Fixtures\AnnotatedInterfaces\Types\FooInterface": you cannot use the default="false" attribute on interfaces'); $type->setClass(FooInterface::class); } } diff --git a/tests/Annotations/UseInputTypeTest.php b/tests/Annotations/UseInputTypeTest.php index 47cb85b329..b2815ecdd2 100644 --- a/tests/Annotations/UseInputTypeTest.php +++ b/tests/Annotations/UseInputTypeTest.php @@ -12,14 +12,14 @@ class UseInputTypeTest extends TestCase public function testException(): void { $this->expectException(BadMethodCallException::class); - $this->expectExceptionMessage('The @UseInputType annotation must be passed an input type. For instance: #[UseInputType("MyInputType")]'); + $this->expectExceptionMessage('The #[UseInputType] attribute must be passed an input type. For instance: #[UseInputType("MyInputType")]'); new UseInputType([]); } public function testException2(): void { $this->expectException(BadMethodCallException::class); - $this->expectExceptionMessage('The @UseInputType annotation must be passed a target and an input type. For instance: #[UseInputType("MyInputType")]'); + $this->expectExceptionMessage('The #[UseInputType] attribute must be passed a target and an input type. For instance: #[UseInputType("MyInputType")]'); (new UseInputType(['inputType' => 'foo']))->getTarget(); } diff --git a/tests/FieldsBuilderTest.php b/tests/FieldsBuilderTest.php index 630b63c7bc..ffcc0b522f 100644 --- a/tests/FieldsBuilderTest.php +++ b/tests/FieldsBuilderTest.php @@ -1,5 +1,7 @@ assertInstanceOf(EnumType::class, $usersQuery->args[9]->getType()); $this->assertSame('TestObjectInput', $usersQuery->args[1]->getType()->getWrappedType()->getWrappedType()->getWrappedType()->name); - $context = ['int' => 42, 'string' => 'foo', 'list' => [ - ['test' => 42], - ['test' => 12], - ], + $context = [ + 'int' => 42, + 'string' => 'foo', + 'list' => [ + ['test' => '42'], + ['test' => '12'], + ], 'boolean' => true, 'float' => 4.2, 'dateTimeImmutable' => '2017-01-01 01:01:01', 'dateTime' => '2017-01-01 01:01:01', 'id' => 42, - 'enum' => TestEnum::ON() + 'enum' => TestEnum::ON(), ]; $resolve = $usersQuery->resolveFn; @@ -147,7 +153,7 @@ public function testMutations(): void $resolve = $testReturnMutation->resolveFn; $result = $resolve( new stdClass(), - ['testObject' => ['test' => 42]], + ['testObject' => ['test' => '42']], null, $this->createMock(ResolveInfo::class), ); @@ -179,10 +185,7 @@ public function testSubscriptions(): void public function testErrors(): void { $controller = new class { - /** - * @Query - * @return string - */ + #[Query] public function test($noTypeHint): string { return 'foo'; @@ -198,12 +201,8 @@ public function test($noTypeHint): string public function testTypeInDocBlock(): void { $controller = new class { - /** - * @Query - * @param int $typeHintInDocBlock - * @return string - */ - public function test($typeHintInDocBlock) + #[Query] + public function test(int $typeHintInDocBlock): string { return 'foo'; } @@ -344,7 +343,7 @@ public function isLogged(): bool return true; } - public function getUser(): ?object + public function getUser(): object|null { return new stdClass(); } @@ -360,16 +359,15 @@ public function getUser(): ?object $this->getParameterMiddlewarePipe(), new AuthorizationFieldMiddleware( $authenticationService, - new VoidAuthorizationService() + new VoidAuthorizationService(), ), - new InputFieldMiddlewarePipe() + new InputFieldMiddlewarePipe(), ); - $fields = $queryProvider->getFields(new TestType(), true); + $fields = $queryProvider->getFields(new TestType()); $this->assertCount(4, $fields); $this->assertSame('testBool', $fields['testBool']->name); - } public function testRightInSourceField(): void @@ -392,16 +390,15 @@ public function isAllowed(string $right, $subject = null): bool $this->getParameterMiddlewarePipe(), new AuthorizationFieldMiddleware( new VoidAuthenticationService(), - $authorizationService + $authorizationService, ), - new InputFieldMiddlewarePipe() + new InputFieldMiddlewarePipe(), ); - $fields = $queryProvider->getFields(new TestType(), true); + $fields = $queryProvider->getFields(new TestType()); $this->assertCount(4, $fields); $this->assertSame('testRight', $fields['testRight']->name); - } public function testMissingTypeAnnotation(): void @@ -409,7 +406,7 @@ public function testMissingTypeAnnotation(): void $queryProvider = $this->buildFieldsBuilder(); $this->expectException(MissingAnnotationException::class); - $queryProvider->getFields(new TestTypeMissingAnnotation(), true); + $queryProvider->getFields(new TestTypeMissingAnnotation()); } public function testSourceFieldDoesNotExists(): void @@ -417,8 +414,8 @@ public function testSourceFieldDoesNotExists(): void $queryProvider = $this->buildFieldsBuilder(); $this->expectException(FieldNotFoundException::class); - $this->expectExceptionMessage("There is an issue with a @SourceField annotation in class \"TheCodingMachine\GraphQLite\Fixtures\TestTypeMissingField\": Could not find a getter or a isser for field \"notExists\". Looked for: \"TheCodingMachine\GraphQLite\Fixtures\TestObject::notExists()\", \"TheCodingMachine\GraphQLite\Fixtures\TestObject::getNotExists()\", \"TheCodingMachine\GraphQLite\Fixtures\TestObject::isNotExists()"); - $queryProvider->getFields(new TestTypeMissingField(), true); + $this->expectExceptionMessage('There is an issue with a @SourceField annotation in class "TheCodingMachine\GraphQLite\Fixtures\TestTypeMissingField": Could not find a getter or a isser for field "notExists". Looked for: "TheCodingMachine\GraphQLite\Fixtures\TestObject::notExists()", "TheCodingMachine\GraphQLite\Fixtures\TestObject::getNotExists()", "TheCodingMachine\GraphQLite\Fixtures\TestObject::isNotExists()'); + $queryProvider->getFields(new TestTypeMissingField()); } public function testSourceFieldHasMissingReturnType(): void @@ -427,13 +424,13 @@ public function testSourceFieldHasMissingReturnType(): void $this->expectException(CannotMapTypeException::class); $this->expectExceptionMessage('For return type of TheCodingMachine\GraphQLite\Fixtures\TestObjectMissingReturnType::getTest, a type-hint is missing (or PHPDoc specifies a "mixed" type-hint). Please provide a better type-hint.'); - $queryProvider->getFields(new TestTypeMissingReturnType(), true); + $queryProvider->getFields(new TestTypeMissingReturnType()); } public function testSourceFieldIsId(): void { $queryProvider = $this->buildFieldsBuilder(); - $fields = $queryProvider->getFields(new TestTypeId(), true); + $fields = $queryProvider->getFields(new TestTypeId()); $this->assertCount(1, $fields); $this->assertSame('test', $fields['test']->name); @@ -454,15 +451,14 @@ public function testFromSourceFieldsInterface(): void $this->getParameterMiddlewarePipe(), new AuthorizationFieldMiddleware( new VoidAuthenticationService(), - new VoidAuthorizationService() + new VoidAuthorizationService(), ), - new InputFieldMiddlewarePipe() + new InputFieldMiddlewarePipe(), ); - $fields = $queryProvider->getFields(new TestTypeWithSourceFieldInterface(), true); + $fields = $queryProvider->getFields(new TestTypeWithSourceFieldInterface()); $this->assertCount(1, $fields); $this->assertSame('test', $fields['test']->name); - } public function testQueryProviderWithIterableClass(): void @@ -571,7 +567,7 @@ public function testQueryProviderWithInvalidInputType(): void $queryProvider = $this->buildFieldsBuilder(); $this->expectException(CannotMapTypeException::class); - $this->expectExceptionMessage('For parameter $foo, in TheCodingMachine\GraphQLite\Fixtures\TestControllerWithInvalidInputType::test, cannot map class "Exception" to a known GraphQL input type. Are you missing a @Factory annotation? If you have a @Factory annotation, is it in a namespace analyzed by GraphQLite?'); + $this->expectExceptionMessage('For parameter $foo, in TheCodingMachine\GraphQLite\Fixtures\TestControllerWithInvalidInputType::test, cannot map class "Throwable" to a known GraphQL input type. Are you missing a @Factory annotation? If you have a @Factory annotation, is it in a namespace analyzed by GraphQLite?'); $queryProvider->getQueries($controller); } @@ -657,14 +653,13 @@ public function testSourceFieldWithFailWith(): void $queryProvider = $this->buildFieldsBuilder(); - $fields = $queryProvider->getFields($controller, true); + $fields = $queryProvider->getFields($controller); $this->assertCount(1, $fields); $this->assertSame('test', $fields['test']->name); $this->assertInstanceOf(StringType::class, $fields['test']->getType()); - $resolve = $fields['test']->resolveFn; $result = $resolve(new stdClass(), [], null, $this->createMock(ResolveInfo::class)); @@ -678,7 +673,7 @@ public function testSourceFieldBadOutputTypeException(): void $queryProvider = $this->buildFieldsBuilder(); $this->expectException(CannotMapTypeExceptionInterface::class); $this->expectExceptionMessage('For @SourceField "test" declared in "TheCodingMachine\GraphQLite\Fixtures\TestSourceFieldBadOutputType", cannot find GraphQL type "[NotExists]". Check your TypeMapper configuration.'); - $queryProvider->getFields(new TestSourceFieldBadOutputType(), true); + $queryProvider->getFields(new TestSourceFieldBadOutputType()); } public function testSourceFieldBadOutputType2Exception(): void @@ -686,7 +681,7 @@ public function testSourceFieldBadOutputType2Exception(): void $queryProvider = $this->buildFieldsBuilder(); $this->expectException(CannotMapTypeExceptionInterface::class); $this->expectExceptionMessage('For @SourceField "test" declared in "TheCodingMachine\GraphQLite\Fixtures\TestSourceFieldBadOutputType2", Syntax Error: Expected ], found '); - $queryProvider->getFields(new TestSourceFieldBadOutputType2(), true); + $queryProvider->getFields(new TestSourceFieldBadOutputType2()); } public function testBadOutputTypeException(): void @@ -694,7 +689,7 @@ public function testBadOutputTypeException(): void $queryProvider = $this->buildFieldsBuilder(); $this->expectException(CannotMapTypeExceptionInterface::class); $this->expectExceptionMessage('For return type of TheCodingMachine\GraphQLite\Fixtures\TestFieldBadOutputType::test, cannot find GraphQL type "[NotExists]". Check your TypeMapper configuration.'); - $queryProvider->getFields(new TestFieldBadOutputType(), true); + $queryProvider->getFields(new TestFieldBadOutputType()); } public function testBadInputTypeException(): void @@ -702,7 +697,7 @@ public function testBadInputTypeException(): void $queryProvider = $this->buildFieldsBuilder(); $this->expectException(CannotMapTypeExceptionInterface::class); $this->expectExceptionMessage('For parameter $input, in TheCodingMachine\GraphQLite\Fixtures\TestFieldBadInputType::testInput, cannot find GraphQL type "[NotExists]". Check your TypeMapper configuration.'); - $queryProvider->getFields(new TestFieldBadInputType(), true); + $queryProvider->getFields(new TestFieldBadInputType()); } public function testDoubleReturnException(): void @@ -710,7 +705,7 @@ public function testDoubleReturnException(): void $queryProvider = $this->buildFieldsBuilder(); $this->expectException(InvalidDocBlockRuntimeException::class); $this->expectExceptionMessage('Method TheCodingMachine\\GraphQLite\\Fixtures\\TestDoubleReturnTag::test has several @return annotations.'); - $queryProvider->getFields(new TestDoubleReturnTag(), true); + $queryProvider->getFields(new TestDoubleReturnTag()); } public function testMissingArgument(): void @@ -855,17 +850,6 @@ public function testQueryProviderWithUnionInputParam(): void $queries = $queryProvider->getQueries($controller); } - public function testParameterAnnotationOnNonExistingParameter(): void - { - $controller = new TestControllerWithInvalidParameterAnnotation(); - - $queryProvider = $this->buildFieldsBuilder(); - - $this->expectException(InvalidParameterException::class); - $this->expectExceptionMessage('Parameter "id" declared in annotation "TheCodingMachine\\GraphQLite\\Annotations\\HideParameter" of method "TheCodingMachine\\GraphQLite\\Fixtures\\TestControllerWithInvalidParameterAnnotation::test()" does not exist.'); - $queries = $queryProvider->getQueries($controller); - } - public function testParameterAnnotationOnNonExistingParameterInSourceField(): void { $controller = new TestTypeWithSourceFieldInvalidParameterAnnotation(); @@ -873,7 +857,7 @@ public function testParameterAnnotationOnNonExistingParameterInSourceField(): vo $queryProvider = $this->buildFieldsBuilder(); $this->expectException(InvalidParameterException::class); - $this->expectExceptionMessage('Could not find parameter "foo" declared in annotation "TheCodingMachine\\GraphQLite\\Annotations\\HideParameter". This annotation is itself declared in a SourceField annotation targeting resolver "TheCodingMachine\\GraphQLite\\Fixtures\\TestObject::getSibling()".'); + $this->expectExceptionMessage('Could not find parameter "foo" declared in annotation "TheCodingMachine\\GraphQLite\\Annotations\\HideParameter". This annotation is itself declared in a SourceField attribute targeting resolver "TheCodingMachine\\GraphQLite\\Fixtures\\TestObject::getSibling()".'); $fields = $queryProvider->getFields($controller); } diff --git a/tests/Fixtures/AbstractTestController.php b/tests/Fixtures/AbstractTestController.php index deb15c2d81..f4042a198b 100644 --- a/tests/Fixtures/AbstractTestController.php +++ b/tests/Fixtures/AbstractTestController.php @@ -8,9 +8,7 @@ // An abstract class to test that the GlobControllerQueryProvider does not try anything with it. abstract class AbstractTestController { - /** - * @Query() - */ + #[Query] public function test(): string { return 'foo'; diff --git a/tests/Fixtures/AnnotatedInterfaces/Controllers/AnnotatedInterfaceController.php b/tests/Fixtures/AnnotatedInterfaces/Controllers/AnnotatedInterfaceController.php index f93611fe16..4b0970ba1e 100644 --- a/tests/Fixtures/AnnotatedInterfaces/Controllers/AnnotatedInterfaceController.php +++ b/tests/Fixtures/AnnotatedInterfaces/Controllers/AnnotatedInterfaceController.php @@ -15,17 +15,13 @@ class AnnotatedInterfaceController { - /** - * @Query() - */ + #[Query] public function getClassA(): ClassA { return new ClassA(); } - /** - * @Query() - */ + #[Query] public function getFoo(): FooInterface { return new ClassD(); @@ -39,17 +35,13 @@ public function getFoo(): FooInterface return new ClassD(); }*/ - /** - * @Query() - */ + #[Query] public function getClassDAsWizInterface(): WizzInterface { return new ClassD(); } - /** - * @Query() - */ + #[Query] public function getQux(): QuxInterface { return new NotAnnotatedQux(); diff --git a/tests/Fixtures/AnnotatedInterfaces/Types/BarInterface.php b/tests/Fixtures/AnnotatedInterfaces/Types/BarInterface.php index b4f9ea3ccf..ade2792985 100644 --- a/tests/Fixtures/AnnotatedInterfaces/Types/BarInterface.php +++ b/tests/Fixtures/AnnotatedInterfaces/Types/BarInterface.php @@ -1,19 +1,15 @@ circularInputB = $circularInputB; } - /** - * @Field - */ - public function setBar(int $bar): void { + #[Field] + public function setBar(int $bar): void + { $this->bar = $bar; } - /** - * @return CircularInputB - */ - public function getCircularInputB() + public function getCircularInputB(): CircularInputB { return $this->circularInputB; } - /** - * @return int - */ public function getBar(): int { return $this->bar; diff --git a/tests/Fixtures/CircularInputReference/Types/CircularInputB.php b/tests/Fixtures/CircularInputReference/Types/CircularInputB.php index aaedad7775..eb5f4f793d 100644 --- a/tests/Fixtures/CircularInputReference/Types/CircularInputB.php +++ b/tests/Fixtures/CircularInputReference/Types/CircularInputB.php @@ -1,48 +1,36 @@ circularInputA = $circularInputA; } - /** - * @Field - */ - public function setBar(int $bar): void { + #[Field] + public function setBar(int $bar): void + { $this->bar = $bar; } - /** - * @return CircularInputA - */ public function getCircularInputA() { return $this->circularInputA; } - /** - * @return int - */ public function getBar(): int { return $this->bar; diff --git a/tests/Fixtures/DuplicateInputTypes/TestFactory.php b/tests/Fixtures/DuplicateInputTypes/TestFactory.php index 6fe81dd275..5072bd8288 100644 --- a/tests/Fixtures/DuplicateInputTypes/TestFactory.php +++ b/tests/Fixtures/DuplicateInputTypes/TestFactory.php @@ -1,20 +1,15 @@ value = $value; } - /** - * @Field() - */ + #[Field] public function getValue(): string { return $this->value; } - /** - * @Factory(name="InAndOut") - */ + #[Factory(name: 'InAndOut')] public static function create(string $value): self { return new self($value); diff --git a/tests/Fixtures/Inputs/FooBar.php b/tests/Fixtures/Inputs/FooBar.php index ff76408377..56fa07db42 100644 --- a/tests/Fixtures/Inputs/FooBar.php +++ b/tests/Fixtures/Inputs/FooBar.php @@ -1,46 +1,32 @@ foo = $foo; $this->bar = $bar; diff --git a/tests/Fixtures/Inputs/InputInterface.php b/tests/Fixtures/Inputs/InputInterface.php index 744299c5f5..f307cf916c 100644 --- a/tests/Fixtures/Inputs/InputInterface.php +++ b/tests/Fixtures/Inputs/InputInterface.php @@ -1,12 +1,12 @@ foo = $foo; } - /** - * @Field(for="InputWithSetterInput") - * @Field(for="ForcedTypeInput", inputType="Int!") - */ - public function setBar(int $bar): void { + #[Field(for: 'InputWithSetterInput')] + #[Field(for: 'ForcedTypeInput', inputType: 'Int!')] + public function setBar(int $bar): void + { $this->bar = $bar; } - /** - * @return string - */ public function getFoo(): string { return $this->foo; } - /** - * @return int - */ public function getBar(): int { return $this->bar; diff --git a/tests/Fixtures/Inputs/TestConstructorAndProperties.php b/tests/Fixtures/Inputs/TestConstructorAndProperties.php index 82647c91ad..57243d4926 100644 --- a/tests/Fixtures/Inputs/TestConstructorAndProperties.php +++ b/tests/Fixtures/Inputs/TestConstructorAndProperties.php @@ -1,49 +1,40 @@ date = $date; $this->foo = $foo; } - public function getDate(): \DateTimeImmutable + public function getDate(): DateTimeImmutable { return $this->date; } public function setFoo(string $foo): void { - throw new \RuntimeException("This should not be called"); + throw new RuntimeException('This should not be called'); } public function getFoo(): string diff --git a/tests/Fixtures/Inputs/TestOnlyConstruct.php b/tests/Fixtures/Inputs/TestOnlyConstruct.php index d4a0ecbf83..e01be70029 100644 --- a/tests/Fixtures/Inputs/TestOnlyConstruct.php +++ b/tests/Fixtures/Inputs/TestOnlyConstruct.php @@ -1,36 +1,26 @@ foo = $foo; $this->bar = $bar; @@ -46,7 +36,7 @@ public function setBar(int $bar): void { throw new Exception('This should not be called!'); } - + public function setBaz(bool $baz): void { throw new Exception('This should not be called!'); diff --git a/tests/Fixtures/Inputs/TypedFooBar.php b/tests/Fixtures/Inputs/TypedFooBar.php index 770eb24fd9..d04e92c481 100644 --- a/tests/Fixtures/Inputs/TypedFooBar.php +++ b/tests/Fixtures/Inputs/TypedFooBar.php @@ -1,23 +1,18 @@ new Contact('Joe'), 'Bill' => new Contact('Bill'), default => null, @@ -43,16 +42,15 @@ public function saveContact(Contact $contact): Contact } #[Mutation] - public function saveBirthDate(\DateTimeInterface $birthDate): Contact { + public function saveBirthDate(DateTimeInterface $birthDate): Contact + { $contact = new Contact('Bill'); $contact->setBirthDate($birthDate); return $contact; } - /** - * @return Contact[] - */ + /** @return Contact[] */ #[Query] public function getContactsIterator(): ArrayResult { @@ -62,9 +60,7 @@ public function getContactsIterator(): ArrayResult ]); } - /** - * @return string[]|ArrayResult - */ + /** @return string[]|ArrayResult */ #[Query] public function getContactsNamesIterator(): ArrayResult { @@ -86,7 +82,7 @@ public function getOtherContact(): Contact * @return Result|Contact[]|null */ #[Query] - public function getNullableResult(): ?Result + public function getNullableResult(): Result|null { return null; } diff --git a/tests/Fixtures/Integration/Controllers/FilterController.php b/tests/Fixtures/Integration/Controllers/FilterController.php index 9c027cf6ad..abb7ee2e57 100644 --- a/tests/Fixtures/Integration/Controllers/FilterController.php +++ b/tests/Fixtures/Integration/Controllers/FilterController.php @@ -1,30 +1,29 @@ getValues()); + return array_map(static function ($item) { + return (string) $item; + }, $filter->getValues()); } - /** - * @Query() - * @return string[]|null - */ - public function echoNullableFilters(?Filter $filter): ?array + /** @return string[]|null */ + #[Query] + public function echoNullableFilters(Filter|null $filter): array|null { if ($filter === null) { return null; @@ -32,10 +31,7 @@ public function echoNullableFilters(?Filter $filter): ?array return $this->echoFilters($filter); } - /** - * @Query() - * @return string - */ + #[Query] public function echoResolveInfo(ResolveInfo $info): string { return $info->fieldName; diff --git a/tests/Fixtures/Integration/Controllers/PostController.php b/tests/Fixtures/Integration/Controllers/PostController.php index 1390069187..8df4ae2179 100644 --- a/tests/Fixtures/Integration/Controllers/PostController.php +++ b/tests/Fixtures/Integration/Controllers/PostController.php @@ -10,26 +10,28 @@ class PostController { /** - * @Mutation() * @param Post $post * * @return Post */ + #[Mutation] public function createPost(Post $post): Post { return $post; } /** - * @Mutation() - * @UseInputType(for="$post", inputType="UpdatePostInput") * * @param int $id * @param Post $post * * @return Post */ - public function updatePost(int $id, Post $post): Post + #[Mutation] + public function updatePost( + int $id, + #[UseInputType('UpdatePostInput')] + Post $post): Post { $post->id = $id; diff --git a/tests/Fixtures/Integration/Controllers/PreferencesController.php b/tests/Fixtures/Integration/Controllers/PreferencesController.php index a31f21900b..599ec12b4c 100644 --- a/tests/Fixtures/Integration/Controllers/PreferencesController.php +++ b/tests/Fixtures/Integration/Controllers/PreferencesController.php @@ -8,11 +8,11 @@ class PreferencesController { /** - * @Mutation() * @param Preferences $preferences * * @return Preferences */ + #[Mutation] public function updatePreferences(Preferences $preferences): Preferences { return $preferences; diff --git a/tests/Fixtures/Integration/Controllers/ProductController.php b/tests/Fixtures/Integration/Controllers/ProductController.php index 75779b10ca..65b1c42408 100644 --- a/tests/Fixtures/Integration/Controllers/ProductController.php +++ b/tests/Fixtures/Integration/Controllers/ProductController.php @@ -1,16 +1,15 @@ setName("Special","box"); + $product->setName('Special', 'box'); $product->price = 11.99; $product->multi = 11.11; return $product; } - /** - * @Mutation() - * @UseInputType(for="$product", inputType="UpdateTrickyProductInput!") - * - * @param TrickyProduct $product - * @return TrickyProduct - */ - public function updateTrickyProduct(TrickyProduct $product): TrickyProduct + #[Mutation] + public function updateTrickyProduct( + #[UseInputType('UpdateTrickyProductInput!')] + TrickyProduct $product, + ): TrickyProduct { return $product; } diff --git a/tests/Fixtures/Integration/Controllers/SecurityController.php b/tests/Fixtures/Integration/Controllers/SecurityController.php index 27c09b7b03..47c9dc294e 100644 --- a/tests/Fixtures/Integration/Controllers/SecurityController.php +++ b/tests/Fixtures/Integration/Controllers/SecurityController.php @@ -1,82 +1,65 @@ bar; } diff --git a/tests/Fixtures/Integration/Models/Article.php b/tests/Fixtures/Integration/Models/Article.php index 0cf0f3a80d..49d914bc0e 100644 --- a/tests/Fixtures/Integration/Models/Article.php +++ b/tests/Fixtures/Integration/Models/Article.php @@ -6,22 +6,15 @@ use TheCodingMachine\GraphQLite\Annotations\Input; use TheCodingMachine\GraphQLite\Annotations\Type; -/** - * @Type() - * @Input() - */ + +#[Type, Input] class Article extends Post { - /** - * @Field(for="Article") - * @var int - */ - public $id = 2; - /** - * @Field() - * @var string|null - */ - public $magazine = null; + #[Field(for: "Article")] + public int $id = 2; + + #[Field] + public ?string $magazine = null; } diff --git a/tests/Fixtures/Integration/Models/Button.php b/tests/Fixtures/Integration/Models/Button.php index 4685ac00a3..0e1a024caa 100644 --- a/tests/Fixtures/Integration/Models/Button.php +++ b/tests/Fixtures/Integration/Models/Button.php @@ -7,52 +7,26 @@ use TheCodingMachine\GraphQLite\Annotations\Field; use TheCodingMachine\GraphQLite\Annotations\Type; -/** - * @Type - */ +#[Type] class Button { - /** - * @var Color - */ - private $color; - - /** - * @var Size - */ - private $size; - - /** - * @var Position - */ - private $state; - - public function __construct(Color $color, Size $size, Position $state) + public function __construct(private Color $color, private Size $size, private Position $state) { - $this->color = $color; - $this->size = $size; - $this->state = $state; } - /** - * @Field - */ + #[Field] public function getColor(): Color { return $this->color; } - /** - * @Field - */ + #[Field] public function getSize(): Size { return $this->size; } - /** - * @Field - */ + #[Field] public function getState(): Position { return $this->state; diff --git a/tests/Fixtures/Integration/Models/Contact.php b/tests/Fixtures/Integration/Models/Contact.php index 58d12549dd..6fdc1f344d 100644 --- a/tests/Fixtures/Integration/Models/Contact.php +++ b/tests/Fixtures/Integration/Models/Contact.php @@ -1,122 +1,72 @@ name = $name; } public function getName() @@ -124,70 +74,49 @@ public function getName() return $this->name; } - /** - * @deprecated use field `name` - */ + /** @deprecated use field `name` */ public function getDeprecatedName() { return $this->name; } - public function getManager(): ?Contact + public function getManager(): Contact|null { return $this->manager; } - /** - * @param Contact|null $manager - */ - public function setManager(?Contact $manager): void + public function setManager(Contact|null $manager): void { $this->manager = $manager; } - /** - * @return Contact[] - */ + /** @return Contact[] */ public function getRelations(): array { return $this->relations; } - /** - * @param Contact[] $relations - */ + /** @param Contact[] $relations */ public function setRelations(array $relations): void { $this->relations = $relations; } - /** - * @return UploadedFileInterface - */ public function getPhoto(): UploadedFileInterface { return $this->photo; } - /** - * @param UploadedFileInterface $photo - */ public function setPhoto(UploadedFileInterface $photo): void { $this->photo = $photo; } - /** - * @return DateTimeInterface - */ - public function getBirthDate() + public function getBirthDate(): DateTimeInterface { return $this->birthDate; } - /** - * @param DateTimeInterface $birthDate - */ public function setBirthDate(DateTimeInterface $birthDate): void { $this->birthDate = $birthDate; @@ -195,31 +124,25 @@ public function setBirthDate(DateTimeInterface $birthDate): void /** * This getter will be overridden in the extend class. - * - * @Field() - * @return string */ + #[Field] public function getCompany(): string { return $this->company; } - /** - * @param string $company - */ public function setCompany(string $company): void { $this->company = $company; } - /** - * @Field() - */ - public function repeatInnerName(#[Prefetch('prefetchTheContacts')] $data): string + #[Field] + public function repeatInnerName(#[Prefetch('prefetchTheContacts')] + $data,): string { $index = array_search($this, $data, true); if ($index === false) { - throw new \RuntimeException('Index not found'); + throw new RuntimeException('Index not found'); } return $data[$index]->getName(); } @@ -229,76 +152,60 @@ public static function prefetchTheContacts(iterable $contacts) return $contacts; } - /** - * @Field() - * @Logged() - * @return string - */ + #[Field] + + #[Logged] public function onlyLogged(): string { return 'you can see this only if you are logged'; } - /** - * @Field() - * @Right(name="CAN_SEE_SECRET") - * @return string - */ + #[Field] + + #[Right('CAN_SEE_SECRET')] public function secret(): string { return 'you can see this only if you have the good right'; } - /** - * @return int - */ public function getAge(): int { return $this->age; } - /** - * @return string - */ public function getStatus(): string { return 'bar'; } - /** - * @return string - */ public function getZipcode(string $foo): string { return $this->zipcode; } - /** - * @return string - */ private function getAddress(): string { return $this->address; } - /** - * @Field() - * @Autowire(for="testService", identifier="testService") - * @Autowire(for="$otherTestService") - * @return string - */ - public function injectService(string $testService, stdClass $otherTestService = null): string + #[Field] + public function injectService( + #[Autowire(identifier: 'testService')] + string $testService, + #[Autowire] + stdClass|null $otherTestService = null, + ): string { if ($testService !== 'foo') { return 'KO'; } - if (!$otherTestService instanceof stdClass) { + if (! $otherTestService instanceof stdClass) { return 'KO'; } return 'OK'; } - public function injectServiceFromExternal(string $testService, string $testSkip = "foo", string $id = '42'): string + public function injectServiceFromExternal(string $testService, string $testSkip = 'foo', string $id = '42'): string { if ($testService !== 'foo') { return 'KO'; diff --git a/tests/Fixtures/Integration/Models/Filter.php b/tests/Fixtures/Integration/Models/Filter.php index e482c7e3fe..0acf5dab20 100644 --- a/tests/Fixtures/Integration/Models/Filter.php +++ b/tests/Fixtures/Integration/Models/Filter.php @@ -34,8 +34,8 @@ public function mergeValues(array $values): void /** * @param string[] $values * - * @Factory() */ + #[Factory] public static function create(array $values = []): self { return new self($values); diff --git a/tests/Fixtures/Integration/Models/Post.php b/tests/Fixtures/Integration/Models/Post.php index ae91b13ae0..758931f447 100644 --- a/tests/Fixtures/Integration/Models/Post.php +++ b/tests/Fixtures/Integration/Models/Post.php @@ -1,5 +1,7 @@ title = $title; $this->description = 'bar'; } - /** - * @return string|null - */ - public function getDescription(): ?string + public function getDescription(): string|null { return $this->description; } - /** - * @param string|null $description - */ - public function setDescription(?string $description): void + public function setDescription(string|null $description): void { $this->description = $description; } - /** - * @param string|null $summary - */ - public function setSummary(?string $summary): void + public function setSummary(string|null $summary): void { $this->summary = $summary; } - /** - * @param string $inaccessible - */ private function setInaccessible(string $inaccessible): void { $this->inaccessible = $inaccessible; diff --git a/tests/Fixtures/Integration/Models/Preferences.php b/tests/Fixtures/Integration/Models/Preferences.php index 9f37a247cd..499190a235 100644 --- a/tests/Fixtures/Integration/Models/Preferences.php +++ b/tests/Fixtures/Integration/Models/Preferences.php @@ -7,35 +7,23 @@ use TheCodingMachine\GraphQLite\Annotations\Input; use TheCodingMachine\GraphQLite\Annotations\Type; -/** - * @Type() - * @Input() - */ +#[Type, Input] class Preferences { - /** - * @Field(inputType="Int!") - * @var int - */ - private $id; + #[Field(inputType: "Int!")] + private int $id; /** - * @Field(inputType="[String!]!") * @var string[] */ - private $options; + #[Field(inputType: "[String!]!")] + private array $options; - /** - * @Field(inputType="Boolean!") - * @var bool - */ - private $enabled; + #[Field(inputType: "Boolean!")] + private bool $enabled; - /** - * @Field(inputType="String!") - * @var string - */ - private $name; + #[Field(inputType: "String!")] + private string $name; public function __construct(int $id, array $options, bool $enabled, string $name) { diff --git a/tests/Fixtures/Integration/Models/Product.php b/tests/Fixtures/Integration/Models/Product.php index e9479c3d90..ee98fc610f 100644 --- a/tests/Fixtures/Integration/Models/Product.php +++ b/tests/Fixtures/Integration/Models/Product.php @@ -1,11 +1,9 @@ name = $name; - $this->price = $price; - $this->type = $type; } - /** - * @Field(name="name") - * @return string - */ + #[Field(name: 'name')] public function getName(): string { return $this->name; } - /** - * @Field() - * @return float - */ + #[Field] public function getPrice(): float { return $this->price; } - /** - * @Field() - * @Right("YOU_DONT_HAVE_THIS_RIGHT") - * @FailWith(null) - * @return string - */ + #[Field] + #[Right('YOU_DONT_HAVE_THIS_RIGHT')] + #[FailWith(null)] public function getUnauthorized(): string { return 'You are not allowed to see this'; } - /** - * @return ProductTypeEnum - */ public function getType(): ProductTypeEnum { return $this->type; } - /** - * @Factory() - * @return Product - */ - public static function create(string $name, float $price, ProductTypeEnum $type = null): self + #[Factory] + public static function create(string $name, float $price, ProductTypeEnum|null $type = null): self { return new self($name, $price, $type); } - /** - * @Field() - * @Security("this.isAllowed(secret)") - */ + #[Field] + #[Security(expression: 'this.isAllowed(secret)')] public function getMargin(string $secret): float { return 12.0; diff --git a/tests/Fixtures/Integration/Models/ProductTypeEnum.php b/tests/Fixtures/Integration/Models/ProductTypeEnum.php index 6bc1983700..57cd6f2d2e 100644 --- a/tests/Fixtures/Integration/Models/ProductTypeEnum.php +++ b/tests/Fixtures/Integration/Models/ProductTypeEnum.php @@ -4,10 +4,7 @@ use MyCLabs\Enum\Enum; use TheCodingMachine\GraphQLite\Annotations\EnumType; - -/** - * @EnumType(name="ProductTypes") - */ +#[EnumType(name: "ProductTypes")] class ProductTypeEnum extends Enum { const FOOD = 'food'; diff --git a/tests/Fixtures/Integration/Models/SpecialProduct.php b/tests/Fixtures/Integration/Models/SpecialProduct.php index 7c78ce908f..bf162ccc51 100644 --- a/tests/Fixtures/Integration/Models/SpecialProduct.php +++ b/tests/Fixtures/Integration/Models/SpecialProduct.php @@ -1,57 +1,34 @@ name = $name; - $this->price = $price; } - /** - * @Field() - * @return string - */ + #[Field] public function getSpecial(): string { - return "unicorn"; + return 'unicorn'; } - /** - * @Field() - * @return string - */ + #[Field] public function getName(): string { return $this->name; } - /** - * @Field() - * @return float - */ + #[Field] public function getPrice(): float { return $this->price; } -} \ No newline at end of file +} diff --git a/tests/Fixtures/Integration/Models/TrickyProduct.php b/tests/Fixtures/Integration/Models/TrickyProduct.php index 203cefda58..4003568168 100644 --- a/tests/Fixtures/Integration/Models/TrickyProduct.php +++ b/tests/Fixtures/Integration/Models/TrickyProduct.php @@ -1,123 +1,86 @@ name; } - /** - * @return float - */ public function getPrice(): float { return $this->price; } - /** - * @Field() - * @Autowire(for="testService", identifier="testService") - * @param string $name - * @param string $testService - * @return void - */ - public function setName(string $name, string $testService): void + #[Field] + public function setName( + string $name, + #[Autowire(identifier: 'testService')] + string $testService, + ): void { - $this->name = $name . " " . $testService; + $this->name = $name . ' ' . $testService; } - /** - * @Field() - * @Right("CAN_SEE_SECRET") - * @return string - */ + #[Field] + + #[Right('CAN_SEE_SECRET')] public function getSecret(): string { return $this->secret; } - /** - * @Field() - * @Right("CAN_SET_SECRET") - * @param string $secret - */ + #[Field] + + #[Right('CAN_SEE_SECRET')] public function setSecret(string $secret): void { $this->secret = $secret; } - /** - * @Field() - * @Security("conditionalSecret == 'actually{secret}'") - * @Security("user && user.bar == 42") - * @param string $conditionalSecret - */ + #[Field] + #[Security("conditionalSecret == 'actually{secret}'")] + #[Security('user && user.bar == 42')] public function setConditionalSecret(string $conditionalSecret): void { $this->conditionalSecret = $conditionalSecret; } - /** - * @Field() - * @Security("this.isAllowed(key)") - */ + #[Field] + #[Security('this.isAllowed(key)')] public function getConditionalSecret(int $key): string { return $this->conditionalSecret; @@ -127,4 +90,4 @@ public function isAllowed(string $conditionalSecret): bool { return $conditionalSecret === '1234'; } -} \ No newline at end of file +} diff --git a/tests/Fixtures/Integration/Models/User.php b/tests/Fixtures/Integration/Models/User.php index f4ca921770..82bd2303be 100644 --- a/tests/Fixtures/Integration/Models/User.php +++ b/tests/Fixtures/Integration/Models/User.php @@ -1,31 +1,21 @@ email = $email; } - /** - * @Field(name="email") - * @return string - */ + #[Field] public function getEmail(): string { return $this->email; diff --git a/tests/Fixtures/Integration/Types/ContactFactory.php b/tests/Fixtures/Integration/Types/ContactFactory.php index 782394bdd4..e3802f503a 100644 --- a/tests/Fixtures/Integration/Types/ContactFactory.php +++ b/tests/Fixtures/Integration/Types/ContactFactory.php @@ -1,9 +1,9 @@ getName()); diff --git a/tests/Fixtures/Integration/Types/ContactType.php b/tests/Fixtures/Integration/Types/ContactType.php index 33ff5449f9..2881e50ccf 100644 --- a/tests/Fixtures/Integration/Types/ContactType.php +++ b/tests/Fixtures/Integration/Types/ContactType.php @@ -1,70 +1,65 @@ getName()); + return $prefix . ' ' . strtoupper($contact->getName()); } - /** - * @Field() - */ - public function repeatName(Contact $contact, #[Prefetch('prefetchContacts')] $data, string $suffix): string + #[Field] + public function repeatName(Contact $contact, #[Prefetch('prefetchContacts')] + $data, string $suffix,): string { $index = array_search($contact, $data['contacts'], true); if ($index === false) { - throw new \RuntimeException('Index not found'); + throw new RuntimeException('Index not found'); } - return $data['prefix'].$data['contacts'][$index]->getName().$suffix; + return $data['prefix'] . $data['contacts'][$index]->getName() . $suffix; } public static function prefetchContacts(iterable $contacts, string $prefix) { return [ 'contacts' => $contacts, - 'prefix' => $prefix + 'prefix' => $prefix, ]; } - /** - * - * @return Post[]|null - */ + /** @return Post[]|null */ #[Field] public function getPosts( Contact $contact, #[Prefetch('prefetchPosts')] - $posts - ): ?array { + $posts, + ): array|null { return $posts[$contact->getName()] ?? null; } @@ -74,10 +69,10 @@ public static function prefetchPosts(iterable $contacts): array foreach ($contacts as $contact) { $contactPost = array_filter( self::getContactPosts(), - fn(Post $post) => $post->author?->getName() === $contact->getName() + static fn (Post $post) => $post->author?->getName() === $contact->getName(), ); - if (!$contactPost) { + if (! $contactPost) { continue; } @@ -90,15 +85,15 @@ public static function prefetchPosts(iterable $contacts): array private static function getContactPosts(): array { return [ - self::generatePost('First Joe post', '1', new Contact('Joe')), - self::generatePost('First Bill post', '2', new Contact('Bill')), - self::generatePost('First Kate post', '3', new Contact('Kate')), + self::generatePost('First Joe post', 1, new Contact('Joe')), + self::generatePost('First Bill post', 2, new Contact('Bill')), + self::generatePost('First Kate post', 3, new Contact('Kate')), ]; } private static function generatePost( string $title, - string $id, + int $id, Contact $author, ): Post { $post = new Post($title); diff --git a/tests/Fixtures/Integration/Types/ExtendedContactOtherType.php b/tests/Fixtures/Integration/Types/ExtendedContactOtherType.php index 483689ffde..264f1babc5 100644 --- a/tests/Fixtures/Integration/Types/ExtendedContactOtherType.php +++ b/tests/Fixtures/Integration/Types/ExtendedContactOtherType.php @@ -1,27 +1,21 @@ getName()); } - /** - * @Field() - * @deprecated use field `uppercaseName` - */ + /** @deprecated use field `uppercaseName` */ + #[Field] public function deprecatedUppercaseName(Contact $contact): string { return strtoupper($contact->getName()); @@ -34,12 +28,10 @@ public function deprecatedUppercaseName(Contact $contact): string /** * Here, we are testing overriding the field in the extend class. - * - * @Field() - * @return string */ + #[Field] public function company(Contact $contact): string { - return $contact->getName().' Ltd'; + return $contact->getName() . ' Ltd'; } } diff --git a/tests/Fixtures/Integration/Types/FilterDecorator.php b/tests/Fixtures/Integration/Types/FilterDecorator.php index 305e6d2140..76cca38f7f 100644 --- a/tests/Fixtures/Integration/Types/FilterDecorator.php +++ b/tests/Fixtures/Integration/Types/FilterDecorator.php @@ -1,49 +1,37 @@ mergeValues($moreValues); return $filter; } - /** - * @Decorate(inputTypeName="FilterInput") - * @param Filter $filter - * @param int[] $evenMoreValues - * @return Filter - */ + /** @param int[] $evenMoreValues */ + #[Decorate(inputTypeName: 'FilterInput')] public static function staticDecorate(Filter $filter, array $evenMoreValues = []): Filter { $filter->mergeValues($evenMoreValues); return $filter; } - /** - * @Decorate(inputTypeName="FilterInput") - * @UseInputType(for="innerFilter", inputType="FilterInput") - * @param Filter $filter - * @param Filter|null $innerFilter - * @return Filter - */ - public static function recursiveDecorate(Filter $filter, ?Filter $innerFilter = null): Filter + #[Decorate(inputTypeName: 'FilterInput')] + public static function recursiveDecorate( + Filter $filter, + #[UseInputType(inputType: 'FilterInput')] + Filter|null $innerFilter = null, + ): Filter { return $filter; } diff --git a/tests/Fixtures/Interfaces/ClassA.php b/tests/Fixtures/Interfaces/ClassA.php index 951efa83ec..772174b646 100644 --- a/tests/Fixtures/Interfaces/ClassA.php +++ b/tests/Fixtures/Interfaces/ClassA.php @@ -1,22 +1,17 @@ foo = $foo; } public function getFoo(): string { return $this->foo; } -} \ No newline at end of file +} diff --git a/tests/Fixtures/Interfaces/ClassB.php b/tests/Fixtures/Interfaces/ClassB.php index ffe72d3fde..8371cb11d5 100644 --- a/tests/Fixtures/Interfaces/ClassB.php +++ b/tests/Fixtures/Interfaces/ClassB.php @@ -1,20 +1,14 @@ bar = $bar; } public function getBar(): string diff --git a/tests/Fixtures/Interfaces/Types/ClassAType.php b/tests/Fixtures/Interfaces/Types/ClassAType.php index 615ac51204..ea12b01533 100644 --- a/tests/Fixtures/Interfaces/Types/ClassAType.php +++ b/tests/Fixtures/Interfaces/Types/ClassAType.php @@ -1,5 +1,6 @@ getTest(); } - return new TestObject($string.$int.$str.($boolean?'true':'false').$float.$dateTimeImmutable->format('YmdHis').$dateTime->format('YmdHis').$withDefault.($id !== null ? $id->val() : '').$enum->getValue()); + return new TestObject($string . $int . $str . ($boolean ? 'true' : 'false') . $float . $dateTimeImmutable->format('YmdHis') . $dateTime->format('YmdHis') . $withDefault . ($id?->val() ?? '') . $enum->getValue()); } #[Query] @@ -50,7 +52,7 @@ public function testLogged(): TestObject } #[Query] - #[Right(name: "CAN_FOO")] + #[Right(name: 'CAN_FOO')] #[HideIfUnauthorized] public function testRight(): TestObject { @@ -69,47 +71,36 @@ public function testNameFromAnnotation(): TestObject return new TestObject('foo'); } - /** - * @return ArrayObject|TestObject[] - */ + /** @return ArrayObject|TestObject[] */ #[Query(name: 'arrayObject')] public function testArrayObject(): ArrayObject { return new ArrayObject([]); } - /** - * @return ArrayObject - */ + /** @return ArrayObject */ #[Query(name: 'arrayObjectGeneric')] public function testArrayObjectGeneric(): ArrayObject { return new ArrayObject([]); } - /** - * @return iterable|TestObject[] - */ + /** @return iterable|TestObject[] */ #[Query(name: 'iterable')] public function testIterable(): iterable { - return array(); + return []; } - /** - * @return iterable - */ + /** @return iterable */ #[Query(name: 'iterableGeneric')] public function testIterableGeneric(): iterable { - return array(); + return []; } - /** - * @return TestObject|TestObject2 - */ #[Query(name: 'union')] - public function testUnion() + public function testUnion(): TestObject|TestObject2 { return new TestObject2('foo'); } @@ -133,9 +124,11 @@ public function testReturn(TestObject $testObject): TestObject #[Subscription(outputType: 'ID')] public function testSubscribe(): void - {} + { + } #[Subscription(outputType: 'ID')] public function testSubscribeWithInput(TestObject $testObject): void - {} + { + } } diff --git a/tests/Fixtures/TestControllerNoReturnType.php b/tests/Fixtures/TestControllerNoReturnType.php index 1823c24453..9e9a3a4736 100644 --- a/tests/Fixtures/TestControllerNoReturnType.php +++ b/tests/Fixtures/TestControllerNoReturnType.php @@ -1,19 +1,14 @@ $params * @return array */ + #[Query] public function test(array $params): array { return $params; diff --git a/tests/Fixtures/TestControllerWithParamDateTime.php b/tests/Fixtures/TestControllerWithParamDateTime.php index c3cfb33fc7..6233a8f30a 100644 --- a/tests/Fixtures/TestControllerWithParamDateTime.php +++ b/tests/Fixtures/TestControllerWithParamDateTime.php @@ -1,5 +1,6 @@ test = $test; - $this->testBool = $testBool; } /** * This is a test summary - * @return string */ public function getTest(): string { return $this->test; } - /** - * @return bool - */ public function isTestBool(): bool { return $this->testBool; } - /** - * @return ?string - */ - public function testRight() + public function testRight(): string|null { - return "foo"; + return 'foo'; } public function getSibling(self $foo): self diff --git a/tests/Fixtures/TestObject2.php b/tests/Fixtures/TestObject2.php index 09ece4f89b..f0dd249db4 100644 --- a/tests/Fixtures/TestObject2.php +++ b/tests/Fixtures/TestObject2.php @@ -1,23 +1,15 @@ test2 = $test2; } - /** - * @return string - */ public function getTest2(): string { return $this->test2; diff --git a/tests/Fixtures/TestSelfType.php b/tests/Fixtures/TestSelfType.php index 5e967b89c0..2c725517b0 100644 --- a/tests/Fixtures/TestSelfType.php +++ b/tests/Fixtures/TestSelfType.php @@ -6,10 +6,8 @@ use TheCodingMachine\GraphQLite\Annotations\SourceField; use TheCodingMachine\GraphQLite\Annotations\Type; -/** - * @Type() - * @SourceField(name="test") - */ +#[Type] +#[SourceField(name: 'test')] class TestSelfType { private $foo = 'foo'; diff --git a/tests/Fixtures/TestSourceFieldBadOutputType.php b/tests/Fixtures/TestSourceFieldBadOutputType.php index 42b5cabc83..edf613f39d 100644 --- a/tests/Fixtures/TestSourceFieldBadOutputType.php +++ b/tests/Fixtures/TestSourceFieldBadOutputType.php @@ -1,15 +1,14 @@ foo = $foo; - $this->bar = $bar; } public function __get($name) diff --git a/tests/Fixtures/TestSourceNameType.php b/tests/Fixtures/TestSourceNameType.php index ddfbaa9a2f..2cf0b39009 100644 --- a/tests/Fixtures/TestSourceNameType.php +++ b/tests/Fixtures/TestSourceNameType.php @@ -1,17 +1,16 @@ getTest().$param; + return $test->getTest() . $param; } } diff --git a/tests/Fixtures/TestTypeId.php b/tests/Fixtures/TestTypeId.php index 626928afd3..74a7ae7257 100644 --- a/tests/Fixtures/TestTypeId.php +++ b/tests/Fixtures/TestTypeId.php @@ -1,15 +1,14 @@ getTest().$arg1; + return $test->getTest() . $arg1; } } diff --git a/tests/Fixtures/TestTypeWithFailWith.php b/tests/Fixtures/TestTypeWithFailWith.php index ad362e1f55..0d008c4d59 100644 --- a/tests/Fixtures/TestTypeWithFailWith.php +++ b/tests/Fixtures/TestTypeWithFailWith.php @@ -1,18 +1,16 @@ 'test']), + new SourceField(['name' => 'test']), ]; } } diff --git a/tests/Fixtures/TestTypeWithSourceFieldInvalidParameterAnnotation.php b/tests/Fixtures/TestTypeWithSourceFieldInvalidParameterAnnotation.php index 71dd3b33a2..2cc4b67c9a 100644 --- a/tests/Fixtures/TestTypeWithSourceFieldInvalidParameterAnnotation.php +++ b/tests/Fixtures/TestTypeWithSourceFieldInvalidParameterAnnotation.php @@ -1,16 +1,15 @@ getTest().$param; + return $test->getTest() . $param; } } diff --git a/tests/Fixtures/Types/FooExtendType.php b/tests/Fixtures/Types/FooExtendType.php index e462b90a1b..0ca423cf5b 100644 --- a/tests/Fixtures/Types/FooExtendType.php +++ b/tests/Fixtures/Types/FooExtendType.php @@ -1,23 +1,19 @@ getTest()); diff --git a/tests/Fixtures/Types/FooType.php b/tests/Fixtures/Types/FooType.php index 22b8c4d55b..c8ab91a854 100644 --- a/tests/Fixtures/Types/FooType.php +++ b/tests/Fixtures/Types/FooType.php @@ -3,13 +3,10 @@ namespace TheCodingMachine\GraphQLite\Fixtures\Types; -use TheCodingMachine\GraphQLite\Annotations\Right; -use TheCodingMachine\GraphQLite\Annotations\SourceField; use TheCodingMachine\GraphQLite\Annotations\Type; +use TheCodingMachine\GraphQLite\Fixtures\TestObject; -/** - * @Type(class=TheCodingMachine\GraphQLite\Fixtures\TestObject::class) - */ +#[Type(class: TestObject::class)] class FooType extends AbstractFooType { } diff --git a/tests/Fixtures/Types/TestFactory.php b/tests/Fixtures/Types/TestFactory.php index 77e22f97a9..5d619b9a9e 100644 --- a/tests/Fixtures/Types/TestFactory.php +++ b/tests/Fixtures/Types/TestFactory.php @@ -1,42 +1,37 @@ format('Y-m-d').'-'.implode('-', $stringList).'-'.count($dateList)); + return new TestObject2($date->format('Y-m-d') . '-' . implode('-', $stringList) . '-' . count($dateList)); } - /** - * @Decorate("InputObject") - */ + #[Decorate('InputObject')] public function myDecorator(TestObject $testObject, int $int): TestObject { return $testObject; diff --git a/tests/Integration/EndToEndTest.php b/tests/Integration/EndToEndTest.php index fccd26d937..ca9eb58033 100644 --- a/tests/Integration/EndToEndTest.php +++ b/tests/Integration/EndToEndTest.php @@ -4,7 +4,6 @@ namespace TheCodingMachine\GraphQLite\Integration; -use Doctrine\Common\Annotations\AnnotationReader as DoctrineAnnotationReader; use GraphQL\Error\DebugFlag; use GraphQL\Executor\ExecutionResult; use GraphQL\GraphQL; diff --git a/tests/Integration/IntegrationTestCase.php b/tests/Integration/IntegrationTestCase.php index d363393d5f..06db73cce9 100644 --- a/tests/Integration/IntegrationTestCase.php +++ b/tests/Integration/IntegrationTestCase.php @@ -2,7 +2,6 @@ namespace TheCodingMachine\GraphQLite\Integration; -use Doctrine\Common\Annotations\AnnotationReader as DoctrineAnnotationReader; use GraphQL\Error\DebugFlag; use GraphQL\Executor\ExecutionResult; use Kcs\ClassFinder\Finder\ComposerFinder; @@ -282,7 +281,7 @@ public function createContainer(array $overloadedServices = []): ContainerInterf ); }, AnnotationReader::class => static function (ContainerInterface $container) { - return new AnnotationReader(new DoctrineAnnotationReader()); + return new AnnotationReader(); }, NamingStrategyInterface::class => static function () { return new NamingStrategy(); diff --git a/tests/Mappers/GlobTypeMapperTest.php b/tests/Mappers/GlobTypeMapperTest.php index ce8ab0aad4..e7e12053ae 100644 --- a/tests/Mappers/GlobTypeMapperTest.php +++ b/tests/Mappers/GlobTypeMapperTest.php @@ -1,13 +1,17 @@ function () { + FooType::class => static function () { return new FooType(); - } + }, ]); $typeGenerator = $this->getTypeGenerator(); @@ -43,7 +46,7 @@ public function testGlobTypeMapper(): void $cache = new Psr16Cache(new ArrayAdapter()); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), $cache); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), $cache); $this->assertSame([TestObject::class], $mapper->getSupportedClasses()); $this->assertTrue($mapper->canMapClassToType(TestObject::class)); @@ -53,25 +56,25 @@ public function testGlobTypeMapper(): void $this->assertFalse($mapper->canMapNameToType('NotExists')); // Again to test cache - $anotherMapperSameCache = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), $cache); + $anotherMapperSameCache = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), $cache); $this->assertTrue($anotherMapperSameCache->canMapClassToType(TestObject::class)); $this->assertTrue($anotherMapperSameCache->canMapNameToType('Foo')); $this->expectException(CannotMapTypeException::class); - $mapper->mapClassToType(\stdClass::class, null); + $mapper->mapClassToType(stdClass::class, null); } public function testGlobTypeMapperDuplicateTypesException(): void { $container = new LazyContainer([ - TestType::class => function () { + TestType::class => static function () { return new TestType(); - } + }, ]); $typeGenerator = $this->getTypeGenerator(); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\DuplicateTypes'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), new Psr16Cache(new NullAdapter())); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\DuplicateTypes'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), new Psr16Cache(new NullAdapter())); $this->expectException(DuplicateMappingException::class); $mapper->canMapClassToType(TestType::class); @@ -80,14 +83,14 @@ public function testGlobTypeMapperDuplicateTypesException(): void public function testGlobTypeMapperDuplicateInputsException(): void { $container = new LazyContainer([ - TestInput::class => function () { + TestInput::class => static function () { return new TestInput(); - } + }, ]); $typeGenerator = $this->getTypeGenerator(); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\DuplicateInputs'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), new Psr16Cache(new NullAdapter())); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\DuplicateInputs'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), new Psr16Cache(new NullAdapter())); $this->expectException(DuplicateMappingException::class); $mapper->canMapClassToInputType(TestInput::class); @@ -103,18 +106,20 @@ public function testGlobTypeMapperDuplicateInputTypesException(): void $typeGenerator = $this->getTypeGenerator(); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\DuplicateInputTypes'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), new Psr16Cache(new NullAdapter())); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\DuplicateInputTypes'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), new Psr16Cache(new NullAdapter())); $caught = false; try { $mapper->canMapClassToInputType(TestObject::class); } catch (DuplicateMappingException $e) { // Depending on the environment, one of the messages can be returned. - $this->assertContains($e->getMessage(), + $this->assertContains( + $e->getMessage(), [ 'The class \'TheCodingMachine\GraphQLite\Fixtures\TestObject\' should be mapped to only one GraphQL Input type. Two methods are pointing via the @Factory annotation to this class: \'TheCodingMachine\GraphQLite\Fixtures\DuplicateInputTypes\TestFactory::myFactory\' and \'TheCodingMachine\GraphQLite\Fixtures\DuplicateInputTypes\TestFactory2::myFactory\'', - 'The class \'TheCodingMachine\GraphQLite\Fixtures\TestObject\' should be mapped to only one GraphQL Input type. Two methods are pointing via the @Factory annotation to this class: \'TheCodingMachine\GraphQLite\Fixtures\DuplicateInputTypes\TestFactory2::myFactory\' and \'TheCodingMachine\GraphQLite\Fixtures\DuplicateInputTypes\TestFactory::myFactory\'' - ]); + 'The class \'TheCodingMachine\GraphQLite\Fixtures\TestObject\' should be mapped to only one GraphQL Input type. Two methods are pointing via the @Factory annotation to this class: \'TheCodingMachine\GraphQLite\Fixtures\DuplicateInputTypes\TestFactory2::myFactory\' and \'TheCodingMachine\GraphQLite\Fixtures\DuplicateInputTypes\TestFactory::myFactory\'', + ], + ); $caught = true; } $this->assertTrue($caught, 'DuplicateMappingException is thrown'); @@ -123,14 +128,14 @@ public function testGlobTypeMapperDuplicateInputTypesException(): void public function testGlobTypeMapperInheritedInputTypesException(): void { $container = new LazyContainer([ - ChildTestFactory::class => function() { + ChildTestFactory::class => static function () { return new ChildTestFactory(); - } + }, ]); $typeGenerator = $this->getTypeGenerator(); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\InheritedInputTypes'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), new Psr16Cache(new NullAdapter())); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\InheritedInputTypes'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), new Psr16Cache(new NullAdapter())); //$this->expectException(DuplicateMappingException::class); //$this->expectExceptionMessage('The class \'TheCodingMachine\GraphQLite\Fixtures\TestObject\' should be mapped to only one GraphQL Input type. Two methods are pointing via the @Factory annotation to this class: \'TheCodingMachine\GraphQLite\Fixtures\DuplicateInputTypes\TestFactory::myFactory\' and \'TheCodingMachine\GraphQLite\Fixtures\DuplicateInputTypes\TestFactory2::myFactory\''); @@ -141,31 +146,31 @@ public function testGlobTypeMapperInheritedInputTypesException(): void public function testGlobTypeMapperClassNotFoundException(): void { $container = new LazyContainer([ - TestType::class => function () { + TestType::class => static function () { return new TestType(); - } + }, ]); $typeGenerator = $this->getTypeGenerator(); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\BadClassType'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), new Psr16Cache(new NullAdapter())); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\BadClassType'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), new Psr16Cache(new NullAdapter())); $this->expectException(ClassNotFoundException::class); - $this->expectExceptionMessage("Could not autoload class 'Foobar' defined in @Type annotation of class 'TheCodingMachine\\GraphQLite\\Fixtures\\BadClassType\\TestType'"); + $this->expectExceptionMessage("Could not autoload class 'Foobar' defined in #[Type] attribute of class 'TheCodingMachine\\GraphQLite\\Fixtures\\BadClassType\\TestType'"); $mapper->canMapClassToType(TestType::class); } public function testGlobTypeMapperNameNotFoundException(): void { $container = new LazyContainer([ - FooType::class => function () { + FooType::class => static function () { return new FooType(); - } + }, ]); $typeGenerator = $this->getTypeGenerator(); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), new Psr16Cache(new NullAdapter())); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), new Psr16Cache(new NullAdapter())); $this->expectException(CannotMapTypeException::class); $mapper->mapNameToType('NotExists', $this->getTypeMapper()); @@ -174,19 +179,19 @@ public function testGlobTypeMapperNameNotFoundException(): void public function testGlobTypeMapperInputType(): void { $container = new LazyContainer([ - FooType::class => function () { + FooType::class => static function () { return new FooType(); }, - TestFactory::class => function () { + TestFactory::class => static function () { return new TestFactory(); - } + }, ]); $typeGenerator = $this->getTypeGenerator(); $cache = new Psr16Cache(new ArrayAdapter()); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), $cache); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), $cache); $this->assertTrue($mapper->canMapClassToInputType(TestObject::class)); @@ -195,12 +200,11 @@ public function testGlobTypeMapperInputType(): void $this->assertSame('TestObjectInput', $inputType->name); // Again to test cache - $anotherMapperSameCache = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), $cache); + $anotherMapperSameCache = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), $cache); $this->assertTrue($anotherMapperSameCache->canMapClassToInputType(TestObject::class)); $this->assertSame('TestObjectInput', $anotherMapperSameCache->mapClassToInputType(TestObject::class, $this->getTypeMapper())->name); - $this->expectException(CannotMapTypeException::class); $mapper->mapClassToInputType(TestType::class, $this->getTypeMapper()); } @@ -208,12 +212,12 @@ public function testGlobTypeMapperInputType(): void public function testGlobTypeMapperExtend(): void { $container = new LazyContainer([ - FooType::class => function () { + FooType::class => static function () { return new FooType(); }, - FooExtendType::class => function () { + FooExtendType::class => static function () { return new FooExtendType(); - } + }, ]); $typeGenerator = $this->getTypeGenerator(); @@ -221,7 +225,7 @@ public function testGlobTypeMapperExtend(): void $cache = new Psr16Cache(new ArrayAdapter()); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), $cache); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), $cache); $type = $mapper->mapClassToType(TestObject::class, null); @@ -232,12 +236,12 @@ public function testGlobTypeMapperExtend(): void $this->assertFalse($mapper->canExtendTypeForName('NotExists', $type)); // Again to test cache - $anotherMapperSameCache = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), $cache); + $anotherMapperSameCache = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), $cache); $this->assertTrue($anotherMapperSameCache->canExtendTypeForClass(TestObject::class, $type)); $this->assertTrue($anotherMapperSameCache->canExtendTypeForName('TestObject', $type)); $this->expectException(CannotMapTypeException::class); - $mapper->extendTypeForClass(\stdClass::class, $type); + $mapper->extendTypeForClass(stdClass::class, $type); } public function testEmptyGlobTypeMapper(): void @@ -249,7 +253,7 @@ public function testEmptyGlobTypeMapper(): void $cache = new Psr16Cache(new ArrayAdapter()); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Integration\Controllers'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), $cache); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Integration\Controllers'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), $cache); $this->assertSame([], $mapper->getSupportedClasses()); } @@ -257,9 +261,9 @@ public function testEmptyGlobTypeMapper(): void public function testGlobTypeMapperDecorate(): void { $container = new LazyContainer([ - FilterDecorator::class => function () { + FilterDecorator::class => static function () { return new FilterDecorator(); - } + }, ]); $typeGenerator = $this->getTypeGenerator(); @@ -267,9 +271,9 @@ public function testGlobTypeMapperDecorate(): void $cache = new Psr16Cache(new ArrayAdapter()); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Integration\Types'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), $cache); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Integration\Types'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), $cache); - $inputType = new MockResolvableInputObjectType(['name'=>'FilterInput']); + $inputType = new MockResolvableInputObjectType(['name' => 'FilterInput']); $mapper->decorateInputTypeForName('FilterInput', $inputType); @@ -283,14 +287,14 @@ public function testGlobTypeMapperDecorate(): void public function testInvalidName(): void { $container = new LazyContainer([ - FooType::class => function () { + FooType::class => static function () { return new FooType(); - } + }, ]); $typeGenerator = $this->getTypeGenerator(); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), new Psr16Cache(new ArrayAdapter())); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Types'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), new Psr16Cache(new ArrayAdapter())); $this->assertFalse($mapper->canExtendTypeForName('{}()/\\@:', new MutableObjectType(['name' => 'foo']))); $this->assertFalse($mapper->canDecorateInputTypeForName('{}()/\\@:', new MockResolvableInputObjectType(['name' => 'foo']))); @@ -300,13 +304,13 @@ public function testInvalidName(): void public function testGlobTypeMapperExtendBadName(): void { $container = new LazyContainer([ - FooType::class => function () { + FooType::class => static function () { return new FooType(); }, - FooExtendType::class => function () { + FooExtendType::class => static function () { return new FooExtendType(); }, - BadExtendType::class => function () { + BadExtendType::class => static function () { return new BadExtendType(); }, ]); @@ -316,7 +320,7 @@ public function testGlobTypeMapperExtendBadName(): void $cache = new Psr16Cache(new ArrayAdapter()); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\BadExtendType'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), $cache); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\BadExtendType'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), $cache); $testObjectType = new MutableObjectType([ 'name' => 'TestObject', @@ -333,13 +337,13 @@ public function testGlobTypeMapperExtendBadName(): void public function testGlobTypeMapperExtendBadClass(): void { $container = new LazyContainer([ - FooType::class => function () { + FooType::class => static function () { return new FooType(); }, - FooExtendType::class => function () { + FooExtendType::class => static function () { return new FooExtendType(); }, - BadExtendType2::class => function () { + BadExtendType2::class => static function () { return new BadExtendType2(); }, ]); @@ -349,7 +353,7 @@ public function testGlobTypeMapperExtendBadClass(): void $cache = new Psr16Cache(new ArrayAdapter()); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\BadExtendType2'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), $cache); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\BadExtendType2'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), $cache); $testObjectType = new MutableObjectType([ 'name' => 'TestObject', @@ -366,9 +370,9 @@ public function testGlobTypeMapperExtendBadClass(): void public function testNonInstantiableType(): void { $container = new LazyContainer([ - FooType::class => function () { + FooType::class => static function () { return new FooType(); - } + }, ]); $typeGenerator = $this->getTypeGenerator(); @@ -376,7 +380,7 @@ public function testNonInstantiableType(): void $cache = new Psr16Cache(new ArrayAdapter()); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\NonInstantiableType'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), $cache); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\NonInstantiableType'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), $cache); $this->expectException(GraphQLRuntimeException::class); $this->expectExceptionMessage('Class "TheCodingMachine\GraphQLite\Fixtures\NonInstantiableType\AbstractFooType" annotated with @Type(class="TheCodingMachine\GraphQLite\Fixtures\TestObject") must be instantiable.'); @@ -391,7 +395,7 @@ public function testNonInstantiableInput(): void $inputTypeGenerator = $this->getInputTypeGenerator(); $cache = new Psr16Cache(new ArrayAdapter()); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\NonInstantiableInput'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), $cache); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\NonInstantiableInput'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), $cache); $this->expectException(FailedResolvingInputType::class); $this->expectExceptionMessage("Class 'TheCodingMachine\GraphQLite\Fixtures\NonInstantiableInput\AbstractFoo' annotated with @Input must be instantiable."); diff --git a/tests/Mappers/Parameters/ContainerParameterMapperTest.php b/tests/Mappers/Parameters/ContainerParameterMapperTest.php index cbb261b42e..a33e8295ae 100644 --- a/tests/Mappers/Parameters/ContainerParameterMapperTest.php +++ b/tests/Mappers/Parameters/ContainerParameterMapperTest.php @@ -1,5 +1,7 @@ getRegistry()); - $refMethod = new ReflectionMethod(__CLASS__, 'dummy'); + $refMethod = new ReflectionMethod(self::class, 'dummy'); $parameter = $refMethod->getParameters()[0]; $this->expectException(MissingAutowireTypeException::class); $this->expectExceptionMessage('For parameter $foo in TheCodingMachine\GraphQLite\Mappers\Parameters\ContainerParameterMapperTest::dummy, annotated with annotation @Autowire, you must either provide a type-hint or specify the container identifier with @Autowire(identifier="my_service")'); - $mapper->mapParameter($parameter, - new DocBlock(), null, $this->getAnnotationReader()->getParameterAnnotations($parameter), new class implements ParameterHandlerInterface { - public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations): ParameterInterface + $mapper->mapParameter( + $parameter, + new DocBlock(), + null, + $this->getAnnotationReader()->getParameterAnnotationsPerParameter([$parameter])['foo'], + new class implements ParameterHandlerInterface { + public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, Type|null $paramTagType, ParameterAnnotations $parameterAnnotations): ParameterInterface { } - }); + }, + ); } - /** - * @Autowire(for="foo") - */ - private function dummy($foo) { - + private function dummy( + #[Autowire] + $foo, + ): void + { } } diff --git a/tests/Mappers/Parameters/TypeMapperTest.php b/tests/Mappers/Parameters/TypeMapperTest.php index dd1327dde5..825cdaacb0 100644 --- a/tests/Mappers/Parameters/TypeMapperTest.php +++ b/tests/Mappers/Parameters/TypeMapperTest.php @@ -1,8 +1,9 @@ getDocBlock($refMethod); $this->expectException(CannotMapTypeException::class); - $this->expectExceptionMessage('For return type of TheCodingMachine\GraphQLite\Mappers\Parameters\TypeMapperTest::dummy, in GraphQL, you can only use union types between objects. These types cannot be used in union types: Int!, String!'); + $this->expectExceptionMessage('For return type of TheCodingMachine\GraphQLite\Mappers\Parameters\TypeMapperTest::dummy, in GraphQL, you can only use union types between objects. These types cannot be used in union types: String!, Int!'); $typeMapper->mapReturnType($refMethod, $docBlockObj); } @@ -80,14 +83,13 @@ public function testMapObjectNullableUnionWorks(): void $gqType = $typeMapper->mapReturnType($refMethod, $docBlockObj); $this->assertNotInstanceOf(NonNull::class, $gqType); - assert(!($gqType instanceof NonNull)); + assert(! ($gqType instanceof NonNull)); $this->assertInstanceOf(UnionType::class, $gqType); assert($gqType instanceof UnionType); $unionTypes = $gqType->getTypes(); $this->assertEquals(2, count($unionTypes)); $this->assertEquals('TestObject', $unionTypes[0]->name); $this->assertEquals('TestObject2', $unionTypes[1]->name); - } public function testHideParameter(): void @@ -104,7 +106,7 @@ public function testHideParameter(): void $refMethod = new ReflectionMethod($this, 'withDefaultValue'); $refParameter = $refMethod->getParameters()[0]; $docBlockObj = $cachedDocBlockFactory->getDocBlock($refMethod); - $annotations = $this->getAnnotationReader()->getParameterAnnotations($refParameter); + $annotations = $this->getAnnotationReader()->getParameterAnnotationsPerParameter([$refParameter])['foo']; $param = $typeMapper->mapParameter($refParameter, $docBlockObj, null, $annotations); @@ -129,7 +131,7 @@ public function testParameterWithDescription(): void $docBlockObj = $cachedDocBlockFactory->getDocBlock($refMethod); $refParameter = $refMethod->getParameters()[0]; - $parameter = $typeMapper->mapParameter($refParameter, $docBlockObj, null, $this->getAnnotationReader()->getParameterAnnotations($refParameter)); + $parameter = $typeMapper->mapParameter($refParameter, $docBlockObj, null, $this->getAnnotationReader()->getParameterAnnotationsPerParameter([$refParameter])['foo']); $this->assertInstanceOf(InputTypeParameter::class, $parameter); assert($parameter instanceof InputTypeParameter); $this->assertEquals('Foo parameter', $parameter->getDescription()); @@ -149,7 +151,7 @@ public function testHideParameterException(): void $refMethod = new ReflectionMethod($this, 'withoutDefaultValue'); $refParameter = $refMethod->getParameters()[0]; $docBlockObj = $cachedDocBlockFactory->getDocBlock($refMethod); - $annotations = $this->getAnnotationReader()->getParameterAnnotations($refParameter); + $annotations = $this->getAnnotationReader()->getParameterAnnotationsPerParameter([$refParameter])['foo']; $this->expectException(CannotHideParameterRuntimeException::class); $this->expectExceptionMessage('For parameter $foo of method TheCodingMachine\GraphQLite\Mappers\Parameters\TypeMapperTest::withoutDefaultValue(), cannot use the @HideParameter annotation. The parameter needs to provide a default value.'); @@ -157,35 +159,22 @@ public function testHideParameterException(): void $typeMapper->mapParameter($refParameter, $docBlockObj, null, $annotations); } - /** - * @return int|string - */ - private function dummy() + private function dummy(): int|string { - } - /** - * @param int $foo Foo parameter - */ - private function withParamDescription(int $foo) + /** @param int $foo Foo parameter */ + private function withParamDescription(int $foo): void { - } - /** - * @HideParameter(for="$foo") - */ - private function withDefaultValue($foo = 24) + private function withDefaultValue(#[HideParameter] + $foo = 24,): void { - } - /** - * @HideParameter(for="$foo") - */ - private function withoutDefaultValue($foo) + private function withoutDefaultValue(#[HideParameter] + $foo,): void { - } } diff --git a/tests/Mappers/RecursiveTypeMapperTest.php b/tests/Mappers/RecursiveTypeMapperTest.php index 6d67e3bdd1..8fc14ee27c 100644 --- a/tests/Mappers/RecursiveTypeMapperTest.php +++ b/tests/Mappers/RecursiveTypeMapperTest.php @@ -1,26 +1,22 @@ 'Foobar' - ]); + $objectType = new MutableObjectType(['name' => 'Foobar']); $typeMapper = new StaticTypeMapper( - types: [ - ClassB::class => $objectType - ] + types: [ClassB::class => $objectType], ); $recursiveTypeMapper = new RecursiveTypeMapper( @@ -46,7 +37,7 @@ public function testMapClassToType(): void new NamingStrategy(), new Psr16Cache(new ArrayAdapter()), $this->getTypeRegistry(), - $this->getAnnotationReader() + $this->getAnnotationReader(), ); $this->assertFalse($typeMapper->canMapClassToType(ClassC::class)); @@ -60,14 +51,10 @@ public function testMapClassToType(): void public function testMapNameToType(): void { - $objectType = new MutableObjectType([ - 'name' => 'Foobar' - ]); + $objectType = new MutableObjectType(['name' => 'Foobar']); $typeMapper = new StaticTypeMapper( - types: [ - ClassB::class => $objectType - ] + types: [ClassB::class => $objectType], ); $recursiveTypeMapper = new RecursiveTypeMapper( @@ -75,7 +62,7 @@ public function testMapNameToType(): void new NamingStrategy(), new Psr16Cache(new ArrayAdapter()), $this->getTypeRegistry(), - $this->getAnnotationReader() + $this->getAnnotationReader(), ); $this->assertTrue($recursiveTypeMapper->canMapNameToType('Foobar')); @@ -97,17 +84,12 @@ public function testMapNameToType2(): void $recursiveMapper->mapNameToType('NotExists'); } - public function testMapClassToInputType(): void { - $inputObjectType = new InputObjectType([ - 'name' => 'Foobar' - ]); + $inputObjectType = new InputObjectType(['name' => 'Foobar']); $typeMapper = new StaticTypeMapper( - inputTypes: [ - ClassB::class => $inputObjectType - ] + inputTypes: [ClassB::class => $inputObjectType], ); $recursiveTypeMapper = new RecursiveTypeMapper( @@ -115,7 +97,7 @@ public function testMapClassToInputType(): void new NamingStrategy(), new Psr16Cache(new ArrayAdapter()), $this->getTypeRegistry(), - $this->getAnnotationReader() + $this->getAnnotationReader(), ); $this->assertFalse($recursiveTypeMapper->canMapClassToInputType(ClassC::class)); @@ -126,33 +108,32 @@ public function testMapClassToInputType(): void protected $typeMapper; - protected function getTypeMapper() + protected function getTypeMapper(): RecursiveTypeMapper { if ($this->typeMapper === null) { $container = new LazyContainer([ - ClassAType::class => function () { + ClassAType::class => static function () { return new ClassAType(); }, - ClassBType::class => function () { + ClassBType::class => static function () { return new ClassBType(); - } + }, ]); $namingStrategy = new NamingStrategy(); - $compositeMapper = new CompositeTypeMapper(); $this->typeMapper = new RecursiveTypeMapper( $compositeMapper, new NamingStrategy(), new Psr16Cache(new ArrayAdapter()), $this->getTypeRegistry(), - $this->getAnnotationReader() + $this->getAnnotationReader(), ); $typeGenerator = new TypeGenerator($this->getAnnotationReader(), $namingStrategy, $this->getTypeRegistry(), $this->getRegistry(), $this->typeMapper, $this->getFieldsBuilder()); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Interfaces\Types'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), $namingStrategy, $this->typeMapper, new Psr16Cache(new NullAdapter())); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Interfaces\Types'), $typeGenerator, $this->getInputTypeGenerator(), $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(), $namingStrategy, $this->typeMapper, new Psr16Cache(new NullAdapter())); $compositeMapper->addTypeMapper($mapper); } return $this->typeMapper; @@ -198,20 +179,14 @@ public function testGetOutputTypes(): void public function testDuplicateDetection(): void { - $objectType = new MutableObjectType([ - 'name' => 'Foobar' - ]); + $objectType = new MutableObjectType(['name' => 'Foobar']); $typeMapper1 = new StaticTypeMapper( - types: [ - ClassB::class => $objectType - ] + types: [ClassB::class => $objectType], ); $typeMapper2 = new StaticTypeMapper( - types: [ - ClassA::class => $objectType - ] + types: [ClassA::class => $objectType], ); $compositeTypeMapper = new CompositeTypeMapper(); @@ -223,7 +198,7 @@ public function testDuplicateDetection(): void new NamingStrategy(), new Psr16Cache(new ArrayAdapter()), $this->getTypeRegistry(), - $this->getAnnotationReader() + $this->getAnnotationReader(), ); $this->expectException(DuplicateMappingException::class); @@ -243,7 +218,7 @@ public function testMapNoTypes(): void new NamingStrategy(), new Psr16Cache(new ArrayAdapter()), $this->getTypeRegistry(), - $this->getAnnotationReader() + $this->getAnnotationReader(), ); $this->expectException(TypeNotFoundException::class); @@ -257,14 +232,14 @@ public function testMapNameToTypeDecorators(): void $cache = new Psr16Cache(new ArrayAdapter()); - $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Integration'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $this->getRegistry(), new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), $cache); + $mapper = new GlobTypeMapper($this->getNamespaceFactory()->createNamespace('TheCodingMachine\GraphQLite\Fixtures\Integration'), $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $this->getRegistry(), new \TheCodingMachine\GraphQLite\AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), $cache); $recursiveTypeMapper = new RecursiveTypeMapper( $mapper, new NamingStrategy(), new Psr16Cache(new ArrayAdapter()), $this->getTypeRegistry(), - $this->getAnnotationReader() + $this->getAnnotationReader(), ); $type = $recursiveTypeMapper->mapNameToType('FilterInput'); diff --git a/tests/Mappers/StaticClassListTypeMapperTest.php b/tests/Mappers/StaticClassListTypeMapperTest.php index c69ede9964..c77beb3929 100644 --- a/tests/Mappers/StaticClassListTypeMapperTest.php +++ b/tests/Mappers/StaticClassListTypeMapperTest.php @@ -2,7 +2,6 @@ namespace TheCodingMachine\GraphQLite\Mappers; -use Doctrine\Common\Annotations\AnnotationReader; use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\Psr16Cache; use Symfony\Component\Cache\Simple\ArrayCache; @@ -22,7 +21,7 @@ public function testClassListException(): void $cache = new Psr16Cache(new ArrayAdapter()); - $mapper = new StaticClassListTypeMapper(['NotExistsClass'], $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(new AnnotationReader()), new NamingStrategy(), $this->getTypeMapper(), $cache); + $mapper = new StaticClassListTypeMapper(['NotExistsClass'], $typeGenerator, $inputTypeGenerator, $this->getInputTypeUtils(), $container, new \TheCodingMachine\GraphQLite\AnnotationReader(), new NamingStrategy(), $this->getTypeMapper(), $cache); $this->expectException(GraphQLRuntimeException::class); $this->expectExceptionMessage('Could not find class "NotExistsClass"'); diff --git a/tests/SchemaFactoryTest.php b/tests/SchemaFactoryTest.php index d57dc78a11..31666902a7 100644 --- a/tests/SchemaFactoryTest.php +++ b/tests/SchemaFactoryTest.php @@ -4,7 +4,6 @@ namespace TheCodingMachine\GraphQLite; -use Doctrine\Common\Annotations\AnnotationReader; use GraphQL\Error\DebugFlag; use GraphQL\Executor\ExecutionResult; use GraphQL\GraphQL; @@ -71,8 +70,7 @@ public function testSetters(): void $factory->addControllerNamespace('TheCodingMachine\\GraphQLite\\Fixtures\\Integration\\Controllers'); $factory->addTypeNamespace('TheCodingMachine\\GraphQLite\\Fixtures\\Integration'); - $factory->setDoctrineAnnotationReader(new AnnotationReader()) - ->setAuthenticationService(new VoidAuthenticationService()) + $factory->setAuthenticationService(new VoidAuthenticationService()) ->setAuthorizationService(new VoidAuthorizationService()) ->setNamingStrategy(new NamingStrategy()) ->addTypeMapper(new CompositeTypeMapper())