Passed
Pull Request — master (#195)
by
unknown
07:19
created

QueryBuilder::buildQuery()   C

Complexity

Conditions 8
Paths 24

Size

Total Lines 154
Code Lines 90

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 90
c 1
b 0
f 0
nc 24
nop 9
dl 0
loc 154
rs 6.9737

How to fix   Long Method    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
namespace EWW\Dpf\Services\ElasticSearch;
3
4
/*
5
 * This file is part of the TYPO3 CMS project.
6
 *
7
 * It is free software; you can redistribute it and/or modify it under
8
 * the terms of the GNU General Public License, either version 2
9
 * of the License, or any later version.
10
 *
11
 * For the full copyright and license information, please read the
12
 * LICENSE.txt file that was distributed with this source code.
13
 *
14
 * The TYPO3 project - inspiring people to share!
15
 */
16
17
use Elasticsearch\ClientBuilder;
18
use EWW\Dpf\Domain\Workflow\DocumentWorkflow;
19
use EWW\Dpf\Security\Security;
20
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
21
22
class QueryBuilder
23
{
24
    /**
25
     *
26
     * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
27
     * @inject
28
     */
29
    protected $configurationManager;
30
31
32
    /**
33
     * documentTypeRepository
34
     *
35
     * @var \EWW\Dpf\Domain\Repository\DocumentTypeRepository
36
     * @inject
37
     */
38
    protected $documentTypeRepository = null;
39
40
    /**
41
     * security
42
     *
43
     * @var \EWW\Dpf\Security\Security
44
     * @inject
45
     */
46
    protected $security = null;
47
48
49
    /**
50
     * Get typoscript settings
51
     *
52
     * @return mixed
53
     */
54
    public function getSettings()
55
    {
56
        $frameworkConfiguration = $this->configurationManager->getConfiguration(
57
            \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
58
        );
59
        return $frameworkConfiguration['settings'];
60
    }
61
62
63
    /**
64
     * Builds the document list query.
65
     *
66
     * @param int $itemsPerPage
67
     * @param array $workspaceFilter
68
     * @param int $from
69
     * @param array $bookmarkIdentifiers
70
     * @param array $filters
71
     * @param array $excludeFilters
72
     * @param string $sortField
73
     * @param string $sortOrder
74
     * @param string $queryString
75
     *
76
     * @return array
77
     */
78
    public function buildQuery(
79
        $itemsPerPage, $workspaceFilter, $from = 0, $bookmarkIdentifiers = [], $filters = [],
80
        $excludeFilters = [], $sortField = null, $sortOrder = null, $queryString = null
81
    )
82
    {
83
84
        if ($workspaceFilter) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $workspaceFilter of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
85
            $workspaceFilter = [0 => $workspaceFilter];
86
        }
87
88
        // The base filter.
89
        $queryFilter = [
90
            'bool' => [
91
                'must' => [
92
                    [
93
                        'bool' => [
94
                            'should' => $workspaceFilter
95
                        ]
96
                    ]
97
                ]
98
            ]
99
        ];
100
101
        if (!($excludeFilters && array_key_exists('bookmarks', $excludeFilters))) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $excludeFilters of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
102
            // Add user document bookmarks.
103
104
            if ($bookmarkIdentifiers && is_array($bookmarkIdentifiers)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $bookmarkIdentifiers of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
105
                $queryFilter['bool']['must'][0]['bool']['should'][] = [
106
                    'terms' => [
107
                        '_id' => array_values(array_filter($bookmarkIdentifiers))
108
                    ]
109
                ];
110
            }
111
        } else {
112
            // Show only user document bookmarks.
113
            $queryFilter['bool']['must'][0] = [
114
                'terms' => [
115
                    '_id' => $bookmarkIdentifiers
116
                ]
117
            ];
118
        }
119
120
        $filterPart = $this->buildFilterQueryPart($filters, $excludeFilters);
121
122
        if ($filterPart) {
123
            $queryFilter['bool']['must'][] = $filterPart;
124
        }
125
126
        if (!is_null($queryString)) {
127
            $query = [
128
                'bool' => [
129
                    'must' => [
130
                        'query_string' => [
131
                            'query' => $queryString
132
                        ]
133
                    ],
134
                    'filter' => $queryFilter
135
                ]
136
            ];
137
        } else {
138
            $query = [
139
                'bool' => [
140
                    'must' => [
141
                        'match_all' => (object)[]
142
                    ],
143
                    'filter' => $queryFilter
144
                ]
145
            ];
146
147
        }
148
149
150
        // Put together the complete query.
151
        $fullQuery = [
152
            'body' => [
153
                'size' => $itemsPerPage,
154
                'from' => $from,
155
                'query' => $query,
156
                'sort' => $this->buildSortQueryPart($sortField, $sortOrder),
157
                'aggs' => [
158
                    'aliasState' => [
159
                        'terms' => [
160
                            'field' => 'aliasState'
161
                        ]
162
                    ],
163
                    'year' => [
164
                        'terms' => [
165
                            'field' => 'year'
166
                        ]
167
                    ],
168
                    'doctype' => [
169
                        'terms' => [
170
                            'field' => 'doctype'
171
                        ]
172
                    ],
173
                    'hasFiles' => [
174
                        'terms' => [
175
                            'field' => 'hasFiles'
176
                        ]
177
                    ],
178
                    'universityCollection' => [
179
                        'terms' => [
180
                            'script' => [
181
                                'lang' => 'painless',
182
                                'source' =>
183
                                    "for (int i = 0; i < doc['collections'].length; ++i) {".
184
                                    "    if(doc['collections'][i] =='".$this->getSettings()['universityCollection']."') {".
185
                                    "        return 'true';".
186
                                    "    }".
187
                                    "}".
188
                                    "return 'false';"
189
                            ]
190
                        ]
191
                    ],
192
                    'persons' => [
193
                        'terms' => [
194
                            'field' => 'personData.name',
195
                            'size'=> 1000
196
                        ]
197
                    ],
198
                    'creatorRole' => [
199
                        'terms' => [
200
                            'script' => [
201
                                'lang' => 'painless',
202
                                'source' =>
203
                                    "if (".
204
                                    "    doc['creator'].size() > 0 &&".
205
                                    "    doc['creator'].value == '".$this->security->getUser()->getUid()."') {".
206
                                    "    return 'self';".
207
                                    "}".
208
                                    "if (".
209
                                    "    doc['creatorRole'].size() > 0 &&".
210
                                    "    doc['creatorRole'].value == '".Security::ROLE_LIBRARIAN."'".
211
                                    ") {".
212
                                    "    return 'librarian';".
213
                                    "}".
214
                                    "if (".
215
                                    "    doc['creatorRole'].size() > 0 &&".
216
                                    "    doc['creatorRole'].value == '".Security::ROLE_RESEARCHER."'".
217
                                    ") {".
218
                                    "    return 'user';".
219
                                    "}".
220
                                    "return 'unknown';"
221
                            ]
222
                        ]
223
                    ]
224
225
                ]
226
            ]
227
        ];
228
229
        // \TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($fullQuery, null, 20);
230
231
        return $fullQuery;
232
233
    }
