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.
Completed
Push — master ( 90c912...99a750 )
by Sebastian
14s queued 11s
created

Collection   D

Complexity

Total Complexity 58

Size/Duplication

Total Lines 414
Duplicated Lines 0 %

Importance

Changes 11
Bugs 0 Features 0
Metric Value
wmc 58
eloc 263
c 11
b 0
f 0
dl 0
loc 414
rs 4.5599

3 Methods

Rating   Name   Duplication   Size   Complexity  
A main() 0 20 3
F showCollectionList() 0 177 31
F showSingleCollection() 0 175 24

How to fix   Complexity   

Complex Class

Complex classes like Collection often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Collection, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * (c) Kitodo. Key to digital objects e.V. <[email protected]>
5
 *
6
 * This file is part of the Kitodo and TYPO3 projects.
7
 *
8
 * @license GNU General Public License version 3 or later.
9
 * For the full copyright and license information, please read the
10
 * LICENSE.txt file that was distributed with this source code.
11
 */
12
13
namespace Kitodo\Dlf\Plugin;
14
15
use Kitodo\Dlf\Common\DocumentList;
16
use Kitodo\Dlf\Common\Helper;
17
use Kitodo\Dlf\Common\Solr;
18
use TYPO3\CMS\Core\Database\ConnectionPool;
19
use TYPO3\CMS\Core\Utility\GeneralUtility;
20
21
/**
22
 * Plugin 'Collection' for the 'dlf' extension
23
 *
24
 * @author Sebastian Meyer <[email protected]>
25
 * @package TYPO3
26
 * @subpackage dlf
27
 * @access public
28
 */
