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
02:32
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
        // get all sortable metadata records
83
        $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

83
        /** @scrutinizer ignore-call */ 
84
        $sortableMetadata = $this->metadataRepository->findByIsSortable(true);
Loading history...
84
85
        // get all metadata records to be shown in results
86
        $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

86
        /** @scrutinizer ignore-call */ 
87
        $listedMetadata = $this->metadataRepository->findByIsListed(true);
Loading history...
87
88
        // get results from search
89
        // find all documents from Solr
90
        $solrResults = [];
91
        if (is_array($searchParams) && !empty($searchParams)) {
92
            $solrResults = $this->documentRepository->findSolrByCollection('', $this->settings, $searchParams, $listedMetadata);
0 ignored issues
show
Bug introduced by
'' of type string is incompatible with the type TYPO3\CMS\Extbase\Persistence\Generic\QueryResult expected by parameter $collections 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

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

386
                $entryArray['title'] = sprintf(/** @scrutinizer ignore-type */ LocalizationUtility::translate('search.resetFacet', 'dlf'), $entryArray['title']);
Loading history...
387
            }
388
        } else {
389
            // Facet is not selected, thus add it to filter.
390
            $queryColumn[] = $field . ':("' . Solr::escapeQuery($value) . '")';
391
            $entryArray['ITEM_STATE'] = 'NO';
392
        }
393
        $uri = $this->uriBuilder->reset()
394
            ->setTargetPageUid($GLOBALS['TSFE']->id)
395
            ->setArguments(['tx_dlf' => ['query' => $search['query'], 'fq' => $queryColumn], 'tx_dlf_search' => ['action' => 'search']])
396
            ->setArgumentPrefix('tx_dlf')
397
            ->build();
398
        $entryArray['_OVERRIDE_HREF'] = $uri;
399
400
        return $entryArray;
401
    }
402
403
    /**
404
     * Returns the extended search form and adds the JS files necessary for extended search.
405
     *
406
     * @access protected
407
     *
408
     * @return string The extended search form or an empty string
409
     */
410
    protected function addExtendedSearch()
411
    {
412
        // Quit without doing anything if no fields for extended search are selected.
413
        if (
414
            empty($this->settings['extendedSlotCount'])
415
            || empty($this->settings['extendedFields'])
416
        ) {
417
            return '';
418
        }
419
        // Get operator options.
420
        $operatorOptions = [];
421
        foreach (['AND', 'OR', 'NOT'] as $operator) {
422
            $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

422
            $operatorOptions[$operator] = htmlspecialchars(/** @scrutinizer ignore-type */ LocalizationUtility::translate('search.' . $operator, 'dlf'));
Loading history...
423
        }
424
        // Get field selector options.
425
        $fieldSelectorOptions = [];
426
        $searchFields = GeneralUtility::trimExplode(',', $this->settings['extendedFields'], true);
427
        foreach ($searchFields as $searchField) {
428
            $fieldSelectorOptions[$searchField] = Helper::translate($searchField, 'tx_dlf_metadata', $this->settings['storagePid']);
429
        }
430
        $slotCountArray = [];
431
        for ($i = 0; $i < $this->settings['extendedSlotCount']; $i++) {
432
            $slotCountArray[] = $i;
433
        }
434
435
        $this->view->assign('extendedSlotCount', $slotCountArray);
436
        $this->view->assign('extendedFields', $this->settings['extendedFields']);
437
        $this->view->assign('operators', $operatorOptions);
438
        $this->view->assign('searchFields', $fieldSelectorOptions);
439
    }
440
}
441