234
235
    /**
236
     * Composes the filter part based on the given filters.
237
     *
238
     * @param array $filters
239
     * @param array $excludeFilters
240
     * @return array
241
     */
242
    protected function buildFilterQueryPart($filters, $excludeFilters = []) {
243
244
        $queryFilter = [];
245
246
        // Build the column filter part.
247
        if ($filters && is_array($filters)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $filters of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
248
249
            $validKeys = [
250
                'aliasState', 'persons', 'doctype', 'hasFiles', 'year',
251
                'universityCollection', 'creatorRole', 'creationDate'
252
            ];
253
254
            foreach ($filters as $key => $filterValues) {
255
                $queryFilterPart = [];
256
                if (in_array($key, $validKeys, true)) {
257
                    if ($key == 'universityCollection') {
258
                        if ($filterValues && is_array($filterValues)) {
259
                            if (in_array("true", $filterValues)) {
260
                                $filterValue = $this->getSettings()['universityCollection'];
261
                                $queryFilterPart['bool']['should'][] = [
262
                                    'term' => [
263
                                        'collections' => $filterValue
264
                                    ]
265
                                ];
266
                            } else {
267
                                $filterValue = $this->getSettings()['universityCollection'];
268
                                $queryFilterPart['bool']['should'][] = [
269
                                    'bool' => [
270
                                        'must_not' => [
271
                                            'term' => [
272
                                                'collections' => $filterValue
273
                                            ]
274
                                        ]
275
                                    ]
276
                                ];
277
                            }
278
                            $queryFilter['bool']['must'][] = $queryFilterPart;
279
                        }
280
                    } elseif ($key == 'creatorRole') {
281
                        $queryFilterPart = [];
282
                        if ($filterValues && is_array($filterValues)) {
283
                            if (in_array("librarian", $filterValues)) {
284
                                $creatorRolePart['bool']['must'] = [
285
                                    [
286
                                        'term' => [
287
                                            'creatorRole' => Security::ROLE_LIBRARIAN
288
                                        ]
289
                                    ],
290
                                    [
291
                                        'bool' => [
292
                                            'must_not' => [
293
                                                'term' => [
294
                                                    'creator' => $this->security->getUser()->getUid()
295
                                                ]
296
                                            ]
297
                                        ]
298
                                    ]
299
                                ];
300
                                $queryFilterPart['bool']['should'][] = $creatorRolePart;
301
                            } elseif (in_array("user", $filterValues)) {
302
                                $creatorRolePart['bool']['must'] = [
303
                                    [
304
                                        'term' => [
305
                                            'creatorRole' => Security::ROLE_RESEARCHER
306
                                        ]
307
                                    ],
308
                                    [
309
                                        'bool' => [
310
                                            'must_not' => [
311
                                                'term' => [
312
                                                    'creator' => $this->security->getUser()->getUid()
313
                                                ]
314
                                            ]
315
                                        ]
316
                                    ]
317
                                ];
318
                                $queryFilterPart['bool']['should'][] = $creatorRolePart;
319
                            } elseif (in_array("self", $filterValues)) {
320
                                $creatorRolePart['bool']['must'] = [
321
                                    [
322
                                        'term' => [
323
                                            'creator' =>  $this->security->getUser()->getUid()
324
                                        ]
325
                                    ]
326
                                ];
327
                                $queryFilterPart['bool']['should'][] = $creatorRolePart;
328
                            } else {
329
                                $creatorRolePart['bool']['must'] = [
330
                                    [
331
                                        'bool' => [
332
                                            'must_not' => [
333
                                                'term' => [
334
                                                    'creator' => $this->security->getUser()->getUid()
335
                                                ]
336
                                            ]
337
                                        ]
338
                                    ],
339
                                    [
340
                                        'bool' => [
341
                                            'must_not' => [
342
                                                'term' => [
343
                                                    'creatorRole' => Security::ROLE_LIBRARIAN
344
                                                ]
345
                                            ]
346
                                        ]
347
                                    ],
348
                                    [
349
                                        'bool' => [
350
                                            'must_not' => [
351
                                                'term' => [
352
                                                    'creatorRole' => Security::ROLE_RESEARCHER
353
                                                ]
354
                                            ]
355
                                        ]
356
                                    ]
357
                                ];
358
                                $queryFilterPart['bool']['should'][] = $creatorRolePart;
359
                            }
360
361
                            if ($queryFilterPart) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $queryFilterPart of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
362
                                $queryFilter['bool']['must'][] = $queryFilterPart;
363
                            }
364
                        }
365
                    } else {
366
                        if ($filterValues && is_array($filterValues)) {
367
                            foreach ($filterValues as $filterValue) {
368
                                $queryFilterPart['bool']['should'][] = [
369
                                    'term' => [
370
                                        $key => $filterValue
371
                                    ]
372
                                ];
373
                            }
374
                            $queryFilter['bool']['must'][] = $queryFilterPart;
375
                        }
376
                    }
377
                }
378
            }
379
        }
