Passed
Pull Request — master (#209)
by
unknown
11:33
created

QueryBuilder::buildQuery()   C

Complexity

Conditions 8
Paths 24

Size

Total Lines 155
Code Lines 91

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 91
c 2
b 0
f 0
dl 0
loc 155
rs 6.9519
cc 8
nc 24
nop 9

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 \EWW\Dpf\Configuration\ClientConfigurationManager
27
     * @TYPO3\CMS\Extbase\Annotation\Inject
28
     */
29
    protected $clientConfigurationManager;
30
31
    /**
32
     * documentTypeRepository
33
     *
34
     * @var \EWW\Dpf\Domain\Repository\DocumentTypeRepository
35
     * @TYPO3\CMS\Extbase\Annotation\Inject
36
     */
37
    protected $documentTypeRepository = null;
38
39
    /**
40
     * security
41
     *
42
     * @var \EWW\Dpf\Security\Security
43
     * @TYPO3\CMS\Extbase\Annotation\Inject
44
     */
45
    protected $security = null;
46
47
    /**
48
     * Builds the document list query.
49
     *
50
     * @param int $itemsPerPage
51
     * @param array $workspaceFilter
52
     * @param int $from
53
     * @param array $bookmarkIdentifiers
54
     * @param array $filters
55
     * @param array $excludeFilters
56
     * @param string $sortField
57
     * @param string $sortOrder
58
     * @param string $queryString
59
     *
60
     * @return array
61
     */
62
    public function buildQuery(
63
        $itemsPerPage, $workspaceFilter, $from = 0, $bookmarkIdentifiers = [], $filters = [],
64
        $excludeFilters = [], $sortField = null, $sortOrder = null, $queryString = null
65
    )
66
    {
67
68
        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...
69
            $workspaceFilter = [0 => $workspaceFilter];
70
        }
71
72
        // The base filter.
73
        $queryFilter = [
74
            'bool' => [
75
                'must' => [
76
                    [
77
                        'bool' => [
78
                            'should' => $workspaceFilter
79
                        ]
80
                    ]
81
                ]
82
            ]
83
        ];
84
85
        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...
86
            // Add user document bookmarks.
87
88
            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...
89
                $queryFilter['bool']['must'][0]['bool']['should'][] = [
90
                    'terms' => [
91
                        '_id' => array_values(array_filter($bookmarkIdentifiers))
92
                    ]
93
                ];
94
            }
95
        } else {
96
            // Show only user document bookmarks.
97
            $queryFilter['bool']['must'][0] = [
98
                'terms' => [
99
                    '_id' => $bookmarkIdentifiers
100
                ]
101
            ];
102
        }
103
104
        $filterPart = $this->buildFilterQueryPart($filters, $excludeFilters);
105
106
        if ($filterPart) {
107
            $queryFilter['bool']['must'][] = $filterPart;
108
        }
109
110
        if (!is_null($queryString)) {
111
            $query = [
112
                'bool' => [
113
                    'must' => [
114
                        'query_string' => [
115
                            'query' => $queryString
116
                        ]
117
                    ],
118
                    'filter' => $queryFilter
119
                ]
120
            ];
121
        } else {
122
            $query = [
123
                'bool' => [
124
                    'must' => [
125
                        'match_all' => (object)[]
126
                    ],
127
                    'filter' => $queryFilter
128
                ]
129
            ];
130
131
        }
132
133
134
        // Put together the complete query.
