Skip to content

Commit 288c41e

Browse files
authored
Merge pull request #1 from api-platform/master
Update
2 parents b7a2bd6 + 12b0701 commit 288c41e

18 files changed

+266
-152
lines changed

core/configuration.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ api_platform:
2222
# Specify a name converter to use.
2323
name_converter: ~
2424

25+
# Specify a name for the folder within bundle that contain api resources.
26+
api_resources_directory: 'Entity'
27+
2528
eager_loading:
2629
# To enable or disable eager loading.
2730
enabled: true

core/data-providers.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ For a given resource, you can implement two kind of interfaces:
1818
is used when fetching items.
1919

2020
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)).
2122

2223
## Custom Collection Data Provider
2324

core/filters.md

Lines changed: 96 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ constant directly.
152152

153153
The boolean filter allows you to search on boolean fields and values.
154154

155-
Syntax: `?property=[on|off|true|false|0|1]`
155+
Syntax: `?property=[true|false|1|0]`
156156

157157
You can either use TRUE or true, the parameters are case insensitive.
158158

@@ -422,15 +422,105 @@ It means that the filter will be **silently** ignored if the property:
422422
Custom filters can be written by implementing the `ApiPlatform\Core\Api\FilterInterface`
423423
interface.
424424

425-
If you use [custom data providers](data-providers.md), they must support filtering and be aware of active filters to work
426-
properly.
425+
API Platform provides a convenient way to create Doctrine ORM filters. If you use [custom data providers](data-providers.md),
426+
you can still create filters by implementing the previously mentioned interface, but - as API Platform isn't aware of your
427+
persistence system's internals - you have to create the filtering logic by yourself.
427428

428429
### Creating Custom Doctrine ORM Filters
429430

