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:43
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');
0 ignored issues
show
Unused Code introduced by
The assignment to $searchParams is dead and can be removed.
Loading history...
61
62
        // output is done by main action
63
//        $this->forward('main', null, null, ['searchParameter' => $searchParams]);
64
//        $this->forward('main', 'ListView', null, ['searchParameter' => $searchParams]);
65
    }
66
67
    /**
68
     * Main action
69
     *
70
     * @return void
71
     */
72
    public function mainAction()
73
    {
74
        // Quit without doing anything if required variables are not set.
75
        if (empty($this->settings['solrcore'])) {
76
            $this->logger->warning('Incomplete plugin configuration');
77
            return;
78
        }
79
80
        // if search was triggered, get search parameters from POST variables
81
        $searchParams = $this->getParametersSafely('searchParameter');
82
83
        // Pagination of Results: Pass the currentPage to the fluid template to calculate current index of search result.
84
        $widgetPage = $this->getParametersSafely('@widget_0');
85
        if (empty($widgetPage)) {
86
            $widgetPage = ['currentPage' => 1];
87
        }
88
89
        // If a targetPid is given, the results will be shown by ListView on the target page.
90
        if (!empty($this->settings['targetPid']) && !empty($searchParams)) {
91
            $this->redirect('main', 'ListView', null,
92
                [
93
                    'searchParameter' => $searchParams,
94
                    'widgetPage' => $widgetPage,
95
                    'solrcore' => $this->settings['solrcore']
96
                ], $this->settings['targetPid']
97
            );
98
        }
99
100
        // get results from search
101
        // find all documents from Solr
102
        $solrResults = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $solrResults is dead and can be removed.
Loading history...
103
        if (is_array($searchParams) && !empty($searchParams)) {
104
           $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

104
           $solrResults = $this->documentRepository->findSolrByCollection(/** @scrutinizer ignore-type */ '', $this->settings, $searchParams, $listedMetadata);
Loading history...
Comprehensibility Best Practice introduced by
The variable $listedMetadata seems to be never defined.
Loading history...
105
106
           // get all sortable metadata records
107
            $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

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

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

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

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