Skip to content

Commit 91847ab

Browse files
Geekimosoyuka
authored andcommitted
fix(serializer): properly handle read link parameters when generating iris
1 parent 6561eb1 commit 91847ab

File tree

6 files changed

+206
-2
lines changed

6 files changed

+206
-2
lines changed
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\Metadata\UriVariableTransformer;
15+
16+
use ApiPlatform\Metadata\IdentifiersExtractorInterface;
17+
use ApiPlatform\Metadata\ResourceClassResolverInterface;
18+
use ApiPlatform\Metadata\UriVariableTransformerInterface;
19+
20+
final class ApiResourceUriVariableTransformer implements UriVariableTransformerInterface
21+
{
22+
public function __construct(private readonly IdentifiersExtractorInterface $identifiersExtractor, private readonly ResourceClassResolverInterface $resourceClassResolver)
23+
{
24+
}
25+
26+
public function transform(mixed $value, array $types, array $context = []): mixed
27+
{
28+
return current($this->identifiersExtractor->getIdentifiersFromItem($value));
29+
}
30+
31+
public function supportsTransformation(mixed $value, array $types, array $context = []): bool
32+
{
33+
return \is_object($value) && $this->resourceClassResolver->isResourceClass($value::class);
34+
}
35+
}

src/Symfony/Bundle/Resources/config/api.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,13 @@
169169
$services->set('api_platform.uri_variables.transformer.date_time', 'ApiPlatform\Metadata\UriVariableTransformer\DateTimeUriVariableTransformer')
170170
->tag('api_platform.uri_variables.transformer', ['priority' => -100]);
171171

172+
$services->set('api_platform.uri_variables.transformer.api_resource', 'ApiPlatform\Metadata\UriVariableTransformer\ApiResourceUriVariableTransformer')
173+
->args([
174+
service('api_platform.api.identifiers_extractor'),
175+
service('api_platform.resource_class_resolver'),
176+
])
177+
->tag('api_platform.uri_variables.transformer', ['priority' => -100]);
178+
172179
$services->alias('api_platform.iri_converter', 'api_platform.symfony.iri_converter');
173180

174181
$services->set('api_platform.symfony.iri_converter', 'ApiPlatform\Symfony\Routing\IriConverter')
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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;
15+
16+
use ApiPlatform\Metadata\ApiResource;
17+
use ApiPlatform\Metadata\Get;
18+
use ApiPlatform\Metadata\HttpOperation;
19+
use ApiPlatform\Metadata\Link;
20+
use ApiPlatform\Metadata\Operation;
21+
use ApiPlatform\State\ParameterProvider\ReadLinkParameterProvider;
22+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue7469Dummy;
23+
24+
#[ApiResource(
25+
operations: [
26+
new Get(
27+
uriTemplate: '/issue_7469_test_resources/{id}',
28+
uriVariables: [
29+
'id' => new Link(
30+
provider: ReadLinkParameterProvider::class,
31+
fromClass: Issue7469Dummy::class
32+
),
33+
],
34+
provider: [self::class, 'provide']
35+
),
36+
]
37+
)]
38+
final class Issue7469TestResource
39+
{
40+
public int $id;
41+
public string $dummyName;
42+
43+
/**
44+
* @param HttpOperation $operation
45+
*/
46+
public static function provide(Operation $operation, array $uriVariables = [], array $context = [])
47+
{
48+
/** @var Issue7469Dummy $dummy */
49+
$dummy = $operation->getUriVariables()['id']->getValue();
50+
51+
$resource = new self();
52+
$resource->id = $dummy->id;
53+
$resource->dummyName = $dummy->name;
54+
55+
return $resource;
56+
}
57+
}
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\Tests\Fixtures\TestBundle\Document;
15+
16+
use ApiPlatform\Metadata\ApiProperty;
17+
use ApiPlatform\Metadata\ApiResource;
18+
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
19+
20+
#[ODM\Document]
21+
#[ApiResource(
22+
uriTemplate: '/issue_7469_dummies/{id}',
23+
)]
24+
class Issue7469Dummy
25+
{
26+
#[ODM\Id]
27+
#[ApiProperty(identifier: true)]
28+
public ?string $id = null;
29+
30+
#[ODM\Field(type: 'string')]
31+
public string $name;
32+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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\ApiProperty;
17+
use ApiPlatform\Metadata\ApiResource;
18+
use Doctrine\ORM\Mapping as ORM;
19+
20+
#[ORM\Entity]
21+
#[ApiResource(
22+
uriTemplate: '/issue_7469_dummies/{id}',
23+
)]
24+
class Issue7469Dummy
25+
{
26+
#[ORM\Column(type: 'integer')]
27+
#[ORM\Id]
28+
#[ORM\GeneratedValue(strategy: 'AUTO')]
29+
#[ApiProperty(identifier: true)]
30+
public ?int $id = null;
31+
32+
#[ORM\Column]
33+
public string $name;
34+
}

