Passed
Pull Request — master (#168)
by
unknown
08:57
created

QueryBuilder::buildQuery()   B

Complexity

Conditions 7
Paths 12

Size

Total Lines 151
Code Lines 88

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 7
eloc 88
nc 12
nop 9
dl 0
loc 151
rs 7.3284
c 2
b 0
f 0

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