Passed
Push — master ( 134b43...f02d33 )
by Ralf
09:50
created

QueryBuilder::getSettings()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 6
rs 10
c 1
b 0
f 0
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