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 ( 118576...18bf9c )
by Sebastian
14:55
created

tx_dlf_oai::getMetsData()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 4
eloc 13
c 2
b 0
f 0
nc 6
nop 1
dl 0
loc 26
rs 8.5806
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
/**
13
 * Plugin 'DLF: OAI-PMH Interface' for the 'dlf' extension.
14
 *
15
 * @author	Sebastian Meyer <[email protected]>
16
 * @package	TYPO3
17
 * @subpackage	tx_dlf
18
 * @access	public
19
 */
20
class tx_dlf_oai extends tx_dlf_plugin {
21
22
    public $scriptRelPath = 'plugins/oai/class.tx_dlf_oai.php';
23
24
    /**
25
     * Did an error occur?
26
     *
27
     * @var	boolean
28
     * @access protected
29
     */
30
    protected $error = FALSE;
31
32
    /**
33
     * This holds the OAI DOM object
34
     *
35
     * @var	DOMDocument
36
     * @access protected
37
     */
38
    protected $oai;
39
40
    /**
41
     * This holds the configuration for all supported metadata prefixes
42
     *
43
     * @var	array
44
     * @access protected
45
     */
46
    protected $formats = array (
47
        'oai_dc' => array (
48
            'schema' => 'http://www.openarchives.org/OAI/2.0/oai_dc.xsd',
49
            'namespace' => 'http://www.openarchives.org/OAI/2.0/oai_dc/',
50
            'requiredFields' => array ('record_id'),
51
        ),
52
        'epicur' => array (
53
            'schema' => 'http://www.persistent-identifier.de/xepicur/version1.0/xepicur.xsd',
54
            'namespace' => 'urn:nbn:de:1111-2004033116',
55
            'requiredFields' => array ('purl', 'urn'),
56
        ),
57
        'mets' => array (
58
            'schema' => 'http://www.loc.gov/standards/mets/version17/mets.v1-7.xsd',
59
            'namespace' => 'http://www.loc.gov/METS/',
60
            'requiredFields' => array ('location'),
61
        )
62
    );
63
64
    /**
65
     * Delete expired resumption tokens
66
     *
67
     * @access	protected
68
     *
69
     * @return	void
70
     */
71
    protected function deleteExpiredTokens() {
72
73
        // Delete expired resumption tokens.
74
        $result = $GLOBALS['TYPO3_DB']->exec_DELETEquery(
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
75
            'tx_dlf_tokens',
76
            'tx_dlf_tokens.ident="oai" AND tx_dlf_tokens.tstamp<'.intval($GLOBALS['EXEC_TIME'] - $this->conf['expired'])
77
        );
78
79
        if ($GLOBALS['TYPO3_DB']->sql_affected_rows() === -1) {
80
            // Deletion failed.
81
            $this->devLog('[tx_dlf_oai->deleteExpiredTokens()] Could not delete expired resumption tokens', SYSLOG_SEVERITY_WARNING);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_WARNING was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
82
        }
83
    }
84
85
    /**
86
     * Process error
87
     *
88
     * @access	protected
89
     *
90
     * @param	string		$type: Error type
91
     *
92
     * @return	DOMElement		XML node to add to the OAI response
93
     */
94
    protected function error($type) {
95
        $this->error = TRUE;
96
97
        $error = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'error', htmlspecialchars($this->pi_getLL($type, $type, FALSE), ENT_NOQUOTES, 'UTF-8'));
98
        $error->setAttribute('code', $type);
99
100
        return $error;
101
    }
102
103
    /**
104
     * Load URL parameters
105
     *
106
     * @access	protected
107
     *
108
     * @return	void
109
     */
110
    protected function getUrlParams() {
111
112
        $allowedParams = array (
113
            'verb',
114
            'identifier',
115
            'metadataPrefix',
116
            'from',
117
            'until',
118
            'set',
119
            'resumptionToken'
120
        );
121
122
        // Clear plugin variables.
123
        $this->piVars = array ();
124
125
        // Set only allowed parameters.
126
        foreach ($allowedParams as $param) {
127
            if (\TYPO3\CMS\Core\Utility\GeneralUtility::_GP($param)) {
128
                $this->piVars[$param] = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP($param);
129
            }
130
        }
131
    }
132
133
    /**
134
     * Get unqualified Dublin Core data.
135
     * @see http://www.openarchives.org/OAI/openarchivesprotocol.html#dublincore
136
     *
137
     * @access	protected
138
     *
139
     * @param	array		$metadata: The metadata array
140
     *
141
     * @return	DOMElement		XML node to add to the OAI response
142
     */