29
class Collection extends \Kitodo\Dlf\Common\AbstractPlugin
30
{
31
    public $scriptRelPath = 'Classes/Plugin/Collection.php';
32
33
    /**
34
     * This holds the hook objects
35
     *
36
     * @var array
37
     * @access protected
38
     */
39
    protected $hookObjects = [];
40
41
    /**
42
     * The main method of the PlugIn
43
     *
44
     * @access public
45
     *
46
     * @param string $content: The PlugIn content
47
     * @param array $conf: The PlugIn configuration
48
     *
49
     * @return string The content that is displayed on the website
50
     */
51
    public function main($content, $conf)
52
    {
53
        $this->init($conf);
54
        // Turn cache on.
55
        $this->setCache(true);
56
        // Quit without doing anything if required configuration variables are not set.
57
        if (empty($this->conf['pages'])) {
58
            Helper::devLog('Incomplete plugin configuration', DEVLOG_SEVERITY_WARNING);
59
            return $content;
60
        }
61
        // Load template file.
62
        $this->getTemplate();
63
        // Get hook objects.
64
        $this->hookObjects = Helper::getHookObjects($this->scriptRelPath);
65
        if (!empty($this->piVars['collection'])) {
66
            $this->showSingleCollection(intval($this->piVars['collection']));
67
        } else {
68
            $content .= $this->showCollectionList();
69
        }
70
        return $this->pi_wrapInBaseClass($content);
71
    }
72
73
    /**
74
     * Builds a collection list
75
     *
76
     * @access protected
77
     *
78
     * @return string The list of collections ready to output
79
     */
80
    protected function showCollectionList()
81
    {
82
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
83
            ->getQueryBuilderForTable('tx_dlf_collections');
84
85
        $selectedCollections = $queryBuilder->expr()->neq('tx_dlf_collections.uid', 0);
86
        $orderBy = 'tx_dlf_collections.label';
87
        $showUserDefinedColls = '';
88
        // Handle collections set by configuration.
89
        if ($this->conf['collections']) {
90
            if (
91
                count(explode(',', $this->conf['collections'])) == 1
92
                && empty($this->conf['dont_show_single'])
93
            ) {
94
                $this->showSingleCollection(intval(trim($this->conf['collections'], ' ,')));
95
            }
96
            $selectedCollections = $queryBuilder->expr()->in('tx_dlf_collections.uid', implode(',', GeneralUtility::intExplode(',', $this->conf['collections'])));
97
        }
98
        // Should user-defined collections be shown?
99
        if (empty($this->conf['show_userdefined'])) {
100
            $showUserDefinedColls = $queryBuilder->expr()->eq('tx_dlf_collections.fe_cruser_id', 0);
101
        } elseif ($this->conf['show_userdefined'] > 0) {
102
            if (!empty($GLOBALS['TSFE']->fe_user->user['uid'])) {
103
                $showUserDefinedColls = $queryBuilder->expr()->eq('tx_dlf_collections.fe_cruser_id', intval($GLOBALS['TSFE']->fe_user->user['uid']));
104
            } else {
105
                $showUserDefinedColls = $queryBuilder->expr()->neq('tx_dlf_collections.fe_cruser_id', 0);
106
            }
107
        }
108
109
        // Get collections.
110
        $queryBuilder
111
            ->select(
112
                'tx_dlf_collections.uid AS uid', // required by getRecordOverlay()
113
                'tx_dlf_collections.pid AS pid', // required by getRecordOverlay()
114
                'tx_dlf_collections.sys_language_uid AS sys_language_uid', // required by getRecordOverlay()
115
                'tx_dlf_collections.index_name AS index_name',
116
                'tx_dlf_collections.index_search as index_query',
117
                'tx_dlf_collections.label AS label',
118
                'tx_dlf_collections.thumbnail AS thumbnail',
119
                'tx_dlf_collections.description AS description',
120
                'tx_dlf_collections.priority AS priority'
121
            )
122
            ->from('tx_dlf_collections')
123
            ->where(
124
                $selectedCollections,
125
                $showUserDefinedColls,
126
                $queryBuilder->expr()->eq('tx_dlf_collections.pid', intval($this->conf['pages'])),
127
                $queryBuilder->expr()->andX(
128
                    $queryBuilder->expr()->orX(
129
                        $queryBuilder->expr()->in('tx_dlf_collections.sys_language_uid', [-1, 0]),
130
                        $queryBuilder->expr()->eq('tx_dlf_collections.sys_language_uid', $GLOBALS['TSFE']->sys_language_uid)
131
                    ),
132
                    $queryBuilder->expr()->eq('tx_dlf_collections.l18n_parent', 0)
133
                )
134
            )
135
            ->orderBy($orderBy);
136
137
        $result = $queryBuilder->execute();
138
        $count = $queryBuilder->count('uid')->execute()->fetchColumn(0);
139
        $content = '';
140
        if ($count == 1 && empty($this->conf['dont_show_single'])) {
141
            $resArray = $result->fetch();
142
            $this->showSingleCollection(intval($resArray['uid']));
143
        }
144
        $solr = Solr::getInstance($this->conf['solrcore']);
145
        if (!$solr->ready) {
146
            Helper::devLog('Apache Solr not available', DEVLOG_SEVERITY_ERROR);
147
            return $content;
148
        }
149
        // We only care about the UID and partOf in the results and want them sorted
150
        $params['fields'] = 'uid,partof';
151
        $params['sort'] = ['uid' => 'asc'];
152
        $collections = [];
153
154
        // Get language overlay if on alterative website language.
155
        $pageRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Page\PageRepository::class);
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Frontend\Page\PageRepository was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
156
        while ($collectionData = $result->fetch()) {
157
            if ($collectionData['sys_language_uid'] != $GLOBALS['TSFE']->sys_language_content) {
158
                $collections[$collectionData['uid']] = $pageRepository->getRecordOverlay('tx_dlf_collections', $collectionData, $GLOBALS['TSFE']->sys_language_content, $GLOBALS['TSFE']->sys_language_contentOL);
159
                // keep the index_name of the default language
160
                $collections[$collectionData['uid']]['index_name'] = $collectionData['index_name'];
161
            } else {
162
                $collections[$collectionData['uid']] = $collectionData;
163
            }
164
        }
165
        // Sort collections according to flexform configuration
166
        if ($this->conf['collections']) {
167
            $sortedCollections = [];
168
            foreach (GeneralUtility::intExplode(',', $this->conf['collections']) as $uid) {
169
                $sortedCollections[$uid] = $collections[$uid];
170
            }
171
            $collections = $sortedCollections;
172
        }
173
        $markerArray = [];
174
        // Process results.
175
        foreach ($collections as $collection) {
176
            $solr_query = '';
177
            if ($collection['index_query'] != '') {
178
                $solr_query .= '(' . $collection['index_query'] . ')';
179
            } else {
180
                $solr_query .= 'collection:("' . $collection['index_name'] . '")';
181
            }
182
            $partOfNothing = $solr->search_raw($solr_query . ' AND partof:0 AND toplevel:true', $params);
183
            $partOfSomething = $solr->search_raw($solr_query . ' AND NOT partof:0 AND toplevel:true', $params);
184
            // Titles are all documents that are "root" elements i.e. partof == 0
185
            $collection['titles'] = [];
186
            foreach ($partOfNothing as $doc) {
187
                $collection['titles'][$doc->uid] = $doc->uid;
188
            }
189
            // Volumes are documents that are both
190
            // a) "leaf" elements i.e. partof != 0
191
            // b) "root" elements that are not referenced by other documents ("root" elements that have no descendants)
192
            $collection['volumes'] = $collection['titles'];
193
            foreach ($partOfSomething as $doc) {
194
                $collection['volumes'][$doc->uid] = $doc->uid;
195
                // If a document is referenced via partof, it’s not a volume anymore.
196
                unset($collection['volumes'][$doc->partof]);
197
            }
198
            // Generate random but unique array key taking priority into account.
199
            do {
200
                $_key = ($collection['priority'] * 1000) + mt_rand(0, 1000);
201
            } while (!empty($markerArray[$_key]));
202
            // Merge plugin variables with new set of values.
203
            $additionalParams = ['collection' => $collection['uid']];
204
            if (is_array($this->piVars)) {
205
                $piVars = $this->piVars;
206
                unset($piVars['DATA']);
207
                $additionalParams = Helper::mergeRecursiveWithOverrule($piVars, $additionalParams);
208
            }
209
            // Build typolink configuration array.
210
            $conf = [
211
                'useCacheHash' => 1,
212
                'parameter' => $GLOBALS['TSFE']->id,
213
                'forceAbsoluteUrl' => !empty($this->conf['forceAbsoluteUrl']) ? 1 : 0,
214
                'forceAbsoluteUrl.' => ['scheme' => !empty($this->conf['forceAbsoluteUrl']) && !empty($this->conf['forceAbsoluteUrlHttps']) ? 'https' : 'http'],
215
                'additionalParams' => \TYPO3\CMS\Core\Utility\GeneralUtility::implodeArrayForUrl($this->prefixId, $additionalParams, '', true, false)
216
            ];
217
            // Link collection's title to list view.
218
            $markerArray[$_key]['###TITLE###'] = $this->cObj->typoLink(htmlspecialchars($collection['label']), $conf);
219
            // Add feed link if applicable.
220
            if (!empty($this->conf['targetFeed'])) {
221
                $img = '<img src="' . \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($this->extKey)) . 'Resources/Public/Icons/txdlffeeds.png" alt="' . htmlspecialchars($this->pi_getLL('feedAlt', '')) . '" title="' . htmlspecialchars($this->pi_getLL('feedTitle', '')) . '" />';
222
                $markerArray[$_key]['###FEED###'] = $this->pi_linkTP($img, [$this->prefixId => ['collection' => $collection['uid']]], false, $this->conf['targetFeed']);
223
            } else {
224
                $markerArray[$_key]['###FEED###'] = '';
225
            }
226
            // Add thumbnail.
227
            if (!empty($collection['thumbnail'])) {
228
                $markerArray[$_key]['###THUMBNAIL###'] = '<img alt="" title="' . htmlspecialchars($collection['label']) . '" src="' . $collection['thumbnail'] . '" />';
229
            } else {
230
                $markerArray[$_key]['###THUMBNAIL###'] = '';
231
            }
232
            // Add description.
233
            $markerArray[$_key]['###DESCRIPTION###'] = $this->pi_RTEcssText($collection['description']);
234
            // Build statistic's output.
235
            $labelTitles = $this->pi_getLL((count($collection['titles']) > 1 ? 'titles' : 'title'), '');
236
            $markerArray[$_key]['###COUNT_TITLES###'] = htmlspecialchars(count($collection['titles']) . $labelTitles);
237
            $labelVolumes = $this->pi_getLL((count($collection['volumes']) > 1 ? 'volumes' : 'volume'), '');
238
            $markerArray[$_key]['###COUNT_VOLUMES###'] = htmlspecialchars(count($collection['volumes']) . $labelVolumes);
239
        }