135
        $fullQuery = [
136
            'body' => [
137
                'size' => $itemsPerPage,
138
                'from' => $from,
139
                'query' => $query,
140
                'sort' => $this->buildSortQueryPart($sortField, $sortOrder),
141
                'aggs' => [
142
                    'aliasState' => [
143
                        'terms' => [
144
                            'field' => 'aliasState'
145
                        ]
146
                    ],
147
                    'year' => [
148
                        'terms' => [
149
                            'field' => 'year'
150
                        ]
151
                    ],
152
                    'doctype' => [
153
                        'terms' => [
154
                            'field' => 'doctype'
155
                        ]
156
                    ],
157
                    'hasFiles' => [
158
                        'terms' => [
159
                            'field' => 'hasFiles'
160
                        ]
161
                    ],
162
                    'universityCollection' => [
163
                        'terms' => [
164
                            'script' => [
165
                                'lang' => 'painless',
166
                                'source' =>
167
                                    "for (int i = 0; i < doc['collections'].length; ++i) {".
168
                                    "    if(doc['collections'][i] =='".
169
                                    $this->clientConfigurationManager->getUniversityCollection() ."') {".
170
                                    "        return 'true';".
171
                                    "    }".
172
                                    "}".
173
                                    "return 'false';"
174
                            ]
175
                        ]
176
                    ],
177
                    'persons' => [
178
                        'terms' => [
179
                            'field' => 'personData.name',
180
                            'size'=> 1000
181
                        ]
182
                    ],
183
                    'creatorRole' => [
184
                        'terms' => [
185
                            'script' => [
186
                                'lang' => 'painless',
187
                                'source' =>
188
                                    "if (".
189
                                    "    doc['creator'].size() > 0 &&".
190
                                    "    doc['creator'].value == '".$this->security->getUser()->getUid()."') {".
191
                                    "    return 'self';".
192
                                    "}".
193
                                    "if (".
194
                                    "    doc['creatorRole'].size() > 0 &&".
195
                                    "    doc['creatorRole'].value == '".Security::ROLE_LIBRARIAN."'".
196
                                    ") {".
197
                                    "    return 'librarian';".
198
                                    "}".
199
                                    "if (".
200
                                    "    doc['creatorRole'].size() > 0 &&".
201
                                    "    doc['creatorRole'].value == '".Security::ROLE_RESEARCHER."'".
202
                                    ") {".
203
                                    "    return 'user';".
204
                                    "}".
205
                                    "return 'unknown';"
206
                            ]
207
                        ]
208
                    ]
209
210
                ]
211
            ]
212
        ];
213
214
        // \TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($fullQuery, null, 20);
215
216
        return $fullQuery;
217
218
    }
219
220
    /**
221
     * Composes the filter part based on the given filters.
222
     *
223
     * @param array $filters
224
     * @param array $excludeFilters
225
     * @return array
226
     */
