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.

Issues (210)

Classes/Command/BaseCommand.php (11 issues)

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\Command;
14
15
use Kitodo\Dlf\Common\AbstractDocument;
16
use Kitodo\Dlf\Common\Helper;
17
use Kitodo\Dlf\Common\Indexer;
18
use Kitodo\Dlf\Domain\Repository\CollectionRepository;
19
use Kitodo\Dlf\Domain\Repository\DocumentRepository;
20
use Kitodo\Dlf\Domain\Repository\LibraryRepository;
21
use Kitodo\Dlf\Domain\Repository\StructureRepository;
22
use Kitodo\Dlf\Domain\Model\Collection;
23
use Kitodo\Dlf\Domain\Model\Document;
24
use Kitodo\Dlf\Domain\Model\Library;
25
use Kitodo\Dlf\Validation\DocumentValidator;
26
use Symfony\Component\Console\Command\Command;
27
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
28
use TYPO3\CMS\Core\Utility\GeneralUtility;
29
use TYPO3\CMS\Core\Utility\MathUtility;
30
use TYPO3\CMS\Core\Database\ConnectionPool;
31
use TYPO3\CMS\Core\Database\Connection;
32
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
33
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
34
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
35
36
/**
37
 * Base class for CLI Command classes.
38
 *
39
 * @package TYPO3
40
 * @subpackage dlf
41
 *
42
 * @access public
43
 */