240
        // Randomize sorting?
241
        if (!empty($this->conf['randomize'])) {
242
            ksort($markerArray, SORT_NUMERIC);
243
            // Don't cache the output.
244
            $this->setCache(false);
245
        }
246
        $entry = $this->templateService->getSubpart($this->template, '###ENTRY###');
247
        foreach ($markerArray as $marker) {
248
            $content .= $this->templateService->substituteMarkerArray($entry, $marker);
249
        }
250
        // Hook for getting custom collection hierarchies/subentries (requested by SBB).
251
        foreach ($this->hookObjects as $hookObj) {
252
            if (method_exists($hookObj, 'showCollectionList_getCustomCollectionList')) {
253
                $hookObj->showCollectionList_getCustomCollectionList($this, $this->conf['templateFile'], $content, $markerArray);
254
            }
255
        }
256
        return $this->templateService->substituteSubpart($this->template, '###ENTRY###', $content, true);
257
    }
258
259
    /**
260
     * Builds a collection's list
261
     *
262
     * @access protected
263
     *
264
     * @param int $id: The collection's UID
265
     *
266
     * @return void
267
     */
268
    protected function showSingleCollection($id)
269
    {
270
        $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
271
        $queryBuilder = $connectionPool->getQueryBuilderForTable('tx_dlf_collections');
272
273
        $additionalWhere = '';
274
        // Should user-defined collections be shown?
275
        if (empty($this->conf['show_userdefined'])) {
276
            $additionalWhere = $queryBuilder->expr()->eq('tx_dlf_collections.fe_cruser_id', 0);
277
        } elseif ($this->conf['show_userdefined'] > 0) {
278
            $additionalWhere = $queryBuilder->expr()->neq('tx_dlf_collections.fe_cruser_id', 0);
279
        }
280
281
        // Get collection information from DB
282
        $collection = $queryBuilder
283
            ->select(
284
                'tx_dlf_collections.uid AS uid', // required by getRecordOverlay()
285
                'tx_dlf_collections.pid AS pid', // required by getRecordOverlay()
286
                'tx_dlf_collections.sys_language_uid AS sys_language_uid', // required by getRecordOverlay()
287
                'tx_dlf_collections.index_name AS index_name',
288
                'tx_dlf_collections.index_search as index_search',
289
                'tx_dlf_collections.label AS label',
290
                'tx_dlf_collections.description AS description',
291
                'tx_dlf_collections.thumbnail AS thumbnail',
292
                'tx_dlf_collections.fe_cruser_id'
293
            )
294
            ->from('tx_dlf_collections')
295
            ->where(
296
                $queryBuilder->expr()->eq('tx_dlf_collections.pid', intval($this->conf['pages'])),
297
                $queryBuilder->expr()->eq('tx_dlf_collections.uid', intval($id)),
298
                $additionalWhere,
299
                $queryBuilder->expr()->andX(
300
                    $queryBuilder->expr()->orX(
301
                        $queryBuilder->expr()->in('tx_dlf_collections.sys_language_uid', [-1, 0]),
302
                        $queryBuilder->expr()->eq('tx_dlf_collections.sys_language_uid', $GLOBALS['TSFE']->sys_language_uid)
303
                    ),
304
                    $queryBuilder->expr()->eq('tx_dlf_collections.l18n_parent', 0)
305
                ),
306
                Helper::whereExpression('tx_dlf_collections')
307
            )
308
            ->setMaxResults(1)
309
            ->execute();
310
311
        // Get language overlay if on alterative website language.
312
        $pageRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Page\PageRepository::class);
