From e1c382d5d4d3400d1254ad8175cb5edc843e9200 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 10 Dec 2019 04:41:52 +0000 Subject: [PATCH 01/13] Update doctrine/coding-standard requirement from ^6.0 to ^6.0 || ^7.0 Updates the requirements on [doctrine/coding-standard](https://github.com/doctrine/coding-standard) to permit the latest version. - [Release notes](https://github.com/doctrine/coding-standard/releases) - [Commits](https://github.com/doctrine/coding-standard/compare/6.0.0...7.0.0) Signed-off-by: dependabot-preview[bot] --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6675cc924d..c94be32068 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "phpstan/phpstan": "^0.11", "beberlei/porpaginas": "^1.2", "myclabs/php-enum": "^1.6.6", - "doctrine/coding-standard": "^6.0", + "doctrine/coding-standard": "^6.0 || ^7.0", "phpstan/phpstan-webmozart-assert": "^0.11.2", "phpstan/extension-installer": "^1.0", "thecodingmachine/phpstan-strict-rules": "^0.11.2", From 5aac84e93f75f173e7e2c87507d5d303f79f3d61 Mon Sep 17 00:00:00 2001 From: Florian Engelhardt Date: Fri, 22 Nov 2019 11:14:15 +0100 Subject: [PATCH 02/13] Add test to expect exception in duplicate queries --- .../TestControllerWithDuplicateQuery.php | 25 +++++++++++++++++++ tests/SchemaFactoryTest.php | 18 +++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 tests/Fixtures/DuplicateQueries/TestControllerWithDuplicateQuery.php diff --git a/tests/Fixtures/DuplicateQueries/TestControllerWithDuplicateQuery.php b/tests/Fixtures/DuplicateQueries/TestControllerWithDuplicateQuery.php new file mode 100644 index 0000000000..6fd62a18f0 --- /dev/null +++ b/tests/Fixtures/DuplicateQueries/TestControllerWithDuplicateQuery.php @@ -0,0 +1,25 @@ +toArray(Debug::RETHROW_INTERNAL_EXCEPTIONS)['data']); } + + public function testDuplicateQueryException(): void + { + $factory = new SchemaFactory( + new ArrayCache(), + new BasicAutoWiringContainer( + new EmptyContainer() + ) + ); + $factory->setAuthenticationService(new VoidAuthenticationService()) + ->setAuthorizationService(new VoidAuthorizationService()) + ->addControllerNamespace('TheCodingMachine\\GraphQLite\\Fixtures\\DuplicateQueries') + ->addTypeNamespace('TheCodingMachine\\GraphQLite\\Fixtures\\Integration'); + + $this->expectException(GraphQLRuntimeException::class); + $schema = $factory->createSchema(); + } + } From a564f66d58d19edccd4b1fbac2f976fc34d8412f Mon Sep 17 00:00:00 2001 From: Florian Engelhardt Date: Fri, 22 Nov 2019 11:28:46 +0100 Subject: [PATCH 03/13] Use more specific exception class --- tests/SchemaFactoryTest.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/SchemaFactoryTest.php b/tests/SchemaFactoryTest.php index d065285c0f..8d86c790a3 100644 --- a/tests/SchemaFactoryTest.php +++ b/tests/SchemaFactoryTest.php @@ -17,6 +17,7 @@ use TheCodingMachine\GraphQLite\Containers\EmptyContainer; use TheCodingMachine\GraphQLite\Mappers\CannotMapTypeException; use TheCodingMachine\GraphQLite\Mappers\CompositeTypeMapper; +use TheCodingMachine\GraphQLite\Mappers\DuplicateMappingException; use TheCodingMachine\GraphQLite\Mappers\Parameters\ContainerParameterHandler; use TheCodingMachine\GraphQLite\Mappers\Parameters\TypeHandler; use TheCodingMachine\GraphQLite\Mappers\RecursiveTypeMapperInterface; @@ -32,6 +33,7 @@ use TheCodingMachine\GraphQLite\Security\VoidAuthorizationService; use TheCodingMachine\GraphQLite\Fixtures\TestSelfType; + class SchemaFactoryTest extends TestCase { @@ -193,8 +195,17 @@ public function testDuplicateQueryException(): void ->addControllerNamespace('TheCodingMachine\\GraphQLite\\Fixtures\\DuplicateQueries') ->addTypeNamespace('TheCodingMachine\\GraphQLite\\Fixtures\\Integration'); - $this->expectException(GraphQLRuntimeException::class); + $this->expectException(DuplicateMappingException::class); $schema = $factory->createSchema(); + $queryString = ' + query { + duplicateQuery + } + '; + GraphQL::executeQuery( + $schema, + $queryString + ); } } From 204a04a29acdce638c0abefa9bf679cd80f3b927 Mon Sep 17 00:00:00 2001 From: Florian Engelhardt Date: Fri, 22 Nov 2019 11:36:56 +0100 Subject: [PATCH 04/13] Throw an exception if duplicate queries are found in controller --- src/FieldsBuilder.php | 9 +++++++-- src/Mappers/DuplicateMappingException.php | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/FieldsBuilder.php b/src/FieldsBuilder.php index c1f5afd783..45a05d0cf6 100644 --- a/src/FieldsBuilder.php +++ b/src/FieldsBuilder.php @@ -17,6 +17,7 @@ use TheCodingMachine\GraphQLite\Annotations\SourceFieldInterface; use TheCodingMachine\GraphQLite\Mappers\CannotMapTypeException; use TheCodingMachine\GraphQLite\Mappers\CannotMapTypeExceptionInterface; +use TheCodingMachine\GraphQLite\Mappers\DuplicateMappingException; use TheCodingMachine\GraphQLite\Mappers\Parameters\ParameterMiddlewareInterface; use TheCodingMachine\GraphQLite\Mappers\Parameters\TypeHandler; use TheCodingMachine\GraphQLite\Mappers\RecursiveTypeMapperInterface; @@ -31,6 +32,7 @@ use Webmozart\Assert\Assert; use function array_merge; use function array_shift; +use function array_values; use function get_parent_class; use function ucfirst; @@ -317,7 +319,10 @@ public function handle(QueryFieldDescriptor $fieldDescriptor): ?FieldDefinition }); if ($field !== null) { - $queryList[] = $field; + if (isset($queryList[$fieldDescriptor->getName()])) { + throw DuplicateMappingException::createForQuery($refClass->getName(), $fieldDescriptor->getName()); + } + $queryList[$fieldDescriptor->getName()] = $field; } /*if ($unauthorized) { @@ -332,7 +337,7 @@ public function handle(QueryFieldDescriptor $fieldDescriptor): ?FieldDefinition }*/ } - return $queryList; + return array_values($queryList); } /** diff --git a/src/Mappers/DuplicateMappingException.php b/src/Mappers/DuplicateMappingException.php index 912324aa0f..99270d24a8 100644 --- a/src/Mappers/DuplicateMappingException.php +++ b/src/Mappers/DuplicateMappingException.php @@ -23,4 +23,9 @@ public static function createForTypeName(string $type, string $sourceClass1, str { throw new self(sprintf("The type '%s' is created by 2 different classes: '%s' and '%s'", $type, $sourceClass1, $sourceClass2)); } + + public static function createForQuery(string $sourceClass, string $queryName): self + { + throw new self(sprintf("The query '%s' is duplicate in class '%s'", $queryName, $sourceClass)); + } } From 6a11bd57d8d9484c5b75f9665ebd1a51f7ab8cf0 Mon Sep 17 00:00:00 2001 From: Florian Engelhardt Date: Mon, 2 Dec 2019 12:29:29 +0100 Subject: [PATCH 05/13] Fix usage of deprecated symfony array cache --- tests/SchemaFactoryTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/SchemaFactoryTest.php b/tests/SchemaFactoryTest.php index 8d86c790a3..ddce2fa338 100644 --- a/tests/SchemaFactoryTest.php +++ b/tests/SchemaFactoryTest.php @@ -10,8 +10,6 @@ use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\Adapter\Psr16Adapter; use Symfony\Component\Cache\Psr16Cache; -use Symfony\Component\Cache\Simple\ArrayCache; -use Symfony\Component\Cache\Simple\PhpFilesCache; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use TheCodingMachine\GraphQLite\Containers\BasicAutoWiringContainer; use TheCodingMachine\GraphQLite\Containers\EmptyContainer; @@ -185,7 +183,7 @@ private function doTestSchema(Schema $schema): void public function testDuplicateQueryException(): void { $factory = new SchemaFactory( - new ArrayCache(), + new Psr16Cache(new ArrayAdapter()), new BasicAutoWiringContainer( new EmptyContainer() ) From 6ced8b35a62e432cf9aee405654245ba1ea74058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 16 Dec 2019 16:37:44 +0100 Subject: [PATCH 06/13] Migrating to PHPStan 0.12 --- composer.json | 10 ++++---- phpstan.neon | 7 ++++++ src/AnnotationReader.php | 15 ++++++++++++ src/Annotations/ExtendType.php | 17 +++++++------- src/Annotations/Type.php | 13 +++++++---- src/FieldsBuilder.php | 23 +++++++++++-------- src/InputTypeUtils.php | 3 ++- src/InvalidPrefetchMethodRuntimeException.php | 3 +++ src/Mappers/AbstractTypeMapper.php | 4 +--- .../CannotMapTypeExceptionInterface.php | 6 +++++ src/Mappers/CannotMapTypeTrait.php | 6 +++++ src/Mappers/GlobExtendTypeMapperCache.php | 1 + src/Mappers/GlobTypeMapper.php | 4 ++-- src/Mappers/GlobTypeMapperCache.php | 1 + .../Parameters/ContainerParameterHandler.php | 2 +- .../ResolveInfoParameterHandler.php | 2 +- src/Mappers/Parameters/TypeHandler.php | 7 +++++- src/Mappers/Root/IteratorTypeMapper.php | 1 + src/Mappers/StaticClassListTypeMapper.php | 4 ++-- src/MissingTypeHintRuntimeException.php | 2 +- src/Reflection/ReflectionInterfaceUtils.php | 4 +++- src/TypeGenerator.php | 2 +- 22 files changed, 94 insertions(+), 43 deletions(-) diff --git a/composer.json b/composer.json index c94be32068..0e758543a3 100644 --- a/composer.json +++ b/composer.json @@ -35,13 +35,13 @@ "phpunit/phpunit": "^8.2.4", "php-coveralls/php-coveralls": "^2.1", "mouf/picotainer": "^1.1", - "phpstan/phpstan": "^0.11", + "phpstan/phpstan": "^0.12.3", "beberlei/porpaginas": "^1.2", "myclabs/php-enum": "^1.6.6", - "doctrine/coding-standard": "^6.0 || ^7.0", - "phpstan/phpstan-webmozart-assert": "^0.11.2", + "doctrine/coding-standard": "^7.0", + "phpstan/phpstan-webmozart-assert": "^0.12", "phpstan/extension-installer": "^1.0", - "thecodingmachine/phpstan-strict-rules": "^0.11.2", + "thecodingmachine/phpstan-strict-rules": "^0.12", "zendframework/zend-diactoros": "^2" }, "suggest": { @@ -58,7 +58,7 @@ } }, "scripts": { - "phpstan": "phpstan analyse src -c phpstan.neon --level=7 --no-progress -vvv", + "phpstan": "phpstan analyse src -c phpstan.neon --level=8 --no-progress -vvv", "cs-check": "phpcs", "cs-fix": "phpcbf", "test": ["@cs-check", "@phpstan", "phpunit"] diff --git a/phpstan.neon b/phpstan.neon index 49a0305c14..054766ad51 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -18,7 +18,14 @@ parameters: - message: '#Parameter \#2 \$subType of method .* expects#' path: src/Mappers/Root/IteratorTypeMapper.php + - + message: '#Unreachable statement - code above always terminates.#' + path: src/Http/WebonyxGraphqlMiddleware.php + - + message: '#Property TheCodingMachine\GraphQLite\Annotations\Type::$class \(class-string|null\) does not accept string.#' + path: src/Annotations/Type.php - '#Call to an undefined method GraphQL\\Error\\ClientAware::getMessage()#' + - '#Method .*::(addSourceFieldInfo|addExtendTypeInfo)\(\) has parameter \$class with generic class ReflectionClass#' #- # message: '#If condition is always true#' # path: src/Middlewares/SecurityFieldMiddleware.php diff --git a/src/AnnotationReader.php b/src/AnnotationReader.php index b8c14c74e7..a41290c910 100644 --- a/src/AnnotationReader.php +++ b/src/AnnotationReader.php @@ -70,6 +70,10 @@ public function __construct(Reader $reader, string $mode = self::STRICT_MODE, ar $this->strictNamespaces = $strictNamespaces; } + /** + * @template T of object + * @param ReflectionClass $refClass + */ public function getTypeAnnotation(ReflectionClass $refClass): ?Type { try { @@ -85,6 +89,10 @@ public function getTypeAnnotation(ReflectionClass $refClass): ?Type return $type; } + /** + * @template T of object + * @param ReflectionClass $refClass + */ public function getExtendTypeAnnotation(ReflectionClass $refClass): ?ExtendType { try { @@ -106,6 +114,8 @@ public function getRequestAnnotation(ReflectionMethod $refMethod, string $annota } /** + * @template T of object + * @param ReflectionClass $refClass * @return SourceField[] */ public function getSourceFields(ReflectionClass $refClass): array @@ -157,6 +167,9 @@ public function getMiddlewareAnnotations(ReflectionMethod $refMethod): Middlewar /** * Returns a class annotation. Does not look in the parent class. + * + * @template T of object + * @param ReflectionClass $refClass */ private function getClassAnnotation(ReflectionClass $refClass, string $annotationClass): ?object { @@ -230,6 +243,8 @@ private function isErrorImportant(string $annotationClass, string $docComment, s /** * Returns the class annotations. Finds in the parents too. * + * @template T of object + * @param ReflectionClass $refClass * @return object[] */ public function getClassAnnotations(ReflectionClass $refClass, string $annotationClass): array diff --git a/src/Annotations/ExtendType.php b/src/Annotations/ExtendType.php index e42ee9ecc9..f7d2d21f3b 100644 --- a/src/Annotations/ExtendType.php +++ b/src/Annotations/ExtendType.php @@ -22,7 +22,7 @@ */ class ExtendType { - /** @var string|null */ + /** @var class-string|null */ private $class; /** @var string|null */ private $name; @@ -35,24 +35,23 @@ public function __construct(array $attributes = []) if (! isset($attributes['class']) && ! isset($attributes['name'])) { throw new BadMethodCallException('In annotation @ExtendType, missing one of the compulsory parameter "class" or "name".'); } - $this->class = $attributes['class'] ?? null; + $class = isset($attributes['class']) ? ltrim($attributes['class'], '\\') : null; $this->name = $attributes['name'] ?? null; - if ($this->class !== null && ! class_exists($this->class) && ! interface_exists($this->class)) { - throw ClassNotFoundException::couldNotFindClass($this->class); + if ($class !== null && ! class_exists($class) && ! interface_exists($class)) { + throw ClassNotFoundException::couldNotFindClass($class); } + $this->class = $class; } /** * Returns the name of the GraphQL query/mutation/field. * If not specified, the name of the method should be used instead. + * + * @return class-string|null */ public function getClass(): ?string { - if ($this->class === null) { - return null; - } - - return ltrim($this->class, '\\'); + return $this->class; } public function getName(): ?string diff --git a/src/Annotations/Type.php b/src/Annotations/Type.php index 008ff7e3c7..31f86da66f 100644 --- a/src/Annotations/Type.php +++ b/src/Annotations/Type.php @@ -27,7 +27,7 @@ */ class Type { - /** @var string|null */ + /** @var class-string|null */ private $class; /** @var string|null */ @@ -74,6 +74,8 @@ public function __construct(array $attributes = []) /** * Returns the fully qualified class name of the targeted class. + * + * @return class-string */ public function getClass(): string { @@ -86,11 +88,12 @@ public function getClass(): string public function setClass(string $class): void { - $this->class = ltrim($class, '\\'); - $isInterface = interface_exists($this->class); - if (! class_exists($this->class) && ! $isInterface) { - throw ClassNotFoundException::couldNotFindClass($this->class); + $class = ltrim($class, '\\'); + $isInterface = interface_exists($class); + if (! class_exists($class) && ! $isInterface) { + throw ClassNotFoundException::couldNotFindClass($class); } + $this->class = $class; if (! $isInterface) { return; diff --git a/src/FieldsBuilder.php b/src/FieldsBuilder.php index 45a05d0cf6..97164d11a7 100644 --- a/src/FieldsBuilder.php +++ b/src/FieldsBuilder.php @@ -34,6 +34,7 @@ use function array_shift; use function array_values; use function get_parent_class; +use function is_string; use function ucfirst; /** @@ -131,11 +132,12 @@ public function getFields(object $controller): array /** * Track Field annotation in a self targeted type * + * @param class-string $className * @return array QueryField indexed by name. */ public function getSelfFields(string $className): array { - $fieldAnnotations = $this->getFieldsByAnnotations(null, Annotations\Field::class, false, $className); + $fieldAnnotations = $this->getFieldsByAnnotations($className, Annotations\Field::class, false); $refClass = new ReflectionClass($className); @@ -193,20 +195,16 @@ public function getParametersForDecorator(ReflectionMethod $refMethod): array } /** + * @param object|class-string $controller The controller instance, or the name of the source class name * @param bool $injectSource Whether to inject the source object or not as the first argument. True for @Field (unless @Type has no class attribute), false for @Query and @Mutation * * @return FieldDefinition[] * - * @throws CannotMapTypeException * @throws ReflectionException */ - private function getFieldsByAnnotations(?object $controller, string $annotationName, bool $injectSource, ?string $sourceClassName = null): array + private function getFieldsByAnnotations($controller, string $annotationName, bool $injectSource): array { - if ($sourceClassName !== null) { - $refClass = new ReflectionClass($sourceClassName); - } else { - $refClass = new ReflectionClass($controller); - } + $refClass = new ReflectionClass($controller); $queryList = []; @@ -297,10 +295,9 @@ private function getFieldsByAnnotations(?object $controller, string $annotationN } else { $type = $this->typeMapper->mapReturnType($refMethod, $docBlockObj); } - if ($sourceClassName !== null) { + if (is_string($controller)) { $fieldDescriptor->setTargetMethodOnSource($methodName); } else { - Assert::notNull($controller); $callable = [$controller, $methodName]; Assert::isCallable($callable); $fieldDescriptor->setCallable($callable); @@ -341,7 +338,9 @@ public function handle(QueryFieldDescriptor $fieldDescriptor): ?FieldDefinition } /** + * @template T of object * @param SourceFieldInterface[] $sourceFields + * @param ReflectionClass $refClass * * @return FieldDefinition[] * @@ -442,6 +441,10 @@ public function handle(QueryFieldDescriptor $fieldDescriptor): ?FieldDefinition return $queryList; } + /** + * @template T of object + * @param ReflectionClass $reflectionClass + */ private function getMethodFromPropertyName(ReflectionClass $reflectionClass, string $propertyName): ReflectionMethod { if ($reflectionClass->hasMethod($propertyName)) { diff --git a/src/InputTypeUtils.php b/src/InputTypeUtils.php index 29127cd036..0a1c211f73 100644 --- a/src/InputTypeUtils.php +++ b/src/InputTypeUtils.php @@ -62,7 +62,7 @@ private function validateReturnType(ReflectionMethod $refMethod): Fqsen throw MissingTypeHintRuntimeException::nullableReturnType($refMethod); } - $type = $returnType->getName(); + $type = (string) $returnType; $typeResolver = new TypeResolver(); @@ -81,6 +81,7 @@ private function validateReturnType(ReflectionMethod $refMethod): Fqsen /** * Resolves "self" types into the class type. + * @param ReflectionClass $reflectionClass */ private function resolveSelf(Type $type, ReflectionClass $reflectionClass): Type { diff --git a/src/InvalidPrefetchMethodRuntimeException.php b/src/InvalidPrefetchMethodRuntimeException.php index 5987cdca72..97ee7916ea 100644 --- a/src/InvalidPrefetchMethodRuntimeException.php +++ b/src/InvalidPrefetchMethodRuntimeException.php @@ -10,6 +10,9 @@ class InvalidPrefetchMethodRuntimeException extends GraphQLRuntimeException { + /** + * @param ReflectionClass $reflectionClass + */ public static function methodNotFound(ReflectionMethod $annotationMethod, ReflectionClass $reflectionClass, string $methodName, ReflectionException $previous): self { throw new self('The @Field annotation in ' . $annotationMethod->getDeclaringClass()->getName() . '::' . $annotationMethod->getName() . ' specifies a "prefetch method" that could not be found. Unable to find method ' . $reflectionClass->getName() . '::' . $methodName . '.', 0, $previous); diff --git a/src/Mappers/AbstractTypeMapper.php b/src/Mappers/AbstractTypeMapper.php index 6179a715af..a2b8a325a1 100644 --- a/src/Mappers/AbstractTypeMapper.php +++ b/src/Mappers/AbstractTypeMapper.php @@ -125,7 +125,7 @@ private function getMapClassToExtendTypeArray(): GlobExtendTypeMapperCache * Returns the array of globbed classes. * Only instantiable classes are returned. * - * @return array Key: fully qualified class name + * @return array> Key: fully qualified class name */ abstract protected function getClassList(): array; @@ -133,7 +133,6 @@ private function buildMap(): GlobTypeMapperCache { $globTypeMapperCache = new GlobTypeMapperCache(); - /** @var ReflectionClass[] $classes */ $classes = $this->getClassList(); foreach ($classes as $className => $refClass) { $annotationsCache = $this->mapClassToAnnotationsCache->get($refClass, function () use ($refClass, $className) { @@ -194,7 +193,6 @@ private function buildMapClassToExtendTypeArray(): GlobExtendTypeMapperCache { $globExtendTypeMapperCache = new GlobExtendTypeMapperCache(); - /** @var ReflectionClass[] $classes */ $classes = $this->getClassList(); foreach ($classes as $className => $refClass) { $annotationsCache = $this->mapClassToExtendAnnotationsCache->get($refClass, function () use ($refClass) { diff --git a/src/Mappers/CannotMapTypeExceptionInterface.php b/src/Mappers/CannotMapTypeExceptionInterface.php index 01b2ebe946..f0845441eb 100644 --- a/src/Mappers/CannotMapTypeExceptionInterface.php +++ b/src/Mappers/CannotMapTypeExceptionInterface.php @@ -17,7 +17,13 @@ public function addParamInfo(ReflectionParameter $parameter): void; public function addReturnInfo(ReflectionMethod $method): void; + /** + * @param ReflectionClass $class + */ public function addSourceFieldInfo(ReflectionClass $class, SourceFieldInterface $sourceField): void; + /** + * @param ReflectionClass $class + */ public function addExtendTypeInfo(ReflectionClass $class, ExtendType $extendType): void; } diff --git a/src/Mappers/CannotMapTypeTrait.php b/src/Mappers/CannotMapTypeTrait.php index 9ecba2b95a..4799a48087 100644 --- a/src/Mappers/CannotMapTypeTrait.php +++ b/src/Mappers/CannotMapTypeTrait.php @@ -51,6 +51,9 @@ public function addReturnInfo(ReflectionMethod $method): void ); } + /** + * @param ReflectionClass $class + */ public function addSourceFieldInfo(ReflectionClass $class, SourceFieldInterface $sourceField): void { if ($this->locationInfoAdded !== false) { @@ -66,6 +69,9 @@ public function addSourceFieldInfo(ReflectionClass $class, SourceFieldInterface ); } + /** + * @param ReflectionClass $class + */ public function addExtendTypeInfo(ReflectionClass $class, ExtendType $extendType): void { if ($this->locationInfoAdded !== false) { diff --git a/src/Mappers/GlobExtendTypeMapperCache.php b/src/Mappers/GlobExtendTypeMapperCache.php index afd638db99..c8745ce1ce 100644 --- a/src/Mappers/GlobExtendTypeMapperCache.php +++ b/src/Mappers/GlobExtendTypeMapperCache.php @@ -18,6 +18,7 @@ class GlobExtendTypeMapperCache /** * Merges annotations of a given class in the global cache. + * @param ReflectionClass $refClass */ public function registerAnnotations(ReflectionClass $refClass, GlobExtendAnnotationsCache $globExtendAnnotationsCache): void { diff --git a/src/Mappers/GlobTypeMapper.php b/src/Mappers/GlobTypeMapper.php index 1c4b4f820f..effede5372 100644 --- a/src/Mappers/GlobTypeMapper.php +++ b/src/Mappers/GlobTypeMapper.php @@ -33,7 +33,7 @@ final class GlobTypeMapper extends AbstractTypeMapper * Only instantiable classes are returned. * Key: fully qualified class name * - * @var array + * @var array> */ private $classes; /** @var bool */ @@ -57,7 +57,7 @@ public function __construct(string $namespace, TypeGenerator $typeGenerator, Inp * Returns the array of globbed classes. * Only instantiable classes are returned. * - * @return array Key: fully qualified class name + * @return array> Key: fully qualified class name */ protected function getClassList(): array { diff --git a/src/Mappers/GlobTypeMapperCache.php b/src/Mappers/GlobTypeMapperCache.php index 80d2558f49..255d8f6680 100644 --- a/src/Mappers/GlobTypeMapperCache.php +++ b/src/Mappers/GlobTypeMapperCache.php @@ -25,6 +25,7 @@ class GlobTypeMapperCache /** * Merges annotations of a given class in the global cache. + * @param ReflectionClass $refClass */ public function registerAnnotations(ReflectionClass $refClass, GlobAnnotationsCache $globAnnotationsCache): void { diff --git a/src/Mappers/Parameters/ContainerParameterHandler.php b/src/Mappers/Parameters/ContainerParameterHandler.php index 683efe2425..d49a6ead41 100644 --- a/src/Mappers/Parameters/ContainerParameterHandler.php +++ b/src/Mappers/Parameters/ContainerParameterHandler.php @@ -43,7 +43,7 @@ public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, if ($type === null) { throw MissingAutowireTypeException::create($parameter); } - $id = $type->getName(); + $id = (string) $type; } return new ContainerParameter($this->container, $id); diff --git a/src/Mappers/Parameters/ResolveInfoParameterHandler.php b/src/Mappers/Parameters/ResolveInfoParameterHandler.php index 2bf510c168..f215920de6 100644 --- a/src/Mappers/Parameters/ResolveInfoParameterHandler.php +++ b/src/Mappers/Parameters/ResolveInfoParameterHandler.php @@ -17,7 +17,7 @@ class ResolveInfoParameterHandler implements ParameterMiddlewareInterface public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations, ParameterHandlerInterface $parameterMapper): ParameterInterface { $type = $parameter->getType(); - if ($type!== null && $type->getName() === ResolveInfo::class) { + if ($type!== null && ((string) $type) === ResolveInfo::class) { return new ResolveInfoParameter(); } diff --git a/src/Mappers/Parameters/TypeHandler.php b/src/Mappers/Parameters/TypeHandler.php index b5a1392d69..06c8aa91db 100644 --- a/src/Mappers/Parameters/TypeHandler.php +++ b/src/Mappers/Parameters/TypeHandler.php @@ -239,9 +239,12 @@ private function appendTypes(Type $type, ?Type $docBlockType): Type return new Compound($types); } + /** + * @param ReflectionClass $reflectionClass + */ private function reflectionTypeToPhpDocType(ReflectionType $type, ReflectionClass $reflectionClass): Type { - $phpdocType = $this->phpDocumentorTypeResolver->resolve($type->getName()); + $phpdocType = $this->phpDocumentorTypeResolver->resolve((string) $type); Assert::notNull($phpdocType); $phpdocType = $this->resolveSelf($phpdocType, $reflectionClass); @@ -255,6 +258,8 @@ private function reflectionTypeToPhpDocType(ReflectionType $type, ReflectionClas /** * Resolves "self" types into the class type. + * + * @param ReflectionClass $reflectionClass */ private function resolveSelf(Type $type, ReflectionClass $reflectionClass): Type { diff --git a/src/Mappers/Root/IteratorTypeMapper.php b/src/Mappers/Root/IteratorTypeMapper.php index 3a14e5aae0..1fc587bf19 100644 --- a/src/Mappers/Root/IteratorTypeMapper.php +++ b/src/Mappers/Root/IteratorTypeMapper.php @@ -132,6 +132,7 @@ private function getTypeInArray(Type $typeHint): ?Type } /** + * @param Compound $type * @return (OutputType&GraphQLType)|(InputType&GraphQLType)|null */ private function toGraphQLType(Compound $type, Closure $topToGraphQLType, bool $isOutputType) diff --git a/src/Mappers/StaticClassListTypeMapper.php b/src/Mappers/StaticClassListTypeMapper.php index 9483351da0..76bbadc5f5 100644 --- a/src/Mappers/StaticClassListTypeMapper.php +++ b/src/Mappers/StaticClassListTypeMapper.php @@ -29,7 +29,7 @@ final class StaticClassListTypeMapper extends AbstractTypeMapper * The array of classes. * Key: fully qualified class name * - * @var array + * @var array> */ private $classes; @@ -47,7 +47,7 @@ public function __construct(array $classList, TypeGenerator $typeGenerator, Inpu * Returns the array of globbed classes. * Only instantiable classes are returned. * - * @return array Key: fully qualified class name + * @return array> Key: fully qualified class name */ protected function getClassList(): array { diff --git a/src/MissingTypeHintRuntimeException.php b/src/MissingTypeHintRuntimeException.php index 4e6f56b5b1..ce3fc13ffe 100644 --- a/src/MissingTypeHintRuntimeException.php +++ b/src/MissingTypeHintRuntimeException.php @@ -18,7 +18,7 @@ public static function invalidReturnType(ReflectionMethod $method): self { $returnType = $method->getReturnType(); - return new self(sprintf('The return type of factory "%s::%s" must be an object, "%s" passed instead.', $method->getDeclaringClass()->getName(), $method->getName(), $returnType ? $returnType->getName() : 'mixed')); + return new self(sprintf('The return type of factory "%s::%s" must be an object, "%s" passed instead.', $method->getDeclaringClass()->getName(), $method->getName(), $returnType ? (string) $returnType : 'mixed')); } public static function nullableReturnType(ReflectionMethod $method): self diff --git a/src/Reflection/ReflectionInterfaceUtils.php b/src/Reflection/ReflectionInterfaceUtils.php index f3f89ac60b..892850c04b 100644 --- a/src/Reflection/ReflectionInterfaceUtils.php +++ b/src/Reflection/ReflectionInterfaceUtils.php @@ -13,7 +13,9 @@ class ReflectionInterfaceUtils * Returns a list of all interfaces directly implemented by this class/interface. * "Super" interfaces are not returned. * - * @return array Interfaces indexed by FQCN + * @template T of object + * @param ReflectionClass $reflectionClass + * @return array> Interfaces indexed by FQCN */ public static function getDirectlyImplementedInterfaces(ReflectionClass $reflectionClass): array { diff --git a/src/TypeGenerator.php b/src/TypeGenerator.php index b350b17997..785a8b53c8 100644 --- a/src/TypeGenerator.php +++ b/src/TypeGenerator.php @@ -51,7 +51,7 @@ public function __construct( } /** - * @param string $annotatedObjectClassName The FQCN of an object with a Type annotation. + * @param class-string $annotatedObjectClassName The FQCN of an object with a Type annotation. * * @return MutableInterface&(MutableInterfaceType|MutableObjectType) * From 3300dd647daad979da77a152066ac4ac25ed724b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 16 Dec 2019 17:04:15 +0100 Subject: [PATCH 07/13] Adapting to new Slevomat classes --- src/Containers/BasicAutoWiringContainer.php | 4 ++-- src/Containers/EmptyContainer.php | 4 ++-- src/Types/DateTimeType.php | 2 +- src/Types/MutableInputObjectType.php | 2 +- src/Types/MutableTrait.php | 4 ++-- src/Types/ResolvableMutableInputInterface.php | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Containers/BasicAutoWiringContainer.php b/src/Containers/BasicAutoWiringContainer.php index a504e932ab..0f71095fde 100644 --- a/src/Containers/BasicAutoWiringContainer.php +++ b/src/Containers/BasicAutoWiringContainer.php @@ -40,7 +40,7 @@ public function __construct(ContainerInterface $container) * @throws NotFoundExceptionInterface No entry was found for **this** identifier. * @throws ContainerExceptionInterface Error while retrieving the entry. * - * @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint + * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint */ public function get($id) { @@ -74,7 +74,7 @@ public function get($id) * * @param string $id Identifier of the entry to look for. * - * @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint + * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint */ public function has($id): bool { diff --git a/src/Containers/EmptyContainer.php b/src/Containers/EmptyContainer.php index deba151bce..1c73b559a5 100644 --- a/src/Containers/EmptyContainer.php +++ b/src/Containers/EmptyContainer.php @@ -14,7 +14,7 @@ class EmptyContainer implements ContainerInterface /** * @param string $id * - * @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint + * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint */ public function get($id): void { @@ -24,7 +24,7 @@ public function get($id): void /** * @param string $id * - * @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint + * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint */ public function has($id): bool { diff --git a/src/Types/DateTimeType.php b/src/Types/DateTimeType.php index a5947b8ea1..57f8c08c75 100644 --- a/src/Types/DateTimeType.php +++ b/src/Types/DateTimeType.php @@ -60,7 +60,7 @@ public function parseValue($value): ?DateTimeImmutable * * @throws Exception * - * @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint + * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint */ public function parseLiteral($valueNode, ?array $variables = null) { diff --git a/src/Types/MutableInputObjectType.php b/src/Types/MutableInputObjectType.php index e1225a72cb..61c9f86a13 100644 --- a/src/Types/MutableInputObjectType.php +++ b/src/Types/MutableInputObjectType.php @@ -60,7 +60,7 @@ public function addFields(callable $fields): void /** * @param string $name * - * @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint + * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint */ public function getField($name): InputObjectField { diff --git a/src/Types/MutableTrait.php b/src/Types/MutableTrait.php index 1123062b65..91f6a9d944 100644 --- a/src/Types/MutableTrait.php +++ b/src/Types/MutableTrait.php @@ -45,7 +45,7 @@ public function addFields(callable $fields): void * * @throws Exception * - * @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint + * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint */ public function getField($name): FieldDefinition { @@ -59,7 +59,7 @@ public function getField($name): FieldDefinition /** * @param string $name * - * @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint + * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint */ public function hasField($name): bool { diff --git a/src/Types/ResolvableMutableInputInterface.php b/src/Types/ResolvableMutableInputInterface.php index bcbc21bb61..022a081f9d 100644 --- a/src/Types/ResolvableMutableInputInterface.php +++ b/src/Types/ResolvableMutableInputInterface.php @@ -17,7 +17,7 @@ interface ResolvableMutableInputInterface extends MutableInputInterface * @param mixed[] $args * @param mixed $context * - * @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint + * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint */ public function resolve(?object $source, array $args, $context, ResolveInfo $resolveInfo): object; From 3826f0b941d71844e84b5aa8e667b2962e3a2f9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 16 Dec 2019 17:09:01 +0100 Subject: [PATCH 08/13] Disabling switch to native type hints in PHP 7.4 --- phpcs.xml.dist | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 06647ae490..a6a71f4b1f 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -51,4 +51,10 @@ + + + + + + From d2544f7d9c14a3ac6ba26bedffa3152684647823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 16 Dec 2019 17:53:07 +0100 Subject: [PATCH 09/13] Ignoring some new rules for Slevomat --- phpcs.xml.dist | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index a6a71f4b1f..42ad281edc 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -57,4 +57,14 @@ + + + + + + + + + + From 4b451456f6041a6647e2645917e928d44b445006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 16 Dec 2019 17:59:24 +0100 Subject: [PATCH 10/13] Applying CS-Fix --- src/AnnotationReader.php | 28 ++++++++++++------- src/Exceptions/GraphQLAggregateException.php | 3 +- src/FieldsBuilder.php | 9 ++++-- src/Http/WebonyxGraphqlMiddleware.php | 3 +- src/InputTypeUtils.php | 1 + src/Mappers/GlobExtendTypeMapperCache.php | 1 + src/Mappers/GlobTypeMapperCache.php | 1 + .../Parameters/ContainerParameterHandler.php | 5 ++-- src/Mappers/Parameters/Next.php | 5 ++-- src/Mappers/Parameters/TypeHandler.php | 7 +++-- src/Mappers/Root/CompoundTypeMapper.php | 3 +- src/Mappers/Root/IteratorTypeMapper.php | 4 ++- .../AuthorizationFieldMiddleware.php | 17 ++++------- src/Middlewares/SecurityFieldMiddleware.php | 5 ++-- src/Reflection/ReflectionInterfaceUtils.php | 4 ++- 15 files changed, 54 insertions(+), 42 deletions(-) diff --git a/src/AnnotationReader.php b/src/AnnotationReader.php index a41290c910..8b02768d7c 100644 --- a/src/AnnotationReader.php +++ b/src/AnnotationReader.php @@ -27,6 +27,7 @@ use function array_key_exists; use function array_merge; use function array_values; +use function assert; use function in_array; use function strpos; use function strrpos; @@ -71,14 +72,15 @@ public function __construct(Reader $reader, string $mode = self::STRICT_MODE, ar } /** - * @template T of object * @param ReflectionClass $refClass + * + * @template T of object */ public function getTypeAnnotation(ReflectionClass $refClass): ?Type { try { - /** @var Type|null $type */ $type = $this->getClassAnnotation($refClass, Type::class); + assert($type instanceof Type || $type === null); if ($type !== null && $type->isSelfType()) { $type->setClass($refClass->getName()); } @@ -90,14 +92,15 @@ public function getTypeAnnotation(ReflectionClass $refClass): ?Type } /** - * @template T of object * @param ReflectionClass $refClass + * + * @template T of object */ public function getExtendTypeAnnotation(ReflectionClass $refClass): ?ExtendType { try { - /** @var ExtendType|null $extendType */ $extendType = $this->getClassAnnotation($refClass, ExtendType::class); + assert($extendType instanceof ExtendType || $extendType === null); } catch (ClassNotFoundException $e) { throw ClassNotFoundException::wrapExceptionForExtendTag($e, $refClass->getName()); } @@ -107,16 +110,18 @@ public function getExtendTypeAnnotation(ReflectionClass $refClass): ?ExtendType public function getRequestAnnotation(ReflectionMethod $refMethod, string $annotationName): ?AbstractRequest { - /** @var AbstractRequest|null $queryAnnotation */ $queryAnnotation = $this->getMethodAnnotation($refMethod, $annotationName); + assert($queryAnnotation instanceof AbstractRequest || $queryAnnotation === null); return $queryAnnotation; } /** - * @template T of object * @param ReflectionClass $refClass + * * @return SourceField[] + * + * @template T of object */ public function getSourceFields(ReflectionClass $refClass): array { @@ -128,16 +133,16 @@ public function getSourceFields(ReflectionClass $refClass): array public function getFactoryAnnotation(ReflectionMethod $refMethod): ?Factory { - /** @var Factory|null $factoryAnnotation */ $factoryAnnotation = $this->getMethodAnnotation($refMethod, Factory::class); + assert($factoryAnnotation instanceof Factory || $factoryAnnotation === null); return $factoryAnnotation; } public function getDecorateAnnotation(ReflectionMethod $refMethod): ?Decorate { - /** @var Decorate|null $decorateAnnotation */ $decorateAnnotation = $this->getMethodAnnotation($refMethod, Decorate::class); + assert($decorateAnnotation instanceof Decorate || $decorateAnnotation === null); return $decorateAnnotation; } @@ -168,8 +173,9 @@ public function getMiddlewareAnnotations(ReflectionMethod $refMethod): Middlewar /** * Returns a class annotation. Does not look in the parent class. * - * @template T of object * @param ReflectionClass $refClass + * + * @template T of object */ private function getClassAnnotation(ReflectionClass $refClass, string $annotationClass): ?object { @@ -243,9 +249,11 @@ private function isErrorImportant(string $annotationClass, string $docComment, s /** * Returns the class annotations. Finds in the parents too. * - * @template T of object * @param ReflectionClass $refClass + * * @return object[] + * + * @template T of object */ public function getClassAnnotations(ReflectionClass $refClass, string $annotationClass): array { diff --git a/src/Exceptions/GraphQLAggregateException.php b/src/Exceptions/GraphQLAggregateException.php index 394eb0503a..b06dd9f597 100644 --- a/src/Exceptions/GraphQLAggregateException.php +++ b/src/Exceptions/GraphQLAggregateException.php @@ -8,6 +8,7 @@ use GraphQL\Error\ClientAware; use Throwable; use function array_map; +use function assert; use function count; use function max; use function reset; @@ -76,8 +77,8 @@ public static function throwExceptions(array $exceptions): void return; } if ($count === 1) { - /** @var Throwable $exception */ $exception = reset($exceptions); + assert($exception instanceof Throwable); throw $exception; } throw new self($exceptions); diff --git a/src/FieldsBuilder.php b/src/FieldsBuilder.php index 97164d11a7..a657c923a3 100644 --- a/src/FieldsBuilder.php +++ b/src/FieldsBuilder.php @@ -133,6 +133,7 @@ public function getFields(object $controller): array * Track Field annotation in a self targeted type * * @param class-string $className + * * @return array QueryField indexed by name. */ public function getSelfFields(string $className): array @@ -259,7 +260,7 @@ private function getFieldsByAnnotations($controller, string $annotationName, boo } $prefetchParameters = $prefetchRefMethod->getParameters(); - $first_prefetch_parameter = array_shift($prefetchParameters); + $firstPrefetchParameter = array_shift($prefetchParameters); $prefetchDocBlockObj = $this->cachedDocBlockFactory->getDocBlock($prefetchRefMethod); @@ -338,7 +339,6 @@ public function handle(QueryFieldDescriptor $fieldDescriptor): ?FieldDefinition } /** - * @template T of object * @param SourceFieldInterface[] $sourceFields * @param ReflectionClass $refClass * @@ -347,6 +347,8 @@ public function handle(QueryFieldDescriptor $fieldDescriptor): ?FieldDefinition * @throws CannotMapTypeException * @throws CannotMapTypeExceptionInterface * @throws ReflectionException + * + * @template T of object */ private function getQueryFieldsFromSourceFields(array $sourceFields, ReflectionClass $refClass): array { @@ -442,8 +444,9 @@ public function handle(QueryFieldDescriptor $fieldDescriptor): ?FieldDefinition } /** - * @template T of object * @param ReflectionClass $reflectionClass + * + * @template T of object */ private function getMethodFromPropertyName(ReflectionClass $reflectionClass, string $propertyName): ReflectionMethod { diff --git a/src/Http/WebonyxGraphqlMiddleware.php b/src/Http/WebonyxGraphqlMiddleware.php index 2994f4a402..279787838d 100644 --- a/src/Http/WebonyxGraphqlMiddleware.php +++ b/src/Http/WebonyxGraphqlMiddleware.php @@ -17,7 +17,6 @@ use Psr\Http\Server\RequestHandlerInterface; use RuntimeException; use TheCodingMachine\GraphQLite\Context\ResetableContextInterface; -use const JSON_ERROR_NONE; use function array_map; use function explode; use function in_array; @@ -27,6 +26,7 @@ use function json_last_error; use function json_last_error_msg; use function max; +use const JSON_ERROR_NONE; final class WebonyxGraphqlMiddleware implements MiddlewareInterface { @@ -146,6 +146,7 @@ private function decideHttpCode($result): int } throw new RuntimeException('Unexpected response from StandardServer::executePsrRequest'); + // @codeCoverageIgnoreEnd } diff --git a/src/InputTypeUtils.php b/src/InputTypeUtils.php index 0a1c211f73..a43460690e 100644 --- a/src/InputTypeUtils.php +++ b/src/InputTypeUtils.php @@ -81,6 +81,7 @@ private function validateReturnType(ReflectionMethod $refMethod): Fqsen /** * Resolves "self" types into the class type. + * * @param ReflectionClass $reflectionClass */ private function resolveSelf(Type $type, ReflectionClass $reflectionClass): Type diff --git a/src/Mappers/GlobExtendTypeMapperCache.php b/src/Mappers/GlobExtendTypeMapperCache.php index c8745ce1ce..7175f866fb 100644 --- a/src/Mappers/GlobExtendTypeMapperCache.php +++ b/src/Mappers/GlobExtendTypeMapperCache.php @@ -18,6 +18,7 @@ class GlobExtendTypeMapperCache /** * Merges annotations of a given class in the global cache. + * * @param ReflectionClass $refClass */ public function registerAnnotations(ReflectionClass $refClass, GlobExtendAnnotationsCache $globExtendAnnotationsCache): void diff --git a/src/Mappers/GlobTypeMapperCache.php b/src/Mappers/GlobTypeMapperCache.php index 255d8f6680..7de956c66d 100644 --- a/src/Mappers/GlobTypeMapperCache.php +++ b/src/Mappers/GlobTypeMapperCache.php @@ -25,6 +25,7 @@ class GlobTypeMapperCache /** * Merges annotations of a given class in the global cache. + * * @param ReflectionClass $refClass */ public function registerAnnotations(ReflectionClass $refClass, GlobAnnotationsCache $globAnnotationsCache): void diff --git a/src/Mappers/Parameters/ContainerParameterHandler.php b/src/Mappers/Parameters/ContainerParameterHandler.php index d49a6ead41..53f9bc7d9f 100644 --- a/src/Mappers/Parameters/ContainerParameterHandler.php +++ b/src/Mappers/Parameters/ContainerParameterHandler.php @@ -12,6 +12,7 @@ use TheCodingMachine\GraphQLite\Annotations\ParameterAnnotations; use TheCodingMachine\GraphQLite\Parameters\ContainerParameter; use TheCodingMachine\GraphQLite\Parameters\ParameterInterface; +use function assert; /** * Maps parameters with the \@Autowire annotation to container entry based on the FQCN or the passed identifier. @@ -28,10 +29,8 @@ public function __construct(ContainerInterface $container) public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations, ParameterHandlerInterface $next): ParameterInterface { - /** - * @var Autowire|null $autowire - */ $autowire = $parameterAnnotations->getAnnotationByType(Autowire::class); + assert($autowire instanceof Autowire || $autowire === null); if ($autowire === null) { return $next->mapParameter($parameter, $docBlock, $paramTagType, $parameterAnnotations); diff --git a/src/Mappers/Parameters/Next.php b/src/Mappers/Parameters/Next.php index 95f468e8fe..a141b6b884 100644 --- a/src/Mappers/Parameters/Next.php +++ b/src/Mappers/Parameters/Next.php @@ -10,6 +10,7 @@ use SplQueue; use TheCodingMachine\GraphQLite\Annotations\ParameterAnnotations; use TheCodingMachine\GraphQLite\Parameters\ParameterInterface; +use function assert; /** * Iterate a queue of middlewares and execute them. @@ -40,10 +41,8 @@ public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, return $this->fallbackHandler->mapParameter($parameter, $docBlock, $paramTagType, $parameterAnnotations); } - /** - * @var ParameterMiddlewareInterface $middleware - */ $middleware = $this->queue->dequeue(); + assert($middleware instanceof ParameterMiddlewareInterface); return $middleware->mapParameter($parameter, $docBlock, $paramTagType, $parameterAnnotations, $this); } diff --git a/src/Mappers/Parameters/TypeHandler.php b/src/Mappers/Parameters/TypeHandler.php index 06c8aa91db..8d5cad8ae0 100644 --- a/src/Mappers/Parameters/TypeHandler.php +++ b/src/Mappers/Parameters/TypeHandler.php @@ -36,11 +36,12 @@ use TheCodingMachine\GraphQLite\Types\ArgumentResolver; use TheCodingMachine\GraphQLite\Types\TypeResolver; use Webmozart\Assert\Assert; -use const SORT_REGULAR; use function array_merge; use function array_unique; +use function assert; use function count; use function iterator_to_array; +use const SORT_REGULAR; class TypeHandler implements ParameterHandlerInterface { @@ -79,8 +80,8 @@ public function mapReturnType(ReflectionMethod $refMethod, DocBlock $docBlockObj $docBlockReturnType = $this->getDocBlocReturnType($docBlockObj, $refMethod); try { - /** @var GraphQLType&OutputType $type */ $type = $this->mapType($phpdocType, $docBlockReturnType, $returnType ? $returnType->allowsNull() : false, false, $refMethod, $docBlockObj); + assert($type instanceof GraphQLType && $type instanceof OutputType); } catch (TypeMappingRuntimeException $e) { throw TypeMappingRuntimeException::wrapWithReturnInfo($e, $refMethod); } catch (CannotMapTypeExceptionInterface $e) { @@ -117,8 +118,8 @@ public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, return new DefaultValueParameter($parameter->getDefaultValue()); } - /** @var UseInputType|null $useInputType */ $useInputType = $parameterAnnotations->getAnnotationByType(UseInputType::class); + assert($useInputType instanceof UseInputType || $useInputType === null); if ($useInputType !== null) { try { $type = $this->typeResolver->mapNameToInputType($useInputType->getInputType()); diff --git a/src/Mappers/Root/CompoundTypeMapper.php b/src/Mappers/Root/CompoundTypeMapper.php index 5e6e3f1503..906430db47 100644 --- a/src/Mappers/Root/CompoundTypeMapper.php +++ b/src/Mappers/Root/CompoundTypeMapper.php @@ -24,6 +24,7 @@ use Webmozart\Assert\Assert; use function array_filter; use function array_values; +use function assert; use function count; use function iterator_to_array; @@ -158,8 +159,8 @@ private function getTypeFromUnion(array $unionTypes): GraphQLType } $graphQlType = new UnionType($nonNullableUnionTypes, $this->recursiveTypeMapper); - /** @var UnionType $graphQlType */ $graphQlType = $this->typeRegistry->getOrRegisterType($graphQlType); + assert($graphQlType instanceof UnionType); } return $graphQlType; diff --git a/src/Mappers/Root/IteratorTypeMapper.php b/src/Mappers/Root/IteratorTypeMapper.php index 1fc587bf19..0c5f04aeb7 100644 --- a/src/Mappers/Root/IteratorTypeMapper.php +++ b/src/Mappers/Root/IteratorTypeMapper.php @@ -24,6 +24,7 @@ use TheCodingMachine\GraphQLite\Mappers\CannotMapTypeExceptionInterface; use TheCodingMachine\GraphQLite\TypeMappingRuntimeException; use Webmozart\Assert\Assert; +use function assert; use function count; use function iterator_to_array; @@ -133,6 +134,7 @@ private function getTypeInArray(Type $typeHint): ?Type /** * @param Compound $type + * * @return (OutputType&GraphQLType)|(InputType&GraphQLType)|null */ private function toGraphQLType(Compound $type, Closure $topToGraphQLType, bool $isOutputType) @@ -155,8 +157,8 @@ private function toGraphQLType(Compound $type, Closure $topToGraphQLType, bool $ // By convention, we trim the NonNull part of the "$subGraphQlType" if ($subGraphQlType instanceof NonNull) { - /** @var OutputType&GraphQLType $subGraphQlType */ $subGraphQlType = $subGraphQlType->getWrappedType(); + assert($subGraphQlType instanceof OutputType && $subGraphQlType instanceof GraphQLType); } } else { $subGraphQlType = null; diff --git a/src/Middlewares/AuthorizationFieldMiddleware.php b/src/Middlewares/AuthorizationFieldMiddleware.php index 413aabf019..250053a81b 100644 --- a/src/Middlewares/AuthorizationFieldMiddleware.php +++ b/src/Middlewares/AuthorizationFieldMiddleware.php @@ -17,6 +17,7 @@ use TheCodingMachine\GraphQLite\Security\AuthenticationServiceInterface; use TheCodingMachine\GraphQLite\Security\AuthorizationServiceInterface; use Webmozart\Assert\Assert; +use function assert; /** * Middleware in charge of managing "Logged" and "Right" annotations. @@ -40,19 +41,13 @@ public function process(QueryFieldDescriptor $queryFieldDescriptor, FieldHandler { $annotations = $queryFieldDescriptor->getMiddlewareAnnotations(); - /** - * @var Logged $loggedAnnotation - */ $loggedAnnotation = $annotations->getAnnotationByType(Logged::class); - /** - * @var Right $rightAnnotation - */ + assert($loggedAnnotation instanceof Logged); $rightAnnotation = $annotations->getAnnotationByType(Right::class); + assert($rightAnnotation instanceof Right); - /** - * @var FailWith|null $failWith - */ $failWith = $annotations->getAnnotationByType(FailWith::class); + assert($failWith instanceof FailWith || $failWith === null); // If the failWith value is null and the return type is non nullable, we must set it to nullable. $type = $queryFieldDescriptor->getType(); @@ -66,10 +61,8 @@ public function process(QueryFieldDescriptor $queryFieldDescriptor, FieldHandler return $fieldHandler->handle($queryFieldDescriptor); } - /** - * @var HideIfUnauthorized|null $hideIfUnauthorized - */ $hideIfUnauthorized = $annotations->getAnnotationByType(HideIfUnauthorized::class); + assert($hideIfUnauthorized instanceof HideIfUnauthorized || $hideIfUnauthorized === null); if ($failWith !== null && $hideIfUnauthorized !== null) { throw IncompatibleAnnotationsException::cannotUseFailWithAndHide(); diff --git a/src/Middlewares/SecurityFieldMiddleware.php b/src/Middlewares/SecurityFieldMiddleware.php index e20c5d0ef8..944dc061db 100644 --- a/src/Middlewares/SecurityFieldMiddleware.php +++ b/src/Middlewares/SecurityFieldMiddleware.php @@ -20,6 +20,7 @@ use function array_combine; use function array_keys; use function array_merge; +use function assert; /** * A field middleware that reads "Security" Symfony annotations. @@ -53,10 +54,8 @@ public function process(QueryFieldDescriptor $queryFieldDescriptor, FieldHandler return $fieldHandler->handle($queryFieldDescriptor); } - /** - * @var FailWith|null $failWith - */ $failWith = $annotations->getAnnotationByType(FailWith::class); + assert($failWith instanceof FailWith || $failWith === null); // If the failWith value is null and the return type is non nullable, we must set it to nullable. $makeReturnTypeNullable = false; diff --git a/src/Reflection/ReflectionInterfaceUtils.php b/src/Reflection/ReflectionInterfaceUtils.php index 892850c04b..1c6a0bbf68 100644 --- a/src/Reflection/ReflectionInterfaceUtils.php +++ b/src/Reflection/ReflectionInterfaceUtils.php @@ -13,9 +13,11 @@ class ReflectionInterfaceUtils * Returns a list of all interfaces directly implemented by this class/interface. * "Super" interfaces are not returned. * - * @template T of object * @param ReflectionClass $reflectionClass + * * @return array> Interfaces indexed by FQCN + * + * @template T of object */ public static function getDirectlyImplementedInterfaces(ReflectionClass $reflectionClass): array { From 82c87b8c609c56a843e09d91e1b97c70d942da12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 16 Dec 2019 18:05:38 +0100 Subject: [PATCH 11/13] Fixing assertions --- .travis.yml | 2 +- src/Middlewares/AuthorizationFieldMiddleware.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3f8f8e78f4..c46836b964 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ jobs: after_script: - travis_retry php vendor/bin/php-coveralls -v - stage: test - php: 7.4snapshot + php: 7.4 env: PREFER_LOWEST="" before_script: - *composerupdate diff --git a/src/Middlewares/AuthorizationFieldMiddleware.php b/src/Middlewares/AuthorizationFieldMiddleware.php index 250053a81b..562d04b7af 100644 --- a/src/Middlewares/AuthorizationFieldMiddleware.php +++ b/src/Middlewares/AuthorizationFieldMiddleware.php @@ -42,12 +42,12 @@ public function process(QueryFieldDescriptor $queryFieldDescriptor, FieldHandler $annotations = $queryFieldDescriptor->getMiddlewareAnnotations(); $loggedAnnotation = $annotations->getAnnotationByType(Logged::class); - assert($loggedAnnotation instanceof Logged); + assert($loggedAnnotation === null || $loggedAnnotation instanceof Logged); $rightAnnotation = $annotations->getAnnotationByType(Right::class); - assert($rightAnnotation instanceof Right); + assert($rightAnnotation === null || $rightAnnotation instanceof Right); $failWith = $annotations->getAnnotationByType(FailWith::class); - assert($failWith instanceof FailWith || $failWith === null); + assert($failWith === null || $failWith instanceof FailWith); // If the failWith value is null and the return type is non nullable, we must set it to nullable. $type = $queryFieldDescriptor->getType(); From 1e9ed5f15962d2a6ba2b1ac12ae5b252ed82d392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 16 Dec 2019 21:12:41 +0100 Subject: [PATCH 12/13] Fixing deprecations of toString in ReflectionType --- src/InputTypeUtils.php | 5 ++++- src/Mappers/Parameters/ContainerParameterHandler.php | 4 +++- src/Mappers/Parameters/ResolveInfoParameterHandler.php | 4 +++- src/Mappers/Parameters/TypeHandler.php | 4 +++- src/MissingTypeHintRuntimeException.php | 6 ++++-- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/InputTypeUtils.php b/src/InputTypeUtils.php index a43460690e..f316ac4e6d 100644 --- a/src/InputTypeUtils.php +++ b/src/InputTypeUtils.php @@ -12,12 +12,14 @@ use phpDocumentor\Reflection\Types\Self_; use ReflectionClass; use ReflectionMethod; +use ReflectionNamedType; use RuntimeException; use TheCodingMachine\GraphQLite\Parameters\InputTypeParameterInterface; use TheCodingMachine\GraphQLite\Parameters\ParameterInterface; use Webmozart\Assert\Assert; use function array_filter; use function array_map; +use function assert; use function ltrim; class InputTypeUtils @@ -57,12 +59,13 @@ private function validateReturnType(ReflectionMethod $refMethod): Fqsen if ($returnType === null) { throw MissingTypeHintRuntimeException::missingReturnType($refMethod); } + assert($returnType instanceof ReflectionNamedType); if ($returnType->allowsNull()) { throw MissingTypeHintRuntimeException::nullableReturnType($refMethod); } - $type = (string) $returnType; + $type = $returnType->getName(); $typeResolver = new TypeResolver(); diff --git a/src/Mappers/Parameters/ContainerParameterHandler.php b/src/Mappers/Parameters/ContainerParameterHandler.php index 53f9bc7d9f..12310e6dc1 100644 --- a/src/Mappers/Parameters/ContainerParameterHandler.php +++ b/src/Mappers/Parameters/ContainerParameterHandler.php @@ -7,6 +7,7 @@ use phpDocumentor\Reflection\DocBlock; use phpDocumentor\Reflection\Type; use Psr\Container\ContainerInterface; +use ReflectionNamedType; use ReflectionParameter; use TheCodingMachine\GraphQLite\Annotations\Autowire; use TheCodingMachine\GraphQLite\Annotations\ParameterAnnotations; @@ -42,7 +43,8 @@ public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, if ($type === null) { throw MissingAutowireTypeException::create($parameter); } - $id = (string) $type; + assert($type instanceof ReflectionNamedType); + $id = $type->getName(); } return new ContainerParameter($this->container, $id); diff --git a/src/Mappers/Parameters/ResolveInfoParameterHandler.php b/src/Mappers/Parameters/ResolveInfoParameterHandler.php index f215920de6..1c5d7bb3f4 100644 --- a/src/Mappers/Parameters/ResolveInfoParameterHandler.php +++ b/src/Mappers/Parameters/ResolveInfoParameterHandler.php @@ -7,6 +7,7 @@ use GraphQL\Type\Definition\ResolveInfo; use phpDocumentor\Reflection\DocBlock; use phpDocumentor\Reflection\Type; +use ReflectionNamedType; use ReflectionParameter; use TheCodingMachine\GraphQLite\Annotations\ParameterAnnotations; use TheCodingMachine\GraphQLite\Parameters\ParameterInterface; @@ -17,7 +18,8 @@ class ResolveInfoParameterHandler implements ParameterMiddlewareInterface public function mapParameter(ReflectionParameter $parameter, DocBlock $docBlock, ?Type $paramTagType, ParameterAnnotations $parameterAnnotations, ParameterHandlerInterface $parameterMapper): ParameterInterface { $type = $parameter->getType(); - if ($type!== null && ((string) $type) === ResolveInfo::class) { + assert($type === null || $type instanceof ReflectionNamedType); + if ($type!== null && $type->getName() === ResolveInfo::class) { return new ResolveInfoParameter(); } diff --git a/src/Mappers/Parameters/TypeHandler.php b/src/Mappers/Parameters/TypeHandler.php index 8d5cad8ae0..da42df1291 100644 --- a/src/Mappers/Parameters/TypeHandler.php +++ b/src/Mappers/Parameters/TypeHandler.php @@ -21,6 +21,7 @@ use phpDocumentor\Reflection\Types\Self_; use ReflectionClass; use ReflectionMethod; +use ReflectionNamedType; use ReflectionParameter; use ReflectionType; use TheCodingMachine\GraphQLite\Annotations\HideParameter; @@ -245,7 +246,8 @@ private function appendTypes(Type $type, ?Type $docBlockType): Type */ private function reflectionTypeToPhpDocType(ReflectionType $type, ReflectionClass $reflectionClass): Type { - $phpdocType = $this->phpDocumentorTypeResolver->resolve((string) $type); + assert($type instanceof ReflectionNamedType); + $phpdocType = $this->phpDocumentorTypeResolver->resolve($type->getName()); Assert::notNull($phpdocType); $phpdocType = $this->resolveSelf($phpdocType, $reflectionClass); diff --git a/src/MissingTypeHintRuntimeException.php b/src/MissingTypeHintRuntimeException.php index ce3fc13ffe..2a0a7e7741 100644 --- a/src/MissingTypeHintRuntimeException.php +++ b/src/MissingTypeHintRuntimeException.php @@ -5,6 +5,8 @@ namespace TheCodingMachine\GraphQLite; use ReflectionMethod; +use ReflectionNamedType; +use function assert; use function sprintf; class MissingTypeHintRuntimeException extends GraphQLRuntimeException @@ -17,8 +19,8 @@ public static function missingReturnType(ReflectionMethod $method): self public static function invalidReturnType(ReflectionMethod $method): self { $returnType = $method->getReturnType(); - - return new self(sprintf('The return type of factory "%s::%s" must be an object, "%s" passed instead.', $method->getDeclaringClass()->getName(), $method->getName(), $returnType ? (string) $returnType : 'mixed')); + assert($returnType === null || $returnType instanceof ReflectionNamedType); + return new self(sprintf('The return type of factory "%s::%s" must be an object, "%s" passed instead.', $method->getDeclaringClass()->getName(), $method->getName(), $returnType ? $returnType->getName() : 'mixed')); } public static function nullableReturnType(ReflectionMethod $method): self From 9643aa50cc6b3664cfc9ea067d49e48440690135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 16 Dec 2019 21:17:05 +0100 Subject: [PATCH 13/13] CS/PHPStan fixes --- phpstan.neon | 1 - src/Mappers/Parameters/ResolveInfoParameterHandler.php | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.neon b/phpstan.neon index 054766ad51..a723732dd8 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -25,7 +25,6 @@ parameters: message: '#Property TheCodingMachine\GraphQLite\Annotations\Type::$class \(class-string|null\) does not accept string.#' path: src/Annotations/Type.php - '#Call to an undefined method GraphQL\\Error\\ClientAware::getMessage()#' - - '#Method .*::(addSourceFieldInfo|addExtendTypeInfo)\(\) has parameter \$class with generic class ReflectionClass#' #- # message: '#If condition is always true#' # path: src/Middlewares/SecurityFieldMiddleware.php diff --git a/src/Mappers/Parameters/ResolveInfoParameterHandler.php b/src/Mappers/Parameters/ResolveInfoParameterHandler.php index 1c5d7bb3f4..a82a0409d0 100644 --- a/src/Mappers/Parameters/ResolveInfoParameterHandler.php +++ b/src/Mappers/Parameters/ResolveInfoParameterHandler.php @@ -12,6 +12,7 @@ use TheCodingMachine\GraphQLite\Annotations\ParameterAnnotations; use TheCodingMachine\GraphQLite\Parameters\ParameterInterface; use TheCodingMachine\GraphQLite\Parameters\ResolveInfoParameter; +use function assert; class ResolveInfoParameterHandler implements ParameterMiddlewareInterface {