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
Pull Request — master (#715)
by Alexander
03:36
created

OaiPmhController::initializeAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
/**
3
 * (c) Kitodo. Key to digital objects e.V. <[email protected]>
4
 *
5
 * This file is part of the Kitodo and TYPO3 projects.
6
 *
7
 * @license GNU General Public License version 3 or later.
8
 * For the full copyright and license information, please read the
9
 * LICENSE.txt file that was distributed with this source code.
10
 */
11
12
namespace Kitodo\Dlf\Controller;
13
14
use TYPO3\CMS\Core\Utility\GeneralUtility;
15
use Kitodo\Dlf\Common\Solr;
16
use Kitodo\Dlf\Domain\Model\Token;
17
use Kitodo\Dlf\Domain\Repository\CollectionRepository;
18
use Kitodo\Dlf\Domain\Repository\LibraryRepository;
19
use Kitodo\Dlf\Domain\Repository\TokenRepository;
20
21
/**
22
 * Controller for the plugin 'OAI-PMH Interface' for the 'dlf' extension
23
 *
24
 * @author Sebastian Meyer <[email protected]>
25
 * @package TYPO3
26
 * @subpackage dlf
27
 * @access public
28
 */
29
class OaiPmhController extends AbstractController
30
{
31
    /**
32
     * @var TokenRepository
33
     */
34
    protected $tokenRepository;
35
36
    /**
37
     * @param TokenRepository $tokenRepository
38
     */
39
    public function injectTokenRepository(TokenRepository $tokenRepository)
40
    {
41
        $this->tokenRepository = $tokenRepository;
42
    }
43
44
    /**
45
     * @var CollectionRepository
46
     */
47
    protected $collectionRepository;
48
49
    /**
50
     * @param CollectionRepository $collectionRepository
51
     */
52
    public function injectCollectionRepository(CollectionRepository $collectionRepository)
53
    {
54
        $this->collectionRepository = $collectionRepository;
55
    }
56
57
    /**
58
     * @var LibraryRepository
59
     */
60
    protected $libraryRepository;
61
62
    /**
63
     * @param LibraryRepository $libraryRepository
64
     */
65
    public function injectLibraryRepository(LibraryRepository $libraryRepository)
66
    {
67
        $this->libraryRepository = $libraryRepository;
68
    }
69
70
    /**
71
     * Initializes the current action
72
     *
73
     * @return void
74
     */
75
    public function initializeAction()
76
    {
77
        $this->request->setFormat('xml');
78
    }
79
80
    /**
81
     * Did an error occur?
82
     *
83
     * @var string
84
     * @access protected
85
     */
86
    protected $error;
87
88
    /**
89
     * This holds the configuration for all supported metadata prefixes
90
     *
91
     * @var array
92
     * @access protected
93
     */
94
    protected $formats = [
95
        'oai_dc' => [
96
            'schema' => 'http://www.openarchives.org/OAI/2.0/oai_dc.xsd',
97
            'namespace' => 'http://www.openarchives.org/OAI/2.0/oai_dc/',
98
            'requiredFields' => ['record_id'],
99
        ],
100
        'epicur' => [
101
            'schema' => 'http://www.persistent-identifier.de/xepicur/version1.0/xepicur.xsd',
102
            'namespace' => 'urn:nbn:de:1111-2004033116',
103
            'requiredFields' => ['purl', 'urn'],
104
        ],
105
        'mets' => [
106
            'schema' => 'http://www.loc.gov/standards/mets/version17/mets.v1-7.xsd',
107
            'namespace' => 'http://www.loc.gov/METS/',
108
            'requiredFields' => ['location'],
109
        ]
110
    ];
111
112
    /**
113
     * @var array
114
     */
115
    protected $parameters = [];
116
117
    /**
118
     * Delete expired resumption tokens
119
     *
120
     * @access protected
121
     *
122
     * @return void
123
     */
124
    protected function deleteExpiredTokens()
125
    {
126
        // Delete expired resumption tokens.
127
        $this->tokenRepository->deleteExpiredTokens($this->settings['expired']);
128
    }
129
130
    /**
131
     * Load URL parameters
132
     *
133
     * @access protected
134
     *
135
     * @return void
136
     */
137
    protected function getUrlParams()
138
    {
139
        $allowedParams = [
140
            'verb',
141
            'identifier',
142
            'metadataPrefix',
143
            'from',
144
            'until',
145
            'set',
146
            'resumptionToken'
147
        ];
148
        // Clear plugin variables.
149
        $this->parameters = [];
150
        // Set only allowed parameters.
151
        foreach ($allowedParams as $param) {
152
            if (GeneralUtility::_GP($param)) {
153
                $this->parameters[$param] = GeneralUtility::_GP($param);
154
            }
155
        }
156
    }
157
158
    /**
159
     * Get unqualified Dublin Core data.
160
     * @see http://www.openarchives.org/OAI/openarchivesprotocol.html#dublincore
161
     *
162
     * @access protected
163
     *
164
     * @param array $record : The full record array
165
     *
166
     * @return array $metadata: The mapped metadata array
167
     */
168
    protected function getDcData(array $record)
169
    {
170
        $metadata = [];
171
172
        $metadata[] = ['dc:identifier' => $record['record_id']];
173
174
        if (!empty($record['purl'])) {
175
            $metadata[] = ['dc:identifier' => $record['purl']];
176
        }
177
        if (!empty($record['prod_id'])) {
178
            $metadata[] = ['dc:identifier' => $record['prod_id']];
179
        }
180
        if (!empty($record['urn'])) {
181
            $metadata[] = ['dc:identifier' => $record['urn']];
182
        }
183
        if (!empty($record['title'])) {
184
            $metadata[] = ['dc:title' => $record['title']];
185
        }
186
        if (!empty($record['author'])) {
187
            $metadata[] = ['dc:creator' => $record['author']];
188
        }
189
        if (!empty($record['year'])) {
190
            $metadata[] = ['dc:date' => $record['year']];
191
        }
192
        if (!empty($record['place'])) {
193
            $metadata[] = ['dc:coverage' => $record['place']];
194
        }
195
        $record[] = ['dc:format' => $record['application/mets+xml']];
196
        $record[] = ['dc:type' => $record['Text']];
197
        if (!empty($record['partof'])) {
198
199
            $document = $this->documentRepository->findOneByPartof($metadata['partof']);
0 ignored issues
show
Bug introduced by
The method findOneByPartof() 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

199
            /** @scrutinizer ignore-call */ 
200
            $document = $this->documentRepository->findOneByPartof($metadata['partof']);
Loading history...
200
201
            if ($document) {
202
                $metadata[] = ['dc:relation' => $document->getRecordId()];
0 ignored issues
show
Bug introduced by
The method getRecordId() 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

202
                $metadata[] = ['dc:relation' => $document->/** @scrutinizer ignore-call */ getRecordId()];

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...
203
            }
204
        }
205
        if (!empty($record['license'])) {
206
            $metadata[] = ['dc:rights' => $record['license']];
207
        }
208
        if (!empty($record['terms'])) {
209
            $metadata[] = ['dc:rights' => $record['terms']];
210
        }
211
        if (!empty($record['restrictions'])) {
212
            $metadata[] = ['dc:rights' => $record['restrictions']];
213
        }
214
        if (!empty($record['out_of_print'])) {
215
            $metadata[] = ['dc:rights' => $record['out_of_print']];
216
        }
217
        if (!empty($record['rights_info'])) {
218
            $metadata[] = ['dc:rights' => $record['rights_info']];
219
        }
220
        return $metadata;
221
    }
222
223
224
    /**
225
     * Get METS data.
226
     * @see http://www.loc.gov/standards/mets/docs/mets.v1-7.html
227
     *
228
     * @access protected
229
     *
230
     * @param array $record : The full record array
231
     *
232
     * @return string: The fetched METS XML
233
     */
234
    protected function getMetsData(array $record)
235
    {
236
        $mets = null;
237
        // Load METS file.
238
        $xml = new \DOMDocument();
239
        if ($xml->load($record['location'])) {
240
            // Get root element.
241
            $root = $xml->getElementsByTagNameNS($this->formats['mets']['namespace'], 'mets');
242
            if ($root->item(0) instanceof \DOMNode) {
243
                // Import node into \DOMDocument.
244
                $mets = $xml->saveXML();
245
                // Remove leading line
246
                $mets = substr($mets, strpos($mets, '>'));
247
            } else {
248
                $this->logger->error('No METS part found in document with location "' . $record['location'] . '"');
249
            }
250
        } else {
251
            $this->logger->error('Could not load XML file from "' . $record['location'] . '"');
252
        }
253
        return $mets;
254
    }
255
256
    /**
257
     * The main method of the plugin
258
     *
259
     * @return void
260
     */
261
    public function mainAction()
262
    {
263
        // Get allowed GET and POST variables.
264
        $this->getUrlParams();
265
266
        // Delete expired resumption tokens.
267
        $this->deleteExpiredTokens();
268
269
        switch ($this->parameters['verb']) {
270
            case 'GetRecord':
271
                $this->verbGetRecord();
272
                break;
273
            case 'Identify':
274
                $this->verbIdentify();
275
                break;
276
            case 'ListIdentifiers':
277
                $this->verbListIdentifiers();
278
                break;
279
            case 'ListMetadataFormats':
280
                $this->verbListMetadataFormats();
281
                break;
282
            case 'ListRecords':
283
                $this->verbListRecords();
284
                break;
285
            case 'ListSets':
286
                $this->verbListSets();
287
                break;
288
        }
289
290
        $this->view->assign('parameters', $this->parameters);
291
        $this->view->assign('error', $this->error);
292
293
        return;
294
    }
295
296
    /**
297
     * Continue with resumption token
298
     *
299
     * @access protected
300
     *
301
     * @return array|null list of uids
302
     */
303
    protected function resume(): ?array
304
    {
305
        $token = $this->tokenRepository->findOneByToken($this->parameters['resumptionToken']);
0 ignored issues
show
Bug introduced by
The method findOneByToken() does not exist on Kitodo\Dlf\Domain\Repository\TokenRepository. 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

305
        /** @scrutinizer ignore-call */ 
306
        $token = $this->tokenRepository->findOneByToken($this->parameters['resumptionToken']);
Loading history...
306
307
        if ($token) {
308
            $options = $token->getOptions();
0 ignored issues
show
Bug introduced by
The method getOptions() 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
            /** @scrutinizer ignore-call */ 
309
            $options = $token->getOptions();

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
        if (is_array($options)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $options does not seem to be defined for all execution paths leading up to this point.
Loading history...
311
            return $options;
312
        } else {
313
            // No resumption token found or resumption token expired.
314
            $this->error = 'badResumptionToken';
315
            return null;
316
        }
317
    }
318
319
    /**
320
     * Process verb "GetRecord"
321
     *
322
     * @access protected
323
     *
324
     * @return void
325
     */
326
    protected function verbGetRecord()
327
    {
328
        if (count($this->parameters) !== 3 || empty($this->parameters['metadataPrefix']) || empty($this->parameters['identifier'])) {
329
            $this->error = 'badArgument';
330
            return;
331
        }
332
333
        if (!array_key_exists($this->parameters['metadataPrefix'], $this->formats)) {
334
            $this->error = 'cannotDisseminateFormat';
335
            return;
336
        }
337
338
        $document = $this->documentRepository->getOaiRecord($this->settings, $this->parameters);
339
340
        if (!$document['uid']) {
341
            $this->error = 'idDoesNotExist';
342
            return;
343
        }
344
345
        // Check for required fields.
346
        foreach ($this->formats[$this->parameters['metadataPrefix']]['requiredFields'] as $required) {
347
            if (empty($document[$required])) {
348
                $this->error = 'cannotDisseminateFormat';
349
                return;
350
            }
351
        }
352
353
        // we need the collections as array later
354
        $document['collections'] = explode(' ', $document['collections']);
355
356
        // Add metadata
357
        switch ($this->parameters['metadataPrefix']) {
358
            case 'oai_dc':
359
                $document['metadata'] = $this->getDcData($document);
360
                break;
361
            case 'epicur':
362
                $document['metadata'] = $document;
363
                break;
364
            case 'mets':
365
                $document['metadata'] = $this->getMetsData($document);
366
                break;
367
        }
368
369
        $this->view->assign('record', $document);
370
    }
371
372
    /**
373
     * Process verb "Identify"
374
     *
375
     * @access protected
376
     *
377
     * @return void
378
     */
379
    protected function verbIdentify()
380
    {
381
        $library = $this->libraryRepository->findByUid($this->settings['library']);
382
383
        $oaiIdentifyInfo = [];
384
385
        if (!$oaiIdentifyInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $oaiIdentifyInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
introduced by
$oaiIdentifyInfo is an empty array, thus ! $oaiIdentifyInfo is always true.
Loading history...
386
            $this->logger->notice('Incomplete plugin configuration');
387
        }
388
389
        $oaiIdentifyInfo['oai_label'] = $library->getOaiLabel();
390
        // Use default values for an installation with incomplete plugin configuration.
391
        if (empty($oaiIdentifyInfo['oai_label'])) {
392
            $oaiIdentifyInfo['oai_label'] = 'Kitodo.Presentation OAI-PMH Interface (default configuration)';
393
            $this->logger->notice('Incomplete plugin configuration (oai_label is missing)');
394
        }
395
396
        $oaiIdentifyInfo['contact'] = $library->getContact();
397
        if (empty($oaiIdentifyInfo['contact'])) {
398
            $oaiIdentifyInfo['contact'] = '[email protected]';
399
            $this->logger->notice('Incomplete plugin configuration (contact is missing)');
400
        }
401
402
        $document = $this->documentRepository->findOldestDocument();
403
404
        if ($document) {
405
            $oaiIdentifyInfo['earliestDatestamp'] = gmdate('Y-m-d\TH:i:s\Z', $document->getTstamp()->getTimestamp());
406
        } else {
407
            // access storagePid from TypoScript
408
            $pageSettings = $this->configurationManager->getConfiguration($this->configurationManager::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
409
            $storagePid = $pageSettings["plugin."]["tx_dlf."]["persistence."]["storagePid"];
410
            if ($storagePid > 0) {
411
                $this->logger->notice('No records found with PID ' . $storagePid);
412
            } else {
413
                $this->logger->notice('No records found');
414
            }
415
        }
416
        $this->view->assign('oaiIdentifyInfo', $oaiIdentifyInfo);
417
    }
418
419
    /**
420
     * Process verb "ListIdentifiers"
421
     *
422
     * @access protected
423
     *
424
     * @return void
425
     */
426
    protected function verbListIdentifiers()
427
    {
428
        // If we have a resumption token we can continue our work
429
        if (!empty($this->parameters['resumptionToken'])) {
430
            // "resumptionToken" is an exclusive argument.
431
            if (count($this->parameters) > 2) {
432
                $this->error = 'badArgument';
433
                return;
434
            } else {
435
                // return next chunk of documents
436
                $resultSet = $this->resume();
437
                if (is_array($resultSet)) {
438
                    $listIdentifiers = $this->generateOutputForDocumentList($resultSet);
439
                    $this->view->assign('listIdentifiers', $listIdentifiers);
440
                }
441
                return;
442
            }
443
        }
444
        // "metadataPrefix" is required and "identifier" is not allowed.
445
        if (empty($this->parameters['metadataPrefix']) || !empty($this->parameters['identifier'])) {
446
            $this->error = 'badArgument';
447
            return;
448
        }
449
        if (!in_array($this->parameters['metadataPrefix'], array_keys($this->formats))) {
450
            $this->error = 'cannotDisseminateFormat';
451
            return;
452
        }
453
        try {
454
            $documentSet = $this->fetchDocumentUIDs();
455
        } catch (\Exception $exception) {
456
            $this->error = 'idDoesNotExist';
457
            return;
458
        }
459
        // create new and empty documentlist
460
        $resultSet = [];
461
        if (is_array($documentSet)) {
462
            $resultSet[] = ($documentSet);
463
            $resultSet['metadata'] = [
464
                'completeListSize' => count($documentSet),
465
                'metadataPrefix' => $this->parameters['metadataPrefix'],
466
            ];
467
        }
468
469
        $listIdentifiers = $this->generateOutputForDocumentList($resultSet);
470
        $this->view->assign('listIdentifiers', $listIdentifiers);
471
    }
472
473
    /**
474
     * Process verb "ListMetadataFormats"
475
     *
476
     * @access protected
477
     *
478
     * @return void
479
     */
480
    protected function verbListMetadataFormats()
481
    {
482
        $resArray = [];
483
        // check for the optional "identifier" parameter
484
        if (isset($this->parameters['identifier'])) {
485
            $resArray = $this->documentRepository->findOneByRecordId($this->parameters['identifier']);
0 ignored issues
show
Bug introduced by
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

485
            /** @scrutinizer ignore-call */ 
486
            $resArray = $this->documentRepository->findOneByRecordId($this->parameters['identifier']);
Loading history...
486
        }
487
488
        $resultSet = [];
489
        foreach ($this->formats as $prefix => $details) {
490
            if (!empty($resArray)) {
491
                // check, if all required fields are available for a given identifier
492
                foreach ($details['requiredFields'] as $required) {
493
                    $methodName = 'get' . GeneralUtility::underscoredToUpperCamelCase($required);
494
                    if (empty($resArray->$methodName())) {
495
                        // Skip metadata formats whose requirements are not met.
496
                        continue 2;
497
                    }
498
                }
499
            }
500
            $details['prefix'] = $prefix;
501
            $resultSet[] = $details;
502
        }
503
        $this->view->assign('metadataFormats', $resultSet);
504
    }
505
506
    /**
507
     * Process verb "ListRecords"
508
     *
509
     * @access protected
510
     *
511
     * @return void
512
     */
513
    protected function verbListRecords()
514
    {
515
        // Check for invalid arguments.
516
        if (!empty($this->parameters['resumptionToken'])) {
517
            // "resumptionToken" is an exclusive argument.
518
            if (count($this->parameters) > 2) {
519
                $this->error = 'badArgument';
520
                return;
521
            } else {
522
                // return next chunk of documents
523
                $resultSet = $this->resume();
524
                if (is_array($resultSet)) {
525
                    $listRecords = $this->generateOutputForDocumentList($resultSet);
526
                    $this->parameters['metadataPrefix'] = $resultSet['metadata']['metadataPrefix'];
527
                    $this->view->assign('listRecords', $listRecords);
528
                }
529
                return;
530
            }
531
        }
532
        if (empty($this->parameters['metadataPrefix']) || !empty($this->parameters['identifier'])) {
533
            // "metadataPrefix" is required and "identifier" is not allowed.
534
            $this->error = 'badArgument';
535
            return;
536
        }
537
        // Check "metadataPrefix" for valid value.
538
        if (!in_array($this->parameters['metadataPrefix'], array_keys($this->formats))) {
539
            $this->error = 'cannotDisseminateFormat';
540
            return;
541
        }
542
        try {
543
            $documentSet = $this->fetchDocumentUIDs();
544
        } catch (\Exception $exception) {
545
            $this->error = 'idDoesNotExist';
546
            return;
547
        }
548
        $resultSet = [];
549
        if (is_array($documentSet)) {
550
            $resultSet[] = $documentSet;
551
            $resultSet['metadata'] = [
552
                'completeListSize' => count($documentSet),
553
                'metadataPrefix' => $this->parameters['metadataPrefix'],
554
            ];
555
        }
556
557
        $resultSet = $this->generateOutputForDocumentList($resultSet);
558
        $this->view->assign('listRecords', $resultSet);
559
    }
560
561
    /**
562
     * Process verb "ListSets"
563
     *
564
     * @access protected
565
     *
566
     * @return void
567
     */
568
    protected function verbListSets()
569
    {
570
        // It is required to set a oai_name inside the collection record to be shown in oai-pmh plugin.
571
        $this->settings['hideEmptyOaiNames'] = true;
572
573
        $oaiSets = $this->collectionRepository->findCollectionsBySettings($this->settings);
574
575
        $this->view->assign('oaiSets', $oaiSets);
576
    }
577
578
    /**
579
     * Fetch records
580
     *
581
     * @access protected
582
     *
583
     * @return array|null Array of matching records
584
     */
585
    protected function fetchDocumentUIDs()
586
    {
587
        $solr_query = '';
588
        // Check "set" for valid value.
589
        if (!empty($this->parameters['set'])) {
590
            // For SOLR we need the index_name of the collection,
591
            // For DB Query we need the UID of the collection
592
593
            $result = $this->collectionRepository->getIndexNameForSolr($this->settings, $this->parameters['set']);
594
595
            if ($resArray = $result->fetch()) {
596
                if ($resArray['index_query'] != "") {
597
                    $solr_query .= '(' . $resArray['index_query'] . ')';
598
                } else {
599
                    $solr_query .= 'collection:' . '"' . $resArray['index_name'] . '"';
600
                }
601
            } else {
602
                $this->error = 'noSetHierarchy';
603
                return null;
604
            }
605
        } else {
606
            // If no set is specified we have to query for all collections
607
            $solr_query .= 'collection:* NOT collection:""';
608
        }
609
        // Check for required fields.
610
        foreach ($this->formats[$this->parameters['metadataPrefix']]['requiredFields'] as $required) {
611
            $solr_query .= ' NOT ' . $required . ':""';
612
        }
613
        // toplevel="true" is always required
614
        $solr_query .= ' AND toplevel:true';
615
        $from = "*";
616
        // Check "from" for valid value.
617
        if (!empty($this->parameters['from'])) {
618
            // Is valid format?
619
            if (
620
                is_array($date_array = strptime($this->parameters['from'], '%Y-%m-%dT%H:%M:%SZ'))
621
                || is_array($date_array = strptime($this->parameters['from'], '%Y-%m-%d'))
622
            ) {
623
                $timestamp = gmmktime($date_array['tm_hour'], $date_array['tm_min'], $date_array['tm_sec'],
624
                    $date_array['tm_mon'] + 1, $date_array['tm_mday'], $date_array['tm_year'] + 1900);
625
                $from = date("Y-m-d", $timestamp) . 'T' . date("H:i:s", $timestamp) . '.000Z';
626
            } else {
627
                $this->error = 'badArgument';
628
                return;
629
            }
630
        }
631
        $until = "*";
632
        // Check "until" for valid value.
633
        if (!empty($this->parameters['until'])) {
634
            // Is valid format?
635
            if (
636
                is_array($date_array = strptime($this->parameters['until'], '%Y-%m-%dT%H:%M:%SZ'))
637
                || is_array($date_array = strptime($this->parameters['until'], '%Y-%m-%d'))
638
            ) {
639
                $timestamp = gmmktime($date_array['tm_hour'], $date_array['tm_min'], $date_array['tm_sec'],
640
                    $date_array['tm_mon'] + 1, $date_array['tm_mday'], $date_array['tm_year'] + 1900);
641
                $until = date("Y-m-d", $timestamp) . 'T' . date("H:i:s", $timestamp) . '.999Z';
642
                if ($from != "*" && $from > $until) {
643
                    $this->error = 'badArgument';
644
                }
645
            } else {
646
                $this->error = 'badArgument';
647
            }
648
        }
649
        // Check "from" and "until" for same granularity.
650
        if (
651
            !empty($this->parameters['from'])
652
            && !empty($this->parameters['until'])
653
        ) {
654
            if (strlen($this->parameters['from']) != strlen($this->parameters['until'])) {
655
                $this->error = 'badArgument';
656
            }
657
        }
658
        $solr_query .= ' AND timestamp:[' . $from . ' TO ' . $until . ']';
659
        $documentSet = [];
660
        $solr = Solr::getInstance($this->settings['solrcore']);
661
        if (!$solr->ready) {
662
            $this->logger->error('Apache Solr not available');
663
            return $documentSet;
664
        }
665
        if (intval($this->settings['solr_limit']) > 0) {
666
            $solr->limit = intval($this->settings['solr_limit']);
667
        }
668
        // We only care about the UID in the results and want them sorted
669
        $parameters = [
670
            "fields" => "uid",
671
            "sort" => [
672
                "uid" => "asc"
673
            ]
674
        ];
675
        $parameters['query'] = $solr_query;
676
        $result = $solr->search_raw($parameters);
677
        if (empty($result)) {
678
            $this->error = 'noRecordsMatch';
679
            return;
680
        }
681
        foreach ($result as $doc) {
682
            $documentSet[] = $doc->uid;
683
        }
684
        return $documentSet;
685
    }
686
687
    /**
688
     * Fetch more information for document list
689
     * @access protected
690
     *
691
     * @param array $documentListSet
692
     *
693
     * @return array of enriched records
694
     */
695
    protected function generateOutputForDocumentList(array $documentListSet)
696
    {
697
        $documentsToProcess = array_splice($documentListSet, 0, (int) $this->settings['limit']);
698
        if ($documentsToProcess === null) {
699
            $this->error = 'noRecordsMatch';
700
            return [];
701
        }
702
        $verb = $this->parameters['verb'];
703
704
        $documents = $this->documentRepository->getOaiDocumentList($this->settings, $documentsToProcess);
705
706
        $records = [];
707
        while ($resArray = $documents->fetch()) {
708
            // we need the collections as array later
709
            $resArray['collections'] = explode(' ', $resArray['collections']);
710
711
            if ($verb === 'ListRecords') {
712
                // Add metadata node.
713
                $metadataPrefix = $this->parameters['metadataPrefix'];
714
                if (!$metadataPrefix) {
715
                    // If we resume an action the metadataPrefix is stored with the documentSet
716
                    $metadataPrefix = $documentListSet['metadata']['metadataPrefix'];
717
                }
718
                switch ($metadataPrefix) {
719
                    case 'oai_dc':
720
                        $resArray['metadata'] = $this->getDcData($resArray);
721
                        break;
722
                    case 'epicur':
723
                        $resArray['metadata'] = $resArray;
724
                        break;
725
                    case 'mets':
726
                        $resArray['metadata'] = $this->getMetsData($resArray);
727
                        break;
728
                }
729
            }
730
731
            $records[] = $resArray;
732
        }
733
734
        $this->generateResumptionTokenForDocumentListSet($documentListSet);
735
736
        return $records;
737
    }
738
739
    /**
740
     * Generate resumption token
741
     *
742
     * @access protected
743
     *
744
     * @param array $documentListSet
745
     *
746
     * @return void
747
     */
748
    protected function generateResumptionTokenForDocumentListSet(array $documentListSet)
749
    {
750
        if (count($documentListSet) !== 0) {
751
            $resumptionToken = uniqid('', false);
752
753
            // create new token
754
            $newToken = GeneralUtility::makeInstance(Token::class);
755
            $newToken->setToken($resumptionToken);
756
            $newToken->setOptions($documentListSet);
757
758
            // add to tokenRepository
759
            $this->tokenRepository->add($newToken);
760
        } else {
761
            // Result set complete. We don't need a token.
762
            $resumptionToken = '';
763
        }
764
765
        $resumptionTokenInfo = [];
766
        $resumptionTokenInfo['token'] = $resumptionToken;
767
        $resumptionTokenInfo['cursor'] = $documentListSet['metadata']['completeListSize'] - count($documentListSet);
768
        $resumptionTokenInfo['completeListSize'] = $documentListSet['metadata']['completeListSize'];
769
        $expireDateTime = new \DateTime();
770
        $expireDateTime->add(new \DateInterval('PT' . $this->settings['expired'] . 'S'));
771
        $resumptionTokenInfo['expired'] = $expireDateTime;
772
773
        $this->view->assign('resumptionToken', $resumptionTokenInfo);
774
    }
775
}
776