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 ( c2a726...77fa83 )
by Sebastian
18s queued 13s
created

Collection   C

Complexity

Total Complexity 57

Size/Duplication

Total Lines 406
Duplicated Lines 0 %

Importance

Changes 10
Bugs 0 Features 0
Metric Value
wmc 57
eloc 258
c 10
b 0
f 0
dl 0
loc 406
rs 5.04

3 Methods

Rating   Name   Duplication   Size   Complexity  
A main() 0 20 3
F showCollectionList() 0 171 30
F showSingleCollection() 0 173 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
        // We only care about the UID and partOf in the results and want them sorted
146
        $params['fields'] = 'uid,partof';
147
        $params['sort'] = ['uid' => 'asc'];
148
        $collections = [];
149
150
        // Get language overlay if on alterative website language.
151
        $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...
152
        while ($collectionData = $result->fetch()) {
153
            if ($collectionData['sys_language_uid'] != $GLOBALS['TSFE']->sys_language_content) {
154
                $collections[$collectionData['uid']] = $pageRepository->getRecordOverlay('tx_dlf_collections', $collectionData, $GLOBALS['TSFE']->sys_language_content, $GLOBALS['TSFE']->sys_language_contentOL);
155
            } else {
156
                $collections[$collectionData['uid']] = $collectionData;
157
            }
158
        }
159
        // Sort collections according to flexform configuration
160
        if ($this->conf['collections']) {
161
            $sortedCollections = [];
162
            foreach (GeneralUtility::intExplode(',', $this->conf['collections']) as $uid) {
163
                $sortedCollections[$uid] = $collections[$uid];
164
            }
165
            $collections = $sortedCollections;
166
        }
167
        $markerArray = [];
168
        // Process results.
