Skip to content

Commit b8827f6

Browse files
committed
Merge branch '2.4'
2 parents 50a15af + e056f5d commit b8827f6

23 files changed

+457
-46
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
* GraphQL: Add support for custom types
66

7+
## 2.4.5
8+
9+
* Fix denormalization of a constructor argument which is a collection of non-resources
10+
* Allow custom operations to return a different class than the expected resource class
11+
712
## 2.4.4
813

914
* Store the original data in the `previous_data` request attribute, and allow to access it in security expressions using the `previous_object` variable (useful for PUT and PATCH requests)

features/main/custom_operation.feature

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ Feature: Custom operation
22
As a client software developer
33
I need to be able to create custom operations
44

5+
Background:
6+
Given I add "Accept" header equal to "application/ld+json"
7+
And I add "Content-Type" header equal to "application/ld+json"
8+
59
@createSchema
610
Scenario: Custom normalization operation
711
When I send a "POST" request to "/custom/denormalization"
8-
And I add "Content-Type" header equal to "application/ld+json"
912
Then the JSON should be equal to:
1013
"""
1114
{
@@ -29,7 +32,6 @@ Feature: Custom operation
2932

3033
Scenario: Custom normalization operation with shorthand configuration
3134
When I send a "POST" request to "/short_custom/denormalization"
32-
And I add "Content-Type" header equal to "application/ld+json"
3335
Then the JSON should be equal to:
3436
"""
3537
{
@@ -68,3 +70,57 @@ Feature: Custom operation
6870
"foo": "custom!"
6971
}
7072
"""
73+
74+
Scenario: Create a payment
75+
When I send a "POST" request to "/payments" with body:
76+
"""
77+
{
78+
"amount": "123.45"
79+
}
80+
"""
81+
Then the response status code should be 201
82+
And the response should be in JSON
83+
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
84+
And the JSON should be equal to:
85+
"""
86+
{
87+
"@context": "/contexts/Payment",
88+
"@id": "/payments/1",
89+
"@type": "Payment",
90+
"id": 1,
91+
"amount": "123.45",
92+
"voidPayment": null
93+
}
94+
"""
95+
96+
Scenario: Void a payment
97+
When I send a "POST" request to "/payments/1/void"
98+
Then the response status code should be 201
99+
And the response should be in JSON
100+
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
101+
And the JSON should be equal to:
102+
"""
103+
{
104+
"@context": "/contexts/VoidPayment",
105+
"@id": "/void_payments/1",
106+
"@type": "VoidPayment",
107+
"id": 1,
108+
"payment": "/payments/1"
109+
}
110+
"""
111+
112+
Scenario: Get a void payment
113+
When I send a "GET" request to "/void_payments/1"
114+
Then the response status code should be 200
115+
And the response should be in JSON
116+
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
117+
And the JSON should be equal to:
118+
"""
119+
{
120+
"@context": "/contexts/VoidPayment",
121+
"@id": "/void_payments/1",
122+
"@type": "VoidPayment",
123+
"id": 1,
124+
"payment": "/payments/1"
125+
}
126+
"""

features/serializer/deserialize_objects_using_constructor.feature

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ Feature: Resource with constructor deserializable
1010
"""
1111
{
1212
"foo": "hello",
13-
"bar": "world"
13+
"bar": "world",
14+
"items": [
15+
{
16+
"foo": "bar"
17+
}
18+
]
1419
}
1520
"""
1621
Then the response status code should be 201
@@ -25,7 +30,11 @@ Feature: Resource with constructor deserializable
2530
"id": 1,
2631
"foo": "hello",
2732
"bar": "world",
33+
"items": [
34+
{
35+
"foo": "bar"
36+
}
37+
],
2838
"baz": null
2939
}
3040
"""
31-

src/Hal/Serializer/ItemNormalizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public function normalize($object, $format = null, array $context = [])
5656
$context['cache_key'] = $this->getHalCacheKey($format, $context);
5757
}
5858

59-
$resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, isset($context['resource_class']));
59+
$resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null);
6060
$context = $this->initContext($resourceClass, $context);
6161
$iri = $this->iriConverter->getIriFromItem($object);
6262
$context['iri'] = $iri;

src/JsonApi/Serializer/ItemNormalizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public function normalize($object, $format = null, array $context = [])
7474
$context['cache_key'] = $this->getJsonApiCacheKey($format, $context);
7575
}
7676

77-
$resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, isset($context['resource_class']));
77+
$resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null);
7878
$context = $this->initContext($resourceClass, $context);
7979
$iri = $this->iriConverter->getIriFromItem($object);
8080
$context['iri'] = $iri;

src/JsonLd/Serializer/ItemNormalizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public function normalize($object, $format = null, array $context = [])
6969
return parent::normalize($object, $format, $context);
7070
}
7171

72-
$resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, isset($context['resource_class']));
72+
$resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null);
7373
$context = $this->initContext($resourceClass, $context);
7474
$iri = $this->iriConverter->getIriFromItem($object);
7575
$context['iri'] = $iri;

