Skip to content

Commit 09cdd7a

Browse files
committed
fix(symfony): align listeners context
1 parent 133028e commit 09cdd7a

File tree

7 files changed

+105
-4
lines changed

7 files changed

+105
-4
lines changed

src/State/Provider/DeserializeProvider.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
126126

127127
$this->stopwatch?->stop('api_platform.provider.deserialize');
128128

129+
$request->attributes->set('data', $data);
130+
129131
return $data;
130132
}
131133

src/State/Provider/ReadProvider.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
9999
}
100100

101101
$request?->attributes->set('data', $data);
102+
$request?->attributes->set('read_data', $data); // data may be lost when deserialization occurs, especially when using an Input see DeserializeProvider
102103
$request?->attributes->set('previous_data', $this->clone($data));
103104

104105
$this->stopwatch?->stop('api_platform.provider.read');

src/Symfony/Controller/MainController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ public function __invoke(Request $request): Response
111111

112112
$context['previous_data'] = $request->attributes->get('previous_data');
113113
$context['data'] = $request->attributes->get('data');
114+
$context['read_data'] = $request->attributes->get('read_data');
114115

115116
if (null === $operation->canWrite()) {
116117
$operation = $operation->withWrite(!$request->isMethodSafe());

src/Symfony/EventListener/DeserializeListener.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,10 @@ public function onKernelRequest(RequestEvent $event): void
7979
return;
8080
}
8181

82-
$data = $this->provider->provide($operation, $request->attributes->get('_api_uri_variables') ?? [], [
82+
$this->provider->provide($operation, $request->attributes->get('_api_uri_variables') ?? [], [
8383
'request' => $request,
8484
'uri_variables' => $request->attributes->get('_api_uri_variables') ?? [],
8585
'resource_class' => $operation->getClass(),
8686
]);
87-
88-
$request->attributes->set('data', $data);
8987
}
9088
}

src/Symfony/EventListener/WriteListener.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ public function onKernelView(ViewEvent $event): void
8181
'request' => $request,
8282
'uri_variables' => $uriVariables,
8383
'resource_class' => $operation->getClass(),
84-
'previous_data' => false === $operation->canRead() ? null : $request->attributes->get('previous_data'),
84+
'previous_data' => false === $operation->canRead() ? null : $request->attributes->get('previous_data'), // this is a clone
85+
'read_data' => false === $operation->canRead() ? null : $request->attributes->get('read_data'), // this is what we read
86+
'data' => false === $operation->canRead() ? null : $request->attributes->get('data'), // this should be the same as getControllerResult but is the result of deserialization
8587
]);
8688

8789
if ($data) {
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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\Tests\Fixtures\TestBundle\ApiResource\Issue7432;
15+
16+
use ApiPlatform\Metadata\Operation;
17+
use ApiPlatform\Metadata\Patch;
18+
19+
#[Patch(
20+
provider: [self::class, 'provide'],
21+
uriTemplate: '/original_data_with_listeners/{uuid}/verify',
22+
uriVariables: ['uuid'],
23+
input: UserVerifyInput::class,
24+
processor: [self::class, 'process']
25+
)]
26+
class OriginalDataWithListeners
27+
{
28+
public function __construct(public string $uuid, public ?string $code = null)
29+
{
30+
}
31+
32+
public static function process($data, Operation $operation, array $uriVariables = [], array $context = [])
33+
{
34+
\assert($data instanceof UserVerifyInput);
35+
\assert($context['previous_data'] instanceof self);
36+
\assert($context['request']->attributes->get('data') instanceof UserVerifyInput);
37+
\assert($context['request']->attributes->get('previous_data') instanceof self);
38+
\assert($context['data'] instanceof UserVerifyInput);
39+
$context['previous_data']->code = $data->code;
40+
41+
return $context['previous_data'];
42+
}
43+
44+
public static function provide(Operation $operation, array $uriVariables = [], array $context = [])
45+
{
46+
return new self($uriVariables['uuid']);
47+
}
48+
}
49+
50+
class UserVerifyInput
51+
{
52+
public string $code;
53+
}

tests/Functional/ListenerTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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\Tests\Functional;
15+
16+
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
17+
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue7432\OriginalDataWithListeners;
18+
use ApiPlatform\Tests\SetupClassResourcesTrait;
19+
20+
final class ListenerTest extends ApiTestCase
21+
{
22+
use SetupClassResourcesTrait;
23+
protected static ?bool $alwaysBootKernel = false;
24+
25+
/**
26+
* @return class-string[]
27+
*/
28+
public static function getResources(): array
29+
{
30+
return [
31+
OriginalDataWithListeners::class,
32+
];
33+
}
34+
35+
public function testListener()
36+
{
37+
self::createClient()->request('PATCH', '/original_data_with_listeners/123/verify', [
38+
'headers' => ['content-type' => 'application/merge-patch+json'],
39+
'json' => ['code' => '456'],
40+
]);
41+
42+
$this->assertResponseIsSuccessful();
43+
}
44+
}

0 commit comments

Comments
 (0)