Skip to content

Commit 6f90626

Browse files
committed
Merge 3.2
2 parents 49c8119 + de8d583 commit 6f90626

File tree

10 files changed

+204
-44
lines changed

10 files changed

+204
-44
lines changed

.github/workflows/subtree.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ on:
66
branches:
77
- main
88
- 3.1
9+
- 3.2
910

1011
env:
1112
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}

CHANGELOG.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,72 @@
11
# Changelog
22

3+
## v3.2.0
4+
5+
### Bug fixes
6+
7+
* [2e48c7ecc](https://github.com/api-platform/core/commit/2e48c7ecccde87653bfc859c5f8b96cc37b8fe51) fix(jsonschema): do not override nor complete ApiProperty::schema user value (#5855, #5864)
8+
* [33b1658a0](https://github.com/api-platform/core/commit/33b1658a0e100e0ca9e7bf46aa2307ead9b1744e) fix(serializer): disable_type_enforcement with null values (#5593)
9+
* [3953f6f0a](https://github.com/api-platform/core/commit/3953f6f0a37e38fd8a3d6b0d9faa80f59e00ec01) fix(state): read provider without request (#5803)
10+
* [49981505a](https://github.com/api-platform/core/commit/49981505a8af281d00e35f1424432fae65686eb8) fix(metadata): convert composite uri variables w/ proper type
11+
* [4ac62b0c2](https://github.com/api-platform/core/commit/4ac62b0c2d88b95d58f2e9477579ceca28313874) fix(jsonschema): build non-resource class schema (#5842)
12+
* [51e4295b2](https://github.com/api-platform/core/commit/51e4295b26e606c5da10d434b6e98dadb8a243b2) fix: missing parent construct calls with named arguments (#5387)
13+
* [6c9e121db](https://github.com/api-platform/core/commit/6c9e121db88256d79c9c4c78c05993b3465c025e) fix(elasticsearch): elasticsearch 8 compatibility (#5795)
14+
* [7ecfdff85](https://github.com/api-platform/core/commit/7ecfdff85e997feafab1377ae6309e273a4e9678) fix(symfony): graphql security/validator only when enabled
15+
* [b58ec1207](https://github.com/api-platform/core/commit/b58ec1207da8ba5b669937508a17451af61b0688) fix(metadata): correct interface aliases (#5766)
16+
* [c353e5aa4](https://github.com/api-platform/core/commit/c353e5aa474d7a2e6c701bfa1c369b560e928c17) fix(graphql): do not add id field if operation already has a dedicated input type (#5095)
17+
* [c76d9b0b7](https://github.com/api-platform/core/commit/c76d9b0b7819036f684da214ad6fac2c3c7fa852) fix(serializer): allow usage of genId property for collection (#5870)
18+
19+
20+
### Features
21+
22+
* [0d04f28f2](https://github.com/api-platform/core/commit/0d04f28f230f5e9ab789644caba7efac1fe20cfa) feat(metadata): improve CreateProvider (#5770)
23+
* [2141b0118](https://github.com/api-platform/core/commit/2141b01189a25b8a242a6878bcafb3be276f8a41) feat: deprecate not setting formats manually (#5808)
24+
* [2cf9d552a](https://github.com/api-platform/core/commit/2cf9d552aa3b8b14820fc71e79cb6bf74347eaa8) feat: improve 'not_normalizable_value_exception' (#5844)
25+
* [3fa0176a3](https://github.com/api-platform/core/commit/3fa0176a34a7cbc24a612b69404dc8c6be82f8a6) feat(metadata): add canonical_uri_template (#5832)
26+
* [46e84ffc1](https://github.com/api-platform/core/commit/46e84ffc182df12221967ab91403f2b0692847be) feat(symfony): add mercure asserts (#5764)
27+
* [4ef0ef856](https://github.com/api-platform/core/commit/4ef0ef856ced658ac942fd6a2c6f7c5c563078d1) feat: error as resources, jsonld errors are now problem-compliant (#5433)
28+
* [6babb3d6b](https://github.com/api-platform/core/commit/6babb3d6b707290fdf314c0e96acd525d6f96670) feat: replace doctrine/inflector by symfony/string (#5637)
29+
* [7a1d351b0](https://github.com/api-platform/core/commit/7a1d351b0a37fc7107c548708f4b9e38a9dedc76) feat(tests): add a method to generate the IRI from a resource (#5582)
30+
* [851aa3778](https://github.com/api-platform/core/commit/851aa3778ef8a6f959a44b759fc343e9f8cfc8bf) feat(graphql)!: add extra args for custom queries or mutations (#5359)
31+
* [92a81f024](https://github.com/api-platform/core/commit/92a81f024541054b9322e7457b75c721261e14e0) feat(graphql): allow to disable the introspection query (#5711)
32+
* [b9cf49969](https://github.com/api-platform/core/commit/b9cf49969e4207ca6044338d992eb8ff97f5740e) feat(openapi): update Swagger UI to v5.6.2 (#5807)
33+
* [ccef472ca](https://github.com/api-platform/core/commit/ccef472cade42b189fa8cb7793e27fad1349e289) feat(openapi): use OpenAPI 3.1 (#5489)
34+
* [c7dcd3669](https://github.com/api-platform/core/commit/c7dcd36690927bdf3bd08055cdf4fff5c08de4da) feat(doctrine): stateOptions can handleLinks for query optimization (#5732)
35+
* [d793ffb92](https://github.com/api-platform/core/commit/d793ffb9228a21655ee35f0b90a959f93281a4cf) feat: union/intersect types (#5470)
36+
* [d85884d53](https://github.com/api-platform/core/commit/d85884d53bda3f0bfc60435f5b0e69e7522d70c8) feat(elasticsearch): filtering on nested fields (#5820)
37+
* [e65d2c35a](https://github.com/api-platform/core/commit/e65d2c35a983813de55104ebd12c49bdfeb8cdc5) feat(serializer): add ApiProperty::uriTemplate option (#5675)
38+
39+
### Notes
40+
41+
Use `composer recipes:update` to update your configuration file. The default configuration file is:
42+
43+
```yaml
44+
api_platform:
45+
title: Hello API Platform
46+
version: 1.0.0
47+
formats:
48+
jsonld: ['application/ld+json']
49+
docs_formats:
50+
jsonld: ['application/ld+json']
51+
jsonopenapi: ['application/vnd.openapi+json']
52+
html: ['text/html']
53+
defaults:
54+
stateless: true
55+
cache_headers:
56+
vary: ['Content-Type', 'Authorization', 'Origin']
57+
extra_properties:
58+
standard_put: true
59+
rfc_7807_compliant_errors: true # this will be the default value in 4.x
60+
event_listeners_backward_compatibility_layer: false # use symfony event listeners
61+
keep_legacy_inflector: false # use doctrine/inflector
62+
```
63+
64+
Listeners will not get removed in API Platform 4 but will rather use our new Providers and Processors. You can now force the request to go through a particular state for example:
65+
66+
```php
67+
#[Post(read: true)] // to force reading even though it's a POST
68+
```
69+
370
## v3.2.0-beta.2
471

572
### Bug fixes
@@ -80,6 +147,20 @@ Notes:
80147
* [92a81f024](https://github.com/api-platform/core/commit/92a81f024541054b9322e7457b75c721261e14e0) feat(graphql): allow to disable the introspection query (#5711)
81148
* [d793ffb92](https://github.com/api-platform/core/commit/d793ffb9228a21655ee35f0b90a959f93281a4cf) feat: union/intersect types (#5470)
82149

150+
## v3.1.20
151+
152+
### Bug fixes
153+
154+
* [eebc7c5a0](https://github.com/api-platform/core/commit/eebc7c5a0bd4d2138f706b8309f53d0b972b21d4) fix: add itemUriTemplate to resources.xsd (#5872)
155+
156+
## v3.1.19
157+
158+
### Bug fixes
159+
160+
* [6a62a53f8](https://github.com/api-platform/core/commit/6a62a53f854ec93947d1c4a5a32007df09e55d06) fix(hydra): add xxx[] hydra:search iexact
161+
* [7f0e00cd2](https://github.com/api-platform/core/commit/7f0e00cd2d838037f716e0b8588a6529ef9f158c) fix(mercure): custom topics on newly created entities causes error #5074
162+
* [1fccb8413](https://github.com/api-platform/core/commit/1fccb8413a902a1011f049d0f8ddcd8d5456d335) fix(doctrine): add SearchFilter case-insensitive strategies constants
163+
83164
## v3.1.18
84165

85166
## v3.1.17

features/main/validation.feature

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -84,26 +84,10 @@ Feature: Using validations groups
8484
"""
8585
Then the response status code should be 422
8686
And the response should be in JSON
87-
And the JSON should be equal to:
88-
"""
89-
{
90-
"@id": "/validation_errors/ad32d13f-c3d4-423b-909a-857b961eb720",
91-
"@type": "ConstraintViolationList",
92-
"status": 422,
93-
"violations": [
94-
{
95-
"propertyPath": "test",
96-
"message": "This value should not be null.",
97-
"code": "ad32d13f-c3d4-423b-909a-857b961eb720"
98-
}
99-
],
100-
"hydra:title": "An error occurred",
101-
"hydra:description": "title: This value should not be null.",
102-
"type": "/validation_errors/ad32d13f-c3d4-423b-909a-857b961eb720",
103-
"title": "An error occurred",
104-
"detail": "title: This value should not be null."
105-
}
106-
"""
87+
And the JSON node "violations[0].message" should be equal to "This value should not be null."
88+
And the JSON node "violations[0].propertyPath" should be equal to "test"
89+
And the JSON node "detail" should be equal to "test: This value should not be null."
90+
And the JSON node "hydra:description" should be equal to "test: This value should not be null."
10791
And the header "Content-Type" should be equal to "application/problem+json; charset=utf-8"
10892

10993
@!mongodb

src/ApiResource/Error.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#[ErrorResource(
2929
types: ['hydra:Error'],
3030
openapi: false,
31+
uriTemplate: '/errors/{status}',
3132
operations: [
3233
new Operation(
3334
name: '_api_errors_problem',
@@ -36,7 +37,6 @@
3637
'groups' => ['jsonproblem'],
3738
'skip_null_values' => true,
3839
],
39-
uriTemplate: '/errors/{status}'
4040
),
4141
new Operation(
4242
name: '_api_errors_hydra',
@@ -46,13 +46,11 @@
4646
'skip_null_values' => true,
4747
],
4848
links: [new Link(rel: ContextBuilderInterface::JSONLD_NS.'error', href: 'http://www.w3.org/ns/hydra/error')],
49-
uriTemplate: '/hydra_errors/{status}'
5049
),
5150
new Operation(
5251
name: '_api_errors_jsonapi',
5352
outputFormats: ['jsonapi' => ['application/vnd.api+json']],
5453
normalizationContext: ['groups' => ['jsonapi'], 'skip_null_values' => true],
55-
uriTemplate: '/jsonapi_errors/{status}'
5654
),
5755
],
5856
graphQlOperations: []

src/Metadata/Extractor/schema/resources.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
<xsd:attribute type="xsd:boolean" name="openapi"/>
4848
<xsd:attribute type="xsd:positiveInteger" name="priority"/>
4949
<xsd:attribute type="xsd:string" name="name"/>
50+
<xsd:attribute type="xsd:string" name="itemUriTemplate"/>
5051
</xsd:complexType>
5152

5253
<xsd:complexType name="graphQlOperations">

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@
4343
<tag name="serializer.normalizer" priority="-995" />
4444
</service>
4545

46+
<service id="api_platform.jsonld.normalizer.validation_exception" class="ApiPlatform\Symfony\Validator\Serializer\ValidationExceptionNormalizer" public="false">
47+
<argument type="service" id="api_platform.jsonld.normalizer.item" />
48+
<argument type="service" id="api_platform.name_converter" on-invalid="ignore" />
49+
50+
<tag name="serializer.normalizer" priority="-800" />
51+
</service>
52+
4653
<service id="api_platform.jsonld.encoder" class="ApiPlatform\Serializer\JsonEncoder" public="false">
4754
<argument>jsonld</argument>
4855
<argument type="service" id="serializer.json.encoder" on-invalid="null" />

src/Symfony/Bundle/Resources/config/symfony/validator.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
<argument type="service" id="api_platform.validator" />
2626
</service>
2727

28+
<service id="api_platform.serializer.normalizer.validation_exception" class="ApiPlatform\Symfony\Validator\Serializer\ValidationExceptionNormalizer" public="false">
29+
<argument type="service" id="api_platform.serializer.normalizer.item" />
30+
<argument type="service" id="api_platform.name_converter" on-invalid="ignore" />
31+
32+
<tag name="serializer.normalizer" priority="-800" />
33+
</service>
2834
</services>
2935

3036
</container>

src/Symfony/EventListener/ErrorListener.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ protected function duplicateRequest(\Throwable $exception, Request $request): Re
148148
$dup->attributes->set('_api_previous_operation', $apiOperation);
149149
$dup->attributes->set('_api_operation', $operation);
150150
$dup->attributes->set('_api_operation_name', $operation->getName());
151-
$dup->attributes->remove('exception');
151+
$dup->attributes->set('exception', $errorResource);
152152
// These are for swagger
153153
$dup->attributes->set('_api_original_route', $request->attributes->get('_route'));
154154
$dup->attributes->set('_api_original_route_params', $request->attributes->get('_route_params'));

src/Symfony/Validator/Exception/ValidationException.php

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -75,35 +75,18 @@ public function getId(): string
7575
return $id;
7676
}
7777

78-
public function __toString(): string
79-
{
80-
$message = '';
81-
foreach ($this->constraintViolationList as $violation) {
82-
if ('' !== $message) {
83-
$message .= "\n";
84-
}
85-
if ($propertyPath = $violation->getPropertyPath()) {
86-
$message .= "$propertyPath: ";
87-
}
88-
89-
$message .= $violation->getMessage();
90-
}
91-
92-
return $message;
93-
}
94-
9578
#[SerializedName('hydra:title')]
9679
#[Groups(['jsonld', 'legacy_jsonld'])]
9780
public function getHydraTitle(): string
9881
{
9982
return $this->errorTitle ?? 'An error occurred';
10083
}
10184

102-
#[SerializedName('hydra:description')]
10385
#[Groups(['jsonld', 'legacy_jsonld'])]
86+
#[SerializedName('hydra:description')]
10487
public function getHydraDescription(): string
10588
{
106-
return $this->__toString();
89+
return $this->detail;
10790
}
10891

10992
#[Groups(['jsonld', 'json', 'legacy_jsonproblem', 'legacy_json'])]
@@ -119,9 +102,16 @@ public function getTitle(): ?string
119102
}
120103

121104
#[Groups(['jsonld', 'json', 'legacy_jsonproblem', 'legacy_json'])]
105+
private string $detail;
106+
122107
public function getDetail(): ?string
123108
{
124-
return $this->__toString();
109+
return $this->detail;
110+
}
111+
112+
public function setDetail(string $detail): void
113+
{
114+
$this->detail = $detail;
125115
}
126116

127117
#[Groups(['jsonld', 'json', 'legacy_jsonproblem', 'legacy_json'])]
@@ -147,4 +137,21 @@ public function getConstraintViolationList(): ConstraintViolationListInterface
147137
{
148138
return $this->constraintViolationList;
149139
}
140+
141+
public function __toString(): string
142+
{
143+
$message = '';
144+
foreach ($this->constraintViolationList as $violation) {
145+
if ('' !== $message) {
146+
$message .= "\n";
147+
}
148+
if ($propertyPath = $violation->getPropertyPath()) {
149+
$message .= "$propertyPath: ";
150+
}
151+
152+
$message .= $violation->getMessage();
153+
}
154+
155+
return $message;
156+
}
150157
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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\Symfony\Validator\Serializer;
15+
16+
use ApiPlatform\Serializer\CacheableSupportsMethodInterface;
17+
use ApiPlatform\Symfony\Validator\Exception\ValidationException;
18+
use Symfony\Component\Serializer\NameConverter\AdvancedNameConverterInterface;
19+
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
20+
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
21+
use Symfony\Component\Serializer\Serializer;
22+
23+
class ValidationExceptionNormalizer implements NormalizerInterface, CacheableSupportsMethodInterface
24+
{
25+
public function __construct(private readonly NormalizerInterface $decorated, private readonly ?NameConverterInterface $nameConverter)
26+
{
27+
}
28+
29+
public function normalize(mixed $object, string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null
30+
{
31+
$messages = [];
32+
foreach ($object->getConstraintViolationList() as $violation) {
33+
$class = \is_object($root = $violation->getRoot()) ? $root::class : null;
34+
35+
if ($this->nameConverter instanceof AdvancedNameConverterInterface) {
36+
$propertyPath = $this->nameConverter->normalize($violation->getPropertyPath(), $class, $format);
37+
} elseif ($this->nameConverter instanceof NameConverterInterface) {
38+
$propertyPath = $this->nameConverter->normalize($violation->getPropertyPath());
39+
} else {
40+
$propertyPath = $violation->getPropertyPath();
41+
}
42+
43+
$messages[] = ($propertyPath ? "{$propertyPath}: " : '').$violation->getMessage();
44+
}
45+
46+
$str = implode("\n", $messages);
47+
$object->setDetail($str);
48+
49+
return $this->decorated->normalize($object, $format, $context);
50+
}
51+
52+
public function supportsNormalization(mixed $data, string $format = null, array $context = []): bool
53+
{
54+
return $data instanceof ValidationException && $this->decorated->supportsNormalization($data, $format);
55+
}
56+
57+
public function hasCacheableSupportsMethod(): bool
58+
{
59+
if (method_exists(Serializer::class, 'getSupportedTypes')) {
60+
trigger_deprecation(
61+
'api-platform/core',
62+
'3.1',
63+
'The "%s()" method is deprecated, use "getSupportedTypes()" instead.',
64+
__METHOD__
65+
);
66+
}
67+
68+
return true;
69+
}
70+
71+
public function getSupportedTypes($format): array
72+
{
73+
return [ValidationException::class => true];
74+
}
75+
}

0 commit comments

Comments
 (0)