Test Failed
Push — master ( b736ea...8d0ac4 )
by Gerhard
26:10 queued 15:52
created

FilterQuery::getOperator()   C

Complexity

Conditions 12
Paths 12

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 156

Importance

Changes 0
Metric Value
dl 0
loc 30
ccs 0
cts 29
cp 0
rs 6.9666
c 0
b 0
f 0
cc 12
nc 12
nop 1
crap 156

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * FilterQuery.php
4
 *
5
 * @since 19/01/17
6
 * @author gseidel
7
 */
8
9
namespace Enhavo\Bundle\AppBundle\Filter;
10
11
12
use Doctrine\ORM\EntityManagerInterface;
13
use Doctrine\ORM\QueryBuilder;
14
use Enhavo\Bundle\AppBundle\Exception\FilterException;
15
16
class FilterQuery
17
{
18
    const OPERATOR_EQUALS = '=';
19
    const OPERATOR_GREATER = '>';
20
    const OPERATOR_LESS = '<';
21
    const OPERATOR_GREATER_EQUAL = '>=';
22
    const OPERATOR_LESS_EQUAL = '<=';
23
    const OPERATOR_NOT = '!=';
24
    const OPERATOR_LIKE = 'like';
25
    const OPERATOR_START_LIKE = 'start_like';
26
    const OPERATOR_END_LIKE = 'end_like';
27
28
    const ORDER_ASC = 'asc';
29
    const ORDER_DESC = 'desc';
30
31
    const HYDRATE_OBJECT = 'object';
32
    const HYDRATE_ID = 'id';
33
34
    /**
35
     * @var array
36
     */
37
    private $where = [];
38
39
    /**
40
     * @var array
41
     */
42
    private $orderBy = [];
43
44
    /**
45
     * @var QueryBuilder
46
     */
47
    private $queryBuilder;
48
49
    /**
50
     * @var string
51
     */
52
    private $alias;
53
54
    /**
55
     * @var string
56
     */
57
    private $hydrate;
58
59
    public function __construct(EntityManagerInterface $em, $class, $alias = 'a')
60
    {
61
        if(strlen($alias) != 1) {
62
            throw new \InvalidArgumentException('Alias should be a single letter');
63
        }
64
65
        $this->alias = $alias;
66
        $this->queryBuilder = new QueryBuilder($em);
67
        $this->queryBuilder->select($this->getAlias());
68
        $this->queryBuilder->from($class, $this->getAlias());
69
    }
70
71
    public function addOrderBy($property, $order, $joinProperty = null)
72
    {
73
        $this->orderBy[] = [
74
            'property' => $property,
75
            'order' => $order,
76
            'joinProperty' => $joinProperty
77
        ];
78
79
        return $this;
80
    }
81
82
    public function removeOrderBy($property, $order)
83
    {
84
        if(!$property && !$order){
85
            return $this;
86
        }
87
        foreach ($this->orderBy as $index => $orderBy){
88
            if($property && $orderBy['property'] !== $property){
89
                continue;
90
            }
91
            if($order && $orderBy['operator'] !== $order){
92
                continue;
93
            }
94
            unset($this->orderBy[$index]);
95
        }
96
97
        return $this;
98
    }
99
100
    public function addWhere($property, $operator, $value, $joinProperty = null)
101
    {
102
        $this->where[] = [
103
            'property' => $property,
104
            'operator' => $operator,
105
            'value' => $value,
106
            'joinProperty' => $joinProperty
107
        ];
108
109
        return $this;
110
    }
111
112
    public function removeWhere($property, $operator, $value, $joinProperty = null)
113
    {
114
        if(!$property && !$operator && !$value && !$joinProperty){
115
            return $this;
116
        }
117
        foreach ($this->where as $index => $where){
118
            if($property && $where['property'] !== $property){
119
                continue;
120
            }
121
            if($operator && $where['operator'] !== $operator){
122
                continue;
123
            }
124
            if($value && $where['value'] !== $value){
125
                continue;
126
            }
127
            if($joinProperty && $where['joinProperty'] !== $joinProperty){
128
                continue;
129
            }
130
            unset($this->where[$index]);
131
        }
132
133
        return $this;
134
    }
135
136
    public function getWhere()
137
    {
138
        return $this->where;
139
    }
140
141
    public function getOrderBy()
142
    {
143
        return $this->orderBy;
144
    }
145
146
    /**
147
     * @return QueryBuilder
148
     */
149
    public function getQueryBuilder()
150
    {
151
        return $this->queryBuilder;
152
    }
153
154
    public function build()
155
    {
156
        /** @var QueryBuilder $query */
157
        $query = $this->queryBuilder;
158
        $i = 0;
159
        foreach($this->getWhere() as $index => $where) {
160
            $i++;
161
            if($where['joinProperty']) {
162
                if(is_array($where['joinProperty']) && count($where['joinProperty'])) {
163
                    $joinPrefixes = $this->createJoinPropertyArray($index, count($where['joinProperty']) + 1);
164 View Code Duplication
                    foreach($where['joinProperty'] as $joinProperty) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
165
                        $joinPrefix = array_shift($joinPrefixes);
166
                        $query->join(sprintf('%s.%s', $joinPrefix, $joinProperty), $joinPrefixes[0]);
167
                    }
168
                    $query->andWhere(sprintf('%s.%s %s %s', $joinPrefixes[0], $where['property'], $this->getOperator($where), $this->getParameter($where, $i)));
169
                } else {
170
                    $query->join(sprintf('%s.%s', $this->getAlias(), $where['property']), sprintf('j%s', $i));
171
                    $query->andWhere(sprintf('j%s.%s %s %s', $i, $where['property'], $this->getOperator($where), $this->getParameter($where, $i)));
172
                }
173
            } else {
174
                $query->andWhere(sprintf('%s.%s %s %s', $this->getAlias(), $where['property'], $this->getOperator($where), $this->getParameter($where, $i)));
175
            }
176
177
            if($this->hasParameter($where)) {
178
                $query->setParameter(sprintf('parameter%s', $i), $this->getValue($where));
179
            }
180
        }
181
182
        $indexMin = count($this->getWhere());
183
        foreach($this->getOrderBy() as $index => $order) {
184
            $i++;
185
            if($order['joinProperty']) {
186
                if(is_array($order['joinProperty']) && count($order['joinProperty'])) {
187
                    $joinPrefixes = $this->createJoinPropertyArray($indexMin + $index, count($order['joinProperty']) + 1);
188 View Code Duplication
                    foreach($order['joinProperty'] as $joinProperty) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
189
                        $joinPrefix = array_shift($joinPrefixes);
190
                        $query->leftJoin(sprintf('%s.%s', $joinPrefix, $joinProperty), $joinPrefixes[0]);
191
                    }
192
                    $query->addOrderBy(sprintf('%s.%s', $joinPrefixes[0], $order['property']), $order['order']);
193
                } else {
194
                    $query->leftJoin(sprintf('%s.%s', $this->getAlias(), $order['property']), sprintf('j%s', $i));
195
                    $query->addOrderBy(sprintf('j%s.%s', $i, $order['property']), $order['order']);
196
                }
197
            } else {
198
                $query->addOrderBy(sprintf('%s.%s', $this->getAlias(), $order['property']), $order['order']);
199
            }
200
        }
