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 ( a56f38...8de386 )
by Simone
01:43
created

QueryBuilderFactory::ensureQueryBuilderIsDefined()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 1
nop 0
dl 0
loc 5
ccs 0
cts 4
cp 0
crap 6
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Mado\QueryBundle\Queries;
4
5
use Mado\QueryBundle\Objects\FilteringObject;
6
use Mado\QueryBundle\Objects\Operator;
7
use Mado\QueryBundle\Objects\Salt;
8
use Mado\QueryBundle\Vocabulary\Operators;
9
10
class QueryBuilderFactory extends AbstractQuery
11
{
12
    const DIRECTION_AZ = 'asc';
13
14
    const DIRECTION_ZA = 'desc';
15
16
    protected $qBuilder;
17
18
    protected $fields;
19
20
    protected $filtering;
21
22
    protected $orFiltering;
23
24
    protected $relationEntityAlias;
25
26
    protected $sorting;
27
28
    protected $joins;
29
30
    protected $rel;
31
32
    protected $printing;
33
34
    protected $page;
35
36
    protected $pageLength;
37
38
    protected $select;
39
40
    private function ensureFieldsDefined()
41
    {
42
        if (!$this->fields) {
43
            throw new \RuntimeException(
44
                'Oops! Fields are not defined'
45
            );
46
        }
47
    }
48
49
    private function ensureSortingIsDefined()
50
    {
51
        if (null === $this->sorting) {
52
            throw new \RuntimeException(
53
                'Oops! Sorting is not defined'
54
            );
55
        }
56
    }
57
58
    private function ensureFilteringIsDefined()
59
    {
60
        if (null === $this->filtering) {
61
            throw new \RuntimeException(
62
                'Oops! Filtering is not defined'
63
            );
64
        }
65
    }
66
67
    private function ensureQueryBuilderIsDefined()
68
    {
69
        if (!$this->qBuilder) {
70
            throw new \RuntimeException(
71
                "Oops! Query builder was never initialized! call ::createQueryBuilder('entityName', 'alias') to start."
72
            );
73
        }
74
    }
75
76 1
    public function getAvailableFilters()
77
    {
78 1
        return array_keys(Operators::getAll());
79
    }
80
81
    public function setFields(array $fields = [])
82
    {
83
        $this->fields = $fields;
84
85
        return $this;
86
    }
87
88
    public function getFields()
89
    {
90
        $this->ensureFieldsDefined();
91
92
        return $this->fields;
93
    }
94
95
    public function setFilters(array $filtering = [])
96
    {
97
        $this->filtering = $filtering;
98
99
        return $this;
100
    }
101
102
    public function setOrFilters(array $orFiltering = [])
103
    {
104
        $this->orFiltering = $orFiltering;
105
106
        return $this;
107
    }
108
109
    public function setSorting(array $sorting = [])
110
    {
111
        $this->sorting = $sorting;
112
113
        return $this;
114
    }
115
116
    public function getFilters()
117
    {
118
        return $this->filtering;
119
    }
120
121
    public function getOrFilters()
122
    {
123
        return $this->orFiltering;
124
    }
125
126
    private function noExistsJoin($prevEntityAlias, $currentEntityAlias)
127
    {
128
        if (null === $this->joins) {
129
            $this->joins = [];
130
        }
131
132
        $needle = $prevEntityAlias . "_" . $currentEntityAlias;
133
134
        return !in_array($needle, $this->joins);
135
    }
136
137
    private function storeJoin($prevEntityAlias, $currentEntityAlias)
138
    {
139
        $needle = $prevEntityAlias . "_" . $currentEntityAlias;
140
        $this->joins[$needle] = $needle;
141
    }
142
143
    public function join(String $relation)
144
    {
145
        $relation = explode('|', $relation)[0];
146
        $relations = [$relation];
147
148
        if (strstr($relation, '_embedded.')) {
149
            $embeddedFields = explode('.', $relation);
150
            unset($embeddedFields[count($embeddedFields) - 1]);
151
            unset($embeddedFields[0]);
152
            $relations = $embeddedFields;
153
        }
154
155
        $entityName = $this->getEntityName();
156
        $entityAlias = $this->entityAlias;
157
158
        foreach ($relations as $relation) {
159
160
            $relation = $this->parser->camelize($relation);
161
            $relationEntityAlias = 'table_' . $relation;
162
163
            $metadata = $this->manager->getClassMetadata($entityName);
164
165
            if ($metadata->hasAssociation($relation)) {
166
167
                $association = $metadata->getAssociationMapping($relation);
168
169
                $fieldName = $this->parser->camelize($association['fieldName']);
170
171
                if ($this->noExistsJoin($relationEntityAlias, $relation)) {
172
173
                    $this->qBuilder
174
                            ->join($entityAlias . "." . $fieldName, $relationEntityAlias);
175
176
                    $this->storeJoin($relationEntityAlias, $relation);
177
                }
178
                $entityName = $association['targetEntity'];
179
                $entityAlias = $relationEntityAlias;
180
            }
181
182
            $this->setRelationEntityAlias($relationEntityAlias);
183
        }
184
185
        return $this;
186
    }
187
188
    public function filter()
189
    {
190
        $this->ensureFilteringIsDefined();
191
        $this->ensureFieldsDefined();
192
193
        foreach ($this->filtering as $filter => $value) {
194
            $this->applyFilterAnd($filter, $value);
195
        }
196
197
        if (null !== $this->orFiltering) {
198
            $orFilter = [];
199
            $orFilter['orCondition'] = null;
200
            $orFilter['parameters'] = [];
201
202
            foreach ($this->orFiltering as $filter => $value) {
203
                $orFilter = $this->applyFilterOr($filter, $value, $orFilter);
204
            }
205
206
            if ((count($orFilter) > 0) && ($orFilter['orCondition'] != null)) {
207
                $this->qBuilder->andWhere($orFilter['orCondition']);
208
209
                foreach ($orFilter['parameters'] as $parameter) {
210
                    $this->qBuilder->setParameter($parameter['field'], $parameter['value']);
211
                }
212
            }
213
        }
214
215
        return $this;
216
    }
217
218
    private function applyFilterAnd($filter, $value)
219
    {
220
        $whereCondition = null;
221
        $filtering = FilteringObject::fromFilter($filter);
222
        $fieldName = $this->parser->camelize($filtering->getFieldName());
223
224
        $op = Operator::fromFilteringObject($filtering);
225
226
        $saltObj = new Salt($this->qBuilder);
227
228
        if (in_array($fieldName, $this->fields)) {
229
230
            $saltObj->generateSaltForName($fieldName);
231
232
            if ($filtering->hasOperator()) {
233 View Code Duplication
                if ('list' == $filtering->getOperator()) {
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...
234
                    $whereCondition =
235
                        $this->entityAlias . '.' . $fieldName . ' ' .
236
                        $op->getMeta() . ' ' .
237
                        '(:field_' . $fieldName . $saltObj->getSalt() . ')';
238
                } else if ('field_eq' == $filtering->getOperator()) {
239
                    $whereCondition =
240
                        $this->entityAlias . '.' . $fieldName . ' ' .
241
                        $op->getMeta() . ' ' .
242
                        $this->entityAlias . '.' . $value;
243
                } else {
244
                    $whereCondition =
245
                        $this->entityAlias . '.' . $fieldName . ' ' .
246
                        $op->getMeta() . ' ' .
247
                        ':field_' . $fieldName . $saltObj->getSalt();
248
                }
249
            } else {
250
                $whereCondition =
251
                    $this->entityAlias . '.' . $fieldName . ' ' .
252
                    $op->getMeta() . ' ' .
253
                    ':field_' . $fieldName . $saltObj->getSalt();
254
            }
255
256
            $this->qBuilder->andWhere($whereCondition);
257
258 View Code Duplication
            if ($op->haveSubstitutionPattern()) {
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...
259
                if ($filtering->hasOperator() && 'list' == $filtering->getOperator()) {
260
                    $value = explode(',', $value);
261
                } else {
262
                    $value = str_replace(
263
                        '{string}',
264
                        $value,
265
                        $op->getSubstitutionPattern()
266
                    );
267
                }
268
            }
269
270
            $this->qBuilder->setParameter('field_' . $fieldName . $saltObj->getSalt(), $value);
271
        } else {
272
            $isNotARelation = 0 !== strpos($fieldName, 'Embedded.');
273
            if ($isNotARelation) {
274
                $whereCondition =
275
                    $this->entityAlias . '.' . $fieldName . ' ' .
276
                    $op->getMeta() . ' ' .
277
                    $this->entityAlias . '.' . $value;
278
                $this->qBuilder->andWhere($whereCondition);
279
            }
280
        }
281
282
        if (strstr($filter, '_embedded.')) {
283
284
            $this->join($filter);
285
            $relationEntityAlias = $this->getRelationEntityAlias();
286
287
            $embeddedFields = explode('.', $fieldName);
288
            $fieldName = $this->parser->camelize($embeddedFields[count($embeddedFields) - 1]);
289
290 View Code Duplication
            if ($filtering->hasOperator() && 'list' == $filtering->getOperator()) {
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...
291
                $whereCondition =
292
                    $relationEntityAlias . '.' . $fieldName . ' ' .
293
                    $op->getMeta() . ' ' .
294
                    '(:field_' . $fieldName . $saltObj->getSalt() . ')';
295
            } else {
296
                $whereCondition =
297
                    $relationEntityAlias . '.' . $fieldName . ' ' .
298
                    $op->getMeta() .
299
                    ' :field_' . $fieldName . $saltObj->getSalt();
300
            }
301
302
            $this->qBuilder->andWhere($whereCondition);
303 View Code Duplication
            if ($op->haveSubstitutionPattern()) {
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...
304
                if ($filtering->hasOperator() && 'list' == $filtering->getOperator()) {
305
                    $value = explode(',', $value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type array; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

305
                    $value = explode(',', /** @scrutinizer ignore-type */ $value);
Loading history...
306
                } else {
307
                    $value = str_replace(
308
                        '{string}',
309
                        $value,
310
                        $op->getSubstitutionPattern()
311
                    );
312
                }
313
            }
314
315
            $this->qBuilder->setParameter('field_' . $fieldName . $saltObj->getSalt(), $value);
316
        }
317
    }
318
319
    private function applyFilterOr($filter, $value, $orCondition)
320
    {
321
        $whereCondition = null;
322
        $filtering = FilteringObject::fromFilter($filter);
323
324
        $fieldName = $this->parser->camelize($filtering->getFieldName());
325
326
        $op = Operator::fromFilteringObject($filtering);
327
328
        if (in_array($fieldName, $this->fields)) {
329
330
            $salt = '';
331 View Code Duplication
            foreach ($this->qBuilder->getParameters() as $parameter) {
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...
332
                if ($parameter->getName() == 'field_' . $fieldName) {
333
                    $salt = '_' . rand(111, 999);
334
                }
335
            }
336
337
            if ($filtering->hasOperator()) {
338 View Code Duplication
                if ('list' == $filtering->getOperator()) {
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...
339
                    $whereCondition =
340
                        $this->entityAlias . '.' . $fieldName . ' ' .
341
                        $op->getMeta()
342
                        .' (:field_' . $fieldName . $salt . ')';
343
                } else if ('field_eq' == $filtering->getOperator()) {
344
                    $whereCondition =
345
                        $this->entityAlias . '.' . $fieldName . ' ' .
346
                        $op->getMeta() . ' ' .
347
                        $this->entityAlias . '.' . $value
348
                    ;
349
                } else {
350
                    $whereCondition =
351
                        $this->entityAlias . '.' . $fieldName . ' ' .
352
                        $op->getMeta() . ' ' .
353
                        ':field_' . $fieldName . $salt;
354
                }
355
            } else {
356
                $whereCondition =
357
                    $this->entityAlias . '.' . $fieldName . ' ' .
358
                    '=' . ' ' .
359
                    ':field_' . $fieldName . $salt;
360
            }
361
362 View Code Duplication
            if ($orCondition['orCondition'] != null) {
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...
363
                $orCondition['orCondition'] .= ' OR ' . $whereCondition;
364
            } else {
365
                $orCondition['orCondition'] = $whereCondition;
366
            }
367
368 View Code Duplication
            if ($op->haveSubstitutionPattern()) {
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...
369
                if ($filtering->hasOperator() && 'list' == $filtering->getOperator()) {
370
                    $value = explode(',', $value);
371
                } else {
372
                    $value = str_replace(
373
                        '{string}',
374
                        $value,
375
                        $op->getSubstitutionPattern()
376
                    );
377
                }
378
            }
379
380
            $orCondition['parameters'][] = [
381
                'field' => 'field_' . $fieldName . $salt,
382
                'value' => $value
383
            ];
384
        } else {
385
            $isNotARelation = 0 !== strpos($fieldName, 'Embedded.');
386
            if ($isNotARelation) {
387
                $whereCondition =
388
                    $this->entityAlias . '.' . $fieldName . ' ' .
389
                    $op->getMeta() . ' ' .
390
                    $this->entityAlias . '.' . $value;
391 View Code Duplication
                if ($orCondition['orCondition'] != null) {
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...
392
                    $orCondition['orCondition'] .= ' OR ' . $whereCondition;
393
                } else {
394
                    $orCondition['orCondition'] = $whereCondition;
395
                }
396
            }
397
        }
398
399
        if (strstr($filter, '_embedded.')) {
400
401
            $this->join($filter);
402
            $relationEntityAlias = $this->getRelationEntityAlias();
403
404
            $embeddedFields = explode('.', $fieldName);
405
            $fieldName = $this->parser->camelize($embeddedFields[count($embeddedFields) - 1]);
406
407
            $salt = '';
408 View Code Duplication
            foreach ($this->qBuilder->getParameters() as $parameter) {
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...
409
                if ($parameter->getName() == 'field_' . $fieldName) {
410
                    $salt = '_' . rand(111, 999);
411
                }
412
            }
413
414 View Code Duplication
            if ($filtering->hasOperator() && 'list' == $filtering->getOperator()) {
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...
415
                $whereCondition =
416
                    $relationEntityAlias . '.' . $fieldName . ' ' .
417
                    $op->getMeta() . ' ' .
418
                    '(:field_' . $fieldName . $salt . ')';
419
            } else {
420
                $whereCondition =
421
                    $relationEntityAlias . '.' . $fieldName . ' ' .
422
                    $op->getMeta() . ' ' .
423
                    ':field_' . $fieldName . $salt;
424
            }
425
426 View Code Duplication
            if ($orCondition['orCondition'] != null) {
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...
427
                $orCondition['orCondition'] .= ' OR ' . $whereCondition;
428
            } else {
429
                $orCondition['orCondition'] = $whereCondition;
430
            }
431
432 View Code Duplication
            if ($op->haveSubstitutionPattern()) {
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...
433
                if ($filtering->hasOperator() && 'list' == $filtering->getOperator()) {
434
                    $value = explode(',', $value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type array; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

434
                    $value = explode(',', /** @scrutinizer ignore-type */ $value);
Loading history...
435
                } else {
436
                    $value = str_replace(
437
                        '{string}',
438
                        $value,
439
                        $op->getSubstitutionPattern()
440
                    );
441
                }
442
            }
443
444
            $orCondition['parameters'][] = [
445
                'field' => 'field_' . $fieldName . $salt,
446
                'value' => $value
447
            ];
448
        }
449
450
        return $orCondition;
451
    }
452
453
    public function sort()
454
    {
455
        $this->ensureFieldsDefined();
456
        $this->ensureSortingIsDefined();
457
458
        foreach ($this->sorting as $sort => $val) {
459
            $val = strtolower($val);
460
461
            $fieldName = $this->parser->camelize($sort);
462
463
            if (in_array($fieldName, $this->fields)) {
464
                $direction = ($val === self::DIRECTION_AZ) ? self::DIRECTION_AZ : self::DIRECTION_ZA;
465
                $this->qBuilder->addOrderBy($this->entityAlias . '.' . $fieldName, $direction);
466
            }
467
468
            if (strstr($sort, '_embedded.')) {
469
                $this->join($sort);
470
                $relationEntityAlias = $this->getRelationEntityAlias();
471
472
                $embeddedFields = explode('.', $sort);
473
                $fieldName = $this->parser->camelize($embeddedFields[2]);
474
                $direction = ($val === self::DIRECTION_AZ) ? self::DIRECTION_AZ : self::DIRECTION_ZA;
475
476
                $this->qBuilder->addOrderBy($relationEntityAlias . '.' . $fieldName, $direction);
477
            }
478
479
        }
480
481
        return $this;
482
    }
483
484
    public function getQueryBuilder()
485
    {
486
        $this->ensureQueryBuilderIsDefined();
487
488
        return $this->qBuilder;
489
    }
490
491
    public function buildSelectValue() : string
492
    {
493
        if ("" == $this->getSelect()) {
494
            return $this->getEntityAlias(
0 ignored issues
show
Bug introduced by
The method getEntityAlias() does not exist on Mado\QueryBundle\Queries\QueryBuilderFactory. Did you maybe mean getEntityName()? ( Ignorable by Annotation )

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

494
            return $this->/** @scrutinizer ignore-call */ getEntityAlias(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
495
                $this->getEntityName()
496
            );
497
        }
498
499
        return $this->getSelect();
500
    }
501
502
    private function setRelationEntityAlias(string $relationEntityAlias)
503
    {
504
        $this->relationEntityAlias = $relationEntityAlias;
505
    }
506
507
    private function getRelationEntityAlias()
508
    {
509
        return $this->relationEntityAlias;
510
    }
511
512
    public function setRel($rel)
513
    {
514
        $this->rel = $rel;
515
516
        return $this;
517
    }
518
519
    public function getRel()
520
    {
521
        return $this->rel;
522
    }
523
524
    public function setPrinting($printing)
525
    {
526
        $this->printing = $printing;
527
528
        return $this;
529
    }
530
531
    public function getPrinting()
532
    {
533
        return $this->printing;
534
    }
535
536
    public function setPage($page)
537
    {
538
        $this->page = $page;
539
540
        return $this;
541
    }
542
543
    public function getPage()
544
    {
545
        return $this->page;
546
    }
547
548
    public function setPageLength($pageLength)
549
    {
550
        $this->pageLength = $pageLength;
551
552
        return $this;
553
    }
554
555
    public function getPageLength()
556
    {
557
        return $this->pageLength;
558
    }
559
560
    public function setSelect(string $select) : QueryBuilderFactory
561
    {
562
        $this->select = $select;
563
564
        return $this;
565
    }
566
567
    public function getSelect()
568
    {
569
        return $this->select;
570
    }
571
572
    public function getEntityManager()
573
    {
574
        return $this->manager;
575
    }
576
}
577