Skip to content

Commit a47f871

Browse files
committed
Merge pull request #154 from dunglas/paginator_extension_point
Extension point for Paginator. Disable output walkers by default.
2 parents 2d60104 + a15f8d2 commit a47f871

File tree

4 files changed

+75
-4
lines changed

4 files changed

+75
-4
lines changed

Doctrine/Orm/DataProvider.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Doctrine\Common\Persistence\ManagerRegistry;
1515
use Doctrine\ORM\Tools\Pagination\Paginator as DoctrineOrmPaginator;
16+
use Doctrine\ORM\QueryBuilder;
1617
use Dunglas\ApiBundle\Doctrine\Orm\Filter\FilterInterface;
1718
use Dunglas\ApiBundle\Model\DataProviderInterface;
1819
use Dunglas\ApiBundle\Api\ResourceInterface;
@@ -126,7 +127,23 @@ public function getCollection(ResourceInterface $resource, Request $request)
126127
$queryBuilder->addOrderBy('o.'.$identifier, $this->order);
127128
}
128129

129-
return new Paginator(new DoctrineOrmPaginator($queryBuilder));
130+
return $this->getPaginator($queryBuilder);
131+
}
132+
133+
/**
134+
* Gets the paginator.
135+
*
136+
* @param QueryBuilder $queryBuilder
137+
*
138+
* @return Paginator
139+
*/
140+
protected function getPaginator(QueryBuilder $queryBuilder)
141+
{
142+
$doctrineOrmPaginator = new DoctrineOrmPaginator($queryBuilder);
143+
// Disable output walkers by default (performance)
144+
$doctrineOrmPaginator->setUseOutputWalkers(false);
145+
146+
return new Paginator($doctrineOrmPaginator);
130147
}
131148

132149
/**

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ This bundle is documented and tested with Behat (take a look at [the `features/`
5555
4. [Data providers](Resources/doc/data-providers.md)
5656
1. [Creating a custom data provider](Resources/doc/data-providers.md#creating-a-custom-data-provider)
5757
2. [Returning a paged collection](Resources/doc/data-providers.md#returning-a-paged-collection)
58-
3. [Supporting filters](Resources/doc/data-providers.md#Supporting-filters)
58+
3. [Supporting filters](Resources/doc/data-providers.md#supporting-filters)
59+
4. [Extending the Doctrine Data Provider](Resources/doc/data-providers.md#extending-the-doctrine-data-provider)
5960
5. [Filters](Resources/doc/filters.md)
6061
1. [Search filter](Resources/doc/filters.md#search-filter)
6162
2. [Date filter](Resources/doc/filters.md#date-filter)

Resources/config/doctrine_orm.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@
1616
<tag name="kernel.event_subscriber" />
1717
</service>
1818

19-
<service id="api.doctrine.orm.data_provider" class="Dunglas\ApiBundle\Doctrine\Orm\DataProvider" public="false">
19+
<service id="api.doctrine.orm.data_provider" public="false" abstract="true">
2020
<argument type="service" id="doctrine" />
2121
<argument>%api.collection.order%</argument>
2222
<argument>%api.collection.pagination.page_parameter_name%</argument>
2323
<argument>%api.collection.pagination.items_per_page.number%</argument>
2424
<argument>%api.collection.pagination.items_per_page.enable_client_request%</argument>
2525
<argument>%api.collection.pagination.items_per_page.parameter_name%</argument>
26+
</service>
2627

28+
<service id="api.doctrine.orm.default_data_provider" parent="api.doctrine.orm.data_provider" class="Dunglas\ApiBundle\Doctrine\Orm\DataProvider">
2729
<tag name="api.data_provider" />
2830
</service>
2931

Resources/doc/data-providers.md

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Data providers
22

33
To retrieve data that will be exposed by the API, DunglasApiBundle use classes called data providers. A data provider
4-
using Doctrine ORM to retrieve data from a database is included with the bundle and enabled by default. This data provider
4+
using [Doctrine ORM](http://www.doctrine-project.org/projects/orm.html) to retrieve data from a database is included with the bundle and enabled by default. This data provider
55
natively supports paged collection and filters. It can be used as is and fits perfectly with common usages.
66

77
But sometime, you want to retrieve data from other sources such as a webservice, ElasticSearch, MongoDB or another ORM.
@@ -85,5 +85,56 @@ To create your own paginators, take a look at the Doctrine ORM paginator bridge:
8585
To be able [to filter collections](filters.md), the Data Provider must be aware of registered filters to the given resource.
8686
The best way to learn how to create filter aware data provider is too look at the default Doctrine ORM dataprovider: [`Dunglas\ApiBundle\Doctrine\Orm\DataProvider`](/Doctrine/Orm/DataProvider.php).
8787

88+
## Extending the Doctrine Data Provider
89+
90+
The bundle is provided with a data provider leveraging the Doctrine ORM. This default data provider can be extended.
91+
92+
For performance reasons, [custom output walkers for the Doctrine ORM Paginator](http://www.doctrine-project.org/jira/browse/DDC-3282)
93+
are disabled. It drastically improves performance when dealing with large collections. However it prevents advanced [filters](filters.md)
94+
adding `HAVING` and `GROUP BY` clauses to DQL queries to work properly.
95+
96+
To enable custom output walkers, start by creating a custom data provider supporting the `AppBundle\Entity\MyEntity` class:
97+
98+
```php
99+
<?php
100+
101+
// src/AppBundle/DataProvider/MyEntityDataProvider.php
102+
103+
namespace AppBundle\DataProvider;
104+
105+
use Dunglas\ApiBundle\Doctrine\Orm\DataProvider;
106+
use Dunglas\ApiBundle\Model\DataProviderInterface;
107+
108+
class MyEntityDataProvider extends DataProvider
109+
{
110+
protected function getPaginator(QueryBuilder $queryBuilder)
111+
{
112+
$doctrineOrmPaginator = new DoctrineOrmPaginator($queryBuilder);
113+
// Enable output walkers to make queries with HAVING and ORDER BY clauses working
114+
$doctrineOrmPaginator->setUseOutputWalkers(true);
115+
116+
return new Paginator($doctrineOrmPaginator);
117+
}
118+
119+
public function supports(ResourceInterface $resource)
120+
{
121+
return 'AppBundle\Entity\MyEntity' === $resource->getEntityClass();
122+
}
123+
}
124+
```
125+
126+
Then register the data provider:
127+
128+
```yaml
129+
130+
# app/config/services.yml
131+
132+
services:
133+
my_entity_data_provider:
134+
parent: "api.doctrine.orm.data_provider"
135+
class: AppBundle\DataProvider\MyEntityDataProvider
136+
tags: [ { name: "api.data_provider", priority: 1 } ]
137+
```
138+
88139
Previous chapter: [Operations](operations.md)<br>
89140
Next chapter: [Filters](filters.md)

0 commit comments

Comments
 (0)