227
    protected function buildFilterQueryPart($filters, $excludeFilters = []) {
228
229
        $queryFilter = [];
230
231
        // Build the column filter part.
232
        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...
233
234
            $validKeys = [
235
                'aliasState', 'persons', 'doctype', 'hasFiles', 'year',
236
                'universityCollection', 'creatorRole', 'creationDate'
237
            ];
238
239
            foreach ($filters as $key => $filterValues) {
240
                $queryFilterPart = [];
241
                if (in_array($key, $validKeys, true)) {
242
                    if ($key == 'universityCollection') {
243
                        if ($filterValues && is_array($filterValues)) {
244
                            if (in_array("true", $filterValues)) {
245
                                $filterValue = $this->clientConfigurationManager->getUniversityCollection();
246
                                $queryFilterPart['bool']['should'][] = [
247
                                    'term' => [
248
                                        'collections' => $filterValue
249
                                    ]
250
                                ];
251
                            } else {
252
                                $filterValue = $this->clientConfigurationManager->getUniversityCollection();
253
                                $queryFilterPart['bool']['should'][] = [
254
                                    'bool' => [
255
                                        'must_not' => [
256
                                            'term' => [
257
                                                'collections' => $filterValue
258
                                            ]
259
                                        ]
260
                                    ]
261
                                ];
262
                            }
263
                            $queryFilter['bool']['must'][] = $queryFilterPart;
264
                        }
265
                    } elseif ($key == 'creatorRole') {
266
                        $queryFilterPart = [];
267
                        if ($filterValues && is_array($filterValues)) {
268
                            if (in_array("librarian", $filterValues)) {
269
                                $creatorRolePart['bool']['must'] = [
270
                                    [
271
                                        'term' => [
272
                                            'creatorRole' => Security::ROLE_LIBRARIAN
273
                                        ]
274
                                    ],
275
                                    [
276
                                        'bool' => [
277
                                            'must_not' => [
278
                                                'term' => [
279
                                                    'creator' => $this->security->getUser()->getUid()
280
                                                ]
281
                                            ]
282
                                        ]
283
                                    ]
284
                                ];
285
                                $queryFilterPart['bool']['should'][] = $creatorRolePart;
286
                            } elseif (in_array("user", $filterValues)) {
287
                                $creatorRolePart['bool']['must'] = [
288
                                    [
289
                                        'term' => [
290
                                            'creatorRole' => Security::ROLE_RESEARCHER
291
                                        ]
292
                                    ],
293
                                    [
294
                                        'bool' => [
295
                                            'must_not' => [
296
                                                'term' => [
297
                                                    'creator' => $this->security->getUser()->getUid()
298
                                                ]
299
                                            ]
300
                                        ]
301
                                    ]
302
                                ];
303
                                $queryFilterPart['bool']['should'][] = $creatorRolePart;
304
                            } elseif (in_array("self", $filterValues)) {
305
                                $creatorRolePart['bool']['must'] = [
306
                                    [
307
                                        'term' => [
308
                                            'creator' =>  $this->security->getUser()->getUid()
309
                                        ]
310
                                    ]
311
                                ];
312
                                $queryFilterPart['bool']['should'][] = $creatorRolePart;
313
                            } else {
314
                                $creatorRolePart['bool']['must'] = [
315
                                    [
316
                                        'bool' => [
317
                                            'must_not' => [
318
                                                'term' => [
319
                                                    'creator' => $this->security->getUser()->getUid()
320
                                                ]
321
                                            ]
322
                                        ]
323
                                    ],
324
                                    [
325
                                        'bool' => [
326
                                            'must_not' => [
327
                                                'term' => [
328
                                                    'creatorRole' => Security::ROLE_LIBRARIAN
329
                                                ]
330
                                            ]
331
                                        ]
332
                                    ],
333
                                    [
334
                                        'bool' => [
335
                                            'must_not' => [
336
                                                'term' => [
337
                                                    'creatorRole' => Security::ROLE_RESEARCHER
338
                                                ]
339
                                            ]
340
                                        ]
341
                                    ]
342
                                ];
343
                                $queryFilterPart['bool']['should'][] = $creatorRolePart;
344
                            }
345
346
                            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...
347
                                $queryFilter['bool']['must'][] = $queryFilterPart;
348
                            }
349
                        }
350
                    } else {
351
                        if ($filterValues && is_array($filterValues)) {
352
                            foreach ($filterValues as $filterValue) {
353
                                $queryFilterPart['bool']['should'][] = [
354
                                    'term' => [
355
                                        $key => $filterValue
356
                                    ]
357
                                ];
358
                            }
359
                            $queryFilter['bool']['must'][] = $queryFilterPart;
360
                        }
361
                    }
362
                }
363
            }
364
        }
365
366
        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...
367
            if ($excludeFilters['aliasState']) {
368
                foreach ($excludeFilters['aliasState'] as $aliasStateExclude) {
369
                    $queryFilter['bool']['must'][] = [
370
                        'bool' => [
371
                            'must_not' => [
372
                                'bool' => [
373
                                    'must' => [
374
                                        [
375
                                            'term' => [
376
                                                'aliasState' => $aliasStateExclude
377
                                            ]
378
                                        ],
379
                                        [
380
                                            'bool' => [
381
                                                'should' => [
382
                                                    [
383
                                                        'term' => [
384
                                                            'creator' => $this->security->getUser()->getUid()
385
                                                        ]
386
                                                    ],
387
                                                    [
388
                                                        'term' => [
389
                                                            'fobIdentifiers' => $this->security->getFisPersId()
390
                                                        ]
391
                                                    ]
392
                                                ]
393
                                            ]
394
                                        ]
395
                                    ]
396
                                ]
397
                            ]
398
                        ]
399
                    ];
400
                }
401
            }
402
        }
403
404
        return $queryFilter;
405
    }
406
407
408
    /**
409
     * Composes the sort query part based on the given sort field and order.
410
     *
411
     * @param string $sortField
412
     * @param string $sortOrder
413
     * @return array
414
     */