143
    protected function getDcData(array $metadata) {
144
145
        $oai_dc = $this->oai->createElementNS($this->formats['oai_dc']['namespace'], 'oai_dc:dc');
146
147
        $oai_dc->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:dc', 'http://purl.org/dc/elements/1.1/');
148
        $oai_dc->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
149
        $oai_dc->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation', $this->formats['oai_dc']['namespace'].' '.$this->formats['oai_dc']['schema']);
150
151
        $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:identifier', htmlspecialchars($metadata['record_id'], ENT_NOQUOTES, 'UTF-8')));
152
153
        if (!empty($metadata['purl'])) {
154
            $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:identifier', htmlspecialchars($metadata['purl'], ENT_NOQUOTES, 'UTF-8')));
155
        }
156
157
        if (!empty($metadata['urn'])) {
158
            $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:identifier', htmlspecialchars($metadata['urn'], ENT_NOQUOTES, 'UTF-8')));
159
        }
160
161
        if (!empty($metadata['title'])) {
162
            $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:title', htmlspecialchars($metadata['title'], ENT_NOQUOTES, 'UTF-8')));
163
        }
164
165
        if (!empty($metadata['author'])) {
166
            $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:creator', htmlspecialchars($metadata['author'], ENT_NOQUOTES, 'UTF-8')));
167
        }
168
169
        if (!empty($metadata['year'])) {
170
            $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:date', htmlspecialchars($metadata['year'], ENT_NOQUOTES, 'UTF-8')));
171
        }
172
173
        if (!empty($metadata['place'])) {
174
            $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:coverage', htmlspecialchars($metadata['place'], ENT_NOQUOTES, 'UTF-8')));
175
        }
176
177
        $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:format', 'application/mets+xml'));
178
        $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:type', 'Text'));
179
180
        if (!empty($metadata['partof'])) {
181
            $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
182
                'tx_dlf_documents.record_id',
183
                'tx_dlf_documents',
184
                'tx_dlf_documents.uid='.intval($metadata['partof']).tx_dlf_helper::whereClause('tx_dlf_documents'),
185
                '',
186
                '',
187
                '1'
188
            );
189
190
            if ($GLOBALS['TYPO3_DB']->sql_num_rows($result)) {
191
                $partof = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result);
192
193
                $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:relation', htmlspecialchars($partof['record_id'], ENT_NOQUOTES, 'UTF-8')));
194
            }
195
        }
196
197
        return $oai_dc;
198
    }
199
200
    /**
201
     * Get epicur data.
202
     * @see http://www.persistent-identifier.de/?link=210
203
     *
204
     * @access	protected
205
     *
206
     * @param	array		$metadata: The metadata array
207
     *
208
     * @return	DOMElement		XML node to add to the OAI response
209
     */
210
    protected function getEpicurData(array $metadata) {
211
212
        // Define all XML elements with or without qualified namespace.
213
        if (empty($this->conf['unqualified_epicur'])) {
214
            $epicur = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:epicur');
215
216
            $admin = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:administrative_data');
217
218
            $delivery = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:delivery');
219
220
            $update = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:update_status');
221
222
            $transfer = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:transfer');
223
224
            $format = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:format', 'text/html');
225
226
            $record = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:record');
227
228
            $identifier = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:identifier', htmlspecialchars($metadata['urn'], ENT_NOQUOTES, 'UTF-8'));
229
230
            $resource = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:resource');
231
232
            $ident = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:identifier', htmlspecialchars($metadata['purl'], ENT_NOQUOTES, 'UTF-8'));
233
234
        } else {
235
            $epicur = $this->oai->createElement('epicur');
236
            $epicur->setAttribute('xmlns', $this->formats['epicur']['namespace']);
237
238
            $admin = $this->oai->createElement('administrative_data');
239
240
            $delivery = $this->oai->createElement('delivery');
241
242
            $update = $this->oai->createElement('update_status');
243
244
            $transfer = $this->oai->createElement('transfer');
245
246
            $format = $this->oai->createElement('format', 'text/html');
247
248
            $record = $this->oai->createElement('record');
249
250
            $identifier = $this->oai->createElement('identifier', htmlspecialchars($metadata['urn'], ENT_NOQUOTES, 'UTF-8'));
251
252
            $resource = $this->oai->createElement('resource');
253
254
            $ident = $this->oai->createElement('identifier', htmlspecialchars($metadata['purl'], ENT_NOQUOTES, 'UTF-8'));
255
        }
256
257
        // Add attributes and build XML tree.
258
        $epicur->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
259
        $epicur->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation', $this->formats['epicur']['namespace'].' '.$this->formats['epicur']['schema']);
260
261
        // Do we update an URN or register a new one?
262
        if ($metadata['tstamp'] == $metadata['crdate']) {
263
            $update->setAttribute('type', 'urn_new');
264
        } else {
265
            $update->setAttribute('type', 'url_update_general');
266
        }
267
268
        $delivery->appendChild($update);
269
270
        $transfer->setAttribute('type', 'http');
271
272
        $delivery->appendChild($transfer);
273
274
        $admin->appendChild($delivery);
275
276
        $epicur->appendChild($admin);
277
278
        $identifier->setAttribute('scheme', 'urn:nbn:de');
279
280
        $record->appendChild($identifier);
281
282
        $ident->setAttribute('scheme', 'url');
283
        $ident->setAttribute('type', 'frontpage');
284
        $ident->setAttribute('role', 'primary');
285
286
        $resource->appendChild($ident);
287
288
        $format->setAttribute('scheme', 'imt');
289
290
        $resource->appendChild($format);
291
292
        $record->appendChild($resource);
293
294
        $epicur->appendChild($record);
295
296
        return $epicur;
297
    }
298
299
    /**
300
     * Get METS data.
301
     * @see http://www.loc.gov/standards/mets/docs/mets.v1-7.html
302
     *
303
     * @access	protected
304
     *
305
     * @param	array		$metadata: The metadata array
306
     *
307
     * @return	DOMElement		XML node to add to the OAI response
308
     */
