GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( eaeb13...1c78c4 )
by Simone
03:00
created

QueryBuilderFactory   F

Complexity

Total Complexity 80

Size/Duplication

Total Lines 530
Duplicated Lines 0 %

Test Coverage

Coverage 83.4%

Importance

Changes 0
Metric Value
wmc 80
dl 0
loc 530
ccs 206
cts 247
cp 0.834
rs 1.5789
c 0
b 0
f 0

32 Methods

Rating   Name   Duplication   Size   Complexity  
A setFilters() 0 5 1
A getPrinting() 0 3 1
A getValueAvailableFilters() 0 3 1
B join() 0 47 5
A getFields() 0 9 2
A setRelationEntityAlias() 0 3 1
A getSelect() 0 3 1
C sort() 0 39 8
A getAvailableFilters() 0 3 1
A storeJoin() 0 4 1
A getRel() 0 3 1
A setAndFilters() 0 3 1
A getAndFilters() 0 3 1
A setPageLength() 0 5 1
A noExistsJoin() 0 9 2
A getRelationEntityAlias() 0 3 1
C filter() 0 45 11
A setOrFilters() 0 5 1
A getPageLength() 0 3 1
A getEntityManager() 0 3 1
F applyFilterOr() 0 101 14
A setPrinting() 0 5 1
A getOrFilters() 0 3 1
C applyFilterAnd() 0 77 11
A ensureQueryBuilderIsDefined() 0 7 2
A setSorting() 0 5 1
A setRel() 0 5 1
A setPage() 0 5 1
A getPage() 0 3 1
A setSelect() 0 5 1
A getQueryBuilder() 0 7 2
A setFields() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like QueryBuilderFactory often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use QueryBuilderFactory, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Mado\QueryBundle\Queries;
4
5
use Doctrine\ORM\EntityManager;
6
use Doctrine\ORM\QueryBuilder;
7
use Mado\QueryBundle\Component\Meta\Exceptions\UnInitializedQueryBuilderException;
8
use Mado\QueryBundle\Dictionary;
9
use Mado\QueryBundle\Exceptions;
10
use Mado\QueryBundle\Queries\Objects\FilterObject;
11
12
class QueryBuilderFactory extends AbstractQuery
13
{
14
    const DIRECTION_AZ = 'asc';
15
16
    const DIRECTION_ZA = 'desc';
17
18
    const DEFAULT_OPERATOR = 'eq';
19
20
    protected $qBuilder;
21
22
    protected $fields;
23
24
    protected $andFilters;
25
26
    protected $orFilters;
27
28
    private $relationEntityAlias;
29
30
    protected $sorting;
31
32
    private $joins;
33
34
    protected $rel;
35
36
    protected $printing;
37
38
    protected $page;
39
40
    protected $pageLength;
41
42
    protected $select;
43
44 1
    public function getAvailableFilters()
45
    {
46 1
        return array_keys($this->getValueAvailableFilters());
47
    }
48
49 2
    public function getValueAvailableFilters()
50
    {
51 2
        return Dictionary::getOperators();
52
    }
53
54 9
    public function setFields(array $fields = [])
55
    {
56 9
        $this->fields = $fields;
57
58 9
        return $this;
59
    }
60
61 2
    public function getFields()
62
    {
63 2
        if (null === $this->fields) {
64 1
            throw new \RuntimeException(
65 1
                'Oops! Fields are not defined'
66
            );
67
        }
68
69 1
        return $this->fields;
70
    }
71
72
    /** @deprecated since version 2.2.2 will be removed in version 2.3 */
73 4
    public function setFilters(array $andFilters = [])
74
    {
75 4
        $this->andFilters = $andFilters;
76
77 4
        return $this;
78
    }
79
80
    /** @since version 2.2.2 */
81 4
    public function setAndFilters(array $andFilters = [])
82
    {
83 4
        return $this->setFilters($andFilters);
0 ignored issues
show
Deprecated Code introduced by
The function Mado\QueryBundle\Queries...erFactory::setFilters() has been deprecated: since version 2.2.2 will be removed in version 2.3 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

83
        return /** @scrutinizer ignore-deprecated */ $this->setFilters($andFilters);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
84
    }
85
86 3
    public function setOrFilters(array $orFilters = [])
87
    {
88 3
        $this->orFilters = $orFilters;
89
90 3
        return $this;
91
    }
92
93 4
    public function setSorting(array $sorting = [])
94
    {
95 4
        $this->sorting = $sorting;
96
97 4
        return $this;
98
    }
99
100 1
    public function getAndFilters()
101
    {
102 1
        return $this->andFilters;
103
    }
104
105 1
    public function getOrFilters()
106
    {
107 1
        return $this->orFilters;
108
    }
109
110 3
    private function noExistsJoin($prevEntityAlias, $currentEntityAlias)
111
    {
112 3
        if (null === $this->joins) {
113 3
            $this->joins = [];
114
        }
115
116 3
        $needle = $prevEntityAlias . '_' . $currentEntityAlias;
117
118 3
        return !in_array($needle, $this->joins);
119
    }
120
121 3
    private function storeJoin($prevEntityAlias, $currentEntityAlias)
122
    {
123 3
        $needle = $prevEntityAlias . '_' . $currentEntityAlias;
124 3
        $this->joins[$needle] = $needle;
125 3
    }
126
127
    /**
128
     * @param String $relation Nome della relazione semplice (groups.name) o con embedded (_embedded.groups.name)
129
     * @return $this
130
     */
131 3
    public function join(String $relation)
132
    {
133 3
        $relation = explode('|', $relation)[0];
134 3
        $relations = [$relation];
135
136 3
        if (strstr($relation, '_embedded.')) {
137 3
            $embeddedFields = explode('.', $relation);
138 3
            $this->parser->camelize($embeddedFields[1]);
139
140
            // elimino l'ultimo elemento che dovrebbe essere il nome del campo
141 3
            unset($embeddedFields[count($embeddedFields) - 1]);
142
143
            // elimino il primo elemento _embedded
144 3
            unset($embeddedFields[0]);
145
146 3
            $relations = $embeddedFields;
147
        }
148
149 3
        $entityName = $this->getEntityName();
150 3
        $entityAlias = $this->entityAlias;
151
152 3
        foreach ($relations as $relation) {
153
154 3
            $relation = $this->parser->camelize($relation);
155 3
            $relationEntityAlias = 'table_' . $relation;
156
157 3
            $metadata = $this->manager->getClassMetadata($entityName);
158
159 3
            if ($metadata->hasAssociation($relation)) {
160
161 3
                $association = $metadata->getAssociationMapping($relation);
162
163 3
                $fieldName = $this->parser->camelize($association['fieldName']);
164
165 3
                if ($this->noExistsJoin($relationEntityAlias, $relation)) {
166 3
                    $this->qBuilder->join($entityAlias . "." . $fieldName, $relationEntityAlias);
167 3
                    $this->storeJoin($relationEntityAlias, $relation);
168
                }
169
170 3
                $entityName = $association['targetEntity'];
171 3
                $entityAlias = $relationEntityAlias;
172
            }
173
174 3
            $this->setRelationEntityAlias($relationEntityAlias);
175
        }
176
177 3
        return $this;
178
    }
179
180 5
    public function filter()
181
    {
182 5
        if (null === $this->andFilters && null === $this->orFilters) {
183 1
            throw new Exceptions\MissingFiltersException();
184
        }
185
186 4
        if (!$this->fields) {
187
            throw new \RuntimeException(
188
                'Oops! Fields are not defined'
189
            );
190
        }
191
192 4
        if (null !== $this->andFilters) {
193 3
            foreach ($this->andFilters as $filter => $value) {
194 3
                $this->applyFilterAnd(
195 3
                    Objects\FilterObject::fromRawFilter($filter),
196 3
                    $value,
197 3
                    Objects\Value::fromFilter($value)
198
                );
199
            }
200
        }
201
202 4
        if (null !== $this->orFilters) {
203 1
            $orFilter = [];
204 1
            $orFilter['orCondition'] = null;
205 1
            $orFilter['parameters'] = [];
206
207 1
            foreach ($this->orFilters as $filter => $value) {
208 1
                $orFilter = $this->applyFilterOr(
209 1
                    Objects\FilterObject::fromRawFilter($filter),
210 1
                    $value,
211 1
                    $orFilter
212
                );
213
            }
214
215 1
            if ((count($orFilter) > 0) && (null != $orFilter['orCondition'])) {
216 1
                $this->qBuilder->andWhere($orFilter['orCondition']);
217
218 1
                foreach ($orFilter['parameters'] as $parameter) {
219 1
                    $this->qBuilder->setParameter($parameter['field'], $parameter['value']);
220
                }
221
            }
222
        }
223
224 4
        return $this;
225
    }
226
227 3
    private function applyFilterAnd(
228
        Objects\FilterObject $filterObject,
229
        $value,
230
        Objects\Value $filterValue
231
    ) {
232 3
        $whereCondition = $this->entityAlias . '.' . $filterObject->getFieldName() . ' '
233 3
            . $filterObject->getOperatorMeta();
234
235 3
        if (in_array($filterObject->getFieldName(), $this->fields)) {
236 2
            $salt = '_' . random_int(111, 999);
237
238 2
            if ($filterObject->isListType()) {
239
                $whereCondition .= ' (:field_' . $filterObject->getFieldName() . $salt . ')';
240 2
            } elseif ($filterObject->isFieldEqualityType()) {
241
                $whereCondition .= ' ' . $this->entityAlias . '.' . $value;
242
            } else {
243 2
                $whereCondition .= ' :field_' . $filterObject->getFieldName() . $salt;
244
            }
245
246 2
            $this->qBuilder->andWhere($whereCondition);
247
248 2
            if ($filterObject->haveOperatorSubstitutionPattern()) {
249
                if ($filterObject->isListType()) {
250
                    $value = explode(',', $value);
251
                } else {
252
                    $value = str_replace(
253
                        '{string}',
254
                        $value,
255
                        $filterObject->getOperatorsSubstitutionPattern()
256
                    );
257
                }
258
            }
259
260 2
            $this->qBuilder->setParameter('field_' . $filterObject->getFieldName() . $salt, $value);
261
        } else {
262 1
            $isNotARelation = 0 !== strpos($filterObject->getFieldName(), 'Embedded.');
263 1
            if ($isNotARelation) {
264
                $whereCondition .= ' ' . $this->entityAlias . '.' . $value;
265
                $this->qBuilder->andWhere($whereCondition);
266
            }
267
        }
268
269
        // controllo se il filtro si riferisce ad una relazione dell'entità quindi devo fare dei join
270
        // esempio per users: filtering[_embedded.groups.name|eq]=admin
271 3
        if (strstr($filterObject->getRawFilter(), '_embedded.')) {
272
273 1
            $this->join($filterObject->getRawFilter());
274 1
            $relationEntityAlias = $this->getRelationEntityAlias();
275
276 1
            $embeddedFields = explode('.', $filterObject->getFieldName());
277 1
            $embeddedFieldName = $this->parser->camelize($embeddedFields[count($embeddedFields) - 1]);
278
279 1
            $salt = '_' . random_int(111, 999);
280
281 1
            $whereCondition = $relationEntityAlias . '.' . $embeddedFieldName . ' '
282 1
                . $filterObject->getOperatorMeta();
283
284 1
            if ($filterObject->isListType()) {
285
                $whereCondition .= ' (:field_' . $embeddedFieldName . $salt . ')';
286
            } else {
287 1
                $whereCondition .= ' :field_' . $embeddedFieldName . $salt;
288
            }
289
290 1
            $this->qBuilder->andWhere($whereCondition);
291 1
            if ($filterObject->haveOperatorSubstitutionPattern()) {
292 1
                if ($filterObject->isListType()) {
293
                    $value = explode(',', $filterValue->getFilter());
294
                } else {
295 1
                    $value = str_replace(
296 1
                        '{string}',
297 1
                        $value,
298 1
                        $filterObject->getOperatorsSubstitutionPattern()
299
                    );
300
                }
301
            }
302
303 1
            $this->qBuilder->setParameter('field_' . $embeddedFieldName . $salt, $value);
304
        }
305 3
    }
306
307 1
    private function applyFilterOr(
308
        Objects\FilterObject $filterObject,
309
        $value,
310
        $orCondition
311
    ) {
312 1
        $whereCondition = $this->entityAlias . '.' . $filterObject->getFieldName() . ' '
313 1
            . $filterObject->getOperatorMeta();
314
315
        // controllo se il filtro che mi arriva dalla richiesta è una proprietà di questa entità
316
        // esempio per users: filtering[username|contains]=mado
317 1
        if (in_array($filterObject->getFieldName(), $this->fields)) {
318
            $salt = '_' . random_int(111, 999);
319
320
            if ($filterObject->isListType()) {
321
                $whereCondition .= ' (:field_' . $filterObject->getFieldName() . $salt . ')';
322
            } else if ($filterObject->isFieldEqualityType()) {
323
                $whereCondition .= $this->entityAlias . '.' . $value;
324
            } else {
325
                $whereCondition .= ' :field_' . $filterObject->getFieldName() . $salt;
326
            }
327
328
            if (null != $orCondition['orCondition']) {
329
                $orCondition['orCondition'] .= ' OR ' . $whereCondition;
330
            } else {
331
                $orCondition['orCondition'] = $whereCondition;
332
            }
333
334
            if ($filterObject->haveOperatorSubstitutionPattern()) {
335
                if ($filterObject->isListType()) {
336
                    $value = explode(',', $value);
337
                } else {
338
                    $value = str_replace(
339
                        '{string}',
340
                        $value,
341
                        $filterObject->getOperatorsSubstitutionPattern()
342
                    );
343
                }
344
            }
345
346
            $orCondition['parameters'][] = [
347
                'field' => 'field_' . $filterObject->getFieldName() . $salt,
348
                'value' => $value
349
            ];
350
        } else {
351 1
            $isNotARelation = 0 !== strpos($filterObject->getFieldName(), 'Embedded.');
352 1
            if ($isNotARelation) {
353
                    $whereCondition .= ' ' . $this->entityAlias . '.' . $value;
354
                if (null != $orCondition['orCondition']) {
355
                    $orCondition['orCondition'] .= ' OR ' . $whereCondition;
356
                } else {
357
                    $orCondition['orCondition'] = $whereCondition;
358
                }
359
            }
360
        }
361
362
        // controllo se il filtro si riferisce ad una relazione dell'entità quindi devo fare dei join
363
        // esempio per users: filtering[_embedded.groups.name|eq]=admin
364 1
        if (strstr($filterObject->getRawFilter(), '_embedded.')) {
365
366 1
            $this->join($filterObject->getRawFilter());
367 1
            $relationEntityAlias = $this->getRelationEntityAlias();
368
369 1
            $embeddedFields = explode('.', $filterObject->getFieldName());
370 1
            $embeddableFieldName = $this->parser->camelize($embeddedFields[count($embeddedFields) - 1]);
371
372 1
            $salt = '_' . random_int(111, 999);
373
374 1
            $whereCondition = $relationEntityAlias . '.' . $embeddableFieldName . ' '
375 1
                . $filterObject->getOperatorMeta();
376
377 1
            if ($filterObject->isListType()) {
378
                $whereCondition .= ' (:field_' . $embeddableFieldName . $salt . ')';
379
            } else {
380 1
                $whereCondition .= ' :field_' . $embeddableFieldName . $salt;
381
            }
382
383 1
            if (null != $orCondition['orCondition']) {
384 1
                $orCondition['orCondition'] .= ' OR ' . $whereCondition;
385
            } else {
386 1
                $orCondition['orCondition'] = $whereCondition;
387
            }
388
389 1
            if ($filterObject->haveOperatorSubstitutionPattern()) {
390 1
                if ($filterObject->isListType()) {
391
                    $value = explode(',', $value);
392
                } else {
393 1
                    $value = str_replace(
394 1
                        '{string}',
395 1
                        $value,
396 1
                        $filterObject->getOperatorsSubstitutionPattern()
397
                    );
398
                }
399
            }
400
401 1
            $orCondition['parameters'][] = [
402 1
                'field' => 'field_' . $embeddableFieldName . $salt,
403 1
                'value' => $value
404
            ];
405
        }
406
407 1
        return $orCondition;
408
    }
409
410 5
    public function sort()
411
    {
412 5
        if (!$this->fields) {
413 1
            throw new \RuntimeException(
414 1
                'Oops! Fields are not defined'
415
            );
416
        }
417
418 4
        if (null === $this->sorting) {
419 1
            throw new \RuntimeException(
420 1
                'Oops! Sorting is not defined'
421
            );
422
        }
423
424 3
        foreach ($this->sorting as $sort => $val) {
425 3
            $val = strtolower($val);
426
427 3
            $fieldName = $this->parser->camelize($sort);
428
429 3
            if (in_array($fieldName, $this->fields)) {
430 2
                $direction = ($val === self::DIRECTION_AZ) ? self::DIRECTION_AZ : self::DIRECTION_ZA;
431 2
                $this->ensureQueryBuilderIsDefined();
432 1
                $this->qBuilder->addOrderBy($this->entityAlias .'.'. $fieldName, $direction);
433
            }
434
435 2
            if (strstr($sort, '_embedded.')) {
436 1
                $this->join($sort);
437 1
                $relationEntityAlias = $this->getRelationEntityAlias();
438
439 1
                $embeddedFields = explode('.', $sort);
440 1
                $fieldName = $this->parser->camelize($embeddedFields[2]);
441 1
                $direction = ($val === self::DIRECTION_AZ) ? self::DIRECTION_AZ : self::DIRECTION_ZA;
442
443 2
                $this->qBuilder->addOrderBy($relationEntityAlias . '.' . $fieldName, $direction);
444
            }
445
446
        }
447
448 2
        return $this;
449
    }
450
451 5
    public function getQueryBuilder() :QueryBuilder
452
    {
453 5
        if (!$this->qBuilder) {
454 1
            throw new UnInitializedQueryBuilderException();
455
        }
456
457 4
        return $this->qBuilder;
458
    }
459
460 3
    private function setRelationEntityAlias(string $relationEntityAlias)
461
    {
462 3
        $this->relationEntityAlias = $relationEntityAlias;
463 3
    }
464
465 3
    private function getRelationEntityAlias()
466
    {
467 3
        return $this->relationEntityAlias;
468
    }
469
470 3
    public function setRel($rel)
471
    {
472 3
        $this->rel = $rel;
473
474 3
        return $this;
475
    }
476
477 1
    public function getRel()
478
    {
479 1
        return $this->rel;
480
    }
481
482 2
    public function setPrinting($printing)
483
    {
484 2
        $this->printing = $printing;
485
486 2
        return $this;
487
    }
488
489 1
    public function getPrinting()
490
    {
491 1
        return $this->printing;
492
    }
493
494 2
    public function setPage(int $page)
495
    {
496 2
        $this->page = $page;
497
498 2
        return $this;
499
    }
500
501 1
    public function getPage() :int
502
    {
503 1
        return $this->page;
504
    }
505
506 2
    public function setPageLength($pageLength)
507
    {
508 2
        $this->pageLength = $pageLength;
509
510 2
        return $this;
511
    }
512
513 1
    public function getPageLength()
514
    {
515 1
        return $this->pageLength;
516
    }
517
518 2
    public function setSelect($select) : QueryBuilderFactory
519
    {
520 2
        $this->select = $select;
521
522 2
        return $this;
523
    }
524
525 1
    public function getSelect()
526
    {
527 1
        return $this->select;
528
    }
529
530
    public function getEntityManager() : EntityManager
531
    {
532
        return $this->manager;
533
    }
534
535 2
    public function ensureQueryBuilderIsDefined()
536
    {
537 2
        if (!$this->qBuilder) {
538 1
            throw new \RuntimeException(
539
                'Oops! QueryBuilder was never initialized. '
540
                . "\n" . 'QueryBuilderFactory::createQueryBuilder()'
541 1
                . "\n" . 'QueryBuilderFactory::createSelectAndGroupBy()'
542
            );
543
        }
544 1
    }
545
}
546