src/Serializer/AbstractItemNormalizer.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ public function normalize($object, $format = null, array $context = [])
125125
return $this->serializer->normalize($transformed, $format, $context);
126126
}
127127

128-
$resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, isset($context['resource_class']));
128+
$resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null);
129129
$context = $this->initContext($resourceClass, $context);
130130
$iri = $context['iri'] ?? $this->iriConverter->getIriFromItem($object);
131131
$context['iri'] = $iri;
@@ -542,7 +542,7 @@ protected function getAttributeValue($object, $attribute, $format = null, array
542542
($className = $type->getClassName()) &&
543543
$this->resourceClassResolver->isResourceClass($className)
544544
) {
545-
$resourceClass = $this->resourceClassResolver->getResourceClass($attributeValue, $className, true);
545+
$resourceClass = $this->resourceClassResolver->getResourceClass($attributeValue, $className);
546546
$childContext = $this->createChildContext($context, $attribute, $format);
547547
$childContext['resource_class'] = $resourceClass;
548548

@@ -677,7 +677,7 @@ private function createAttributeValue($attribute, $value, $format = null, array
677677

678678
unset($context['resource_class']);
679679

680-
return $this->serializer->denormalize($value, $className, $format, $context);
680+
return $this->serializer->denormalize($value, $className.'[]', $format, $context);
681681
}
682682

683683
if (null !== $className = $type->getClassName()) {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Controller\Payment;
15+
16+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\Payment as PaymentDocument;
17+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Payment;
18+
19+
final class VoidPaymentAction
20+
{
21+
public function __invoke($data)
22+
{
23+
if (!$data instanceof Payment && !$data instanceof PaymentDocument) {
24+
throw new \InvalidArgumentException();
25+
}
26+
$payment = $data;
27+
28+
$payment->void();
29+
30+
return $payment->getVoidPayment();
31+
}
32+
}

tests/Fixtures/TestBundle/Document/DummyEntityWithConstructor.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Document;
1515

1616
use ApiPlatform\Core\Annotation\ApiResource;
17+
use ApiPlatform\Core\Tests\Fixtures\DummyObjectWithoutConstructor;
1718
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
1819
use Symfony\Component\Serializer\Annotation\Groups;
1920

@@ -62,10 +63,19 @@ class DummyEntityWithConstructor
6263
*/
6364
private $baz;
6465

65-
public function __construct(string $foo, string $bar)
66+
/**
67+
* @var DummyObjectWithoutConstructor[]
68+
*/
69+
private $items;
70+
71+
/**
72+
* @param DummyObjectWithoutConstructor[] $items
73+
*/
74+
public function __construct(string $foo, string $bar, array $items)
6675
{
6776
$this->foo = $foo;
6877
$this->bar = $bar;
78+
$this->items = $items;
6979
}
7080

7181
public function getId(): int
@@ -83,6 +93,14 @@ public function getBar(): string
8393
return $this->bar;
8494
}
8595

96+
/**
97+
* @return DummyObjectWithoutConstructor[]
98+
*/
99+
public function getItems(): array
100+
{
101+
return $this->items;
102+
}
103+
86104
/**
87105
* @return string
88106
*/
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Document;
15+
16+
use ApiPlatform\Core\Annotation\ApiResource;
17+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Controller\Payment\VoidPaymentAction;
18+
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
19+
20+
/**
21+
* @ODM\Document
22+
*
23+
* @ApiResource(
24+
* itemOperations={
25+
* "get",
26+
* "post_void"={
27+
* "method"="POST",
28+
* "path"="/payments/{id}/void",
29+
* "controller"=VoidPaymentAction::class,
30+
* "deserialize"=false,
31+
* },
32+
* },
33+
* )
34+
*/
35+
class Payment
36+
{
37+
/**
38+
* @var int|null
39+
*
40+
* @ODM\Id(strategy="INCREMENT", type="integer")
41+
*/
42+
private $id;
43+
44+
/**
45+
* @var string
46+
*/
47+
private $amount;
48+
49+
/**
50+
* @ODM\ReferenceOne(targetDocument=VoidPayment::class, mappedBy="payment")
51+
*/
52+
private $voidPayment;
53+
54+
public function __construct(string $amount)
55+
{
56+
$this->amount = $amount;
57+
}
58+
59+
public function getId(): ?int
60+
{
61+
return $this->id;
62+
}
63+
64+
public function getAmount(): string
65+
{
66+
return $this->amount;
67+
}
68+
69+
public function void(): void
70+
{
71+
if (null !== $this->voidPayment) {
72+
return;
73+
}
74+
75+
$this->voidPayment = new VoidPayment($this);
76+
}
77+
78+
public function getVoidPayment(): ?VoidPayment
79+
{
80+
return $this->voidPayment;
81+
}
82+
}

0 commit comments

Comments
 (0)