Skip to content

Commit c539432

Browse files
committed
Merge branch '2.3' into merge-2.3
2 parents e0c6134 + 7cc59e6 commit c539432

File tree

15 files changed

+216
-18
lines changed

15 files changed

+216
-18
lines changed

.travis.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ env:
1111
- SYMFONY_DEPRECATIONS_HELPER=weak_vendors
1212
- APP_ENV=test
1313

14-
matrix:
14+
jobs:
1515
include:
1616
- php: '7.1'
1717
- php: '7.2'
@@ -32,7 +32,8 @@ matrix:
3232
- mysql -e 'CREATE DATABASE api_platform_test;'
3333
env: APP_ENV=mysql
3434
allow_failures:
35-
env: SYMFONY_DEPRECATIONS_HELPER=0
35+
- env: SYMFONY_DEPRECATIONS_HELPER=0
36+
fast_finish: true
3637

3738
before_install:
3839
- phpenv config-rm xdebug.ini || echo "xdebug not available"

appveyor.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ cache:
66
- '%LOCALAPPDATA%\Composer\files'
77

88
environment:
9-
APP_ENV: 'test'
9+
SYMFONY_DEPRECATIONS_HELPER: weak_vendors
10+
APP_ENV: test
1011

1112
install:
1213
- ps: Set-Service wuauserv -StartupType Manual

features/bootstrap/FeatureContext.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,31 @@ public function thereAreDummyPropertyObjects(int $nb)
219219
$this->manager->flush();
220220
}
221221

222+
/**
223+
* @Given there are :nb dummy property objects with a shared group
224+
*/
225+
public function thereAreDummyPropertyObjectsWithASharedGroup(int $nb)
226+
{
227+
$dummyGroup = new DummyGroup();
228+
foreach (['foo', 'bar', 'baz'] as $property) {
229+
$dummyGroup->$property = ucfirst($property).' #shared';
230+
}
231+
$this->manager->persist($dummyGroup);
232+
233+
for ($i = 1; $i <= $nb; ++$i) {
234+
$dummyProperty = new DummyProperty();
235+
236+
foreach (['foo', 'bar', 'baz'] as $property) {
237+
$dummyProperty->$property = ucfirst($property).' #'.$i;
238+
}
239+
240+
$dummyProperty->group = $dummyGroup;
241+
$this->manager->persist($dummyProperty);
242+
}
243+
244+
$this->manager->flush();
245+
}
246+
222247
/**
223248
* @Given there are :nb dummy property objects with :nb2 groups
224249
*/

features/graphql/filters.feature

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,28 @@ Feature: Collections filtering
154154
And the header "Content-Type" should be equal to "application/json"
155155
And the JSON node "data.dummies.edges[0].node.name" should be equal to "Dummy #2"
156156
And the JSON node "data.dummies.edges[1].node.name" should be equal to "Dummy #1"
157+
158+
@createSchema
159+
Scenario: Retrieve a collection filtered using the related search filter with two values and exact strategy
160+
Given there are 3 dummy objects with relatedDummy
161+
When I send the following GraphQL request:
162+
"""
163+
{
164+
dummies(relatedDummy_name_list: ["RelatedDummy #1", "RelatedDummy #2"]) {
165+
edges {
166+
node {
167+
id
168+
name
169+
relatedDummy {
170+
name
171+
}
172+
}
173+
}
174+
}
175+
}
176+
"""
177+
Then the response status code should be 200
178+
And the header "Content-Type" should be equal to "application/json"
179+
And the JSON node "data.dummies.edges" should have 2 element
180+
And the JSON node "data.dummies.edges[0].node.relatedDummy.name" should be equal to "RelatedDummy #1"
181+
And the JSON node "data.dummies.edges[1].node.relatedDummy.name" should be equal to "RelatedDummy #2"