tests/Functional/Parameters/LinkProviderParameterTest.php

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
namespace ApiPlatform\Tests\Functional\Parameters;
1515

1616
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
17+
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\Issue7469TestResource;
1718
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\LinkParameterProviderResource;
1819
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\WithParameter;
1920
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Company;
2021
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy;
2122
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Employee;
23+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue7469Dummy;
2224
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\RelatedDummy;
2325
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\RelatedOwnedDummy;
2426
use ApiPlatform\Tests\RecreateSchemaTrait;
@@ -36,15 +38,15 @@ final class LinkProviderParameterTest extends ApiTestCase
3638
*/
3739
public static function getResources(): array
3840
{
39-
return [WithParameter::class, Dummy::class, Employee::class, Company::class, LinkParameterProviderResource::class];
41+
return [WithParameter::class, Dummy::class, Employee::class, Company::class, LinkParameterProviderResource::class, Issue7469TestResource::class, Issue7469Dummy::class];
4042
}
4143

4244
/**
4345
* @throws \Throwable
4446
*/
4547
protected function setUp(): void
4648
{
47-
$this->recreateSchema([Dummy::class, RelatedOwnedDummy::class, RelatedDummy::class, Employee::class, Company::class]);
49+
$this->recreateSchema([Dummy::class, RelatedOwnedDummy::class, RelatedDummy::class, Employee::class, Company::class, Issue7469Dummy::class]);
4850
}
4951

5052
public function testReadDummyProviderFromQueryParameter(): void
@@ -183,4 +185,41 @@ public function testUriVariableHasDummy(): void
183185
'dummy' => '/dummies/1',
184186
]);
185187
}
188+
189+
public function testCollectionIdIsCorrect(): void
190+
{
191+
$container = static::getContainer();
192+
if ('mongodb' === $container->getParameter('kernel.environment')) {
193+
$this->markTestSkipped();
194+
}
195+
196+
$manager = $this->getManager();
197+
$dummy = new Dummy();
198+
$dummy->setName('hi');
199+
$manager->persist($dummy);
200+
$manager->flush();
201+
202+
self::createClient()->request('GET', '/link_parameter_provider_resources/'.$dummy->getId());
203+
204+
$this->assertJsonContains([
205+
'@id' => '/link_parameter_provider_resources/1',
206+
]);
207+
}
208+
209+
public function testIssue7469IriGenerationFailsForLinkedResource(): void
210+
{
211+
$container = static::getContainer();
212+
if ('mongodb' === $container->getParameter('kernel.environment')) {
213+
$this->markTestSkipped();
214+
}
215+
216+
$manager = $this->getManager();
217+
$issue7469Dummy = new Issue7469Dummy();
218+
$issue7469Dummy->name = 'Linked Dummy';
219+
$manager->persist($issue7469Dummy);
220+
$manager->flush();
221+
222+
$r = self::createClient()->request('GET', '/issue_7469_test_resources/'.$issue7469Dummy->id, ['headers' => ['Accept' => 'application/ld+json']]);
223+
$this->assertResponseIsSuccessful();
224+
}
186225
}

0 commit comments

Comments
 (0)