OrderByToSelectWalker   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 75
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 7

Importance

Changes 0
Metric Value
wmc 14
lcom 0
cbo 7
dl 0
loc 75
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
C walkSelectStatement() 0 54 12
A createSelectExpressionItem() 0 12 2
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\DoctrineORMAdminBundle\Datagrid;
15
16
use Doctrine\ORM\Query\AST\Functions\IdentityFunction;
17
use Doctrine\ORM\Query\AST\OrderByClause;
18
use Doctrine\ORM\Query\AST\PathExpression;
19
use Doctrine\ORM\Query\AST\SelectExpression;
20
use Doctrine\ORM\Query\AST\SelectStatement;
21
use Doctrine\ORM\Query\TreeWalkerAdapter;
22
23
/**
24
 * Finds all PathExpressions in an AST's OrderByClause, and ensures that
25
 * the referenced fields are present in the SelectClause of the passed AST.
26
 *
27
 * Inspired by Doctrine\ORM\Tools\Pagination classes.
28
 *
29
 * @author Dariusz Markowicz <[email protected]>
30
 */
31
final class OrderByToSelectWalker extends TreeWalkerAdapter
32
{
33
    public function walkSelectStatement(SelectStatement $AST): void
34
    {
35
        if (!$AST->orderByClause instanceof OrderByClause) {
36
            return;
37
        }
38
39
        // Get a map of referenced identifiers to field names.
40
        $selects = [];
41
        foreach ($AST->orderByClause->orderByItems as $item) {
42
            if (!$item->expression instanceof PathExpression) {
43
                continue;
44
            }
45
46
            $pathExpression = $item->expression;
47
            $idVar = $pathExpression->identificationVariable;
48
            $field = $pathExpression->field;
49
            if (!isset($selects[$idVar])) {
50
                $selects[$idVar] = [];
51
            }
52
            $selects[$idVar][$field] = $pathExpression;
53
        }
54
55
        // Loop the select clause of the AST and exclude items from $selects
56
        // that are already being selected in the query.
57
        foreach ($AST->selectClause->selectExpressions as $selectExpression) {
58
            if ($selectExpression instanceof SelectExpression) {
59
                $idVar = $selectExpression->expression;
60
                if ($idVar instanceof IdentityFunction) {
61
                    $idVar = $idVar->pathExpression->identificationVariable;
62
                }
63
                if (!\is_string($idVar)) {
64
                    continue;
65
                }
66
                $field = $selectExpression->fieldIdentificationVariable;
67
                if (null === $field) {
68
                    // No need to add this select, as we're already fetching the whole object.
69
                    unset($selects[$idVar]);
70
                } else {
71
                    unset($selects[$idVar][$field]);
72
                }
73
            }
74
        }
75
76
        // Add select items which were not excluded to the AST's select clause.
77
        foreach ($selects as $idVar => $fields) {
78
            foreach ($fields as $field => $expression) {
79
                $AST->selectClause->selectExpressions[] = new SelectExpression(
80
                    $this->createSelectExpressionItem($expression),
81
                    null,
82
                    true
83
                );
84
            }
85
        }
86
    }
87
88
    /**
89
     * Retrieve either an IdentityFunction (IDENTITY(u.assoc)) or a state field (u.name).
90
     *
91
     * @return IdentityFunction|PathExpression
92
     */
93
    private function createSelectExpressionItem(PathExpression $pathExpression)
94
    {
95
        if (PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION === $pathExpression->type) {
96
            $identity = new IdentityFunction('identity');
97
98
            $identity->pathExpression = clone $pathExpression;
99
100
            return $identity;
101
        }
102
103
        return clone $pathExpression;
104
    }
105
}
106