309
    protected function getMetsData(array $metadata) {
310
311
        $mets = NULL;
312
313
        // Load METS file.
314
        $xml = new DOMDocument();
315
316
        if ($xml->load($metadata['location'])) {
317
            // Get root element.
318
            $root = $xml->getElementsByTagNameNS($this->formats['mets']['namespace'], 'mets');
319
320
            if ($root->item(0) instanceof DOMNode) {
321
                // Import node into DOMDocument.
322
                $mets = $this->oai->importNode($root->item(0), TRUE);
323
            } else {
324
                    $this->devLog('[tx_dlf_oai->getMetsData([data])] No METS part found in document with location "'.$metadata['location'].'"', SYSLOG_SEVERITY_ERROR, $metadata);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_ERROR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
325
            }
326
        } else {
327
            $this->devLog('[tx_dlf_oai->getMetsData([data])] Could not load XML file from "'.$metadata['location'].'"', SYSLOG_SEVERITY_ERROR, $metadata);
328
        }
329
330
        if ($mets === NULL) {
331
            $mets = $this->oai->createElementNS('http://kitodo.org/', 'kitodo:error', htmlspecialchars($this->pi_getLL('error', 'Error!', FALSE), ENT_NOQUOTES, 'UTF-8'));
332
        }
333
334
        return $mets;
335
    }
336
337
    /**
338
     * The main method of the PlugIn
339
     *
340
     * @access	public
341
     *
342
     * @param	string		$content: The PlugIn content
343
     * @param	array		$conf: The PlugIn configuration
344
     *
345
     * @return	void
346
     */
347
    public function main($content, $conf) {
348
349
        // Initialize plugin.
350
        $this->init($conf);
351
352
        // Turn cache off.
353
        $this->setCache(FALSE);
354
355
        // Get GET and POST variables.
356
        $this->getUrlParams();
357
358
        // Delete expired resumption tokens.
359
        $this->deleteExpiredTokens();
360
361
        // Create XML document.
362
        $this->oai = new DOMDocument('1.0', 'UTF-8');
363
364
        // Add processing instruction (aka XSL stylesheet).
365
        if (!empty($this->conf['stylesheet'])) {
366
            // Resolve "EXT:" prefix in file path.
367
            if (substr($this->conf['stylesheet'], 0, 4) == 'EXT:') {
368
369
                list ($extKey, $filePath) = explode('/', substr($this->conf['stylesheet'], 4), 2);
370
371
                if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded($extKey)) {
372
                    $this->conf['stylesheet'] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::siteRelPath($extKey).$filePath;
373
                }
374
            }
375
376
            $stylesheet = \TYPO3\CMS\Core\Utility\GeneralUtility::locationHeaderUrl($this->conf['stylesheet']);
377
378
        } else {
379
            // Use default stylesheet if no custom stylesheet is given.
380
            $stylesheet = \TYPO3\CMS\Core\Utility\GeneralUtility::locationHeaderUrl(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::siteRelPath($this->extKey).'plugins/oai/transform.xsl');
381
        }
382
383
        $this->oai->appendChild($this->oai->createProcessingInstruction('xml-stylesheet', 'type="text/xsl" href="'.htmlspecialchars($stylesheet, ENT_NOQUOTES, 'UTF-8').'"'));
384
385
        // Create root element.
386
        $root = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'OAI-PMH');
387
388
        $root->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
389
        $root->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation', 'http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd');
390
391
        // Add response date.
392
        $root->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'responseDate', gmdate('Y-m-d\TH:i:s\Z', $GLOBALS['EXEC_TIME'])));
393
394
        // Get response data.
395
        switch ($this->piVars['verb']) {
396
            case 'GetRecord':
397
                $response = $this->verbGetRecord();
398
                break;
399
400
            case 'Identify':
401
                $response = $this->verbIdentify();
402
                break;
403
404
            case 'ListIdentifiers':
405
                $response = $this->verbListIdentifiers();
406
                break;
407
408
            case 'ListMetadataFormats':
409
                $response = $this->verbListMetadataFormats();
410
                break;
411
412
            case 'ListRecords':
413
                $response = $this->verbListRecords();
414
                break;
415
416
            case 'ListSets':
417
                $response = $this->verbListSets();
418
                break;
419
420
            default:
421
                $response = $this->error('badVerb');
422
        }
423
424
        // Add request.
425
        $linkConf = array (
426
            'parameter' => $GLOBALS['TSFE']->id,
427
            'forceAbsoluteUrl' => 1
428
        );
429
430
        $request = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'request', htmlspecialchars($this->cObj->typoLink_URL($linkConf), ENT_NOQUOTES, 'UTF-8'));
431
432
        if (!$this->error) {
433
            foreach ($this->piVars as $key => $value) {
434
                $request->setAttribute($key, htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8'));
435
            }
436
        }
437
438
        $root->appendChild($request);
439
        $root->appendChild($response);
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type string; however, parameter $newnode of DOMNode::appendChild() does only seem to accept DOMNode, maybe add an additional type check? ( Ignorable by Annotation )

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

439
        $root->appendChild(/** @scrutinizer ignore-type */ $response);
Loading history...
440
441
        $this->oai->appendChild($root);
442
443
        $content = $this->oai->saveXML();
444
445
        // Clean output buffer.
446
        \TYPO3\CMS\Core\Utility\GeneralUtility::cleanOutputBuffers();
0 ignored issues
show
Deprecated Code introduced by
The function TYPO3\CMS\Core\Utility\G...y::cleanOutputBuffers() has been deprecated: since TYPO3 CMS 7, will be removed in CMS 8, use ob_* functions directly or self::flushOutputBuffers ( Ignorable by Annotation )

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

446
        /** @scrutinizer ignore-deprecated */ \TYPO3\CMS\Core\Utility\GeneralUtility::cleanOutputBuffers();

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...
447
448
        // Send headers.
449
        header('HTTP/1.1 200 OK');
450
        header('Cache-Control: no-cache');
451
        header('Content-Length: '.strlen($content));
452
        header('Content-Type: text/xml; charset=utf-8');
453
        header('Date: '.date('r', $GLOBALS['EXEC_TIME']));
454
        header('Expires: '.date('r', $GLOBALS['EXEC_TIME'] + $this->conf['expired']));
455
456
        echo $content;
457
458
        // Flush output buffer and end script processing.
459
        ob_end_flush();
460
461
        exit;
1 ignored issue
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
462
    }
