diff --git a/.github/workflows/continuous_integration.yml b/.github/workflows/continuous_integration.yml index 15e2b3ca31..49638e7e49 100644 --- a/.github/workflows/continuous_integration.yml +++ b/.github/workflows/continuous_integration.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: install-args: ['', '--prefer-lowest'] - php-version: ['8.1', '8.2', '8.3'] + php-version: ['8.1', '8.2', '8.3', '8.4'] fail-fast: false steps: @@ -74,21 +74,22 @@ jobs: - name: "Run static code analysis with phpstan/phpstan" run: "composer phpstan" - - name: "Run coding standard checks with squizlabs/php_codesniffer" - run: "composer cs-check" + - name: "Run coding standard checks with squizlabs/php_codesniffer on minimum supported PHP version" + if: matrix.php-version == '8.1' + run: composer cs-check - name: "Archive code coverage results" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: "codeCoverage" + name: codeCoverage-${{ matrix.php-version }}-${{ github.run_id }} path: "build" overwrite: true - - uses: codecov/codecov-action@v5.1.1 # upload the coverage to codecov + - uses: codecov/codecov-action@v5.4.0 # upload the coverage to codecov with: fail_ci_if_error: false # optional (default = false) - Need CODECOV_TOKEN - # Do not upload in forks, and only on php8.3, latest deps - if: ${{ github.repository == 'thecodingmachine/graphqlite' && matrix.php-version == '8.3' && matrix.install-args == '' }} + # Do not upload in forks, and only on php8.4, latest deps + if: ${{ github.repository == 'thecodingmachine/graphqlite' && matrix.php-version == '8.4' && matrix.install-args == '' }} examples: name: Check Examples @@ -103,7 +104,7 @@ jobs: - name: "Install PHP with extensions" uses: "shivammathur/setup-php@v2" with: - php-version: "8.2" + php-version: "8.4" tools: composer:v2 - name: "Install dependencies with composer" working-directory: "examples/${{ matrix.example }}" diff --git a/.github/workflows/doc_generation.yml b/.github/workflows/doc_generation.yml index e2a2abaf92..aeeb34dba5 100644 --- a/.github/workflows/doc_generation.yml +++ b/.github/workflows/doc_generation.yml @@ -36,7 +36,7 @@ jobs: - name: "Deploy website" if: "${{ github.event_name == 'push' || github.event_name == 'release' }}" - uses: JamesIves/github-pages-deploy-action@v4.7.2 + uses: JamesIves/github-pages-deploy-action@v4.7.3 with: token: ${{ secrets.GITHUB_TOKEN }} branch: gh-pages # The branch the action should deploy to. diff --git a/composer.json b/composer.json index d4ef009482..15e98ee2bd 100644 --- a/composer.json +++ b/composer.json @@ -27,17 +27,16 @@ "kcs/class-finder": "^0.6.0" }, "require-dev": { - "beberlei/porpaginas": "^1.2 || ^2.0", - "doctrine/coding-standard": "^11.0 || ^12.0", + "beberlei/porpaginas": "^2.0", + "doctrine/coding-standard": "^12.0 || ^13.0", "ecodev/graphql-upload": "^7.0", - "laminas/laminas-diactoros": "^2 || ^3", + "laminas/laminas-diactoros": "^3.5", "myclabs/php-enum": "^1.6.6", - "php-coveralls/php-coveralls": "^2.1", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.11", - "phpunit/phpunit": "^10.1 || ^11.0", - "symfony/var-dumper": "^5.4 || ^6.0 || ^7", - "thecodingmachine/phpstan-strict-rules": "^1.0" + "php-coveralls/php-coveralls": "^2.7", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^10.5 || ^11.0", + "symfony/var-dumper": "^6.4" }, "suggest": { "beberlei/porpaginas": "If you want automatic pagination in your GraphQL types", diff --git a/phpstan.neon b/phpstan.neon index 86c9770f50..11a355ed6b 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,12 +4,7 @@ parameters: tmpDir: .phpstan-cache paths: - src - excludePaths: - # TODO: exlude only for PHP < 8.1 - - src/Mappers/Root/EnumTypeMapper.php - - src/Types/EnumType.php level: 8 - checkGenericClassInNonGenericObjectType: false reportUnmatchedIgnoredErrors: false treatPhpDocTypesAsCertain: false ignoreErrors: @@ -42,3 +37,5 @@ parameters: - message: '#Call to an undefined method object::__toString\(\)#' path : src/Types/ID.php + - + identifier: missingType.generics diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7c3964cbe5..0ec34cb736 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,18 +1,34 @@ - + + ./tests/ ./tests/Bootstrap.php + + src/ diff --git a/src/Annotations/EnumType.php b/src/Annotations/EnumType.php index 77f624bd6e..e83431fbaf 100644 --- a/src/Annotations/EnumType.php +++ b/src/Annotations/EnumType.php @@ -20,11 +20,8 @@ #[Attribute(Attribute::TARGET_CLASS)] class EnumType { - /** @var string|null */ - private $name; - - /** @var bool */ - private $useValues; + private string|null $name; + private bool $useValues; /** @param mixed[] $attributes */ public function __construct(array $attributes = [], string|null $name = null, bool|null $useValues = null) diff --git a/src/Annotations/ExtendType.php b/src/Annotations/ExtendType.php index 609c141138..55831b23ea 100644 --- a/src/Annotations/ExtendType.php +++ b/src/Annotations/ExtendType.php @@ -19,13 +19,15 @@ class ExtendType { /** @var class-string|null */ - private $class; - /** @var string|null */ - private $name; + private string|null $class; + private string|null $name; /** @param mixed[] $attributes */ - public function __construct(array $attributes = [], string|null $class = null, string|null $name = null) - { + public function __construct( + array $attributes = [], + string|null $class = null, + string|null $name = null, + ) { $className = isset($attributes['class']) ? ltrim($attributes['class'], '\\') : null; $className = $className ?? $class; if ($className !== null && ! class_exists($className) && ! interface_exists($className)) { diff --git a/src/Annotations/Factory.php b/src/Annotations/Factory.php index 9d617e4744..6032d8dddb 100644 --- a/src/Annotations/Factory.php +++ b/src/Annotations/Factory.php @@ -13,10 +13,8 @@ #[Attribute(Attribute::TARGET_METHOD)] class Factory { - /** @var string|null */ - private $name; - /** @var bool */ - private $default; + private string|null $name; + private bool $default; /** @param mixed[] $attributes */ public function __construct(array $attributes = [], string|null $name = null, bool|null $default = null) diff --git a/src/Annotations/FailWith.php b/src/Annotations/FailWith.php index 9e87eb0d80..b647908ae2 100644 --- a/src/Annotations/FailWith.php +++ b/src/Annotations/FailWith.php @@ -15,10 +15,8 @@ class FailWith implements MiddlewareAnnotationInterface { /** * The default value to use if the right is not enforced. - * - * @var mixed */ - private $value; + private mixed $value; /** @throws BadMethodCallException */ public function __construct(mixed $values = [], mixed $value = '__fail__with__magic__key__') diff --git a/src/Annotations/Field.php b/src/Annotations/Field.php index 12712bd6e8..82044c5d29 100644 --- a/src/Annotations/Field.php +++ b/src/Annotations/Field.php @@ -13,28 +13,31 @@ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] class Field extends AbstractRequest { - /** @var string|null */ - private $prefetchMethod; + private string|null $prefetchMethod; /** * Input/Output type names for which this fields should be applied to. * * @var string[]|null */ - private $for = null; + private array|null $for = null; - /** @var string|null */ - private $description; - - /** @var string|null */ - private $inputType; + private string|null $description; + private string|null $inputType; /** * @param mixed[] $attributes * @param string|string[] $for */ - public function __construct(array $attributes = [], string|null $name = null, string|null $outputType = null, string|null $prefetchMethod = null, string|array|null $for = null, string|null $description = null, string|null $inputType = null) - { + public function __construct( + array $attributes = [], + string|null $name = null, + string|null $outputType = null, + string|null $prefetchMethod = null, + string|array|null $for = null, + string|null $description = null, + string|null $inputType = null, + ) { parent::__construct($attributes, $name, $outputType); $this->prefetchMethod = $prefetchMethod ?? $attributes['prefetchMethod'] ?? null; diff --git a/src/Annotations/MagicField.php b/src/Annotations/MagicField.php index 650143ff2e..306bddd92c 100644 --- a/src/Annotations/MagicField.php +++ b/src/Annotations/MagicField.php @@ -16,44 +16,56 @@ #[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] class MagicField implements SourceFieldInterface { - /** @var string */ - private $name; + private string $name; + private string|null $outputType; + private string|null $phpType; + private string|null $description; + private string|null $sourceName; - /** @var string|null */ - private $outputType; - - /** @var string|null */ - private $phpType; - - /** @var string|null */ - private $description; - - /** @var string|null */ - private $sourceName; - - /** @var MiddlewareAnnotations */ - private $middlewareAnnotations; + private MiddlewareAnnotations $middlewareAnnotations; /** @var array */ - private $parameterAnnotations; + private array $parameterAnnotations; /** * @param mixed[] $attributes * @param array $annotations */ - public function __construct(array $attributes = [], string|null $name = null, string|null $outputType = null, string|null $phpType = null, string|null $description = null, string|null $sourceName = null, array $annotations = []) - { - $this->name = $attributes['name'] ?? $name; + public function __construct( + array $attributes = [], + string|null $name = null, + string|null $outputType = null, + string|null $phpType = null, + string|null $description = null, + string|null $sourceName = null, + array $annotations = [], + ) { + $name = $attributes['name'] ?? $name; + if (! $name) { + throw new BadMethodCallException( + 'The #[MagicField] attribute must be passed a name. For instance: #[MagicField(name: "phone")]', + ); + } + + $this->name = $name; $this->outputType = $attributes['outputType'] ?? $outputType ?? null; $this->phpType = $attributes['phpType'] ?? $phpType ?? null; $this->description = $attributes['description'] ?? $description ?? null; $this->sourceName = $attributes['sourceName'] ?? $sourceName ?? null; - if (! $this->name || (! $this->outputType && ! $this->phpType)) { - throw new BadMethodCallException('The #[MagicField] attribute must be passed a name and an output type or a php type. For instance: "#[MagicField(name: \'phone\', outputType: \'String!\')]" or "#[MagicField(name: \'phone\', phpType: \'string\')]"'); + if (! $this->outputType && ! $this->phpType) { + throw new BadMethodCallException( + "The #[MagicField] attribute must be passed an output type or a php type. + For instance: #[MagicField(name: 'phone', outputType: 'String!')] + or #[MagicField(name: 'phone', phpType: 'string')]", + ); } if (isset($this->outputType) && $this->phpType) { - throw new BadMethodCallException('In a #[MagicField] attribute, you cannot use the outputType and the phpType at the same time. For instance: "#[MagicField(name: \'phone\', outputType: \'String!\')]" or "#[MagicField(name: \'phone\', phpType: \'string\')]"'); + throw new BadMethodCallException( + "In a #[MagicField] attribute, you cannot use the outputType and the phpType at the + same time. For instance: #[MagicField(name: 'phone', outputType: 'String!')] + or #[MagicField(name: 'phone', phpType: 'string')]", + ); } $middlewareAnnotations = []; $parameterAnnotations = []; @@ -67,13 +79,18 @@ public function __construct(array $attributes = [], string|null $name = null, st } elseif ($annotation instanceof ParameterAnnotationInterface) { $parameterAnnotations[$annotation->getTarget()][] = $annotation; } else { - throw new BadMethodCallException('The #[MagicField] attribute\'s "annotations" attribute must be passed an array of annotations implementing either MiddlewareAnnotationInterface or ParameterAnnotationInterface."'); + throw new BadMethodCallException( + "The #[MagicField] attribute's 'annotation' attribute must be passed an array + of annotations implementing either MiddlewareAnnotationInterface or + ParameterAnnotationInterface.", + ); } } $this->middlewareAnnotations = new MiddlewareAnnotations($middlewareAnnotations); - $this->parameterAnnotations = array_map(static function (array $parameterAnnotationsForAttribute): ParameterAnnotations { - return new ParameterAnnotations($parameterAnnotationsForAttribute); - }, $parameterAnnotations); + $this->parameterAnnotations = array_map( + static fn (array $parameterAnnotationsForAttribute): ParameterAnnotations => new ParameterAnnotations($parameterAnnotationsForAttribute), + $parameterAnnotations, + ); } /** diff --git a/src/Annotations/Right.php b/src/Annotations/Right.php index d14597a326..63f5a5b380 100644 --- a/src/Annotations/Right.php +++ b/src/Annotations/Right.php @@ -12,8 +12,7 @@ #[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] class Right implements MiddlewareAnnotationInterface { - /** @var string */ - private $name; + private string $name; /** * @param array|string $name diff --git a/src/Annotations/Security.php b/src/Annotations/Security.php index c41c396f60..13db0c93db 100644 --- a/src/Annotations/Security.php +++ b/src/Annotations/Security.php @@ -6,46 +6,42 @@ use Attribute; use BadMethodCallException; -use TypeError; use function array_key_exists; -use function gettype; -use function is_array; use function is_string; -use function sprintf; #[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] class Security implements MiddlewareAnnotationInterface { - /** @var string */ - private $expression; - /** @var mixed */ - private $failWith; - /** @var bool */ - private $failWithIsSet = false; - /** @var int */ - private $statusCode; - /** @var string */ - private $message; + private string $expression; + private mixed $failWith; + private bool $failWithIsSet = false; + private int $statusCode; + private string $message; /** * @param array|string $data data array managed by the Doctrine Annotations library or the expression * * @throws BadMethodCallException */ - public function __construct(array|string $data = [], string|null $expression = null, mixed $failWith = '__fail__with__magic__key__', string|null $message = null, int|null $statusCode = null) - { + public function __construct( + array|string $data = [], + string|null $expression = null, + mixed $failWith = '__fail__with__magic__key__', + string|null $message = null, + int|null $statusCode = null, + ) { if (is_string($data)) { $data = ['expression' => $data]; - } elseif (! is_array($data)) { - throw new TypeError(sprintf('"%s": Argument $data is expected to be a string or array, got "%s".', __METHOD__, gettype($data))); } - $this->expression = $data['value'] ?? $data['expression'] ?? $expression; - if (! $this->expression) { + $expression = $data['value'] ?? $data['expression'] ?? $expression; + if (! $expression) { throw new BadMethodCallException('The #[Security] attribute must be passed an expression. For instance: "#[Security("is_granted(\'CAN_EDIT_STUFF\')")]"'); } + $this->expression = $expression; + if (array_key_exists('failWith', $data)) { $this->failWith = $data['failWith']; $this->failWithIsSet = true; diff --git a/src/Exceptions/GraphQLAggregateException.php b/src/Exceptions/GraphQLAggregateException.php index d63ca3a0c3..5c7c1909b8 100644 --- a/src/Exceptions/GraphQLAggregateException.php +++ b/src/Exceptions/GraphQLAggregateException.php @@ -6,6 +6,7 @@ use Exception; use GraphQL\Error\ClientAware; +use RuntimeException; use Throwable; use function array_map; @@ -22,7 +23,7 @@ class GraphQLAggregateException extends Exception implements GraphQLAggregateExc /** @param (ClientAware&Throwable)[] $exceptions */ public function __construct(iterable $exceptions = []) { - parent::__construct('Many exceptions have be thrown:'); + parent::__construct('Many exceptions have been thrown:'); foreach ($exceptions as $exception) { $this->add($exception); @@ -56,6 +57,11 @@ private function updateCode(): void $codes = array_map(static function (Throwable $t) { return $t->getCode(); }, $this->exceptions); + + if (count($codes) === 0) { + throw new RuntimeException('Unable to determine code for exception'); + } + $this->code = max($codes); } diff --git a/src/FactoryContext.php b/src/FactoryContext.php index 0aaf40ac42..672d90ca99 100644 --- a/src/FactoryContext.php +++ b/src/FactoryContext.php @@ -103,7 +103,7 @@ public function getClassFinderComputedCache(): ClassFinderComputedCache return $this->classFinderComputedCache; } - public function getClassBoundCache(): ClassBoundCache|null + public function getClassBoundCache(): ClassBoundCache { return $this->classBoundCache; } diff --git a/src/FieldsBuilder.php b/src/FieldsBuilder.php index d8ab99cc6b..c0dc7d27d1 100644 --- a/src/FieldsBuilder.php +++ b/src/FieldsBuilder.php @@ -497,6 +497,7 @@ private function getFieldsByMethodAnnotations( $resolver = is_string($controller) ? new SourceMethodResolver($refMethod) + /** @phpstan-ignore argument.type */ : new ServiceResolver([$controller, $methodName]); $fieldDescriptor = new QueryFieldDescriptor( @@ -512,7 +513,7 @@ private function getFieldsByMethodAnnotations( ); $field = $this->fieldMiddleware->process($fieldDescriptor, new class implements FieldHandlerInterface { - public function handle(QueryFieldDescriptor $fieldDescriptor): FieldDefinition|null + public function handle(QueryFieldDescriptor $fieldDescriptor): FieldDefinition { return QueryField::fromFieldDescriptor($fieldDescriptor); } @@ -605,7 +606,7 @@ private function getFieldsByPropertyAnnotations( ); $field = $this->fieldMiddleware->process($fieldDescriptor, new class implements FieldHandlerInterface { - public function handle(QueryFieldDescriptor $fieldDescriptor): FieldDefinition|null + public function handle(QueryFieldDescriptor $fieldDescriptor): FieldDefinition { return QueryField::fromFieldDescriptor($fieldDescriptor); } @@ -688,6 +689,7 @@ private function getQueryFieldsFromSourceFields( $docBlockComment = rtrim($docBlockObj->getSummary() . "\n" . $docBlockObj->getDescription()->render()); $deprecated = $docBlockObj->getTagsByName('deprecated'); + $deprecationReason = null; if (count($deprecated) >= 1) { $deprecationReason = trim((string) $deprecated[0]); } @@ -744,7 +746,7 @@ private function getQueryFieldsFromSourceFields( ->withMiddlewareAnnotations($sourceField->getMiddlewareAnnotations()); $field = $this->fieldMiddleware->process($fieldDescriptor, new class implements FieldHandlerInterface { - public function handle(QueryFieldDescriptor $fieldDescriptor): FieldDefinition|null + public function handle(QueryFieldDescriptor $fieldDescriptor): FieldDefinition { return QueryField::fromFieldDescriptor($fieldDescriptor); } @@ -822,7 +824,6 @@ private function resolvePhpType( $context = $this->docBlockFactory->createContext($refClass); $phpdocType = $typeResolver->resolve($phpTypeStr, $context); - assert($phpdocType !== null); $fakeDocBlock = new DocBlock('', null, [new DocBlock\Tags\Return_($phpdocType)], $context); return $this->typeMapper->mapReturnType($refMethod, $fakeDocBlock); @@ -1080,7 +1081,7 @@ private function getInputFieldsByMethodAnnotations( ); $field = $this->inputFieldMiddleware->process($inputFieldDescriptor, new class implements InputFieldHandlerInterface { - public function handle(InputFieldDescriptor $inputFieldDescriptor): InputField|null + public function handle(InputFieldDescriptor $inputFieldDescriptor): InputField { return InputField::fromFieldDescriptor($inputFieldDescriptor); } @@ -1175,7 +1176,7 @@ private function getInputFieldsByPropertyAnnotations( ); $field = $this->inputFieldMiddleware->process($inputFieldDescriptor, new class implements InputFieldHandlerInterface { - public function handle(InputFieldDescriptor $inputFieldDescriptor): InputField|null + public function handle(InputFieldDescriptor $inputFieldDescriptor): InputField { return InputField::fromFieldDescriptor($inputFieldDescriptor); } diff --git a/src/Http/Psr15GraphQLMiddlewareBuilder.php b/src/Http/Psr15GraphQLMiddlewareBuilder.php index 76bb4d6de8..c36ee03633 100644 --- a/src/Http/Psr15GraphQLMiddlewareBuilder.php +++ b/src/Http/Psr15GraphQLMiddlewareBuilder.php @@ -51,6 +51,7 @@ public function __construct(Schema $schema) $this->config->setSchema($schema); $this->config->setDebugFlag(DebugFlag::RETHROW_UNSAFE_EXCEPTIONS); $this->config->setErrorFormatter([WebonyxErrorHandler::class, 'errorFormatter']); + /** @phpstan-ignore argument.type */ $this->config->setErrorsHandler([WebonyxErrorHandler::class, 'errorHandler']); $this->config->setContext(new Context()); $this->config->setPersistedQueryLoader(new NotSupportedPersistedQueryLoader()); diff --git a/src/Http/WebonyxGraphqlMiddleware.php b/src/Http/WebonyxGraphqlMiddleware.php index ac49cc2939..0bd7fa095e 100644 --- a/src/Http/WebonyxGraphqlMiddleware.php +++ b/src/Http/WebonyxGraphqlMiddleware.php @@ -19,6 +19,7 @@ use TheCodingMachine\GraphQLite\Context\ResetableContextInterface; use function array_map; +use function count; use function explode; use function in_array; use function is_array; @@ -99,11 +100,7 @@ private function processResult(ExecutionResult|array|Promise $result): array }, $result); } - if ($result instanceof Promise) { - throw new RuntimeException('Only SyncPromiseAdapter is supported'); - } - - throw new RuntimeException('Unexpected response from StandardServer::executePsrRequest'); // @codeCoverageIgnore + throw new RuntimeException('Only SyncPromiseAdapter is supported'); } /** @param ExecutionResult|array|Promise $result */ @@ -118,19 +115,14 @@ private function decideHttpCode(ExecutionResult|array|Promise $result): int return $this->httpCodeDecider->decideHttpStatusCode($executionResult); }, $result); - return (int) max($codes); - } + if (count($codes) === 0) { + throw new RuntimeException('Unable to determine HTTP status code'); + } - // @codeCoverageIgnoreStart - // Code unreachable because exceptions will be triggered in processResult first. - // We keep it for defensive programming purpose - if ($result instanceof Promise) { - throw new RuntimeException('Only SyncPromiseAdapter is supported'); + return (int) max($codes); } - throw new RuntimeException('Unexpected response from StandardServer::executePsrRequest'); - - // @codeCoverageIgnoreEnd + throw new RuntimeException('Only SyncPromiseAdapter is supported'); } private function isGraphqlRequest(ServerRequestInterface $request): bool diff --git a/src/InputTypeUtils.php b/src/InputTypeUtils.php index 3e4ad37fbb..319fc7eebf 100644 --- a/src/InputTypeUtils.php +++ b/src/InputTypeUtils.php @@ -73,7 +73,6 @@ private function validateReturnType(ReflectionMethod $refMethod): Fqsen $typeResolver = new TypeResolver(); $phpdocType = $typeResolver->resolve($type); - assert($phpdocType !== null); $phpdocType = $this->resolveSelf($phpdocType, $refMethod->getDeclaringClass()); if (! $phpdocType instanceof Object_) { throw MissingTypeHintRuntimeException::invalidReturnType($refMethod); diff --git a/src/Mappers/Parameters/TypeHandler.php b/src/Mappers/Parameters/TypeHandler.php index b4b8d098ee..cd1a2d6b5e 100644 --- a/src/Mappers/Parameters/TypeHandler.php +++ b/src/Mappers/Parameters/TypeHandler.php @@ -53,7 +53,6 @@ use function explode; use function in_array; use function iterator_to_array; -use function method_exists; use function reset; use function trim; @@ -74,7 +73,10 @@ public function __construct( $this->phpDocumentorTypeResolver = new PhpDocumentorTypeResolver(); } - public function mapReturnType(ReflectionMethod $refMethod, DocBlock $docBlockObj): GraphQLType&OutputType + public function mapReturnType( + ReflectionMethod $refMethod, + DocBlock $docBlockObj, + ): GraphQLType&OutputType { $returnType = $refMethod->getReturnType(); if ($returnType !== null) { @@ -94,7 +96,7 @@ public function mapReturnType(ReflectionMethod $refMethod, DocBlock $docBlockObj $refMethod, $docBlockObj, ); - assert($type instanceof GraphQLType && $type instanceof OutputType); + assert($type instanceof OutputType); } catch (CannotMapTypeExceptionInterface $e) { $e->addReturnInfo($refMethod); throw $e; @@ -158,7 +160,12 @@ private function getDocBlockPropertyType(DocBlock $docBlock, ReflectionProperty return reset($varTags)->getType(); } - public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, Type|null $paramTagType, ParameterAnnotations $parameterAnnotations): ParameterInterface + public function mapParameter( + ReflectionParameter $parameter, + DocBlock $docBlock, + Type|null $paramTagType, + ParameterAnnotations $parameterAnnotations, + ): ParameterInterface { $hideParameter = $parameterAnnotations->getAnnotationByType(HideParameter::class); if ($hideParameter) { @@ -318,21 +325,14 @@ public function mapInputProperty( } if ($isNullable === null) { - $isNullable = false; - // getType function on property reflection is available only since PHP 7.4 - if (method_exists($refProperty, 'getType')) { - $refType = $refProperty->getType(); - if ($refType !== null) { - $isNullable = $refType->allowsNull(); - } - } + $isNullable = $refProperty->getType()?->allowsNull() ?? false; } if ($inputTypeName) { $inputType = $this->typeResolver->mapNameToInputType($inputTypeName); } else { $inputType = $this->mapPropertyType($refProperty, $docBlock, true, $argumentName, $isNullable); - assert($inputType instanceof InputType && $inputType instanceof GraphQLType); + assert($inputType instanceof InputType); } $hasDefault = $defaultValue !== null || $isNullable; @@ -452,8 +452,6 @@ private function reflectionTypeToPhpDocType(ReflectionType $type, ReflectionClas assert($type instanceof ReflectionNamedType || $type instanceof ReflectionUnionType); if ($type instanceof ReflectionNamedType) { $phpdocType = $this->phpDocumentorTypeResolver->resolve($type->getName()); - assert($phpdocType !== null); - $phpdocType = $this->resolveSelf($phpdocType, $reflectionClass); if ($type->allowsNull()) { @@ -467,8 +465,6 @@ private function reflectionTypeToPhpDocType(ReflectionType $type, ReflectionClas function ($namedType) use ($reflectionClass): Type { assert($namedType instanceof ReflectionNamedType); $phpdocType = $this->phpDocumentorTypeResolver->resolve($namedType->getName()); - assert($phpdocType !== null); - $phpdocType = $this->resolveSelf($phpdocType, $reflectionClass); if ($namedType->allowsNull()) { diff --git a/src/Mappers/Proxys/MutableAdapterTrait.php b/src/Mappers/Proxys/MutableAdapterTrait.php index f4f2f8b3ad..5c780b2471 100644 --- a/src/Mappers/Proxys/MutableAdapterTrait.php +++ b/src/Mappers/Proxys/MutableAdapterTrait.php @@ -39,13 +39,13 @@ public function assertValid(): void $this->type->assertValid(); } - public function jsonSerialize():string + public function jsonSerialize(): string { return $this->type->jsonSerialize(); } - public function toString():string + public function toString(): string { return $this->type->toString(); } diff --git a/src/Mappers/Proxys/MutableInterfaceTypeAdapter.php b/src/Mappers/Proxys/MutableInterfaceTypeAdapter.php index 2f179ab4e1..ffa954aa91 100644 --- a/src/Mappers/Proxys/MutableInterfaceTypeAdapter.php +++ b/src/Mappers/Proxys/MutableInterfaceTypeAdapter.php @@ -3,22 +3,9 @@ namespace TheCodingMachine\GraphQLite\Mappers\Proxys; -use Exception; -use GraphQL\Error\InvariantViolation; -use GraphQL\Type\Definition\FieldDefinition; use GraphQL\Type\Definition\InterfaceType; -use GraphQL\Type\Definition\ObjectType; -use GraphQL\Type\Definition\ResolveInfo; -use GraphQL\Utils\Utils; -use RuntimeException; -use TheCodingMachine\GraphQLite\Types\MutableInterface; +use TheCodingMachine\GraphQLite\Mappers\Proxys\MutableAdapterTrait; use TheCodingMachine\GraphQLite\Types\MutableInterfaceType; -use TheCodingMachine\GraphQLite\Types\NoFieldsException; -use function call_user_func; -use function is_array; -use function is_callable; -use function is_string; -use function sprintf; /** * An adapter class (actually a proxy) that adds the "mutable" feature to any Webonyx ObjectType. @@ -27,7 +14,6 @@ */ final class MutableInterfaceTypeAdapter extends MutableInterfaceType { - /** @use MutableAdapterTrait */ use MutableAdapterTrait; public function __construct(InterfaceType $type, ?string $className = null) @@ -35,6 +21,7 @@ public function __construct(InterfaceType $type, ?string $className = null) $this->type = $type; $this->className = $className; $this->name = $type->name; + $this->description = $type->description; $this->config = $type->config; $this->astNode = $type->astNode; $this->extensionASTNodes = $type->extensionASTNodes; diff --git a/src/Mappers/Proxys/MutableObjectTypeAdapter.php b/src/Mappers/Proxys/MutableObjectTypeAdapter.php index cae384e1e0..53ac3e4fc6 100644 --- a/src/Mappers/Proxys/MutableObjectTypeAdapter.php +++ b/src/Mappers/Proxys/MutableObjectTypeAdapter.php @@ -3,23 +3,12 @@ namespace TheCodingMachine\GraphQLite\Mappers\Proxys; -use Exception; -use GraphQL\Error\InvariantViolation; -use GraphQL\Type\Definition\FieldDefinition; use GraphQL\Type\Definition\InterfaceType; use GraphQL\Type\Definition\ObjectType; use GraphQL\Type\Definition\ResolveInfo; -use GraphQL\Utils\Utils; -use RuntimeException; -use TheCodingMachine\GraphQLite\Types\MutableInterface; +use TheCodingMachine\GraphQLite\Mappers\Proxys\MutableAdapterTrait; use TheCodingMachine\GraphQLite\Types\MutableObjectType; -use TheCodingMachine\GraphQLite\Types\NoFieldsException; use function assert; -use function call_user_func; -use function is_array; -use function is_callable; -use function is_string; -use function sprintf; /** * An adapter class (actually a proxy) that adds the "mutable" feature to any Webonyx ObjectType. @@ -28,7 +17,6 @@ */ final class MutableObjectTypeAdapter extends MutableObjectType { - /** @use MutableAdapterTrait */ use MutableAdapterTrait; public function __construct(ObjectType $type, ?string $className = null) @@ -36,6 +24,7 @@ public function __construct(ObjectType $type, ?string $className = null) $this->type = $type; $this->className = $className; $this->name = $type->name; + $this->description = $type->description; $this->config = $type->config; $this->astNode = $type->astNode; $this->extensionASTNodes = $type->extensionASTNodes; diff --git a/src/Mappers/RecursiveTypeMapper.php b/src/Mappers/RecursiveTypeMapper.php index f55c341419..12f6d8af43 100644 --- a/src/Mappers/RecursiveTypeMapper.php +++ b/src/Mappers/RecursiveTypeMapper.php @@ -237,7 +237,6 @@ public function findInterfaces(string $className): array { $interfaces = []; - /** @var array> $implements */ $implements = class_implements($className); foreach ($implements as $interface) { if (! $this->typeMapper->canMapClassToType($interface)) { @@ -359,7 +358,7 @@ public function mapClassToInterfaceOrType(string $className, OutputType|null $su $supportedClasses = $this->getClassTree(); if ($objectType instanceof ObjectFromInterfaceType) { $this->interfaces[$cacheKey] = $objectType->getInterfaces()[0]; - } elseif ($objectType instanceof MutableObjectType && isset($supportedClasses[$closestClassName]) && ! empty($supportedClasses[$closestClassName]->getChildren())) { + } elseif (isset($supportedClasses[$closestClassName]) && ! empty($supportedClasses[$closestClassName]->getChildren())) { // Cast as an interface $this->interfaces[$cacheKey] = new InterfaceFromObjectType($this->namingStrategy->getInterfaceNameFromConcreteName($objectType->name), $objectType, $subType, $this); $this->typeRegistry->registerType($this->interfaces[$cacheKey]); diff --git a/src/Mappers/Root/EnumTypeMapper.php b/src/Mappers/Root/EnumTypeMapper.php index 64d4696b9c..87e575bb6c 100644 --- a/src/Mappers/Root/EnumTypeMapper.php +++ b/src/Mappers/Root/EnumTypeMapper.php @@ -17,6 +17,7 @@ use ReflectionMethod; use ReflectionProperty; use TheCodingMachine\GraphQLite\AnnotationReader; +use TheCodingMachine\GraphQLite\Annotations\Type as TypeAnnotation; use TheCodingMachine\GraphQLite\Discovery\Cache\ClassFinderComputedCache; use TheCodingMachine\GraphQLite\Discovery\ClassFinder; use TheCodingMachine\GraphQLite\Reflection\DocBlock\DocBlockFactory; @@ -119,10 +120,11 @@ private function mapByClassName(string $enumClass): EnumType|null $typeName = $typeAnnotation?->getName() ?? $reflectionEnum->getShortName(); // Expose values instead of names if specifically configured to and if enum is string-backed - $useValues = $typeAnnotation !== null && - $typeAnnotation->useEnumValues() && - $reflectionEnum->isBacked() && - (string) $reflectionEnum->getBackingType() === 'string'; + $useValues = $typeAnnotation !== null + && $typeAnnotation instanceof TypeAnnotation + && $typeAnnotation->useEnumValues() + && $reflectionEnum->isBacked() + && (string) $reflectionEnum->getBackingType() === 'string'; $enumDescription = $this->docBlockFactory ->create($reflectionEnum) diff --git a/src/Mappers/Root/IteratorTypeMapper.php b/src/Mappers/Root/IteratorTypeMapper.php index 8d9f9fb1da..767f0489f6 100644 --- a/src/Mappers/Root/IteratorTypeMapper.php +++ b/src/Mappers/Root/IteratorTypeMapper.php @@ -146,7 +146,7 @@ private function toGraphQLType(Compound $type, Closure $topToGraphQLType, bool $ // By convention, we trim the NonNull part of the "$subGraphQlType" if ($subGraphQlType instanceof NonNull) { $subGraphQlType = $subGraphQlType->getWrappedType(); - assert($subGraphQlType instanceof OutputType && $subGraphQlType instanceof GraphQLType); + assert($subGraphQlType instanceof OutputType); } } else { $subGraphQlType = null; diff --git a/src/Mappers/StaticClassListTypeMapperFactory.php b/src/Mappers/StaticClassListTypeMapperFactory.php index 09fca187ae..4e82017f20 100644 --- a/src/Mappers/StaticClassListTypeMapperFactory.php +++ b/src/Mappers/StaticClassListTypeMapperFactory.php @@ -16,7 +16,7 @@ final class StaticClassListTypeMapperFactory implements TypeMapperFactoryInterfa /** * StaticClassListTypeMapperFactory constructor. * - * @param array $classList The list of classes to be scanned. + * @param list $classList The list of classes to be scanned. */ public function __construct( private array $classList, diff --git a/src/Middlewares/SecurityFieldMiddleware.php b/src/Middlewares/SecurityFieldMiddleware.php index d9fabaa0c1..f9d744afa7 100644 --- a/src/Middlewares/SecurityFieldMiddleware.php +++ b/src/Middlewares/SecurityFieldMiddleware.php @@ -19,19 +19,23 @@ use function array_combine; use function array_keys; use function assert; -use function is_array; /** * A field middleware that reads "Security" Symfony annotations. */ class SecurityFieldMiddleware implements FieldMiddlewareInterface { - public function __construct(private readonly ExpressionLanguage $language, private readonly AuthenticationServiceInterface $authenticationService, private readonly AuthorizationServiceInterface $authorizationService/*, ?LoggerInterface $logger = null*/) - { - /*$this->logger = $logger;*/ + public function __construct( + private readonly ExpressionLanguage $language, + private readonly AuthenticationServiceInterface $authenticationService, + private readonly AuthorizationServiceInterface $authorizationService, + ) { } - public function process(QueryFieldDescriptor $queryFieldDescriptor, FieldHandlerInterface $fieldHandler): FieldDefinition|null + public function process( + QueryFieldDescriptor $queryFieldDescriptor, + FieldHandlerInterface $fieldHandler, + ): FieldDefinition|null { $annotations = $queryFieldDescriptor->getMiddlewareAnnotations(); /** @var Security[] $securityAnnotations */ @@ -116,24 +120,6 @@ private function getVariables(array $args, array $parameters, object|null $sourc $argsName = array_keys($parameters); $argsByName = array_combine($argsName, $args); - assert(is_array($argsByName)); - - /*if ($diff = array_intersect(array_keys($variables), array_keys($argsName))) { - foreach ($diff as $key => $variableName) { - if ($variables[$variableName] !== $argsByName[$variableName]) { - continue; - } - - unset($diff[$key]); - } - - if ($diff) { - $singular = count($diff) === 1; - if ($this->logger !== null) { - $this->logger->warning(sprintf('Controller argument%s "%s" collided with the built-in security expression variables. The built-in value%s are being used for the @Security expression.', $singular ? '' : 's', implode('", "', $diff), $singular ? 's' : '')); - } - } - }*/ return $variables + $argsByName; } diff --git a/src/Middlewares/SecurityInputFieldMiddleware.php b/src/Middlewares/SecurityInputFieldMiddleware.php index 9eaba0b626..c2e77c207b 100644 --- a/src/Middlewares/SecurityInputFieldMiddleware.php +++ b/src/Middlewares/SecurityInputFieldMiddleware.php @@ -15,8 +15,6 @@ use function array_combine; use function array_keys; -use function assert; -use function is_array; /** * A field input middleware that reads "Security" Symfony annotations. @@ -85,7 +83,6 @@ private function getVariables(array $args, array $parameters, object|null $sourc $argsName = array_keys($parameters); $argsByName = array_combine($argsName, $args); - assert(is_array($argsByName)); return $variables + $argsByName; } diff --git a/src/Schema.php b/src/Schema.php index 2e53d3c1c7..f90c7fbbff 100644 --- a/src/Schema.php +++ b/src/Schema.php @@ -11,8 +11,6 @@ use TheCodingMachine\GraphQLite\Mappers\Root\RootTypeMapperInterface; use TheCodingMachine\GraphQLite\Types\TypeResolver; -use function assert; - /** * A GraphQL schema that takes into constructor argument a QueryProvider. * @@ -112,9 +110,7 @@ public function __construct( return $subscription; } - $type = $rootTypeMapper->mapNameToType($name); - assert($type instanceof Type); - return $type; + return $rootTypeMapper->mapNameToType($name); }); $typeResolver->registerSchema($this); diff --git a/src/Types/EnumType.php b/src/Types/EnumType.php index 9e48f98d22..25ff52af43 100644 --- a/src/Types/EnumType.php +++ b/src/Types/EnumType.php @@ -19,7 +19,7 @@ class EnumType extends BaseEnumType { /** * @param class-string $enumName - * @param array $caseDescriptions + * @param array $caseDescriptions * @param array $caseDeprecationReasons */ public function __construct( diff --git a/src/Types/ID.php b/src/Types/ID.php index 950214a4ed..64cf0599c4 100644 --- a/src/Types/ID.php +++ b/src/Types/ID.php @@ -7,7 +7,6 @@ use InvalidArgumentException; use function is_bool; -use function is_object; use function is_scalar; use function method_exists; @@ -21,7 +20,7 @@ class ID */ public function __construct(private readonly bool|float|int|string|object $value) { - if (! is_scalar($value) && (! is_object($value) || ! method_exists($value, '__toString'))) { + if (! is_scalar($value) && ! method_exists($value, '__toString')) { throw new InvalidArgumentException('ID constructor cannot be passed a non scalar value.'); } } diff --git a/src/Types/TypeAnnotatedObjectType.php b/src/Types/TypeAnnotatedObjectType.php index 9954c4daef..0fcf296432 100644 --- a/src/Types/TypeAnnotatedObjectType.php +++ b/src/Types/TypeAnnotatedObjectType.php @@ -61,7 +61,6 @@ public static function createFromAnnotatedClass(string $typeName, string $classN // FIXME: add an interface with a @Type that is implemented by noone. // Check that it does not trigger an exception. - /** @var array> $interfaces */ $interfaces = class_implements($className); foreach ($interfaces as $interface) { if (! $recursiveTypeMapper->canMapClassToType($interface)) { diff --git a/tests/AnnotationReaderTest.php b/tests/AnnotationReaderTest.php index f7493dead9..36e1a1f220 100644 --- a/tests/AnnotationReaderTest.php +++ b/tests/AnnotationReaderTest.php @@ -9,15 +9,12 @@ use ReflectionMethod; use TheCodingMachine\GraphQLite\Annotations\Autowire; use TheCodingMachine\GraphQLite\Annotations\Exceptions\ClassNotFoundException; -use TheCodingMachine\GraphQLite\Annotations\Exceptions\InvalidParameterException; use TheCodingMachine\GraphQLite\Annotations\Field; use TheCodingMachine\GraphQLite\Annotations\Security; use TheCodingMachine\GraphQLite\Annotations\Type; use TheCodingMachine\GraphQLite\Fixtures\Annotations\ClassWithInvalidClassAnnotation; use TheCodingMachine\GraphQLite\Fixtures\Annotations\ClassWithInvalidExtendTypeAnnotation; use TheCodingMachine\GraphQLite\Fixtures\Annotations\ClassWithInvalidTypeAnnotation; -use TheCodingMachine\GraphQLite\Fixtures\Annotations\ClassWithTargetMethodParameterAnnotation; -use TheCodingMachine\GraphQLite\Fixtures\Annotations\TargetMethodParameterAnnotation; use TheCodingMachine\GraphQLite\Fixtures\Attributes\TestType; class AnnotationReaderTest extends TestCase @@ -26,7 +23,10 @@ public function testBadAnnotation(): void { $annotationReader = new AnnotationReader(); - $type = $annotationReader->getTypeAnnotation(new ReflectionClass(ClassWithInvalidClassAnnotation::class)); + $type = $annotationReader->getTypeAnnotation( + new ReflectionClass(ClassWithInvalidClassAnnotation::class), + ); + $this->assertNull($type); } @@ -34,14 +34,20 @@ public function testSmellyAnnotation(): void { $annotationReader = new AnnotationReader(); - $this->assertNull($annotationReader->getTypeAnnotation(new ReflectionClass(ClassWithInvalidTypeAnnotation::class))); + $this->assertNull($annotationReader->getTypeAnnotation( + new ReflectionClass(ClassWithInvalidTypeAnnotation::class)), + ); } public function testGetAnnotationsWithBadAnnotation(): void { $annotationReader = new AnnotationReader(); - $types = $annotationReader->getClassAnnotations(new ReflectionClass(ClassWithInvalidClassAnnotation::class), Type::class); + $types = $annotationReader->getClassAnnotations( + new ReflectionClass(ClassWithInvalidClassAnnotation::class), + Type::class, + ); + $this->assertSame([], $types); } @@ -49,7 +55,10 @@ public function testMethodWithBadAnnotation(): void { $annotationReader = new AnnotationReader(); - $type = $annotationReader->getRequestAnnotation(new ReflectionMethod(ClassWithInvalidClassAnnotation::class, 'testMethod'), Field::class); + $type = $annotationReader->getRequestAnnotation( + new ReflectionMethod(ClassWithInvalidClassAnnotation::class, 'testMethod'), + Field::class, + ); $this->assertNull($type); } @@ -59,14 +68,20 @@ public function testExtendAnnotationException(): void $this->expectException(ClassNotFoundException::class); $this->expectExceptionMessage("Could not autoload class 'foo' defined in #[ExtendType] attribute of class 'TheCodingMachine\GraphQLite\Fixtures\Annotations\ClassWithInvalidExtendTypeAnnotation'"); - $annotationReader->getExtendTypeAnnotation(new ReflectionClass(ClassWithInvalidExtendTypeAnnotation::class)); + $annotationReader->getExtendTypeAnnotation( + new ReflectionClass(ClassWithInvalidExtendTypeAnnotation::class), + ); } public function testMethodsWithBadAnnotation(): void { $annotationReader = new AnnotationReader(); - $type = $annotationReader->getMethodAnnotations(new ReflectionMethod(ClassWithInvalidClassAnnotation::class, 'testMethod'), Field::class); + $type = $annotationReader->getMethodAnnotations( + new ReflectionMethod(ClassWithInvalidClassAnnotation::class, 'testMethod'), + Field::class, + ); + $this->assertSame([], $type); } @@ -102,7 +117,11 @@ public function testPhp8AttributeMethodAnnotation(): void { $annotationReader = new AnnotationReader(); - $type = $annotationReader->getRequestAnnotation(new ReflectionMethod(TestType::class, 'getField'), Field::class); + $type = $annotationReader->getRequestAnnotation( + new ReflectionMethod(TestType::class, 'getField'), + Field::class, + ); + $this->assertInstanceOf(Field::class, $type); } @@ -110,7 +129,9 @@ public function testPhp8AttributeMethodAnnotations(): void { $annotationReader = new AnnotationReader(); - $middlewareAnnotations = $annotationReader->getMiddlewareAnnotations(new ReflectionMethod(TestType::class, 'getField')); + $middlewareAnnotations = $annotationReader->getMiddlewareAnnotations( + new ReflectionMethod(TestType::class, 'getField'), + ); /** @var Security[] $securitys */ $securitys = $middlewareAnnotations->getAnnotationsByType(Security::class); @@ -124,34 +145,14 @@ public function testPhp8AttributeParameterAnnotations(): void { $annotationReader = new AnnotationReader(); - $parameterAnnotations = $annotationReader->getParameterAnnotationsPerParameter((new ReflectionMethod(self::class, 'method1'))->getParameters()); - - $this->assertInstanceOf(Autowire::class, $parameterAnnotations['dao']->getAnnotationByType(Autowire::class)); - } - - /** - * This functionality can be dropped with next major release (8.0) with added explicit deprecations before release. - */ - public function testPhp8AttributeParameterAnnotationsForTargetMethod(): void - { - $annotationReader = new AnnotationReader(); - - $parameterAnnotations = $annotationReader->getParameterAnnotationsPerParameter((new ReflectionMethod(ClassWithTargetMethodParameterAnnotation::class, 'method'))->getParameters()); - - $this->assertInstanceOf(TargetMethodParameterAnnotation::class, $parameterAnnotations['bar']->getAnnotationByType(TargetMethodParameterAnnotation::class)); - } - - /** - * This functionality can be dropped with next major release (8.0) with added explicit deprecations before release. - */ - public function testPhp8AttributeParameterAnnotationsForTargetMethodWithInvalidTargetParameter(): void - { - $annotationReader = new AnnotationReader(); - - $this->expectException(InvalidParameterException::class); - $this->expectExceptionMessage('Parameter "unexistent" declared in annotation "TheCodingMachine\GraphQLite\Fixtures\Annotations\TargetMethodParameterAnnotation" of method "TheCodingMachine\GraphQLite\Fixtures\Annotations\ClassWithTargetMethodParameterAnnotation::methodWithInvalidAnnotation()" does not exist.'); + $parameterAnnotations = $annotationReader->getParameterAnnotationsPerParameter( + (new ReflectionMethod(self::class, 'method1'))->getParameters(), + ); - $annotationReader->getParameterAnnotationsPerParameter((new ReflectionMethod(ClassWithTargetMethodParameterAnnotation::class, 'methodWithInvalidAnnotation'))->getParameters()); + $this->assertInstanceOf( + Autowire::class, + $parameterAnnotations['dao']->getAnnotationByType(Autowire::class), + ); } /** @noinspection PhpUnusedPrivateMethodInspection Used in {@see testPhp8AttributeParameterAnnotations} */ diff --git a/tests/Annotations/SecurityTest.php b/tests/Annotations/SecurityTest.php index a35275092f..3f82ae129d 100644 --- a/tests/Annotations/SecurityTest.php +++ b/tests/Annotations/SecurityTest.php @@ -4,8 +4,6 @@ use BadMethodCallException; use PHPUnit\Framework\TestCase; -use stdClass; -use TypeError; class SecurityTest extends TestCase { diff --git a/tests/FieldsBuilderTest.php b/tests/FieldsBuilderTest.php index 0cd11d0d49..c280218fec 100644 --- a/tests/FieldsBuilderTest.php +++ b/tests/FieldsBuilderTest.php @@ -37,11 +37,13 @@ use TheCodingMachine\GraphQLite\Fixtures\TestControllerWithParamDateTime; use TheCodingMachine\GraphQLite\Fixtures\TestControllerWithReturnDateTime; use TheCodingMachine\GraphQLite\Fixtures\TestControllerWithUnionInputParam; +use TheCodingMachine\GraphQLite\Fixtures\TestDeprecatedField; use TheCodingMachine\GraphQLite\Fixtures\TestDoubleReturnTag; use TheCodingMachine\GraphQLite\Fixtures\TestEnum; use TheCodingMachine\GraphQLite\Fixtures\TestFieldBadInputType; use TheCodingMachine\GraphQLite\Fixtures\TestFieldBadOutputType; use TheCodingMachine\GraphQLite\Fixtures\TestObject; +use TheCodingMachine\GraphQLite\Fixtures\TestObjectWithDeprecatedField; use TheCodingMachine\GraphQLite\Fixtures\TestSelfType; use TheCodingMachine\GraphQLite\Fixtures\TestSourceFieldBadOutputType; use TheCodingMachine\GraphQLite\Fixtures\TestSourceFieldBadOutputType2; @@ -922,4 +924,20 @@ public function testSourceNameInSourceAndMagicFields(): void $result = $resolve($source, [], null, $this->createMock(ResolveInfo::class)); $this->assertSame('bar value', $result); } + + public function testDeprecationInDocblock(): void + { + $fieldsBuilder = $this->buildFieldsBuilder(); + $inputFields = $fieldsBuilder->getFields( + new TestDeprecatedField(), + 'Test', + ); + + $this->assertCount(2, $inputFields); + + $this->assertEquals('this is deprecated', $inputFields['deprecatedField']->deprecationReason); + $this->assertTrue( $inputFields['deprecatedField']->isDeprecated()); + $this->assertNull( $inputFields['name']->deprecationReason); + $this->assertFalse( $inputFields['name']->isDeprecated()); + } } diff --git a/tests/Fixtures/Annotations/ClassWithTargetMethodParameterAnnotation.php b/tests/Fixtures/Annotations/ClassWithTargetMethodParameterAnnotation.php deleted file mode 100644 index 6830f2bbdf..0000000000 --- a/tests/Fixtures/Annotations/ClassWithTargetMethodParameterAnnotation.php +++ /dev/null @@ -1,21 +0,0 @@ -target; - } -} diff --git a/tests/Fixtures/TestDeprecatedField.php b/tests/Fixtures/TestDeprecatedField.php new file mode 100644 index 0000000000..c417836ceb --- /dev/null +++ b/tests/Fixtures/TestDeprecatedField.php @@ -0,0 +1,16 @@ +