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 ( 26dfd6...38922b )
by Simone
04:29
created

QueryBuilderFactory::buildSelectValue()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 9
ccs 0
cts 5
cp 0
crap 6
rs 9.6666
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
        $saltObj->generateSaltForName($fieldName);
228
229
        if (in_array($fieldName, $this->fields)) {
230
231 View Code Duplication
            if ($filtering->hasOperator()) {
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...
232
                if ($filtering->isListOperator()) {
233
                    $whereCondition =
234
                        $this->entityAlias . '.' . $fieldName . ' ' .
235
                        $op->getMeta() . ' ' .
236
                        '(:field_' . $fieldName . $saltObj->getSalt() . ')';
237
                } else if ($filtering->isFieldEqualsOperator()) {
238
                    $whereCondition =
239
                        $this->entityAlias . '.' . $fieldName . ' ' .
240
                        $op->getMeta() . ' ' .
241
                        $this->entityAlias . '.' . $value;
242
                } else {
243
                    $whereCondition =
244
                        $this->entityAlias . '.' . $fieldName . ' ' .
245
                        $op->getMeta() . ' ' .
246
                        ':field_' . $fieldName . $saltObj->getSalt();
247
                }
248
            } else {
249
                $whereCondition =
250
                    $this->entityAlias . '.' . $fieldName . ' ' .
251
                    $op->getMeta() . ' ' .
252
                    ':field_' . $fieldName . $saltObj->getSalt();
253
            }
254
255
            $this->qBuilder->andWhere($whereCondition);
256
257 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...
258
                if ($filtering->isListOperator()) {
259
                    $value = explode(',', $value);
260
                } else {
261
                    $value = str_replace(
262
                        '{string}',
263
                        $value,
264
                        $op->getSubstitutionPattern()
265
                    );
266
                }
267
            }
268
269
            $this->qBuilder->setParameter('field_' . $fieldName . $saltObj->getSalt(), $value);
270
        } else {
271
            $isNotARelation = 0 !== strpos($fieldName, 'Embedded.');
272
            if ($isNotARelation) {
273
                $whereCondition =
274
                    $this->entityAlias . '.' . $fieldName . ' ' .
275
                    $op->getMeta() . ' ' .
276
                    $this->entityAlias . '.' . $value;
277
                $this->qBuilder->andWhere($whereCondition);
278
            }
279
        }
280
281
        if (strstr($filter, '_embedded.')) {
282
283
            $this->join($filter);
284
            $relationEntityAlias = $this->getRelationEntityAlias();
285
286
            $embeddedFields = explode('.', $fieldName);
287
            $fieldName = $this->parser->camelize($embeddedFields[count($embeddedFields) - 1]);
288
289 View Code Duplication
            if ($filtering->isListOperator()) {
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...
290
                $whereCondition =
291
                    $relationEntityAlias . '.' . $fieldName . ' ' .
292
                    $op->getMeta() . ' ' .
293
                    '(:field_' . $fieldName . $saltObj->getSalt() . ')';
294
            } else {
295
                $whereCondition =
296
                    $relationEntityAlias . '.' . $fieldName . ' ' .
297
                    $op->getMeta() . ' ' .
298
                    ':field_' . $fieldName . $saltObj->getSalt();
299
            }
300
301
            $this->qBuilder->andWhere($whereCondition);
302 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...
303
                if ($filtering->isListOperator()) {
304
                    $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

304
                    $value = explode(',', /** @scrutinizer ignore-type */ $value);
Loading history...
305
                } else {
306
                    $value = str_replace(
307
                        '{string}',
308
                        $value,
309
                        $op->getSubstitutionPattern()
310
                    );
311
                }
312
            }
313
314
            $this->qBuilder->setParameter('field_' . $fieldName . $saltObj->getSalt(), $value);
315
        }
316
    }
317
318
    private function applyFilterOr($filter, $value, $orCondition)
319
    {
320
        $whereCondition = null;
321
        $filtering = FilteringObject::fromFilter($filter);
322
323
        $fieldName = $this->parser->camelize($filtering->getFieldName());
324
325
        $op = Operator::fromFilteringObject($filtering);
326
327
        $saltObj = new Salt($this->qBuilder);
328
        $saltObj->generateSaltForName($fieldName);
329
330
        if (in_array($fieldName, $this->fields)) {
331
332 View Code Duplication
            if ($filtering->hasOperator()) {
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...
333
                if ($filtering->isListOperator()) {
334
                    $whereCondition =
335
                        $this->entityAlias . '.' . $fieldName . ' ' .
336
                        $op->getMeta()
337
                        .' (:field_' . $fieldName . $saltObj->getSalt() . ')';
338
                } else if ($filtering->isFieldEqualsOperator()) {
339
                    $whereCondition =
340
                        $this->entityAlias . '.' . $fieldName . ' ' .
341
                        $op->getMeta() . ' ' .
342
                        $this->entityAlias . '.' . $value
343
                    ;
344
                } else {
345
                    $whereCondition =
346
                        $this->entityAlias . '.' . $fieldName . ' ' .
347
                        $op->getMeta() . ' ' .
348
                        ':field_' . $fieldName . $saltObj->getSalt();
349
                }
350
            } else {
351
                $whereCondition =
352
                    $this->entityAlias . '.' . $fieldName . ' ' .
353
                    '=' . ' ' .
354
                    ':field_' . $fieldName . $saltObj->getSalt();
355
            }
356
357 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...
358
                $orCondition['orCondition'] .= ' OR ' . $whereCondition;
359
            } else {
360
                $orCondition['orCondition'] = $whereCondition;
361
            }
362
363 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...
364
                if ($filtering->isListOperator()) {
365
                    $value = explode(',', $value);
366
                } else {
367
                    $value = str_replace(
368
                        '{string}',
369
                        $value,
370
                        $op->getSubstitutionPattern()
371
                    );
372
                }
373
            }
