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

286
                    $value = explode(',', /** @scrutinizer ignore-type */ $value);
Loading history...
287
                } else {
288
                    $value = str_replace(
289
                        '{string}',
290
                        $value,
291
                        $op->getSubstitutionPattern()
292
                    );
293
                }
294
            }
295
296
            $this->qBuilder->setParameter('field_' . $fieldName . $saltObj->getSalt(), $value);
297
        }
298
    }
299
300
    private function applyFilterOr($filter, $value, $orCondition)
301
    {
302
        $whereCondition = null;
303
        $filtering = FilteringObject::fromFilter($filter);
304
305
        $fieldName = $this->parser->camelize($filtering->getFieldName());
306
307
        $op = Operator::fromFilteringObject($filtering);
308
309
        $saltObj = new Salt($this->qBuilder);
310
        $saltObj->generateSaltForName($fieldName);
311
312
        if (in_array($fieldName, $this->fields)) {
313
314
            if ($filtering->hasOperator()) {
315
                if ($filtering->isListOperator()) {
316
                    $whereCondition =
317
                        $this->entityAlias . '.' . $fieldName . ' ' .
318
                        $op->getMeta()
319
                        .' (:field_' . $fieldName . $saltObj->getSalt() . ')';
320
                } else if ($filtering->isFieldEqualsOperator()) {
321
                    $whereCondition =
322
                        $this->entityAlias . '.' . $fieldName . ' ' .
323
                        $op->getMeta() . ' ' .
324
                        $this->entityAlias . '.' . $value
325
                    ;
326
                } else {
327
                    $whereCondition =
328
                        $this->entityAlias . '.' . $fieldName . ' ' .
329
                        $op->getMeta() . ' ' .
330
                        ':field_' . $fieldName . $saltObj->getSalt();
331
                }
332
            } else {
333
                $whereCondition =
334
                    $this->entityAlias . '.' . $fieldName . ' ' .
335
                    '=' . ' ' .
336
                    ':field_' . $fieldName . $saltObj->getSalt();
337
            }
338
339 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...
340
                $orCondition['orCondition'] .= ' OR ' . $whereCondition;
341
            } else {
342
                $orCondition['orCondition'] = $whereCondition;
343
            }
344
345 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...
346
                if ($filtering->isListOperator()) {
347
                    $value = explode(',', $value);
348
                } else {
349
                    $value = str_replace(
350
                        '{string}',
351
                        $value,
352
                        $op->getSubstitutionPattern()
353
                    );
354
                }
355
            }
356
357
            $orCondition['parameters'][] = [
358
                '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...
359
                'value' => $value
360
            ];
361
        } else {
362
            $isNotARelation = 0 !== strpos($fieldName, 'Embedded.');
363
            if ($isNotARelation) {
364
                $whereCondition =
365
                    $this->entityAlias . '.' . $fieldName . ' ' .
366
                    $op->getMeta() . ' ' .
367
                    $this->entityAlias . '.' . $value;
368 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...
369
                    $orCondition['orCondition'] .= ' OR ' . $whereCondition;
370
                } else {
371
                    $orCondition['orCondition'] = $whereCondition;
372
                }
373
            }
374
        }
375
376
        if (strstr($filter, '_embedded.')) {
377
378
            $this->join($filter);
379
            $relationEntityAlias = $this->getRelationEntityAlias();
380
381
            $embeddedFields = explode('.', $fieldName);
382
            $fieldName = $this->parser->camelize($embeddedFields[count($embeddedFields) - 1]);
383
384
            if ($filtering->isListOperator()) {
385
                $whereCondition =
386
                    $relationEntityAlias . '.' . $fieldName . ' ' .
387
                    $op->getMeta() . ' ' .
388
                    '(:field_' . $fieldName . $saltObj->getSalt() . ')';
389
            } else {
390
                $whereCondition =
391
                    $relationEntityAlias . '.' . $fieldName . ' ' .
392
                    $op->getMeta() . ' ' .
393
                    ':field_' . $fieldName . $saltObj->getSalt();
394
            }
395
396 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...
397
                $orCondition['orCondition'] .= ' OR ' . $whereCondition;
398
            } else {
399
                $orCondition['orCondition'] = $whereCondition;
400
            }