463
464
    /**
465
     * Continue with resumption token
466
     *
467
     * @access	protected
468
     *
469
     * @return	string		Substitution for subpart "###RESPONSE###"
470
     */
471
    protected function resume() {
472
        // Get resumption token.
473
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
474
            'tx_dlf_tokens.options AS options',
475
            'tx_dlf_tokens',
476
            'tx_dlf_tokens.ident="oai" AND tx_dlf_tokens.token='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->piVars['resumptionToken'], 'tx_dlf_tokens'),
477
            '',
478
            '',
479
            '1'
480
        );
481
482
        if (!$GLOBALS['TYPO3_DB']->sql_num_rows($result)) {
483
            // No resumption token found or resumption token expired.
484
            return $this->error('badResumptionToken');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error('badResumptionToken') returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
485
        }
486
487
        $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result);
488
489
        $resultSet = unserialize($resArray['options']);
490
491
        return $this->generateOutputForDocumentList($resultSet);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->generateOu...ocumentList($resultSet) returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
492
493
    }
494
495
    /**
496
     * Process verb "GetRecord"
497
     *
498
     * @access	protected
499
     *
500
     * @return	string		Substitution for subpart "###RESPONSE###"
501
     */
502
    protected function verbGetRecord() {
503
504
        if (count($this->piVars) != 3 || empty($this->piVars['metadataPrefix']) || empty($this->piVars['identifier'])) {
505
            return $this->error('badArgument');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error('badArgument') returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
506
        }
507
508
        if (!in_array($this->piVars['metadataPrefix'], array_keys($this->formats))) {
509
            return $this->error('cannotDisseminateFormat');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error('cannotDisseminateFormat') returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
510
        }
511
512
        $where = '';
513
514
        if (!$this->conf['show_userdefined']) {
515
            $where .= ' AND tx_dlf_collections.fe_cruser_id=0';
516
        }
517
518
        $record = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query(
519
            'tx_dlf_documents.*,GROUP_CONCAT(DISTINCT tx_dlf_collections.oai_name ORDER BY tx_dlf_collections.oai_name SEPARATOR " ") AS collections',
520
            'tx_dlf_documents',
521
            'tx_dlf_relations',
522
            'tx_dlf_collections',
523
            'AND tx_dlf_documents.record_id='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->piVars['identifier'], 'tx_dlf_documents').' AND tx_dlf_documents.pid='.intval($this->conf['pages']).' AND tx_dlf_collections.pid='.intval($this->conf['pages']).' AND tx_dlf_relations.ident='.$GLOBALS['TYPO3_DB']->fullQuoteStr('docs_colls', 'tx_dlf_relations').$where.tx_dlf_helper::whereClause('tx_dlf_collections'),
524
            'tx_dlf_documents.uid',
525
            'tx_dlf_documents.tstamp',
526
            '1'
527
        );
528
529
        if (!$GLOBALS['TYPO3_DB']->sql_num_rows($record)) {
530
            return $this->error('idDoesNotExist');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error('idDoesNotExist') returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
531
        }
532
533
        $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($record);
534
535
        // Check for required fields.
536
        foreach ($this->formats[$this->piVars['metadataPrefix']]['requiredFields'] as $required) {
537
            if (empty($resArray[$required])) {
538
                return $this->error('cannotDisseminateFormat');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error('cannotDisseminateFormat') returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
539
            }
540
        }
541
542
        $GetRecord = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'GetRecord');
543
544
        $recordNode = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'record');
545
546
        $headerNode = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'header');
547
        $headerNode->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'identifier', htmlspecialchars($resArray['record_id'], ENT_NOQUOTES, 'UTF-8')));
548
        $headerNode->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'datestamp', gmdate('Y-m-d\TH:i:s\Z', $resArray['tstamp'])));
549
550
        // Handle deleted documents.
551
        // TODO: Use TYPO3 API functions here!
552
        if ($resArray['deleted'] || $resArray['hidden']) {
553
            $headerNode->setAttribute('status', 'deleted');
554
555
            $recordNode->appendChild($headerNode);
556
557
        } else {
558
            foreach (explode(' ', $resArray['collections']) as $spec) {
559
                $headerNode->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'setSpec', htmlspecialchars($spec, ENT_NOQUOTES, 'UTF-8')));
560
            }
561
562
            $recordNode->appendChild($headerNode);
563
564
            $metadataNode = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'metadata');
565
566
            switch ($this->piVars['metadataPrefix']) {
567
                case 'oai_dc':
568
                    $metadataNode->appendChild($this->getDcData($resArray));
569
                    break;
570
571
                case 'epicur':
572
                    $metadataNode->appendChild($this->getEpicurData($resArray));
573
                    break;
574
575
                case 'mets':
576
                    $metadataNode->appendChild($this->getMetsData($resArray));
577
                    break;
578
            }
579
580
            $recordNode->appendChild($metadataNode);
581
        }
582
583
        $GetRecord->appendChild($recordNode);
584
585
        return $GetRecord;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $GetRecord returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
586
    }
587
588
    /**
589
     * Process verb "Identify"
590
     *
591
     * @access	protected
592
     *
593
     * @return	DOMElement		XML node to add to the OAI response
594
     */
