Failed Conditions
Pull Request — master (#6959)
by Matthew
19:32
created

CountWalker   A

Complexity

Total Complexity 5

Size/Duplication

Total Lines 57
Duplicated Lines 0 %

Test Coverage

Coverage 84.62%

Importance

Changes 0
Metric Value
dl 0
loc 57
rs 10
c 0
b 0
f 0
ccs 22
cts 26
cp 0.8462
wmc 5

1 Method

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