Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 48 additions & 58 deletions core/data-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,26 @@ ORM](http://www.doctrine-project.org/projects/orm.html) to retrieve data from a
is enabled by default. This data provider natively supports paged collections and filters. It can be used as is and fits
perfectly with common usages.

But sometime, you want to retrieve data from other sources such as a webservice, ElasticSearch, MongoDB or another ORM.
Custom data providers can be used to do so. A project can include as many data providers as it needs. The first able to retrieve data for a given resource will be used.
But sometime, you want to retrieve data from other sources such as another persistence layer, a webservice, ElasticSearch
or MongoDB.
Custom data providers can be used to do so. A project can include as many data providers as it needs. The first able to
retrieve data for a given resource will be used.

For a given resource, you can implement two kind of data providers:
- the [CollectionDataProvider](https://github.com/api-platform/core/blob/master/src/Api/CollectionDataProviderInterface.php) is used when fetching a collection.
- the [ItemDataProvider](https://github.com/api-platform/core/blob/master/src/Api/ItemDataProviderInterface.php) is used when fetching items.
For a given resource, you can implement two kind of interfaces:

In the following examples we will create custom data providers for the class `AppBundle\Model\BlogPost`.
* the [`CollectionDataProviderInterface`](https://github.com/api-platform/core/blob/master/src/Api/CollectionDataProviderInterface.php)
is used when fetching a collection.
* the [`ItemDataProviderInterface`](https://github.com/api-platform/core/blob/master/src/Api/ItemDataProviderInterface.php)
is used when fetching items.

## Custom collection data provider

First declare a Symfony service, for example:
In the following examples we will create custom data providers for an entity class class called `AppBundle\Entity\BlogPost`.

```yaml
# AppBundle\Resources\config\services.yml

services:
blog_post.collection_data_provider:
class: 'AppBundle\DataProvider\BlogPostCollectionDataProvider'
# data providers are using decorators (http://symfony.com/doc/master//components/dependency_injection/advanced.html#decorating-services)
decorates: 'api_platform.collection_data_provider'
arguments:
- '@blog_post.collection_data_provider.inner'
```
## Custom collection data provider

Then, your `BlogPostCollectionDataProvider` has to implement the [`CollectionDataProviderInterface`](https://github.com/api-platform/core/blob/master/src/Api/CollectionDataProviderInterface.php):
First, your `BlogPostCollectionDataProvider` has to implement the [`CollectionDataProviderInterface`](https://github.com/api-platform/core/blob/master/src/Api/CollectionDataProviderInterface.php):

The `getCollection` method must return an `array`, a `\Traversable` or a `PaginatorInterface` instance. If no data is available, you should return an empty array.
The `getCollection` method must return an `array`, a `Traversable` or a `ApiPlatform\Core\Api\PaginatorInterface` instance.
If no data is available, you should return an empty array.

```php

Expand All @@ -46,45 +38,39 @@ use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;

class BlogPostCollectionDataProvider implements CollectionDataProviderInterface
{
private $decorated;

public function __construct(CollectionDataProviderInterface $decorated = null)
{
$this->decorated = $decorated;
}

/**
* {@inheritdoc}
*/
public function getCollection(string $resourceClass, string $operationName = null)
{
// tests if the class is supported by this data provider
if (BlogPost::class !== $resourceClass) {
throw new ResourceClassNotSupportedException();
throw new ResourceClassNotSupportedException();
}

return ['foo' => 'bar'];
// Retrieve the blog post collection from somewhere
return [new BlogPost(1), new BlogPost(2)];
}
}
```

## Custom item data provider

Declare a Symfony service, for example:
Then declare a Symfony service, for example:

```yaml

# AppBundle\Resources\config\services.yml
# app/config/services.yml

services:
blog_post.item_data_provider:
class: 'AppBundle\DataProvider\BlogPostItemDataProvider'
decorates: 'api_platform.item_data_provider'
arguments:
- '@blog_post.item_data_provider.inner'
blog_post.collection_data_provider:
class: 'AppBundle\DataProvider\BlogPostCollectionDataProvider'
tags:
- { name: 'api_platform.collection_data_provider', priority: 2 }
```

Then, your `BlogPostItemDataProvider` has to implement the [`ItemDataProviderInterface`](https://github.com/api-platform/core/blob/master/src/Api/ItemDataProviderInterface.php):
Tagging the service with the tag `api_platform.collection_data_provider` will enable API Platform Core to automatically
register and use this data provider. The optional attribute `priority` allows to define the order in wich are called the
data providers. The first data provider not throwing a `ApiPlatform\Core\Exception\ResourceClassNotSupportedException` will
be used.

## Custom item data provider

The process is similar for item data providers. Create a `BlogPostItemDataProvider` implementing the [`ItemDataProviderInterface`](https://github.com/api-platform/core/blob/master/src/Api/ItemDataProviderInterface.php)
interface:

The `getItem` method can return `null` if no result has been found.

Expand All @@ -100,26 +86,30 @@ use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;

class BlogPostItemDataProvider implements ItemDataProviderInterface
{
private $decorated;

public function __construct(ItemDataProviderInterface $decorated = null)
{
$this->decorated = $decorated;
}

/**
* {@inheritdoc}
*/
public function getCollection(string $resourceClass, string $operationName = null)
public function getItem(string $resourceClass, $id, string $operationName = null, bool $fetchData = false);
{
if (BlogPost::class !== $resourceClass) {
throw new ResourceClassNotSupportedException();
}

return (object) ['foo' => 'bar'];
// Retrieve the blog post item from somewhere
return new BlogPost($id);
}
}
```

The tag to use for item data providers is `api_platform.item_data_provider`. As for collection data providers, the `priority`
attribute can be used to order providers.

```yaml
# app/config/services.yml

services:
blog_post.collection_data_provider:
class: 'AppBundle\DataProvider\BlogPostCollectionDataProvider'
tags:
- { name: 'api_platform.item_data_provider' }
```

Previous chapter: [Operations](operations.md)<br>
Next chapter: [Filters](filters.md)