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
Push — master ( 03fab6...086e8a )
by Sebastian
03:23 queued 11s
created

Collection   B

Complexity

Total Complexity 51

Size/Duplication

Total Lines 399
Duplicated Lines 0 %

Importance

Changes 10
Bugs 0 Features 0
Metric Value
wmc 51
eloc 252
c 10
b 0
f 0
dl 0
loc 399
rs 7.92

3 Methods

Rating   Name   Duplication   Size   Complexity  
A main() 0 20 3
F showCollectionList() 0 169 27
F showSingleCollection() 0 168 21

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
                'additionalParams' => \TYPO3\CMS\Core\Utility\GeneralUtility::implodeArrayForUrl($this->prefixId, $additionalParams, '', true, false)
208
            ];
209
            // Link collection's title to list view.
210
            $markerArray[$_key]['###TITLE###'] = $this->cObj->typoLink(htmlspecialchars($collection['label']), $conf);
211
            // Add feed link if applicable.
212
            if (!empty($this->conf['targetFeed'])) {
213
                $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

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