Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Pull Request — dev-extbase-fluid (#754)
by Alexander
03:00
created

SearchController::injectMetadataRepository()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
/**
3
 * (c) Kitodo. Key to digital objects e.V. <[email protected]>
4
 *
5
 * This file is part of the Kitodo and TYPO3 projects.
6
 *
7
 * @license GNU General Public License version 3 or later.
8
 * For the full copyright and license information, please read the
9
 * LICENSE.txt file that was distributed with this source code.
10
 */
11
12
namespace Kitodo\Dlf\Controller;
13
14
use Kitodo\Dlf\Common\Doc;
15
use Kitodo\Dlf\Common\DocumentList;
16
use Kitodo\Dlf\Common\Helper;
17
use Kitodo\Dlf\Common\Indexer;
18
use Kitodo\Dlf\Common\Solr;
19
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
20
use TYPO3\CMS\Core\Utility\GeneralUtility;
21
use Kitodo\Dlf\Domain\Repository\CollectionRepository;
22
use Kitodo\Dlf\Domain\Repository\MetadataRepository;
23
24
class SearchController extends AbstractController
25
{
26
    /**
27
     * @var CollectionRepository
28
     */
29
    protected $collectionRepository;
30
31
    /**
32
     * @param CollectionRepository $collectionRepository
33
     */
34
    public function injectCollectionRepository(CollectionRepository $collectionRepository)
35
    {
36
        $this->collectionRepository = $collectionRepository;
37
    }
38
39
    /**
40
     * @var MetadataRepository
41
     */
42
    protected $metadataRepository;
43
44
    /**
45
     * @param MetadataRepository $metadataRepository
46
     */
47
    public function injectMetadataRepository(MetadataRepository $metadataRepository)
48
    {
49
        $this->metadataRepository = $metadataRepository;
50
    }
51
52
    /**
53
     * Search Action
54
     *
55
     * @return void
56
     */
57
    public function searchAction()
58
    {
59
        // if search was triggered, get search parameters from POST variables
60
        $searchParams = $this->getParametersSafely('searchParameter');
61
62
        // output is done by main action
63
        $this->forward('main', null, null, ['searchParameter' => $searchParams]);
64
    }
65
66
    /**
67
     * Main action
68
     *
69
     * @return void
70
     */
71
    public function mainAction()
72
    {
73
        // Quit without doing anything if required variables are not set.
74
        if (empty($this->settings['solrcore'])) {
75
            $this->logger->warning('Incomplete plugin configuration');
76
            return;
77
        }
78
79
        // if search was triggered, get search parameters from POST variables
80
        $searchParams = $this->getParametersSafely('searchParameter');
81
82
        // Pagination of Results: Pass the currentPage to the fluid template to calculate current index of search result.
83
        $widgetPage = $this->getParametersSafely('@widget_0');
84
        if (empty($widgetPage)) {
85
            $widgetPage = ['currentPage' => 1];
86
        }
87
88
        // If a targetPid is given, the results will be shown by ListView on the target page.
89
        if (!empty($this->settings['targetPid']) && !empty($searchParams)) {
90
            $this->redirect('main', 'ListView', null,
91
                [
92
                    'searchParameter' => $searchParams,
93
                    'widgetPage' => $widgetPage
94
                ], $this->settings['targetPid']
95
            );
96
        }
97
98
        // get results from search
99
        // find all documents from Solr
100
        $solrResults = [];
101
        if (is_array($searchParams) && !empty($searchParams)) {
102
            // get all sortable metadata records
103
            $sortableMetadata = $this->metadataRepository->findByIsSortable(true);
0 ignored issues
show
Bug introduced by
The method findByIsSortable() does not exist on Kitodo\Dlf\Domain\Repository\MetadataRepository. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

103
            /** @scrutinizer ignore-call */ 
104
            $sortableMetadata = $this->metadataRepository->findByIsSortable(true);
Loading history...
104
105
            // get all metadata records to be shown in results
106
            $listedMetadata = $this->metadataRepository->findByIsListed(true);
0 ignored issues
show
Bug introduced by
The method findByIsListed() does not exist on Kitodo\Dlf\Domain\Repository\MetadataRepository. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

106
            /** @scrutinizer ignore-call */ 
107
            $listedMetadata = $this->metadataRepository->findByIsListed(true);
Loading history...
107
108
            if (is_array($searchParams) && !empty($searchParams)) {
109
                $solrResults = $this->documentRepository->findSolrByCollection('', $this->settings, $searchParams, $listedMetadata);
0 ignored issues
show
Bug introduced by
'' of type string is incompatible with the type Kitodo\Dlf\Domain\Model\Collection expected by parameter $collection of Kitodo\Dlf\Domain\Reposi...:findSolrByCollection(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

109
                $solrResults = $this->documentRepository->findSolrByCollection(/** @scrutinizer ignore-type */ '', $this->settings, $searchParams, $listedMetadata);
Loading history...
110
            }
111
112
            $documents = $solrResults['documents'] ? : [];
113
            $this->view->assign('documents', $documents);
114
            $rawResults = $solrResults['solrResults']['documents'] ? : [];
115
            $this->view->assign('numResults', count($rawResults));
116
            $this->view->assign('widgetPage', $widgetPage);
117
            $this->view->assign('lastSearch', $searchParams);
118
            $this->view->assign('listedMetadata', $listedMetadata);
119
            $this->view->assign('sortableMetadata', $sortableMetadata);
120
        }
121
122
        // ABTODO: facets and extended search might fail
123
        // Add the facets menu
124
        $this->addFacetsMenu();
125
126
        // Get additional fields for extended search.
127
        $this->addExtendedSearch();
128
    }
129
130
    /**
131
     * Adds the current document's UID or parent ID to the search form
132
     *
133
     * @access protected
134
     *
135
     * @return string HTML input fields with current document's UID
136
     */
137
    protected function addCurrentDocument()
138
    {
139
        // Load current list object.
140
        $list = GeneralUtility::makeInstance(DocumentList::class);
141
        // Load current document.
142
        if (
143
            !empty($this->requestData['id'])
144
            && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->requestData['id'])
145
        ) {
146
            $this->loadDocument($this->requestData);
147
            // Get document's UID
148
            if ($this->document) {
149
                $this->view->assign('DOCUMENT_ID', $this->document->getUid());
150
            }
151
        } elseif (!empty($list->metadata['options']['params']['filterquery'])) {
152
            // Get document's UID from search metadata.
153
            // The string may be e.g. "{!join from=uid to=partof}uid:{!join from=uid to=partof}uid:2" OR {!join from=uid to=partof}uid:2 OR uid:2"
154
            // or "collection_faceting:("Some Collection Title")"
155
            foreach ($list->metadata['options']['params']['filterquery'] as $facet) {
156
                if (($lastUidPos = strrpos($facet['query'], 'uid:')) !== false) {
157
                    $facetKeyVal = explode(':', substr($facet['query'], $lastUidPos));
158
                    if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($facetKeyVal[1])) {
159
                        $documentId = (int) $facetKeyVal[1];
160
                    }
161
                }
162
            }
163
            if (!empty($documentId)) {
164
                $this->view->assign('DOCUMENT_ID', $documentId);
165
            }
166
        }
167
    }
168
169
170
    /**
171
     * Adds the current collection's UID to the search form
172
     *
173
     * @access protected
174
     *
175
     * @return string HTML input fields with current document's UID and parent ID
176
     */
177
    protected function addCurrentCollection()
178
    {
179
        // Load current collection.
180
        $list = GeneralUtility::makeInstance(DocumentList::class);
181
        if (
182
            !empty($list->metadata['options']['source'])
183
            && $list->metadata['options']['source'] == 'collection'
184
        ) {
185
            $this->view->assign('COLLECTION_ID', $list->metadata['options']['select']);
186
            // Get collection's UID.
187
        } elseif (!empty($list->metadata['options']['params']['filterquery'])) {
188
            // Get collection's UID from search metadata.
189
            foreach ($list->metadata['options']['params']['filterquery'] as $facet) {
190
                $facetKeyVal = explode(':', $facet['query'], 2);
191
                if (
192
                    $facetKeyVal[0] == 'collection_faceting'
193
                    && !strpos($facetKeyVal[1], '" OR "')
194
                ) {
195
                    $collectionId = Helper::getUidFromIndexName(trim($facetKeyVal[1], '(")'), 'tx_dlf_collections');
196
                }
197
            }
198
            $this->view->assign('COLLECTION_ID', $collectionId);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $collectionId does not seem to be defined for all execution paths leading up to this point.
Loading history...
199
        }
200
    }
201
202
    /**
203
     * Adds the facets menu to the search form
204
     *
205
     * @access protected
206
     *
207
     * @return string HTML output of facets menu
208
     */
209
    protected function addFacetsMenu()
210
    {
211
        // Check for typoscript configuration to prevent fatal error.
212
        if (empty($this->settings['facetsConf'])) {
213
            $this->logger->warning('Incomplete plugin configuration');
214
            return '';
215
        }
216
        // Quit without doing anything if no facets are selected.
217
        if (empty($this->settings['facets']) && empty($this->settings['facetCollections'])) {
218
            return '';
219
        }
220
221
        // Get facets from plugin configuration.
222
        $facets = [];
223
        foreach (GeneralUtility::trimExplode(',', $this->settings['facets'], true) as $facet) {
224
            $facets[$facet . '_faceting'] = Helper::translate($facet, 'tx_dlf_metadata', $this->settings['storagePid']);
225
        }
226
227
        $this->view->assign('facetsMenu', $this->makeFacetsMenuArray($facets));
228
    }
229
230
    /**
231
     * This builds a menu array for HMENU
232
     *
233
     * @access public
234
     *
235
     * @param string $content: The PlugIn content
236
     * @param array $conf: The PlugIn configuration
237
     *
238
     * @return array HMENU array
239
     */
240
    public function makeFacetsMenuArray($facets)
241
    {
242
        $menuArray = [];
243
        // Set default value for facet search.
244
        $search = [
245
            'query' => '*',
246
            'params' => [
247
                'component' => [
248
                    'facetset' => [
249
                        'facet' => []
250
                    ]
251
                ]
252
            ]
253
        ];
254
        // Extract query and filter from last search.
255
        $list = GeneralUtility::makeInstance(DocumentList::class);
256
        if (!empty($list->metadata['options']['source'])) {
257
            if ($list->metadata['options']['source'] == 'search') {
258
                $search['query'] = $list->metadata['options']['select'];
259
            }
260
            $search['params'] = $list->metadata['options']['params'];
261
        }
262
        // Get applicable facets.
263
        $solr = Solr::getInstance($this->settings['solrcore']);
264
        if (!$solr->ready) {
265
            $this->logger->error('Apache Solr not available');
266
            return [];
267
        }
268
        // Set needed parameters for facet search.
269
        if (empty($search['params']['filterquery'])) {
270
            $search['params']['filterquery'] = [];
271
        }
272
273
        foreach (array_keys($facets) as $field) {
274
            $search['params']['component']['facetset']['facet'][] = [
275
                'type' => 'field',
276
                'key' => $field,
277
                'field' => $field,
278
                'limit' => $this->settings['limitFacets'],
279
                'sort' => isset($this->settings['sortingFacets']) ? $this->settings['sortingFacets'] : 'count'
280
            ];
281
        }
282
283
        // Set additional query parameters.
284
        $search['params']['start'] = 0;
285
        $search['params']['rows'] = 0;
286
        // Set query.
287
        $search['params']['query'] = $search['query'];
288
        // Perform search.
289
        $selectQuery = $solr->service->createSelect($search['params']);
290
        $results = $solr->service->select($selectQuery);
291
        $facet = $results->getFacetSet();
292
293
        $facetCollectionArray = [];
294
295
        // replace everything expect numbers and comma
296
        $facetCollections = preg_replace('/[^0-9,]/', '', $this->settings['facetCollections']);
297
298
        if (!empty($facetCollections)) {
299
            $collections = $this->collectionRepository->findCollectionsBySettings(['collections' => $facetCollections]);
300
301
            /** @var Collection $collection */
302
            foreach ($collections as $collection) {
303
                $facetCollectionArray[] = $collection->getIndexName();
304
            }
305
        }
306
307
        // Process results.
308
        if ($facet) {
309
            foreach ($facet as $field => $values) {
310
                $entryArray = [];
311
                $entryArray['title'] = htmlspecialchars($facets[$field]);
312
                $entryArray['count'] = 0;
313
                $entryArray['_OVERRIDE_HREF'] = '';
314
                $entryArray['doNotLinkIt'] = 1;
315
                $entryArray['ITEM_STATE'] = 'NO';
316
                // Count number of facet values.
317
                $i = 0;
318
                foreach ($values as $value => $count) {
319
                    if ($count > 0) {
320
                        // check if facet collection configuration exists
321
                        if (!empty($this->settings['facetCollections'])) {
322
                            if ($field == "collection_faceting" && !in_array($value, $facetCollectionArray)) {
323
                                continue;
324
                            }
325
                        }
326
                        $entryArray['count']++;
327
                        if ($entryArray['ITEM_STATE'] == 'NO') {
328
                            $entryArray['ITEM_STATE'] = 'IFSUB';
329
                        }
330
                        $entryArray['_SUB_MENU'][] = $this->getFacetsMenuEntry($field, $value, $count, $search, $entryArray['ITEM_STATE']);
331
                        if (++$i == $this->settings['limit']) {
332
                            break;
333
                        }
334
                    } else {
335
                        break;
336
                    }
337
                }
338
                $menuArray[] = $entryArray;
339
            }
340
        }
341
        return $menuArray;
342
    }
343
344
    /**
345
     * Creates an array for a HMENU entry of a facet value.
346
     *
347
     * @access protected
348
     *
349
     * @param string $field: The facet's index_name
350
     * @param string $value: The facet's value
351
     * @param int $count: Number of hits for this facet
352
     * @param array $search: The parameters of the current search query
353
     * @param string &$state: The state of the parent item
354
     *
355
     * @return array The array for the facet's menu entry
356
     */
357
    protected function getFacetsMenuEntry($field, $value, $count, $search, &$state)
358
    {
359
        $entryArray = [];
360
        // Translate value.
361
        if ($field == 'owner_faceting') {
362
            // Translate name of holding library.
363
            $entryArray['title'] = htmlspecialchars(Helper::translate($value, 'tx_dlf_libraries', $this->settings['storagePid']));
364
        } elseif ($field == 'type_faceting') {
365
            // Translate document type.
366
            $entryArray['title'] = htmlspecialchars(Helper::translate($value, 'tx_dlf_structures', $this->settings['storagePid']));
367
        } elseif ($field == 'collection_faceting') {
368
            // Translate name of collection.
369
            $entryArray['title'] = htmlspecialchars(Helper::translate($value, 'tx_dlf_collections', $this->settings['storagePid']));
370
        } elseif ($field == 'language_faceting') {
371
            // Translate ISO 639 language code.
372
            $entryArray['title'] = htmlspecialchars(Helper::getLanguageName($value));
373
        } else {
374
            $entryArray['title'] = htmlspecialchars($value);
375
        }
376
        $entryArray['count'] = $count;
377
        $entryArray['doNotLinkIt'] = 0;
378
        // Check if facet is already selected.
379
        $queryColumn = array_column($search['params']['filterquery'], 'query');
380
        $index = array_search($field . ':("' . Solr::escapeQuery($value) . '")', $queryColumn);
381
        if ($index !== false) {
382
            // Facet is selected, thus remove it from filter.
383
            unset($queryColumn[$index]);
384
            $queryColumn = array_values($queryColumn);
385
            $entryArray['ITEM_STATE'] = 'CUR';
386
            $state = 'ACTIFSUB';
387
            //Reset facets
388
            if ($this->settings['resetFacets']) {
389
                //remove ($count) for selected facet in template
390
                $entryArray['count'] = false;
391
                //build link to delete selected facet
392
                $uri = $this->uriBuilder->reset()
393
                    ->setTargetPageUid($GLOBALS['TSFE']->id)
394
                    ->setArguments(['tx_dlf' => ['query' => $search['query'], 'fq' => $queryColumn], 'tx_dlf_search' => ['action' => 'search']])
395
                    ->setAddQueryString(true)
396
                    ->build();
397
                $entryArray['_OVERRIDE_HREF'] = $uri;
398
                $entryArray['title'] = sprintf(LocalizationUtility::translate('search.resetFacet', 'dlf'), $entryArray['title']);
0 ignored issues
show
Bug introduced by
It seems like TYPO3\CMS\Extbase\Utilit...rch.resetFacet', 'dlf') can also be of type null; however, parameter $format of sprintf() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

398
                $entryArray['title'] = sprintf(/** @scrutinizer ignore-type */ LocalizationUtility::translate('search.resetFacet', 'dlf'), $entryArray['title']);
Loading history...
399
            }
400
        } else {
401
            // Facet is not selected, thus add it to filter.
402
            $queryColumn[] = $field . ':("' . Solr::escapeQuery($value) . '")';
403
            $entryArray['ITEM_STATE'] = 'NO';
404
        }
405
        $uri = $this->uriBuilder->reset()
406
            ->setTargetPageUid($GLOBALS['TSFE']->id)
407
            ->setArguments(['tx_dlf' => ['query' => $search['query'], 'fq' => $queryColumn], 'tx_dlf_search' => ['action' => 'search']])
408
            ->setArgumentPrefix('tx_dlf')
409
            ->build();
410
        $entryArray['_OVERRIDE_HREF'] = $uri;
411
412
        return $entryArray;
413
    }
414
415
    /**
416
     * Returns the extended search form and adds the JS files necessary for extended search.
417
     *
418
     * @access protected
419
     *
420
     * @return string The extended search form or an empty string
421
     */
422
    protected function addExtendedSearch()
423
    {
424
        // Quit without doing anything if no fields for extended search are selected.
425
        if (
426
            empty($this->settings['extendedSlotCount'])
427
            || empty($this->settings['extendedFields'])
428
        ) {
429
            return '';
430
        }
431
        // Get operator options.
432
        $operatorOptions = [];
433
        foreach (['AND', 'OR', 'NOT'] as $operator) {
434
            $operatorOptions[$operator] = htmlspecialchars(LocalizationUtility::translate('search.' . $operator, 'dlf'));
0 ignored issues
show
Bug introduced by
It seems like TYPO3\CMS\Extbase\Utilit...h.' . $operator, 'dlf') can also be of type null; however, parameter $string of htmlspecialchars() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

434
            $operatorOptions[$operator] = htmlspecialchars(/** @scrutinizer ignore-type */ LocalizationUtility::translate('search.' . $operator, 'dlf'));
Loading history...
435
        }
436
        // Get field selector options.
437
        $fieldSelectorOptions = [];
438
        $searchFields = GeneralUtility::trimExplode(',', $this->settings['extendedFields'], true);
439
        foreach ($searchFields as $searchField) {
440
            $fieldSelectorOptions[$searchField] = Helper::translate($searchField, 'tx_dlf_metadata', $this->settings['storagePid']);
441
        }
442
        $slotCountArray = [];
443
        for ($i = 0; $i < $this->settings['extendedSlotCount']; $i++) {
444
            $slotCountArray[] = $i;
445
        }
446
447
        $this->view->assign('extendedSlotCount', $slotCountArray);
448
        $this->view->assign('extendedFields', $this->settings['extendedFields']);
449
        $this->view->assign('operators', $operatorOptions);
450
        $this->view->assign('searchFields', $fieldSelectorOptions);
451
    }
452
}
453