Skip to content

Commit 6f61c7e

Browse files
committed
Merge 4.1 into 4.2
2 parents 20f2889 + 7c76fb8 commit 6f61c7e

File tree

8 files changed

+315
-10
lines changed

8 files changed

+315
-10
lines changed

CHANGELOG.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
# Changelog
22

33
## v4.2.3
4-
5-
### Bug fixes
6-
7-
* [4fa6d3fa2](https://github.com/api-platform/core/commit/4fa6d3fa2a8d26b33318a19298cea3cd5ee43470) fix(laravel): groups with input/output
4+
<<<<<<< HEAD
85
* [9416083f7](https://github.com/api-platform/core/commit/9416083f7631b28093f3c79db995862338477137) fix(state): object mapper aware interface (#7486)
96
* [99718d954](https://github.com/api-platform/core/commit/99718d9547ab8b064f1184c7ec2b15d882853dcb) fix(serializer): resilient denormalizeRelation capability (#7474)
107
* [9b2f98610](https://github.com/api-platform/core/commit/9b2f98610cbf661335416880fcd25052468107b3) fix(metadata): eliminate duplicate keys in the constructor of `Parameters` (#7492)
@@ -333,6 +330,17 @@ TypeInfo:
333330
* [cff61eab8](https://github.com/api-platform/core/commit/cff61eab8643f8ed08d59c0684e77740d0d81b04) fix(metadata): append php file resource extractor (#7193)
334331
* [f3d4afe03](https://github.com/api-platform/core/commit/f3d4afe032385f3b665131a365e42706930f0730) fix(symfony): validator type-info
335332

333+
## v4.1.26
334+
335+
### Bug fixes
336+
337+
* [4fa6d3fa2](https://github.com/api-platform/core/commit/4fa6d3fa2a8d26b33318a19298cea3cd5ee43470) fix(laravel): groups with input/output
338+
* [99718d954](https://github.com/api-platform/core/commit/99718d9547ab8b064f1184c7ec2b15d882853dcb) fix(serializer): resilient denormalizeRelation capability (#7474)
339+
* [a26c35840](https://github.com/api-platform/core/commit/a26c358404ed1c100dc3472fe00600368bb611f3) fix(doctrine): properly set properties according to interface (#7487)
340+
* [a2867e986](https://github.com/api-platform/core/commit/a2867e986cea5c63ca79b19cf9a1b929edb94b79) fix(laravel): serializer attributes on Eloquent methods (#7416)
341+
* [ddf4c0b5e](https://github.com/api-platform/core/commit/ddf4c0b5e6bd048ef9b702cd77b89bbbcbbf9a1f) fix(graphql): stateOptions to get filter class (#7485)
342+
* [fafbe5c7b](https://github.com/api-platform/core/commit/fafbe5c7b1418c33baea2506458449562001d2fa) fix(validator): custom message was not translated (#7424)
343+
336344
## v4.1.25
337345

338346
### Bug fixes

src/Metadata/IdentifiersExtractor.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ public function getIdentifiersFromItem(object $item, ?Operation $operation = nul
6464
return $this->getIdentifiersFromOperation($item, $operation, $context);
6565
}
6666

67+
/**
68+
* @param array<string, mixed> $context
69+
*/
6770
private function getIdentifiersFromOperation(object $item, Operation $operation, array $context = []): array
6871
{
6972
if ($operation instanceof HttpOperation) {
@@ -77,24 +80,26 @@ private function getIdentifiersFromOperation(object $item, Operation $operation,
7780
if (1 < (is_countable($link->getIdentifiers()) ? \count($link->getIdentifiers()) : 0)) {
7881
$compositeIdentifiers = [];
7982
foreach ($link->getIdentifiers() as $identifier) {
80-
$compositeIdentifiers[$identifier] = $this->getIdentifierValue($item, $link->getFromClass() ?? $operation->getClass(), $identifier, $link->getParameterName());
83+
$compositeIdentifiers[$identifier] = $this->getIdentifierValue($item, $link->getFromClass() ?? $operation->getClass(), $identifier, $link->getParameterName(), null, $context, $operation);
8184
}
8285

8386
$identifiers[$link->getParameterName()] = CompositeIdentifierParser::stringify($compositeIdentifiers);
8487
continue;
8588
}
8689

8790
$parameterName = $link->getParameterName();
88-
$identifiers[$parameterName] = $this->getIdentifierValue($item, $link->getFromClass() ?? $operation->getClass(), $link->getIdentifiers()[0] ?? $k, $parameterName, $link->getToProperty());
91+
$identifiers[$parameterName] = $this->getIdentifierValue($item, $link->getFromClass() ?? $operation->getClass(), $link->getIdentifiers()[0] ?? $k, $parameterName, $link->getToProperty(), $context, $operation);
8992
}
9093

9194
return $identifiers;
9295
}
9396

9497
/**
9598
* Gets the value of the given class property.
99+
*
100+
* @param array<string, mixed> $context
96101
*/
97-
private function getIdentifierValue(object $item, string $class, string $property, string $parameterName, ?string $toProperty = null): float|bool|int|string
102+
private function getIdentifierValue(object $item, string $class, string $property, string $parameterName, ?string $toProperty, array $context, Operation $operation): float|bool|int|string
98103
{
99104
if ($item instanceof $class) {
100105
try {
@@ -104,6 +109,15 @@ private function getIdentifierValue(object $item, string $class, string $propert
104109
}
105110
}
106111

112+
// ItemUriTemplate is defined on a collection and we read the identifier alghough the PHP class may be different
113+
if (isset($context['item_uri_template']) && $operation->getClass() === $class) {
114+
try {
115+
return $this->resolveIdentifierValue($this->propertyAccessor->getValue($item, $property), $parameterName);
116+
} catch (NoSuchPropertyException $e) {
117+
throw new RuntimeException(\sprintf('Could not retrieve identifier "%s" for class "%s" using itemUriTemplate "%s". Check that the property exists and is accessible.', $property, $class, $context['item_uri_template']), $e->getCode(), $e);
118+
}
119+
}
120+
107121
if ($toProperty) {
108122
return $this->resolveIdentifierValue($this->propertyAccessor->getValue($item, "$toProperty.$property"), $parameterName);
109123
}

src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ private function registerMetadataConfiguration(ContainerBuilder $container, arra
409409
$container->getDefinition('api_platform.metadata.resource_extractor.xml')->replaceArgument(0, $xmlResources);
410410
$container->getDefinition('api_platform.metadata.property_extractor.xml')->replaceArgument(0, $xmlResources);
411411

412-
if (class_exists(PhpDocParser::class)) {
412+
if ($config['enable_phpdoc_parser'] && class_exists(PhpDocParser::class)) {
413413
$loader->load('metadata/php_doc.php');
414414
}
415415

src/Symfony/Bundle/DependencyInjection/Configuration.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ public function getConfigTreeBuilder(): TreeBuilder
116116
->booleanNode('enable_entrypoint')->defaultTrue()->info('Enable the entrypoint')->end()
117117
->booleanNode('enable_docs')->defaultTrue()->info('Enable the docs')->end()
118118
->booleanNode('enable_profiler')->defaultTrue()->info('Enable the data collector and the WebProfilerBundle integration.')->end()
119+
->booleanNode('enable_phpdoc_parser')->defaultTrue()->info('Enable resource metadata collector using PHPStan PhpDocParser.')->end()
119120
->booleanNode('enable_link_security')->defaultFalse()->info('Enable security for Links (sub resources)')->end()
120121
->arrayNode('collection')
121122
->addDefaultsIfNotSet()
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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\ItemUriTemplateWithCollection;
15+
16+
use ApiPlatform\Doctrine\Orm\State\Options;
17+
use ApiPlatform\Metadata\Get;
18+
use ApiPlatform\Metadata\Operation;
19+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Recipe as EntityRecipe;
20+
21+
#[Get(
22+
uriTemplate: '/item_uri_template_recipes/{id}{._format}',
23+
shortName: 'ItemRecipe',
24+
uriVariables: ['id'],
25+
provider: [self::class, 'provide'],
26+
openapi: false
27+
)]
28+
#[Get(
29+
uriTemplate: '/item_uri_template_recipes_state_option/{id}{._format}',
30+
shortName: 'ItemRecipe',
31+
uriVariables: ['id'],
32+
openapi: false,
33+
stateOptions: new Options(entityClass: EntityRecipe::class)
34+
)]
35+
class Recipe
36+
{
37+
public ?string $id;
38+
public ?string $name = null;
39+
40+
public ?string $description = null;
41+
42+
public ?string $author = null;
43+
44+
public ?array $recipeIngredient = [];
45+
46+
public ?string $recipeInstructions = null;
47+
48+
public ?string $prepTime = null;
49+
50+
public ?string $cookTime = null;
51+
52+
public ?string $totalTime = null;
53+
54+
public ?string $recipeCuisine = null;
55+
56+
public ?string $suitableForDiet = null;
57+
58+
public static function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
59+
{
60+
$recipe = new self();
61+
$recipe->id = '1';
62+
$recipe->name = 'Dummy Recipe';
63+
$recipe->description = 'A simple recipe for testing purposes.';
64+
$recipe->prepTime = 'PT15M';
65+
$recipe->cookTime = 'PT30M';
66+
$recipe->totalTime = 'PT45M';
67+
$recipe->recipeIngredient = ['Ingredient 1', 'Ingredient 2'];
68+
$recipe->recipeInstructions = 'Do these things.';
69+
70+
return $recipe;
71+
}
72+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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\ItemUriTemplateWithCollection;
15+
16+
use ApiPlatform\Doctrine\Orm\State\Options;
17+
use ApiPlatform\Metadata\GetCollection;
18+
use ApiPlatform\Metadata\Operation;
19+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Recipe as EntityRecipe;
20+
21+
#[GetCollection(
22+
uriTemplate: '/item_uri_template_recipes{._format}',
23+
provider: [self::class, 'provide'],
24+
openapi: false,
25+
shortName: 'CollectionRecipe',
26+
itemUriTemplate: '/item_uri_template_recipes/{id}{._format}',
27+
normalizationContext: ['hydra_prefix' => false],
28+
)]
29+
#[GetCollection(
30+
uriTemplate: '/item_uri_template_recipes_state_option{._format}',
31+
openapi: false,
32+
shortName: 'CollectionRecipe',
33+
itemUriTemplate: '/item_uri_template_recipes_state_option/{id}{._format}',
34+
stateOptions: new Options(entityClass: EntityRecipe::class),
35+
normalizationContext: ['hydra_prefix' => false],
36+
)]
37+
class RecipeCollection
38+
{
39+
public ?string $id;
40+
public ?string $name = null;
41+
42+
public static function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
43+
{
44+
$recipe = new self();
45+
$recipe->id = '1';
46+
$recipe->name = 'Dummy Recipe';
47+
48+
$recipe2 = new self();
49+
$recipe2->id = '2';
50+
$recipe2->name = 'Dummy Recipe 2';
51+
52+
return [$recipe, $recipe2];
53+
}
54+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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 Doctrine\ORM\Mapping as ORM;
17+
18+
#[ORM\Entity]
19+
class Recipe
20+
{
21+
#[ORM\Id]
22+
#[ORM\GeneratedValue]
23+
#[ORM\Column(type: 'integer')]
24+
private ?int $id = null;
25+
26+
#[ORM\Column(type: 'string', nullable: true)]
27+
public ?string $name = null;
28+
29+
#[ORM\Column(type: 'text', nullable: true)]
30+
public ?string $description = null;
31+
32+
#[ORM\Column(type: 'string', nullable: true)]
33+
public ?string $author = null;
34+
35+
#[ORM\Column(type: 'json', nullable: true)]
36+
public ?array $recipeIngredient = [];
37+
38+
#[ORM\Column(type: 'text', nullable: true)]
39+
public ?string $recipeInstructions = null;
40+
41+
#[ORM\Column(type: 'string', nullable: true)]
42+
public ?string $prepTime = null;
43+
44+
#[ORM\Column(type: 'string', nullable: true)]
45+
public ?string $cookTime = null;
46+
47+
#[ORM\Column(type: 'string', nullable: true)]
48+
public ?string $totalTime = null;
49+
50+
#[ORM\Column(type: 'string', nullable: true)]
51+
public ?string $recipeCategory = null;
52+
53+
#[ORM\Column(type: 'string', nullable: true)]
54+
public ?string $recipeCuisine = null;
55+
56+
#[ORM\Column(type: 'string', nullable: true)]
57+
public ?string $suitableForDiet = null;
58+
59+
public function getId(): ?int
60+
{
61+
return $this->id;
62+
}
63+
}

0 commit comments

Comments
 (0)