374
375
            $orCondition['parameters'][] = [
376
                'field' => 'field_' . $fieldName . $salt,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $salt does not exist. Did you maybe mean $saltObj?
Loading history...
377
                'value' => $value
378
            ];
379
        } else {
380
            $isNotARelation = 0 !== strpos($fieldName, 'Embedded.');
381
            if ($isNotARelation) {
382
                $whereCondition =
383
                    $this->entityAlias . '.' . $fieldName . ' ' .
384
                    $op->getMeta() . ' ' .
385
                    $this->entityAlias . '.' . $value;
386 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...
387
                    $orCondition['orCondition'] .= ' OR ' . $whereCondition;
388
                } else {
389
                    $orCondition['orCondition'] = $whereCondition;
390
                }
391
            }
392
        }
393
394
        if (strstr($filter, '_embedded.')) {
395
396
            $this->join($filter);
397
            $relationEntityAlias = $this->getRelationEntityAlias();
398
399
            $embeddedFields = explode('.', $fieldName);
400
            $fieldName = $this->parser->camelize($embeddedFields[count($embeddedFields) - 1]);
401
402 View Code Duplication
            if ($filtering->isListOperator()) {
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...
403
                $whereCondition =
404
                    $relationEntityAlias . '.' . $fieldName . ' ' .
405
                    $op->getMeta() . ' ' .
406
                    '(:field_' . $fieldName . $saltObj->getSalt() . ')';
407
            } else {
408
                $whereCondition =
409
                    $relationEntityAlias . '.' . $fieldName . ' ' .
410
                    $op->getMeta() . ' ' .
411
                    ':field_' . $fieldName . $saltObj->getSalt();
412
            }
413
414 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...
415
                $orCondition['orCondition'] .= ' OR ' . $whereCondition;
416
            } else {
417
                $orCondition['orCondition'] = $whereCondition;
418
            }
419
420 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...
421
                if ($filtering->isListOperator()) {
422
                    $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

422
                    $value = explode(',', /** @scrutinizer ignore-type */ $value);
Loading history...
423
                } else {
424
                    $value = str_replace(
425
                        '{string}',
426
                        $value,
427
                        $op->getSubstitutionPattern()
428
                    );
429
                }
430
            }
431
432
            $orCondition['parameters'][] = [
433
                'field' => 'field_' . $fieldName . $saltObj->getSalt(),
434
                'value' => $value
435
            ];
436
        }
437
438
        return $orCondition;
439
    }
440
441
    public function sort()
442
    {
443
        $this->ensureFieldsDefined();
444
        $this->ensureSortingIsDefined();
445
446
        foreach ($this->sorting as $sort => $val) {
447
            $val = strtolower($val);
448
449
            $fieldName = $this->parser->camelize($sort);
450
451
            if (in_array($fieldName, $this->fields)) {
452
                $direction = ($val === self::DIRECTION_AZ) ? self::DIRECTION_AZ : self::DIRECTION_ZA;
453
                $this->qBuilder->addOrderBy($this->entityAlias . '.' . $fieldName, $direction);
454
            }
455
456
            if (strstr($sort, '_embedded.')) {
457
                $this->join($sort);
458
                $relationEntityAlias = $this->getRelationEntityAlias();
459
460
                $embeddedFields = explode('.', $sort);
461
                $fieldName = $this->parser->camelize($embeddedFields[2]);
462
                $direction = ($val === self::DIRECTION_AZ) ? self::DIRECTION_AZ : self::DIRECTION_ZA;
463
464
                $this->qBuilder->addOrderBy($relationEntityAlias . '.' . $fieldName, $direction);
465
            }
466
467
        }
468
469
        return $this;
470
    }
471
472
    public function getQueryBuilder()
473
    {
474
        $this->ensureQueryBuilderIsDefined();
475
476
        return $this->qBuilder;
477
    }
478
479
    public function buildSelectValue() : string
480
    {
481
        if ("" == $this->getSelect()) {
482
            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

482
            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...
483
                $this->getEntityName()
484
            );
485
        }
486
487
        return $this->getSelect();
488
    }
489
490
    private function setRelationEntityAlias(string $relationEntityAlias)
491
    {
492
        $this->relationEntityAlias = $relationEntityAlias;
493
    }
494
495
    private function getRelationEntityAlias()
496
    {
497
        return $this->relationEntityAlias;
498
    }
499
500
    public function setRel($rel)
501
    {
502
        $this->rel = $rel;
503
504
        return $this;
505
    }
506
507
    public function getRel()
508
    {
509
        return $this->rel;
510
    }
511
512
    public function setPrinting($printing)
513
    {
514
        $this->printing = $printing;
515
516
        return $this;
517
    }
518
519
    public function getPrinting()
520
    {
521
        return $this->printing;
522
    }
523
524
    public function setPage($page)
525
    {
526
        $this->page = $page;
527
528
        return $this;
529
    }
530
531
    public function getPage()
532
    {
533
        return $this->page;
534
    }
535
536
    public function setPageLength($pageLength)
537
    {
538
        $this->pageLength = $pageLength;
539
540
        return $this;
541
    }
542
543
    public function getPageLength()
544
    {
545
        return $this->pageLength;
546
    }
547
548
    public function setSelect( $select) : QueryBuilderFactory
549
    {
550
        $this->select = $select;
551
552
        return $this;
553
    }
554
555
    public function getSelect()
556
    {
557
        return $this->select;
558
    }
559
560
    public function getEntityManager()
561
    {
562
        return $this->manager;
563
    }
564
}
565