401
402 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...
403
                if ($filtering->isListOperator()) {
404
                    $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

404
                    $value = explode(',', /** @scrutinizer ignore-type */ $value);
Loading history...
405
                } else {
406
                    $value = str_replace(
407
                        '{string}',
408
                        $value,
409
                        $op->getSubstitutionPattern()
410
                    );
411
                }
412
            }
413
414
            $orCondition['parameters'][] = [
415
                'field' => 'field_' . $fieldName . $saltObj->getSalt(),
416
                'value' => $value
417
            ];
418
        }
419
420
        return $orCondition;
421
    }
422
423
    public function sort()
424
    {
425
        $this->ensureFieldsDefined();
426
        $this->ensureSortingIsDefined();
427
428
        foreach ($this->sorting as $sort => $val) {
429
            $val = strtolower($val);
430
431
            $fieldName = $this->parser->camelize($sort);
432
433
            if (in_array($fieldName, $this->fields)) {
434
                $direction = ($val === self::DIRECTION_AZ) ? self::DIRECTION_AZ : self::DIRECTION_ZA;
435
                $this->qBuilder->addOrderBy($this->entityAlias . '.' . $fieldName, $direction);
436
            }
437
438
            if (strstr($sort, '_embedded.')) {
439
                $this->join($sort);
440
                $relationEntityAlias = $this->getRelationEntityAlias();
441
442
                $embeddedFields = explode('.', $sort);
443
                $fieldName = $this->parser->camelize($embeddedFields[2]);
444
                $direction = ($val === self::DIRECTION_AZ) ? self::DIRECTION_AZ : self::DIRECTION_ZA;
445
446
                $this->qBuilder->addOrderBy($relationEntityAlias . '.' . $fieldName, $direction);
447
            }
448
449
        }
450
451
        return $this;
452
    }
453
454
    public function getQueryBuilder()
455
    {
456
        $this->ensureQueryBuilderIsDefined();
457
458
        return $this->qBuilder;
459
    }
460
461
    public function buildSelectValue() : string
462
    {
463
        if ("" == $this->getSelect()) {
464
            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

464
            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...
465
                $this->getEntityName()
466
            );
467
        }
468
469
        return $this->getSelect();
470
    }
471
472
    private function setRelationEntityAlias(string $relationEntityAlias)
473
    {
474
        $this->relationEntityAlias = $relationEntityAlias;
475
    }
476
477
    private function getRelationEntityAlias()
478
    {
479
        return $this->relationEntityAlias;
480
    }
481
482
    public function setRel($rel)
483
    {
484
        $this->rel = $rel;
485
486
        return $this;
487
    }
488
489
    public function getRel()
490
    {
491
        return $this->rel;
492
    }
493
494
    public function setPrinting($printing)
495
    {
496
        $this->printing = $printing;
497
498
        return $this;
499
    }
500
501
    public function getPrinting()
502
    {
503
        return $this->printing;
504
    }
505
506
    public function setPage($page)
507
    {
508
        $this->page = $page;
509
510
        return $this;
511
    }
512
513
    public function getPage()
514
    {
515
        return $this->page;
516
    }
517
518
    public function setPageLength($pageLength)
519
    {
520
        $this->pageLength = $pageLength;
521
522
        return $this;
523
    }
524
525
    public function getPageLength()
526
    {
527
        return $this->pageLength;
528
    }
529
530
    public function setSelect(string $select) : QueryBuilderFactory
531
    {
532
        $this->select = $select;
533
534
        return $this;
535
    }
536
537
    public function getSelect()
538
    {
539
        return $this->select;
540
    }
541
542
    public function getEntityManager()
543
    {
544
        return $this->manager;
545
    }
546
}
547