Skip to content

Commit a05b89a

Browse files
committed
Merge branch '4.0'
2 parents e11fdfe + e6b2569 commit a05b89a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1959
-138
lines changed

.github/workflows/cd.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
runs-on: ubuntu-latest
1212
steps:
1313
- name: Checkout the website
14-
uses: actions/checkout@v3
14+
uses: actions/checkout@v4
1515
with:
1616
repository: api-platform/website
1717
ref: main
@@ -20,7 +20,7 @@ jobs:
2020
id: yarn-cache-dir-path
2121
run: echo "dir=$(yarn cache dir)" >> "$GITHUB_OUTPUT"
2222

23-
- uses: actions/cache@v3
23+
- uses: actions/cache@v4
2424
id: yarn-cache
2525
with:
2626
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
@@ -32,7 +32,7 @@ jobs:
3232
- name: Setup Hugo
3333
uses: peaceiris/actions-hugo@v2
3434
with:
35-
hugo-version: '0.119.0'
35+
hugo-version: '0.134.2'
3636
extended: true
3737

3838
- name: Install php

.github/workflows/ci.yml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,34 @@ on:
44
push:
55
pull_request:
66

7+
permissions: {}
8+
79
jobs:
810
build:
911
name: Lint
1012
runs-on: ubuntu-latest
1113

14+
permissions:
15+
contents: read
16+
packages: read
17+
statuses: write
18+
1219
steps:
1320
- name: Checkout
14-
uses: actions/checkout@v3
21+
uses: actions/checkout@v4
22+
with:
23+
fetch-depth: 0
1524

1625
- name: Lint
1726
uses: github/super-linter/slim@v4
1827
env:
1928
VALIDATE_ALL_CODEBASE: false
2029
VALIDATE_EDITORCONFIG: false
2130
VALIDATE_JSCPD: false
22-
DEFAULT_BRANCH: main
31+
DEFAULT_BRANCH: "4.0"
2332
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2433

25-
- uses: actions/cache@v3
34+
- uses: actions/cache@v4
2635
with:
2736
path: ~/.cache/pip
2837
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}

core/bootstrap.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Bootstraping the core library
22

3-
You may want to run a minimal version of API Platform. This one file runs API Platform (without GraphQL, Doctrine and MongoDB).
4-
It requires the following composer packages:
3+
You may want to run a minimal version of API Platform. This one file runs API Platform (without GraphQL, Eloquent, Doctrine MongoDB...).
4+
It requires the following Composer packages:
55

