Skip to content

Commit f62dadf

Browse files
authored
Merge pull request #2359 from antograssiot/master
Merge 2.3 into master
2 parents 822c78c + 4575a5e commit f62dadf

20 files changed

+97
-70
lines changed

composer.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
],
1515
"require": {
1616
"php": ">=7.1",
17-
1817
"doctrine/inflector": "^1.0",
1918
"psr/cache": "^1.0",
2019
"psr/container": "^1.0",
@@ -70,7 +69,7 @@
7069
"symfony/validator": "^3.3 || ^4.0",
7170
"symfony/web-profiler-bundle": "^3.3 || ^4.0",
7271
"symfony/yaml": "^3.3 || ^4.0",
73-
"webonyx/graphql-php": ">=0.12 <1.0"
72+
"webonyx/graphql-php": ">=0.13 <1.0"
7473
},
7574
"conflict": {
7675
"symfony/dependency-injection": "<3.4"

features/graphql/introspection.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,6 @@ Feature: GraphQL introspection support
310310
And the JSON node "data.typeCreatePayload.fields[2].name" should be equal to "baz"
311311
And the JSON node "data.typeCreatePayload.fields[3].name" should be equal to "clientMutationId"
312312

313-
@dropSchema
314313
Scenario: Retrieve an item through a GraphQL query
315314
Given there are 4 dummy objects with relatedDummy
316315
When I send the following GraphQL request:

features/graphql/mutation.feature

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ Feature: GraphQL mutation support
122122
And the JSON node "data.deleteFoo.id" should be equal to "/foos/1"
123123
And the JSON node "data.deleteFoo.clientMutationId" should be equal to "anotherId"
124124

125-
@dropSchema
126125
Scenario: Delete an item with composite identifiers through a mutation
127126
Given there are Composite identifier objects
128127
When I send the following GraphQL request:
@@ -250,7 +249,6 @@ Feature: GraphQL mutation support
250249
And the JSON node "data.createDummyGroup.baz" should be null
251250
And the JSON node "data.createDummyGroup.clientMutationId" should be equal to "myId"
252251

253-
@dropSchema
254252
Scenario: Trigger a validation error
255253
When I send the following GraphQL request:
256254
"""

features/graphql/query.feature

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,6 @@ Feature: GraphQL query support
138138
And the header "Content-Type" should be equal to "application/json"
139139
And the JSON node "data.dummy._id" should be equal to "1"
140140

141-
@dropSchema
142141
Scenario: Retrieve an nonexistent item through a GraphQL query
143142
When I send the following GraphQL request:
144143
"""
@@ -152,3 +151,63 @@ Feature: GraphQL query support
152151
And the response should be in JSON
153152
And the header "Content-Type" should be equal to "application/json"
154153
And the JSON node "data.dummy" should be null
154+
155+
Scenario: Retrieve an nonexistent IRI through a GraphQL query
156+
When I send the following GraphQL request:
157+
"""
158+
{
159+
foo(id: "/foo/1") {
160+
name
161+
}
162+
}
163+
"""
164+
Then the response status code should be 200
165+
And the response should be in JSON
166+
And the header "Content-Type" should be equal to "application/json"
167+
And the JSON node "errors[0].debugMessage" should be equal to 'No route matches "/foo/1".'
168+
And the JSON should be valid according to this schema:
169+
"""
170+
{
171+
"type": "object",
172+
"properties": {
173+
"errors": {
174+
"type": "array",
175+
"items": {
176+
"type": "object",
177+
"properties": {
178+
"debugMessage": {"type": "string"},
179+
"message": {"type": "string"},
180+
"extensions": {"type": "object"},
181+
"locations": {"type": "array"},
182+
"path": {"type": "array"},
183+
"trace": {
184+
"type": "array",
185+
"items": {
186+
"type": "object",
187+
"properties": {
188+
"file": {"type": "string"},
189+
"line": {"type": "integer"},
190+
"call": {"type": ["string", "null"]},
191+
"function": {"type": ["string", "null"]}
192+
},
193+
"additionalProperties": false
194+
},
195+
"minItems": 1
196+
}
197+
},
198+
"required": [
199+
"debugMessage",
200+
"message",
201+
"extensions",
202+
"locations",
203+
"path",
204+
"trace"
205+
],
206+
"additionalProperties": false
207+
},
208+
"minItems": 1,
209+
"maxItems": 1
210+
}
211+
}
212+
}
213+
"""

features/hal/collection.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,6 @@ Feature: HAL Collections support
808808
}
809809
"""
810810

811-
@dropSchema
812811
Scenario: Allow passing 0 to `itemsPerPage`
813812
When I add "Accept" header equal to "application/hal+json"
814813
And I send a "GET" request to "/dummies?itemsPerPage=0"

features/hal/max_depth.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ Feature: Max depth handling
9191
}
9292
"""
9393