313
        if ($resArray = $collection->fetch()) {
314
            if ($resArray['sys_language_uid'] != $GLOBALS['TSFE']->sys_language_content) {
315
                $collectionData = $pageRepository->getRecordOverlay('tx_dlf_collections', $resArray, $GLOBALS['TSFE']->sys_language_content, $GLOBALS['TSFE']->sys_language_contentOL);
316
                // keep the index_name of the default language
317
                $collectionData['index_name'] = $resArray['index_name'];
318
            } else {
319
                $collectionData = $resArray;
320
            }
321
        } else {
322
            Helper::devLog('No collection with UID ' . $id . ' found.', DEVLOG_SEVERITY_WARNING);
323
            return;
324
        }
325
        // Fetch corresponding document UIDs from Solr.
326
        if ($collectionData['index_search'] != '') {
327
            $solr_query = '(' . $collectionData['index_search'] . ')';
328
        } else {
329
            $solr_query = 'collection:("' . $collectionData['index_name'] . '") AND toplevel:true';
330
        }
331
        $solr = Solr::getInstance($this->conf['solrcore']);
332
        if (!$solr->ready) {
333
            Helper::devLog('Apache Solr not available', DEVLOG_SEVERITY_ERROR);
334
            return;
335
        }
336
        $params['fields'] = 'uid';
337
        $params['sort'] = ['uid' => 'asc'];
338
        $solrResult = $solr->search_raw($solr_query, $params);
339
        // Initialize array
340
        $documentSet = [];
341
        foreach ($solrResult as $doc) {
342
            if ($doc->uid) {
343
                $documentSet[] = $doc->uid;
344
            }
345
        }
346
        $documentSet = array_unique($documentSet);
347
        $queryBuilder = $connectionPool->getQueryBuilderForTable('tx_dlf_documents');
