tx_dlf_oai::fetchDocumentUIDs()   F
last analyzed

Complexity

Conditions 19
Paths 398

Size

Total Lines 112
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 19
eloc 56
nc 398
nop 0
dl 0
loc 112
rs 3.6524
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 ();
0 ignored issues
show
Bug Best Practice introduced by
The property piVars does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
124
125
        // Set only allowed parameters.
126
        foreach ($allowedParams as $param) {
127
            if (\TYPO3\CMS\Core\Utility\GeneralUtility::_GP($param)) {
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Core\Utility\GeneralUtility was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
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();
0 ignored issues
show
Bug introduced by
The call to DOMDocument::__construct() has too few arguments starting with version. ( Ignorable by Annotation )

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

314
        $xml = /** @scrutinizer ignore-call */ new DOMDocument();

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
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)) {
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Core\Utility\ExtensionManagementUtility was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
372
                    $this->conf['stylesheet'] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::siteRelPath($extKey).$filePath;
0 ignored issues
show
Bug Best Practice introduced by
The property conf does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
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();
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;
0 ignored issues
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'];
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));
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) {
0 ignored issues
show
Bug introduced by
The constant TYPO3_DLOG was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
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']) {
0 ignored issues
show
Bug introduced by
The constant TYPO3_MODE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1132
    include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/dlf/plugins/oai/class.tx_dlf_oai.php']);
1133
1134
}
1135