Skip to content

Commit 0cb2f42

Browse files
committed
Merge branch '2.0'
2 parents 61471a0 + 95591e4 commit 0cb2f42

File tree

11 files changed

+136
-22
lines changed

11 files changed

+136
-22
lines changed

core/content-negotiation.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,107 @@ API Platform Core will automatically call the serializer with your defined forma
6868
as `format` parameter during the deserialization process. Then it will return the result to the client with the asked MIME
6969
type using its built-in responder.
7070

71+
72+
## Writing a Custom Normalizer
73+
74+
Using composition is the recommended way to implement a custom normalizer. You can use the following template to start with your
75+
own implementation of `CustomItemNormalizer`:
76+
77+
78+
```yaml
79+
# app/config/services.yml
80+
81+
services:
82+
app.custom_item_normalizer:
83+
public: false
84+
class: AppBundle\Serializer\CustomItemNormalizer
85+
arguments: [ '@api_platform.serializer.normalizer.item' ]
86+
tags: [ { name: serializer.normalizer } ]
87+
```
88+
89+
```php
90+
<?php
91+
92+
// src/AppBundle/Serializer/CustomItemNormalizer.php
93+
94+
namespace AppBundle\Serializer;
95+
96+
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
97+
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
98+
99+
class CustomItemNormalizer implements NormalizerInterface, DenormalizerInterface
100+
{
101+
private $normalizer;
102+
103+
public function __construct(NormalizerInterface $normalizer)
104+
{
105+
if (!$normalizer instanceof DenormalizerInterface) {
106+
throw new \InvalidArgumentException('The normalizer must implement the DenormalizerInterface');
107+
}
108+
109+
$this->normalizer = $normalizer;
110+
}
111+
112+
public function denormalize($data, $class, $format = null, array $context = [])
113+
{
114+
return $this->normalizer->denormalize($data, $class, $format, $context);
115+
}
116+
117+
public function supportsDenormalization($data, $type, $format = null)
118+
{
119+
return $this->normalizer->supportsDenormalization($data, $type, $format);
120+
}
121+
122+
public function normalize($object, $format = null, array $context = [])
123+
{
124+
return $this->normalizer->normalize($object, $format, $context);
125+
}
126+
127+
public function supportsNormalization($data, $format = null)
128+
{
129+
return $this->normalizer->supportsNormalization($data, $format);
130+
}
131+
}
132+
```
133+
134+
For example if you want to make the `csv` format to work for even complex entities with a lot of hierarchy, you have
135+
to flatten or remove too complex relations:
136+
137+
```php
138+
<?php
139+
140+
// src/AppBundle/Serializer/CustomItemNormalizer.php
141+
142+
namespace AppBundle\Serializer;
143+
144+
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
145+
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
146+
147+
class CustomItemNormalizer implements NormalizerInterface, DenormalizerInterface
148+
{
149+
// ...
150+
151+
public function normalize($object, $format = null, array $context = [])
152+
{
153+
$result = $this->normalizer->normalize($object, $format, $context);
154+
155+
if ('csv' !== $format || !is_array($result)) {
156+
return $result;
157+
}
158+
159+
foreach ($result as $key => $value) {
160+
if (is_array($value) && array_keys(array_keys($value)) === array_keys($value)) {
161+
unset($result[$key]);
162+
}
163+
}
164+
165+
return $result;
166+
}
167+
168+
// ...
169+
}
170+
```
171+
71172
Previous chapter: [The Event System](events.md)
72173

73174
Next chapter: [Using External JSON-LD Vocabularies](external-vocabularies.md)

