Skip to content

Commit b3bc4d6

Browse files
authored
fix: use legacy iri converter for legacy resources (#5172)
* fix: use legacy iri converter for legacy resources when the backward compatibility layer is `false` we can still use legacy resources while upgrading and therefore the legacy IriConverter is needed as it calls legacy providers
1 parent 706f66f commit b3bc4d6

File tree

12 files changed

+255
-15
lines changed

12 files changed

+255
-15
lines changed

features/main/relation.feature

+9
Original file line numberDiff line numberDiff line change
@@ -548,3 +548,12 @@ Feature: Relations support
548548
}
549549
"""
550550

551+
@createSchema
552+
@!mongodb
553+
Scenario: Issue #5094
554+
When I add "Content-Type" header equal to "application/ld+json"
555+
And I send a "POST" request to "/issue5094_resources" with body:
556+
"""
557+
{"relation": "/issue5094_relations/1"}
558+
"""
559+
Then the response status code should be 201

src/Core/Api/LegacyIriConverter.php

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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\Api;
15+
16+
use ApiPlatform\Api\IriConverterInterface;
17+
use ApiPlatform\Api\UrlGeneratorInterface;
18+
use ApiPlatform\Core\Api\IriConverterInterface as LegacyIriConverterInterface;
19+
use ApiPlatform\Metadata\Operation;
20+
21+
/**
22+
* This IRI converter calls the legacy IriConverter on legacy resources.
23+
*
24+
* @author Antoine Bluchet <[email protected]>
25+
*
26+
* @internal
27+
*/
28+
final class LegacyIriConverter implements IriConverterInterface
29+
{
30+
private $legacyIriConverter;
31+
private $iriConverter;
32+
33+
public function __construct(LegacyIriConverterInterface $legacyIriConverter, IriConverterInterface $iriConverter)
34+
{
35+
$this->legacyIriConverter = $legacyIriConverter;
36+
$this->iriConverter = $iriConverter;
37+
}
38+
39+
/**
40+
* {@inheritdoc}
41+
*/
42+
public function getResourceFromIri(string $iri, array $context = [], ?Operation $operation = null)
43+
{
44+
if (!$operation && !($operation = $context['operation'] ?? null)) {
45+
return $this->iriConverter->getResourceFromIri($iri, $context);
46+
}
47+
48+
if (!($operation->getExtraProperties()['is_legacy_resource_metadata'] ?? false) && !($operation->getExtraProperties()['is_legacy_subresource'] ?? false)) {
49+
return $this->iriConverter->getResourceFromIri($iri, $context, $operation);
50+
}
51+
52+
return $this->legacyIriConverter->getItemFromIri($iri, $context);
53+
}
54+
55+
/**
56+
* {@inheritdoc}
57+
*/
58+
public function getIriFromResource($item, int $referenceType = UrlGeneratorInterface::ABS_PATH, Operation $operation = null, array $context = []): ?string
59+
{
60+
return $this->iriConverter->getIriFromResource($item, $referenceType, $operation, $context);
61+
}
62+
}

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

+14
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,20 @@
146146
</service>
147147
<service id="ApiPlatform\Api\IriConverterInterface" alias="api_platform.symfony.iri_converter" />
148148

149+
<service id="api_platform.iri_converter.legacy" class="ApiPlatform\Core\Bridge\Symfony\Routing\IriConverter" public="false">
150+
<argument type="service" id="api_platform.metadata.property.name_collection_factory" />
151+
<argument type="service" id="api_platform.metadata.property.metadata_factory.legacy" />
152+
<argument type="service" id="api_platform.item_data_provider" />
153+
<argument type="service" id="api_platform.route_name_resolver" />
154+
<argument type="service" id="api_platform.router" />
155+
<argument type="service" id="api_platform.property_accessor" />
156+
<argument type="service" id="api_platform.identifiers_extractor.cached" />
157+
<argument type="service" id="api_platform.subresource_data_provider" on-invalid="ignore" />
158+
<argument type="service" id="api_platform.identifier.converter" on-invalid="ignore" />
159+
<argument type="service" id="api_platform.resource_class_resolver" />
160+
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
161+
</service>
162+
149163
<service id="api_platform.symfony.iri_converter.skolem" class="ApiPlatform\Symfony\Routing\SkolemIriConverter" public="false">
150164
<argument type="service" id="api_platform.router" />
151165
</service>

src/Symfony/Bundle/Resources/config/legacy/api.xml

-13
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,6 @@
4545
<argument type="service" id="api_platform.subresource_operation_factory" />
4646
</service>
4747

48-
<service id="api_platform.iri_converter.legacy" class="ApiPlatform\Core\Bridge\Symfony\Routing\IriConverter" public="false">
49-
<argument type="service" id="api_platform.metadata.property.name_collection_factory" />
50-
<argument type="service" id="api_platform.metadata.property.metadata_factory.legacy" />
51-
<argument type="service" id="api_platform.item_data_provider" />
52-
<argument type="service" id="api_platform.route_name_resolver" />
53-
<argument type="service" id="api_platform.router" />
54-
<argument type="service" id="api_platform.property_accessor" />
55-
<argument type="service" id="api_platform.identifiers_extractor.cached" />
56-
<argument type="service" id="api_platform.subresource_data_provider" on-invalid="ignore" />
57-
<argument type="service" id="api_platform.identifier.converter" on-invalid="ignore" />
58-
<argument type="service" id="api_platform.resource_class_resolver" />
59-
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
60-
</service>
6148
<service id="ApiPlatform\Core\Api\IriConverterInterface" alias="api_platform.iri_converter.legacy" />
6249

6350
<service id="api_platform.listener.request.add_format" class="ApiPlatform\Symfony\EventListener\AddFormatListener">

src/Symfony/Bundle/Resources/config/v3/api.xml

+4-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
<tag name="routing.loader" />
2525
</service>
2626

27-
<service id="api_platform.iri_converter" alias="api_platform.symfony.iri_converter" />
27+
<service id="api_platform.iri_converter" class="ApiPlatform\Core\Api\LegacyIriConverter">
28+
<argument type="service" id="api_platform.iri_converter.legacy" />
29+
<argument type="service" id="api_platform.symfony.iri_converter" />
30+
</service>
2831
</services>
2932
</container>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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\DataProvider;
15+
16+
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
17+
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
18+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue5094Relation;
19+
20+
/**
21+
* @author Kévin Dunglas <[email protected]>
22+
*/
23+
class Issue5094RelationDataProvider implements ItemDataProviderInterface, RestrictedDataProviderInterface
24+
{
25+
public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
26+
{
27+
return Issue5094Relation::class === $resourceClass;
28+
}
29+
30+
/**
31+
* {@inheritdoc}
32+
*/
33+
public function getItem(string $resourceClass, $id, string $operationName = null, array $context = [])
34+
{
35+
return new Issue5094Relation((int) $id);
36+
}
37+
}
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\Entity;
15+
16+
use ApiPlatform\Core\Annotation\ApiProperty;
17+
use ApiPlatform\Core\Annotation\ApiResource;
18+
19+
/**
20+
* A legacy relation with a custom provider.
21+
*
22+
* @ApiResource
23+
*/
24+
class Issue5094Relation
25+
{
26+
public function __construct(int $id)
27+
{
28+
$this->id = $id;
29+
}
30+
31+
/**
32+
* @ApiProperty(identifier=true)
33+
*/
34+
public $id;
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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\Core\Annotation\ApiResource;
17+
use Doctrine\ORM\Mapping as ORM;
18+
19+
/**
20+
* A legacy resource with a relation that has a custom data provider.
21+
*
22+
* @ApiResource
23+
*
24+
* @ORM\Entity
25+
*/
26+
class Issue5094Resource
27+
{
28+
/**
29+
* @var int|null The id
30+
*
31+
* @ORM\Column(type="integer")
32+
* @ORM\Id
33+
* @ORM\GeneratedValue(strategy="AUTO")
34+
*/
35+
private $id;
36+
37+
/**
38+
* @var Issue5094Relation
39+
*/
40+
public $relation;
41+
42+
public function getId(): ?int
43+
{
44+
return $this->id;
45+
}
46+
}

tests/Fixtures/TestBundle/Metadata/ProviderResourceMetadatatCollectionFactory.php

+6
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
use ApiPlatform\Tests\Fixtures\TestBundle\Document\ContainNonResource as ContainNonResourceDocument;
1919
use ApiPlatform\Tests\Fixtures\TestBundle\Document\Taxon as TaxonDocument;
2020
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\ContainNonResource;
21+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue5094Relation;
2122
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\ResourceInterface;
2223
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Taxon;
2324
use ApiPlatform\Tests\Fixtures\TestBundle\Model\ResourceInterface as ResourceInterfaceDocument;
2425
use ApiPlatform\Tests\Fixtures\TestBundle\Model\SerializableResource;
2526
use ApiPlatform\Tests\Fixtures\TestBundle\Model\TaxonInterface;
2627
use ApiPlatform\Tests\Fixtures\TestBundle\State\ContainNonResourceProvider;
28+
use ApiPlatform\Tests\Fixtures\TestBundle\State\Issue5094RelationProvider;
2729
use ApiPlatform\Tests\Fixtures\TestBundle\State\ResourceInterfaceImplementationProvider;
2830
use ApiPlatform\Tests\Fixtures\TestBundle\State\SerializableProvider;
2931
use ApiPlatform\Tests\Fixtures\TestBundle\State\TaxonItemProvider;
@@ -63,6 +65,10 @@ public function create(string $resourceClass): ResourceMetadataCollection
6365
return $this->setProvider($resourceMetadataCollection, TaxonItemProvider::class);
6466
}
6567

68+
if (Issue5094Relation::class === $resourceClass) {
69+
return $this->setProvider($resourceMetadataCollection, Issue5094RelationProvider::class);
70+
}
71+
6672
return $resourceMetadataCollection;
6773
}
6874

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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\State;
15+
16+
use ApiPlatform\Metadata\Operation;
17+
use ApiPlatform\State\ProviderInterface;
18+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue5094Relation;
19+
20+
/**
21+
* @author Kévin Dunglas <[email protected]>
22+
*/
23+
class Issue5094RelationProvider implements ProviderInterface
24+
{
25+
public function provide(Operation $operation, array $uriVariables = [], array $context = [])
26+
{
27+
return new Issue5094Relation((int) $uriVariables['id']);
28+
}
29+
}

tests/Fixtures/app/config/config_common.yml

+12
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ services:
107107
tags:
108108
- { name: 'api_platform.state_provider' }
109109

110+
ApiPlatform\Tests\Fixtures\TestBundle\State\Issue5094RelationProvider:
111+
class: 'ApiPlatform\Tests\Fixtures\TestBundle\State\Issue5094RelationProvider'
112+
public: false
113+
tags:
114+
- { name: 'api_platform.state_provider' }
115+
110116
ApiPlatform\Tests\Fixtures\TestBundle\State\DummyCollectionDtoProvider:
111117
class: 'ApiPlatform\Tests\Fixtures\TestBundle\State\DummyCollectionDtoProvider'
112118
public: false
@@ -165,6 +171,12 @@ services:
165171
tags:
166172
- { name: 'api_platform.item_data_provider' }
167173

174+
issue5094_relation.item_data_provider:
175+
class: 'ApiPlatform\Tests\Fixtures\TestBundle\DataProvider\Issue5094RelationDataProvider'
176+
public: false
177+
tags:
178+
- { name: 'api_platform.item_data_provider' }
179+
168180
serializable.item_data_provider:
169181
class: 'ApiPlatform\Tests\Fixtures\TestBundle\DataProvider\SerializableItemDataProvider'
170182
public: false

tests/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -436,11 +436,11 @@ public function testCommonConfigurationWithoutMetadataBackwardCompatibilityLayer
436436
'api_platform.metadata.resource.metadata_collection_factory.legacy_subresource_metadata',
437437
'api_platform.listener.view.write.legacy',
438438
'api_platform.listener.request.read.legacy',
439+
'api_platform.iri_converter',
439440
];
440441

441442
$aliases = [
442443
// v3/api.xml
443-
'api_platform.iri_converter',
444444
'ApiPlatform\Api\IriConverterInterface',
445445
'api_platform.identifiers_extractor',
446446
'ApiPlatform\Api\IdentifiersExtractorInterface',

0 commit comments

Comments
 (0)