Skip to content

Commit 20c9165

Browse files
authored
fix(symfony): no read should not throw on wrong uri variables (#6359)
* fix(symfony): no read should not throw on wrong uri variables fixes #6358 * add tests
1 parent 10f24f7 commit 20c9165

File tree

7 files changed

+126
-2
lines changed

7 files changed

+126
-2
lines changed

features/main/input_output.feature

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Feature: DTO input and output
2+
In order to use a hypermedia API
3+
As a client software developer
4+
I need to be able to use DTOs on my resources as Input or Output objects.
5+
6+
Background:
7+
Given I add "Accept" header equal to "application/ld+json"
8+
And I add "Content-Type" header equal to "application/ld+json"
9+
10+
@!mongodb
11+
Scenario: Fetch a collection of outputs with an entityClass as state option
12+
When I send a "GET" request to "/output_and_entity_classes"
13+
And the JSON node "hydra:member[0].@type" should be equal to "OutputAndEntityClassEntity"
14+
15+

src/Serializer/SerializerContextBuilder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public function createFromRequest(Request $request, bool $normalization, ?array
8181
}
8282
}
8383

84-
if (($options = $operation?->getStateOptions()) && $options instanceof Options && $options->getEntityClass()) {
84+
if (null === $context['output'] && ($options = $operation?->getStateOptions()) && $options instanceof Options && $options->getEntityClass()) {
8585
$context['force_resource_class'] = $operation->getClass();
8686
}
8787

src/State/Processor/SerializeProcessor.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,14 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
5151
// @see ApiPlatform\State\Processor\RespondProcessor
5252
$context['original_data'] = $data;
5353

54+
$class = $operation->getClass();
55+
if ($request->attributes->get('_api_resource_class') && $request->attributes->get('_api_resource_class') !== $operation->getClass()) {
56+
$class = $request->attributes->get('_api_resource_class');
57+
trigger_deprecation('api-platform/core', '3.3', 'The resource class on the router is not the same as the operation\'s class which leads to wrong behaviors. Prefer using "stateOptions" if you need to change the entity class.');
58+
}
59+
5460
$serializerContext = $this->serializerContextBuilder->createFromRequest($request, true, [
55-
'resource_class' => $operation->getClass(),
61+
'resource_class' => $class,
5662
'operation' => $operation,
5763
]);
5864

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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\Issue6358;
15+
16+
use ApiPlatform\Doctrine\Orm\State\Options;
17+
use ApiPlatform\Metadata\ApiResource;
18+
use ApiPlatform\Metadata\GetCollection;
19+
20+
#[ApiResource(
21+
operations: [
22+
new GetCollection(
23+
output: OutputAndEntityClassDto::class,
24+
provider: [self::class, 'provide'],
25+
stateOptions: new Options(entityClass: OutputAndEntityClassEntity::class)
26+
),
27+
],
28+
)]
29+
class OutputAndEntityClass
30+
{
31+
public static function provide(): array
32+
{
33+
return [new OutputAndEntityClassEntity(1)];
34+
}
35+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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\Issue6358;
15+
16+
class OutputAndEntityClassDto
17+
{
18+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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\Issue6358;
15+
16+
use Doctrine\ORM\Mapping as ORM;
17+
18+
#[ORM\Entity]
19+
class OutputAndEntityClassEntity
20+
{
21+
public function __construct(
22+
#[ORM\Id]
23+
#[ORM\Column(type: 'integer')]
24+
#[ORM\GeneratedValue(strategy: 'AUTO')]
25+
public readonly ?int $id = null
26+
) {
27+
}
28+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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\Entity;
15+
16+
use ApiPlatform\Metadata\Patch;
17+
18+
#[Patch(uriTemplate: '/identifiers_shortcut/{id}', uriVariables: [self::class, 'id'])]
19+
class IdentifierShortcut
20+
{
21+
public $id;
22+
}

0 commit comments

Comments
 (0)