201
202
        if ($this->getHydrate() === self::HYDRATE_ID) {
203
            $query->select($this->getAlias() . '.id');
204
        }
205
206
        return $this;
207
    }
208
209
    public function createJoinPropertyArray($index, $length)
210
    {
211
        $i=0;
212
        $allLetters = [];
213
214
        $letters = range($this->getAlias(), 'z');
215
        $lettersAdded = $letters;
216
        while ($length > 0) {
217
            $i++;
218
            foreach ($lettersAdded as $indexFor => &$addLetter){
219
                $addLetter .= $letters[$indexFor];
220
            }
221
            foreach ($lettersAdded as $letter) {
222
                $letter .= $index;
223
                $allLetters[] = $letter;
224
                $length--;
225
                if($length <= 0){
226
                    $allLetters[0] = $this->getAlias();
227
                    return $allLetters;
228
                }
229
            }
230
        }
231
        return $allLetters;
232
    }
233
234
    private function getValue($where)
235
    {
236
        $value = $where['value'];
237
238
        if($where['operator'] == FilterQuery::OPERATOR_LIKE) {
239
            return '%'.$value.'%';
240
        }
241
242
        if($where['operator'] == FilterQuery::OPERATOR_START_LIKE) {
243
            return $value.'%';
244
        }
245
246
        if($where['operator'] == FilterQuery::OPERATOR_END_LIKE) {
247
            return '%'.$value;
248
        }
249
250
        return $value;
251
    }
252
253
    private function getOperator($where)
254
    {
255
        $value = $where['value'];
256
257
        switch($where['operator']) {
258
            case(FilterQuery::OPERATOR_EQUALS):
259
                if($value === null) {
260
                    return 'is';
261
                }
262
                return '=';
263
            case(FilterQuery::OPERATOR_GREATER):
264
                return '>';
265
            case(FilterQuery::OPERATOR_GREATER_EQUAL):
266
                return '>=';
267
            case(FilterQuery::OPERATOR_LESS):
268
                return '<';
269
            case(FilterQuery::OPERATOR_LESS_EQUAL):
270
                return '<=';
271
            case(FilterQuery::OPERATOR_NOT):
272
                if($value === null) {
273
                    return 'is not';
274
                }
275
                return '!=';
276
            case(FilterQuery::OPERATOR_LIKE):
277
            case(FilterQuery::OPERATOR_START_LIKE):
278
            case(FilterQuery::OPERATOR_END_LIKE):
279
                return 'like';
280
        }
281
        throw new FilterException('Operator not supported in Repository');
282
    }
283
284
    private function getParameter($where, $number)
285
    {
286
        $value = $where['value'];
287
        if(FilterQuery::OPERATOR_EQUALS && $value === null) {
288
            return 'null';
289
        }
290
        return sprintf(':parameter%s', $number);
291
    }
292
293
    private function hasParameter($where)
294
    {
295
        $value = $where['value'];
296
        if(FilterQuery::OPERATOR_EQUALS && $value === null) {
297
            return false;
298
        }
299
        return true;
300
    }
301
302
    public function getAlias()
303
    {
304
        return $this->alias;
305
    }
306
307
    /**
308
     * @return string
309
     */
310
    public function getHydrate(): string
311
    {
312
        return $this->hydrate;
313
    }
314
315
    /**
316
     * @param string $hydrate
317
     */
318
    public function setHydrate(string $hydrate): void
319
    {
320
        $this->hydrate = $hydrate;
321
    }
322
}
323