595
    protected function verbIdentify() {
596
597
        // Check for invalid arguments.
598
        if (count($this->piVars) > 1) {
599
            return $this->error('badArgument');
600
        }
601
602
        // Get repository name and administrative contact.
603
        // Use default values for an installation with incomplete plugin configuration.
604
605
        $adminEmail = '[email protected]';
606
        $repositoryName = 'Kitodo.Presentation OAI-PMH interface (incomplete configuration)';
607
608
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
609
            'tx_dlf_libraries.oai_label AS oai_label,tx_dlf_libraries.contact AS contact',
610
            'tx_dlf_libraries',
611
            'tx_dlf_libraries.pid='.intval($this->conf['pages']).' AND tx_dlf_libraries.uid='.intval($this->conf['library']).tx_dlf_helper::whereClause('tx_dlf_libraries'),
612
            '',
613
            '',
614
            ''
615
        );
616
617
        if ($GLOBALS['TYPO3_DB']->sql_num_rows($result)) {
618
            $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result);
619
620
            $adminEmail = htmlspecialchars(trim(str_replace('mailto:', '', $resArray['contact'])), ENT_NOQUOTES);
621
            $repositoryName = htmlspecialchars($resArray['oai_label'], ENT_NOQUOTES);
622
623
        } else {
624
            $this->devLog('[tx_dlf_oai->verbIdentify()] Incomplete plugin configuration', SYSLOG_SEVERITY_NOTICE);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_NOTICE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
625
        }
626
627
        // Get earliest datestamp. Use a default value if that fails.
628
629
        $earliestDatestamp = '0000-00-00T00:00:00Z';
630
631
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
632
            'tx_dlf_documents.tstamp AS tstamp',
633
            'tx_dlf_documents',
634
            'tx_dlf_documents.pid='.intval($this->conf['pages']),
635
            '',
636
            'tx_dlf_documents.tstamp ASC',
637
            '1'
638
        );
639
640
        if ($GLOBALS['TYPO3_DB']->sql_num_rows($result)) {
641
            list ($timestamp) = $GLOBALS['TYPO3_DB']->sql_fetch_row($result);
642
            $earliestDatestamp = gmdate('Y-m-d\TH:i:s\Z', $timestamp);
643
        } else {
644
            $this->devLog('[tx_dlf_oai->verbIdentify()] No records found with PID "'.$this->conf['pages'].'"', SYSLOG_SEVERITY_NOTICE);
645
        }
646
647
        $linkConf = array (
648
            'parameter' => $GLOBALS['TSFE']->id,
649
            'forceAbsoluteUrl' => 1
650
        );
651
        $baseURL = htmlspecialchars($this->cObj->typoLink_URL($linkConf), ENT_NOQUOTES);
652
653
        // Add identification node.
654
        $Identify = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'Identify');
655
        $Identify->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'repositoryName', $repositoryName));
656
        $Identify->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'baseURL', $baseURL));
657
        $Identify->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'protocolVersion', '2.0'));
658
        $Identify->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'adminEmail', $adminEmail));
659
        $Identify->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'earliestDatestamp', $earliestDatestamp));
660
        $Identify->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'deletedRecord', 'transient'));
661
        $Identify->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'granularity', 'YYYY-MM-DDThh:mm:ssZ'));
662
663
        return $Identify;
664
    }
665
666
    /**
667
     * Process verb "ListIdentifiers"
668
     *
669
     * @access	protected
670
     *
671
     * @return	string		Substitution for subpart "###RESPONSE###"
672
     */
673
    protected function verbListIdentifiers() {
674
675
        // If we have a resumption token we can continue our work
676
        if (!empty($this->piVars['resumptionToken'])) {
677
            // "resumptionToken" is an exclusive argument.
678
            if (count($this->piVars) > 2) {
679
                return $this->error('badArgument');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error('badArgument') returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
680
            } else {
681
                return $this->resume();
682
            }
683
        }
684
685
        // "metadataPrefix" is required and "identifier" is not allowed.
686
        if (empty($this->piVars['metadataPrefix']) || !empty($this->piVars['identifier'])) {
687
            return $this->error('badArgument');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error('badArgument') returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
688
        }
689
690
        if (!in_array($this->piVars['metadataPrefix'], array_keys($this->formats))) {
691
            return $this->error('cannotDisseminateFormat');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error('cannotDisseminateFormat') returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
692
        }
693
694
        try {
695
            $documentSet = $this->fetchDocumentUIDs();
696
        } catch (Exception $exception) {
697
            return $this->error($exception->getMessage());
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error($exception->getMessage()) returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
698
        }
699
700
        $resultSet = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('tx_dlf_list');
701
702
        $resultSet->reset();
703
        $resultSet->add($documentSet);
704
        $resultSet->metadata = array (
705
            'completeListSize' => count($documentSet),
706
            'metadataPrefix' => $this->piVars['metadataPrefix'],
707
        );
708
709
        return $this->generateOutputForDocumentList($resultSet);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->generateOu...ocumentList($resultSet) returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
710
711
    }
712
713
    /**
714
     * Process verb "ListMetadataFormats"
715
     *
716
     * @access	protected
717
     *
718
     * @return	DOMElement		XML node to add to the OAI response
719
     */
720
    protected function verbListMetadataFormats() {
721
722
        $resArray = array ();
723
724
        // Check for invalid arguments.
725
        if (count($this->piVars) > 1) {
726
            if (empty($this->piVars['identifier']) || count($this->piVars) > 2) {
727
                return $this->error('badArgument');
728
            }
729
730
            // Check given identifier.
731
            $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
732
                'tx_dlf_documents.*',
733
                'tx_dlf_documents',
734
                'tx_dlf_documents.pid='.intval($this->conf['pages']).' AND tx_dlf_documents.record_id='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->piVars['identifier'], 'tx_dlf_documents'),
735
                '',
736
                '',
737
                '1'
738
            );