features/jsonapi/related-resouces-inclusion.feature

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,3 +496,91 @@ Feature: JSON API Inclusion of Related Resources
496496
}
497497
"""
498498

499+
@createSchema
500+
Scenario: Request inclusion of a related resources on collection should not duplicated included object
501+
Given there are 3 dummy property objects with a shared group
502+
When I send a "GET" request to "/dummy_properties?include=group"
503+
Then the response status code should be 200
504+
And the response should be in JSON
505+
And the JSON should be valid according to the JSON API schema
506+
And the JSON should be deep equal to:
507+
"""
508+
{
509+
"links": {
510+
"self": "\/dummy_properties?include=group"
511+
},
512+
"meta": {
513+
"totalItems": 3,
514+
"itemsPerPage": 3,
515+
"currentPage": 1
516+
},
517+
"data": [
518+
{
519+
"id": "/dummy_properties/1",
520+
"type": "DummyProperty",
521+
"attributes": {
522+
"_id": 1,
523+
"foo": "Foo #1",
524+
"bar": "Bar #1",
525+
"baz": "Baz #1"
526+
},
527+
"relationships": {
528+
"group": {
529+
"data": {
530+
"type": "DummyGroup",
531+
"id": "/dummy_groups/1"
532+
}
533+
}
534+
}
535+
},
536+
{
537+
"id": "/dummy_properties/2",
538+
"type": "DummyProperty",
539+
"attributes": {
540+
"_id": 2,
541+
"foo": "Foo #2",
542+
"bar": "Bar #2",
543+
"baz": "Baz #2"
544+
},
545+
"relationships": {
546+
"group": {
547+
"data": {
548+
"type": "DummyGroup",
549+
"id": "/dummy_groups/1"
550+
}
551+
}
552+
}
553+
},
554+
{
555+
"id": "/dummy_properties/3",
556+
"type": "DummyProperty",
557+
"attributes": {
558+
"_id": 3,
559+
"foo": "Foo #3",
560+
"bar": "Bar #3",
561+
"baz": "Baz #3"
562+
},
563+
"relationships": {
564+
"group": {
565+
"data": {
566+
"type": "DummyGroup",
567+
"id": "/dummy_groups/1"
568+
}
569+
}
570+
}
571+
}
572+
],
573+
"included": [
574+
{
575+
"id": "\/dummy_groups\/1",
576+
"type": "DummyGroup",
577+
"attributes": {
578+
"_id": 1,
579+
"foo": "Foo #shared",
580+
"bar": "Bar #shared",
581+
"baz": "Baz #shared"
582+
}
583+
}
584+
]
585+
}
586+
"""

src/Annotation/AttributesHydratorTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
namespace ApiPlatform\Core\Annotation;
2323

2424
use ApiPlatform\Core\Exception\InvalidArgumentException;
25-
use Doctrine\Common\Util\Inflector;
25+
use Doctrine\Common\Inflector\Inflector;
2626

2727
/**
2828
* Hydrates attributes from annotation's parameters.

src/Bridge/Symfony/Routing/RouteNameGenerator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
use ApiPlatform\Core\Api\OperationType;
1717
use ApiPlatform\Core\Api\OperationTypeDeprecationHelper;
1818
use ApiPlatform\Core\Exception\InvalidArgumentException;
19-
use Doctrine\Common\Util\Inflector;
19+
use Doctrine\Common\Inflector\Inflector;
2020

2121
/**
2222
* Generates the Symfony route name associated with an operation name and a resource short name.

src/GraphQl/Resolver/Factory/CollectionResolverFactory.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,16 @@ private function getSubresource(string $rootClass, array $rootResolvedFields, ar
162162
private function getNormalizedFilters(array $args): array
163163
{
164164
$filters = $args;
165+
165166
foreach ($filters as $name => $value) {
166167
if (\is_array($value)) {
168+
if (strpos($name, '_list')) {
169+
$name = substr($name, 0, \strlen($name) - \strlen('_list'));
170+
}
167171
$filters[$name] = $this->getNormalizedFilters($value);
168-
continue;
169172
}
170173

171-
if (strpos($name, '_')) {
174+
if (\is_string($name) && strpos($name, '_')) {
172175
// Gives a chance to relations/nested fields.
173176
$filters[str_replace('_', '.', $name)] = $value;
174177
}

src/GraphQl/Type/SchemaBuilder.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
2424
use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
2525
use ApiPlatform\Core\Util\ClassInfoTrait;
26-
use Doctrine\Common\Util\Inflector;
26+
use Doctrine\Common\Inflector\Inflector;
2727
use GraphQL\Type\Definition\InputObjectType;
2828
use GraphQL\Type\Definition\InterfaceType;
2929
use GraphQL\Type\Definition\ObjectType;
@@ -231,12 +231,15 @@ private function getResourceFieldConfiguration(string $resourceClass, ResourceMe
231231
$filterType = \in_array($value['type'], Type::$builtinTypes, true) ? new Type($value['type'], $nullable) : new Type('object', $nullable, $value['type']);
232232
$graphqlFilterType = $this->convertType($filterType, false, null, $depth);
233233

234-
if ('[]' === $newKey = substr($key, -2)) {
235-
$key = $newKey;
234+
if ('[]' === substr($key, -2)) {
236235
$graphqlFilterType = GraphQLType::listOf($graphqlFilterType);
236+
$key = substr($key, 0, -2).'_list';
237237
}
238238

239239
parse_str($key, $parsed);
240+
if (array_key_exists($key, $parsed) && \is_array($parsed[$key])) {
241+
$parsed = [$key => ''];
242+
}
240243
array_walk_recursive($parsed, function (&$value) use ($graphqlFilterType) {
241244
$value = $graphqlFilterType;
242245
});
@@ -297,6 +300,7 @@ private function convertFilterArgsToTypes(array $args): array
297300
if (strpos($key, '.')) {
298301
// Declare relations/nested fields in a GraphQL compatible syntax.
299302
$args[str_replace('.', '_', $key)] = $value;
303+
unset($args[$key]);
300304
}
301305
}
302306

src/HttpCache/EventListener/AddTagsListener.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public function onKernelResponse(FilterResponseEvent $event)
5656
}
5757

5858
$resources = $request->attributes->get('_resources');
59-
if (isset($attributes['collection_operation_name'])) {
59+
if (isset($attributes['collection_operation_name']) || ($attributes['subresource_context']['collection'] ?? false)) {
6060
// Allows to purge collections
6161
$iri = $this->iriConverter->getIriFromResourceClass($attributes['resource_class']);
6262
$resources[$iri] = $iri;

0 commit comments

Comments
 (0)