380
381
        if ($excludeFilters && array_key_exists('aliasState', $excludeFilters)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $excludeFilters of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
382
            if ($excludeFilters['aliasState']) {
383
                foreach ($excludeFilters['aliasState'] as $aliasStateExclude) {
384
                    $queryFilter['bool']['must'][] = [
385
                        'bool' => [
386
                            'must_not' => [
387
                                'bool' => [
388
                                    'must' => [
389
                                        [
390
                                            'term' => [
391
                                                'aliasState' => $aliasStateExclude
392
                                            ]
393
                                        ],
394
                                        [
395
                                            'bool' => [
396
                                                'should' => [
397
                                                    [
398
                                                        'term' => [
399
                                                            'creator' => $this->security->getUser()->getUid()
400
                                                        ]
401
                                                    ],
402
                                                    [
403
                                                        'term' => [
404
                                                            'fobIdentifiers' => $this->security->getUser()->getFisPersId()
405
                                                        ]
406
                                                    ]
407
                                                ]
408
                                            ]
409
                                        ]
410
                                    ]
411
                                ]
412
                            ]
413
                        ]
414
                    ];
415
                }
416
            }
417
        }
418
419
        return $queryFilter;
420
    }
421
422
423
    /**
424
     * Composes the sort query part based on the given sort field and order.
425
     *
426
     * @param string $sortField
427
     * @param string $sortOrder
428
     * @return array
429
     */
