From 1d4eea9c199a6f95032e62e5b355c601a7065fc0 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Sat, 15 Oct 2022 20:07:49 +0200 Subject: [PATCH 01/27] graphql-php-v15: workaround to allow testing with graphql-php v15 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index fbc617c4..fddcc8ee 100644 --- a/composer.json +++ b/composer.json @@ -38,9 +38,9 @@ "ext-json": "*", "illuminate/contracts": "^6.0|^8.0|^9.0", "illuminate/support": "^6.0|^8.0|^9.0", - "laragraph/utils": "^1", + "laragraph/utils": "dev-graphql-php-15", "thecodingmachine/safe": "^1.3", - "webonyx/graphql-php": "^14.6.4" + "webonyx/graphql-php": "dev-master" }, "require-dev": { "ext-pdo_sqlite": "*", From 17096de362abbf2be4892bad515c0e191f533727 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Sat, 15 Oct 2022 20:11:50 +0200 Subject: [PATCH 02/27] graphql-php-v15: adding property types due to upstream changes --- src/Support/UploadType.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Support/UploadType.php b/src/Support/UploadType.php index a6d614d2..5edba2a1 100644 --- a/src/Support/UploadType.php +++ b/src/Support/UploadType.php @@ -12,10 +12,8 @@ class UploadType extends ScalarType implements TypeConvertible { - /** @var string */ - public $name = 'Upload'; - /** @var string */ - public $description = + public string $name = 'Upload'; + public ?string $description = 'The `Upload` special type represents a file to be uploaded in the same HTTP request as specified by [graphql-multipart-request-spec](https://github.com/jaydenseric/graphql-multipart-request-spec).'; From 57027673ab79fc620cc18f36613c0023eaa472c3 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Mon, 17 Oct 2022 20:50:29 +0200 Subject: [PATCH 03/27] graphql-php-v15: adapt for file/line/trace changes --- tests/Database/EmptyQueryTest.php | 4 ++- tests/Database/SelectFieldsTest.php | 4 ++- tests/TestCase.php | 8 +++--- tests/Unit/AutomatedPersistedQueriesTest.php | 26 +++++++++++++++++++- tests/Unit/EndpointTest.php | 5 +++- tests/Unit/GraphQLTest.php | 14 +++++++++-- tests/Unit/UnusedVariablesTest.php | 3 +++ 7 files changed, 55 insertions(+), 9 deletions(-) diff --git a/tests/Database/EmptyQueryTest.php b/tests/Database/EmptyQueryTest.php index 9e4427d5..39c44100 100644 --- a/tests/Database/EmptyQueryTest.php +++ b/tests/Database/EmptyQueryTest.php @@ -37,7 +37,9 @@ public function testEmptyBatchedQuery(): void $results = array_map( static function (array $result): array { - unset($result['errors'][0]['trace']); + unset($result['errors'][0]['extensions']['file']); + unset($result['errors'][0]['extensions']['line']); + unset($result['errors'][0]['extensions']['trace']); return $result; }, diff --git a/tests/Database/SelectFieldsTest.php b/tests/Database/SelectFieldsTest.php index 499bbdf0..7824548d 100644 --- a/tests/Database/SelectFieldsTest.php +++ b/tests/Database/SelectFieldsTest.php @@ -164,7 +164,9 @@ public function testWithSelectFieldsNonInjectableTypehints(): void 'expectErrors' => true, ]); - unset($result['errors'][0]['trace']); + unset($result['errors'][0]['extensions']['file']); + unset($result['errors'][0]['extensions']['line']); + unset($result['errors'][0]['extensions']['trace']); $expectedResult = [ 'errors' => [ diff --git a/tests/TestCase.php b/tests/TestCase.php index d852791d..453d9e35 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -203,15 +203,17 @@ protected function httpGraphql(string $query, array $options = []): array if (!$expectErrors && isset($result['errors'])) { $appendErrors = ''; - if (isset($result['errors'][0]['trace'])) { - $appendErrors = "\n\n" . $this->formatSafeTrace($result['errors'][0]['trace']); + if (isset($result['errors'][0]['extensions']['trace'])) { + $appendErrors = "\n\n" . $this->formatSafeTrace($result['errors'][0]['extensions']['trace']); } $assertMessage = "Probably unexpected error in GraphQL response:\n" . var_export($result, true) . $appendErrors; } - unset($result['errors'][0]['trace']); + unset($result['errors'][0]['extensions']['trace']); + unset($result['errors'][0]['extensions']['file']); + unset($result['errors'][0]['extensions']['line']); if ($assertMessage) { throw new ExpectationFailedException($assertMessage); diff --git a/tests/Unit/AutomatedPersistedQueriesTest.php b/tests/Unit/AutomatedPersistedQueriesTest.php index 407e58f1..992300de 100644 --- a/tests/Unit/AutomatedPersistedQueriesTest.php +++ b/tests/Unit/AutomatedPersistedQueriesTest.php @@ -49,6 +49,9 @@ public function testPersistedQueryNotSupported(): void $content = $response->json(); + unset($content['errors'][0]['extensions']['file']); + unset($content['errors'][0]['extensions']['line']); + self::assertEquals([ 'errors' => [ [ @@ -77,6 +80,9 @@ public function testPersistedQueryNotFound(): void $content = $response->json(); + unset($content['errors'][0]['extensions']['file']); + unset($content['errors'][0]['extensions']['line']); + self::assertEquals([ 'errors' => [ [ @@ -200,6 +206,9 @@ public function testPersistedQueryInvalidHash(): void $content = $response->json(); + unset($content['errors'][0]['extensions']['file']); + unset($content['errors'][0]['extensions']['line']); + self::assertEquals([ 'errors' => [ [ @@ -244,6 +253,11 @@ public function testPersistedQueryBatchingNotSupported(): void $content = $response->json(); + unset($content[0]['errors'][0]['extensions']['file']); + unset($content[0]['errors'][0]['extensions']['line']); + unset($content[1]['errors'][0]['extensions']['file']); + unset($content[1]['errors'][0]['extensions']['line']); + self::assertArrayHasKey(0, $content); self::assertArrayHasKey(1, $content); @@ -329,6 +343,11 @@ public function testPersistedQueryBatchingFoundNotFoundAndInvalidHash(): void $content = $response->json(); + unset($content[1]['errors'][0]['extensions']['file']); + unset($content[1]['errors'][0]['extensions']['line']); + unset($content[2]['errors'][0]['extensions']['file']); + unset($content[2]['errors'][0]['extensions']['line']); + self::assertArrayHasKey(0, $content); self::assertArrayHasKey(1, $content); self::assertArrayHasKey(2, $content); @@ -452,7 +471,9 @@ public function testPersistedQueryNotAnArray(): void $content = $response->json(); - unset($content['errors'][0]['trace']); + unset($content['errors'][0]['extensions']['file']); + unset($content['errors'][0]['extensions']['line']); + unset($content['errors'][0]['extensions']['trace']); $expected = [ 'errors' => [ @@ -485,6 +506,9 @@ public function testPersistedQueryParseError(): void $content = $response->json(); + unset($content['errors'][0]['extensions']['file']); + unset($content['errors'][0]['extensions']['line']); + $expected = [ 'errors' => [ [ diff --git a/tests/Unit/EndpointTest.php b/tests/Unit/EndpointTest.php index 007a6605..59ecf0b5 100644 --- a/tests/Unit/EndpointTest.php +++ b/tests/Unit/EndpointTest.php @@ -159,7 +159,10 @@ public function testBatchedQueriesDontWorkWithGet(): void self::assertEquals(200, $response->getStatusCode()); $content = $response->getData(true); - unset($content['errors'][0]['trace']); + + unset($content['errors'][0]['extensions']['file']); + unset($content['errors'][0]['extensions']['line']); + unset($content['errors'][0]['extensions']['trace']); $expected = [ 'errors' => [ diff --git a/tests/Unit/GraphQLTest.php b/tests/Unit/GraphQLTest.php index 9d55d652..e790acc2 100644 --- a/tests/Unit/GraphQLTest.php +++ b/tests/Unit/GraphQLTest.php @@ -287,6 +287,9 @@ public function testFormatError(): void $result = GraphQL::queryAndReturnResult($this->queries['examplesWithError']); $error = GraphQL::formatError($result->errors[0]); + unset($error['extensions']['file']); + unset($error['extensions']['line']); + self::assertIsArray($error); self::assertArrayHasKey('message', $error); self::assertArrayHasKey('locations', $error); @@ -301,6 +304,8 @@ public function testFormatError(): void 'column' => 13, ], ], + 'extensions' => [ + ], ]; self::assertEquals($expectedError, $error); } @@ -315,8 +320,13 @@ public function testFormatValidationError(): void $error = new Error('error', null, null, [], null, $validationError); $error = GraphQL::formatError($error); - self::assertArrayHasKey('trace', $error); - unset($error['trace']); + self::assertArrayHasKey('extensions', $error); + self::assertArrayHasKey('file', $error['extensions']); + self::assertArrayHasKey('line', $error['extensions']); + self::assertArrayHasKey('trace', $error['extensions']); + unset($error['extensions']['file']); + unset($error['extensions']['line']); + unset($error['extensions']['trace']); $expected = [ 'message' => 'error', diff --git a/tests/Unit/UnusedVariablesTest.php b/tests/Unit/UnusedVariablesTest.php index 069c4c0c..74162141 100644 --- a/tests/Unit/UnusedVariablesTest.php +++ b/tests/Unit/UnusedVariablesTest.php @@ -56,6 +56,9 @@ public function testFeatureEnabledUnusedVariableThrowsError(): void $content = $response->getData(true); + unset($content['errors'][0]['extensions']['file']); + unset($content['errors'][0]['extensions']['line']); + $expected = [ 'errors' => [ [ From bbeb9b1f22aabc49c538ba2d38280b6e964fa399 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Mon, 17 Oct 2022 20:51:08 +0200 Subject: [PATCH 04/27] graphql-php-v15: category as provided by graphql-php has been removed A later commit adds support back for our own error classes. --- tests/Database/EmptyQueryTest.php | 5 ----- tests/Unit/AutomatedPersistedQueriesTest.php | 2 -- tests/Unit/EndpointTest.php | 1 - tests/Unit/GraphQLTest.php | 3 --- tests/Unit/IntrospectionCanBeDisabledTest.php | 3 --- tests/Unit/TypesInSchemas/TypesTest.php | 6 ------ tests/Unit/UnusedVariablesTest.php | 1 - 7 files changed, 21 deletions(-) diff --git a/tests/Database/EmptyQueryTest.php b/tests/Database/EmptyQueryTest.php index 39c44100..d468d12c 100644 --- a/tests/Database/EmptyQueryTest.php +++ b/tests/Database/EmptyQueryTest.php @@ -52,7 +52,6 @@ static function (array $result): array { [ 'message' => 'GraphQL Request must include at least one of those two parameters: "query" or "queryId"', 'extensions' => [ - 'category' => 'request', ], ], ], @@ -62,7 +61,6 @@ static function (array $result): array { [ 'message' => 'GraphQL Request must include at least one of those two parameters: "query" or "queryId"', 'extensions' => [ - 'category' => 'request', ], ], ], @@ -72,7 +70,6 @@ static function (array $result): array { [ 'message' => 'GraphQL Request must include at least one of those two parameters: "query" or "queryId"', 'extensions' => [ - 'category' => 'request', ], ], ], @@ -82,7 +79,6 @@ static function (array $result): array { [ 'message' => 'GraphQL Request must include at least one of those two parameters: "query" or "queryId"', 'extensions' => [ - 'category' => 'request', ], ], ], @@ -92,7 +88,6 @@ static function (array $result): array { [ 'message' => 'Syntax Error: Unexpected ', 'extensions' => [ - 'category' => 'graphql', ], 'locations' => [ [ diff --git a/tests/Unit/AutomatedPersistedQueriesTest.php b/tests/Unit/AutomatedPersistedQueriesTest.php index 992300de..0791c497 100644 --- a/tests/Unit/AutomatedPersistedQueriesTest.php +++ b/tests/Unit/AutomatedPersistedQueriesTest.php @@ -480,7 +480,6 @@ public function testPersistedQueryNotAnArray(): void [ 'message' => 'GraphQL Request must include at least one of those two parameters: "query" or "queryId"', 'extensions' => [ - 'category' => 'request', ], ], ], @@ -514,7 +513,6 @@ public function testPersistedQueryParseError(): void [ 'message' => 'Syntax Error: Expected :, found )', 'extensions' => [ - 'category' => 'graphql', ], 'locations' => [ [ diff --git a/tests/Unit/EndpointTest.php b/tests/Unit/EndpointTest.php index 59ecf0b5..5e6aec14 100644 --- a/tests/Unit/EndpointTest.php +++ b/tests/Unit/EndpointTest.php @@ -169,7 +169,6 @@ public function testBatchedQueriesDontWorkWithGet(): void [ 'message' => 'GraphQL Request must include at least one of those two parameters: "query" or "queryId"', 'extensions' => [ - 'category' => 'request', ], ], ], diff --git a/tests/Unit/GraphQLTest.php b/tests/Unit/GraphQLTest.php index e790acc2..8bcc90f8 100644 --- a/tests/Unit/GraphQLTest.php +++ b/tests/Unit/GraphQLTest.php @@ -295,9 +295,6 @@ public function testFormatError(): void self::assertArrayHasKey('locations', $error); $expectedError = [ 'message' => 'Cannot query field "examplesQueryNotFound" on type "Query".', - 'extensions' => [ - 'category' => 'graphql', - ], 'locations' => [ [ 'line' => 3, diff --git a/tests/Unit/IntrospectionCanBeDisabledTest.php b/tests/Unit/IntrospectionCanBeDisabledTest.php index 34b4d8fc..2db5a8f7 100644 --- a/tests/Unit/IntrospectionCanBeDisabledTest.php +++ b/tests/Unit/IntrospectionCanBeDisabledTest.php @@ -27,9 +27,6 @@ public function testIntrospectionCanBeDisabled(): void 'errors' => [ [ 'message' => 'GraphQL introspection is not allowed, but the query contained __schema or __type', - 'extensions' => [ - 'category' => 'graphql', - ], 'locations' => [ [ 'line' => 2, diff --git a/tests/Unit/TypesInSchemas/TypesTest.php b/tests/Unit/TypesInSchemas/TypesTest.php index 9df8526d..ce4a8c03 100644 --- a/tests/Unit/TypesInSchemas/TypesTest.php +++ b/tests/Unit/TypesInSchemas/TypesTest.php @@ -107,9 +107,6 @@ public function testQueryAndTypeInCustomSchemaQueryingDefaultSchema(): void 'errors' => [ [ 'message' => 'Cannot query field "query" on type "Query".', - 'extensions' => [ - 'category' => 'graphql', - ], 'locations' => [ [ 'line' => 2, @@ -292,9 +289,6 @@ public function testDifferentQueriesInDifferentSchemasAndTypeGlobal(): void 'errors' => [ [ 'message' => 'Cannot query field "title" on type "Type".', - 'extensions' => [ - 'category' => 'graphql', - ], 'locations' => [ [ 'line' => 3, diff --git a/tests/Unit/UnusedVariablesTest.php b/tests/Unit/UnusedVariablesTest.php index 74162141..bf24d4bd 100644 --- a/tests/Unit/UnusedVariablesTest.php +++ b/tests/Unit/UnusedVariablesTest.php @@ -64,7 +64,6 @@ public function testFeatureEnabledUnusedVariableThrowsError(): void [ 'message' => 'The following variables were provided but not consumed: unused_variable, another_unused_variable', 'extensions' => [ - 'category' => 'graphql', ], ], ], From e5a533700d715ef6c8db822e0cc37e235f314173 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Mon, 17 Oct 2022 17:08:37 +0200 Subject: [PATCH 05/27] graphql-php-v15: add interface to provide errors.*.extensions.category for our own error classes --- src/Error/ProvidesErrorCategory.php | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/Error/ProvidesErrorCategory.php diff --git a/src/Error/ProvidesErrorCategory.php b/src/Error/ProvidesErrorCategory.php new file mode 100644 index 00000000..da51c629 --- /dev/null +++ b/src/Error/ProvidesErrorCategory.php @@ -0,0 +1,9 @@ + Date: Mon, 17 Oct 2022 17:08:49 +0200 Subject: [PATCH 06/27] graphql-php-v15: use new ProvidesErrorCategory interface on error classes --- src/Error/AuthorizationError.php | 2 +- src/Error/AutomaticPersistedQueriesError.php | 2 +- src/Error/ValidationError.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Error/AuthorizationError.php b/src/Error/AuthorizationError.php index d97ffb3f..896ca20f 100644 --- a/src/Error/AuthorizationError.php +++ b/src/Error/AuthorizationError.php @@ -5,7 +5,7 @@ use GraphQL\Error\Error; -class AuthorizationError extends Error +class AuthorizationError extends Error implements ProvidesErrorCategory { public function isClientSafe(): bool { diff --git a/src/Error/AutomaticPersistedQueriesError.php b/src/Error/AutomaticPersistedQueriesError.php index 54831a6d..2841b732 100644 --- a/src/Error/AutomaticPersistedQueriesError.php +++ b/src/Error/AutomaticPersistedQueriesError.php @@ -5,7 +5,7 @@ use GraphQL\Error\Error; -class AutomaticPersistedQueriesError extends Error +class AutomaticPersistedQueriesError extends Error implements ProvidesErrorCategory { public const CODE_PERSISTED_QUERY_NOT_SUPPORTED = 'PERSISTED_QUERY_NOT_SUPPORTED'; public const CODE_PERSISTED_QUERY_NOT_FOUND = 'PERSISTED_QUERY_NOT_FOUND'; diff --git a/src/Error/ValidationError.php b/src/Error/ValidationError.php index 90450f9c..bcfb0337 100644 --- a/src/Error/ValidationError.php +++ b/src/Error/ValidationError.php @@ -7,7 +7,7 @@ use Illuminate\Contracts\Support\MessageBag; use Illuminate\Contracts\Validation\Validator; -class ValidationError extends Error +class ValidationError extends Error implements ProvidesErrorCategory { /** @var Validator */ private $validator; From 5fcd96a8cd3a8a04383dc2c3bd1d820ab14cd0be Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Mon, 17 Oct 2022 17:08:57 +0200 Subject: [PATCH 07/27] graphql-php-v15: check for `ProvidesErrorCategory` and add category back to payload --- src/GraphQL.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/GraphQL.php b/src/GraphQL.php index 6a4fb110..70c01a94 100644 --- a/src/GraphQL.php +++ b/src/GraphQL.php @@ -21,6 +21,7 @@ use Illuminate\Support\Traits\Macroable; use Illuminate\Validation\ValidationException; use Rebing\GraphQL\Error\AuthorizationError; +use Rebing\GraphQL\Error\ProvidesErrorCategory; use Rebing\GraphQL\Error\ValidationError; use Rebing\GraphQL\Exception\SchemaNotFound; use Rebing\GraphQL\Exception\TypeNotFound; @@ -510,6 +511,12 @@ public static function formatError(Error $e): array if ($previous instanceof ValidationError) { $error['extensions']['validation'] = $previous->getValidatorMessages()->getMessages(); } + + if ($previous instanceof ProvidesErrorCategory) { + $error['extensions']['category'] = $previous->getCategory(); + } + } elseif ($e instanceof ProvidesErrorCategory) { + $error['extensions']['category'] = $e->getCategory(); } return $error; From c8c61ea5d8c7cca3b2f61f245d157b498b57d71a Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Mon, 17 Oct 2022 17:09:33 +0200 Subject: [PATCH 08/27] graphql-php-v15: adapt for changed location of debugMessage --- .../SelectFields/ValidateFieldTests/ValidateFieldTest.php | 3 +-- tests/Database/SelectFieldsTest.php | 3 +-- .../EngineErrorInResolverTests/EngineErrorInResolverTest.php | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/Database/SelectFields/ValidateFieldTests/ValidateFieldTest.php b/tests/Database/SelectFields/ValidateFieldTests/ValidateFieldTest.php index e1c2e232..23906dfd 100644 --- a/tests/Database/SelectFields/ValidateFieldTests/ValidateFieldTest.php +++ b/tests/Database/SelectFields/ValidateFieldTests/ValidateFieldTest.php @@ -505,10 +505,9 @@ public function testPrivacyWrongType(): void $expectedResult = [ 'errors' => [ [ - 'debugMessage' => 'Unsupported use of \'privacy\' configuration on field \'title_privacy_wrong_type\'.', 'message' => 'Internal server error', 'extensions' => [ - 'category' => 'internal', + 'debugMessage' => 'Unsupported use of \'privacy\' configuration on field \'title_privacy_wrong_type\'.', ], 'locations' => [ [ diff --git a/tests/Database/SelectFieldsTest.php b/tests/Database/SelectFieldsTest.php index 7824548d..202cca70 100644 --- a/tests/Database/SelectFieldsTest.php +++ b/tests/Database/SelectFieldsTest.php @@ -171,10 +171,9 @@ public function testWithSelectFieldsNonInjectableTypehints(): void $expectedResult = [ 'errors' => [ [ - 'debugMessage' => "'coolNumber' could not be injected", 'message' => 'Internal server error', 'extensions' => [ - 'category' => 'internal', + 'debugMessage' => "'coolNumber' could not be injected", ], 'locations' => [ [ diff --git a/tests/Unit/EngineErrorInResolverTests/EngineErrorInResolverTest.php b/tests/Unit/EngineErrorInResolverTests/EngineErrorInResolverTest.php index bee45bb2..dac07b8c 100644 --- a/tests/Unit/EngineErrorInResolverTests/EngineErrorInResolverTest.php +++ b/tests/Unit/EngineErrorInResolverTests/EngineErrorInResolverTest.php @@ -28,7 +28,7 @@ public function testForEngineError(): void ]); // Using a regex here because in some cases the message gets prefixed with "Type error:" - self::assertMatchesRegularExpression('/Simulating a TypeError/', $result['errors'][0]['debugMessage']); + self::assertMatchesRegularExpression('/Simulating a TypeError/', $result['errors'][0]['extensions']['debugMessage']); } protected function resolveApplicationExceptionHandler($app): void From 0124fd4c294e36fef782279559356e5356bf07ce Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Mon, 17 Oct 2022 20:40:34 +0200 Subject: [PATCH 09/27] graphql-php-v15: use FCQN now instead only the class name The ability to internally prepend the graphql-php namespace was removed [1]. [1] https://github.com/webonyx/graphql-php/commit/d36e80962bd82b2f515617de50e0c87c8049bc3c#diff-fa0403de31548d680d863a100fdc906ec53696abb9d1e8b0cbc92020b7cce9a2L255 --- src/GraphQLServiceProvider.php | 6 +++--- tests/Unit/ConfigTest.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/GraphQLServiceProvider.php b/src/GraphQLServiceProvider.php index 34f54d1a..08cce9c4 100644 --- a/src/GraphQLServiceProvider.php +++ b/src/GraphQLServiceProvider.php @@ -77,7 +77,7 @@ protected function applySecurityRules(Repository $config): void if (null !== $maxQueryComplexity) { /** @var QueryComplexity $queryComplexity */ - $queryComplexity = DocumentValidator::getRule('QueryComplexity'); + $queryComplexity = DocumentValidator::getRule(QueryComplexity::class); $queryComplexity->setMaxQueryComplexity($maxQueryComplexity); } @@ -85,7 +85,7 @@ protected function applySecurityRules(Repository $config): void if (null !== $maxQueryDepth) { /** @var QueryDepth $queryDepth */ - $queryDepth = DocumentValidator::getRule('QueryDepth'); + $queryDepth = DocumentValidator::getRule(QueryDepth::class); $queryDepth->setMaxQueryDepth($maxQueryDepth); } @@ -93,7 +93,7 @@ protected function applySecurityRules(Repository $config): void if (true === $disableIntrospection) { /** @var DisableIntrospection $disableIntrospection */ - $disableIntrospection = DocumentValidator::getRule('DisableIntrospection'); + $disableIntrospection = DocumentValidator::getRule(DisableIntrospection::class); $disableIntrospection->setEnabled(DisableIntrospection::ENABLED); } } diff --git a/tests/Unit/ConfigTest.php b/tests/Unit/ConfigTest.php index dc6e3c0f..82dea397 100644 --- a/tests/Unit/ConfigTest.php +++ b/tests/Unit/ConfigTest.php @@ -72,11 +72,11 @@ public function testSchema(): void public function testSecurity(): void { /** @var QueryComplexity $queryComplexity */ - $queryComplexity = DocumentValidator::getRule('QueryComplexity'); + $queryComplexity = DocumentValidator::getRule(QueryComplexity::class); self::assertEquals(1000, $queryComplexity->getMaxQueryComplexity()); /** @var QueryDepth $queryDepth */ - $queryDepth = DocumentValidator::getRule('QueryDepth'); + $queryDepth = DocumentValidator::getRule(QueryDepth::class); self::assertEquals(10, $queryDepth->getMaxQueryDepth()); } From 363f3214ea9da8a47249ccc8beccd00b3b02c100 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Mon, 17 Oct 2022 21:05:11 +0200 Subject: [PATCH 10/27] graphql-php-v15: replace `getWrappedType(true)` with `getInnermostType()` --- src/Support/AliasArguments/AliasArguments.php | 2 +- src/Support/RulesInFields.php | 2 +- src/Support/SelectFields.php | 8 ++++---- tests/Unit/GraphQLTest.php | 12 ++++++------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Support/AliasArguments/AliasArguments.php b/src/Support/AliasArguments/AliasArguments.php index e42e5d90..a38b71c3 100644 --- a/src/Support/AliasArguments/AliasArguments.php +++ b/src/Support/AliasArguments/AliasArguments.php @@ -119,7 +119,7 @@ private function isWrappedInList(Type $type): bool private function getWrappedType(Type $type): Type { if ($type instanceof WrappingType) { - $type = $type->getWrappedType(true); + $type = $type->getInnermostType(); } return $type; diff --git a/src/Support/RulesInFields.php b/src/Support/RulesInFields.php index fae4ab49..5dd66c82 100644 --- a/src/Support/RulesInFields.php +++ b/src/Support/RulesInFields.php @@ -21,7 +21,7 @@ class RulesInFields public function __construct(Type $parentType, array $fieldsAndArgumentsSelection) { $this->parentType = $parentType instanceof WrappingType - ? $parentType->getWrappedType(true) + ? $parentType->getInnermostType() : $parentType; $this->fieldsAndArguments = $fieldsAndArgumentsSelection; } diff --git a/src/Support/SelectFields.php b/src/Support/SelectFields.php index 8c487028..303a21fc 100644 --- a/src/Support/SelectFields.php +++ b/src/Support/SelectFields.php @@ -41,7 +41,7 @@ class SelectFields public function __construct(GraphqlType $parentType, array $queryArgs, $ctx, array $fieldsAndArguments) { if ($parentType instanceof WrappingType) { - $parentType = $parentType->getWrappedType(true); + $parentType = $parentType->getInnermostType(); } $requestedFields = [ @@ -77,7 +77,7 @@ public static function getSelectableFieldsAndRelations( $with = []; if ($parentType instanceof WrappingType) { - $parentType = $parentType->getWrappedType(true); + $parentType = $parentType->getInnermostType(); } $parentTable = static::getTableNameFromParentType($parentType); $primaryKey = static::getPrimaryKeyFromParentType($parentType); @@ -164,7 +164,7 @@ protected static function handleFields( $parentTypeUnwrapped = $parentType; if ($parentTypeUnwrapped instanceof WrappingType) { - $parentTypeUnwrapped = $parentTypeUnwrapped->getWrappedType(true); + $parentTypeUnwrapped = $parentTypeUnwrapped->getInnermostType(); } // First check if the field is even accessible @@ -500,7 +500,7 @@ function (GraphqlType $type) use ($query) { } if ($newParentType instanceof WrappingType) { - $newParentType = $newParentType->getWrappedType(true); + $newParentType = $newParentType->getInnermostType(); } /** @var callable $callable */ diff --git a/tests/Unit/GraphQLTest.php b/tests/Unit/GraphQLTest.php index 8bcc90f8..1c4f9071 100644 --- a/tests/Unit/GraphQLTest.php +++ b/tests/Unit/GraphQLTest.php @@ -125,11 +125,11 @@ public function testListOfNonNullType(): void /** @var ListOfType */ $typeOther = GraphQL::type('[Example!]'); - self::assertSame($type->getWrappedType(true), $typeOther->getWrappedType(true)); + self::assertSame($type->getInnermostType(), $typeOther->getInnermostType()); /** @var ListOfType */ $typeOther = GraphQL::type('[Example!]', true); - self::assertNotSame($type->getWrappedType(true), $typeOther->getWrappedType(true)); + self::assertNotSame($type->getInnermostType(), $typeOther->getInnermostType()); } public function testNonNullListOfNonNullType(): void @@ -145,11 +145,11 @@ public function testNonNullListOfNonNullType(): void /** @var NonNull */ $typeOther = GraphQL::type('[Example!]!'); - self::assertSame($type->getWrappedType(true), $typeOther->getWrappedType(true)); + self::assertSame($type->getInnermostType(), $typeOther->getInnermostType()); /** @var NonNull */ $typeOther = GraphQL::type('[Example!]!', true); - self::assertNotSame($type->getWrappedType(true), $typeOther->getWrappedType(true)); + self::assertNotSame($type->getInnermostType(), $typeOther->getInnermostType()); } public function testMalformedListOfWithNoLeadingBracket(): void @@ -225,7 +225,7 @@ public function testStandardTypeModifiers(): void self::assertInstanceOf(ListOfType::class, $type); self::assertInstanceOf(NonNull::class, $type->getWrappedType()); - self::assertSame($type->getWrappedType(true), $standardType); + self::assertSame($type->getInnermostType(), $standardType); /** @var NonNull */ $type = GraphQL::type("[$standardType->name!]!"); @@ -235,7 +235,7 @@ public function testStandardTypeModifiers(): void self::assertInstanceOf(NonNull::class, $type); self::assertInstanceOf(ListOfType::class, $wrappedType); self::assertInstanceOf(NonNull::class, $wrappedType->getWrappedType()); - self::assertSame($type->getWrappedType(true), $standardType); + self::assertSame($type->getInnermostType(), $standardType); } } From da2fde404d0a3e0a4383ef6d79bdde92048e02f4 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Mon, 17 Oct 2022 21:07:19 +0200 Subject: [PATCH 11/27] graphql-php-v15: adjust for changed error message --- tests/Unit/GraphQLTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/GraphQLTest.php b/tests/Unit/GraphQLTest.php index 1c4f9071..953bb117 100644 --- a/tests/Unit/GraphQLTest.php +++ b/tests/Unit/GraphQLTest.php @@ -294,7 +294,7 @@ public function testFormatError(): void self::assertArrayHasKey('message', $error); self::assertArrayHasKey('locations', $error); $expectedError = [ - 'message' => 'Cannot query field "examplesQueryNotFound" on type "Query".', + 'message' => 'Cannot query field "examplesQueryNotFound" on type "Query". Did you mean "examplesPagination"?', 'locations' => [ [ 'line' => 3, From 86f2ded0efd09454ada50c500df386cfca14e60c Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Mon, 17 Oct 2022 21:13:46 +0200 Subject: [PATCH 12/27] graphql-php-v15: temporarily skip test Until we figure out what the replacement for the getter is --- tests/Unit/ConfigTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Unit/ConfigTest.php b/tests/Unit/ConfigTest.php index 82dea397..3f8be393 100644 --- a/tests/Unit/ConfigTest.php +++ b/tests/Unit/ConfigTest.php @@ -71,6 +71,8 @@ public function testSchema(): void public function testSecurity(): void { + self::markTestSkipped('Skipped until we know whether/how to retrieve the applied config values, see also https://github.com/webonyx/graphql-php/discussions/1231#discussioncomment-3899310'); + /** @var QueryComplexity $queryComplexity */ $queryComplexity = DocumentValidator::getRule(QueryComplexity::class); self::assertEquals(1000, $queryComplexity->getMaxQueryComplexity()); From a911604d9d9c7e5e402b217a535b87db8823b015 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Mon, 17 Oct 2022 21:36:28 +0200 Subject: [PATCH 13/27] graphql-php-v15: `OperationParams` methods `getOriginalInput` and `isReadOnly` have been dropped in favour of the public properties --- src/Support/OperationParams.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Support/OperationParams.php b/src/Support/OperationParams.php index 282e676b..1c8686c6 100644 --- a/src/Support/OperationParams.php +++ b/src/Support/OperationParams.php @@ -32,14 +32,17 @@ protected function init(BaseOperationParams $baseOperationParams): void $this->baseOperationParams = $baseOperationParams; } - public function getOriginalInput($key) + /** + * @return mixed|null + */ + public function getOriginalInput(string $key) { - return $this->baseOperationParams->getOriginalInput($key); + return $this->baseOperationParams->originalInput[$key] ?? null; } - public function isReadOnly() + public function isReadOnly(): bool { - return $this->baseOperationParams->isReadOnly(); + return $this->baseOperationParams->readOnly; } public function getParsedQuery(): DocumentNode From ebd843a875b0da58681444a5c4de8f587dff44f9 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Mon, 17 Oct 2022 21:45:31 +0200 Subject: [PATCH 14/27] graphql-php-v15: adapt phpstan config --- phpstan.neon.dist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 7f7739df..958db772 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -23,11 +23,11 @@ parameters: - '/Trying to invoke Closure\|null but it might not be a callable/' - '/Property Rebing\\GraphQL\\Support\\Field\:\:\$name \(string\) does not accept int\|string/' - '/Parameter #1 \$name of method Rebing\\GraphQL\\Support\\Type\:\:getFieldResolver\(\) expects string, int\|string given/' - # tests/Unit/EndpointTest.php - - '/Parameter #1 \$wrappedType of static method GraphQL\\Type\\Definition\\Type::nonNull\(\) expects \(callable\(\): mixed\)\|GraphQL\\Type\\Definition\\NullableType, GraphQL\\Type\\Definition\\Type given/' # Mass ignore the raw array property access used in many tests for now # See also https://github.com/nunomaduro/larastan/issues/611 - path: tests/* message: '/Cannot access property \$[a-z]+ on Rebing\\GraphQL\\Tests\\Support\\Models\\[A-Za-z]+\|null./' + - path: tests/* + message: '/Parameter #1 \$type of static method GraphQL\\Type\\Definition\\Type::nonNull\(\) expects .*, GraphQL\\Type\\Definition\\Type given./' reportUnmatchedIgnoredErrors: true From c01f88dab4abbf2faf24036dacf1b16e3e3a54f6 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Mon, 17 Oct 2022 21:48:07 +0200 Subject: [PATCH 15/27] graphql-php-v15: adapt phpstan baseline --- phpstan-baseline.neon | 75 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 9d5de947..624c1490 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -5,6 +5,16 @@ parameters: count: 2 path: src/GraphQL.php + - + message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Definition\\\\ObjectType constructor expects array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, resolveField\\?\\: \\(callable\\(mixed, array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|null, fields\\: \\(callable\\(\\)\\: iterable\\)\\|iterable, interfaces\\?\\: \\(callable\\(\\)\\: iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>\\)\\|iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>, isTypeOf\\?\\: \\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: bool\\|GraphQL\\\\Deferred\\|null\\)\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\ObjectTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}, non\\-empty\\-array\\\\|\\(ArrayAccess&Rebing\\\\GraphQL\\\\Support\\\\Field\\)\\>\\|string\\> given\\.$#" + count: 1 + path: src/GraphQL.php + + - + message: "#^Property GraphQL\\\\Type\\\\Definition\\\\ObjectType\\:\\:\\$config \\(array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, resolveField\\?\\: \\(callable\\(mixed, array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|null, fields\\: \\(callable\\(\\)\\: iterable\\)\\|iterable, interfaces\\?\\: \\(callable\\(\\)\\: iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>\\)\\|iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>, isTypeOf\\?\\: \\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: bool\\|GraphQL\\\\Deferred\\|null\\)\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\ObjectTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}\\) does not accept non\\-empty\\-array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|\\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: bool\\|GraphQL\\\\Deferred\\|null\\)\\|GraphQL\\\\Language\\\\AST\\\\ObjectTypeDefinitionNode\\|iterable\\|string\\|null\\>\\.$#" + count: 1 + path: src/GraphQL.php + - message: "#^Property Rebing\\\\GraphQL\\\\GraphQL\\:\\:\\$types \\(array\\\\) does not accept array\\\\.$#" count: 1 @@ -65,6 +75,11 @@ parameters: count: 1 path: src/Support/AliasArguments/ArrayKeyChange.php + - + message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Definition\\\\EnumType constructor expects array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, values\\: \\(callable\\(\\)\\: iterable\\\\|iterable\\\\)\\|iterable\\, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\EnumTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}, array\\ given\\.$#" + count: 1 + path: src/Support/EnumType.php + - message: "#^Parameter \\#2 \\$schema of method Rebing\\\\GraphQL\\\\Support\\\\ExecutionMiddleware\\\\AbstractExecutionMiddleware\\:\\:handle\\(\\) expects GraphQL\\\\Type\\\\Schema, Closure given\\.$#" count: 1 @@ -140,6 +155,16 @@ parameters: count: 1 path: src/Support/Field.php + - + message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Definition\\\\InputObjectType constructor expects array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, fields\\: \\(callable\\(\\)\\: iterable\\\\)\\|iterable\\, parseValue\\?\\: callable\\(array\\\\)\\: mixed, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\InputObjectTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}, array\\ given\\.$#" + count: 1 + path: src/Support/InputType.php + + - + message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Definition\\\\InterfaceType constructor expects array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, fields\\: \\(callable\\(\\)\\: iterable\\)\\|iterable, interfaces\\?\\: \\(callable\\(\\)\\: iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>\\)\\|iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>, resolveType\\?\\: \\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: \\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|string\\|null\\)\\|GraphQL\\\\Deferred\\|GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|string\\|null\\)\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\InterfaceTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}, array\\ given\\.$#" + count: 1 + path: src/Support/InterfaceType.php + - message: "#^Method Rebing\\\\GraphQL\\\\Support\\\\Middleware\\:\\:handle\\(\\) has no return type specified\\.$#" count: 1 @@ -185,6 +210,11 @@ parameters: count: 1 path: src/Support/Privacy.php + - + message: "#^Access to an undefined property GraphQL\\\\Type\\\\Definition\\\\Type\\:\\:\\$config\\.$#" + count: 1 + path: src/Support/SelectFields.php + - message: "#^Instanceof between \\*NEVER\\* and 'Jenssegers\\\\\\\\Mongodb…' will always evaluate to false\\.$#" count: 1 @@ -280,6 +310,21 @@ parameters: count: 1 path: src/Support/SelectFields.php + - + message: "#^Offset 'always' on array\\{name\\: string, type\\: \\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\OutputType&GraphQL\\\\Type\\\\Definition\\\\Type\\)\\|\\(GraphQL\\\\Type\\\\Definition\\\\OutputType&GraphQL\\\\Type\\\\Definition\\\\Type\\), resolve\\?\\: \\(callable\\(mixed, array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|null, args\\?\\: iterable\\\\|null, description\\?\\: string\\|null, deprecationReason\\?\\: string\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\FieldDefinitionNode\\|null, complexity\\?\\: \\(callable\\(int, array\\\\)\\: int\\)\\|null\\} in isset\\(\\) does not exist\\.$#" + count: 1 + path: src/Support/SelectFields.php + + - + message: "#^Offset 'privacy' on array\\{name\\: string, type\\: \\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\OutputType&GraphQL\\\\Type\\\\Definition\\\\Type\\)\\|\\(GraphQL\\\\Type\\\\Definition\\\\OutputType&GraphQL\\\\Type\\\\Definition\\\\Type\\), resolve\\?\\: \\(callable\\(mixed, array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|null, args\\?\\: iterable\\\\|null, description\\?\\: string\\|null, deprecationReason\\?\\: string\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\FieldDefinitionNode\\|null, complexity\\?\\: \\(callable\\(int, array\\\\)\\: int\\)\\|null\\} in isset\\(\\) does not exist\\.$#" + count: 1 + path: src/Support/SelectFields.php + + - + message: "#^Offset 'selectable' on array\\{name\\: string, type\\: \\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\OutputType&GraphQL\\\\Type\\\\Definition\\\\Type\\)\\|\\(GraphQL\\\\Type\\\\Definition\\\\OutputType&GraphQL\\\\Type\\\\Definition\\\\Type\\), resolve\\?\\: \\(callable\\(mixed, array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|null, args\\?\\: iterable\\\\|null, description\\?\\: string\\|null, deprecationReason\\?\\: string\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\FieldDefinitionNode\\|null, complexity\\?\\: \\(callable\\(int, array\\\\)\\: int\\)\\|null\\} in isset\\(\\) does not exist\\.$#" + count: 1 + path: src/Support/SelectFields.php + - message: "#^Parameter \\#1 \\$callback of function call_user_func expects callable\\(\\)\\: mixed, array\\{\\*NEVER\\*, mixed\\} given\\.$#" count: 1 @@ -295,6 +340,11 @@ parameters: count: 1 path: src/Support/SelectFields.php + - + message: "#^Result of && is always false\\.$#" + count: 1 + path: src/Support/SelectFields.php + - message: "#^Anonymous function never returns null so it can be removed from the return type\\.$#" count: 2 @@ -316,9 +366,14 @@ parameters: path: src/Support/Type.php - - message: "#^Parameter \\#2 \\$nodes of class GraphQL\\\\Error\\\\Error constructor expects GraphQL\\\\Language\\\\AST\\\\Node\\|\\(iterable\\&Traversable\\)\\|null, array\\ given\\.$#" + message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Definition\\\\ObjectType constructor expects array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, resolveField\\?\\: \\(callable\\(mixed, array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|null, fields\\: \\(callable\\(\\)\\: iterable\\)\\|iterable, interfaces\\?\\: \\(callable\\(\\)\\: iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>\\)\\|iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>, isTypeOf\\?\\: \\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: bool\\|GraphQL\\\\Deferred\\|null\\)\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\ObjectTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}, array\\ given\\.$#" count: 1 - path: src/Support/UploadType.php + path: src/Support/Type.php + + - + message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Definition\\\\UnionType constructor expects array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, types\\: \\(callable\\(\\)\\: iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\)\\|GraphQL\\\\Type\\\\Definition\\\\ObjectType\\>\\)\\|iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\)\\|GraphQL\\\\Type\\\\Definition\\\\ObjectType\\>, resolveType\\?\\: \\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: \\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|string\\|null\\)\\|GraphQL\\\\Deferred\\|GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|string\\|null\\)\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\UnionTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}, array\\ given\\.$#" + count: 1 + path: src/Support/UnionType.php - message: "#^Unsafe usage of new static\\(\\)\\.$#" @@ -1245,6 +1300,11 @@ parameters: count: 1 path: tests/Unit/AliasArguments/Stubs/UpdateExampleMutation.php + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: tests/Unit/ConfigTest.php + - message: "#^Method Rebing\\\\GraphQL\\\\Tests\\\\Unit\\\\Console\\\\EnumMakeCommandTest\\:\\:dataForMakeCommand\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 @@ -1306,15 +1366,20 @@ parameters: path: tests/Unit/EngineErrorInResolverTests/QueryWithEngineErrorInCodeQuery.php - - message: "#^Offset 'index' does not exist on array\\|null\\.$#" - count: 1 - path: tests/Unit/ExecutionMiddlewareTest/ChangeVariableMiddleware.php + message: "#^Access to an undefined property GraphQL\\\\Type\\\\Definition\\\\Type\\:\\:\\$name\\.$#" + count: 5 + path: tests/Unit/GraphQLTest.php - message: "#^Parameter \\#1 \\$abstract of function app expects string\\|null, object\\|string given\\.$#" count: 3 path: tests/Unit/GraphQLTest.php + - + message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Definition\\\\ObjectType constructor expects array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, resolveField\\?\\: \\(callable\\(mixed, array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|null, fields\\: \\(callable\\(\\)\\: iterable\\)\\|iterable, interfaces\\?\\: \\(callable\\(\\)\\: iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>\\)\\|iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>, isTypeOf\\?\\: \\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: bool\\|GraphQL\\\\Deferred\\|null\\)\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\ObjectTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}, array\\{name\\: 'ObjectType'\\} given\\.$#" + count: 1 + path: tests/Unit/GraphQLTest.php + - message: "#^Method Rebing\\\\GraphQL\\\\Tests\\\\Unit\\\\InstantiableTypesTest\\\\FormattableDate\\:\\:__construct\\(\\) has parameter \\$settings with no value type specified in iterable type array\\.$#" count: 1 From 38c518da50ff6118b2e25ad3a29399442830885f Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Fri, 21 Oct 2022 13:15:43 +0200 Subject: [PATCH 16/27] Revert "graphql-php-v15: temporarily skip test" This reverts commit 86f2ded0efd09454ada50c500df386cfca14e60c. --- tests/Unit/ConfigTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Unit/ConfigTest.php b/tests/Unit/ConfigTest.php index 3f8be393..82dea397 100644 --- a/tests/Unit/ConfigTest.php +++ b/tests/Unit/ConfigTest.php @@ -71,8 +71,6 @@ public function testSchema(): void public function testSecurity(): void { - self::markTestSkipped('Skipped until we know whether/how to retrieve the applied config values, see also https://github.com/webonyx/graphql-php/discussions/1231#discussioncomment-3899310'); - /** @var QueryComplexity $queryComplexity */ $queryComplexity = DocumentValidator::getRule(QueryComplexity::class); self::assertEquals(1000, $queryComplexity->getMaxQueryComplexity()); From 5415db905df16524e83541d3e4702cca2ec3ec57 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Sat, 7 Jan 2023 11:55:43 +0100 Subject: [PATCH 17/27] graphql-php-v15: switch composer version to 15 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7173f4ee..582803f4 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,7 @@ "illuminate/support": "^6.0|^8.0|^9.0", "laragraph/utils": "dev-graphql-php-15", "thecodingmachine/safe": "^1.3", - "webonyx/graphql-php": "dev-master" + "webonyx/graphql-php": "^15" }, "require-dev": { "ext-pdo_sqlite": "*", From 9297b5cba1b996d968acefda2b252c1dc7762f8e Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Sat, 7 Jan 2023 11:56:06 +0100 Subject: [PATCH 18/27] graphql-php-v15: fix rename of FieldArgument and arg requires explicit key name --- tests/Support/Directives/ExampleDirective.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Support/Directives/ExampleDirective.php b/tests/Support/Directives/ExampleDirective.php index bdad2787..3eee8d3e 100644 --- a/tests/Support/Directives/ExampleDirective.php +++ b/tests/Support/Directives/ExampleDirective.php @@ -5,7 +5,7 @@ use GraphQL\Language\DirectiveLocation; use GraphQL\Type\Definition\Directive; -use GraphQL\Type\Definition\FieldArgument; +use GraphQL\Type\Definition\Argument; use GraphQL\Type\Definition\Type; class ExampleDirective extends Directive @@ -20,7 +20,7 @@ public function __construct() DirectiveLocation::QUERY, ], 'args' => [ - new FieldArgument([ + 'first' => new Argument([ 'name' => 'first', 'description' => 'Description of this argument', 'type' => Type::string(), From 027d590de5ff99955d9d473eb4c4176db90ea4e2 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Sat, 7 Jan 2023 12:26:13 +0100 Subject: [PATCH 19/27] graphql-php-v15: update phpstan baseline --- phpstan-baseline.neon | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 428d7e2d..2d9eef8c 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -10,6 +10,11 @@ parameters: count: 1 path: src/GraphQL.php + - + message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Schema constructor expects array\\{query\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, mutation\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, subscription\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, types\\?\\: \\(callable\\(\\)\\: iterable\\\\)\\|iterable\\\\|null, directives\\?\\: array\\\\|null, typeLoader\\?\\: \\(callable\\(string\\)\\: \\(GraphQL\\\\Type\\\\Definition\\\\NamedType&GraphQL\\\\Type\\\\Definition\\\\Type\\)\\|null\\)\\|null, assumeValid\\?\\: bool\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\SchemaDefinitionNode\\|null, \\.\\.\\.\\}\\|GraphQL\\\\Type\\\\SchemaConfig, array\\{query\\: GraphQL\\\\Type\\\\Definition\\\\Type, mutation\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null, subscription\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null, directives\\: array\\, types\\: Closure\\(\\)\\: array\\, typeLoader\\: \\(Closure\\(mixed\\)\\: GraphQL\\\\Type\\\\Definition\\\\Type\\)\\|null\\} given\\.$#" + count: 1 + path: src/GraphQL.php + - message: "#^Property GraphQL\\\\Type\\\\Definition\\\\ObjectType\\:\\:\\$config \\(array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, resolveField\\?\\: \\(callable\\(mixed, array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|null, fields\\: \\(callable\\(\\)\\: iterable\\)\\|iterable, interfaces\\?\\: \\(callable\\(\\)\\: iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>\\)\\|iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>, isTypeOf\\?\\: \\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: bool\\|GraphQL\\\\Deferred\\|null\\)\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\ObjectTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}\\) does not accept non\\-empty\\-array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|\\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: bool\\|GraphQL\\\\Deferred\\|null\\)\\|GraphQL\\\\Language\\\\AST\\\\ObjectTypeDefinitionNode\\|iterable\\|string\\|null\\>\\.$#" count: 1 @@ -195,6 +200,11 @@ parameters: count: 1 path: src/Support/Middleware.php + - + message: "#^Access to an undefined property GraphQL\\\\Type\\\\Definition\\\\Type\\:\\:\\$config\\.$#" + count: 1 + path: src/Support/PaginationType.php + - message: "#^Anonymous function never returns null so it can be removed from the return type\\.$#" count: 2 @@ -212,7 +222,7 @@ parameters: - message: "#^Access to an undefined property GraphQL\\\\Type\\\\Definition\\\\Type\\:\\:\\$config\\.$#" - count: 1 + count: 6 path: src/Support/SelectFields.php - @@ -345,6 +355,11 @@ parameters: count: 1 path: src/Support/SelectFields.php + - + message: "#^Access to an undefined property GraphQL\\\\Type\\\\Definition\\\\Type\\:\\:\\$config\\.$#" + count: 1 + path: src/Support/SimplePaginationType.php + - message: "#^Anonymous function never returns null so it can be removed from the return type\\.$#" count: 2 @@ -735,6 +750,11 @@ parameters: count: 1 path: tests/Database/SelectFields/ValidateFieldTests/ValidateFieldsQuery.php + - + message: "#^Parameter \\#1 \\$config of method GraphQL\\\\Type\\\\Definition\\\\Directive\\:\\:__construct\\(\\) expects array\\{name\\: string, description\\?\\: string\\|null, args\\?\\: iterable\\\\|null, locations\\: array\\, isRepeatable\\?\\: bool\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\DirectiveDefinitionNode\\|null\\}, array\\{name\\: 'exampleDirective', description\\: 'This is an example…', locations\\: array\\{'QUERY'\\}, args\\: array\\{first\\: GraphQL\\\\Type\\\\Definition\\\\Argument\\}\\} given\\.$#" + count: 1 + path: tests/Support/Directives/ExampleDirective.php + - message: "#^Method Rebing\\\\GraphQL\\\\Tests\\\\Support\\\\Objects\\\\CustomExamplesQuery\\:\\:resolve\\(\\) has no return type specified\\.$#" count: 1 @@ -1305,11 +1325,6 @@ parameters: count: 1 path: tests/Unit/AliasArguments/Stubs/UpdateExampleMutation.php - - - message: "#^Unreachable statement \\- code above always terminates\\.$#" - count: 1 - path: tests/Unit/ConfigTest.php - - message: "#^Method Rebing\\\\GraphQL\\\\Tests\\\\Unit\\\\Console\\\\EnumMakeCommandTest\\:\\:dataForMakeCommand\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 @@ -1570,6 +1585,11 @@ parameters: count: 1 path: tests/Unit/WithTypeTests/SimpleMessage.php + - + message: "#^Access to an undefined property GraphQL\\\\Type\\\\Definition\\\\Type\\:\\:\\$config\\.$#" + count: 1 + path: tests/Unit/WithTypeTests/WrapperType.php + - message: "#^Method Rebing\\\\GraphQL\\\\Tests\\\\Unit\\\\WithTypeTests\\\\WrapperType\\:\\:getMessagesFields\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 From 9f97bf6d8dd52322c498a48aa82e5f79fe4eb3b5 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Sat, 7 Jan 2023 12:26:49 +0100 Subject: [PATCH 20/27] graphql-php-v15: composer fix-style --- tests/Support/Directives/ExampleDirective.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Support/Directives/ExampleDirective.php b/tests/Support/Directives/ExampleDirective.php index 3eee8d3e..938a2ea6 100644 --- a/tests/Support/Directives/ExampleDirective.php +++ b/tests/Support/Directives/ExampleDirective.php @@ -4,8 +4,8 @@ namespace Rebing\GraphQL\Tests\Support\Directives; use GraphQL\Language\DirectiveLocation; -use GraphQL\Type\Definition\Directive; use GraphQL\Type\Definition\Argument; +use GraphQL\Type\Definition\Directive; use GraphQL\Type\Definition\Type; class ExampleDirective extends Directive From 93632a28acdf063b878ba10bbd88acbcf2f7e3c1 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Sat, 7 Jan 2023 15:27:08 +0100 Subject: [PATCH 21/27] graphql-php-v15: update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27e64b61..2dd54c84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ CHANGELOG [Next release](https://github.com/rebing/graphql-laravel/compare/8.4.0...master) -------------- +### Added +- Upgrade to graphql-php 15 [\#953 / mfn](https://github.com/rebing/graphql-laravel/pull/953)\ + This includes possible breaking changes also outside of this package, see also https://github.com/webonyx/graphql-php/releases/tag/v15.0.0 + 2023-01-06, 8.4.0 ----------------- ### Added From cb78e3089cb43442ca6ab8cb0e4fd10c29e74436 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Sat, 7 Jan 2023 15:30:35 +0100 Subject: [PATCH 22/27] graphql-php-v15: add breaking change headline --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dd54c84..610a05ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG [Next release](https://github.com/rebing/graphql-laravel/compare/8.4.0...master) -------------- +## Breaking changes ### Added - Upgrade to graphql-php 15 [\#953 / mfn](https://github.com/rebing/graphql-laravel/pull/953)\ This includes possible breaking changes also outside of this package, see also https://github.com/webonyx/graphql-php/releases/tag/v15.0.0 From e4530ff7c1dc517c99fbb0aec7fb7a163d2582fe Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Sat, 7 Jan 2023 15:44:31 +0100 Subject: [PATCH 23/27] Remove optional support for non-lazy loading of types Lazy loading has been introduced in 2.0.0 (2019-08) and has been enabled by default in 8.0.0 (2021-11). From now on the type loader is always used when resolving types and the impact mostly means that you can't have types registered using an alias different from their name. As can be seen by th commit, this reduces complexity and maintenance overhead of the library. --- .github/workflows/tests.yml | 7 +--- CHANGELOG.md | 8 ++++ README.md | 41 ------------------- composer.json | 6 +-- config/config.php | 5 --- phpstan-baseline.neon | 17 +------- src/GraphQL.php | 14 ++----- tests/Support/Objects/ExampleType2.php | 26 ------------ .../Objects/ExamplesConfigAliasQuery.php | 40 ------------------ tests/TestCase.php | 8 ---- tests/Unit/GraphQLQueryTest.php | 30 -------------- ...ueriesAndTypesEachInTheirOwnSchemaTest.php | 5 --- tests/Unit/TypesInSchemas/TypesTest.php | 5 --- 13 files changed, 15 insertions(+), 197 deletions(-) delete mode 100644 tests/Support/Objects/ExampleType2.php delete mode 100644 tests/Support/Objects/ExamplesConfigAliasQuery.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bc548d43..a560e0d7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,7 +35,6 @@ jobs: matrix: php: ${{ fromJson(needs.supported-versions-matrix.outputs.version) }} laravel: [^6.0, ^8.0, ^9.0] - lazy_types: ['false', 'true'] exclude: - php: 7.4 laravel: ^9.0 @@ -45,7 +44,7 @@ jobs: laravel: ^6.0 - php: 8.2 laravel: ^6.0 - name: P=${{ matrix.php }} L=${{ matrix.laravel }} Lazy types=${{ matrix.lazy_types }} + name: P=${{ matrix.php }} L=${{ matrix.laravel }} runs-on: ubuntu-latest env: COMPOSER_NO_INTERACTION: 1 @@ -79,9 +78,5 @@ jobs: - run: composer update --prefer-dist --no-progress - - name: Enable lazy types conditionally - run: echo "TESTS_ENABLE_LAZYLOAD_TYPES=1" >> $GITHUB_ENV - if: matrix.lazy_types == 'true' - - name: Run tests run: composer tests diff --git a/CHANGELOG.md b/CHANGELOG.md index 610a05ab..25c0bf52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,14 @@ CHANGELOG - Upgrade to graphql-php 15 [\#953 / mfn](https://github.com/rebing/graphql-laravel/pull/953)\ This includes possible breaking changes also outside of this package, see also https://github.com/webonyx/graphql-php/releases/tag/v15.0.0 +### Removed +- Remove support for eager loading (=non-lazy loading) of types\ + Lazy loading has been introduced in 2.0.0 (2019-08) and has been made the + default since 8.0.0 (2021-11).\ + The practical impact is that types are always going to be resolved using a + type loader and therefore cannot use aliases anymore. Types and their type + name have to match. + 2023-01-06, 8.4.0 ----------------- ### Added diff --git a/README.md b/README.md index 74dbc8ef..3e8883cd 100644 --- a/README.md +++ b/README.md @@ -126,8 +126,6 @@ The default GraphiQL view makes use of the global `csrf_token()` helper function - [Upgrading from v1 to v2](#upgrading-from-v1-to-v2) - [Migrating from Folklore](#migrating-from-folklore) - [Performance considerations](#performance-considerations) - - [Lazy loading of types](#lazy-loading-of-types) - - [Example of aliasing **not** supported by lazy loading](#example-of-aliasing-not-supported-by-lazy-loading) - [Wrap Types](#wrap-types) - [GraphQL testing clients](#graphql-testing-clients) @@ -278,12 +276,6 @@ them, in addition to the global middleware. For example: 'default' => [ 'query' => [ ExampleQuery::class, - // It's possible to specify a name/alias with the key - // but this is discouraged as it prevents things - // like improving performance with e.g. `lazyload_types=true` - // It's recommended to specify just the class here and - // rely on the `'name'` attribute in the query / type. - 'someQuery' => AnotherExampleQuery::class, ], 'mutation' => [ ExampleMutation::class, @@ -447,18 +439,6 @@ Alternatively you can: GraphQL::addType(\App\GraphQL\Types\UserType::class); ``` -As with queries/mutations, you can use an alias name (though again this prevents -it from taking advantage of lazy type loading): -```php -'schemas' => [ - 'default' => [ - // ... - - 'types' => [ - 'Useralias' => App\GraphQL\Types\UserType::class, - ], -``` - Then you need to define a query that returns this type (or a list). You can also specify arguments that you can use in the resolve method. ```php namespace App\GraphQL\Queries; @@ -2696,9 +2676,6 @@ To prevent such scenarios, you can add the `UnusedVariablesMiddleware` to your - `batching`\ - 'enable'\ Whether to support GraphQL batching or not -- `lazyload_types`\ - The types will be loaded on demand. Enabled by default as it improves - performance. Cannot be used with type aliasing. - `error_formatter`\ This callable will be passed the Error object for each errors GraphQL catch. The method should return an array representing the error. @@ -2824,24 +2801,6 @@ The following is not a bullet-proof list but should serve as a guide. It's not a ## Performance considerations -### Lazy loading of types - -Lazy loading of types is a way of improving the start up performance. - -If you are declaring types using aliases, this is not supported and you need to -set `lazyload_types` set to `false`. - -#### Example of aliasing **not** supported by lazy loading - -I.e. you cannot have a query class `ExampleQuery` with the `$name` property -`example` but register it with a different one; this will **not** work: - -```php -'query' => [ - 'aliasedExample' => ExampleQuery::class, -], -``` - ### Wrap Types You can wrap types to add more information to the queries and mutations. Similar as the pagination is working you can do the same with your extra data that you want to inject ([see test examples](https://github.com/rebing/graphql-laravel/tree/master/tests/Unit/WithTypeTests)). For instance, in your query: diff --git a/composer.json b/composer.json index 582803f4..36e123f2 100644 --- a/composer.json +++ b/composer.json @@ -69,11 +69,7 @@ "phpstan-baseline": "phpstan analyse --memory-limit=512M --generate-baseline", "lint": "php-cs-fixer fix --diff --dry-run", "fix-style": "php-cs-fixer fix", - "tests": "phpunit --colors=always --verbose", - "tests-all": [ - "TESTS_ENABLE_LAZYLOAD_TYPES=0 phpunit --colors=always --verbose", - "TESTS_ENABLE_LAZYLOAD_TYPES=1 phpunit --colors=always --verbose" - ] + "tests": "phpunit --colors=always --verbose" }, "extra": { "branch-alias": { diff --git a/config/config.php b/config/config.php index 551e9775..03ddeddc 100644 --- a/config/config.php +++ b/config/config.php @@ -111,11 +111,6 @@ // \Rebing\GraphQL\Support\UploadType::class, ], - // The types will be loaded on demand. Default is to load all types on each request - // Can increase performance on schemes with many types - // Presupposes the config type key to match the type class name property - 'lazyload_types' => true, - // This callable will be passed the Error object for each errors GraphQL catch. // The method should return an array representing the error. // Typically: diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 2d9eef8c..a9836943 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -11,7 +11,7 @@ parameters: path: src/GraphQL.php - - message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Schema constructor expects array\\{query\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, mutation\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, subscription\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, types\\?\\: \\(callable\\(\\)\\: iterable\\\\)\\|iterable\\\\|null, directives\\?\\: array\\\\|null, typeLoader\\?\\: \\(callable\\(string\\)\\: \\(GraphQL\\\\Type\\\\Definition\\\\NamedType&GraphQL\\\\Type\\\\Definition\\\\Type\\)\\|null\\)\\|null, assumeValid\\?\\: bool\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\SchemaDefinitionNode\\|null, \\.\\.\\.\\}\\|GraphQL\\\\Type\\\\SchemaConfig, array\\{query\\: GraphQL\\\\Type\\\\Definition\\\\Type, mutation\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null, subscription\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null, directives\\: array\\, types\\: Closure\\(\\)\\: array\\, typeLoader\\: \\(Closure\\(mixed\\)\\: GraphQL\\\\Type\\\\Definition\\\\Type\\)\\|null\\} given\\.$#" + message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Schema constructor expects array\\{query\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, mutation\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, subscription\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, types\\?\\: \\(callable\\(\\)\\: iterable\\\\)\\|iterable\\\\|null, directives\\?\\: array\\\\|null, typeLoader\\?\\: \\(callable\\(string\\)\\: \\(GraphQL\\\\Type\\\\Definition\\\\NamedType&GraphQL\\\\Type\\\\Definition\\\\Type\\)\\|null\\)\\|null, assumeValid\\?\\: bool\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\SchemaDefinitionNode\\|null, \\.\\.\\.\\}\\|GraphQL\\\\Type\\\\SchemaConfig, array\\{query\\: GraphQL\\\\Type\\\\Definition\\\\Type, mutation\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null, subscription\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null, directives\\: array\\, types\\: Closure\\(\\)\\: array\\, typeLoader\\: Closure\\(mixed\\)\\: GraphQL\\\\Type\\\\Definition\\\\Type\\} given\\.$#" count: 1 path: src/GraphQL.php @@ -940,21 +940,6 @@ parameters: count: 1 path: tests/Support/Objects/ExamplesAuthorizeQuery.php - - - message: "#^Method Rebing\\\\GraphQL\\\\Tests\\\\Support\\\\Objects\\\\ExamplesConfigAliasQuery\\:\\:resolve\\(\\) has no return type specified\\.$#" - count: 1 - path: tests/Support/Objects/ExamplesConfigAliasQuery.php - - - - message: "#^Method Rebing\\\\GraphQL\\\\Tests\\\\Support\\\\Objects\\\\ExamplesConfigAliasQuery\\:\\:resolve\\(\\) has parameter \\$args with no type specified\\.$#" - count: 1 - path: tests/Support/Objects/ExamplesConfigAliasQuery.php - - - - message: "#^Method Rebing\\\\GraphQL\\\\Tests\\\\Support\\\\Objects\\\\ExamplesConfigAliasQuery\\:\\:resolve\\(\\) has parameter \\$root with no type specified\\.$#" - count: 1 - path: tests/Support/Objects/ExamplesConfigAliasQuery.php - - message: "#^Method Rebing\\\\GraphQL\\\\Tests\\\\Support\\\\Objects\\\\ExamplesFilteredQuery\\:\\:resolve\\(\\) has parameter \\$args with no type specified\\.$#" count: 1 diff --git a/src/GraphQL.php b/src/GraphQL.php index 49de5cd2..0969a0a8 100644 --- a/src/GraphQL.php +++ b/src/GraphQL.php @@ -243,11 +243,7 @@ public function getType(string $name, bool $fresh = false): Type } if (!isset($this->types[$name])) { - $error = "Type $name not found."; - - if ($this->config->get('graphql.lazyload_types', true)) { - $error .= "\nCheck that the config array key for the type matches the name attribute in the type's class.\nIt is required when 'lazyload_types' is enabled"; - } + $error = "Type $name not found. Check that the config array key for the type matches the name attribute in the type's class."; throw new TypeNotFound($error); } @@ -402,11 +398,9 @@ public function buildSchemaFromConfig(array $schemaConfig): Schema return $types; }, - 'typeLoader' => $this->config->get('graphql.lazyload_types', true) - ? function ($name) { - return $this->type($name); - } - : null, + 'typeLoader' => function ($name) { + return $this->type($name); + }, ]); } diff --git a/tests/Support/Objects/ExampleType2.php b/tests/Support/Objects/ExampleType2.php deleted file mode 100644 index f42e7d55..00000000 --- a/tests/Support/Objects/ExampleType2.php +++ /dev/null @@ -1,26 +0,0 @@ - 'Example2', - 'description' => 'An example', - ]; - - public function fields(): array - { - return [ - 'test' => [ - 'type' => Type::string(), - 'description' => 'A test field', - ], - 'test_validation' => ExampleValidationField::class, - ]; - } -} diff --git a/tests/Support/Objects/ExamplesConfigAliasQuery.php b/tests/Support/Objects/ExamplesConfigAliasQuery.php deleted file mode 100644 index bd159e48..00000000 --- a/tests/Support/Objects/ExamplesConfigAliasQuery.php +++ /dev/null @@ -1,40 +0,0 @@ - 'examplesAlias', - ]; - - public function type(): Type - { - return Type::listOf(GraphQL::type('ExampleConfigAlias')); - } - - public function args(): array - { - return [ - 'index' => ['name' => 'index', 'type' => Type::int()], - ]; - } - - public function resolve($root, $args) - { - $data = include __DIR__ . '/data.php'; - - if (isset($args['index'])) { - return [ - $data[$args['index']], - ]; - } - - return $data; - } -} diff --git a/tests/TestCase.php b/tests/TestCase.php index 453d9e35..5a0ae632 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -18,13 +18,11 @@ use Rebing\GraphQL\Tests\Support\Objects\ExamplesAuthorizeMessageQuery; use Rebing\GraphQL\Tests\Support\Objects\ExamplesAuthorizeQuery; use Rebing\GraphQL\Tests\Support\Objects\ExampleSchema; -use Rebing\GraphQL\Tests\Support\Objects\ExamplesConfigAliasQuery; use Rebing\GraphQL\Tests\Support\Objects\ExamplesFilteredQuery; use Rebing\GraphQL\Tests\Support\Objects\ExamplesMiddlewareQuery; use Rebing\GraphQL\Tests\Support\Objects\ExamplesPaginationQuery; use Rebing\GraphQL\Tests\Support\Objects\ExamplesQuery; use Rebing\GraphQL\Tests\Support\Objects\ExampleType; -use Rebing\GraphQL\Tests\Support\Objects\ExampleType2; use Rebing\GraphQL\Tests\Support\Objects\UpdateExampleMutation; use Symfony\Component\Console\Tester\CommandTester; @@ -43,10 +41,6 @@ protected function setUp(): void protected function getEnvironmentSetUp($app): void { - if ('0' === env('TESTS_ENABLE_LAZYLOAD_TYPES')) { - $app['config']->set('graphql.lazyload_types', false); - } - $app['config']->set('graphql.schemas.default', [ 'query' => [ 'examples' => ExamplesQuery::class, @@ -55,7 +49,6 @@ protected function getEnvironmentSetUp($app): void 'examplesMiddleware' => ExamplesMiddlewareQuery::class, 'examplesPagination' => ExamplesPaginationQuery::class, 'examplesFiltered' => ExamplesFilteredQuery::class, - 'examplesConfigAlias' => ExamplesConfigAliasQuery::class, ], 'mutation' => [ 'updateExample' => UpdateExampleMutation::class, @@ -75,7 +68,6 @@ protected function getEnvironmentSetUp($app): void $app['config']->set('graphql.types', [ 'Example' => ExampleType::class, - 'ExampleConfigAlias' => ExampleType2::class, 'ExampleFilterInput' => ExampleFilterInputType::class, ]); diff --git a/tests/Unit/GraphQLQueryTest.php b/tests/Unit/GraphQLQueryTest.php index a0731316..209ceec1 100644 --- a/tests/Unit/GraphQLQueryTest.php +++ b/tests/Unit/GraphQLQueryTest.php @@ -20,36 +20,6 @@ public function testQueryAndReturnResult(): void ]); } - public function testConfigKeysIsDifferentFromTypeClassNameQuery(): void - { - if (app('config')->get('graphql.lazyload_types')) { - self::markTestSkipped('Skipping test when lazyload_types=true'); - } - - $result = GraphQL::queryAndReturnResult($this->queries['examplesWithConfigAlias']); - - self::assertObjectHasAttribute('data', $result); - - self::assertEquals($result->data, [ - 'examplesConfigAlias' => $this->data, - ]); - } - - public function testConfigKeyIsDifferentFromTypeClassNameNotSupportedInLazyLoadingOfTypes(): void - { - if (false === app('config')->get('graphql.lazyload_types')) { - self::markTestSkipped('Skipping test when lazyload_types=false'); - } - - $result = GraphQL::queryAndReturnResult($this->queries['examplesWithConfigAlias']); - self::assertObjectHasAttribute('errors', $result); - - $expected = "Type Example2 not found. -Check that the config array key for the type matches the name attribute in the type's class. -It is required when 'lazyload_types' is enabled"; - self::assertSame($expected, $result->errors[0]->getMessage()); - } - public function testQuery(): void { $resultArray = GraphQL::query($this->queries['examples']); diff --git a/tests/Unit/TypesInSchemas/QueriesAndTypesEachInTheirOwnSchemaTest.php b/tests/Unit/TypesInSchemas/QueriesAndTypesEachInTheirOwnSchemaTest.php index d9dbd886..2c1d937c 100644 --- a/tests/Unit/TypesInSchemas/QueriesAndTypesEachInTheirOwnSchemaTest.php +++ b/tests/Unit/TypesInSchemas/QueriesAndTypesEachInTheirOwnSchemaTest.php @@ -25,11 +25,6 @@ protected function getEnvironmentSetUp($app): void SchemaTwo\Type::class, ], ]); - - // To still properly support dual tests, we thus have to add this - if ('0' === env('TESTS_ENABLE_LAZYLOAD_TYPES')) { - $app['config']->set('graphql.lazyload_types', false); - } } public function testQueriesAndTypesEachInTheirOwnSchema(): void diff --git a/tests/Unit/TypesInSchemas/TypesTest.php b/tests/Unit/TypesInSchemas/TypesTest.php index ce4a8c03..5a372fca 100644 --- a/tests/Unit/TypesInSchemas/TypesTest.php +++ b/tests/Unit/TypesInSchemas/TypesTest.php @@ -11,11 +11,6 @@ class TypesTest extends TestCase protected function getEnvironmentSetUp($app): void { // Note: deliberately not calling parent to start with a clean config - - // To still properly support dual tests, we thus have to add this - if ('0' === env('TESTS_ENABLE_LAZYLOAD_TYPES')) { - $app['config']->set('graphql.lazyload_types', false); - } } public function testQueryAndTypeInDefaultSchema(): void From 0cd9ceb5da4df42a46e783e19b5fac28cfa70c0b Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Fri, 13 Jan 2023 11:17:30 +0100 Subject: [PATCH 24/27] graphql-php-v15: switch to laragraph/utils release also supporting graphql-php 15 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5eef1ddb..1a0a45ae 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "ext-json": "*", "illuminate/contracts": "^6.0|^8.0|^9.0", "illuminate/support": "^6.0|^8.0|^9.0", - "laragraph/utils": "dev-graphql-php-15", + "laragraph/utils": "^1.5", "thecodingmachine/safe": "^1.1|^2.4", "webonyx/graphql-php": "^15" }, From 503a96629279d2efdf5c2608f3d43e92b2865173 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Fri, 13 Jan 2023 12:04:44 +0100 Subject: [PATCH 25/27] graphql-php-v15: include a more detailed BC changelog --- CHANGELOG.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44295850..fc1c5a2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,35 @@ CHANGELOG ## Breaking changes ### Added - Upgrade to graphql-php 15 [\#953 / mfn](https://github.com/rebing/graphql-laravel/pull/953)\ - This includes possible breaking changes also outside of this package, see also https://github.com/webonyx/graphql-php/releases/tag/v15.0.0 + This includes possible breaking changes also outside of this package, see also https://github.com/webonyx/graphql-php/releases/tag/v15.0.0 \ + Known breaking changes: + - non-standard error related data keys are not included directly in + `errors.*.` any more, but have been moved to + `errors.*.extensions.`.\ + Also new keys may appear here from upstream. + - The `errors.*.extensions.category` has been removed upstream, but we try to + keep it alive with the interface + `\Rebing\GraphQL\Error\ProvidesErrorCategory` as it can be a useful + discriminator on the client side in certain cases. But only the cases from + _this_ library are preserved, e.g. categories like `request`, `graphql` or + `internal` are gone. + - The `\Rebing\GraphQL\Support\OperationParams` has added required types due to + its base class changes: + - Old: `public function getOriginalInput($key)`\ + new: `public function getOriginalInput(string $key)` + - Old: `public function isReadOnly()`\ + new: `public function isReadOnly(): bool` + + Some BC may happen also if you extended code originating in graphql-php, + some examples: + - if you implement custom types, you now have to use property types for e.g. + `$name` or `$description` + - If you used any `\GraphQL\Validator\DocumentValidator` in your code + directly, you now need use FQCN to reference them and not the shortened + string names. + - `->getWrappedType(true)` was replaced with `->getInnermostType()` + - the class `\GraphQL\Type\Definition\FieldArgument` has been renamed to + `\GraphQL\Type\Definition\Argument` ### Removed - Remove support for eager loading (=non-lazy loading) of types\ From 5e09d3401af6e56489d3ec63248578eb6c44eaa2 Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Sun, 5 Mar 2023 08:11:48 +0100 Subject: [PATCH 26/27] graphql-php-v15: adapt phpstan after merge with master --- phpstan-baseline.neon | 39 ++++++++++++--------------------------- phpstan.neon.dist | 2 +- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 8f351a33..6d26efc9 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -6,22 +6,22 @@ parameters: path: src/GraphQL.php - - message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Definition\\\\ObjectType constructor expects array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, resolveField\\?\\: \\(callable\\(mixed, array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|null, fields\\: \\(callable\\(\\)\\: iterable\\)\\|iterable, interfaces\\?\\: \\(callable\\(\\)\\: iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>\\)\\|iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>, isTypeOf\\?\\: \\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: bool\\|GraphQL\\\\Deferred\\|null\\)\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\ObjectTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}, non\\-empty\\-array\\\\|\\(ArrayAccess&Rebing\\\\GraphQL\\\\Support\\\\Field\\)\\>\\|string\\> given\\.$#" + message: "#^Instanceof between Error and Error will always evaluate to true\\.$#" count: 1 path: src/GraphQL.php - - message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Schema constructor expects array\\{query\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, mutation\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, subscription\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, types\\?\\: \\(callable\\(\\)\\: iterable\\\\)\\|iterable\\\\|null, directives\\?\\: array\\\\|null, typeLoader\\?\\: \\(callable\\(string\\)\\: \\(GraphQL\\\\Type\\\\Definition\\\\NamedType&GraphQL\\\\Type\\\\Definition\\\\Type\\)\\|null\\)\\|null, assumeValid\\?\\: bool\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\SchemaDefinitionNode\\|null, \\.\\.\\.\\}\\|GraphQL\\\\Type\\\\SchemaConfig, array\\{query\\: GraphQL\\\\Type\\\\Definition\\\\Type, mutation\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null, subscription\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null, directives\\: array\\, types\\: Closure\\(\\)\\: array\\, typeLoader\\: Closure\\(mixed\\)\\: GraphQL\\\\Type\\\\Definition\\\\Type\\} given\\.$#" + message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Definition\\\\ObjectType constructor expects array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, resolveField\\?\\: \\(callable\\(mixed, array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|null, fields\\: \\(callable\\(\\)\\: iterable\\)\\|iterable, interfaces\\?\\: \\(callable\\(\\)\\: iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>\\)\\|iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>, isTypeOf\\?\\: \\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: bool\\|GraphQL\\\\Deferred\\|null\\)\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\ObjectTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}, non\\-empty\\-array\\\\|\\(ArrayAccess&Rebing\\\\GraphQL\\\\Support\\\\Field\\)\\>\\|string\\> given\\.$#" count: 1 path: src/GraphQL.php - - message: "#^Property GraphQL\\\\Type\\\\Definition\\\\ObjectType\\:\\:\\$config \\(array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, resolveField\\?\\: \\(callable\\(mixed, array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|null, fields\\: \\(callable\\(\\)\\: iterable\\)\\|iterable, interfaces\\?\\: \\(callable\\(\\)\\: iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>\\)\\|iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>, isTypeOf\\?\\: \\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: bool\\|GraphQL\\\\Deferred\\|null\\)\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\ObjectTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}\\) does not accept non\\-empty\\-array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|\\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: bool\\|GraphQL\\\\Deferred\\|null\\)\\|GraphQL\\\\Language\\\\AST\\\\ObjectTypeDefinitionNode\\|iterable\\|string\\|null\\>\\.$#" + message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Schema constructor expects array\\{query\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, mutation\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, subscription\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, types\\?\\: \\(callable\\(\\)\\: iterable\\\\)\\|iterable\\\\|null, directives\\?\\: array\\\\|null, typeLoader\\?\\: \\(callable\\(string\\)\\: \\(GraphQL\\\\Type\\\\Definition\\\\NamedType&GraphQL\\\\Type\\\\Definition\\\\Type\\)\\|null\\)\\|null, assumeValid\\?\\: bool\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\SchemaDefinitionNode\\|null, \\.\\.\\.\\}\\|GraphQL\\\\Type\\\\SchemaConfig, array\\{query\\: GraphQL\\\\Type\\\\Definition\\\\Type, mutation\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null, subscription\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null, directives\\: array\\, types\\: Closure\\(\\)\\: list\\, typeLoader\\: Closure\\(mixed\\)\\: GraphQL\\\\Type\\\\Definition\\\\Type\\} given\\.$#" count: 1 path: src/GraphQL.php - - message: "#^Instanceof between Error and Error will always evaluate to true\\.$#" + message: "#^Property GraphQL\\\\Type\\\\Definition\\\\ObjectType\\:\\:\\$config \\(array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, resolveField\\?\\: \\(callable\\(mixed, array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|null, fields\\: \\(callable\\(\\)\\: iterable\\)\\|iterable, interfaces\\?\\: \\(callable\\(\\)\\: iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>\\)\\|iterable\\<\\(callable\\(\\)\\: GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\)\\|GraphQL\\\\Type\\\\Definition\\\\InterfaceType\\>, isTypeOf\\?\\: \\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: bool\\|GraphQL\\\\Deferred\\|null\\)\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\ObjectTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}\\) does not accept non\\-empty\\-array\\, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: mixed\\)\\|\\(callable\\(mixed, mixed, GraphQL\\\\Type\\\\Definition\\\\ResolveInfo\\)\\: bool\\|GraphQL\\\\Deferred\\|null\\)\\|GraphQL\\\\Language\\\\AST\\\\ObjectTypeDefinitionNode\\|iterable\\|string\\|null\\>\\.$#" count: 1 path: src/GraphQL.php @@ -91,7 +91,7 @@ parameters: path: src/Support/AliasArguments/ArrayKeyChange.php - - message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Definition\\\\EnumType constructor expects array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, values\\: \\(callable\\(\\)\\: iterable\\\\|iterable\\\\)\\|iterable\\, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\EnumTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}, array\\ given\\.$#" + message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Definition\\\\EnumType constructor expects array\\{name\\?\\: string\\|null, description\\?\\: string\\|null, values\\: \\(callable\\(\\)\\: iterable\\\\)\\|iterable\\, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\EnumTypeDefinitionNode\\|null, extensionASTNodes\\?\\: array\\\\|null\\}, array\\ given\\.$#" count: 1 path: src/Support/EnumType.php @@ -210,11 +210,6 @@ parameters: count: 1 path: src/Support/Middleware.php - - - message: "#^Access to an undefined property GraphQL\\\\Type\\\\Definition\\\\Type\\:\\:\\$config\\.$#" - count: 1 - path: src/Support/PaginationType.php - - message: "#^Anonymous function never returns null so it can be removed from the return type\\.$#" count: 2 @@ -232,11 +227,6 @@ parameters: - message: "#^Access to an undefined property GraphQL\\\\Type\\\\Definition\\\\Type\\:\\:\\$config\\.$#" - count: 6 - path: src/Support/SelectFields.php - - - - message: "#^Instanceof between \\*NEVER\\* and 'Jenssegers\\\\\\\\Mongodb…' will always evaluate to false\\.$#" count: 1 path: src/Support/SelectFields.php @@ -365,11 +355,6 @@ parameters: count: 1 path: src/Support/SelectFields.php - - - message: "#^Access to an undefined property GraphQL\\\\Type\\\\Definition\\\\Type\\:\\:\\$config\\.$#" - count: 1 - path: src/Support/SimplePaginationType.php - - message: "#^Anonymous function never returns null so it can be removed from the return type\\.$#" count: 2 @@ -1401,8 +1386,13 @@ parameters: path: tests/Unit/EngineErrorInResolverTests/QueryWithEngineErrorInCodeQuery.php - - message: "#^Access to an undefined property GraphQL\\\\Type\\\\Definition\\\\Type\\:\\:\\$name\\.$#" - count: 5 + message: "#^Parameter \\#2 \\$visitor of static method GraphQL\\\\Language\\\\Visitor\\:\\:visit\\(\\) expects array\\\\|\\(callable\\(GraphQL\\\\Language\\\\AST\\\\Node\\)\\: GraphQL\\\\Language\\\\VisitorOperation\\|void\\|false\\|null\\)\\>, array\\{VariableDefinition\\: Closure\\(mixed, mixed, mixed, mixed, mixed\\)\\: mixed\\} given\\.$#" + count: 1 + path: tests/Unit/ExecutionMiddlewareTest/ChangeQueryArgTypeMiddleware.php + + - + message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertIsArray\\(\\) with non\\-empty\\-array will always evaluate to true\\.$#" + count: 1 path: tests/Unit/GraphQLTest.php - @@ -1565,11 +1555,6 @@ parameters: count: 1 path: tests/Unit/WithTypeTests/SimpleMessage.php - - - message: "#^Access to an undefined property GraphQL\\\\Type\\\\Definition\\\\Type\\:\\:\\$config\\.$#" - count: 1 - path: tests/Unit/WithTypeTests/WrapperType.php - - message: "#^Method Rebing\\\\GraphQL\\\\Tests\\\\Unit\\\\WithTypeTests\\\\WrapperType\\:\\:getMessagesFields\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 3a2fa228..e3d78834 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -34,7 +34,7 @@ parameters: message: '/Cannot call method make\(\) on Illuminate\\Foundation\\Application\|null\./' - path: tests/* - message: "/Offset 'config' might not exist on Illuminate.*Application\\|null./" + message: "/Offset 'config' might not exist/" - path: tests/* message: '/Parameter #1 \$type of static method GraphQL\\Type\\Definition\\Type::nonNull\(\) expects .*, GraphQL\\Type\\Definition\\Type given./' reportUnmatchedIgnoredErrors: true From 39c5ca9a95ab9022268037d18988b25787c9de0b Mon Sep 17 00:00:00 2001 From: Markus Podar Date: Sun, 5 Mar 2023 14:56:19 +0100 Subject: [PATCH 27/27] graphql-php-v15: also resolve our top level types --- CHANGELOG.md | 4 ++++ phpstan-baseline.neon | 2 +- src/GraphQL.php | 20 ++++++++++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 389e4bef..f2b2b8c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,10 @@ CHANGELOG type loader and therefore cannot use aliases anymore. Types and their type name have to match. +## Changed +- The type resolver is now able to resolve the top level types 'Query', + 'Mutation' and 'Subscription' + 2023-02-18, 8.6.0 ----------------- ### Added diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 6d26efc9..752b4483 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -16,7 +16,7 @@ parameters: path: src/GraphQL.php - - message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Schema constructor expects array\\{query\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, mutation\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, subscription\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, types\\?\\: \\(callable\\(\\)\\: iterable\\\\)\\|iterable\\\\|null, directives\\?\\: array\\\\|null, typeLoader\\?\\: \\(callable\\(string\\)\\: \\(GraphQL\\\\Type\\\\Definition\\\\NamedType&GraphQL\\\\Type\\\\Definition\\\\Type\\)\\|null\\)\\|null, assumeValid\\?\\: bool\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\SchemaDefinitionNode\\|null, \\.\\.\\.\\}\\|GraphQL\\\\Type\\\\SchemaConfig, array\\{query\\: GraphQL\\\\Type\\\\Definition\\\\Type, mutation\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null, subscription\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null, directives\\: array\\, types\\: Closure\\(\\)\\: list\\, typeLoader\\: Closure\\(mixed\\)\\: GraphQL\\\\Type\\\\Definition\\\\Type\\} given\\.$#" + message: "#^Parameter \\#1 \\$config of class GraphQL\\\\Type\\\\Schema constructor expects array\\{query\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, mutation\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, subscription\\?\\: GraphQL\\\\Type\\\\Definition\\\\ObjectType\\|null, types\\?\\: \\(callable\\(\\)\\: iterable\\\\)\\|iterable\\\\|null, directives\\?\\: array\\\\|null, typeLoader\\?\\: \\(callable\\(string\\)\\: \\(GraphQL\\\\Type\\\\Definition\\\\NamedType&GraphQL\\\\Type\\\\Definition\\\\Type\\)\\|null\\)\\|null, assumeValid\\?\\: bool\\|null, astNode\\?\\: GraphQL\\\\Language\\\\AST\\\\SchemaDefinitionNode\\|null, \\.\\.\\.\\}\\|GraphQL\\\\Type\\\\SchemaConfig, array\\{query\\: GraphQL\\\\Type\\\\Definition\\\\Type, mutation\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null, subscription\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null, directives\\: array\\, types\\: Closure\\(\\)\\: list\\, typeLoader\\: Closure\\(mixed\\)\\: GraphQL\\\\Type\\\\Definition\\\\Type\\|null\\} given\\.$#" count: 1 path: src/GraphQL.php diff --git a/src/GraphQL.php b/src/GraphQL.php index 0969a0a8..9b04a93a 100644 --- a/src/GraphQL.php +++ b/src/GraphQL.php @@ -398,8 +398,24 @@ public function buildSchemaFromConfig(array $schemaConfig): Schema return $types; }, - 'typeLoader' => function ($name) { - return $this->type($name); + 'typeLoader' => function ($name) use ( + $query, + $mutation, + $subscription + ) { + switch ($name) { + case 'Query': + return $query; + + case 'Mutation': + return $mutation; + + case 'Subscription': + return $subscription; + + default: + return $this->type($name); + } }, ]); }