core/data-providers.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ For a given resource, you can implement two kind of interfaces:
1717
* the [`ItemDataProviderInterface`](https://github.com/api-platform/core/blob/master/src/DataProvider/ItemDataProviderInterface.php)
1818
is used when fetching items.
1919

20-
In the following examples we will create custom data providers for an entity class class called `AppBundle\Entity\BlogPost`.
21-
Note, that if your entity is not doctrine-related, you need to flag the identifier property by using `@ApiProperty(identifiier=true)` for things to work properly (see also [Entity Identifier Case](serialization-groups-and-relations.md#entity-identifier-case)).
20+
In the following examples we will create custom data providers for an entity class called `AppBundle\Entity\BlogPost`.
21+
Note, that if your entity is not Doctrine-related, you need to flag the identifier property by using `@ApiProperty(identifiier=true)` for things to work properly (see also [Entity Identifier Case](serialization-groups-and-relations.md#entity-identifier-case)).
2222

2323
## Custom Collection Data Provider
2424

@@ -66,8 +66,8 @@ services:
6666
```
6767
6868
Tagging the service with the tag `api_platform.collection_data_provider` will enable API Platform Core to automatically
69-
register and use this data provider. The optional attribute `priority` allows to define the order in wich are called the
70-
data providers. The first data provider not throwing a `ApiPlatform\Core\Exception\ResourceClassNotSupportedException`
69+
register and use this data provider. The optional attribute `priority` allows to define the order in which the
70+
data providers are called. The first data provider not throwing a `ApiPlatform\Core\Exception\ResourceClassNotSupportedException`
7171
will be used.
7272

7373
## Custom Item Data Provider

core/events.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ final class BookMailSubscriber implements EventSubscriberInterface
4040
public static function getSubscribedEvents()
4141
{
4242
return [
43-
KernelEvents::VIEW => [['sendMail', EventPriorities::POST_WRITE]],
43+
KernelEvents::VIEW => ['sendMail', EventPriorities::POST_WRITE],
4444
];
4545
}
4646

core/filters.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -707,9 +707,9 @@ use Symfony\Component\HttpFoundation\Request;
707707
708708
final class CustomOrderFilter extends OrderFilter
709709
{
710-
protected function extractProperties(Request $request)
710+
protected function extractProperties(Request $request): array
711711
{
712-
$filter = $request->query->get('filter[order]', []);
712+
return $request->query->get('filter[order]', []);
713713
}
714714
}
715715
```

core/form-data.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ final class DeserializeListener
5858
return;
5959
}
6060
$context = $this->serializerContextBuilder->createFromRequest($request, false, $attributes);
61+
$populated = $request->attributes->get('data');
62+
if (null !== $populated) {
63+
$context['object_to_populate'] = $populated;
64+
}
65+
6166
$data = $request->request->all();
6267
$object = $this->denormalizer->denormalize($data, $attributes['resource_class'], null, $context);
6368
$request->attributes->set('data', $object);

core/operations.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,10 @@ AppBundle\Entity\Book:
8686
<!-- src/AppBundle/Resources/config/api_resources/resources.xml -->
8787

8888
<?xml version="1.0" encoding="UTF-8" ?>
89-
<resources>
89+
<resources xmlns="https://api-platform.com/schema/metadata"
90+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
91+
xsi:schemaLocation="https://api-platform.com/schema/metadata
92+
https://api-platform.com/schema/metadata/metadata-2.0.xsd">
9093
<resource class="AppBundle\Entity\Book">
9194
<itemOperations>
9295
<itemOperation name="get">
@@ -153,7 +156,10 @@ AppBundle\Entity\Book:
153156
<!-- src/AppBundle/Resources/config/api_resources/resources.xml -->
154157

155158
<?xml version="1.0" encoding="UTF-8" ?>
156-
<resources>
159+
<resources xmlns="https://api-platform.com/schema/metadata"
160+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
161+
xsi:schemaLocation="https://api-platform.com/schema/metadata
162+
https://api-platform.com/schema/metadata/metadata-2.0.xsd">
157163
<resource class="AppBundle\Entity\Book">
158164
<itemOperations>
159165
<itemOperation name="get">
@@ -235,7 +241,10 @@ AppBundle\Entity\Book:
235241
<!-- src/AppBundle/Resources/config/api_resources/resources.xml -->
236242

237243
<?xml version="1.0" encoding="UTF-8" ?>
238-
<resources>
244+
<resources xmlns="https://api-platform.com/schema/metadata"
245+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
246+
xsi:schemaLocation="https://api-platform.com/schema/metadata
247+
https://api-platform.com/schema/metadata/metadata-2.0.xsd">
239248
<resource class="AppBundle\Entity\Book">
240249
<itemOperations>
241250
<itemOperation name="get">
@@ -306,7 +315,7 @@ together.
306315
Here we consider that DunglasActionBundle is installed (the default when using the API Platform distribution). This
307316
action will be automatically registered as a service (the service name is the same as the class name: `AppBundle\Action\BookSpecial`).
308317

309-
API Platform automatically retrieve the appropriate PHP entity then then deserializes it, and for `POST` and `PUT` requests
318+
API Platform automatically retrieves the appropriate PHP entity then deserializes it, and for `POST` and `PUT` requests
310319
updates the entity with data provided by the user.
311320

312321
Services (`$myService` here) are automatically injected thanks to the autowiring feature. You can type-hint any service

core/pagination.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,9 @@ api_platform:
5252
5353
## Disabling the Pagination
5454
55-
Paginating collection is generally accepted as a good practice. It also allows browsing large collections without to much
55+
Paginating collections is generally accepted as a good practice. It allows browsing large collections without too much
5656
overhead as well as preventing [DOS attacks](https://en.wikipedia.org/wiki/Denial-of-service_attack).
57-
It allows to browse large collections and prevent. However, for small collections, it can be convenient to fully disable
58-
the pagination.
57+
However, for small collections, it can be convenient to fully disable the pagination.
5958
6059
### Globally
6160

core/serialization-groups-and-relations.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ final class BookContextBuilder implements SerializerContextBuilderInterface
334334
$context = $this->decorated->createFromRequest($request, $normalization, $extractedAttributes);
335335
$subject = $request->attributes->get('data');
336336

337-
if ($subject instanceof Book && $this->authorizationChecker->isGranted('ROLE_ADMIN') && false === $normalization) {
337+
if ($subject instanceof Book && isset($context['groups']) && $this->authorizationChecker->isGranted('ROLE_ADMIN') && false === $normalization) {
338338
$context['groups'][] = 'admin_input';
339339
}
340340

distribution/index.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ several pre-configured and ready-use services with everything needed to run API
4848
| nginx | An HTTP server provided by Nginx 1.11 | 8080
4949
| varnish | An HTTP cache provided by Varnish 4.1 | 80
5050

51-
Start by [downloading the API Platform Standard Edition archive](https://api.github.com/repos/api-platform/api-platform/zipball) and extract its content.
51+
Start by [downloading the API Platform Standard Edition archive](https://github.com/api-platform/api-platform/releases/latest) and extract its content.
5252
The resulting directory contains an empty API Platform project structure. You will add your own code and configuration inside
5353
it.
5454
Then, if you do not already have Docker on your computer, [it's the right time to install it](https://www.docker.com/products/overview#/install_the_platform).
@@ -99,7 +99,7 @@ ORM and its bridge supports major RDBMS including MySQL, PostgreSQL, SQLite, SQL
9999
Instead of using Docker, API Platform can also be installed on the local machine using [Composer](https://getcomposer.org/):
100100

101101
$ composer create-project api-platform/api-platform bookshop-api
102-
102+
103103
Then, enter the project folder, create the database and its schema:
104104

105105
$ cd bookshop-api
@@ -443,12 +443,12 @@ Oops, we missed to add the title. But submit the request anyway. You should get
443443

444444
Did you notice that the error was automatically serialized in JSON-LD and respect the Hydra Core vocabulary for errors?
445445
It allows the client to easily extract useful information from the error. Anyway, it's bad to get a SQL error when submitting
446-
a request. It means that we doesn't use a valid input, and [it's a very bad and dangerous practice](https://www.owasp.org/index.php/Input_Validation_Cheat_Sheet).
446+
a request. It means that we didn't use a valid input, and [it's a very bad and dangerous practice](https://www.owasp.org/index.php/Input_Validation_Cheat_Sheet).
447447

448448
API Platform comes with a bridge with [the Symfony Validator Component](http://symfony.com/doc/current/validation.html).
449449
Adding some of [its numerous validation constraints](http://symfony.com/doc/current/validation.html#supported-constraints)
450450
(or [creating custom ones](http://symfony.com/doc/current/validation/custom_constraint.html)) to our entities is enough
451-
to get validate user submitted data. Let's add some validation rules to our data model:
451+
to validate user submitted data. Let's add some validation rules to our data model:
452452

453453
```php
454454
<?php

index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
1. [Enabling Several Formats](core/content-negotiation.md#enabling-several-formats)
5757
2. [Registering a Custom Serializer](core/content-negotiation.md#registering-a-custom-serializer)
5858
3. [Creating a Responder](core/content-negotiation.md#creating-a-responder)
59+
4. [Writing a Custom Normalizer](core/content-negotiation.md#writing-a-custom-normalizer)
5960
11. [Using External JSON-LD Vocabularies](core/external-vocabularies.md)
6061
12. [Extending JSON-LD context](core/extending-jsonld-context.md)
6162
13. [Data Providers](core/data-providers.md)

schema-generator/configuration.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ author: "Kévin Dunglas <[email protected]>"
260260
## Disabling Generators and Creating Custom Ones
261261

262262
By default, all generators except `DunglasJsonLdApi` (API Platform v1) and `SerializerGroups` are enabled.
263-
You can specify the list of generators to use with the `generators` option.
263+
You can specify the list of generators to use with the `annotationGenerators` option.
264264

265265
Example (enabling only the PHPDoc generator):
266266

@@ -283,8 +283,7 @@ annotationGenerators:
283283

284284
## Disabling `id` Generator
285285

286-
By default, the generator add a property called `id` not provided by Schema.org. This useful when using generated entity
287-
with an ORM or an ODM.
286+
By default, the generator adds a property called `id` not provided by Schema.org. This may be useful when generating an entity for use with an ORM or an ODM.
288287
This behavior can be disabled with the following setting:
289288

290289
```yaml

0 commit comments

Comments
 (0)