739
740
            if (!$GLOBALS['TYPO3_DB']->sql_num_rows($result)) {
741
                return $this->error('idDoesNotExist');
742
            }
743
744
            $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result);
745
        }
746
747
        // Add metadata formats node.
748
        $ListMetadaFormats = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'ListMetadataFormats');
749
750
        foreach ($this->formats as $prefix => $details) {
751
            if (!empty($resArray)) {
752
                foreach ($details['requiredFields'] as $required) {
753
                    if (empty($resArray[$required])) {
754
                        // Skip metadata formats whose requirements are not met.
755
                        continue 2;
756
                    }
757
                }
758
            }
759
760
            // Add format node.
761
            $format = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'metadataFormat');
762
763
            $format->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'metadataPrefix', htmlspecialchars($prefix, ENT_NOQUOTES, 'UTF-8')));
764
            $format->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'schema', htmlspecialchars($details['schema'], ENT_NOQUOTES, 'UTF-8')));
765
            $format->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'metadataNamespace', htmlspecialchars($details['namespace'], ENT_NOQUOTES, 'UTF-8')));
766
767
            $ListMetadaFormats->appendChild($format);
768
        }
769
770
        return $ListMetadaFormats;
771
    }
772
773
    /**
774
     * Process verb "ListRecords"
775
     *
776
     * @access	protected
777
     *
778
     * @return	string		Substitution for subpart "###RESPONSE###"
779
     */
780
    protected function verbListRecords() {
781
782
        // Check for invalid arguments.
783
        if (!empty($this->piVars['resumptionToken'])) {
784
            // "resumptionToken" is an exclusive argument.
785
            if (count($this->piVars) > 2) {
786
                return $this->error('badArgument');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error('badArgument') returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
787
            } else {
788
                return $this->resume();
789
            }
790
791
        }
792
793
        if (empty($this->piVars['metadataPrefix']) || !empty($this->piVars['identifier'])) {
794
            // "metadataPrefix" is required and "identifier" is not allowed.
795
            return $this->error('badArgument');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error('badArgument') returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
796
        }
797
798
        // Check "metadataPrefix" for valid value.
799
        if (!in_array($this->piVars['metadataPrefix'], array_keys($this->formats))) {
800
            return $this->error('cannotDisseminateFormat');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error('cannotDisseminateFormat') returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
801
        }
802
803
        try {
804
            $documentSet = $this->fetchDocumentUIDs();
805
        } catch (Exception $exception) {
806
            return $this->error($exception->getMessage());
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error($exception->getMessage()) returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
807
        }
808
809
        $resultSet = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('tx_dlf_list');
810
811
        $resultSet->reset();
812
        $resultSet->add($documentSet);
813
        $resultSet->metadata = array (
814
            'completeListSize' => count($documentSet),
815
            'metadataPrefix' => $this->piVars['metadataPrefix'],
816
        );
817
818
        return $this->generateOutputForDocumentList($resultSet);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->generateOu...ocumentList($resultSet) returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
819
    }
820
821
    /**
822
     * Process verb "ListSets"
823
     *
824
     * @access	protected
825
     *
826
     * @return	string		Substitution for subpart "###RESPONSE###"
827
     */
828
    protected function verbListSets() {
829
830
        // Check for invalid arguments.
831
        if (count($this->piVars) > 1) {
832
            if (!empty($this->piVars['resumptionToken'])) {
833
                return $this->error('badResumptionToken');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error('badResumptionToken') returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
834
            } else {
835
                return $this->error('badArgument');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error('badArgument') returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
836
            }
837
        }
838
839
        $where = '';
840
841
        if (!$this->conf['show_userdefined']) {
842
            $where = ' AND tx_dlf_collections.fe_cruser_id=0';
843
        }
844
845
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
846
            'tx_dlf_collections.oai_name AS oai_name,tx_dlf_collections.label AS label',
847
            'tx_dlf_collections',
848
            'tx_dlf_collections.sys_language_uid IN (-1,0) AND NOT tx_dlf_collections.oai_name=\'\' AND tx_dlf_collections.pid='.intval($this->conf['pages']).$where.tx_dlf_helper::whereClause('tx_dlf_collections'),
849
            'tx_dlf_collections.oai_name',
850
            'tx_dlf_collections.oai_name',
851
            ''
852
        );
853
854
        if (!$GLOBALS['TYPO3_DB']->sql_num_rows($result)) {
855
            return $this->error('noSetHierarchy');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->error('noSetHierarchy') returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
856
        }
857
858
        $ListSets = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'ListSets');
859
860
        while ($resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) {
861
862
            $set = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'set');
863
864
            $set->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'setSpec', htmlspecialchars($resArray['oai_name'], ENT_NOQUOTES, 'UTF-8')));
865
            $set->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'setName', htmlspecialchars($resArray['label'], ENT_NOQUOTES, 'UTF-8')));
866
867
            $ListSets->appendChild($set);
868
        }
869
870
        return $ListSets;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $ListSets returns the type DOMElement which is incompatible with the documented return type string.
Loading history...
871
    }
872
873
874
875
    /**
876
     * @return array
877
     * @throws Exception
878
     */