430
    protected function buildSortQueryPart($sortField, $sortOrder) {
431
432
        $sortField = ($sortField)? $sortField : 'title';
433
        $sortOrder = ($sortOrder)? $sortOrder : 'asc';
434
435
        // Build the sorting part.
436
        $script = "";
437
        if ($sortField == "aliasState") {
438
            $script = $this->getSortScriptState();
439
        } elseif ($sortField == "universityCollection") {
440
            $script = $this->getSortScriptUniversityCollection($this->getSettings()['universityCollection']);
441
        } elseif ($sortField == "hasFiles") {
442
            $script = $this->getSortScriptHasFiles();
443
        } elseif ($sortField == "creatorRole") {
444
            $script = $this->getSortScriptCreatorRole($this->security->getUser()->getUid());
445
        }
446
447
        if ($script) {
448
            $sort = [
449
                "_script" => [
450
                    "type" => "string",
451
                    "order" => $sortOrder,
452
                    "script" => [
453
                        "lang" => "painless",
454
                        "source" => $script
455
                    ]
456
                ],
457
                "title.keyword" => [
458
                    "order" => "asc"
459
                ]
460
            ];
461
        } else {
462
            if ($sortField == 'title') {
463
                $sortField.= ".keyword";
464
            }
465
466
            if ($sortField == 'personsSort') {
467
                $sortField.= ".keyword";
468
            }
469
470
            $sort = [
471
                $sortField => [
472
                    'order' => $sortOrder
473
                ]
474
            ];
475
        }
476
477
        return $sort;
478
    }
479
480
481
    protected function getSortScriptUniversityCollection($collection)
482
    {
483
        $script  = "for (int i = 0; i < doc['collections'].length; ++i) {";
484
        $script .= "    if (doc['collections'][i] == '".$collection."') {";
485
        $script .= "        return '1';";
486
        $script .= "    }";
487
        $script .= "}";
488
        $script .= "return '2'";
489
490
        return $script;
491
    }
492
493
    protected function getSortScriptHasFiles()
494
    {
495
        $script = "if (doc['hasFiles'].value == 'true') {";
496
        $script .= "    return '1';";
497
        $script .= "}";
498
        $script .= "return '2'";
499
500
        return $script;
501
    }
502
503
    protected function getSortScriptCreatorRole($feUserUid)
504
    {
505
        $script = "if (doc['creator'].value == '".$feUserUid."') {";
506
        $script .= "    return '1';";
507
        $script .= "}";
508
        $script .= "if (doc['creatorRole'].value == '".Security::ROLE_LIBRARIAN."') {";
509
        $script .= "return '2';";
510
        $script .= "}";
511
        $script .= "if (doc['creatorRole'].value == '".Security::ROLE_RESEARCHER."') {";
512
        $script .= "    return '3';";
513
        $script .= "}";
514
        $script .= "return '4';";
515
516
        return $script;
517
    }
518
519
520
    protected function getSortScriptState()
521
    {
522
        $sortStates = [];
523
        foreach (DocumentWorkflow::PLACES as $state) {
524
            if (array_key_exists($state, DocumentWorkflow::STATE_TO_ALIASSTATE_MAPPING)) {
525
                $aliasState = DocumentWorkflow::STATE_TO_ALIASSTATE_MAPPING[$state];
526
                $key = 'LLL:EXT:dpf/Resources/Private/Language/locallang.xlf:manager.documentList.state.'.$aliasState;
527
                $stateName = LocalizationUtility::translate($key, 'dpf');
528
                $sortStates[] = "if (doc['state'].value == '".$state."') return '".$stateName."';";
529
            }
530
        }
531
532
        $sortStates = implode(" ", $sortStates);
533
534
        return $sortStates." return '';";
535
    }
536
537
538
    protected function getSortScriptDoctype()
539
    {
540
        $sortDoctypes = [];
541
        foreach ($this->documentTypeRepository->findAll() as $documentType) {
542
            if ($documentType->getName() && $documentType->getDisplayname()) {
543
                $sortDoctypes[] = "if (doc['doctype'].value == '".$documentType->getName()."')"
544
                    ." return '".$documentType->getDisplayname()."';";
545
            }
546
        }
547
548
        $sortDoctypes = implode(" ", $sortDoctypes);
549
550
        return $sortDoctypes." return '';";
551
    }
552
553
}
554