169
        foreach ($collections as $collection) {
170
            $solr_query = '';
171
            if ($collection['index_query'] != '') {
172
                $solr_query .= '(' . $collection['index_query'] . ')';
173
            } else {
174
                $solr_query .= 'collection:("' . $collection['index_name'] . '")';
175
            }
176
            $partOfNothing = $solr->search_raw($solr_query . ' AND partof:0 AND toplevel:true', $params);
177
            $partOfSomething = $solr->search_raw($solr_query . ' AND NOT partof:0 AND toplevel:true', $params);
178
            // Titles are all documents that are "root" elements i.e. partof == 0
179
            $collection['titles'] = [];
180
            foreach ($partOfNothing as $doc) {
181
                $collection['titles'][$doc->uid] = $doc->uid;
182
            }
183
            // Volumes are documents that are both
184
            // a) "leaf" elements i.e. partof != 0
185
            // b) "root" elements that are not referenced by other documents ("root" elements that have no descendants)
186
            $collection['volumes'] = $collection['titles'];
187
            foreach ($partOfSomething as $doc) {
188
                $collection['volumes'][$doc->uid] = $doc->uid;
189
                // If a document is referenced via partof, it’s not a volume anymore.
190
                unset($collection['volumes'][$doc->partof]);
191
            }
192
            // Generate random but unique array key taking priority into account.
193
            do {
194
                $_key = ($collection['priority'] * 1000) + mt_rand(0, 1000);
195
            } while (!empty($markerArray[$_key]));
196
            // Merge plugin variables with new set of values.
197
            $additionalParams = ['collection' => $collection['uid']];
198
            if (is_array($this->piVars)) {
199
                $piVars = $this->piVars;
200
                unset($piVars['DATA']);
201
                $additionalParams = Helper::mergeRecursiveWithOverrule($piVars, $additionalParams);
202
            }
203
            // Build typolink configuration array.
204
            $conf = [
205
                'useCacheHash' => 1,
206
                'parameter' => $GLOBALS['TSFE']->id,
207
                'forceAbsoluteUrl' => !empty($this->conf['forceAbsoluteUrl']) ? 1 : 0,
208
                'forceAbsoluteUrl.' => ['scheme' => !empty($this->conf['forceAbsoluteUrl']) && !empty($this->conf['forceAbsoluteUrlHttps']) ? 'https' : 'http'],
209
                'additionalParams' => \TYPO3\CMS\Core\Utility\GeneralUtility::implodeArrayForUrl($this->prefixId, $additionalParams, '', true, false)
210
            ];
211
            // Link collection's title to list view.
212
            $markerArray[$_key]['###TITLE###'] = $this->cObj->typoLink(htmlspecialchars($collection['label']), $conf);
213
            // Add feed link if applicable.
214
            if (!empty($this->conf['targetFeed'])) {
215
                $img = '<img src="' . \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::siteRelPath($this->extKey) . 'Resources/Public/Icons/txdlffeeds.png" alt="' . $this->pi_getLL('feedAlt', '', true) . '" title="' . $this->pi_getLL('feedTitle', '', true) . '" />';
0 ignored issues
show
Deprecated Code introduced by
The function TYPO3\CMS\Core\Utility\E...tUtility::siteRelPath() has been deprecated: use extPath() or GeneralUtility::getFileAbsFileName() together with PathUtility::getAbsoluteWebPath() instead. ( Ignorable by Annotation )

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

215
                $img = '<img src="' . /** @scrutinizer ignore-deprecated */ \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::siteRelPath($this->extKey) . 'Resources/Public/Icons/txdlffeeds.png" alt="' . $this->pi_getLL('feedAlt', '', true) . '" title="' . $this->pi_getLL('feedTitle', '', true) . '" />';

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
216
                $markerArray[$_key]['###FEED###'] = $this->pi_linkTP($img, [$this->prefixId => ['collection' => $collection['uid']]], false, $this->conf['targetFeed']);
217
            } else {
218
                $markerArray[$_key]['###FEED###'] = '';
219
            }
220
            // Add thumbnail.
221
            if (!empty($collection['thumbnail'])) {
222
                $markerArray[$_key]['###THUMBNAIL###'] = '<img alt="" title="' . htmlspecialchars($collection['label']) . '" src="' . $collection['thumbnail'] . '" />';
223
            } else {
224
                $markerArray[$_key]['###THUMBNAIL###'] = '';
225
            }
226
            // Add description.
227
            $markerArray[$_key]['###DESCRIPTION###'] = $this->pi_RTEcssText($collection['description']);
228
            // Build statistic's output.
229
            $labelTitles = $this->pi_getLL((count($collection['titles']) > 1 ? 'titles' : 'title'), '', false);
230
            $markerArray[$_key]['###COUNT_TITLES###'] = htmlspecialchars(count($collection['titles']) . $labelTitles);
231
            $labelVolumes = $this->pi_getLL((count($collection['volumes']) > 1 ? 'volumes' : 'volume'), '', false);
232
            $markerArray[$_key]['###COUNT_VOLUMES###'] = htmlspecialchars(count($collection['volumes']) . $labelVolumes);
233
        }
234
        // Randomize sorting?
235
        if (!empty($this->conf['randomize'])) {
236
            ksort($markerArray, SORT_NUMERIC);
237
            // Don't cache the output.
238
            $this->setCache(false);
239
        }
240
        $entry = $this->templateService->getSubpart($this->template, '###ENTRY###');
241
        foreach ($markerArray as $marker) {
242
            $content .= $this->templateService->substituteMarkerArray($entry, $marker);
243
        }
244
        // Hook for getting custom collection hierarchies/subentries (requested by SBB).
245
        foreach ($this->hookObjects as $hookObj) {
246
            if (method_exists($hookObj, 'showCollectionList_getCustomCollectionList')) {
247
                $hookObj->showCollectionList_getCustomCollectionList($this, $this->conf['templateFile'], $content, $markerArray);
248
            }
249
        }
250
        return $this->templateService->substituteSubpart($this->template, '###ENTRY###', $content, true);
251
    }
252
253
    /**
254
     * Builds a collection's list
255
     *
256
     * @access protected
257
     *
258
     * @param int $id: The collection's UID
259
     *
260
     * @return void
261
     */
262
    protected function showSingleCollection($id)
