Passed
Pull Request — master (#195)
by
unknown
09:41 queued 02:26
created

QueryBuilder::getSortScriptUniversityCollection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 1
dl 0
loc 10
rs 10
c 0
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 \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