Completed
Push — master ( 799620...8a5869 )
by Kamil
116:02 queued 102:30
created

GridBundle/Doctrine/PHPCRODM/ExpressionVisitor.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Doctrine\PHPCRODM;
15
16
use Doctrine\Common\Collections\Expr\Comparison;
17
use Doctrine\Common\Collections\Expr\CompositeExpression;
18
use Doctrine\Common\Collections\Expr\Expression;
19
use Doctrine\ODM\PHPCR\Query\Builder\AbstractNode;
20
use Doctrine\ODM\PHPCR\Query\Builder\QueryBuilder;
21
22
/**
23
 * Walks a Doctrine\Commons\Expr object graph and builds up a PHPCR-ODM
24
 * query using the (fluent) PHPCR-ODM query builder.
25
 */
26
final class ExpressionVisitor
27
{
28
    private $queryBuilder;
29
30
    /**
31
     * @param QueryBuilder $queryBuilder
32
     */
33
    public function __construct(QueryBuilder $queryBuilder)
34
    {
35
        $this->queryBuilder = $queryBuilder;
36
    }
37
38
    /**
39
     * @param Comparison $comparison
40
     * @param AbstractNode $parentNode
41
     *
42
     * @return mixed
43
     *
44
     * @throws \RuntimeException
45
     */
46
    public function walkComparison(Comparison $comparison, AbstractNode $parentNode)
47
    {
48
        $field = $comparison->getField();
49
        $value = $comparison->getValue()->getValue(); // shortcut for walkValue()
50
51
        switch ($comparison->getOperator()) {
52
            case Comparison::EQ:
53
                return $parentNode->eq()->field($this->getField($field))->literal($value)->end();
54
            case Comparison::NEQ:
55
                return $parentNode->neq()->field($this->getField($field))->literal($value)->end();
56
            case Comparison::LT:
57
                return $parentNode->lt()->field($this->getField($field))->literal($value)->end();
58
            case Comparison::LTE:
59
                return $parentNode->lte()->field($this->getField($field))->literal($value)->end();
60
            case Comparison::GT:
61
                return $parentNode->gt()->field($this->getField($field))->literal($value)->end();
62
            case Comparison::GTE:
63
                return $parentNode->gte()->field($this->getField($field))->literal($value)->end();
64
            case Comparison::IN:
65
                return $this->getInConstraint($parentNode, $field, $value);
66
            case Comparison::NIN:
67
                $node = $parentNode->not();
68
                $this->getInConstraint($node, $field, $value);
69
70
                return $node->end();
71
            case Comparison::CONTAINS:
72
                return $parentNode->like()->field($this->getField($field))->literal($value)->end();
73
            case ExtraComparison::NOT_CONTAINS:
74
                return $parentNode->not()->like()->field($this->getField($field))->literal($value)->end()->end();
75
            case ExtraComparison::IS_NULL:
76
                return $parentNode->not()->fieldIsset($this->getField($field))->end();
77
            case ExtraComparison::IS_NOT_NULL:
78
                return $parentNode->fieldIsset($this->getField($field));
79
        }
80
81
        throw new \RuntimeException('Unknown comparison operator: ' . $comparison->getOperator());
82
    }
83
84
    /**
85
     * @param CompositeExpression $expr
86
     * @param AbstractNode $parentNode
87
     *
88
     * @return mixed
89
     *
90
     * @throws \RuntimeException
91
     */
92
    public function walkCompositeExpression(CompositeExpression $expr, AbstractNode $parentNode)
93
    {
94
        switch ($expr->getType()) {
95
            case CompositeExpression::TYPE_AND:
96
                $node = $parentNode->andX();
97
98
                break;
99
            case CompositeExpression::TYPE_OR:
100
                $node = $parentNode->orX();
101
102
                break;
103
            default:
104
                throw new \RuntimeException('Unknown composite: ' . $expr->getType());
105
        }
106
107
        $expressions = $expr->getExpressionList();
108
109
        $leftExpression = array_shift($expressions);
110
        $this->dispatch($leftExpression, $node);
0 ignored issues
show
It seems like $leftExpression defined by array_shift($expressions) on line 109 can be null; however, Sylius\Bundle\GridBundle...sionVisitor::dispatch() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
111
112
        $parentNode = $node;
113
        foreach ($expressions as $index => $expression) {
114
            if (count($expressions) === $index + 1) {
115
                $this->dispatch($expression, $parentNode);
116
117
                break;
118
            }
119
120
            switch ($expr->getType()) {
121
                case CompositeExpression::TYPE_AND:
122
                    $parentNode = $parentNode->andX();
123
124
                    break;
125
                case CompositeExpression::TYPE_OR:
126
                    $parentNode = $parentNode->orX();
127
128
                    break;
129
            }
130
131
            $this->dispatch($expression, $parentNode);
132
        }
133
134
        return $node;
135
    }
136
137
    /**
138
     * Walk the given expression to build up the PHPCR-ODM query builder.
139
     *
140
     * @param Expression $expr
141
     * @param AbstractNode|null $parentNode
142
     *
143
     * @return mixed
144
     *
145
     * @throws \RuntimeException
146
     */
147
    public function dispatch(Expression $expr, ?AbstractNode $parentNode = null)
148
    {
149
        if ($parentNode === null) {
150
            $parentNode = $this->queryBuilder->where();
151
        }
152
153
        switch (true) {
154
            case $expr instanceof Comparison:
155
                return $this->walkComparison($expr, $parentNode);
156
            case $expr instanceof CompositeExpression:
157
                return $this->walkCompositeExpression($expr, $parentNode);
158
        }
159
160
        throw new \RuntimeException('Unknown Expression: ' . get_class($expr));
161
    }
162
163
    /**
164
     * @param string $field
165
     *
166
     * @return string
167
     */
168
    private function getField(string $field): string
169
    {
170
        return Driver::QB_SOURCE_ALIAS . '.' . $field;
171
    }
172
173
    /**
174
     * @param AbstractNode $parentNode
175
     * @param string $field
176
     * @param array $values
177
     */
178
    private function getInConstraint(AbstractNode $parentNode, string $field, array $values): void
179
    {
180
        $orNode = $parentNode->orx();
181
182
        foreach ($values as $value) {
183
            $orNode->eq()->field($this->getField($field))->literal($value);
184
        }
185
186
        $orNode->end();
187
    }
188
}
189