66
```console
77
composer require \

core/configuration.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ api_platform:
6868
# Enable the data collector and the WebProfilerBundle integration.
6969
enable_profiler: true
7070

71+
# Keep doctrine/inflector instead of symfony/string to generate plurals for routes.
72+
keep_legacy_inflector: true
73+
7174
collection:
7275
# The name of the query parameter to filter nullable results (with the ExistsFilter).
7376
exists_parameter_name: 'exists'

core/content-negotiation.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
The API system has built-in [content negotiation](https://en.wikipedia.org/wiki/Content_negotiation) capabilities.
44

5-
By default, only the [JSON-LD](https://json-ld.org) and JSON formats are enabled. However API Platform supports many more formats and can be extended.
5+
By default, only the [JSON-LD](https://json-ld.org) format is enabled. However API Platform supports many more formats and can be extended.
66

77
The framework natively supports JSON-LD (and Hydra), GraphQL, JSON:API, HAL, YAML, CSV, HTML (API docs), raw JSON and raw XML.
88
Using the raw JSON or raw XML formats is discouraged, prefer using JSON-LD instead, which provides more feature and is as easy to use.
99

10-
API Platform also supports [JSON Merge Patch (RFC 7396)](https://tools.ietf.org/html/rfc7396) the JSON:API [`PATCH`](https://tools.ietf.org/html/rfc5789) formats, as well as [Problem Details (RFC 7807)](https://tools.ietf.org/html/rfc7807), Hydra and JSON:API error formats.
10+
API Platform also supports [JSON Merge Patch (RFC 7396)](https://tools.ietf.org/html/rfc7396) the JSON:API [`PATCH`](https://jsonapi.org/format/#crud-updating) formats, as well as [Problem Details (RFC 7807)](https://tools.ietf.org/html/rfc7807), [Hydra](https://www.hydra-cg.com/spec/latest/core/#description-of-http-status-codes-and-errors) and [JSON:API](https://jsonapi.org/format/#errors) error formats.
1111

1212
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/formats?cid=apip"><img src="/docs/distribution/images/symfonycasts-player.png" alt="Formats screencast"><br>Watch the Formats screencast</a></p>
1313

core/deprecations.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ properties:
107107

108108
## Setting the `Sunset` HTTP Header to Indicate When a Resource or an Operation Will Be Removed
109109

110-
[The `Sunset` HTTP response header](https://tools.ietf.org/html/draft-wilde-sunset-header) indicates that a URI is likely to become unresponsive at a specified point in the future.
110+
[The `Sunset` HTTP response header (RFC 8594)](https://www.rfc-editor.org/rfc/rfc8594) indicates that a URI is likely to become unresponsive at a specified point in the future.
111111
It is especially useful to indicate when a deprecated URL will not be available anymore.
112112

113113
Thanks to the `sunset` attribute, API Platform makes it easy to set this header for all URLs related to a resource class:

core/errors.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ api_platform:
105105
# The 4 following handlers are registered by default, keep those lines to prevent unexpected side effects
106106
Symfony\Component\Serializer\Exception\ExceptionInterface: 400 # Use a raw status code (recommended)
107107
ApiPlatform\Exception\InvalidArgumentException: !php/const Symfony\Component\HttpFoundation\Response::HTTP_BAD_REQUEST
108-
ApiPlatform\Exception\FilterValidationException: 400
108+
ApiPlatform\ParameterValidator\Exception\ValidationExceptionInterface: 400
109109
Doctrine\ORM\OptimisticLockException: 409
110110
111111
# Validation exception

core/extensions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ final readonly class CurrentUserExtension implements QueryCollectionExtensionInt
9898

9999
```
100100

101+
Note that the default `rootAlias` is "o" in the bundled `ItemProvider` and `CollectionProvider`, so you should use different aliases for your custom joins in your extension.
102+
101103
Finally, if you're not using the autoconfiguration, you have to register the custom extension with either of those tags:
102104