94-
@dropSchema
9594
Scenario: Add a 2nd level of descendants when eager fetching is disabled
9695
Given there is a max depth dummy with 1 level of descendants
9796
When I add "Accept" header equal to "application/hal+json"

features/jsonld/max_depth.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ Feature: Max depth handling
3535
}
3636
"""
3737

38-
@dropSchema
3938
Scenario: Add a 2nd level of descendants
4039
When I add "Content-Type" header equal to "application/ld+json"
4140
And I send a "PUT" request to "max_depth_eager_dummies/1" with body:

features/main/exposed_state.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ Feature: Expose persisted object state
2525
}
2626
"""
2727

28-
@dropSchema
2928
Scenario: Update a resource with truncable value value should return the correct object state
3029
When I add "Content-Type" header equal to "application/ld+json"
3130
And I send a "PUT" request to "/truncated_dummies/1" with body:

features/main/operation.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ Feature: Operation support
3838
"""
3939

4040
@createSchema
41-
@dropSchema
4241
Scenario: Select a resource and it's embedded data
4342
Given there are 1 embedded dummy objects
4443
When I send a "GET" request to "/embedded_dummies_groups/1"

features/main/relation.feature

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,6 @@ Feature: Relations support
555555
}
556556
"""
557557

558-
@dropSchema
559558
Scenario: Passing an invalid IRI to a relation
560559
When I add "Content-Type" header equal to "application/ld+json"
561560
And I send a "POST" request to "/relation_embedders" with body:
@@ -569,7 +568,6 @@ Feature: Relations support
569568
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
570569
And the JSON node "hydra:description" should contain "Invalid value provided (invalid IRI?)."
571570

572-
@dropSchema
573571
Scenario: Passing an invalid type to a relation
574572
When I add "Content-Type" header equal to "application/ld+json"
575573
And I send a "POST" request to "/relation_embedders" with body:

features/main/subresource.feature

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,6 @@ Feature: Subresource support
407407
}
408408
"""
409409

410-
@dropSchema
411410
Scenario: Recursive resource
412411
When I send a "GET" request to "/dummy_products/2"
413412
And the response status code should be 200

features/main/validation.feature

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ Feature: Using validations groups
33
I need to be able to use validation groups
44

55
@createSchema
6-
@dropSchema
76
Scenario: Create a resource
87
When I add "Content-Type" header equal to "application/ld+json"
98
And I send a "POST" request to "/dummy_validation" with body:
@@ -17,7 +16,6 @@ Feature: Using validations groups
1716
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
1817

1918
@createSchema
20-
@dropSchema
2119
Scenario: Create a resource with validation
2220
When I add "Content-Type" header equal to "application/ld+json"
2321
And I send a "POST" request to "/dummy_validation/validation_groups" with body:
@@ -46,7 +44,6 @@ Feature: Using validations groups
4644
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
4745

4846
@createSchema
49-
@dropSchema
5047
Scenario: Create a resource with validation group sequence
5148
When I add "Content-Type" header equal to "application/ld+json"
5249
And I send a "POST" request to "/dummy_validation/validation_sequence" with body:

phpstan.neon

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ parameters:
2020
- '#Parameter \#1 \$function of function call_user_func expects callable, .+ given\.#'
2121
- '#Parameter \#1 \$classes of class ApiPlatform\\Core\\Metadata\\Resource\\ResourceNameCollection constructor expects array<string>, array<int, int\|string> given\.#'
2222
- '#Method ApiPlatform\\Core\\Util\\RequestParser::parseRequestParams\(\) should return array but returns array\|false\.#'
23+
- '#Parameter \#1 \$vars of class GraphQL\\Language\\AST\\(IntValue|ObjectField|ObjectValue|BooleanValue|ListValue|StringValue)Node constructor expects array<GraphQL\\Language\\AST\\Location\|GraphQL\\Language\\AST\\NameNode\|GraphQL\\Language\\AST\\NodeList\|GraphQL\\Language\\AST\\SelectionSetNode\|string\|null>, array<string, .+> given\.#'
24+
- '#Parameter \#1 \$defaultContext of class Symfony\\Component\\Serializer\\Encoder\\Json(De|En)code constructor expects array, (int|true) given\.#'
2325
# Temporary fix while the PHPStan extension for Prophecy isn't compatible with 0.10
2426
- '#Parameter .* expects .*, .*object.* given\.#'
2527
- '#Parameter \#[0-9] \$filterLocator of class ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Extension\\FilterExtension constructor expects ApiPlatform\\Core\\Api\\FilterCollection|Psr\\Container\\ContainerInterface(\|null)?, ArrayObject given\.#'
@@ -38,9 +40,3 @@ parameters:
3840
- '#Method ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Filter\\FilterInterface::apply\(\) invoked with 5 parameters, 3-4 required\.#'
3941
- '#Method ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Filter\\OrderFilter::filterProperty\(\) invoked with 7 parameters, 5-6 required\.#'
4042
- '#Method ApiPlatform\\Core\\DataProvider\\CollectionDataProviderInterface::getCollection\(\) invoked with 3 parameters, 1-2 required\.#'
41-
42-
# Expected, due to feature detection, to adapt when Symfony 4.2 will be released
43-
- '#Class Symfony\\Component\\Serializer\\NameConverter\\AdvancedNameConverterInterface not found\.#'
44-
- '#Method Symfony\\Component\\Serializer\\Normalizer\\AbstractObjectNormalizer::__construct\(\) invoked with 6 parameters, 0-4 required\.#'
45-
- '#Parameter \#1 \$bitmask of class Symfony\\Component\\Serializer\\Encoder\\JsonEncode constructor expects int, array<string, int> given\.#'
46-
- '#Parameter \#1 \$associative of class Symfony\\Component\\Serializer\\Encoder\\JsonDecode constructor expects bool, array<string, true> given\.#'

src/GraphQl/Action/EntrypointAction.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
use ApiPlatform\Core\GraphQl\ExecutorInterface;
1717
use ApiPlatform\Core\GraphQl\Type\SchemaBuilderInterface;
18+
use GraphQL\Error\Debug;
1819
use GraphQL\Error\Error;
1920
use GraphQL\Executor\ExecutionResult;
2021
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -40,7 +41,7 @@ public function __construct(SchemaBuilderInterface $schemaBuilder, ExecutorInter
4041
$this->schemaBuilder = $schemaBuilder;
4142
$this->executor = $executor;
4243
$this->twig = $twig;
43-
$this->debug = $debug;
44+
$this->debug = $debug ? Debug::INCLUDE_DEBUG_MESSAGE | Debug::INCLUDE_TRACE : false;
4445
$this->graphiqlEnabled = $graphiqlEnabled;
4546
$this->title = $title;
4647
}
@@ -64,7 +65,7 @@ public function __invoke(Request $request): Response
6465
try {
6566
$executionResult = $this->executor->executeQuery($this->schemaBuilder->getSchema(), $query, null, null, $variables, $operation);
6667
} catch (\Exception $e) {
67-
$executionResult = new ExecutionResult(null, [$e] + ($this->debug ? ['trace' => $e->getTraceAsString()] : []));
68+
$executionResult = new ExecutionResult(null, [new Error($e->getMessage(), null, null, null, null, $e)]);
6869
}
6970

7071
return new JsonResponse($executionResult->toArray($this->debug));

src/GraphQl/Type/SchemaBuilder.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,15 +208,15 @@ private function getResourceFieldConfiguration(string $resourceClass, ResourceMe
208208
}
209209

210210
$graphqlWrappedType = $graphqlType instanceof WrappingType ? $graphqlType->getWrappedType() : $graphqlType;
211-
$isInternalGraphqlType = \in_array($graphqlWrappedType, GraphQLType::getInternalTypes(), true);
212-
if ($isInternalGraphqlType) {
211+
$isStandardGraphqlType = \in_array($graphqlWrappedType, GraphQLType::getStandardTypes(), true);
212+
if ($isStandardGraphqlType) {
213213
$className = '';
214214
} else {
215215
$className = $this->isCollection($type) ? $type->getCollectionValueType()->getClassName() : $type->getClassName();
216216
}
217217

218218
$args = [];
219-
if (!$input && null === $mutationName && !$isInternalGraphqlType && $this->isCollection($type)) {
219+
if (!$input && null === $mutationName && !$isStandardGraphqlType && $this->isCollection($type)) {
220220
if ($this->paginationEnabled) {
221221
$args = [
222222
'first' => [
@@ -258,7 +258,7 @@ private function getResourceFieldConfiguration(string $resourceClass, ResourceMe
258258
$args = $this->convertFilterArgsToTypes($args);
259259
}
260260

261-
if ($isInternalGraphqlType || $input) {
261+
if ($isStandardGraphqlType || $input) {
262262
$resolve = null;
263263
} elseif ($this->isCollection($type)) {
264264
$resolverFactory = $this->collectionResolverFactory;

tests/GraphQl/Action/EntrypointActionTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public function testBadContentTypePostAction()
7676
$mockedEntrypoint = $this->getEntrypointAction();
7777

7878
$this->assertEquals(400, $mockedEntrypoint($request)->getStatusCode());
79-
$this->assertEquals('{"errors":[{"message":"GraphQL query is not valid","category":"graphql"}]}', $mockedEntrypoint($request)->getContent());
79+
$this->assertEquals('{"errors":[{"message":"GraphQL query is not valid","extensions":{"category":"graphql"}}]}', $mockedEntrypoint($request)->getContent());
8080
}
8181

8282
public function testBadMethodAction()
@@ -86,7 +86,7 @@ public function testBadMethodAction()
8686
$mockedEntrypoint = $this->getEntrypointAction();
8787

8888
$this->assertEquals(400, $mockedEntrypoint($request)->getStatusCode());
89-
$this->assertEquals('{"errors":[{"message":"GraphQL query is not valid","category":"graphql"}]}', $mockedEntrypoint($request)->getContent());
89+
$this->assertEquals('{"errors":[{"message":"GraphQL query is not valid","extensions":{"category":"graphql"}}]}', $mockedEntrypoint($request)->getContent());
9090
}
9191

9292
public function testBadVariablesAction()
@@ -96,7 +96,7 @@ public function testBadVariablesAction()
9696
$mockedEntrypoint = $this->getEntrypointAction();
9797

9898
$this->assertEquals(400, $mockedEntrypoint($request)->getStatusCode());
99-
$this->assertEquals('{"errors":[{"message":"GraphQL variables are not valid JSON","category":"graphql"}]}', $mockedEntrypoint($request)->getContent());
99+
$this->assertEquals('{"errors":[{"message":"GraphQL variables are not valid JSON","extensions":{"category":"graphql"}}]}', $mockedEntrypoint($request)->getContent());
100100
}
101101

102102
private function getEntrypointAction(): EntrypointAction
@@ -106,7 +106,7 @@ private function getEntrypointAction(): EntrypointAction
106106
$schemaBuilderProphecy->getSchema()->willReturn($schema->reveal());
107107

108108
$executionResultProphecy = $this->prophesize(ExecutionResult::class);
109-
$executionResultProphecy->toArray(true)->willReturn(['GraphQL']);
109+
$executionResultProphecy->toArray(3)->willReturn(['GraphQL']);
110110
$executorProphecy = $this->prophesize(ExecutorInterface::class);
111111
$executorProphecy->executeQuery(Argument::is($schema->reveal()), 'graphqlQuery', null, null, ['graphqlVariable'], 'graphqlOperationName')->willReturn($executionResultProphecy->reveal());
112112

tests/GraphQl/Resolver/Factory/CollectionResolverFactoryTest.php

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
2424
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy;
2525
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\RelatedDummy;
26+
use GraphQL\Type\Definition\ObjectType;
2627
use GraphQL\Type\Definition\ResolveInfo;
28+
use GraphQL\Type\Definition\Type;
29+
use GraphQL\Type\Schema;
2730
use PHPUnit\Framework\TestCase;
2831
use Prophecy\Argument;
2932
use Symfony\Component\HttpFoundation\Request;
@@ -44,9 +47,7 @@ public function testCreateCollectionResolverNoCollection(bool $paginationEnabled
4447
$factory = $this->createCollectionResolverFactory([], [], ['id' => 1], $paginationEnabled);
4548
$resolver = $factory(RelatedDummy::class, Dummy::class, 'operationName');
4649

47-
$resolveInfo = new ResolveInfo([]);
48-
$resolveInfo->fieldName = 'relatedDummies';
49-
$resolveInfo->fieldNodes = [];
50+
$resolveInfo = new ResolveInfo('relatedDummies', [], null, new ObjectType(['name' => '']), '', new Schema([]), null, null, null, null);
5051

5152
$this->assertEquals($expected, $resolver(null, [], null, $resolveInfo));
5253
}
@@ -68,9 +69,7 @@ public function testCreateCollectionResolverNoPagination()
6869

6970
$resolver = $factory(RelatedDummy::class, Dummy::class, 'operationName');
7071

71-
$resolveInfo = new ResolveInfo([]);
72-
$resolveInfo->fieldName = 'rootProperty';
73-
$resolveInfo->fieldNodes = [];
72+
$resolveInfo = new ResolveInfo('rootProperty', [], null, new ObjectType(['name' => '']), '', new Schema([]), null, null, null, null);
7473

7574
$this->assertEquals(['normalizedObject1', 'normalizedObject2'], $resolver(null, [], null, $resolveInfo));
7675
}
@@ -87,9 +86,7 @@ public function testCreateSubresourceCollectionResolverNoPagination(array $subco
8786

8887
$resolver = $factory(RelatedDummy::class, Dummy::class, 'operationName');
8988

90-
$resolveInfo = new ResolveInfo([]);
91-
$resolveInfo->fieldName = 'relatedDummies';
92-
$resolveInfo->fieldNodes = [];
89+
$resolveInfo = new ResolveInfo('relatedDummies', [], null, new ObjectType(['name' => '']), '', new Schema([]), null, null, null, null);
9390

9491
$dummy = new Dummy();
9592
$dummy->setId(1);
@@ -122,9 +119,7 @@ public function testCreateCollectionResolver(string $cursor, array $expectedCurs
122119

123120
$resolver = $factory(RelatedDummy::class, Dummy::class, 'operationName');
124121

125-
$resolveInfo = new ResolveInfo([]);
126-
$resolveInfo->fieldName = 'relatedDummies';
127-
$resolveInfo->fieldNodes = [];
122+
$resolveInfo = new ResolveInfo('relatedDummies', [], null, new ObjectType(['name' => '']), '', new Schema([]), null, null, null, null);
128123

129124
if ('$bad$' === $cursor) {
130125
$this->expectException(\Exception::class);
@@ -167,9 +162,7 @@ public function testCreatePaginatorCollectionResolver()
167162
$resolverFactory = $this->createCollectionResolverFactory($collectionPaginatorProphecy->reveal(), [], [], true, $cursor);
168163
$resolver = $resolverFactory(RelatedDummy::class, Dummy::class, 'operationName');
169164

170-
$resolveInfo = new ResolveInfo([]);
171-
$resolveInfo->fieldName = 'relatedDummies';
172-
$resolveInfo->fieldNodes = [];
165+
$resolveInfo = new ResolveInfo('relatedDummies', [], null, new ObjectType(['name' => '']), '', new Schema([]), null, null, null, null);
173166

174167
$this->assertEquals(
175168
['edges' => [['node' => 'normalizedObject1', 'cursor' => 'Mg==']], 'pageInfo' => ['endCursor' => 'MTY=', 'hasNextPage' => true], 'totalCount' => 17],

0 commit comments

Comments
 (0)