430-
Doctrine ORM filters must implement the `ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\FilterInterface`.
431-
They can interact directly with the Doctrine `QueryBuilder`.
431+
Doctrine filters can access to the HTTP request (Symfony's `Request` object) and to the `QueryBuilder` instance used to
432+
retrieve data from the database. They are only applied to collections. If you want to deal with the DQL query generated
433+
to retrieve items, or don't need to access the HTTP request, [extensions](extensions.md) are the way to go.
432434

433-
A convenient abstract class is also shipped with the bundle: `ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractFilter`
435+
A Doctrine ORM filter is basically a class implementing the `ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\FilterInterface`.
436+
API Platform includes a convenient abstract class implementing this interface and providing utility methods: `ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractFilter`
437+
438+
In the following example, we create a class to filter a collection by applying a regexp to a property. The `REGEXP` DQL
439+
function used in this example can be found in the [`DoctrineExtensions`](https://github.com/beberlei/DoctrineExtensions)
440+
library. This library must be properly installed and registered to use this example (works only with MySQL).
441+
442+
```php
443+
<?php
444+
445+
// src/AppBundle/Filter/RegexpFilter.php
446+
447+
namespace AppBundle\Filter;
448+
449+
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\AbstractFilter;
450+
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
451+
use Doctrine\ORM\QueryBuilder;
452+
453+
final class RegexpFilter extends AbstractFilter
454+
{
455+
protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
456+
{
457+
$parameterName = $queryNameGenerator->generateParameterName($property); // Generate a unique parameter name to avoid collisions with other filters
458+
$queryBuilder
459+
->andWhere(sprintf('REGEXP(o.%s, :%s) = 1', $property, $parameterName))
460+
->setParameter($parameterName, $value);
461+
}
462+
463+
// This function is only used to hook in documentation generators (supported by Swagger and Hydra)
464+
public function getDescription(string $resourceClass): array
465+
{
466+
$description = [];
467+
foreach ($this->properties as $property => $strategy) {
468+
$description['regexp_'.$property] = [
469+
'property' => $property,
470+
'type' => 'string',
471+
'required' => false,
472+
'swagger' => ['description' => 'Filter using a regex. This will appear in the Swagger documentation!'],
473+
];
474+
}
475+
476+
return $description;
477+
}
478+
}
479+
```
480+
481+
Then, register this filter as a service:
482+
483+
```yaml
484+
services:
485+
'AppBundle\Filter\RegexpFilter':
486+
class: 'AppBundle\Filter\RegexpFilter'
487+
autowire: true # See the next example for a plain old definition
488+
tags: [ { name: 'api_platform.filter', id: 'regexp' } ]
489+
```
490+
491+
In the previous example, the filter can be applied on any property. However, thanks to the `AbstractFilter` class,
492+
it can also be enabled for some properties:
493+
494+
```yaml
495+
services:
496+
'AppBundle\Filter\RegexpFilter':
497+
class: 'AppBundle\Filter\RegexpFilter'
498+
arguments: [ '@doctrine', '@request_stack', '@?logger', { email: ~, anOtherProperty: ~ } ]
499+
tags: [ { name: 'api_platform.filter', id: 'regexp' } ]
500+
```
501+
502+
Finally, add this filter to resources you want to be filtered:
503+
504+
```php
505+
<?php
506+
507+
// src/AppBundle/Entity/Offer.php
508+
509+
namespace AppBundle\Entity;
510+
511+
use ApiPlatform\Core\Annotation\ApiResource;
512+
513+
/**
514+
* @ApiResource(attributes={"filters"={"regexp"}})
515+
*/
516+
class Offer
517+
{
518+
// ...
519+
}
520+
```
521+
522+
You can now enable this filter using URLs like `http://example.com/offers?regexp_email=^[FOO]`. This new filter will also
523+
appear in Swagger and Hydra documentations.
434524

435525
### Overriding Extraction of Properties from the Request
436526

core/form-data.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class AppBundle extends Bundle
102102
$container->addCompilerPass(new class implements CompilerPassInterface {
103103
public function process(ContainerBuilder $container) {
104104
$container
105-
->findDefinition('api_platform.listener.request.deserialize');
105+
->findDefinition('api_platform.listener.request.deserialize')
106106
->clearTags();
107107
}
108108
});

core/fosuser-bundle.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ You need to use serialization groups to hide some properties like `plainPassword
1010
shown are handled with the [`normalization_context`](serialization-groups-and-relations.md#normalization), while the properties
1111
you can modify are handled with [`denormalization_context`](serialization-groups-and-relations.md#denormalization).
1212

13-
First register the following service:
13+
Create your User entity with serialization groups:
1414

1515
```php
1616
<?php

core/getting-started.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ API Platform Core is able to automatically expose entities mapped as "API resour
5656
operations.
5757
To expose your entities, you can use Docblock annotations, XML and YAML configuration files.
5858
59-
Here is an example of entities mapped using annotations which will be exposed trough a REST API:
59+
Here is an example of entities mapped using annotations which will be exposed through a REST API:
6060
6161
```php
6262
<?php
@@ -138,7 +138,7 @@ class Offer
138138
}
139139
```
140140

141-
It is the minimal configuration required to expose `Product` and `Offer` entities as JSON-LD documents trough an hypermedia
141+
It is the minimal configuration required to expose `Product` and `Offer` entities as JSON-LD documents through an hypermedia
142142
web API.
143143

144144
If you are familiar with the Symfony ecosystem, you noticed that entity classes are also mapped with Doctrine ORM annotations
@@ -173,7 +173,10 @@ As an alternative to annotations, you can map entity classes using XML or YAML:
173173
<!-- src/AppBundle/Resources/config/api_resources/resources.xml -->
174174

175175
<?xml version="1.0" encoding="UTF-8" ?>
176-
<resources>
176+
<resources xmlns="https://api-platform.com/schema/metadata"
177+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
178+
xsi:schemaLocation="https://api-platform.com/schema/metadata
179+
https://api-platform.com/schema/metadata/metadata-2.0.xsd">
177180
<resource class="AppBundle\Entity\Product" />
178181
<resource
179182
class="AppBundle\Entity\Offer"

core/jwt.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# JWT Authentification
22

3-
> [JSON Web Token (JWT)](jwt.io) is a JSON-based open standard ([RFC 7519](https://tools.ietf.org/html/rfc7519)) for creating access tokens that assert some number of claims. For example, a server could generate a token that has the claim "logged in as admin" and provide that to a client. The client could then use that token to prove that he/she is logged in as admin. The tokens are signed by the server's key, so the server is able to verify that the token is legitimate. The tokens are designed to be compact, URL-safe and usable especially in web browser single sign-on (SSO) context.
3+
> [JSON Web Token (JWT)](https://jwt.io/) is a JSON-based open standard ([RFC 7519](https://tools.ietf.org/html/rfc7519)) for creating access tokens that assert some number of claims. For example, a server could generate a token that has the claim "logged in as admin" and provide that to a client. The client could then use that token to prove that he/she is logged in as admin. The tokens are signed by the server's key, so the server is able to verify that the token is legitimate. The tokens are designed to be compact, URL-safe and usable especially in web browser single sign-on (SSO) context.
44
55
[Uncyclopedia](https://en.wikipedia.org/wiki/JSON_Web_Token)
66

@@ -35,13 +35,12 @@ security:
3535
stateless: true
3636
anonymous: true
3737
provider: fos_userbundle
38-
form_login:
38+
json_login:
3939
check_path: /login_check
40-
username_parameter: email
41-
password_parameter: password
40+
username_path: email
41+
password_path: password
4242
success_handler: lexik_jwt_authentication.handler.authentication_success
4343
failure_handler: lexik_jwt_authentication.handler.authentication_failure
44-
require_previous_session: false
4544

4645
main:
4746
pattern: ^/

core/operations.md

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ Operations can be configured using annotations, XML or YAML. In the following ex
4949
for the `GET` method for both `collectionOperations` and `itemOperations` to create a readonly endpoint.
5050

5151
`itemOperations` and `collectionOperations` are arrays containing a list of operation. Each operation is defined by a key
52-
corresponding to the name of the operation that can be anything you want and an array of properties as value.
52+
corresponding to the name of the operation that can be anything you want and an array of properties as value. If an
53+
empty list of operations is provided, all operations are disabled.
5354

5455
<configurations>
5556

@@ -87,12 +88,16 @@ AppBundle\Entity\Book:
8788
<?xml version="1.0" encoding="UTF-8" ?>
8889
<resources>
8990
<resource class="AppBundle\Entity\Book">
90-
<itemOperation name="get">
91-
<attribute name="method">GET</attribute>
92-
</itemOperation>
93-
<collectionOperation name="get">
94-
<attribute name="method">GET</attribute>
95-
</collectionOperation>
91+
<itemOperations>
92+
<itemOperation name="get">
93+
<attribute name="method">GET</attribute>
94+
</itemOperation>
95+
</itemOperations>
96+
<collectionOperations>
97+
<collectionOperation name="get">
98+
<attribute name="method">GET</attribute>
99+
</collectionOperation>
100+
</collectionOperations>
96101
</resource>
97102
</resources>
98103
```
@@ -150,17 +155,19 @@ AppBundle\Entity\Book:
150155
<?xml version="1.0" encoding="UTF-8" ?>
151156
<resources>
152157
<resource class="AppBundle\Entity\Book">
153-
<itemOperation name="get">
154-
<attribute name="method">GET</attribute>
155-
<attribute name="path">/grimoire/{id}</attribute>
156-
</itemOperation>
157-
<itemOperation name="put">
158-
<attribute name="method">PUT</attribute>
159-
<attribute name="path">/grimoire/{id}/update</attribute>
160-
<attribute name="hydra_context">
161-
<attribute name="foo">bar</attribute>
162-
</attribute>
163-
</itemOperation>
158+
<itemOperations>
159+
<itemOperation name="get">
160+
<attribute name="method">GET</attribute>
161+
<attribute name="path">/grimoire/{id}</attribute>
162+
</itemOperation>
163+
<itemOperation name="put">
164+
<attribute name="method">PUT</attribute>
165+
<attribute name="path">/grimoire/{id}/update</attribute>
166+
<attribute name="hydra_context">
167+
<attribute name="foo">bar</attribute>
168+
</attribute>
169+
</itemOperation>
170+
</itemOperations>
164171
</resource>
165172
</resources>
166173
```
@@ -230,12 +237,14 @@ AppBundle\Entity\Book:
230237
<?xml version="1.0" encoding="UTF-8" ?>
231238
<resources>
232239
<resource class="AppBundle\Entity\Book">
233-
<itemOperation name="get">
234-
<attribute name="method">GET</attribute>
235-
</itemOperation>
236-
<itemOperation name="special">
237-
<attribute name="route_name">book_special</attribute>
238-
</itemOperation>
240+
<itemOperations>
241+
<itemOperation name="get">
242+
<attribute name="method">GET</attribute>
243+
</itemOperation>
244+
<itemOperation name="special">
245+
<attribute name="route_name">book_special</attribute>
246+
</itemOperation>
247+
</itemOperations>
239248
</resource>
240249
</resources>
241250
```

core/performance.md

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Keep in mind that PPM is still in an early stage of development and can cause is
2222

2323
When using the `SearchFilter` and case insensivity, Doctrine will use the `LOWER` SQL function. Depending on your
2424
driver, you may want to carefully index it by using a [function-based
25-
index](http://use-the-index-luke.com/sql/where-clause/functions/case-insensitive-search) or it will impact performanc
25+
index](http://use-the-index-luke.com/sql/where-clause/functions/case-insensitive-search) or it will impact performance
2626
with a huge collection. [Here are some examples to index LIKE
2727
filters](http://use-the-index-luke.com/sql/where-clause/searching-for-ranges/like-performance-tuning) depending on your
2828
database driver.
@@ -36,11 +36,20 @@ Fortunately, Doctrine proposes another approach to remedy this problem: [eager l
3636
This can easily be enabled for a relation: `@ORM\ManyToOne(fetch="EAGER")`.
3737

3838
By default in API Platform, we made the choice to force eager loading for all relations, with or without the Doctrine
39-
`fetch` attribute. Thanks to the eager loading [extension](extensions.md).
39+
`fetch` attribute. Thanks to the eager loading [extension](extensions.md). The `EagerLoadingExtension` will join every
40+
readable association according to the serialization context. If you want to fetch an association that is not serializable
41+
you've to bypass `readable` and `readableLink` by using the `fetchEager` attribute on the property declaration, for example:
42+
43+
```php
44+
/**
45+
* @ApiProperty(attributes={"fetchEager": true})
46+
*/
47+
public $foo;
48+
```
4049

4150
#### Max joins
4251

43-
There is a default restriction with this feature. We allow up to 30 joins per query. Beyond, an
52+
There is a default restriction with this feature. We allow up to 30 joins per query. Beyond, an
4453
`ApiPlatform\Core\Exception\RuntimeException` exception will be thrown but this value can easily be increased with a
4554
little of configuration:
4655

@@ -61,7 +70,7 @@ can be a good solution to fix this issue.
6170

6271
#### Force eager
6372

64-
As mentioned above, by default we force eager loading for all relations. This behaviour can be modified with the
73+
As mentioned above, by default we force eager loading for all relations. This behaviour can be modified with the
6574
configuration in order to apply it only on join relations having the `EAGER` fetch mode:
6675

6776
```yaml
@@ -117,8 +126,8 @@ class User
117126
{
118127
/**
119128
* @var Address
120-
*
121-
* @ORM\ManyToOne(targetEntity="Address", fetch="EAGER")
129+
*
130+
* @ORM\ManyToOne(targetEntity="Address", fetch="EAGER")
122131
*/
123132
public $address;
124133

@@ -171,7 +180,7 @@ configuration.
171180

172181
#### Disable eager loading
173182

174-
If for any reason you don't want the eager loading feature, you can turn off it in the configuration:
183+
If for any reason you don't want the eager loading feature, you can turn it off in the configuration:
175184

176185
```yaml
177186
# app/config/config.yaml

core/serialization-groups-and-relations.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ In the following JSON document, the relation from a book to an author is represe
136136
### Normalization
137137

138138
To improve the application's performance, it is sometimes necessary to avoid issuing extra HTTP requests. It is possible
139-
to embed related objects (or only some of their properties) directly in the parent response trough serialization groups.
139+
to embed related objects (or only some of their properties) directly in the parent response through serialization groups.
140140
By using the following serialization groups annotations (`@Groups`), a JSON representation of the author is embedded in
141141
the book response:
142142

@@ -239,7 +239,7 @@ class Book
239239

240240
The following rules apply when denormalizating embedded relations:
241241

242-
* If a `@id` key is present in the embedded resource, the object corresponding to the given URI will be retrieved trough
242+
* If a `@id` key is present in the embedded resource, the object corresponding to the given URI will be retrieved through
243243
the data provider and any changes in the embedded relation will be applied to that object.
244244
* If no `@id` key exists, a new object will be created containing data provided in the embedded JSON document.
245245

deployment/docker.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ stack is shipped with the API Platform distribution.
77
To install it, run the following commands (Docker must be installed on your system):
88

99
$ docker-compose up -d # Download, build and run Docker images
10-
$ docker-compose exec web bin/console doctrine:schema:create # Create the MySQL schema
10+
$ docker-compose exec app bin/console doctrine:schema:create # Create the MySQL schema
1111

1212
Your project will be accessible at the URL `http://127.0.0.1`.
1313

deployment/heroku.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Deploying an API Platform App on Heroku
22

33
[Heroku](http://heroku.com) is a popular, fast, scalable and reliable *Platform As A Service* (PaaS). As Heroku offers a
4-
free plan including database support trough [Heroku Postgres](https://www.heroku.com/postgres), it's
4+
free plan including database support through [Heroku Postgres](https://www.heroku.com/postgres), it's
55
a very convenient way to experiment with the API Platform.
66

77
The API Platform Heroku integration also supports MySQL databases provided by [the ClearDB add-on](https://addons.heroku.com/cleardb).

0 commit comments

Comments
 (0)