103105
```yaml

core/file-upload.md

Lines changed: 22 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ before proceeding. It will help you get a grasp on how the bundle works, and why
1111
**Note**: Uploading files won't work in `PUT` or `PATCH` requests, you must use `POST` method to upload files.
1212
See [the related issue on Symfony](https://github.com/symfony/symfony/issues/9226) and [the related bug in PHP](https://bugs.php.net/bug.php?id=55815) talking about this behavior.
1313

14+
Enable the multipart format globally in order to use it as the input format of your resource:
15+
16+
```yaml
17+
api_platform:
18+
formats:
19+
multipart: ['multipart/form-data']
20+
jsonld: ['application/ld+json']
21+
```
22+
1423
## Installing VichUploaderBundle
1524
1625
Install the bundle with the help of Composer:
@@ -44,9 +53,6 @@ In this example, we will create a `MediaObject` API resource. We will post files
4453
to this resource endpoint, and then link the newly created resource to another
4554
resource (in our case: `Book`).
4655

47-
This example will use a custom controller to receive the file.
48-
The second example will use a custom `multipart/form-data` decoder to deserialize the resource instead.
49-
5056
### Configuring the Resource Receiving the Uploaded File
5157

5258
The `MediaObject` resource is implemented like this:
@@ -63,7 +69,7 @@ use ApiPlatform\Metadata\Get;
6369
use ApiPlatform\Metadata\GetCollection;
6470
use ApiPlatform\Metadata\Post;
6571
use ApiPlatform\OpenApi\Model;
66-
use App\Controller\CreateMediaObjectAction;
72+
use App\State\SaveMediaObject;
6773
use Doctrine\ORM\Mapping as ORM;
6874
use Symfony\Component\HttpFoundation\File\File;
6975
use Symfony\Component\Serializer\Annotation\Groups;
@@ -75,13 +81,12 @@ use Vich\UploaderBundle\Mapping\Annotation as Vich;
7581
#[ApiResource(
7682
normalizationContext: ['groups' => ['media_object:read']],
7783
types: ['https://schema.org/MediaObject'],
84+
outputFormats: ['jsonld' => ['application/ld+json']],
7885
operations: [
7986
new Get(),
8087
new GetCollection(),
8188
new Post(
82-
controller: CreateMediaObjectAction::class,
83-
deserialize: false,
84-
validationContext: ['groups' => ['Default', 'media_object_create']],
89+
inputFormats: ['multipart' => ['multipart/form-data']],
8590
openapi: new Model\Operation(
8691
requestBody: new Model\RequestBody(
8792
content: new \ArrayObject([
@@ -107,14 +112,15 @@ class MediaObject
107112
#[ORM\Id, ORM\Column, ORM\GeneratedValue]
108113
private ?int $id = null;
109114
110-
#[ApiProperty(types: ['https://schema.org/contentUrl'])]
115+
#[ApiProperty(types: ['https://schema.org/contentUrl'], writable: false)]
111116
#[Groups(['media_object:read'])]
112117
public ?string $contentUrl = null;
113118
114119
#[Vich\UploadableField(mapping: 'media_object', fileNameProperty: 'filePath')]
115-
#[Assert\NotNull(groups: ['media_object_create'])]
120+
#[Assert\NotNull]
116121
public ?File $file = null;
117122
123+
#[ApiProperty(writable: false)]
118124
#[ORM\Column(nullable: true)]
119125
public ?string $filePath = null;
120126
@@ -124,41 +130,7 @@ class MediaObject
124130
}
125131
}
126132
```
127-
128-
### Creating the Controller
129-
130-
At this point, the entity is configured, but we still need to write the action
131-
that handles the file upload.
132-
133-
```php
134-
<?php
135-
// api/src/Controller/CreateMediaObjectAction.php
136-
137-
namespace App\Controller;
138-
139-
use App\Entity\MediaObject;
140-
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
141-
use Symfony\Component\HttpFoundation\Request;
142-
use Symfony\Component\HttpKernel\Attribute\AsController;
143-
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
144-
145-
#[AsController]
146-
final class CreateMediaObjectAction extends AbstractController
147-
{
148-
public function __invoke(Request $request): MediaObject
149-
{
150-
$uploadedFile = $request->files->get('file');
151-
if (!$uploadedFile) {
152-
throw new BadRequestHttpException('"file" is required');
153-
}
154-
155-
$mediaObject = new MediaObject();
156-
$mediaObject->file = $uploadedFile;
157-
158-
return $mediaObject;
159-
}
160-
}
161-
```
133+
Note: From V3.3 onwards, `'multipart/form-data'` must either be including in the global API-Platform config, either in `formats` or `defaults->inputFormats`, or defined as an `inputFormats` parameter on an operation by operation basis.
162134

163135
### Resolving the File URL
164136

@@ -169,6 +141,7 @@ A [normalizer](serialization.md#normalization) could be used to set the `content
169141

170142
```php
171143
<?php
144+
// api/src/Serializer/MediaObjectNormalizer.php
172145
173146
namespace App\Serializer;
174147
@@ -183,7 +156,7 @@ class MediaObjectNormalizer implements NormalizerInterface
183156
private const ALREADY_CALLED = 'MEDIA_OBJECT_NORMALIZER_ALREADY_CALLED';
184157
185158
public function __construct(
186-
#[Autowire(service: 'serializer.normalizer.object')]
159+
#[Autowire(service: 'api_platform.jsonld.normalizer.item')]
187160
private readonly NormalizerInterface $normalizer,
188161
private readonly StorageInterface $storage
189162
) {
@@ -383,7 +356,10 @@ use Vich\UploaderBundle\Mapping\Annotation as Vich;
383356
types: ['https://schema.org/Book'],
384357
operations: [
385358
new GetCollection(),
386-
new Post(inputFormats: ['multipart' => ['multipart/form-data']])
359+
new Post(
360+
outputFormats: ['jsonld' => ['application/ld+json']],
361+
inputFormats: ['multipart' => ['multipart/form-data']]
362+
)
387363
]
388364
)]
389365
class Book

0 commit comments

Comments
 (0)