Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 05ab13d

Browse files
vvasiloipamil
authored andcommitted
make doctrine orm paginator fetchJoinCollection and useOutputWalkers arguments configurable per grid and add default value for all grids
1 parent 61d0919 commit 05ab13d

8 files changed

Lines changed: 174 additions & 9 deletions

File tree

src/Bundle/Doctrine/ORM/DataSource.php

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,29 @@ final class DataSource implements DataSourceInterface
2828
/** @var ExpressionBuilderInterface */
2929
private $expressionBuilder;
3030

31-
public function __construct(QueryBuilder $queryBuilder)
32-
{
31+
/** @var bool */
32+
private $fetchJoinCollection;
33+
34+
/** @var bool|null */
35+
private $useOutputWalkers;
36+
37+
/**
38+
* @param bool $fetchJoinCollection must be 'true' when the query fetch-joins a to-many collection,
39+
* otherwise the pagination will yield incorrect results
40+
* https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/tutorials/pagination.html
41+
* @param bool|null $useOutputWalkers must be 'true' if the query has an order by statement for a field from
42+
* the to-many association, otherwise it will throw an exception
43+
* might greatly affect the performance (https://github.com/Sylius/Sylius/issues/3775)
44+
*/
45+
public function __construct(
46+
QueryBuilder $queryBuilder,
47+
bool $fetchJoinCollection = false,
48+
?bool $useOutputWalkers = false
49+
) {
3350
$this->queryBuilder = $queryBuilder;
3451
$this->expressionBuilder = new ExpressionBuilder($queryBuilder);
52+
$this->fetchJoinCollection = $fetchJoinCollection;
53+
$this->useOutputWalkers = $useOutputWalkers;
3554
}
3655

3756
public function restrict($expression, string $condition = DataSourceInterface::CONDITION_AND): void
@@ -55,8 +74,7 @@ public function getExpressionBuilder(): ExpressionBuilderInterface
5574

5675
public function getData(Parameters $parameters)
5776
{
58-
// Use output walkers option in DoctrineORMAdapter should be false as it affects performance greatly. (see #3775)
59-
$paginator = new Pagerfanta(new DoctrineORMAdapter($this->queryBuilder, false, false));
77+
$paginator = new Pagerfanta(new DoctrineORMAdapter($this->queryBuilder, $this->fetchJoinCollection, $this->useOutputWalkers));
6078
$paginator->setNormalizeOutOfRangePages(true);
6179
$paginator->setCurrentPage($parameters->get('page', 1));
6280

src/Bundle/Doctrine/ORM/Driver.php

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,24 @@ final class Driver implements DriverInterface
2727
/** @var ManagerRegistry */
2828
private $managerRegistry;
2929

30-
public function __construct(ManagerRegistry $managerRegistry)
31-
{
30+
/** @var bool */
31+
private $fetchJoinCollection;
32+
33+
/** @var bool|null */
34+
private $useOutputWalkers;
35+
36+
/**
37+
* @param bool $fetchJoinCollection {@see \Sylius\Bundle\GridBundle\Doctrine\ORM\DataSource::__construct}
38+
* @param bool|null $useOutputWalkers {@see \Sylius\Bundle\GridBundle\Doctrine\ORM\DataSource::__construct}
39+
*/
40+
public function __construct(
41+
ManagerRegistry $managerRegistry,
42+
bool $fetchJoinCollection = false,
43+
?bool $useOutputWalkers = false
44+
) {
3245
$this->managerRegistry = $managerRegistry;
46+
$this->fetchJoinCollection = $fetchJoinCollection;
47+
$this->useOutputWalkers = $useOutputWalkers;
3348
}
3449

3550
public function getDataSource(array $configuration, Parameters $parameters): DataSourceInterface
@@ -44,8 +59,11 @@ public function getDataSource(array $configuration, Parameters $parameters): Dat
4459
/** @var EntityRepository $repository */
4560
$repository = $manager->getRepository($configuration['class']);
4661

62+
$fetchJoinCollection = $configuration['pagination']['fetch_join_collection'] ?? $this->fetchJoinCollection;
63+
$useOutputWalkers = $configuration['pagination']['use_output_walkers'] ?? $this->useOutputWalkers;
64+
4765
if (!isset($configuration['repository']['method'])) {
48-
return new DataSource($repository->createQueryBuilder('o'));
66+
return new DataSource($repository->createQueryBuilder('o'), $fetchJoinCollection, $useOutputWalkers);
4967
}
5068

5169
$arguments = isset($configuration['repository']['arguments']) ? array_values($configuration['repository']['arguments']) : [];
@@ -54,9 +72,9 @@ public function getDataSource(array $configuration, Parameters $parameters): Dat
5472
$queryBuilder = $method[0];
5573
$method = $method[1];
5674

57-
return new DataSource($queryBuilder->$method(...$arguments));
75+
return new DataSource($queryBuilder->$method(...$arguments), $fetchJoinCollection, $useOutputWalkers);
5876
}
5977

60-
return new DataSource($repository->$method(...$arguments));
78+
return new DataSource($repository->$method(...$arguments), $fetchJoinCollection, $useOutputWalkers);
6179
}
6280
}

