Completed
Push — master ( 8c259e...a3e53b )
by Guilherme
27:10 queued 12:02
created

CountWalker   A

Complexity

Total Complexity 5

Size/Duplication

Total Lines 54
Duplicated Lines 0 %

Test Coverage

Coverage 95.83%

Importance

Changes 0
Metric Value
eloc 25
c 0
b 0
f 0
dl 0
loc 54
ccs 23
cts 24
cp 0.9583
rs 10
wmc 5

1 Method

Rating   Name   Duplication   Size   Complexity  
A walkSelectStatement() 0 42 5
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ORM\Tools\Pagination;
6
7
use Doctrine\ORM\Mapping\AssociationMetadata;
8
use Doctrine\ORM\Mapping\ToOneAssociationMetadata;
9
use Doctrine\ORM\Query\AST\AggregateExpression;
10
use Doctrine\ORM\Query\AST\PathExpression;
11
use Doctrine\ORM\Query\AST\SelectExpression;
12
use Doctrine\ORM\Query\AST\SelectStatement;
13
use Doctrine\ORM\Query\TreeWalkerAdapter;
14
use RuntimeException;
15
use function count;
16
use function reset;
17
18
/**
19
 * Replaces the selectClause of the AST with a COUNT statement.
20
 */
21
class CountWalker extends TreeWalkerAdapter
22
{
23
    /**
24
     * Distinct mode hint name.
25
     */
26
    public const HINT_DISTINCT = 'doctrine_paginator.distinct';
27
28
    /**
29
     * Walks down a SelectStatement AST node, modifying it to retrieve a COUNT.
30
     *
31
     * @throws RuntimeException
32
     */
33 16
    public function walkSelectStatement(SelectStatement $AST)
34
    {
35 16
        if ($AST->havingClause) {
36 3
            throw new RuntimeException('Cannot count query that uses a HAVING clause. Use the output walkers for pagination');
37
        }
38
39 13
        $queryComponents = $this->getQueryComponents();
40
        // Get the root entity and alias from the AST fromClause
41 13
        $from = $AST->fromClause->identificationVariableDeclarations;
42
43 13
        if (count($from) > 1) {
44
            throw new RuntimeException('Cannot count query which selects two FROM components, cannot make distinction');
45
        }
46
47 13
        $fromRoot  = reset($from);
48 13
        $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable;
49 13
        $rootClass = $queryComponents[$rootAlias]['metadata'];
50 13
        $property  = $rootClass->getProperty($rootClass->getSingleIdentifierFieldName());
51 13
        $pathType  = PathExpression::TYPE_STATE_FIELD;
52
53 13
        if ($property instanceof AssociationMetadata) {
54 1
            $pathType = $property instanceof ToOneAssociationMetadata
55 1
                ? PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION
56 1
                : PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION;
57
        }
58
59 13
        $pathExpression = new PathExpression(
60 13
            PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION,
61
            $rootAlias,
62 13
            $property->getName()
63
        );
64
65 13
        $pathExpression->type = $pathType;
66
67 13
        $distinct = $this->getQuery()->getHint(self::HINT_DISTINCT);
68
69 13
        $AST->selectClause->selectExpressions = [
70 13
            new SelectExpression(new AggregateExpression('count', $pathExpression, $distinct), null),
71
        ];
72
73
        // ORDER BY is not needed, only increases query execution through unnecessary sorting.
74 13
        $AST->orderByClause = null;
75 13
    }
76
}
77