415
    protected function buildSortQueryPart($sortField, $sortOrder) {
416
417
        $sortField = ($sortField)? $sortField : 'title';
418
        $sortOrder = ($sortOrder)? $sortOrder : 'asc';
419
420
        // Build the sorting part.
421
        $script = "";
422
        if ($sortField == "aliasState") {
423
            $script = $this->getSortScriptState();
424
        } elseif ($sortField == "universityCollection") {
425
            $script = $this->getSortScriptUniversityCollection(
426
                $this->clientConfigurationManager->getUniversityCollection());
427
        } elseif ($sortField == "hasFiles") {
428
            $script = $this->getSortScriptHasFiles();
429
        } elseif ($sortField == "creatorRole") {
430
            $script = $this->getSortScriptCreatorRole($this->security->getUser()->getUid());
431
        }
432
433
        if ($script) {
434
            $sort = [
435
                "_script" => [
436
                    "type" => "string",
437
                    "order" => $sortOrder,
438
                    "script" => [
439
                        "lang" => "painless",
440
                        "source" => $script
441
                    ]
442
                ],
443
                "title.keyword" => [
444
                    "order" => "asc"
445
                ]
446
            ];
447
        } else {
448
            if ($sortField == 'title') {
449
                $sortField.= ".keyword";
450
            }
451
452
            if ($sortField == 'personsSort') {
453
                $sortField.= ".keyword";
454
            }
455
456
            $sort = [
457
                $sortField => [
458
                    'order' => $sortOrder
459
                ]
460
            ];
461
        }
462
463
        return $sort;
464
    }
465
466
467
    protected function getSortScriptUniversityCollection($collection)
468
    {
469
        $script  = "for (int i = 0; i < doc['collections'].length; ++i) {";
470
        $script .= "    if (doc['collections'][i] == '".$collection."') {";
471
        $script .= "        return '1';";
472
        $script .= "    }";
473
        $script .= "}";
474
        $script .= "return '2'";
475
476
        return $script;
477
    }
478
479
    protected function getSortScriptHasFiles()
480
    {
481
        $script = "if (doc['hasFiles'].value == 'true') {";
482
        $script .= "    return '1';";
483
        $script .= "}";
484
        $script .= "return '2'";
485
486
        return $script;
487
    }
488
489
    protected function getSortScriptCreatorRole($feUserUid)
490
    {
491
        $script = "if (doc['creator'].value == '".$feUserUid."') {";
492
        $script .= "    return '1';";
493
        $script .= "}";
494
        $script .= "if (doc['creatorRole'].value == '".Security::ROLE_LIBRARIAN."') {";
495
        $script .= "return '2';";
496
        $script .= "}";
497
        $script .= "if (doc['creatorRole'].value == '".Security::ROLE_RESEARCHER."') {";
498
        $script .= "    return '3';";
499
        $script .= "}";
500
        $script .= "return '4';";
501
502
        return $script;
503
    }
504
505
506
    protected function getSortScriptState()
507
    {
508
        $sortStates = [];
509
        foreach (DocumentWorkflow::PLACES as $state) {
510
            if (array_key_exists($state, DocumentWorkflow::STATE_TO_ALIASSTATE_MAPPING)) {
511
                $aliasState = DocumentWorkflow::STATE_TO_ALIASSTATE_MAPPING[$state];
512
                $key = 'LLL:EXT:dpf/Resources/Private/Language/locallang.xlf:manager.documentList.state.'.$aliasState;
513
                $stateName = LocalizationUtility::translate($key, 'dpf');
514
                $sortStates[] = "if (doc['state'].value == '".$state."') return '".$stateName."';";
515
            }
516
        }
517
518
        $sortStates = implode(" ", $sortStates);
519
520
        return $sortStates." return '';";
521
    }
522
523
524
    protected function getSortScriptDoctype()
525
    {
526
        $sortDoctypes = [];
527
        foreach ($this->documentTypeRepository->findAll() as $documentType) {
528
            if ($documentType->getName() && $documentType->getDisplayname()) {
529
                $sortDoctypes[] = "if (doc['doctype'].value == '".$documentType->getName()."')"
530
                    ." return '".$documentType->getDisplayname()."';";
531
            }
532
        }
533
534
        $sortDoctypes = implode(" ", $sortDoctypes);
535
536
        return $sortDoctypes." return '';";
537
    }
538
539
}
540