Skip to content

Commit 9fd77f1

Browse files
committed
Merge branch 'master' of github.com:api-platform/core
2 parents c2073ee + 8570146 commit 9fd77f1

File tree

18 files changed

+115
-349
lines changed

18 files changed

+115
-349
lines changed

features/bootstrap/FeatureContext.php

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
declare(strict_types=1);
1313

14-
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\AlwaysIdentifierDummy;
1514
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Answer;
1615
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\CompositeItem;
1716
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\CompositeLabel;
@@ -862,24 +861,6 @@ public function thereAreDummyDateObjectsWithDummyDate(int $nb)
862861
$this->manager->flush();
863862
}
864863

865-
/**
866-
* @Given there are AlwaysIdentifierDummies
867-
*/
868-
public function thereAreAlwaysIdentifierDummies()
869-
{
870-
$mainDummy = new AlwaysIdentifierDummy();
871-
$relatedDummy = new AlwaysIdentifierDummy();
872-
873-
$this->manager->persist($relatedDummy);
874-
875-
$mainDummy->setParent($relatedDummy);
876-
$mainDummy->setChildren([$relatedDummy]);
877-
$mainDummy->setRelated([$relatedDummy]);
878-
879-
$this->manager->persist($mainDummy);
880-
$this->manager->flush();
881-
}
882-
883864
/**
884865
* @Given there are :nb dummyimmutabledate objects with dummyDate
885866
*/

features/graphql/mutation.feature

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,36 @@ Feature: GraphQL mutation support
5454
And the JSON node "data.createFoo.bar" should be equal to "new"
5555
And the JSON node "data.createFoo.clientMutationId" should be equal to "myId"
5656