263
    {
264
        $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
265
        $queryBuilder = $connectionPool->getQueryBuilderForTable('tx_dlf_collections');
266
267
        $additionalWhere = '';
268
        // Should user-defined collections be shown?
269
        if (empty($this->conf['show_userdefined'])) {
270
            $additionalWhere = $queryBuilder->expr()->eq('tx_dlf_collections.fe_cruser_id', 0);
271
        } elseif ($this->conf['show_userdefined'] > 0) {
272
            $additionalWhere = $queryBuilder->expr()->neq('tx_dlf_collections.fe_cruser_id', 0);
273
        }
274
275
        // Get collection information from DB
276
        $collection = $queryBuilder
277
            ->select(
278
                'tx_dlf_collections.uid AS uid', // required by getRecordOverlay()
279
                'tx_dlf_collections.pid AS pid', // required by getRecordOverlay()
280
                'tx_dlf_collections.sys_language_uid AS sys_language_uid', // required by getRecordOverlay()
281
                'tx_dlf_collections.index_name AS index_name',
282
                'tx_dlf_collections.index_search as index_search',
283
                'tx_dlf_collections.label AS label',
284
                'tx_dlf_collections.description AS description',
285
                'tx_dlf_collections.thumbnail AS thumbnail',
286
                'tx_dlf_collections.fe_cruser_id'
287
            )
288
            ->from('tx_dlf_collections')
289
            ->where(
290
                $queryBuilder->expr()->eq('tx_dlf_collections.pid', intval($this->conf['pages'])),
291
                $queryBuilder->expr()->eq('tx_dlf_collections.uid', intval($id)),
292
                $additionalWhere,
293
                $queryBuilder->expr()->andX(
294
                    $queryBuilder->expr()->orX(
295
                        $queryBuilder->expr()->in('tx_dlf_collections.sys_language_uid', [-1, 0]),
296
                        $queryBuilder->expr()->eq('tx_dlf_collections.sys_language_uid', $GLOBALS['TSFE']->sys_language_uid)
297
                    ),
298
                    $queryBuilder->expr()->eq('tx_dlf_collections.l18n_parent', 0)
299
                ),
300
                Helper::whereExpression('tx_dlf_collections')
301
            )
302
            ->setMaxResults(1)
303
            ->execute();
304
305
        // Get language overlay if on alterative website language.
306
        $pageRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Page\PageRepository::class);
307
        if ($resArray = $collection->fetch()) {
308
            if ($resArray['sys_language_uid'] != $GLOBALS['TSFE']->sys_language_content) {
309
                $collectionData = $pageRepository->getRecordOverlay('tx_dlf_collections', $resArray, $GLOBALS['TSFE']->sys_language_content, $GLOBALS['TSFE']->sys_language_contentOL);
310
            } else {
311
                $collectionData = $resArray;
312
            }
313
        } else {
314
            Helper::devLog('No collection with UID ' . $id . ' found.', DEVLOG_SEVERITY_WARNING);
315
            return;
316
        }
317
        // Fetch corresponding document UIDs from Solr.
318
        if ($collectionData['index_search'] != '') {
319
            $solr_query = '(' . $collectionData['index_search'] . ')';
320
        } else {
321
            $solr_query = 'collection:("' . $collectionData['index_name'] . '") AND toplevel:true';
322
        }
323
        $solr = Solr::getInstance($this->conf['solrcore']);
324
        if (!$solr->ready) {
325
            Helper::devLog('Apache Solr not available', DEVLOG_SEVERITY_ERROR);
326
            return;
327
        }
328
        $params['fields'] = 'uid';
329
        $params['sort'] = ['uid' => 'asc'];
330
        $solrResult = $solr->search_raw($solr_query, $params);
331
        // Initialize array
332
        $documentSet = [];
333
        foreach ($solrResult as $doc) {
334
            if ($doc->uid) {
335
                $documentSet[] = $doc->uid;
336
            }
337
        }
338
        $documentSet = array_unique($documentSet);
339
        $queryBuilder = $connectionPool->getQueryBuilderForTable('tx_dlf_documents');
340
        // Fetch document info for UIDs in $documentSet from DB
341
        $documents = $queryBuilder
342
            ->select(
343
                'tx_dlf_documents.uid AS uid',
344
                'tx_dlf_documents.metadata_sorting AS metadata_sorting',
345
                'tx_dlf_documents.volume_sorting AS volume_sorting',
346
                'tx_dlf_documents.partof AS partof'
347
            )
