Skip to content

Commit 427ef3a

Browse files
committed
fix dbal pagination count with groupBy
1 parent 59ef316 commit 427ef3a

File tree

9 files changed

+41
-44
lines changed

9 files changed

+41
-44
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
parameters:
22
ignoreErrors:
3-
-
4-
message: "#^Call to an undefined method Doctrine\\\\DBAL\\\\Query\\\\QueryBuilder\\:\\:resetQueryParts\\(\\)\\.$#"
5-
count: 1
6-
path: src/Knp/Component/Pager/Event/Subscriber/Paginate/Doctrine/DBALQueryBuilderSubscriber.php
7-
83
-
94
message: "#^Method Knp\\\\Component\\\\Pager\\\\Event\\\\Subscriber\\\\Sortable\\\\ArraySubscriber\\:\\:sortFunction\\(\\) has parameter \\$object1 with no value type specified in iterable type array\\.$#"
105
count: 1

src/Knp/Component/Pager/Event/BeforeEvent.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Knp\Component\Pager\Event;
44

5+
use Doctrine\DBAL\Connection;
56
use Knp\Component\Pager\ArgumentAccess\ArgumentAccessInterface;
67
use Symfony\Contracts\EventDispatcher\Event;
78
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
@@ -11,14 +12,11 @@
1112
*/
1213
final class BeforeEvent extends Event
1314
{
14-
private EventDispatcherInterface $eventDispatcher;
15-
16-
private ArgumentAccessInterface $argumentAccess;
17-
18-
public function __construct(EventDispatcherInterface $eventDispatcher, ArgumentAccessInterface $argumentAccess)
19-
{
20-
$this->eventDispatcher = $eventDispatcher;
21-
$this->argumentAccess = $argumentAccess;
15+
public function __construct(
16+
private EventDispatcherInterface $eventDispatcher,
17+
private ArgumentAccessInterface $argumentAccess,
18+
private ?Connection $connection = null
19+
) {
2220
}
2321

2422
public function getEventDispatcher(): EventDispatcherInterface
@@ -30,4 +28,9 @@ public function getArgumentAccess(): ArgumentAccessInterface
3028
{
3129
return $this->argumentAccess;
3230
}
31+
32+
public function getConnection(): ?Connection
33+
{
34+
return $this->connection;
35+
}
3336
}

src/Knp/Component/Pager/Event/Subscriber/Paginate/Doctrine/DBALQueryBuilderSubscriber.php

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Knp\Component\Pager\Event\Subscriber\Paginate\Doctrine;
44

5+
use Doctrine\DBAL\Connection;
56
use Doctrine\DBAL\Query\QueryBuilder;
67
use Knp\Component\Pager\Event\ItemsEvent;
78
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -13,26 +14,21 @@
1314
*/
1415
class DBALQueryBuilderSubscriber implements EventSubscriberInterface
1516
{
17+
public function __construct(private Connection $connection)
18+
{
19+
}
20+
1621
public function items(ItemsEvent $event): void
1722
{
1823
if ($event->target instanceof QueryBuilder) {
1924
$target = $event->target;
20-
21-
// count results
22-
$qb = clone $target;
23-
24-
//reset count orderBy since it can break query and slow it down
25-
if (method_exists($qb, 'resetOrderBy')) {
26-
$qb->resetOrderBy();
27-
} else {
28-
$qb->resetQueryParts(['orderBy']);
29-
}
30-
31-
// get the query
32-
$sql = $qb->getSQL();
3325

34-
$qb
35-
->select('count(*) as cnt')
26+
$qb = $this
27+
->connection
28+
->createQueryBuilder()
29+
->select('COUNT(*)')
30+
->from('(' . $target->getSQL() . ')', 'tmp')
31+
->setParameters($target->getParameters(), $target->getParameterTypes())
3632
;
3733

3834
$compat = $qb->executeQuery();

src/Knp/Component/Pager/Event/Subscriber/Paginate/PaginationSubscriber.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ public function before(BeforeEvent $event): void
3939
$dispatcher->addSubscriber(new Doctrine\ODM\PHPCR\QueryBuilderSubscriber);
4040
$dispatcher->addSubscriber(new Doctrine\ODM\PHPCR\QuerySubscriber);
4141
$dispatcher->addSubscriber(new Doctrine\CollectionSubscriber);
42-
$dispatcher->addSubscriber(new Doctrine\DBALQueryBuilderSubscriber);
42+
if (null !== $connection = $event->getConnection()) {
43+
$dispatcher->addSubscriber(new Doctrine\DBALQueryBuilderSubscriber($connection));
44+
}
4345
$dispatcher->addSubscriber(new PropelQuerySubscriber);
4446
$dispatcher->addSubscriber(new SolariumQuerySubscriber());
4547
$dispatcher->addSubscriber(new ElasticaQuerySubscriber());

src/Knp/Component/Pager/Paginator.php

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Knp\Component\Pager;
44

5+
use Doctrine\DBAL\Connection;
56
use Knp\Component\Pager\ArgumentAccess\ArgumentAccessInterface;
67
use Knp\Component\Pager\Exception\PageLimitInvalidException;
78
use Knp\Component\Pager\Exception\PageNumberInvalidException;
@@ -17,8 +18,6 @@
1718
*/
1819
final class Paginator implements PaginatorInterface
1920
{
20-
private EventDispatcherInterface $eventDispatcher;
21-
2221
/**
2322
* Default options of paginator
2423
*
@@ -35,12 +34,11 @@ final class Paginator implements PaginatorInterface
3534
self::DEFAULT_LIMIT => self::DEFAULT_LIMIT_VALUE,
3635
];
3736

38-
private ArgumentAccessInterface $argumentAccess;
39-
40-
public function __construct(EventDispatcherInterface $eventDispatcher, ArgumentAccessInterface $argumentAccess)
41-
{
42-
$this->eventDispatcher = $eventDispatcher;
43-
$this->argumentAccess = $argumentAccess;
37+
public function __construct(
38+
private EventDispatcherInterface $eventDispatcher,
39+
private ArgumentAccessInterface $argumentAccess,
40+
private ?Connection $connection = null
41+
) {
4442
}
4543

4644
/**
@@ -89,7 +87,7 @@ public function paginate($target, int $page = 1, int $limit = null, array $optio
8987
}
9088

9189
// before pagination start
92-
$beforeEvent = new Event\BeforeEvent($this->eventDispatcher, $this->argumentAccess);
90+
$beforeEvent = new Event\BeforeEvent($this->eventDispatcher, $this->argumentAccess, $this->connection);
9391
$this->eventDispatcher->dispatch($beforeEvent, 'knp_pager.before');
9492
// items
9593
$itemsEvent = new Event\ItemsEvent($offset, $limit);

tests/Test/Fixture/Document/Image.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace Test\Fixture\Document;
44

5-
use Doctrine\ODM\PHPCR\Mapping\Annotations as PHPCRAnnotations;
65
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
76

87
/**

tests/Test/Pager/Subscriber/Paginate/Doctrine/DBALQueryBuilderTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ final class DBALQueryBuilderTest extends BaseTestCaseORM
1414
public function shouldPaginateSimpleDoctrineQuery(): void
1515
{
1616
$this->populate();
17-
$p = $this->getPaginatorInstance();
17+
$p = $this->getPaginatorInstance(null, null, $this->em->getConnection());
1818

1919
$qb = new QueryBuilder($this->em->getConnection());
2020
$qb->select('*')

tests/Test/Pager/Subscriber/Paginate/PaginationSubscriberTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ final class PaginationSubscriberTest extends BaseTestCase
1616
public function shouldRegisterExpectedSubscribersOnlyOnce(): void
1717
{
1818
$dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock();
19-
$dispatcher->expects($this->exactly(13))->method('addSubscriber');
19+
$dispatcher->expects($this->exactly(12))->method('addSubscriber');
2020

2121
$subscriber = new PaginationSubscriber;
2222

tests/Test/Tool/BaseTestCase.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Test\Tool;
44

5+
use Doctrine\DBAL\Connection;
56
use Knp\Component\Pager\ArgumentAccess\ArgumentAccessInterface;
67
use Knp\Component\Pager\ArgumentAccess\RequestArgumentAccess;
78
use Knp\Component\Pager\Event\Subscriber\Paginate\PaginationSubscriber;
@@ -17,8 +18,11 @@
1718
*/
1819
abstract class BaseTestCase extends TestCase
1920
{
20-
protected function getPaginatorInstance(?RequestStack $requestStack = null, ?EventDispatcher $dispatcher = null): Paginator
21-
{
21+
protected function getPaginatorInstance(
22+
?RequestStack $requestStack = null,
23+
?EventDispatcher $dispatcher = null,
24+
?Connection $connection = null
25+
): Paginator {
2226
if (null === $dispatcher) {
2327
$dispatcher = new EventDispatcher();
2428
$dispatcher->addSubscriber(new PaginationSubscriber());
@@ -30,7 +34,7 @@ protected function getPaginatorInstance(?RequestStack $requestStack = null, ?Eve
3034
$accessor = $this->createMock(ArgumentAccessInterface::class);
3135
}
3236

33-
return new Paginator($dispatcher, $accessor);
37+
return new Paginator($dispatcher, $accessor, $connection);
3438
}
3539

3640
protected function createRequestStack(array $params): RequestStack

0 commit comments

Comments
 (0)