Skip to content

Commit 7861f97

Browse files
authored
Merge pull request #5228 from soyuka/merge-2.7
Merge 2.7
2 parents 84a7e56 + fa2cf88 commit 7861f97

File tree

9 files changed

+113
-20
lines changed

9 files changed

+113
-20
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,17 @@ Breaking changes:
8989
* Serializer: `skip_null_values` now defaults to `true`
9090
* Metadata: `Patch` is added to the automatic CRUD
9191

92+
## v2.7.5
93+
94+
### Bug fixes
95+
96+
* [096ac119a](https://github.com/api-platform/core/commit/096ac119a5126bdc5e7877172a033d7cdaa28983) fix(metadata): keep configured uri variables (#5217)
97+
* [2b2d468f0](https://github.com/api-platform/core/commit/2b2d468f06a63ecfa4928d5d631953acb624c181) fix(metadata): operations must inherit from resource and defaults
98+
* [2cb3b4272](https://github.com/api-platform/core/commit/2cb3b42725105aaf34dc9d71d2c03e156acd5833) fix(serializer): use iri from $context if defined (#5201)
99+
* [39398579e](https://github.com/api-platform/core/commit/39398579e32976b5b4b0219da98fdb35629a35ad) fix(symfony): definition when mercure is not installed (#5206)
100+
* [e9c7e4abb](https://github.com/api-platform/core/commit/e9c7e4abb683bb830a61712a8b63b8063e015b13) fix(serializer): avoid call to legacy iri converter with non-resource class (#5219)
101+
* [ebaad51b2](https://github.com/api-platform/core/commit/ebaad51b2ce173b6c59582dcc6fb311f1f4b7fa9) fix(serializer): read groups off the root operation (#5196)
102+
92103
## v2.7.4
93104

94105
### Bug fixes

features/main/attribute_resource.feature

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
@php8
2+
@v3
3+
@!mysql
4+
@!mongodb
15
Feature: Resource attributes
26
In order to use the Resource attribute
37
As a developer
48
I should be able to fetch data from a state provider
59

6-
@php8
7-
@!mysql
8-
@!mongodb
910
Scenario: Retrieve a Resource collection
1011
When I add "Content-Type" header equal to "application/ld+json"
1112
And I send a "GET" request to "/attribute_resources"
@@ -35,9 +36,6 @@ Feature: Resource attributes
3536
}
3637
"""
3738

38-
@php8
39-
@!mysql
40-
@!mongodb
4139
Scenario: Retrieve the first resource
4240
When I add "Content-Type" header equal to "application/ld+json"
4341
And I send a "GET" request to "/attribute_resources/1"
@@ -55,9 +53,6 @@ Feature: Resource attributes
5553
}
5654
"""
5755

58-
@php8
59-
@!mysql
60-
@!mongodb
6156
Scenario: Retrieve the aliased resource
6257
When I add "Content-Type" header equal to "application/ld+json"
6358
And I send a "GET" request to "/dummy/1/attribute_resources/2"
@@ -77,9 +72,6 @@ Feature: Resource attributes
7772
}
7873
"""
7974

80-
@php8
81-
@!mysql
82-
@!mongodb
8375
Scenario: Patch the aliased resource
8476
When I add "Content-Type" header equal to "application/merge-patch+json"
8577
And I send a "PATCH" request to "/dummy/1/attribute_resources/2" with body:
@@ -101,3 +93,10 @@ Feature: Resource attributes
10193
"name": "Patched"
10294
}
10395
"""
96+
97+
Scenario: Uri variables should be configured properly
98+
When I send a "GET" request to "/photos/1/resize/300/100"
99+
Then the response status code should be 400
100+
And the response should be in JSON
101+
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
102+
And the JSON node "hydra:description" should be equal to 'Unable to generate an IRI for the item of type "ApiPlatform\Tests\Fixtures\TestBundle\Entity\IncompleteUriVariableConfigured"'

src/Doctrine/Odm/State/LinksHandlerTrait.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ private function handleLinks(Builder $aggregationBuilder, array $identifiers, ar
3737
return;
3838
}
3939

40+
foreach ($links as $i => $link) {
41+
if (null !== $link->getExpandedValue()) {
42+
unset($links[$i]);
43+
}
44+
}
45+
4046
$executeOptions = $operation->getExtraProperties()['doctrine_mongodb']['execute_options'] ?? [];
4147

4248
$this->buildAggregation($resourceClass, array_reverse($links), array_reverse($identifiers), $context, $executeOptions, $resourceClass, $aggregationBuilder);

src/Doctrine/Orm/State/LinksHandlerTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ private function handleLinks(QueryBuilder $queryBuilder, array $identifiers, Que
4545
$identifiers = array_reverse($identifiers);
4646

4747
foreach (array_reverse($links) as $link) {
48-
if ($link->getExpandedValue() || !$link->getFromClass()) {
48+
if (null !== $link->getExpandedValue() || !$link->getFromClass()) {
4949
continue;
5050
}
5151

src/Metadata/Resource/Factory/UriTemplateResourceMetadataCollectionFactory.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,9 @@ private function configureUriVariables(ApiResource|HttpOperation $operation): Ap
137137
return $this->normalizeUriVariables($operation);
138138
}
139139

140+
$hasUserConfiguredUriVariables = !($operation->getExtraProperties['is_legacy_resource_metadata'] ?? false);
140141
if (!$operation->getUriVariables()) {
142+
$hasUserConfiguredUriVariables = false;
141143
$operation = $operation->withUriVariables($this->transformLinksToUriVariables($this->linkFactory->createLinksFromIdentifiers($operation)));
142144
}
143145

@@ -164,6 +166,10 @@ private function configureUriVariables(ApiResource|HttpOperation $operation): Ap
164166
$variables = $route->getPathVariables();
165167

166168
if (\count($variables) !== \count($uriVariables)) {
169+
if ($hasUserConfiguredUriVariables) {
170+
return $operation;
171+
}
172+
167173
$newUriVariables = [];
168174
foreach ($variables as $variable) {
169175
if (isset($uriVariables[$variable])) {

src/OpenApi/Factory/OpenApiFactory.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ private function collectPaths(ApiResource $resource, ResourceMetadataCollection
189189

190190
// Set up parameters
191191
foreach ($uriVariables ?? [] as $parameterName => $uriVariable) {
192+
if ($uriVariable->getExpandedValue() ?? false) {
193+
continue;
194+
}
195+
192196
$parameter = new Parameter($parameterName, 'path', (new \ReflectionClass($uriVariable->getFromClass()))->getShortName().' identifier', true, false, false, ['type' => 'string']);
193197
if ($this->hasParameter($parameter, $parameters)) {
194198
continue;

tests/Fixtures/TestBundle/Entity/Company.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,7 @@
2525
#[GetCollection]
2626
#[Get]
2727
#[Post]
28-
#[Get(
29-
uriTemplate: '/employees/{employeeId}/rooms/{roomId}/company/{companyId}',
30-
uriVariables: [
31-
'employeeId' => ['from_class' => Employee::class, 'from_property' => 'company'],
32-
],
33-
)]
34-
#[Get(
28+
#[ApiResource(
3529
uriTemplate: '/employees/{employeeId}/company',
3630
uriVariables: [
3731
'employeeId' => ['from_class' => Employee::class, 'from_property' => 'company'],
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\Get;
17+
use ApiPlatform\Metadata\Operation;
18+
19+
#[Get(uriTemplate: '/photos/{id}/resize/{width}/{height}', uriVariables: ['id'], provider: [IncompleteUriVariableConfigured::class, 'provide'], openapi: false)]
20+
final class IncompleteUriVariableConfigured
21+
{
22+
public function __construct(public string $id)
23+
{
24+
}
25+
26+
public static function provide(Operation $operation, array $uriVariables = [], array $context = []): self
27+
{
28+
if (isset($uriVariables['width'])) {
29+
throw new \LogicException('URI variable "width" should not exist');
30+
}
31+
32+
return new self($uriVariables['id']);
33+
}
34+
}

tests/Serializer/ItemNormalizerTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,45 @@ public function testDenormalizeWithIdAndUpdateNotAllowed(): void
201201
$normalizer->denormalize(['id' => '12', 'name' => 'hello'], Dummy::class, null, $context);
202202
}
203203

204+
public function testDenormalizeWithDefinedIri(): void
205+
{
206+
$dummy = new Dummy();
207+
$dummy->setName('hello');
208+
209+
$propertyNameCollection = new PropertyNameCollection(['name']);
210+
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
211+
$propertyNameCollectionFactoryProphecy->create(Dummy::class, [])->willReturn($propertyNameCollection);
212+
213+
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
214+
$resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true);
215+
216+
$propertyMetadata = (new ApiProperty())->withReadable(true);
217+
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
218+
$propertyMetadataFactoryProphecy->create(Dummy::class, 'name', [])->willReturn($propertyMetadata);
219+
220+
$iriConverterProphecy = $this->prophesize(IriConverterInterface::class);
221+
$iriConverterProphecy->getIriFromResource($dummy)->shouldNotBeCalled();
222+
223+
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
224+
$resourceClassResolverProphecy->getResourceClass($dummy, null)->willReturn(Dummy::class);
225+
$resourceClassResolverProphecy->getResourceClass(null, Dummy::class)->willReturn(Dummy::class);
226+
$resourceClassResolverProphecy->isResourceClass(Dummy::class)->willReturn(true);
227+
228+
$serializerProphecy = $this->prophesize(SerializerInterface::class);
229+
$serializerProphecy->willImplement(NormalizerInterface::class);
230+
$serializerProphecy->normalize('hello', null, Argument::type('array'))->willReturn('hello');
231+
232+
$normalizer = new ItemNormalizer(
233+
$propertyNameCollectionFactoryProphecy->reveal(),
234+
$propertyMetadataFactoryProphecy->reveal(),
235+
$iriConverterProphecy->reveal(),
236+
$resourceClassResolverProphecy->reveal()
237+
);
238+
$normalizer->setSerializer($serializerProphecy->reveal());
239+
240+
$this->assertEquals(['name' => 'hello'], $normalizer->normalize($dummy, null, ['resources' => [], 'iri' => '/custom']));
241+
}
242+
204243
public function testDenormalizeWithIdAndNoResourceClass(): void
205244
{
206245
$context = [];

0 commit comments

Comments
 (0)