src/Bundle/Resources/config/services/integrations/doctrine/orm.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,17 @@
1212
-->
1313

1414
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
15+
<parameters>
16+
<parameter key="sylius.grid.doctrine.orm.paginator.fetch_join_collection">false</parameter>
17+
<parameter key="sylius.grid.doctrine.orm.paginator.use_output_walkers">false</parameter>
18+
</parameters>
1519
<services>
1620
<defaults public="true" />
1721

1822
<service id="sylius.grid_driver.doctrine.orm" class="Sylius\Bundle\GridBundle\Doctrine\ORM\Driver">
1923
<argument type="service" id="doctrine" />
24+
<argument type="string">%sylius.grid.doctrine.orm.paginator.fetch_join_collection%</argument>
25+
<argument type="string">%sylius.grid.doctrine.orm.paginator.use_output_walkers%</argument>
2026
<tag name="sylius.grid_driver" alias="doctrine/orm" />
2127
</service>
2228
<service id="sylius.grid_driver.doctrine.dbal" class="Sylius\Bundle\GridBundle\Doctrine\DBAL\Driver">
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Paweł Jędrzejewski
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Sylius\Bundle\GridBundle\Tests\Functional;
15+
16+
use ApiTestCase\JsonApiTestCase;
17+
18+
class PaginationTest extends JsonApiTestCase
19+
{
20+
protected function setUp(): void
21+
{
22+
parent::setUp();
23+
24+
$this->loadFixturesFromFile('fixtures.yml');
25+
}
26+
27+
/** @test */
28+
public function it_returns_incorrect_amount_of_items_per_page_with_fetch_join_collection_disabled(): void
29+
{
30+
$this->client->request('GET', '/books/by-author/with-fetch-join-collection-disabled');
31+
32+
self::assertNotCount(10, $this->getItemsFromCurrentResponse());
33+
}
34+
35+
/** @test */
36+
public function it_returns_correct_amount_of_items_per_page_with_fetch_join_collection_enabled(): void
37+
{
38+
$this->client->request('GET', '/books/by-author/with-fetch-join-collection-enabled');
39+
40+
self::assertCount(10, $this->getItemsFromCurrentResponse());
41+
}
42+
43+
private function getItemsFromCurrentResponse(): array
44+
{
45+
return json_decode($this->client->getResponse()->getContent(), true, 512, \JSON_THROW_ON_ERROR)['_embedded']['items'];
46+
}
47+
}

src/Bundle/test/app/config/grids.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,21 @@ sylius_grid:
149149
path: na.name
150150
sortable: na.name
151151
limits: [10, 5, 15]
152+
153+
app_books_by_author_with_fetch_join_collection_disabled:
154+
extends: app_author
155+
driver:
156+
options:
157+
repository:
158+
method: [expr:service('app.books_by_author_query_builder'), create]
159+
pagination:
160+
fetch_join_collection: false
161+
162+
app_books_by_author_with_fetch_join_collection_enabled:
163+
extends: app_author
164+
driver:
165+
options:
166+
repository:
167+
method: [ expr:service('app.books_by_author_query_builder'), create ]
168+
pagination:
169+
fetch_join_collection: true

src/Bundle/test/app/config/routing.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,19 @@ app_books_by_english_authors:
2929
only: ['index']
3030
type: sylius.resource_api
3131
prefix: /by-english-authors
32+
33+
app_books_by_author_with_fetch_join_collection_disabled:
34+
path: /books/by-author/with-fetch-join-collection-disabled
35+
methods: [GET]
36+
defaults:
37+
_controller: app.controller.author:indexAction
38+
_sylius:
39+
grid: app_books_by_author_with_fetch_join_collection_disabled
40+
41+
app_books_by_author_with_fetch_join_collection_enabled:
42+
path: /books/by-author/with-fetch-join-collection-enabled
43+
methods: [GET]
44+
defaults:
45+
_controller: app.controller.author:indexAction
46+
_sylius:
47+
grid: app_books_by_author_with_fetch_join_collection_enabled

src/Bundle/test/app/config/services.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,9 @@ services:
44
arguments:
55
- '@app.repository.book'
66
public: true
7+
8+
app.books_by_author_query_builder:
9+
class: AppBundle\QueryBuilder\BooksByAuthorQueryBuilder
10+
arguments:
11+
- '@app.repository.author'
12+
public: true
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Paweł Jędrzejewski
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace AppBundle\QueryBuilder;
15+
16+
use Doctrine\ORM\QueryBuilder;
17+
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
18+
19+
final class BooksByAuthorQueryBuilder
20+
{
21+
/** @var EntityRepository */
22+
private $authorRepository;
23+
24+
public function __construct(EntityRepository $authorRepository)
25+
{
26+
$this->authorRepository = $authorRepository;
27+
}
28+
29+
public function create(): QueryBuilder
30+
{
31+
return $this->authorRepository->createQueryBuilder('a')
32+
->addSelect('book')
33+
->innerJoin('a.books', 'book')
34+
;
35+
}
36+
}

0 commit comments

Comments
 (0)