44
class BaseCommand extends Command
45
{
46
    /**
47
     * @access protected
48
     * @var CollectionRepository
49
     */
50
    protected CollectionRepository $collectionRepository;
51
52
    /**
53
     * @access protected
54
     * @var DocumentRepository
55
     */
56
    protected DocumentRepository $documentRepository;
57
58
    /**
59
     * @access protected
60
     * @var LibraryRepository
61
     */
62
    protected LibraryRepository $libraryRepository;
63
64
    /**
65
     * @access protected
66
     * @var StructureRepository
67
     */
68
    protected StructureRepository $structureRepository;
69
70
    /**
71
     * @access protected
72
     * @var int
73
     */
74
    protected int $storagePid;
75
76
    /**
77
     * @access protected
78
     * @var Library|null
79
     */
80
    protected ?Library $owner;
81
82
    /**
83
     * @access protected
84
     * @var array
85
     */
86
    protected array $extConf;
87
88
    /**
89
     * @access protected
90
     * @var ConfigurationManager
91
     */
92
    protected ConfigurationManager $configurationManager;
93
94
    /**
95
     * @access protected
96
     * @var PersistenceManager
97
     */
98
    protected PersistenceManager $persistenceManager;
99
100
    public function __construct(
101
        CollectionRepository $collectionRepository,
102
        DocumentRepository $documentRepository,
103
        LibraryRepository $libraryRepository,
104
        StructureRepository $structureRepository,
105
        ConfigurationManager $configurationManager,
106
        PersistenceManager $persistenceManager
107
    ) {
108
        parent::__construct();
109
110
        $this->collectionRepository = $collectionRepository;
111
        $this->documentRepository = $documentRepository;
112
        $this->libraryRepository = $libraryRepository;
113
        $this->structureRepository = $structureRepository;
114
        $this->configurationManager = $configurationManager;
115
        $this->persistenceManager = $persistenceManager;
116
    }
117
118
    /**
119
     * Initialize the extbase repository based on the given storagePid.
120
     *
121
     * TYPO3 10+: Find a better solution e.g. based on Symfony Dependency Injection.
122
     *
123
     * @access protected
124
     *
125
     * @param int $storagePid The storage pid
126
     *
127
     * @return void
128
     */
129
    protected function initializeRepositories(int $storagePid): void
130
    {
131
        $frameworkConfiguration = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
132
        $frameworkConfiguration['persistence']['storagePid'] = MathUtility::forceIntegerInRange($storagePid, 0);
133
        $this->configurationManager->setConfiguration($frameworkConfiguration);
134
        $this->extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('dlf');
135
        $this->storagePid = MathUtility::forceIntegerInRange($storagePid, 0);
136
        $this->persistenceManager = GeneralUtility::makeInstance(PersistenceManager::class);
137
    }
138
139
    /**
140
     * Return matching uid of Solr core depending on the input value.
141
     *
142
     * @access protected
143
     *
144
     * @param array $solrCores array of the valid Solr cores
145
     * @param string|bool|null $inputSolrId possible uid or name of Solr core
146
     *
147
     * @return int matching uid of Solr core
148
     */
149
    protected function getSolrCoreUid(array $solrCores, $inputSolrId): ?int
150
    {
151
        if (MathUtility::canBeInterpretedAsInteger($inputSolrId)) {
152
            $solrCoreUid = MathUtility::forceIntegerInRange((int) $inputSolrId, 0);
153
        } else {
154
            $solrCoreUid = $solrCores[$inputSolrId];
155
        }
156
        return $solrCoreUid;
157
    }
158
159
    /**
160
     * Fetches all Solr cores on given page.
161
     *
162
     * @access protected
163
     *
164
     * @param int $pageId The UID of the Solr core or 0 to disable indexing
165
     *
166
     * @return array Array of valid Solr cores
167
     */
168
    protected function getSolrCores(int $pageId): array
169
    {
170
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
171
            ->getQueryBuilderForTable('tx_dlf_solrcores');
172
173
        $solrCores = [];
174
        $result = $queryBuilder
175
            ->select('uid', 'index_name')
176
            ->from('tx_dlf_solrcores')
177
            ->where(
178
                $queryBuilder->expr()->eq(
179
                    'pid',
180
                    $queryBuilder->createNamedParameter((int) $pageId, Connection::PARAM_INT)
181
                )
182
            )
183
            ->execute();
184
185
        while ($record = $result->fetchAssociative()) {
186
            $solrCores[$record['index_name']] = $record['uid'];
187
        }
188
189
        return $solrCores;
190
    }
191
192
    /**
193
     * Update or insert document to database
194
     *
195
     * @access protected
196
     *
197
     * @param Document $document The document instance
198
     * @param bool $softCommit If true, documents are just added to the index by a soft commit
199
     *
200
     * @return bool true on success, false otherwise
201
     */
202
    protected function saveToDatabase(Document $document, bool $softCommit = false): bool
203
    {
204
        $doc = $document->getCurrentDocument();
205
        if ($doc === null) {
206
            return false;
207
        }
208
209
        $doc->cPid = $this->storagePid;
210
211
        $metadata = $doc->getToplevelMetadata($this->storagePid);
212
        $validator = new DocumentValidator($metadata, explode(',', $this->extConf['general']['requiredMetadataFields']));
213
214
        if ($validator->hasAllMandatoryMetadataFields()) {
215
            // set title data
216
            $document->setTitle($metadata['title'][0] ? : '');
217
            $document->setTitleSorting($metadata['title_sorting'][0] ? : '');
218
            $document->setPlace(implode('; ', $metadata['place']));
219
            $document->setYear(implode('; ', $metadata['year']));
220
            $document->setAuthor($this->getAuthors($metadata['author']));
221
            $document->setThumbnail($doc->thumbnail ? : '');
222
            $document->setMetsLabel($metadata['mets_label'][0] ? : '');
223
            $document->setMetsOrderlabel($metadata['mets_orderlabel'][0] ? : '');
224
225
            $structure = $this->structureRepository->findOneByIndexName($metadata['type'][0]);
0 ignored issues
show
The method findOneByIndexName() does not exist on Kitodo\Dlf\Domain\Repository\StructureRepository. 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

225
            /** @scrutinizer ignore-call */ 
226
            $structure = $this->structureRepository->findOneByIndexName($metadata['type'][0]);
Loading history...
226
            $document->setStructure($structure);
227
228
            if (is_array($metadata['collection'])) {
229
                $this->addCollections($document, $metadata['collection']);
230
            }
231
232
            // set identifiers
233
            $document->setProdId($metadata['prod_id'][0] ? : '');
234
            $document->setOpacId($metadata['opac_id'][0] ? : '');
235
            $document->setUnionId($metadata['union_id'][0] ? : '');
236
237
            $document->setRecordId($metadata['record_id'][0]);
238
            $document->setUrn($metadata['urn'][0] ? : '');
239
            $document->setPurl($metadata['purl'][0] ? : '');
240
            $document->setDocumentFormat($metadata['document_format'][0] ? : '');
241
242
            // set access
243
            $document->setLicense($metadata['license'][0] ? : '');
244
            $document->setTerms($metadata['terms'][0] ? : '');
245
            $document->setRestrictions($metadata['restrictions'][0] ? : '');
246
            $document->setOutOfPrint($metadata['out_of_print'][0] ? : '');
247
            $document->setRightsInfo($metadata['rights_info'][0] ? : '');
248
            $document->setStatus(0);
249
250
            $this->setOwner($metadata['owner'][0]);
251
            $document->setOwner($this->owner);
252
253
            // set volume data
254
            $document->setVolume($metadata['volume'][0] ? : '');
255
            $document->setVolumeSorting($metadata['volume_sorting'][0] ? : $metadata['mets_order'][0] ? : '');
256
257
            // Get UID of parent document.
258
            if ($document->getDocumentFormat() === 'METS') {
259
                $document->setPartof($this->getParentDocumentUidForSaving($document, $softCommit));
260
            }
261
262
            if ($document->getUid() === null) {
263
                // new document
264
                $this->documentRepository->add($document);
265
            } else {
266
                // update of existing document
267
                $this->documentRepository->update($document);
268
            }
269
270
            $this->persistenceManager->persistAll();
271
272
            return true;
273
        }
274
275
        return false;
276
    }
277
278
    /**
279
     * Get the ID of the parent document if the current document has one.
280
     * Currently only applies to METS documents.
281
     *
282
     * @access protected
283
     *
284
     * @param Document $document for which parent UID should be taken
285
     * @param bool $softCommit If true, documents are just added to the index by a soft commit
286
     *
287
     * @return int The parent document's id.
288
     */
289
    protected function getParentDocumentUidForSaving(Document $document, bool $softCommit = false): int
290
    {
291
        $doc = $document->getCurrentDocument();
292
293
        if ($doc !== null && !empty($doc->parentHref)) {
0 ignored issues
show
Bug Best Practice introduced by
The property parentHref does not exist on Kitodo\Dlf\Common\AbstractDocument. Since you implemented __get, consider adding a @property annotation.
Loading history...
294
            // find document object by record_id of parent
295
            $parent = AbstractDocument::getInstance($doc->parentHref, ['storagePid' => $this->storagePid]);
296
297
            if ($parent->recordId) {
298
                $parentDocument = $this->documentRepository->findOneByRecordId($parent->recordId);
0 ignored issues
show
The method findOneByRecordId() does not exist on Kitodo\Dlf\Domain\Repository\DocumentRepository. 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

298
                /** @scrutinizer ignore-call */ 
299
                $parentDocument = $this->documentRepository->findOneByRecordId($parent->recordId);
Loading history...
299
300
                if ($parentDocument === null) {
301
                    // create new Document object
302
                    $parentDocument = GeneralUtility::makeInstance(Document::class);
303
                }
304
305
                $parentDocument->setOwner($this->owner);
0 ignored issues
show
The method setOwner() does not exist on TYPO3\CMS\Extbase\Persistence\QueryResultInterface. ( Ignorable by Annotation )

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

305
                $parentDocument->/** @scrutinizer ignore-call */ 
306
                                 setOwner($this->owner);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
306
                $parentDocument->setCurrentDocument($parent);
0 ignored issues
show
The method setCurrentDocument() does not exist on TYPO3\CMS\Extbase\Persistence\QueryResultInterface. ( Ignorable by Annotation )

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

306
                $parentDocument->/** @scrutinizer ignore-call */ 
307
                                 setCurrentDocument($parent);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
307
                $parentDocument->setLocation($doc->parentHref);
0 ignored issues
show
The method setLocation() does not exist on TYPO3\CMS\Extbase\Persistence\QueryResultInterface. ( Ignorable by Annotation )

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

307
                $parentDocument->/** @scrutinizer ignore-call */ 
308
                                 setLocation($doc->parentHref);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
308
                $parentDocument->setSolrcore($document->getSolrcore());
0 ignored issues
show
The method setSolrcore() does not exist on TYPO3\CMS\Extbase\Persistence\QueryResultInterface. ( Ignorable by Annotation )

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

308
                $parentDocument->/** @scrutinizer ignore-call */ 
309
                                 setSolrcore($document->getSolrcore());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
309
310
                $success = $this->saveToDatabase($parentDocument, $softCommit);
311
312
                if ($success === true) {
313
                    // add to index
314
                    Indexer::add($parentDocument, $this->documentRepository, $softCommit);
315
                    return $parentDocument->getUid();
0 ignored issues
show
The method getUid() does not exist on TYPO3\CMS\Extbase\Persistence\QueryResultInterface. ( Ignorable by Annotation )

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

315
                    return $parentDocument->/** @scrutinizer ignore-call */ getUid();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
316
                }
317
            }
318
        }
319
320
        return 0;
321
    }
322
323
    /**
324
     * Add collections.
325
     *
326
     * @access private
327
     * 
328
     * @param Document &$document
329
     * @param array $collections
330
     *
331
     * @return void
332
     */
333
    private function addCollections(Document &$document, array $collections): void
334
    {
335
        foreach ($collections as $collection) {
336
            $documentCollection = $this->collectionRepository->findOneByIndexName($collection);
0 ignored issues
show
The method findOneByIndexName() does not exist on Kitodo\Dlf\Domain\Repository\CollectionRepository. 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

336
            /** @scrutinizer ignore-call */ 
337
            $documentCollection = $this->collectionRepository->findOneByIndexName($collection);
Loading history...
337
            if (!$documentCollection) {
338
                // create new Collection object
339
                $documentCollection = GeneralUtility::makeInstance(Collection::class);
340
                $documentCollection->setIndexName($collection);
341
                $documentCollection->setLabel($collection);
342
                $documentCollection->setOaiName((!empty($this->extConf['general']['publishNewCollections']) ? Helper::getCleanString($collection) : ''));
343
                $documentCollection->setIndexSearch('');
344
                $documentCollection->setDescription('');
345
                // add to CollectionRepository
346
                $this->collectionRepository->add($documentCollection);
347
                // persist collection to prevent duplicates
348
                $this->persistenceManager->persistAll();
349
            }
350
            // add to document
351
            $document->addCollection($documentCollection);
352
        }
353
    }
354
355
    /**
356
     * Get authors considering that database field can't accept
357
     * more than 255 characters.
358
     *
359
     * @access private
360
     * 
361
     * @param array $metadataAuthor
362
     *
363
     * @return string
364
     */
365
    private function getAuthors(array $metadataAuthor): string
366
    {
367
        // Remove appended "valueURI" from authors' names for storing in database.
368
        foreach ($metadataAuthor as $i => $author) {
369
            $splitName = explode(pack('C', 31), $author);
370
            $metadataAuthor[$i] = $splitName[0];
371
        }
372
373
        $authors = '';
374
        $delimiter = '; ';
375
        $ellipsis = 'et al.';
376
377
        $count = count($metadataAuthor);
378
379
        for ($i = 0; $i < $count; $i++) {
380
            // Build the next part to add
381
            $nextPart = ($i === 0 ? '' : $delimiter) . $metadataAuthor[$i];
382
            // Check if adding this part and ellipsis in future would exceed the character limit
383
            if (strlen($authors . $nextPart . $delimiter . $ellipsis) > 255) {
384
                // Add ellipsis and stop adding more authors
385
                $authors .= $delimiter . $ellipsis;
386
                break;
387
            }
388
            // Add the part to the main string
389
            $authors .= $nextPart;
390
        }
391
392
        return $authors;
393
    }
394
395
    /**
396
     * If owner is not set set but found by metadata, take it or take default library, if nothing found in database then create new owner.
397
     *
398
     * @access private
399
     *
400
     * @param ?string $owner
401
     *
402
     * @return void
403
     */
404
    private function setOwner($owner): void
405
    {
406
        if (empty($this->owner)) {
407
            // owner is not set set but found by metadata --> take it or take default library
408
            $owner = $owner ? : 'default';
409
            $this->owner = $this->libraryRepository->findOneByIndexName($owner);
0 ignored issues
show
The method findOneByIndexName() does not exist on Kitodo\Dlf\Domain\Repository\LibraryRepository. 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

409
            /** @scrutinizer ignore-call */ 
410
            $this->owner = $this->libraryRepository->findOneByIndexName($owner);
Loading history...
410
            if (empty($this->owner)) {
411
                // create library
412
                $this->owner = GeneralUtility::makeInstance(Library::class);
413
                $this->owner->setLabel($owner);
0 ignored issues
show
The method setLabel() does not exist on null. ( Ignorable by Annotation )

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

413
                $this->owner->/** @scrutinizer ignore-call */ 
414
                              setLabel($owner);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
414
                $this->owner->setIndexName($owner);
415
                $this->libraryRepository->add($this->owner);
416
            }
417
        }
418
    }
419
}
420