57+
Scenario: Create an item with a subresource
58+
Given there are 1 dummy objects with relatedDummy
59+
When I send the following GraphQL request:
60+
"""
61+
mutation {
62+
createDummy(input: {_id: 1, name: "A dummy", foo: [], relatedDummy: "/related_dummies/1", clientMutationId: "myId"}) {
63+
id
64+
name
65+
foo
66+
relatedDummy {
67+
name
68+
}
69+
clientMutationId
70+
}
71+
}
72+
"""
73+
Then the response status code should be 200
74+
And the response should be in JSON
75+
And the header "Content-Type" should be equal to "application/json"
76+
And the JSON node "data.createDummy.id" should be equal to "/dummies/2"
77+
And the JSON node "data.createDummy.name" should be equal to "A dummy"
78+
And the JSON node "data.createDummy.foo" should have 0 elements
79+
And the JSON node "data.createDummy.relatedDummy.name" should be equal to "RelatedDummy #1"
80+
And the JSON node "data.createDummy.clientMutationId" should be equal to "myId"
81+
5782
Scenario: Create an item with an iterable field
5883
When I send the following GraphQL request:
5984
"""
6085
mutation {
61-
createDummy(input: {_id: 1, name: "A dummy", foo: [], jsonData: {bar:{baz:3,qux:[7.6,false,null]}}, clientMutationId: "myId"}) {
86+
createDummy(input: {_id: 2, name: "A dummy", foo: [], jsonData: {bar:{baz:3,qux:[7.6,false,null]}}, clientMutationId: "myId"}) {
6287
id
6388
name
6489
foo
@@ -70,7 +95,7 @@ Feature: GraphQL mutation support
7095
Then the response status code should be 200
7196
And the response should be in JSON
7297
And the header "Content-Type" should be equal to "application/json"
73-
And the JSON node "data.createDummy.id" should be equal to "/dummies/1"
98+
And the JSON node "data.createDummy.id" should be equal to "/dummies/3"
7499
And the JSON node "data.createDummy.name" should be equal to "A dummy"
75100
And the JSON node "data.createDummy.foo" should have 0 elements
76101
And the JSON node "data.createDummy.jsonData.bar.baz" should be equal to the number 3

features/hal/always_identifier.feature

Lines changed: 0 additions & 52 deletions
This file was deleted.

features/json/always_identifier.feature

Lines changed: 0 additions & 28 deletions
This file was deleted.

features/jsonld/always_identifier.feature

Lines changed: 0 additions & 32 deletions
This file was deleted.

src/Annotation/ApiProperty.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,4 @@ final class ApiProperty
6767
* @var array
6868
*/
6969
public $attributes = [];
70-
71-
/**
72-
* @var bool
73-
*/
74-
public $alwaysIdentifier;
7570
}

src/Bridge/Doctrine/Orm/Extension/FilterExtension.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGenerator
6565
continue;
6666
}
6767

68+
$context['filters'] = $context['filters'] ?? [];
69+
6870
$filter->apply($queryBuilder, $queryNameGenerator, $resourceClass, $operationName, $context);
6971
}
7072
}

src/GraphQl/Type/SchemaBuilder.php

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,10 @@ private function getMutationFields(string $resourceClass, ResourceMetadata $reso
189189
*
190190
* @return array|null
191191
*/
192-
private function getResourceFieldConfiguration(string $resourceClass, ResourceMetadata $resourceMetadata, string $fieldDescription = null, Type $type, string $rootResource, bool $input = false, string $mutationName = null)
192+
private function getResourceFieldConfiguration(string $resourceClass, ResourceMetadata $resourceMetadata, string $fieldDescription = null, Type $type, string $rootResource, bool $input = false, string $mutationName = null, int $depth = 0)
193193
{
194194
try {
195-
if (null === $graphqlType = $this->convertType($type, $input, $mutationName)) {
195+
if (null === $graphqlType = $this->convertType($type, $input, $mutationName, $depth)) {
196196
return null;
197197
}
198198

@@ -227,7 +227,7 @@ private function getResourceFieldConfiguration(string $resourceClass, ResourceMe
227227
foreach ($this->filterLocator->get($filterId)->getDescription($resourceClass) as $key => $value) {
228228
$nullable = isset($value['required']) ? !$value['required'] : true;
229229
$filterType = \in_array($value['type'], Type::$builtinTypes, true) ? new Type($value['type'], $nullable) : new Type('object', $nullable, $value['type']);
230-
$graphqlFilterType = $this->convertType($filterType);
230+
$graphqlFilterType = $this->convertType($filterType, false, null, $depth);
231231

232232
if ('[]' === $newKey = substr($key, -2)) {
233233
$key = $newKey;
@@ -317,7 +317,7 @@ private function convertFilterArgsToTypes(array $args): array
317317
*
318318
* @throws InvalidTypeException
319319
*/
320-
private function convertType(Type $type, bool $input = false, string $mutationName = null)
320+
private function convertType(Type $type, bool $input = false, string $mutationName = null, int $depth = 0)
321321
{
322322
$resourceClass = null;
323323
switch ($builtinType = $type->getBuiltinType()) {
@@ -341,7 +341,7 @@ private function convertType(Type $type, bool $input = false, string $mutationNa
341341
$graphqlType = $this->graphqlTypes['#iterable'];
342342
break;
343343
case Type::BUILTIN_TYPE_OBJECT:
344-
if (is_a($type->getClassName(), \DateTimeInterface::class, true)) {
344+
if (($input && $depth > 0) || is_a($type->getClassName(), \DateTimeInterface::class, true)) {
345345
$graphqlType = GraphQLType::string();
346346
break;
347347
}
@@ -357,14 +357,14 @@ private function convertType(Type $type, bool $input = false, string $mutationNa
357357
return null;
358358
}
359359

360-
$graphqlType = $this->getResourceObjectType($resourceClass, $resourceMetadata, $input, $mutationName);
360+
$graphqlType = $this->getResourceObjectType($resourceClass, $resourceMetadata, $input, $mutationName, $depth);
361361
break;
362362
default:
363363
throw new InvalidTypeException(sprintf('The type "%s" is not supported.', $builtinType));
364364
}
365365

366366
if ($this->isCollection($type)) {
367-
return $this->paginationEnabled ? $this->getResourcePaginatedCollectionType($resourceClass, $graphqlType, $input) : GraphQLType::listOf($graphqlType);
367+
return $this->paginationEnabled && !$input ? $this->getResourcePaginatedCollectionType($resourceClass, $graphqlType) : GraphQLType::listOf($graphqlType);
368368
}
369369

370370
return $type->isNullable() || (null !== $mutationName && 'update' === $mutationName) ? $graphqlType : GraphQLType::nonNull($graphqlType);
@@ -375,7 +375,7 @@ private function convertType(Type $type, bool $input = false, string $mutationNa
375375
*
376376
* @return ObjectType|InputObjectType
377377
*/
378-
private function getResourceObjectType(string $resourceClass, ResourceMetadata $resourceMetadata, bool $input = false, string $mutationName = null): GraphQLType
378+
private function getResourceObjectType(string $resourceClass, ResourceMetadata $resourceMetadata, bool $input = false, string $mutationName = null, int $depth = 0): GraphQLType
379379
{
380380
if (isset($this->graphqlTypes[$resourceClass][$mutationName][$input])) {
381381
return $this->graphqlTypes[$resourceClass][$mutationName][$input];
@@ -395,8 +395,8 @@ private function getResourceObjectType(string $resourceClass, ResourceMetadata $
395395
'name' => $shortName,
396396
'description' => $resourceMetadata->getDescription(),
397397
'resolveField' => $this->defaultFieldResolver,
398-
'fields' => function () use ($resourceClass, $resourceMetadata, $input, $mutationName) {
399-
return $this->getResourceObjectTypeFields($resourceClass, $resourceMetadata, $input, $mutationName);
398+
'fields' => function () use ($resourceClass, $resourceMetadata, $input, $mutationName, $depth) {
399+
return $this->getResourceObjectTypeFields($resourceClass, $resourceMetadata, $input, $mutationName, $depth);
400400
},
401401
'interfaces' => [$this->getNodeInterface()],
402402
];
@@ -407,7 +407,7 @@ private function getResourceObjectType(string $resourceClass, ResourceMetadata $
407407
/**
408408
* Gets the fields of the type of the given resource.
409409
*/
410-
private function getResourceObjectTypeFields(string $resourceClass, ResourceMetadata $resourceMetadata, bool $input = false, string $mutationName = null): array
410+
private function getResourceObjectTypeFields(string $resourceClass, ResourceMetadata $resourceMetadata, bool $input = false, string $mutationName = null, int $depth = 0): array
411411
{
412412
$fields = [];
413413
$idField = ['type' => GraphQLType::nonNull(GraphQLType::id())];
@@ -434,7 +434,7 @@ private function getResourceObjectTypeFields(string $resourceClass, ResourceMeta
434434
continue;
435435
}
436436

437-
if ($fieldConfiguration = $this->getResourceFieldConfiguration($resourceClass, $resourceMetadata, $propertyMetadata->getDescription(), $propertyType, $resourceClass, $input, $mutationName)) {
437+
if ($fieldConfiguration = $this->getResourceFieldConfiguration($resourceClass, $resourceMetadata, $propertyMetadata->getDescription(), $propertyType, $resourceClass, $input, $mutationName, ++$depth)) {
438438
$fields['id' === $property ? '_id' : $property] = $fieldConfiguration;
439439
}
440440
}
@@ -449,19 +449,16 @@ private function getResourceObjectTypeFields(string $resourceClass, ResourceMeta
449449
/**
450450
* Gets the type of a paginated collection of the given resource type.
451451
*
452-
* @param ObjectType|InputObjectType $resourceType
452+
* @param ObjectType $resourceType
453453
*
454-
* @return ObjectType|InputObjectType
454+
* @return ObjectType
455455
*/
456-
private function getResourcePaginatedCollectionType(string $resourceClass, GraphQLType $resourceType, bool $input = false): GraphQLType
456+
private function getResourcePaginatedCollectionType(string $resourceClass, GraphQLType $resourceType): GraphQLType
457457
{
458458
$shortName = $resourceType->name;
459-
if ($input) {
460-
$shortName .= 'Input';
461-
}
462459

463-
if (isset($this->graphqlTypes[$resourceClass]['connection'][$input])) {
464-
return $this->graphqlTypes[$resourceClass]['connection'][$input];
460+
if (isset($this->graphqlTypes[$resourceClass]['connection'])) {
461+
return $this->graphqlTypes[$resourceClass]['connection'];
465462
}
466463

467464
$edgeObjectTypeConfiguration = [
@@ -472,7 +469,7 @@ private function getResourcePaginatedCollectionType(string $resourceClass, Graph
472469
'cursor' => GraphQLType::nonNull(GraphQLType::string()),
473470
],
474471
];
475-
$edgeObjectType = $input ? new InputObjectType($edgeObjectTypeConfiguration) : new ObjectType($edgeObjectTypeConfiguration);
472+
$edgeObjectType = new ObjectType($edgeObjectTypeConfiguration);
476473
$pageInfoObjectTypeConfiguration = [
477474
'name' => "{$shortName}PageInfo",
478475
'description' => 'Information about the current page.',
@@ -481,7 +478,7 @@ private function getResourcePaginatedCollectionType(string $resourceClass, Graph
481478
'hasNextPage' => GraphQLType::nonNull(GraphQLType::boolean()),
482479
],
483480
];
484-
$pageInfoObjectType = $input ? new InputObjectType($pageInfoObjectTypeConfiguration) : new ObjectType($pageInfoObjectTypeConfiguration);
481+
$pageInfoObjectType = new ObjectType($pageInfoObjectTypeConfiguration);
485482

486483
$configuration = [
487484
'name' => "{$shortName}Connection",
@@ -492,7 +489,7 @@ private function getResourcePaginatedCollectionType(string $resourceClass, Graph
492489
],
493490
];
494491

495-
return $this->graphqlTypes[$resourceClass]['connection'][$input] = $input ? new InputObjectType($configuration) : new ObjectType($configuration);
492+
return $this->graphqlTypes[$resourceClass]['connection'] = new ObjectType($configuration);
496493
}
497494

498495
private function isCollection(Type $type): bool

src/Metadata/Extractor/XmlExtractor.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,22 +73,25 @@ private function getOperations(\SimpleXMLElement $resource, string $operationTyp
7373
}
7474

7575
$operationsParent = $graphql ? 'graphql' : "{$operationType}s";
76-
7776
if (!isset($resource->$operationsParent)) {
7877
return null;
7978
}
8079

81-
return $this->getAttributes($resource->$operationsParent, $operationType);
80+
return $this->getAttributes($resource->$operationsParent, $operationType, true);
8281
}
8382

8483
/**
8584
* Recursively transforms an attribute structure into an associative array.
8685
*/
87-
private function getAttributes(\SimpleXMLElement $resource, string $elementName): array
86+
private function getAttributes(\SimpleXMLElement $resource, string $elementName, bool $topLevel = false): array
8887
{
8988
$attributes = [];
9089
foreach ($resource->$elementName as $attribute) {
9190
$value = isset($attribute->attribute[0]) ? $this->getAttributes($attribute, 'attribute') : XmlUtils::phpize($attribute);
91+
// allow empty operations definition, like <collectionOperation name="post" />
92+
if ($topLevel && '' === $value) {
93+
$value = [];
94+
}
9295
if (isset($attribute['name'])) {
9396
$attributes[(string) $attribute['name']] = $value;
9497
} else {

0 commit comments

Comments
 (0)