diff --git a/docs/class-reference.md b/docs/class-reference.md index d1ca03913..26922b7fc 100644 --- a/docs/class-reference.md +++ b/docs/class-reference.md @@ -3,6 +3,7 @@ This is the primary facade for fulfilling GraphQL operations. See [related documentation](executing-queries.md). +@phpstan-import-type ArgsMapper from Executor @phpstan-import-type FieldResolver from Executor @see \GraphQL\Tests\GraphQLTest @@ -164,6 +165,17 @@ static function getStandardValidationRules(): array static function setDefaultFieldResolver(callable $fn): void ``` +```php +/** + * Set default args mapper implementation. + * + * @phpstan-param ArgsMapper $fn + * + * @api + */ +static function setDefaultArgsMapper(callable $fn): void +``` + ## GraphQL\Type\Definition\Type Registry of standard GraphQL types and base class for all other types. diff --git a/docs/error-handling.md b/docs/error-handling.md index b5783a03f..4afdc880f 100644 --- a/docs/error-handling.md +++ b/docs/error-handling.md @@ -130,7 +130,7 @@ This will make each error entry look like this: 'extensions' => [ 'debugMessage' => 'Actual exception message', 'trace' => [ - /* Formatted original exception trace */ + // Formatted original exception trace ], ], ] diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 5800a769a..c9ad1df81 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,10 +1,5 @@ parameters: ignoreErrors: - - - message: "#^SplObjectStorage\\, ArrayObject\\\\>\\>\\> does not accept SplObjectStorage\\, ArrayObject\\\\>\\>\\|SplObjectStorage\\\\.$#" - count: 1 - path: src/Executor/ReferenceExecutor.php - - message: "#^Unable to resolve the template type TCloneable in call to method static method GraphQL\\\\Language\\\\AST\\\\Node\\:\\:cloneValue\\(\\)$#" count: 1 diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index dad4eaf6e..f7ce2bff1 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -63,19 +63,25 @@ public static function setDefaultFieldResolver(callable $fieldResolver): void self::$defaultFieldResolver = $fieldResolver; } + /** @phpstan-return ArgsMapper */ + public static function getDefaultArgsMapper(): callable + { + return self::$defaultArgsMapper; + } + /** @phpstan-param ArgsMapper $argsMapper */ public static function setDefaultArgsMapper(callable $argsMapper): void { self::$defaultArgsMapper = $argsMapper; } - public static function getPromiseAdapter(): PromiseAdapter + public static function getDefaultPromiseAdapter(): PromiseAdapter { return self::$defaultPromiseAdapter ??= new SyncPromiseAdapter(); } /** Set a custom default promise adapter. */ - public static function setPromiseAdapter(?PromiseAdapter $defaultPromiseAdapter = null): void + public static function setDefaultPromiseAdapter(?PromiseAdapter $defaultPromiseAdapter = null): void { self::$defaultPromiseAdapter = $defaultPromiseAdapter; } diff --git a/src/Executor/ReferenceExecutor.php b/src/Executor/ReferenceExecutor.php index 9cda56ead..303287080 100644 --- a/src/Executor/ReferenceExecutor.php +++ b/src/Executor/ReferenceExecutor.php @@ -61,7 +61,12 @@ class ReferenceExecutor implements ExecutorImplementation */ protected \SplObjectStorage $subFieldCache; - /** @var \SplObjectStorage> */ + /** + * @var \SplObjectStorage< + * FieldDefinition, + * \SplObjectStorage + * > + */ protected \SplObjectStorage $fieldArgsCache; protected function __construct(ExecutionContext $context) @@ -94,7 +99,7 @@ public static function create( array $variableValues, ?string $operationName, callable $fieldResolver, - callable $argsMapper + ?callable $argsMapper = null // TODO make non-optional in next major release ): ExecutorImplementation { $exeContext = static::buildExecutionContext( $schema, @@ -104,7 +109,7 @@ public static function create( $variableValues, $operationName, $fieldResolver, - $argsMapper, + $argsMapper ?? Executor::getDefaultArgsMapper(), $promiseAdapter, ); @@ -128,8 +133,8 @@ public function doExecute(): Promise } /** - * Constructs an ExecutionContext object from the arguments passed to - * execute, which we will pass throughout the other execution methods. + * Constructs an ExecutionContext object from the arguments passed to execute, + * which we will pass throughout the other execution methods. * * @param mixed $rootValue * @param mixed $contextValue @@ -741,7 +746,7 @@ protected function resolveFieldValueOrError( try { // Build a map of arguments from the field.arguments AST, using the // variables scope to fulfill any variable references. - /** @phpstan-ignore-next-line ignored because no way to tell phpstan what are generics of SplObjectStorage without assign it to var first */ + // @phpstan-ignore-next-line generics of SplObjectStorage are not inferred from empty instantiation $this->fieldArgsCache[$fieldDef] ??= new \SplObjectStorage(); $args = $this->fieldArgsCache[$fieldDef][$fieldNode] ??= $argsMapper(Values::getArgumentValues( @@ -1331,6 +1336,7 @@ protected function collectAndExecuteSubfields( */ protected function collectSubFields(ObjectType $returnType, \ArrayObject $fieldNodes): \ArrayObject { + // @phpstan-ignore-next-line generics of SplObjectStorage are not inferred from empty instantiation $returnTypeCache = $this->subFieldCache[$returnType] ??= new \SplObjectStorage(); if (! isset($returnTypeCache[$fieldNodes])) { diff --git a/src/GraphQL.php b/src/GraphQL.php index 0da1e729b..919b09dec 100644 --- a/src/GraphQL.php +++ b/src/GraphQL.php @@ -24,6 +24,7 @@ * This is the primary facade for fulfilling GraphQL operations. * See [related documentation](executing-queries.md). * + * @phpstan-import-type ArgsMapper from Executor * @phpstan-import-type FieldResolver from Executor * * @see \GraphQL\Tests\GraphQLTest @@ -243,4 +244,16 @@ public static function setDefaultFieldResolver(callable $fn): void { Executor::setDefaultFieldResolver($fn); } + + /** + * Set default args mapper implementation. + * + * @phpstan-param ArgsMapper $fn + * + * @api + */ + public static function setDefaultArgsMapper(callable $fn): void + { + Executor::setDefaultArgsMapper($fn); + } } diff --git a/src/Server/Helper.php b/src/Server/Helper.php index f0c9f62a3..0c2405418 100644 --- a/src/Server/Helper.php +++ b/src/Server/Helper.php @@ -197,7 +197,7 @@ public function validateOperationParams(OperationParams $params): array */ public function executeOperation(ServerConfig $config, OperationParams $op) { - $promiseAdapter = $config->getPromiseAdapter() ?? Executor::getPromiseAdapter(); + $promiseAdapter = $config->getPromiseAdapter() ?? Executor::getDefaultPromiseAdapter(); $result = $this->promiseToExecuteOperation($promiseAdapter, $config, $op); if ($promiseAdapter instanceof SyncPromiseAdapter) { @@ -222,7 +222,7 @@ public function executeOperation(ServerConfig $config, OperationParams $op) */ public function executeBatch(ServerConfig $config, array $operations) { - $promiseAdapter = $config->getPromiseAdapter() ?? Executor::getPromiseAdapter(); + $promiseAdapter = $config->getPromiseAdapter() ?? Executor::getDefaultPromiseAdapter(); $result = []; foreach ($operations as $operation) { diff --git a/tests/Executor/ExecutorTest.php b/tests/Executor/ExecutorTest.php index 4d3e2c890..e8f5be331 100644 --- a/tests/Executor/ExecutorTest.php +++ b/tests/Executor/ExecutorTest.php @@ -29,7 +29,7 @@ final class ExecutorTest extends TestCase public function tearDown(): void { - Executor::setPromiseAdapter(null); + Executor::setDefaultPromiseAdapter(null); } // Execute: Handles basic execution tasks @@ -398,8 +398,8 @@ public function testArgsMapper(): void ]), ]); $result = Executor::execute($schema, $docAst); - self::assertEquals(1, $mapperCalledCount); - self::assertEquals(3, $resolverCalledCount); + self::assertSame(1, $mapperCalledCount); + self::assertSame(3, $resolverCalledCount); self::assertCount(0, $result->errors); } diff --git a/tests/Language/VisitorTest.php b/tests/Language/VisitorTest.php index 843e4e7a9..c1eceea6f 100644 --- a/tests/Language/VisitorTest.php +++ b/tests/Language/VisitorTest.php @@ -66,7 +66,7 @@ private function checkVisitorFnArgs(DocumentNode $ast, array $args, bool $isEdit if ($parent instanceof NodeList) { self::assertEquals($node, $parent[$key]); } else { - /** @phpstan-ignore-next-line */ + // @phpstan-ignore-next-line dynamic property access self::assertEquals($node, $parent->{$key}); }