348
        // Fetch document info for UIDs in $documentSet from DB
349
        $documents = $queryBuilder
350
            ->select(
351
                'tx_dlf_documents.uid AS uid',
352
                'tx_dlf_documents.metadata_sorting AS metadata_sorting',
353
                'tx_dlf_documents.volume_sorting AS volume_sorting',
354
                'tx_dlf_documents.partof AS partof'
355
            )
356
            ->from('tx_dlf_documents')
357
            ->where(
358
                $queryBuilder->expr()->eq('tx_dlf_documents.pid', intval($this->conf['pages'])),
359
                $queryBuilder->expr()->in('tx_dlf_documents.uid', $documentSet),
360
                Helper::whereExpression('tx_dlf_documents')
361
            )
362
            ->execute();
363
364
        $toplevel = [];
365
        $subparts = [];
366
        $listMetadata = [];
367
        // Process results.
368
        while ($resArray = $documents->fetch()) {
369
            if (empty($listMetadata)) {
370
                $listMetadata = [
371
                    'label' => htmlspecialchars($collectionData['label']),
372
                    'description' => $this->pi_RTEcssText($collectionData['description']),
373
                    'thumbnail' => htmlspecialchars($collectionData['thumbnail']),
374
                    'options' => [
375
                        'source' => 'collection',
376
                        'select' => $id,
377
                        'userid' => $collectionData['userid'],
378
                        'params' => ['filterquery' => [['query' => 'collection_faceting:("' . $collectionData['index_name'] . '")']]],
379
                        'core' => '',
380
                        'pid' => $this->conf['pages'],
381
                        'order' => 'title',
382
                        'order.asc' => true
383
                    ]
384
                ];
385
            }
386
            // Prepare document's metadata for sorting.
387
            $sorting = unserialize($resArray['metadata_sorting']);
388
            if (!empty($sorting['type']) && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($sorting['type'])) {
389
                $sorting['type'] = Helper::getIndexNameFromUid($sorting['type'], 'tx_dlf_structures', $this->conf['pages']);
390
            }
391
            if (!empty($sorting['owner']) && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($sorting['owner'])) {
392
                $sorting['owner'] = Helper::getIndexNameFromUid($sorting['owner'], 'tx_dlf_libraries', $this->conf['pages']);
393
            }
394
            if (!empty($sorting['collection']) && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($sorting['collection'])) {
395
                $sorting['collection'] = Helper::getIndexNameFromUid($sorting['collection'], 'tx_dlf_collections', $this->conf['pages']);
396
            }
397
            // Split toplevel documents from volumes.
398
            if ($resArray['partof'] == 0) {
399
                $toplevel[$resArray['uid']] = [
400
                    'u' => $resArray['uid'],
401
                    'h' => '',
402
                    's' => $sorting,
403
                    'p' => []
404
                ];
405
            } else {
406
                $subparts[$resArray['partof']][$resArray['volume_sorting']] = [
407
                    'u' => $resArray['uid'],
408
                    'h' => '',
409
                    's' => $sorting,
410
                    'p' => []
411
                ];
412
            }
413
        }
414
        // Add volumes to the corresponding toplevel documents.
415
        foreach ($subparts as $partof => $parts) {
416
            ksort($parts);
417
            foreach ($parts as $part) {
418
                if (!empty($toplevel[$partof])) {
419
                    $toplevel[$partof]['p'][] = ['u' => $part['u']];
420
                } else {
421
                    $toplevel[$part['u']] = $part;
422
                }
423
            }
424
        }
425
        // Save list of documents.
426
        $list = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(DocumentList::class);
427
        $list->reset();
428
        $list->add(array_values($toplevel));
429
        $listMetadata['options']['numberOfToplevelHits'] = count($list);
430
        $list->metadata = $listMetadata;
431
        $list->sort('title');
432
        $list->save();
433
        // Clean output buffer.
434
        ob_end_clean();
435
        // Send headers.
436
        $linkConf = [
437
            'parameter' => $this->conf['targetPid'],
438
            'forceAbsoluteUrl' => !empty($this->conf['forceAbsoluteUrl']) ? 1 : 0,
439
            'forceAbsoluteUrl.' => ['scheme' => !empty($this->conf['forceAbsoluteUrl']) && !empty($this->conf['forceAbsoluteUrlHttps']) ? 'https' : 'http']
440
        ];
441
        header('Location: ' . \TYPO3\CMS\Core\Utility\GeneralUtility::locationHeaderUrl($this->cObj->typoLink_URL($linkConf)));
442
        exit;
443
    }
444
}
445