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 (214)

Classes/Command/HarvestCommand.php (1 issue)

calls to magic methods without @method annotation.

Bug Major
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\Command\BaseCommand;
17
use Kitodo\Dlf\Common\Indexer;
18
use Kitodo\Dlf\Domain\Model\Document;
19
use Symfony\Component\Console\Input\InputInterface;
20
use Symfony\Component\Console\Input\InputOption;
21
use Symfony\Component\Console\Output\OutputInterface;
22
use Symfony\Component\Console\Style\SymfonyStyle;
23
use TYPO3\CMS\Core\Utility\GeneralUtility;
24
use TYPO3\CMS\Core\Utility\MathUtility;
25
use Phpoaipmh\Endpoint;
26
use Phpoaipmh\Exception\BaseOaipmhException;
27
28
/**
29
 * CLI Command for harvesting OAI-PMH interfaces into database and Solr.
30
 *
31
 * @package TYPO3
32
 * @subpackage dlf
33
 *
34
 * @access public
35
 */
36
class HarvestCommand extends BaseCommand
37
{
38
    /**
39
     * Configure the command by defining the name, options and arguments
40
     *
41
     * @access public
42
     *
43
     * @return void
44
     */
45
    public function configure(): void
46
    {
47
        $this
48
            ->setDescription('Harvest OAI-PMH contents into database and Solr.')
49
            ->setHelp('')
50
            ->addOption(
51
                'dry-run',
52
                null,
53
                InputOption::VALUE_NONE,
54
                'If this option is set, the files will not actually be processed but the location URIs are shown.'
55
            )
56
            ->addOption(
57
                'lib',
58
                'l',
59
                InputOption::VALUE_REQUIRED,
60
                'UID of the library to harvest.'
61
            )
62
            ->addOption(
63
                'pid',
64
                'p',
65
                InputOption::VALUE_REQUIRED,
66
                'UID of the page the documents should be added to.'
67
            )
68
            ->addOption(
69
                'solr',
70
                's',
71
                InputOption::VALUE_REQUIRED,
72
                '[UID|index_name] of the Solr core the document should be added to.'
73
            )
74
            ->addOption(
75
                'from',
76
                null,
77
                InputOption::VALUE_OPTIONAL,
78
                'Datestamp (YYYY-MM-DD) to begin harvesting from.'
79
            )
80
            ->addOption(
81
                'until',
82
                null,
83
                InputOption::VALUE_OPTIONAL,
84
                'Datestamp (YYYY-MM-DD) to end harvesting on.'
85
            )
86
            ->addOption(
87
                'set',
88
                null,
89
                InputOption::VALUE_OPTIONAL,
90
                'Name of the set to limit harvesting to.'
91
            )
92
            ->addOption(
93
                'softCommit',
94
                null,
95
                InputOption::VALUE_NONE,
96
                'If this option is set, documents are just added to the index by a soft commit.'
97
            );
98
    }
99
100
    /**
101
     * Executes the command to index the given document to DB and SOLR.
102
     * 
103
     * @access protected
104
     *
105
     * @param InputInterface $input The input parameters
106
     * @param OutputInterface $output The Symfony interface for outputs on console
107
     *
108
     * @return int
109
     */
110
    protected function execute(InputInterface $input, OutputInterface $output): int
111
    {
112
        $dryRun = $input->getOption('dry-run') != false ? true : false;
113
114
        $io = new SymfonyStyle($input, $output);
115
        $io->title($this->getDescription());
116
117
        $this->initializeRepositories((int) $input->getOption('pid'));
118
119
        if ($this->storagePid == 0) {
120
            $io->error('ERROR: No valid PID (' . $this->storagePid . ') given.');
121
            return BaseCommand::FAILURE;
122
        }
123
124
        if (
125
            !empty($input->getOption('solr'))
126
            && !is_array($input->getOption('solr'))
127
        ) {
128
            $allSolrCores = $this->getSolrCores($this->storagePid);
129
            if (MathUtility::canBeInterpretedAsInteger($input->getOption('solr'))) {
130
                $solrCoreUid = MathUtility::forceIntegerInRange((int) $input->getOption('solr'), 0);
131
            } else {
132
                $solrCoreUid = $allSolrCores[$input->getOption('solr')];
133
            }
134
            // Abort if solrCoreUid is empty or not in the array of allowed solr cores.
135
            if (empty($solrCoreUid) || !in_array($solrCoreUid, $allSolrCores)) {
136
                $outputSolrCores = [];
137
                foreach ($allSolrCores as $indexName => $uid) {
138
                    $outputSolrCores[] = $uid . ' : ' . $indexName;
139
                }
140
                if (empty($outputSolrCores)) {
141
                    $io->error('ERROR: No valid Solr core ("' . $input->getOption('solr') . '") given. No valid cores found on PID ' . $this->storagePid . ".\n");
142
                    return BaseCommand::FAILURE;
143
                } else {
144
                    $io->error('ERROR: No valid Solr core ("' . $input->getOption('solr') . '") given. ' . "Valid cores are (<uid>:<index_name>):\n" . implode("\n", $outputSolrCores) . "\n");
145
                    return BaseCommand::FAILURE;
146
                }
147
            }
148
        } else {
149
            $io->error('ERROR: Required parameter --solr|-s is missing or array.');
150
            return BaseCommand::FAILURE;
151
        }
152
153
        if (MathUtility::canBeInterpretedAsInteger($input->getOption('lib'))) {
154
            $this->owner = $this->libraryRepository->findByUid(MathUtility::forceIntegerInRange((int) $input->getOption('lib'), 1));
155
        }
156
157
        if ($this->owner) {
158
            $baseUrl = $this->owner->getOaiBase();
159
        } else {
160
            $io->error('ERROR: Required parameter --lib|-l is not a valid UID.');
161
            return BaseCommand::FAILURE;
162
        }
163
        if (!GeneralUtility::isValidUrl($baseUrl)) {
164
            $io->error('ERROR: No valid OAI Base URL set for library with given UID ("' . $input->getOption('lib') . '").');
165
            return BaseCommand::FAILURE;
166
        } else {
167
            try {
168
                $oai = Endpoint::build($baseUrl);
169
            } catch (BaseoaipmhException $e) {
170
                $this->handleOaiError($e, $io);
171
            }
172
        }
173
174
        if (
175
            !is_array($input->getOption('from'))
176
            && preg_match('/^\d{4}-\d{2}-\d{2}$/', $input->getOption('from'))
177
        ) {
178
            $from = new \DateTime($input->getOption('from'));
179
        } else {
180
            $from = null;
181
        }
182
183
        if (
184
            !is_array($input->getOption('until'))
185
            && preg_match('/^\d{4}-\d{2}-\d{2}$/', $input->getOption('until'))
186
        ) {
187
            $until = new \DateTime($input->getOption('until'));
188
        } else {
189
            $until = null;
190
        }
191
192
        $set = null;
193
        if (
194
            !is_array($input->getOption('set'))
195
            && !empty($input->getOption('set'))
196
            && !empty($oai)
197
        ) {
198
            $setsAvailable = $oai->listSets();
199
            foreach ($setsAvailable as $setAvailable) {
200
                if ((string) $setAvailable->setSpec === $input->getOption('set')) {
201
                    $set = $input->getOption('set');
202
                    break;
203
                }
204
            }
205
            if (empty($set)) {
206
                $io->error('ERROR: OAI interface does not provide a set with given setSpec ("' . $input->getOption('set') . '").');
207
                return BaseCommand::FAILURE;
208
            }
209
        }
210
211
        $identifiers = [];
212
        // Get OAI record identifiers to process.
213
        try {
214
            if (!empty($oai)) {
215
                $identifiers = $oai->listIdentifiers('mets', $from, $until, $set);
216
            } else {
217
                $io->error('ERROR: OAI interface does not exist.');
218
            }
219
        } catch (BaseoaipmhException $exception) {
220
            $this->handleOaiError($exception, $io);
221
        }
222
223
        // Process all identifiers.
224
        $baseLocation = $baseUrl . (parse_url($baseUrl, PHP_URL_QUERY) ? '&' : '?');
225
        foreach ($identifiers as $identifier) {
226
            // Build OAI GetRecord URL...
227
            $params = [
228
                'verb' => 'GetRecord',
229
                'metadataPrefix' => 'mets',
230
                'identifier' => (string) $identifier->identifier
231
            ];
232
            $docLocation = $baseLocation . http_build_query($params);
233
            // ...index the document...
234
            $document = null;
235
            $doc = AbstractDocument::getInstance($docLocation, ['storagePid' => $this->storagePid], true);
236
237
            if ($doc === null) {
238
                $io->warning('WARNING: Document "' . $docLocation . '" could not be loaded. Skip to next document.');
239
                continue;
240
            }
241
242
            if ($doc->recordId) {
243
                $document = $this->documentRepository->findOneByRecordId($doc->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

243
                /** @scrutinizer ignore-call */ 
244
                $document = $this->documentRepository->findOneByRecordId($doc->recordId);
Loading history...
244
            }
245
246
            if ($document === null) {
247
                // create new Document object
248
                $document = GeneralUtility::makeInstance(Document::class);
249
            }
250
251
            $document->setLocation($docLocation);
252
            $document->setSolrcore($solrCoreUid);
253
254
            if ($dryRun) {
255
                $io->writeln('DRY RUN: Would index ' . $document->getUid() . ' ("' . $document->getLocation() . '") on PID ' . $this->storagePid . ' and Solr core ' . $solrCoreUid . '.');
256
            } else {
257
                if ($io->isVerbose()) {
258
                    $io->writeln(date('Y-m-d H:i:s') . ' Indexing ' . $document->getUid() . ' ("' . $document->getLocation() . '") on PID ' . $this->storagePid . ' and Solr core ' . $solrCoreUid . '.');
259
                }
260
                $document->setCurrentDocument($doc);
261
                // save to database
262
                $this->saveToDatabase($document, $input->getOption('softCommit'));
263
                // add to index
264
                Indexer::add($document, $this->documentRepository, $input->getOption('softCommit'));
265
            }
266
        }
267
268
        $io->success('All done!');
269
270
        return BaseCommand::SUCCESS;
271
    }
272
273
    /**
274
     * Handles OAI errors
275
     *
276
     * @access protected
277
     *
278
     * @param BaseoaipmhException $exception Instance of exception thrown
279
     * @param SymfonyStyle $io
280
     *
281
     * @return void
282
     */
283
    protected function handleOaiError(BaseoaipmhException $exception, SymfonyStyle $io): void
284
    {
285
        $io->error('ERROR: Trying to retrieve data from OAI interface resulted in error:' . "\n    " . $exception->getMessage());
286
    }
287
}
288