879
    private function fetchDocumentUIDs() {
880
        $solr_query = '';
881
882
        if (!$this->conf['show_userdefined']) {
883
            $where = ' AND tx_dlf_collections.fe_cruser_id=0';
884
        }
885
886
        // Check "set" for valid value.
887
        if (!empty($this->piVars['set'])) {
888
889
            // For SOLR we need the index_name of the collection,
890
            // For DB Query we need the UID of the collection
891
            $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
892
                'tx_dlf_collections.index_name AS index_name, tx_dlf_collections.uid AS uid, tx_dlf_collections.index_search as index_query ',
893
                'tx_dlf_collections',
894
                'tx_dlf_collections.pid='.intval($this->conf['pages']).' AND tx_dlf_collections.oai_name='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->piVars['set'],
895
                    'tx_dlf_collections').$where.tx_dlf_helper::whereClause('tx_dlf_collections'),
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $where does not seem to be defined for all execution paths leading up to this point.
Loading history...
896
                '',
897
                '',
898
                '1'
899
            );
900
901
            if (!$GLOBALS['TYPO3_DB']->sql_num_rows($result)) {
902
                throw new Exception('noSetHierarchy');
903
            }
904
905
            $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result);
906
907
            if ($resArray['index_query'] != "") {
908
                $solr_query .= '('.$resArray['index_query'].')';
909
            } else {
910
                $solr_query .= 'collection:'.'"'.$resArray['index_name'].'"';
911
            }
912
913
        } else {
914
            // If no set is specified we have to query for all collections
915
            $solr_query .= 'collection:* NOT collection:""';
916
917
        }
918
919
        // Check for required fields.
920
        foreach ($this->formats[$this->piVars['metadataPrefix']]['requiredFields'] as $required) {
921
            $solr_query .= ' NOT '.$required.':""';
922
        }
923
924
        $from = "*";
925
        // Check "from" for valid value.
926
        if (!empty($this->piVars['from'])) {
927
928
            // Is valid format?
929
            if (is_array($date_array = strptime($this->piVars['from'],
930
                    '%Y-%m-%dT%H:%M:%SZ')) || is_array($date_array = strptime($this->piVars['from'], '%Y-%m-%d'))) {
931
932
                $timestamp = gmmktime($date_array['tm_hour'], $date_array['tm_min'], $date_array['tm_sec'], $date_array['tm_mon'] + 1,
933
                    $date_array['tm_mday'], $date_array['tm_year'] + 1900);
934
935
                $from = date("Y-m-d", $timestamp).'T'.date("H:i:s", $timestamp).'.000Z';
936
937
            } else {
938
                throw new Exception('badArgument');
939
            }
940
        }
941
942
        $until = "*";
943
        // Check "until" for valid value.
944
        if (!empty($this->piVars['until'])) {
945
946
            // Is valid format?
947
            if (is_array($date_array = strptime($this->piVars['until'],
948
                    '%Y-%m-%dT%H:%M:%SZ')) || is_array($date_array = strptime($this->piVars['until'], '%Y-%m-%d'))) {
949
950
                $timestamp = gmmktime($date_array['tm_hour'], $date_array['tm_min'], $date_array['tm_sec'], $date_array['tm_mon'] + 1,
951
                    $date_array['tm_mday'], $date_array['tm_year'] + 1900);
952
953
                $until = date("Y-m-d", $timestamp).'T'.date("H:i:s", $timestamp).'.999Z';
954
955
                if ($from != "*" && $from > $until) {
956
                    throw new Exception('badArgument');
957
                }
958
959
            } else {
960
                throw new Exception('badArgument');
961
            }
962
        }
963
964
        // Check "from" and "until" for same granularity.
965
        if (!empty($this->piVars['from']) && !empty($this->piVars['until'])) {
966
            if (strlen($this->piVars['from']) != strlen($this->piVars['until'])) {
967
                throw new Exception('badArgument');
968
            }
969
        }
970
971
        $solr_query .= ' AND timestamp:['.$from.' TO '.$until.']';
972
973
        $documentSet = array ();
974
975
        $solr = tx_dlf_solr::getInstance($this->conf['solrcore']);
976
977
        // We only care about the UID in the results and want them sorted
978
        $parameters = array ("fl" => "uid", "sort" => "uid asc");
979
980
        $result = $solr->search_raw($solr_query, $parameters);
981
982
        if (empty($result)) {
983
            throw new Exception('noRecordsMatch');
984
        }
985
986
        foreach ($result as $doc) {
987
            $documentSet[] = $doc->uid;
988
        }
989
990
        return $documentSet;
991
    }
992
993
    /**
994
     * @param tx_dlf_list $documentListSet
995
     * @return DOMElement
996
     */
997
    private function generateOutputForDocumentList($documentListSet) {
998
999
            $documentsToProcess = $documentListSet->removeRange(0, intval($this->conf['limit']));
1000
            $verb = $this->piVars['verb'];
1001
1002
        $documents = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query(
1003
            'tx_dlf_documents.*,GROUP_CONCAT(DISTINCT tx_dlf_collections.oai_name ORDER BY tx_dlf_collections.oai_name SEPARATOR " ") AS collections',
1004
            'tx_dlf_documents',
1005
            'tx_dlf_relations',
1006
            'tx_dlf_collections',
1007
            'AND tx_dlf_documents.uid IN ('.implode(',', $GLOBALS['TYPO3_DB']->cleanIntArray($documentsToProcess)).') AND tx_dlf_documents.pid='.intval($this->conf['pages']).' AND tx_dlf_collections.pid='.intval($this->conf['pages']).' AND tx_dlf_relations.ident='.$GLOBALS['TYPO3_DB']->fullQuoteStr('docs_colls', 'tx_dlf_relations').tx_dlf_helper::whereClause('tx_dlf_collections'),
1008
            'tx_dlf_documents.uid',
1009
            'tx_dlf_documents.tstamp',
1010
            $this->conf['limit']
1011
        );
1012
1013
        $output = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', $verb);
1014
1015
        while ($resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($documents)) {
1016
            // Add header node.
1017
            $header = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'header');
1018
1019
            $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'identifier', htmlspecialchars($resArray['record_id'], ENT_NOQUOTES, 'UTF-8')));