348
            ->from('tx_dlf_documents')
349
            ->where(
350
                $queryBuilder->expr()->eq('tx_dlf_documents.pid', intval($this->conf['pages'])),
351
                $queryBuilder->expr()->in('tx_dlf_documents.uid', $documentSet),
352
                Helper::whereExpression('tx_dlf_documents')
353
            )
354
            ->execute();
355
356
        $toplevel = [];
357
        $subparts = [];
358
        $listMetadata = [];
359
        // Process results.
360
        while ($resArray = $documents->fetch()) {
361
            if (empty($listMetadata)) {
362
                $listMetadata = [
363
                    'label' => htmlspecialchars($collectionData['label']),
364
                    'description' => $this->pi_RTEcssText($collectionData['description']),
365
                    'thumbnail' => htmlspecialchars($collectionData['thumbnail']),
366
                    'options' => [
367
                        'source' => 'collection',
368
                        'select' => $id,
369
                        'userid' => $collectionData['userid'],
370
                        'params' => ['filterquery' => [['query' => 'collection_faceting:("' . $collectionData['index_name'] . '")']]],
371
                        'core' => '',
372
                        'pid' => $this->conf['pages'],
373
                        'order' => 'title',
374
                        'order.asc' => true
375
                    ]
376
                ];
377
            }
378
            // Prepare document's metadata for sorting.
379
            $sorting = unserialize($resArray['metadata_sorting']);
380
            if (!empty($sorting['type']) && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($sorting['type'])) {
381
                $sorting['type'] = Helper::getIndexNameFromUid($sorting['type'], 'tx_dlf_structures', $this->conf['pages']);
382
            }
383
            if (!empty($sorting['owner']) && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($sorting['owner'])) {
384
                $sorting['owner'] = Helper::getIndexNameFromUid($sorting['owner'], 'tx_dlf_libraries', $this->conf['pages']);
385
            }
386
            if (!empty($sorting['collection']) && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($sorting['collection'])) {
387
                $sorting['collection'] = Helper::getIndexNameFromUid($sorting['collection'], 'tx_dlf_collections', $this->conf['pages']);
388
            }
389
            // Split toplevel documents from volumes.
390
            if ($resArray['partof'] == 0) {
391
                $toplevel[$resArray['uid']] = [
392
                    'u' => $resArray['uid'],
393
                    'h' => '',
394
                    's' => $sorting,
395
                    'p' => []
396
                ];
397
            } else {
398
                $subparts[$resArray['partof']][$resArray['volume_sorting']] = [
399
                    'u' => $resArray['uid'],
400
                    'h' => '',
401
                    's' => $sorting,
402
                    'p' => []
403
                ];
404
            }
405
        }
406
        // Add volumes to the corresponding toplevel documents.
407
        foreach ($subparts as $partof => $parts) {
408
            ksort($parts);
409
            foreach ($parts as $part) {
410
                if (!empty($toplevel[$partof])) {
411
                    $toplevel[$partof]['p'][] = ['u' => $part['u']];
412
                } else {
413
                    $toplevel[$part['u']] = $part;
414
                }
415
            }
416
        }
417
        // Save list of documents.
418
        $list = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(DocumentList::class);
419
        $list->reset();
420
        $list->add(array_values($toplevel));
421
        $listMetadata['options']['numberOfToplevelHits'] = count($list);
422
        $list->metadata = $listMetadata;
423
        $list->sort('title');
424
        $list->save();
425
        // Clean output buffer.
426
        ob_end_clean();
427
        // Send headers.
428
        $linkConf = [
429
            'parameter' => $this->conf['targetPid'],
430
            'forceAbsoluteUrl' => !empty($this->conf['forceAbsoluteUrl']) ? 1 : 0,
431
            'forceAbsoluteUrl.' => ['scheme' => !empty($this->conf['forceAbsoluteUrl']) && !empty($this->conf['forceAbsoluteUrlHttps']) ? 'https' : 'http']
432
        ];
433
        header('Location: ' . \TYPO3\CMS\Core\Utility\GeneralUtility::locationHeaderUrl($this->cObj->typoLink_URL($linkConf)));
434
        exit;
435
    }
436
}
437