1020
            $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'datestamp', gmdate('Y-m-d\TH:i:s\Z', $resArray['tstamp'])));
1021
1022
            // Check if document is deleted or hidden.
1023
            // TODO: Use TYPO3 API functions here!
1024
            if ($resArray['deleted'] || $resArray['hidden']) {
1025
                // Add "deleted" status.
1026
                $header->setAttribute('status', 'deleted');
1027
1028
                if ($verb == 'ListRecords') {
1029
                    // Add record node.
1030
                    $record = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'record');
1031
1032
                    $record->appendChild($header);
1033
                    $output->appendChild($record);
1034
1035
                } elseif ($verb == 'ListIdentifiers') {
1036
                    $output->appendChild($header);
1037
                }
1038
1039
            } else {
1040
                // Add sets.
1041
                foreach (explode(' ', $resArray['collections']) as $spec) {
1042
                    $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'setSpec', htmlspecialchars($spec, ENT_NOQUOTES, 'UTF-8')));
1043
                }
1044
1045
                if ($verb == 'ListRecords') {
1046
                    // Add record node.
1047
                    $record = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'record');
1048
1049
                    $record->appendChild($header);
1050
1051
                    // Add metadata node.
1052
                    $metadata = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'metadata');
1053
1054
                    $metadataPrefix = $this->piVars['metadataPrefix'];
1055
                    if (!$metadataPrefix) {
1056
                        // If we resume an action the metadataPrefix is stored with the documentSet
1057
                        $metadataPrefix = $documentListSet->metadata['metadataPrefix'];
0 ignored issues
show
Bug Best Practice introduced by
The property $metadata is declared protected in tx_dlf_list. Since you implement __get, consider adding a @property or @property-read.
Loading history...
1058
                    }
1059
1060
                    switch ($metadataPrefix) {
1061
                        case 'oai_dc':
1062
                            $metadata->appendChild($this->getDcData($resArray));
1063
                            break;
1064
1065
                        case 'epicur':
1066
                            $metadata->appendChild($this->getEpicurData($resArray));
1067
                            break;
1068
1069
                        case 'mets':
1070
                            $metadata->appendChild($this->getMetsData($resArray));
1071
                            break;
1072
                    }
1073
1074
                    $record->appendChild($metadata);
1075
                    $output->appendChild($record);
1076
1077
                } elseif ($verb == 'ListIdentifiers') {
1078
                    $output->appendChild($header);
1079
                }
1080
            }
1081
        }
1082
1083
        $output->appendChild($this->generateResumptionTokenForDocumentListSet($documentListSet));
1084
1085
        return $output;
1086
    }
1087
1088
    /**
1089
     * @param tx_dlf_list $documentListSet
1090
     * @return DOMElement
1091
     */
1092
    private function generateResumptionTokenForDocumentListSet($documentListSet) {
1093
        $resumptionToken = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'resumptionToken');
1094
1095
        if ($documentListSet->count() != 0) {
1096
1097
            $token = uniqid();
1098
1099
            $GLOBALS['TYPO3_DB']->exec_INSERTquery(
1100
                'tx_dlf_tokens',
1101
                array (
1102
                    'tstamp' => $GLOBALS['EXEC_TIME'],
1103
                    'token' => $token,
1104
                    'options' => serialize($documentListSet),
1105
                    'ident' => 'oai',
1106
                )
1107
            );
1108
1109
            if ($GLOBALS['TYPO3_DB']->sql_affected_rows() == 1) {
1110
                $resumptionToken->setAttribute('resumptionToken', htmlspecialchars($token, ENT_NOQUOTES, 'UTF-8'));
1111
            } else {
1112
                $this->devLog('[tx_dlf_oai->verb'.$this->piVars['verb'].'()] Could not create resumption token', SYSLOG_SEVERITY_ERROR);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_ERROR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1113
            }
1114
        }
1115
1116
        $resumptionToken->setAttribute('cursor', intval($documentListSet->metadata['completeListSize']) - count($documentListSet));
0 ignored issues
show
Bug Best Practice introduced by
The property $metadata is declared protected in tx_dlf_list. Since you implement __get, consider adding a @property or @property-read.
Loading history...
1117
        $resumptionToken->setAttribute('completeListSize', $documentListSet->metadata['completeListSize']);
1118
        $resumptionToken->setAttribute('expirationDate', gmdate('Y-m-d\TH:i:s\Z', $GLOBALS['EXEC_TIME'] + $this->conf['expired']));
1119
1120
        return $resumptionToken;
1121
    }
1122
1123
    private function devLog($message, $severity, $data = NULL) {
1124
        if (TYPO3_DLOG) {
1125
            \TYPO3\CMS\Core\Utility\GeneralUtility::devLog($message, $this->extKey, $severity, $data);
1126
        }
1127
    }
1128
1129
}
1130
1131
if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dlf/plugins/oai/class.tx_dlf_oai.php']) {
1132
    include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dlf/plugins/oai/class.tx_dlf_oai.php']);
1133
1134
}
1135