Merge lp:~sebastian-meyer/goobi-presentation/bug802031 into lp:goobi-presentation/1.1
- bug802031
- Merge into 1.1
Proposed by
Sebastian Meyer
Status: | Merged |
---|---|
Merged at revision: | 41 |
Proposed branch: | lp:~sebastian-meyer/goobi-presentation/bug802031 |
Merge into: | lp:goobi-presentation/1.1 |
Diff against target: |
1865 lines (+910/-640) (has conflicts) 2 files modified
dlf/ext_tables.sql (+5/-4) dlf/plugins/oai/class.tx_dlf_oai.php (+905/-636) Contents conflict in dlf/plugins/oai/template.tmpl |
To merge this branch: | bzr merge lp:~sebastian-meyer/goobi-presentation/bug802031 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sebastian Meyer | Approve | ||
Review via email: mp+75213@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Sebastian Meyer (sebastian-meyer) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'dlf/ext_tables.sql' |
2 | --- dlf/ext_tables.sql 2011-08-18 10:38:09 +0000 |
3 | +++ dlf/ext_tables.sql 2011-09-13 15:52:34 +0000 |
4 | @@ -199,11 +199,12 @@ |
5 | CREATE TABLE tx_dlf_tokens ( |
6 | uid int(11) NOT NULL auto_increment, |
7 | tstamp int(11) DEFAULT '0' NOT NULL, |
8 | - token tinytext NOT NULL, |
9 | - options longtext NOT NULL, |
10 | - ident varchar(30) DEFAULT '' NOT NULL, |
11 | + token tinytext NOT NULL, |
12 | + options longtext NOT NULL, |
13 | + ident varchar(30) DEFAULT '' NOT NULL, |
14 | |
15 | - PRIMARY KEY (uid) |
16 | + PRIMARY KEY (uid), |
17 | + KEY token (token(13)) |
18 | ); |
19 | |
20 | -- |
21 | |
22 | === modified file 'dlf/plugins/oai/class.tx_dlf_oai.php' |
23 | --- dlf/plugins/oai/class.tx_dlf_oai.php 2011-06-25 13:50:11 +0000 |
24 | +++ dlf/plugins/oai/class.tx_dlf_oai.php 2011-09-13 15:52:34 +0000 |
25 | @@ -48,27 +48,34 @@ |
26 | protected $error = FALSE; |
27 | |
28 | /** |
29 | + * This holds the OAI DOM object |
30 | + * |
31 | + * @var DOMDocument |
32 | + * @access protected |
33 | + */ |
34 | + protected $oai; |
35 | + |
36 | + /** |
37 | * This holds the configuration for all supported metadata prefixes |
38 | * |
39 | * @var array |
40 | * @access protected |
41 | */ |
42 | protected $formats = array ( |
43 | -// 'oai_dc' => array ( |
44 | -// 'schema' => 'http://www.openarchives.org/OAI/2.0/oai_dc.xsd', |
45 | -// 'namespace' => 'http://www.openarchives.org/OAI/2.0/oai_dc/', |
46 | -// ), |
47 | -// 'epicur' => array ( |
48 | -// 'schema' => 'http://www.persistent-identifier.de/xepicur/version1.0/xepicur.xsd', |
49 | -// 'namespace' => 'urn:nbn:de:1111-2004033116', |
50 | -// ), |
51 | -// 'ese' => array ( |
52 | -// 'schema' => 'http://www.europeana.eu/schemas/ese/ESE-V3.3.xsd', |
53 | -// 'namespace' => 'http://www.europeana.eu/schemas/ese/', |
54 | -// ), |
55 | + 'oai_dc' => array ( |
56 | + 'schema' => 'http://www.openarchives.org/OAI/2.0/oai_dc.xsd', |
57 | + 'namespace' => 'http://www.openarchives.org/OAI/2.0/oai_dc/', |
58 | + 'requiredFields' => array ('record_id'), |
59 | + ), |
60 | + 'epicur' => array ( |
61 | + 'schema' => 'http://www.persistent-identifier.de/xepicur/version1.0/xepicur.xsd', |
62 | + 'namespace' => 'urn:nbn:de:1111-2004033116', |
63 | + 'requiredFields' => array ('purl', 'urn'), |
64 | + ), |
65 | 'mets' => array ( |
66 | 'schema' => 'http://www.loc.gov/standards/mets/version17/mets.v1-7.xsd', |
67 | 'namespace' => 'http://www.loc.gov/METS/', |
68 | + 'requiredFields' => array ('location'), |
69 | ) |
70 | ); |
71 | |
72 | @@ -82,7 +89,7 @@ |
73 | protected function deleteExpiredTokens() { |
74 | |
75 | // Delete expired resumption tokens. |
76 | - $GLOBALS['TYPO3_DB']->exec_DELETEquery( |
77 | + $_result = $GLOBALS['TYPO3_DB']->exec_DELETEquery( |
78 | 'tx_dlf_tokens', |
79 | 'tx_dlf_tokens.ident="oai" AND tx_dlf_tokens.tstamp<'.intval($GLOBALS['EXEC_TIME'] - $this->conf['expired']) |
80 | ); |
81 | @@ -103,18 +110,17 @@ |
82 | * |
83 | * @param string $type: Error type |
84 | * |
85 | - * @return string Substitution for subpart "###ERROR###" |
86 | + * @return DOMElement XML node to add to the OAI response |
87 | */ |
88 | protected function error($type) { |
89 | |
90 | $this->error = TRUE; |
91 | |
92 | - $markerArray = array ( |
93 | - '###ERROR_CODE###' => $type, |
94 | - '###ERROR_MESSAGE###' => $this->pi_getLL($type, $type, TRUE) |
95 | - ); |
96 | - |
97 | - return $this->cObj->substituteMarkerArray($this->cObj->getSubpart($this->template, '###ERROR###'), $markerArray); |
98 | + $error = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'error', $this->pi_getLL($type, $type, TRUE)); |
99 | + |
100 | + $error->setAttribute('code', $type); |
101 | + |
102 | + return $error; |
103 | |
104 | } |
105 | |
106 | @@ -154,6 +160,204 @@ |
107 | } |
108 | |
109 | /** |
110 | + * Get unqualified Dublin Core data. |
111 | + * @see http://www.openarchives.org/OAI/openarchivesprotocol.html#dublincore |
112 | + * |
113 | + * @access protected |
114 | + * |
115 | + * @param array $metadata: The metadata array |
116 | + * |
117 | + * @return DOMElement XML node to add to the OAI response |
118 | + */ |
119 | + protected function getDcData(array $metadata) { |
120 | + |
121 | + $oai_dc = $this->oai->createElementNS($this->formats['oai_dc']['namespace'], 'oai_dc:dc'); |
122 | + |
123 | + $oai_dc->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:dc', 'http://purl.org/dc/elements/1.1/'); |
124 | + |
125 | + $oai_dc->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); |
126 | + |
127 | + $oai_dc->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation', $this->formats['oai_dc']['namespace'].' '.$this->formats['oai_dc']['schema']); |
128 | + |
129 | + $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:identifier', htmlspecialchars($metadata['record_id'], ENT_NOQUOTES, 'UTF-8'))); |
130 | + |
131 | + if (!empty($metadata['purl'])) { |
132 | + |
133 | + $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:identifier', htmlspecialchars($metadata['purl'], ENT_NOQUOTES, 'UTF-8'))); |
134 | + |
135 | + } |
136 | + |
137 | + if (!empty($metadata['urn'])) { |
138 | + |
139 | + $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:identifier', htmlspecialchars($metadata['urn'], ENT_NOQUOTES, 'UTF-8'))); |
140 | + |
141 | + } |
142 | + |
143 | + if (!empty($metadata['title'])) { |
144 | + |
145 | + $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:title', htmlspecialchars($metadata['title'], ENT_NOQUOTES, 'UTF-8'))); |
146 | + |
147 | + } |
148 | + |
149 | + if (!empty($metadata['author'])) { |
150 | + |
151 | + $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:creator', htmlspecialchars($metadata['author'], ENT_NOQUOTES, 'UTF-8'))); |
152 | + |
153 | + } |
154 | + |
155 | + if (!empty($metadata['year'])) { |
156 | + |
157 | + $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:date', htmlspecialchars($metadata['year'], ENT_NOQUOTES, 'UTF-8'))); |
158 | + |
159 | + } |
160 | + |
161 | + if (!empty($metadata['place'])) { |
162 | + |
163 | + $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:coverage', htmlspecialchars($metadata['place'], ENT_NOQUOTES, 'UTF-8'))); |
164 | + |
165 | + } |
166 | + |
167 | + $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:format', 'application/mets+xml')); |
168 | + |
169 | + $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:type', 'text')); |
170 | + |
171 | + if (!empty($metadata['partof'])) { |
172 | + |
173 | + $_result = $GLOBALS['TYPO3_DB']->exec_SELECTquery( |
174 | + 'tx_dlf_documents.record_id', |
175 | + 'tx_dlf_documents', |
176 | + 'tx_dlf_documents.uid='.intval($metadata['partof']).tx_dlf_helper::whereClause('tx_dlf_documents'), |
177 | + '', |
178 | + '', |
179 | + '1' |
180 | + ); |
181 | + |
182 | + if ($GLOBALS['TYPO3_DB']->sql_num_rows($_result)) { |
183 | + |
184 | + $_partof = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($_result); |
185 | + |
186 | + $oai_dc->appendChild($this->oai->createElementNS('http://purl.org/dc/elements/1.1/', 'dc:relation', htmlspecialchars($_partof['record_id'], ENT_NOQUOTES, 'UTF-8'))); |
187 | + |
188 | + } |
189 | + |
190 | + } |
191 | + |
192 | + return $oai_dc; |
193 | + |
194 | + } |
195 | + |
196 | + /** |
197 | + * Get epicur data. |
198 | + * @see http://www.persistent-identifier.de/?link=210 |
199 | + * |
200 | + * @access protected |
201 | + * |
202 | + * @param array $metadata: The metadata array |
203 | + * |
204 | + * @return DOMElement XML node to add to the OAI response |
205 | + */ |
206 | + protected function getEpicurData(array $metadata) { |
207 | + |
208 | + // Create epicur element. |
209 | + $epicur = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:epicur'); |
210 | + |
211 | + $epicur->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); |
212 | + |
213 | + $epicur->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation', $this->formats['epicur']['namespace'].' '.$this->formats['epicur']['schema']); |
214 | + |
215 | + // Add administrative data. |
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 | + // Do we update an URN or register a new one? |
223 | + if ($metadata['tstamp'] == $metadata['crdate']) { |
224 | + |
225 | + $update->setAttribute('type', 'urn_new'); |
226 | + |
227 | + } else { |
228 | + |
229 | + $update->setAttribute('type', 'url_update_general'); |
230 | + |
231 | + } |
232 | + |
233 | + $delivery->appendChild($update); |
234 | + |
235 | + $transfer = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:transfer'); |
236 | + |
237 | + $transfer->setAttribute('type', 'http'); |
238 | + |
239 | + $delivery->appendChild($transfer); |
240 | + |
241 | + $admin->appendChild($delivery); |
242 | + |
243 | + $epicur->appendChild($admin); |
244 | + |
245 | + // Add record data. |
246 | + $record = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:record'); |
247 | + |
248 | + $identifier = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:identifier', htmlspecialchars($metadata['urn'], ENT_NOQUOTES, 'UTF-8')); |
249 | + |
250 | + $identifier->setAttribute('scheme', 'urn:nbn:de'); |
251 | + |
252 | + $record->appendChild($identifier); |
253 | + |
254 | + $resource = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:resource'); |
255 | + |
256 | + $ident = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:identifier', htmlspecialchars($metadata['purl'], ENT_NOQUOTES, 'UTF-8')); |
257 | + |
258 | + $ident->setAttribute('scheme', 'url'); |
259 | + |
260 | + $ident->setAttribute('type', 'frontpage'); |
261 | + |
262 | + $ident->setAttribute('role', 'primary'); |
263 | + |
264 | + $resource->appendChild($ident); |
265 | + |
266 | + $format = $this->oai->createElementNS($this->formats['epicur']['namespace'], 'epicur:format', 'text/html'); |
267 | + |
268 | + $format->setAttribute('scheme', 'imt'); |
269 | + |
270 | + $resource->appendChild($format); |
271 | + |
272 | + $record->appendChild($resource); |
273 | + |
274 | + $epicur->appendChild($record); |
275 | + |
276 | + return $epicur; |
277 | + |
278 | + } |
279 | + |
280 | + /** |
281 | + * Get METS data. |
282 | + * @see http://www.loc.gov/standards/mets/docs/mets.v1-7.html |
283 | + * |
284 | + * @access protected |
285 | + * |
286 | + * @param array $metadata: The metadata array |
287 | + * |
288 | + * @return DOMElement XML node to add to the OAI response |
289 | + */ |
290 | + protected function getMetsData(array $metadata) { |
291 | + |
292 | + // Load METS file. |
293 | + $xml = new DOMDocument(); |
294 | + |
295 | + $xml->load($metadata['location']); |
296 | + |
297 | + // Get root element. |
298 | + $root = $xml->getElementsByTagNameNS($this->formats['mets']['namespace'], 'mets'); |
299 | + |
300 | + // Import node into DOMDocument. |
301 | + $mets = $this->oai->importNode($root->item(0), TRUE); |
302 | + |
303 | + return $mets; |
304 | + |
305 | + } |
306 | + |
307 | + /** |
308 | * The main method of the PlugIn |
309 | * |
310 | * @access public |
311 | @@ -174,20 +378,50 @@ |
312 | // Get GET and POST variables. |
313 | $this->getUrlParams(); |
314 | |
315 | - // Load template file. |
316 | - if (!empty($this->conf['templateFile'])) { |
317 | - |
318 | - $this->template = $this->cObj->getSubpart($this->cObj->fileResource($this->conf['templateFile']), '###TEMPLATE###'); |
319 | - |
320 | - } else { |
321 | - |
322 | - $this->template = $this->cObj->getSubpart($this->cObj->fileResource('EXT:dlf/plugins/oai/template.tmpl'), '###TEMPLATE###'); |
323 | - |
324 | - } |
325 | - |
326 | // Delete expired resumption tokens. |
327 | $this->deleteExpiredTokens(); |
328 | |
329 | + // Create XML document. |
330 | + $this->oai = new DOMDocument('1.0', 'utf-8'); |
331 | + |
332 | + // Add processing instruction (aka XSL stylesheet). |
333 | + if (!empty($this->conf['stylesheet'])) { |
334 | + |
335 | + // Resolve "EXT:" prefix in file path. |
336 | + if (substr($this->conf['stylesheet'], 0, 4) == 'EXT:') { |
337 | + |
338 | + list ($_extKey, $_filePath) = explode('/', substr($this->conf['stylesheet'], 4), 2); |
339 | + |
340 | + if (t3lib_extMgm::isLoaded($_extKey)) { |
341 | + |
342 | + $this->conf['stylesheet'] = t3lib_extMgm::siteRelPath($_extKey).$_filePath; |
343 | + |
344 | + } |
345 | + |
346 | + } |
347 | + |
348 | + $_stylesheet = t3lib_div::locationHeaderUrl($this->conf['stylesheet']); |
349 | + |
350 | + } else { |
351 | + |
352 | + // Use default stylesheet if no custom stylesheet is given. |
353 | + $_stylesheet = t3lib_div::locationHeaderUrl(t3lib_extMgm::siteRelPath($this->extKey).'plugins/oai/transform.xsl'); |
354 | + |
355 | + } |
356 | + |
357 | + $this->oai->appendChild($this->oai->createProcessingInstruction('xml-stylesheet', 'type="text/xsl" href="'.htmlspecialchars($_stylesheet, ENT_NOQUOTES, 'UTF-8').'"')); |
358 | + |
359 | + // Create root element. |
360 | + $root = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'OAI-PMH'); |
361 | + |
362 | + $root->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); |
363 | + |
364 | + $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'); |
365 | + |
366 | + // Add response date. |
367 | + $root->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'responseDate', gmdate('Y-m-d\TH:i:s\Z', $GLOBALS['EXEC_TIME']))); |
368 | + |
369 | + // Get response data. |
370 | switch ($this->piVars['verb']) { |
371 | |
372 | case 'GetRecord': |
373 | @@ -232,49 +466,28 @@ |
374 | |
375 | } |
376 | |
377 | - // Set response date, base url and request. |
378 | - $markerArray = array ( |
379 | - '###RESPONSEDATE###' => gmdate('Y-m-d\TH:i:s\Z', $GLOBALS['EXEC_TIME']), |
380 | - '###BASE_URL###' => t3lib_div::locationHeaderUrl($this->pi_getPageLink($GLOBALS['TSFE']->id)), |
381 | - '###REQUEST###' => '' |
382 | - ); |
383 | + // Add request. |
384 | + $request = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'request', htmlspecialchars(t3lib_div::locationHeaderUrl($this->pi_getPageLink($GLOBALS['TSFE']->id)), ENT_NOQUOTES, 'UTF-8')); |
385 | |
386 | if (!$this->error) { |
387 | |
388 | foreach ($this->piVars as $key => $value) { |
389 | |
390 | - $markerArray['###REQUEST###'] .= ' '.$key.'="'.$value.'"'; |
391 | - |
392 | - } |
393 | - |
394 | - } |
395 | - |
396 | - // Set XSL transformation stylesheet. |
397 | - if (!empty($this->conf['stylesheet'])) { |
398 | - |
399 | - // Resolve "EXT:" prefix in file path. |
400 | - if (substr($this->conf['stylesheet'], 0, 4) == 'EXT:') { |
401 | - |
402 | - list ($_extKey, $_filePath) = explode('/', substr($this->conf['stylesheet'], 4), 2); |
403 | - |
404 | - if (t3lib_extMgm::isLoaded($_extKey)) { |
405 | - |
406 | - $this->conf['stylesheet'] = t3lib_extMgm::siteRelPath($_extKey).$_filePath; |
407 | - |
408 | - } |
409 | - |
410 | - } |
411 | - |
412 | - $markerArray['###STYLESHEET###'] = t3lib_div::locationHeaderUrl($this->conf['stylesheet']); |
413 | - |
414 | - } else { |
415 | - |
416 | - $markerArray['###STYLESHEET###'] = t3lib_div::locationHeaderUrl(t3lib_extMgm::siteRelPath($this->extKey).'plugins/oai/transform.xsl'); |
417 | - |
418 | - } |
419 | - |
420 | - // Substitute markers and subparts. |
421 | - $content = trim($this->cObj->substituteSubpart($this->cObj->substituteMarkerArray($this->template, $markerArray), '###RESPONSE###', $response, TRUE)); |
422 | + $request->setAttribute($key, htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8')); |
423 | + |
424 | + } |
425 | + |
426 | + } |
427 | + |
428 | + $root->appendChild($request); |
429 | + |
430 | + // Add response data. |
431 | + $root->appendChild($response); |
432 | + |
433 | + // Build XML output. |
434 | + $this->oai->appendChild($root); |
435 | + |
436 | + $content = $this->oai->saveXML(); |
437 | |
438 | // Send headers. |
439 | header('HTTP/1.1 200 OK'); |
440 | @@ -328,105 +541,15 @@ |
441 | |
442 | $resultSet = unserialize($_resArray['options']); |
443 | |
444 | - // Get template and fill with data. |
445 | - if ($this->piVars['verb'] == 'ListRecords') { |
446 | - |
447 | - $_itemTemplate = $this->cObj->getSubpart($this->template, '###LISTRECORDS_ITEM###'); |
448 | - |
449 | - } else { |
450 | - |
451 | - $_itemTemplate = $this->cObj->getSubpart($this->template, '###LISTIDENTIFIERS_ITEM###'); |
452 | - |
453 | - } |
454 | - |
455 | - $_specTemplate = $this->cObj->getSubpart($_itemTemplate, '###RECORD_SETSPEC_ITEM###'); |
456 | - |
457 | - $_recordTemplate = $this->cObj->getSubpart($_itemTemplate, '###RECORD_METADATA###'); |
458 | - |
459 | - $content = ''; |
460 | - |
461 | $complete = FALSE; |
462 | |
463 | + $todo = array (); |
464 | + |
465 | + $resume = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', $this->piVars['verb']); |
466 | + |
467 | for ($i = $resultSet->metadata['offset'], $j = intval($resultSet->metadata['offset'] + $this->conf['limit']); $i < $j; $i++) { |
468 | |
469 | - $markerArray = array ( |
470 | - '###RECORD_DELETED###' => '', |
471 | - '###RECORD_IDENTIFIER###' => $resultSet->elements[$i]['record_id'], |
472 | - '###RECORD_DATESTAMP###' => gmdate('Y-m-d\TH:i:s\Z', $resultSet->elements[$i]['tstamp']), |
473 | - ); |
474 | - |
475 | - $subpartArray = array ( |
476 | - '###RECORD_SETSPEC_ITEM###' => '', |
477 | - '###RECORD_METADATA###' => '', |
478 | - ); |
479 | - |
480 | - // Check if document is deleted or hidden. |
481 | - $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery( |
482 | - '*', |
483 | - 'tx_dlf_documents', |
484 | - 'tx_dlf_documents.uid='.intval($resultSet->elements[$i]['uid']).tx_dlf_helper::whereClause('tx_dlf_documents'), |
485 | - '', |
486 | - '', |
487 | - '1' |
488 | - ); |
489 | - |
490 | - if ($GLOBALS['TYPO3_DB']->sql_num_rows($result)) { |
491 | - |
492 | - foreach (explode(' ', $resultSet->elements[$i]['collections']) as $_spec) { |
493 | - |
494 | - $subpartArray['###RECORD_SETSPEC_ITEM###'] .= $this->cObj->substituteMarkerArray($_specTemplate, array ('###RECORD_SETSPEC###' => $_spec)); |
495 | - |
496 | - } |
497 | - |
498 | - if ($this->piVars['verb'] == 'ListRecords') { |
499 | - |
500 | - switch ($resultSet->metadata['metadataPrefix']) { |
501 | - |
502 | - case 'oai_dc': |
503 | - |
504 | - // TODO! |
505 | - |
506 | - break; |
507 | - |
508 | - case 'epicur': |
509 | - |
510 | - // TODO! |
511 | - |
512 | - break; |
513 | - |
514 | - case 'ese': |
515 | - |
516 | - // TODO! |
517 | - |
518 | - break; |
519 | - |
520 | - case 'mets': |
521 | - |
522 | - $xml = simplexml_load_file($resultSet->elements[$i]['location']); |
523 | - |
524 | - $xml->registerXPathNamespace('mets', 'http://www.loc.gov/METS/'); |
525 | - |
526 | - $mets = $xml->xpath('//mets:mets'); |
527 | - |
528 | - $recordMarker['###RECORD_XML###'] = trim(str_replace('<?xml version="1.0" encoding="UTF-8"?>', '', $mets[0]->asXML())); |
529 | - |
530 | - break; |
531 | - |
532 | - } |
533 | - |
534 | - $subpartArray['###RECORD_METADATA###'] = $this->cObj->substituteMarkerArray($_recordTemplate, $recordMarker); |
535 | - |
536 | - } |
537 | - |
538 | - } else { |
539 | - |
540 | - $markerArray['###RECORD_DELETED###'] = ' status="deleted"'; |
541 | - |
542 | - } |
543 | - |
544 | - $_content = $this->cObj->substituteSubpartArray($_itemTemplate, $subpartArray); |
545 | - |
546 | - $content .= $this->cObj->substituteMarkerArray($_content, $markerArray); |
547 | + $todo[] = $resultSet->elements[$i]['uid']; |
548 | |
549 | if (empty($resultSet->elements[$i + 1])) { |
550 | |
551 | @@ -438,19 +561,114 @@ |
552 | |
553 | } |
554 | |
555 | + $result = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query( |
556 | + 'tx_dlf_documents.*,GROUP_CONCAT(DISTINCT tx_dlf_collections.oai_name ORDER BY tx_dlf_collections.oai_name SEPARATOR " ") AS collections', |
557 | + 'tx_dlf_documents', |
558 | + 'tx_dlf_relations', |
559 | + 'tx_dlf_collections', |
560 | + 'AND tx_dlf_documents.uid IN ('.implode(',', $GLOBALS['TYPO3_DB']->cleanIntArray($todo)).') AND tx_dlf_documents.pid='.intval($this->conf['pages']).' AND tx_dlf_collections.pid='.intval($this->conf['pages']).$where.tx_dlf_helper::whereClause('tx_dlf_collections'), |
561 | + 'tx_dlf_documents.uid', |
562 | + 'tx_dlf_documents.tstamp', |
563 | + '' |
564 | + ); |
565 | + |
566 | + while ($resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) { |
567 | + |
568 | + // Add header node. |
569 | + $header = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'header'); |
570 | + |
571 | + $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'identifier', htmlspecialchars($resArray['record_id'], ENT_NOQUOTES, 'UTF-8'))); |
572 | + |
573 | + $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'datestamp', gmdate('Y-m-d\TH:i:s\Z', $resArray['tstamp']))); |
574 | + |
575 | + // Check if document is deleted or hidden. |
576 | + // TODO: Use TYPO3 API functions here! |
577 | + if ($resArray['deleted'] || $resArray['hidden']) { |
578 | + |
579 | + // Add "deleted" status. |
580 | + $header->setAttribute('status', 'deleted'); |
581 | + |
582 | + if ($this->piVars['verb'] == 'ListRecords') { |
583 | + |
584 | + // Add record node. |
585 | + $record = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'record'); |
586 | + |
587 | + $record->appendChild($header); |
588 | + |
589 | + $resume->appendChild($record); |
590 | + |
591 | + } elseif ($this->piVars['verb'] == 'ListIdentifiers') { |
592 | + |
593 | + $resume->appendChild($header); |
594 | + |
595 | + } |
596 | + |
597 | + } else { |
598 | + |
599 | + // Add sets. |
600 | + foreach (explode(' ', $resArray['collections']) as $_spec) { |
601 | + |
602 | + $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'setSpec', htmlspecialchars($_spec, ENT_NOQUOTES, 'UTF-8'))); |
603 | + |
604 | + } |
605 | + |
606 | + if ($this->piVars['verb'] == 'ListRecords') { |
607 | + |
608 | + // Add record node. |
609 | + $record = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'record'); |
610 | + |
611 | + $record->appendChild($header); |
612 | + |
613 | + // Add metadata node. |
614 | + $metadata = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'metadata'); |
615 | + |
616 | + switch ($this->piVars['metadataPrefix']) { |
617 | + |
618 | + case 'oai_dc': |
619 | + |
620 | + $metadata->appendChild($this->getDcData($resArray)); |
621 | + |
622 | + break; |
623 | + |
624 | + case 'epicur': |
625 | + |
626 | + $metadata->appendChild($this->getEpicurData($resArray)); |
627 | + |
628 | + break; |
629 | + |
630 | + case 'mets': |
631 | + |
632 | + $metadata->appendChild($this->getMetsData($resArray)); |
633 | + |
634 | + break; |
635 | + |
636 | + } |
637 | + |
638 | + $record->appendChild($metadata); |
639 | + |
640 | + $resume->appendChild($record); |
641 | + |
642 | + } elseif ($this->piVars['verb'] == 'ListIdentifiers') { |
643 | + |
644 | + $resume->appendChild($header); |
645 | + |
646 | + } |
647 | + |
648 | + } |
649 | + |
650 | + } |
651 | + |
652 | if (!$complete) { |
653 | |
654 | // Save result set to database and generate resumption token. |
655 | $token = uniqid(); |
656 | |
657 | - $resumptionToken['###RESUMPTIONTOKEN###'] = '<resumptionToken completeListSize="'.$resultSet->count.'" cursor="'.$resultSet->metadata['offset'].'">'.$token.'</resumptionToken>'; |
658 | - |
659 | $resultSet->metadata = array ( |
660 | 'offset' => intval($resultSet->metadata['offset'] + $this->conf['limit']), |
661 | 'metadataPrefix' => $resultSet->metadata['metadataPrefix'], |
662 | ); |
663 | |
664 | - $GLOBALS['TYPO3_DB']->exec_INSERTquery( |
665 | + $_result = $GLOBALS['TYPO3_DB']->exec_INSERTquery( |
666 | 'tx_dlf_tokens', |
667 | array ( |
668 | 'tstamp' => $GLOBALS['EXEC_TIME'], |
669 | @@ -460,31 +678,30 @@ |
670 | ) |
671 | ); |
672 | |
673 | - } else { |
674 | - |
675 | - // List completed, no new resumption token needed. |
676 | - $resumptionToken['###RESUMPTIONTOKEN###'] = '<resumptionToken completeListSize="'.$resultSet->count.'" cursor="'.$resultSet->metadata['offset'].'" />'; |
677 | - |
678 | - } |
679 | - |
680 | - // Substitute subpart marker. |
681 | - if ($this->piVars['verb'] == 'ListRecords') { |
682 | - |
683 | - $template = $this->cObj->getSubpart($this->template, '###LISTRECORDS###'); |
684 | - |
685 | - $template = $this->cObj->substituteMarkerArray($template, $resumptionToken); |
686 | - |
687 | - return $this->cObj->substituteSubpart($template, '###LISTRECORDS_ITEM###', $content, TRUE); |
688 | - |
689 | - } else { |
690 | - |
691 | - $template = $this->cObj->getSubpart($this->template, '###LISTIDENTIFIERS###'); |
692 | - |
693 | - $template = $this->cObj->substituteMarkerArray($template, $resumptionToken); |
694 | - |
695 | - return $this->cObj->substituteSubpart($template, '###LISTIDENTIFIERS_ITEM###', $content, TRUE); |
696 | - |
697 | - } |
698 | + if ($GLOBALS['TYPO3_DB']->sql_affected_rows($_result) == 1) { |
699 | + |
700 | + $resumptionToken = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'resumptionToken', htmlspecialchars($token, ENT_NOQUOTES, 'UTF-8')); |
701 | + |
702 | + } else { |
703 | + |
704 | + trigger_error('Could not create resumption token', E_USER_ERROR); |
705 | + |
706 | + } |
707 | + |
708 | + } else { |
709 | + |
710 | + // Result set complete. No more resumption token needed. |
711 | + $resumptionToken = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'resumptionToken'); |
712 | + |
713 | + } |
714 | + |
715 | + $resumptionToken->setAttribute('cursor', $resultSet->metadata['offset']); |
716 | + |
717 | + $resumptionToken->setAttribute('completeListSize', $resultSet->count); |
718 | + |
719 | + $resume->appendChild($resumptionToken); |
720 | + |
721 | + return $resume; |
722 | |
723 | } |
724 | |
725 | @@ -520,8 +737,8 @@ |
726 | |
727 | } |
728 | |
729 | - $result = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query( |
730 | - 'tx_dlf_documents.uid AS uid,tx_dlf_documents.record_id AS record_id,tx_dlf_documents.tstamp AS tstamp,tx_dlf_documents.location AS location,GROUP_CONCAT(DISTINCT tx_dlf_collections.oai_name ORDER BY tx_dlf_collections.oai_name SEPARATOR " ") AS collections', |
731 | + $_result = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query( |
732 | + 'tx_dlf_documents.*,GROUP_CONCAT(DISTINCT tx_dlf_collections.oai_name ORDER BY tx_dlf_collections.oai_name SEPARATOR " ") AS collections', |
733 | 'tx_dlf_documents', |
734 | 'tx_dlf_relations', |
735 | 'tx_dlf_collections', |
736 | @@ -531,353 +748,89 @@ |
737 | '1' |
738 | ); |
739 | |
740 | - if (!$GLOBALS['TYPO3_DB']->sql_num_rows($result)) { |
741 | + if (!$GLOBALS['TYPO3_DB']->sql_num_rows($_result)) { |
742 | |
743 | return $this->error('idDoesNotExist'); |
744 | |
745 | } else { |
746 | |
747 | - $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result); |
748 | - |
749 | - // Get template and fill with data. |
750 | - $_itemTemplate = $this->cObj->getSubpart($this->template, '###GETRECORD###'); |
751 | - |
752 | - $_specTemplate = $this->cObj->getSubpart($_itemTemplate, '###RECORD_SETSPEC_ITEM###'); |
753 | - |
754 | - $_recordTemplate = $this->cObj->getSubpart($_itemTemplate, '###RECORD_METADATA###'); |
755 | - |
756 | - $markerArray = array ( |
757 | - '###RECORD_DELETED###' => '', |
758 | - '###RECORD_IDENTIFIER###' => $resArray['record_id'], |
759 | - '###RECORD_DATESTAMP###' => gmdate('Y-m-d\TH:i:s\Z', $resArray['tstamp']), |
760 | - ); |
761 | - |
762 | - $subpartArray = array ( |
763 | - '###RECORD_SETSPEC_ITEM###' => '', |
764 | - '###RECORD_METADATA###' => '', |
765 | - ); |
766 | - |
767 | - // Check if document is deleted or hidden. |
768 | - $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery( |
769 | - '*', |
770 | - 'tx_dlf_documents', |
771 | - 'tx_dlf_documents.uid='.intval($resArray['uid']).tx_dlf_helper::whereClause('tx_dlf_documents'), |
772 | - '', |
773 | - '', |
774 | - '1' |
775 | - ); |
776 | - |
777 | - if ($GLOBALS['TYPO3_DB']->sql_num_rows($result)) { |
778 | + $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($_result); |
779 | + |
780 | + // Check for required fields. |
781 | + foreach ($this->formats[$this->piVars['metadataPrefix']]['requiredFields'] as $required) { |
782 | + |
783 | + if (empty($resArray[$required])) { |
784 | + |
785 | + return $this->error('cannotDisseminateFormat'); |
786 | + |
787 | + } |
788 | + |
789 | + } |
790 | + |
791 | + // Add record node. |
792 | + $GetRecord = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'GetRecord'); |
793 | + |
794 | + $record = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'record'); |
795 | + |
796 | + // Add header node. |
797 | + $header = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'header'); |
798 | + |
799 | + $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'identifier', htmlspecialchars($resArray['record_id'], ENT_NOQUOTES, 'UTF-8'))); |
800 | + |
801 | + $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'datestamp', gmdate('Y-m-d\TH:i:s\Z', $resArray['tstamp']))); |
802 | + |
803 | + // Handle deleted documents. |
804 | + // TODO: Use TYPO3 API functions here! |
805 | + if ($resArray['deleted'] || $resArray['hidden']) { |
806 | + |
807 | + $header->setAttribute('status', 'deleted'); |
808 | + |
809 | + $record->appendChild($header); |
810 | + |
811 | + } else { |
812 | |
813 | foreach (explode(' ', $resArray['collections']) as $_spec) { |
814 | |
815 | - $subpartArray['###RECORD_SETSPEC_ITEM###'] .= $this->cObj->substituteMarkerArray($_specTemplate, array ('###RECORD_SETSPEC###' => $_spec)); |
816 | + $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'setSpec', htmlspecialchars($_spec, ENT_NOQUOTES, 'UTF-8'))); |
817 | |
818 | } |
819 | |
820 | + $record->appendChild($header); |
821 | + |
822 | + // Add metadata node. |
823 | + $metadata = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'metadata'); |
824 | + |
825 | switch ($this->piVars['metadataPrefix']) { |
826 | |
827 | case 'oai_dc': |
828 | |
829 | - // TODO! |
830 | + $metadata->appendChild($this->getDcData($resArray)); |
831 | |
832 | break; |
833 | |
834 | case 'epicur': |
835 | |
836 | - // TODO! |
837 | - |
838 | - break; |
839 | - |
840 | - case 'ese': |
841 | - |
842 | - // TODO! |
843 | + $metadata->appendChild($this->getEpicurData($resArray)); |
844 | |
845 | break; |
846 | |
847 | case 'mets': |
848 | |
849 | - $xml = simplexml_load_file($resArray['location']); |
850 | - |
851 | - $xml->registerXPathNamespace('mets', 'http://www.loc.gov/METS/'); |
852 | - |
853 | - $mets = $xml->xpath('//mets:mets'); |
854 | - |
855 | - $recordMarker['###RECORD_XML###'] = trim(str_replace('<?xml version="1.0" encoding="UTF-8"?>', '', $mets[0]->asXML())); |
856 | + $metadata->appendChild($this->getMetsData($resArray)); |
857 | |
858 | break; |
859 | |
860 | } |
861 | |
862 | - $subpartArray['###RECORD_METADATA###'] = $this->cObj->substituteMarkerArray($_recordTemplate, $recordMarker); |
863 | - |
864 | - } else { |
865 | - |
866 | - $markerArray['###RECORD_DELETED###'] = ' status="deleted"'; |
867 | - |
868 | - } |
869 | - |
870 | - // Substitute subparts and markers. |
871 | - $template = $this->cObj->substituteSubpartArray($_itemTemplate, $subpartArray); |
872 | - |
873 | - return $this->cObj->substituteMarkerArray($template, $markerArray); |
874 | - |
875 | - } |
876 | - |
877 | - } |
878 | - |
879 | - } |
880 | - |
881 | - /** |
882 | - * Process verb "ListIdentifiers" |
883 | - * |
884 | - * @access protected |
885 | - * |
886 | - * @return string Substitution for subpart "###RESPONSE###" |
887 | - */ |
888 | - protected function verbListIdentifiers() { |
889 | - |
890 | - // Check for invalid arguments. |
891 | - if (!empty($this->piVars['resumptionToken'])) { |
892 | - |
893 | - // "resumptionToken" is an exclusive argument. |
894 | - if (count($this->piVars) > 2) { |
895 | - |
896 | - return $this->error('badArgument'); |
897 | - |
898 | - } else { |
899 | - |
900 | - return $this->resume(); |
901 | - |
902 | - } |
903 | - |
904 | - } elseif (empty($this->piVars['metadataPrefix']) || !empty($this->piVars['identifier'])) { |
905 | - |
906 | - // "metadataPrefix" is required and "identifier" is not allowed. |
907 | - return $this->error('badArgument'); |
908 | - |
909 | - } else { |
910 | - |
911 | - $where = ''; |
912 | - |
913 | - // Check "metadataPrefix" for valid value. |
914 | - if (!in_array($this->piVars['metadataPrefix'], array_keys($this->formats))) { |
915 | - |
916 | - return $this->error('cannotDisseminateFormat'); |
917 | - |
918 | - } |
919 | - |
920 | - // Check "set" for valid value. |
921 | - if (!empty($this->piVars['set'])) { |
922 | - |
923 | - // Get set information. |
924 | - $_additionalWhere = ''; |
925 | - |
926 | - if (!$this->conf['show_userdefined']) { |
927 | - |
928 | - $_additionalWhere = ' AND tx_dlf_collections.fe_cruser_id=0'; |
929 | - |
930 | - } |
931 | - |
932 | - $_result = $GLOBALS['TYPO3_DB']->exec_SELECTquery( |
933 | - 'tx_dlf_collections.uid AS uid', |
934 | - 'tx_dlf_collections', |
935 | - 'tx_dlf_collections.pid='.intval($this->conf['pages']).' AND tx_dlf_collections.oai_name='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->piVars['set'], 'tx_dlf_collections').$_additionalWhere.tx_dlf_helper::whereClause('tx_dlf_collections'), |
936 | - '', |
937 | - '', |
938 | - '1' |
939 | - ); |
940 | - |
941 | - if (!$GLOBALS['TYPO3_DB']->sql_num_rows($_result)) { |
942 | - |
943 | - return $this->error('noSetHierarchy'); |
944 | - |
945 | - } else { |
946 | - |
947 | - $_resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($_result); |
948 | - |
949 | - $where .= ' AND tx_dlf_collections.uid='.intval($_resArray['uid']); |
950 | - |
951 | - } |
952 | - |
953 | - } |
954 | - |
955 | - // Check "from" for valid value. |
956 | - if (!empty($this->piVars['from'])) { |
957 | - |
958 | - if (is_array($_from = strptime($this->piVars['from'], '%Y-%m-%dT%H:%M:%SZ')) || is_array($_from = strptime($this->piVars['from'], '%Y-%m-%d'))) { |
959 | - |
960 | - $_from = gmmktime($_from['tm_hour'], $_from['tm_min'], $_from['tm_sec'], $_from['tm_mon'] + 1, $_from['tm_mday'], $_from['tm_year'] + 1900); |
961 | - |
962 | - } else { |
963 | - |
964 | - return $this->error('badArgument'); |
965 | - |
966 | - } |
967 | - |
968 | - $where .= ' AND tx_dlf_documents.tstamp>='.intval($_from); |
969 | - |
970 | - } |
971 | - |
972 | - // Check "until" for valid value. |
973 | - if (!empty($this->piVars['until'])) { |
974 | - |
975 | - if (is_array($_until = strptime($this->piVars['until'], '%Y-%m-%dT%H:%M:%SZ')) || is_array($_until = strptime($this->piVars['until'], '%Y-%m-%d'))) { |
976 | - |
977 | - $_until = gmmktime($_until['tm_hour'], $_until['tm_min'], $_until['tm_sec'], $_until['tm_mon'] + 1, $_until['tm_mday'], $_until['tm_year'] + 1900); |
978 | - |
979 | - } else { |
980 | - |
981 | - return $this->error('badArgument'); |
982 | - |
983 | - } |
984 | - |
985 | - if (!empty($_from) && $_from > $_until) { |
986 | - |
987 | - return $this->error('badArgument'); |
988 | - |
989 | - } |
990 | - |
991 | - $where .= ' AND tx_dlf_documents.tstamp<='.intval($_until); |
992 | - |
993 | - } |
994 | - |
995 | - } |
996 | - |
997 | - // Select records from database. |
998 | - if (!$this->conf['show_userdefined']) { |
999 | - |
1000 | - $where .= ' AND tx_dlf_collections.fe_cruser_id=0'; |
1001 | - |
1002 | - } |
1003 | - |
1004 | - $result = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query( |
1005 | - 'tx_dlf_documents.uid AS uid,tx_dlf_documents.record_id AS record_id,tx_dlf_documents.tstamp AS tstamp,GROUP_CONCAT(DISTINCT tx_dlf_collections.oai_name ORDER BY tx_dlf_collections.oai_name SEPARATOR " ") AS collections', |
1006 | - 'tx_dlf_documents', |
1007 | - 'tx_dlf_relations', |
1008 | - 'tx_dlf_collections', |
1009 | - 'AND tx_dlf_documents.pid='.intval($this->conf['pages']).' AND tx_dlf_collections.pid='.intval($this->conf['pages']).$where.tx_dlf_helper::whereClause('tx_dlf_collections'), |
1010 | - 'tx_dlf_documents.uid', |
1011 | - 'tx_dlf_documents.tstamp', |
1012 | - '' |
1013 | - ); |
1014 | - |
1015 | - if (!$GLOBALS['TYPO3_DB']->sql_num_rows($result)) { |
1016 | - |
1017 | - return $this->error('noRecordsMatch'); |
1018 | - |
1019 | - } else { |
1020 | - |
1021 | - // Build result set. |
1022 | - $results = array (); |
1023 | - |
1024 | - while ($resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) { |
1025 | - |
1026 | - $results[] = $resArray; |
1027 | - |
1028 | - } |
1029 | - |
1030 | - // Save result set as list object. |
1031 | - $resultSet = t3lib_div::makeInstance('tx_dlf_list'); |
1032 | - |
1033 | - $resultSet->reset(); |
1034 | - |
1035 | - $resultSet->add($results); |
1036 | - |
1037 | - // Get template and fill with data. |
1038 | - $_itemTemplate = $this->cObj->getSubpart($this->template, '###LISTIDENTIFIERS_ITEM###'); |
1039 | - |
1040 | - $_specTemplate = $this->cObj->getSubpart($_itemTemplate, '###RECORD_SETSPEC_ITEM###'); |
1041 | - |
1042 | - $content = ''; |
1043 | - |
1044 | - $complete = FALSE; |
1045 | - |
1046 | - for ($i = 0, $j = intval($this->conf['limit']); $i < $j; $i++) { |
1047 | - |
1048 | - $markerArray = array ( |
1049 | - '###RECORD_DELETED###' => '', |
1050 | - '###RECORD_IDENTIFIER###' => $resultSet->elements[$i]['record_id'], |
1051 | - '###RECORD_DATESTAMP###' => gmdate('Y-m-d\TH:i:s\Z', $resultSet->elements[$i]['tstamp']), |
1052 | - ); |
1053 | - |
1054 | - $subpartArray = array ( |
1055 | - '###RECORD_SETSPEC_ITEM###' => '', |
1056 | - ); |
1057 | - |
1058 | - // Check if document is deleted or hidden. |
1059 | - $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery( |
1060 | - '*', |
1061 | - 'tx_dlf_documents', |
1062 | - 'tx_dlf_documents.uid='.intval($resultSet->elements[$i]['uid']).tx_dlf_helper::whereClause('tx_dlf_documents'), |
1063 | - '', |
1064 | - '', |
1065 | - '1' |
1066 | - ); |
1067 | - |
1068 | - if ($GLOBALS['TYPO3_DB']->sql_num_rows($result)) { |
1069 | - |
1070 | - foreach (explode(' ', $resultSet->elements[$i]['collections']) as $_spec) { |
1071 | - |
1072 | - $subpartArray['###RECORD_SETSPEC_ITEM###'] .= $this->cObj->substituteMarkerArray($_specTemplate, array ('###RECORD_SETSPEC###' => $_spec)); |
1073 | - |
1074 | - } |
1075 | - |
1076 | - } else { |
1077 | - |
1078 | - $markerArray['###RECORD_DELETED###'] = ' status="deleted"'; |
1079 | - |
1080 | - } |
1081 | - |
1082 | - $_content = $this->cObj->substituteSubpartArray($_itemTemplate, $subpartArray); |
1083 | - |
1084 | - $content .= $this->cObj->substituteMarkerArray($_content, $markerArray); |
1085 | - |
1086 | - if (empty($resultSet->elements[$i + 1])) { |
1087 | - |
1088 | - $complete = TRUE; |
1089 | - |
1090 | - break; |
1091 | - |
1092 | - } |
1093 | - |
1094 | - } |
1095 | - |
1096 | - if (!$complete) { |
1097 | - |
1098 | - // Save result set to database and generate resumption token. |
1099 | - $token = uniqid(); |
1100 | - |
1101 | - $resumptionToken['###RESUMPTIONTOKEN###'] = '<resumptionToken completeListSize="'.$resultSet->count.'" cursor="0">'.$token.'</resumptionToken>'; |
1102 | - |
1103 | - $resultSet->metadata = array ( |
1104 | - 'offset' => intval($this->conf['limit']), |
1105 | - 'metadataPrefix' => $this->piVars['metadataPrefix'], |
1106 | - ); |
1107 | - |
1108 | - $GLOBALS['TYPO3_DB']->exec_INSERTquery( |
1109 | - 'tx_dlf_tokens', |
1110 | - array ( |
1111 | - 'tstamp' => $GLOBALS['EXEC_TIME'], |
1112 | - 'token' => $token, |
1113 | - 'options' => serialize($resultSet), |
1114 | - 'ident' => 'oai', |
1115 | - ) |
1116 | - ); |
1117 | - |
1118 | - } else { |
1119 | - |
1120 | - // Complete list returned, no resumption token needed. |
1121 | - $resumptionToken['###RESUMPTIONTOKEN###'] = ''; |
1122 | - |
1123 | - } |
1124 | - |
1125 | - // Substitute subpart marker. |
1126 | - $template = $this->cObj->getSubpart($this->template, '###LISTIDENTIFIERS###'); |
1127 | - |
1128 | - $template = $this->cObj->substituteMarkerArray($template, $resumptionToken); |
1129 | - |
1130 | - return $this->cObj->substituteSubpart($template, '###LISTIDENTIFIERS_ITEM###', $content, TRUE); |
1131 | + $record->appendChild($metadata); |
1132 | + |
1133 | + } |
1134 | + |
1135 | + $GetRecord->appendChild($record); |
1136 | + |
1137 | + return $GetRecord; |
1138 | + |
1139 | + } |
1140 | |
1141 | } |
1142 | |
1143 | @@ -888,7 +841,7 @@ |
1144 | * |
1145 | * @access protected |
1146 | * |
1147 | - * @return string Substitution for subpart "###RESPONSE###" |
1148 | + * @return DOMElement XML node to add to the OAI response |
1149 | */ |
1150 | protected function verbIdentify() { |
1151 | |
1152 | @@ -913,12 +866,49 @@ |
1153 | |
1154 | $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($_result); |
1155 | |
1156 | - $markerArray = array ( |
1157 | - '###IDENTIFY_NAME###' => htmlspecialchars($resArray['oai_label'], ENT_NOQUOTES, 'UTF-8'), |
1158 | - '###IDENTIFY_URL###' => t3lib_div::locationHeaderUrl($this->pi_getPageLink($GLOBALS['TSFE']->id)), |
1159 | - '###IDENTIFY_MAIL###' => trim(str_replace('mailto:', '', $resArray['contact'])) |
1160 | + // Get earliest datestamp. |
1161 | + $_result = $GLOBALS['TYPO3_DB']->exec_SELECTquery( |
1162 | + 'tx_dlf_documents.tstamp AS tstamp', |
1163 | + 'tx_dlf_documents', |
1164 | + 'tx_dlf_documents.pid='.intval($this->conf['pages']), |
1165 | + '', |
1166 | + 'tx_dlf_documents.tstamp ASC', |
1167 | + '1' |
1168 | ); |
1169 | |
1170 | + if ($GLOBALS['TYPO3_DB']->sql_num_rows($_result)) { |
1171 | + |
1172 | + list ($_timestamp) = $GLOBALS['TYPO3_DB']->sql_fetch_row($_result); |
1173 | + |
1174 | + $datestamp = gmdate('Y-m-d\TH:i:s\Z', $_timestamp); |
1175 | + |
1176 | + } else { |
1177 | + |
1178 | + $datestamp = '0000-00-00T00:00:00Z'; |
1179 | + |
1180 | + trigger_error('No records found with PID '.$this->conf['pages'], E_USER_WARNING); |
1181 | + |
1182 | + } |
1183 | + |
1184 | + // Add identification node. |
1185 | + $Identify = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'Identify'); |
1186 | + |
1187 | + $Identify->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'repositoryName', htmlspecialchars($resArray['oai_label'], ENT_NOQUOTES, 'UTF-8'))); |
1188 | + |
1189 | + $Identify->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'baseURL', htmlspecialchars(t3lib_div::locationHeaderUrl($this->pi_getPageLink($GLOBALS['TSFE']->id)), ENT_NOQUOTES, 'UTF-8'))); |
1190 | + |
1191 | + $Identify->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'protocolVersion', '2.0')); |
1192 | + |
1193 | + $Identify->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'adminEmail', htmlspecialchars(trim(str_replace('mailto:', '', $resArray['contact'])), ENT_NOQUOTES, 'UTF-8'))); |
1194 | + |
1195 | + $Identify->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'earliestDatestamp', $datestamp)); |
1196 | + |
1197 | + $Identify->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'deletedRecord', 'transient')); |
1198 | + |
1199 | + $Identify->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'granularity', 'YYYY-MM-DDThh:mm:ssZ')); |
1200 | + |
1201 | + return $Identify; |
1202 | + |
1203 | } else { |
1204 | |
1205 | trigger_error('OAI interface needs more configuration', E_USER_ERROR); |
1206 | @@ -927,32 +917,280 @@ |
1207 | |
1208 | } |
1209 | |
1210 | - // Get earliest datestamp. |
1211 | - $_result = $GLOBALS['TYPO3_DB']->exec_SELECTquery( |
1212 | - 'tx_dlf_documents.tstamp AS tstamp', |
1213 | + } |
1214 | + |
1215 | + /** |
1216 | + * Process verb "ListIdentifiers" |
1217 | + * |
1218 | + * @access protected |
1219 | + * |
1220 | + * @return string Substitution for subpart "###RESPONSE###" |
1221 | + */ |
1222 | + protected function verbListIdentifiers() { |
1223 | + |
1224 | + // Check for invalid arguments. |
1225 | + if (!empty($this->piVars['resumptionToken'])) { |
1226 | + |
1227 | + // "resumptionToken" is an exclusive argument. |
1228 | + if (count($this->piVars) > 2) { |
1229 | + |
1230 | + return $this->error('badArgument'); |
1231 | + |
1232 | + } else { |
1233 | + |
1234 | + return $this->resume(); |
1235 | + |
1236 | + } |
1237 | + |
1238 | + } elseif (empty($this->piVars['metadataPrefix']) || !empty($this->piVars['identifier'])) { |
1239 | + |
1240 | + // "metadataPrefix" is required and "identifier" is not allowed. |
1241 | + return $this->error('badArgument'); |
1242 | + |
1243 | + } else { |
1244 | + |
1245 | + $where = ''; |
1246 | + |
1247 | + // Check "metadataPrefix" for valid value. |
1248 | + if (!in_array($this->piVars['metadataPrefix'], array_keys($this->formats))) { |
1249 | + |
1250 | + return $this->error('cannotDisseminateFormat'); |
1251 | + |
1252 | + } |
1253 | + |
1254 | + // Check "set" for valid value. |
1255 | + if (!empty($this->piVars['set'])) { |
1256 | + |
1257 | + // Get set information. |
1258 | + $_additionalWhere = ''; |
1259 | + |
1260 | + if (!$this->conf['show_userdefined']) { |
1261 | + |
1262 | + $_additionalWhere = ' AND tx_dlf_collections.fe_cruser_id=0'; |
1263 | + |
1264 | + } |
1265 | + |
1266 | + $_result = $GLOBALS['TYPO3_DB']->exec_SELECTquery( |
1267 | + 'tx_dlf_collections.uid AS uid', |
1268 | + 'tx_dlf_collections', |
1269 | + 'tx_dlf_collections.pid='.intval($this->conf['pages']).' AND tx_dlf_collections.oai_name='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->piVars['set'], 'tx_dlf_collections').$_additionalWhere.tx_dlf_helper::whereClause('tx_dlf_collections'), |
1270 | + '', |
1271 | + '', |
1272 | + '1' |
1273 | + ); |
1274 | + |
1275 | + if (!$GLOBALS['TYPO3_DB']->sql_num_rows($_result)) { |
1276 | + |
1277 | + return $this->error('noSetHierarchy'); |
1278 | + |
1279 | + } else { |
1280 | + |
1281 | + $_resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($_result); |
1282 | + |
1283 | + $where .= ' AND tx_dlf_collections.uid='.intval($_resArray['uid']); |
1284 | + |
1285 | + } |
1286 | + |
1287 | + } |
1288 | + |
1289 | + // Check "from" for valid value. |
1290 | + if (!empty($this->piVars['from'])) { |
1291 | + |
1292 | + if (is_array($_from = strptime($this->piVars['from'], '%Y-%m-%dT%H:%M:%SZ')) || is_array($_from = strptime($this->piVars['from'], '%Y-%m-%d'))) { |
1293 | + |
1294 | + $_from = gmmktime($_from['tm_hour'], $_from['tm_min'], $_from['tm_sec'], $_from['tm_mon'] + 1, $_from['tm_mday'], $_from['tm_year'] + 1900); |
1295 | + |
1296 | + } else { |
1297 | + |
1298 | + return $this->error('badArgument'); |
1299 | + |
1300 | + } |
1301 | + |
1302 | + $where .= ' AND tx_dlf_documents.tstamp>='.intval($_from); |
1303 | + |
1304 | + } |
1305 | + |
1306 | + // Check "until" for valid value. |
1307 | + if (!empty($this->piVars['until'])) { |
1308 | + |
1309 | + if (is_array($_until = strptime($this->piVars['until'], '%Y-%m-%dT%H:%M:%SZ')) || is_array($_until = strptime($this->piVars['until'], '%Y-%m-%d'))) { |
1310 | + |
1311 | + $_until = gmmktime($_until['tm_hour'], $_until['tm_min'], $_until['tm_sec'], $_until['tm_mon'] + 1, $_until['tm_mday'], $_until['tm_year'] + 1900); |
1312 | + |
1313 | + } else { |
1314 | + |
1315 | + return $this->error('badArgument'); |
1316 | + |
1317 | + } |
1318 | + |
1319 | + if (!empty($_from) && $_from > $_until) { |
1320 | + |
1321 | + return $this->error('badArgument'); |
1322 | + |
1323 | + } |
1324 | + |
1325 | + $where .= ' AND tx_dlf_documents.tstamp<='.intval($_until); |
1326 | + |
1327 | + } |
1328 | + |
1329 | + // Check "from" and "until" for same granularity. |
1330 | + if (!empty($this->piVars['from']) && !empty($this->piVars['until'])) { |
1331 | + |
1332 | + if (strlen($this->piVars['from']) != strlen($this->piVars['until'])) { |
1333 | + |
1334 | + return $this->error('badArgument'); |
1335 | + |
1336 | + } |
1337 | + |
1338 | + } |
1339 | + |
1340 | + } |
1341 | + |
1342 | + // Select records from database. |
1343 | + if (!$this->conf['show_userdefined']) { |
1344 | + |
1345 | + $where .= ' AND tx_dlf_collections.fe_cruser_id=0'; |
1346 | + |
1347 | + } |
1348 | + |
1349 | + $result = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query( |
1350 | + 'tx_dlf_documents.*,GROUP_CONCAT(DISTINCT tx_dlf_collections.oai_name ORDER BY tx_dlf_collections.oai_name SEPARATOR " ") AS collections', |
1351 | 'tx_dlf_documents', |
1352 | - 'tx_dlf_documents.pid='.intval($this->conf['pages']), |
1353 | - '', |
1354 | - 'tx_dlf_documents.tstamp ASC', |
1355 | - '1' |
1356 | + 'tx_dlf_relations', |
1357 | + 'tx_dlf_collections', |
1358 | + 'AND tx_dlf_documents.pid='.intval($this->conf['pages']).' AND tx_dlf_collections.pid='.intval($this->conf['pages']).$where.tx_dlf_helper::whereClause('tx_dlf_collections'), |
1359 | + 'tx_dlf_documents.uid', |
1360 | + 'tx_dlf_documents.tstamp', |
1361 | + '' |
1362 | ); |
1363 | |
1364 | - if ($GLOBALS['TYPO3_DB']->sql_num_rows($_result)) { |
1365 | - |
1366 | - $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($_result); |
1367 | - |
1368 | - $markerArray['###IDENTIFY_DATE###'] = gmdate('Y-m-d\TH:i:s\Z', $resArray['tstamp']); |
1369 | + if (!$GLOBALS['TYPO3_DB']->sql_num_rows($result)) { |
1370 | + |
1371 | + return $this->error('noRecordsMatch'); |
1372 | |
1373 | } else { |
1374 | |
1375 | - $markerArray['###IDENTIFY_DATE###'] = '0000-00-00T00:00:00Z'; |
1376 | - |
1377 | - trigger_error('No records found with PID '.$this->conf['pages'], E_USER_WARNING); |
1378 | + // Build result set. |
1379 | + $results = array (); |
1380 | + |
1381 | + while ($resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) { |
1382 | + |
1383 | + // Check for required fields. |
1384 | + foreach ($this->formats[$this->piVars['metadataPrefix']]['requiredFields'] as $required) { |
1385 | + |
1386 | + if (empty($resArray[$required])) { |
1387 | + |
1388 | + // Skip documents with missing required fields. |
1389 | + continue 2; |
1390 | + |
1391 | + } |
1392 | + |
1393 | + } |
1394 | + |
1395 | + $results[] = $resArray; |
1396 | + |
1397 | + // Save only UIDs for resumption token. |
1398 | + $results['resumptionList'][] = array ('uid' => $resArray['uid']); |
1399 | + |
1400 | + } |
1401 | + |
1402 | + if (empty($results)) { |
1403 | + |
1404 | + return $this->error('noRecordsMatch'); |
1405 | + |
1406 | + } |
1407 | + |
1408 | + $complete = FALSE; |
1409 | + |
1410 | + $ListIdentifiers = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'ListIdentifiers'); |
1411 | + |
1412 | + for ($i = 0, $j = intval($this->conf['limit']); $i < $j; $i++) { |
1413 | + |
1414 | + $header = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'header'); |
1415 | + |
1416 | + $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'identifier', htmlspecialchars($results[$i]['record_id'], ENT_NOQUOTES, 'UTF-8'))); |
1417 | + |
1418 | + $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'datestamp', gmdate('Y-m-d\TH:i:s\Z', $results[$i]['tstamp']))); |
1419 | + |
1420 | + // Check if document is deleted or hidden. |
1421 | + // TODO: Use TYPO3 API functions here! |
1422 | + if ($results[$i]['deleted'] || $results[$i]['hidden']) { |
1423 | + |
1424 | + // Add "deleted" status. |
1425 | + $header->setAttribute('status', 'deleted'); |
1426 | + |
1427 | + } else { |
1428 | + |
1429 | + // Add sets. |
1430 | + foreach (explode(' ', $results[$i]['collections']) as $_spec) { |
1431 | + |
1432 | + $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'setSpec', htmlspecialchars($_spec, ENT_NOQUOTES, 'UTF-8'))); |
1433 | + |
1434 | + } |
1435 | + |
1436 | + } |
1437 | + |
1438 | + $ListIdentifiers->appendChild($header); |
1439 | + |
1440 | + if (empty($results[$i + 1])) { |
1441 | + |
1442 | + $complete = TRUE; |
1443 | + |
1444 | + break; |
1445 | + |
1446 | + } |
1447 | + |
1448 | + } |
1449 | + |
1450 | + if (!$complete) { |
1451 | + |
1452 | + // Save result set as list object. |
1453 | + $resultSet = t3lib_div::makeInstance('tx_dlf_list'); |
1454 | + |
1455 | + $resultSet->reset(); |
1456 | + |
1457 | + $resultSet->add($results['resumptionList']); |
1458 | + |
1459 | + // Save result set to database and generate resumption token. |
1460 | + $token = uniqid(); |
1461 | + |
1462 | + $resultSet->metadata = array ( |
1463 | + 'offset' => intval($this->conf['limit']), |
1464 | + 'metadataPrefix' => $this->piVars['metadataPrefix'], |
1465 | + ); |
1466 | + |
1467 | + $_result = $GLOBALS['TYPO3_DB']->exec_INSERTquery( |
1468 | + 'tx_dlf_tokens', |
1469 | + array ( |
1470 | + 'tstamp' => $GLOBALS['EXEC_TIME'], |
1471 | + 'token' => $token, |
1472 | + 'options' => serialize($resultSet), |
1473 | + 'ident' => 'oai', |
1474 | + ) |
1475 | + ); |
1476 | + |
1477 | + if ($GLOBALS['TYPO3_DB']->sql_affected_rows($_result) == 1) { |
1478 | + |
1479 | + $resumptionToken = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'resumptionToken', htmlspecialchars($token, ENT_NOQUOTES, 'UTF-8')); |
1480 | + |
1481 | + $resumptionToken->setAttribute('cursor', '0'); |
1482 | + |
1483 | + $resumptionToken->setAttribute('completeListSize', $resultSet->count); |
1484 | + |
1485 | + $ListIdentifiers->appendChild($resumptionToken); |
1486 | + |
1487 | + } else { |
1488 | + |
1489 | + trigger_error('Could not create resumption token', E_USER_ERROR); |
1490 | + |
1491 | + } |
1492 | + |
1493 | + } |
1494 | + |
1495 | + return $ListIdentifiers; |
1496 | |
1497 | } |
1498 | |
1499 | - return $this->cObj->substituteMarkerArray($this->cObj->getSubpart($this->template, '###IDENTIFY###'), $markerArray); |
1500 | - |
1501 | } |
1502 | |
1503 | /** |
1504 | @@ -960,10 +1198,12 @@ |
1505 | * |
1506 | * @access protected |
1507 | * |
1508 | - * @return string Substitution for subpart "###RESPONSE###" |
1509 | + * @return DOMElement XML node to add to the OAI response |
1510 | */ |
1511 | protected function verbListMetadataFormats() { |
1512 | |
1513 | + $resArray = array (); |
1514 | + |
1515 | // Check for invalid arguments. |
1516 | if (count($this->piVars) > 1) { |
1517 | |
1518 | @@ -987,30 +1227,51 @@ |
1519 | |
1520 | return $this->error('idDoesNotExist'); |
1521 | |
1522 | + } else { |
1523 | + |
1524 | + $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result); |
1525 | + |
1526 | } |
1527 | |
1528 | } |
1529 | |
1530 | } |
1531 | |
1532 | - // Get template and fill with data. |
1533 | - $_itemTemplate = $this->cObj->getSubpart($this->template, '###LISTMETADATAFORMATS_ITEM###'); |
1534 | - |
1535 | - $content = ''; |
1536 | + // Add metadata formats node. |
1537 | + $ListMetadaFormats = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'ListMetadataFormats'); |
1538 | |
1539 | foreach ($this->formats as $prefix => $details) { |
1540 | |
1541 | - $markerArray = array ( |
1542 | - '###LISTMETADATAFORMATS_PREFIX###' => $prefix, |
1543 | - '###LISTMETADATAFORMATS_SCHEMA###' => $details['schema'], |
1544 | - '###LISTMETADATAFORMATS_NAMESPACE###' => $details['namespace'] |
1545 | - ); |
1546 | - |
1547 | - $content .= $this->cObj->substituteMarkerArray($_itemTemplate, $markerArray); |
1548 | + // Check for required fields. |
1549 | + if (!empty($resArray)) { |
1550 | + |
1551 | + foreach ($details['requiredFields'] as $required) { |
1552 | + |
1553 | + if (empty($resArray[$required])) { |
1554 | + |
1555 | + // Skip metadata formats whose requirements are not met. |
1556 | + continue 2; |
1557 | + |
1558 | + } |
1559 | + |
1560 | + } |
1561 | + |
1562 | + } |
1563 | + |
1564 | + // Add format node. |
1565 | + $format = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'metadataFormat'); |
1566 | + |
1567 | + $format->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'metadataPrefix', htmlspecialchars($prefix, ENT_NOQUOTES, 'UTF-8'))); |
1568 | + |
1569 | + $format->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'schema', htmlspecialchars($details['schema'], ENT_NOQUOTES, 'UTF-8'))); |
1570 | + |
1571 | + $format->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'metadataNamespace', htmlspecialchars($details['namespace'], ENT_NOQUOTES, 'UTF-8'))); |
1572 | + |
1573 | + $ListMetadaFormats->appendChild($format); |
1574 | |
1575 | } |
1576 | |
1577 | - return $this->cObj->substituteSubpart($this->cObj->getSubpart($this->template, '###LISTMETADATAFORMATS###'), '###LISTMETADATAFORMATS_ITEM###', $content, TRUE); |
1578 | + return $ListMetadaFormats; |
1579 | |
1580 | } |
1581 | |
1582 | @@ -1128,6 +1389,17 @@ |
1583 | |
1584 | } |
1585 | |
1586 | + // Check "from" and "until" for same granularity. |
1587 | + if (!empty($this->piVars['from']) && !empty($this->piVars['until'])) { |
1588 | + |
1589 | + if (strlen($this->piVars['from']) != strlen($this->piVars['until'])) { |
1590 | + |
1591 | + return $this->error('badArgument'); |
1592 | + |
1593 | + } |
1594 | + |
1595 | + } |
1596 | + |
1597 | } |
1598 | |
1599 | // Select records from database. |
1600 | @@ -1138,7 +1410,7 @@ |
1601 | } |
1602 | |
1603 | $result = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query( |
1604 | - 'tx_dlf_documents.uid AS uid,tx_dlf_documents.record_id AS record_id,tx_dlf_documents.tstamp AS tstamp,tx_dlf_documents.location AS location,GROUP_CONCAT(DISTINCT tx_dlf_collections.oai_name ORDER BY tx_dlf_collections.oai_name SEPARATOR " ") AS collections', |
1605 | + 'tx_dlf_documents.*,GROUP_CONCAT(DISTINCT tx_dlf_collections.oai_name ORDER BY tx_dlf_collections.oai_name SEPARATOR " ") AS collections', |
1606 | 'tx_dlf_documents', |
1607 | 'tx_dlf_relations', |
1608 | 'tx_dlf_collections', |
1609 | @@ -1159,106 +1431,92 @@ |
1610 | |
1611 | while ($resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) { |
1612 | |
1613 | + foreach ($this->formats[$this->piVars['metadataPrefix']]['requiredFields'] as $required) { |
1614 | + |
1615 | + if (empty($resArray[$required])) { |
1616 | + |
1617 | + // Skip records which do not meet the requirements. |
1618 | + continue 2; |
1619 | + |
1620 | + } |
1621 | + |
1622 | + } |
1623 | + |
1624 | $results[] = $resArray; |
1625 | |
1626 | + // Save only UIDs for resumption token. |
1627 | + $results['resumptionList'][] = array ('uid' => $resArray['uid']); |
1628 | + |
1629 | } |
1630 | |
1631 | - // Save result set as list object. |
1632 | - $resultSet = t3lib_div::makeInstance('tx_dlf_list'); |
1633 | - |
1634 | - $resultSet->reset(); |
1635 | - |
1636 | - $resultSet->add($results); |
1637 | - |
1638 | - // Get template and fill with data. |
1639 | - $_itemTemplate = $this->cObj->getSubpart($this->template, '###LISTRECORDS_ITEM###'); |
1640 | - |
1641 | - $_specTemplate = $this->cObj->getSubpart($_itemTemplate, '###RECORD_SETSPEC_ITEM###'); |
1642 | - |
1643 | - $_recordTemplate = $this->cObj->getSubpart($_itemTemplate, '###RECORD_METADATA###'); |
1644 | - |
1645 | - $content = ''; |
1646 | - |
1647 | $complete = FALSE; |
1648 | |
1649 | + $ListRecords = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'ListRecords'); |
1650 | + |
1651 | for ($i = 0, $j = intval($this->conf['limit']); $i < $j; $i++) { |
1652 | |
1653 | - $markerArray = array ( |
1654 | - '###RECORD_DELETED###' => '', |
1655 | - '###RECORD_IDENTIFIER###' => $resultSet->elements[$i]['record_id'], |
1656 | - '###RECORD_DATESTAMP###' => gmdate('Y-m-d\TH:i:s\Z', $resultSet->elements[$i]['tstamp']), |
1657 | - ); |
1658 | - |
1659 | - $subpartArray = array ( |
1660 | - '###RECORD_SETSPEC_ITEM###' => '', |
1661 | - '###RECORD_METADATA###' => '', |
1662 | - ); |
1663 | + // Add record node. |
1664 | + $record = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'record'); |
1665 | + |
1666 | + // Add header node. |
1667 | + $header = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'header'); |
1668 | + |
1669 | + $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'identifier', htmlspecialchars($results[$i]['record_id'], ENT_NOQUOTES, 'UTF-8'))); |
1670 | + |
1671 | + $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'datestamp', gmdate('Y-m-d\TH:i:s\Z', $results[$i]['tstamp']))); |
1672 | |
1673 | // Check if document is deleted or hidden. |
1674 | - $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery( |
1675 | - '*', |
1676 | - 'tx_dlf_documents', |
1677 | - 'tx_dlf_documents.uid='.intval($resultSet->elements[$i]['uid']).tx_dlf_helper::whereClause('tx_dlf_documents'), |
1678 | - '', |
1679 | - '', |
1680 | - '1' |
1681 | - ); |
1682 | - |
1683 | - if ($GLOBALS['TYPO3_DB']->sql_num_rows($result)) { |
1684 | - |
1685 | - foreach (explode(' ', $resultSet->elements[$i]['collections']) as $_spec) { |
1686 | - |
1687 | - $subpartArray['###RECORD_SETSPEC_ITEM###'] .= $this->cObj->substituteMarkerArray($_specTemplate, array ('###RECORD_SETSPEC###' => $_spec)); |
1688 | + // TODO: Use TYPO3 API functions here! |
1689 | + if ($results[$i]['deleted'] || $results[$i]['hidden']) { |
1690 | + |
1691 | + // Add "deleted" status. |
1692 | + $header->setAttribute('status', 'deleted'); |
1693 | + |
1694 | + $record->appendChild($header); |
1695 | + |
1696 | + } else { |
1697 | + |
1698 | + // Add sets. |
1699 | + foreach (explode(' ', $results[$i]['collections']) as $_spec) { |
1700 | + |
1701 | + $header->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'setSpec', htmlspecialchars($_spec, ENT_NOQUOTES, 'UTF-8'))); |
1702 | |
1703 | } |
1704 | |
1705 | + $record->appendChild($header); |
1706 | + |
1707 | + // Add metadata node. |
1708 | + $metadata = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'metadata'); |
1709 | + |
1710 | switch ($this->piVars['metadataPrefix']) { |
1711 | |
1712 | case 'oai_dc': |
1713 | |
1714 | - // TODO! |
1715 | + $metadata->appendChild($this->getDcData($results[$i])); |
1716 | |
1717 | break; |
1718 | |
1719 | case 'epicur': |
1720 | |
1721 | - // TODO! |
1722 | - |
1723 | - break; |
1724 | - |
1725 | - case 'ese': |
1726 | - |
1727 | - // TODO! |
1728 | + $metadata->appendChild($this->getEpicurData($results[$i])); |
1729 | |
1730 | break; |
1731 | |
1732 | case 'mets': |
1733 | |
1734 | - $xml = simplexml_load_file($resultSet->elements[$i]['location']); |
1735 | - |
1736 | - $xml->registerXPathNamespace('mets', 'http://www.loc.gov/METS/'); |
1737 | - |
1738 | - $mets = $xml->xpath('//mets:mets'); |
1739 | - |
1740 | - $recordMarker['###RECORD_XML###'] = trim(str_replace('<?xml version="1.0" encoding="UTF-8"?>', '', $mets[0]->asXML())); |
1741 | + $metadata->appendChild($this->getMetsData($results[$i])); |
1742 | |
1743 | break; |
1744 | |
1745 | } |
1746 | |
1747 | - $subpartArray['###RECORD_METADATA###'] = $this->cObj->substituteMarkerArray($_recordTemplate, $recordMarker); |
1748 | - |
1749 | - } else { |
1750 | - |
1751 | - $markerArray['###RECORD_DELETED###'] = ' status="deleted"'; |
1752 | + $record->appendChild($metadata); |
1753 | |
1754 | } |
1755 | |
1756 | - $_content = $this->cObj->substituteSubpartArray($_itemTemplate, $subpartArray); |
1757 | - |
1758 | - $content .= $this->cObj->substituteMarkerArray($_content, $markerArray); |
1759 | - |
1760 | - if (empty($resultSet->elements[$i + 1])) { |
1761 | + $ListRecords->appendChild($record); |
1762 | + |
1763 | + if (empty($results[$i + 1])) { |
1764 | |
1765 | $complete = TRUE; |
1766 | |
1767 | @@ -1270,17 +1528,22 @@ |
1768 | |
1769 | if (!$complete) { |
1770 | |
1771 | + // Save result set as list object. |
1772 | + $resultSet = t3lib_div::makeInstance('tx_dlf_list'); |
1773 | + |
1774 | + $resultSet->reset(); |
1775 | + |
1776 | + $resultSet->add($results['resumptionList']); |
1777 | + |
1778 | // Save result set to database and generate resumption token. |
1779 | $token = uniqid(); |
1780 | |
1781 | - $resumptionToken['###RESUMPTIONTOKEN###'] = '<resumptionToken completeListSize="'.$resultSet->count.'" cursor="0">'.$token.'</resumptionToken>'; |
1782 | - |
1783 | $resultSet->metadata = array ( |
1784 | 'offset' => intval($this->conf['limit']), |
1785 | 'metadataPrefix' => $this->piVars['metadataPrefix'], |
1786 | ); |
1787 | |
1788 | - $GLOBALS['TYPO3_DB']->exec_INSERTquery( |
1789 | + $_result = $GLOBALS['TYPO3_DB']->exec_INSERTquery( |
1790 | 'tx_dlf_tokens', |
1791 | array ( |
1792 | 'tstamp' => $GLOBALS['EXEC_TIME'], |
1793 | @@ -1290,19 +1553,25 @@ |
1794 | ) |
1795 | ); |
1796 | |
1797 | - } else { |
1798 | - |
1799 | - // Complete list returned, no resumption token needed. |
1800 | - $resumptionToken['###RESUMPTIONTOKEN###'] = ''; |
1801 | + if ($GLOBALS['TYPO3_DB']->sql_affected_rows($_result) == 1) { |
1802 | + |
1803 | + $resumptionToken = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'resumptionToken', htmlspecialchars($token, ENT_NOQUOTES, 'UTF-8')); |
1804 | + |
1805 | + $resumptionToken->setAttribute('cursor', '0'); |
1806 | + |
1807 | + $resumptionToken->setAttribute('completeListSize', $resultSet->count); |
1808 | + |
1809 | + $ListRecords->appendChild($resumptionToken); |
1810 | + |
1811 | + } else { |
1812 | + |
1813 | + trigger_error('Could not create resumption token', E_USER_ERROR); |
1814 | + |
1815 | + } |
1816 | |
1817 | } |
1818 | |
1819 | - // Substitute subpart marker. |
1820 | - $template = $this->cObj->getSubpart($this->template, '###LISTRECORDS###'); |
1821 | - |
1822 | - $template = $this->cObj->substituteMarkerArray($template, $resumptionToken); |
1823 | - |
1824 | - return $this->cObj->substituteSubpart($template, '###LISTRECORDS_ITEM###', $content, TRUE); |
1825 | + return $ListRecords; |
1826 | |
1827 | } |
1828 | |
1829 | @@ -1356,23 +1625,23 @@ |
1830 | |
1831 | } |
1832 | |
1833 | - // Get template and fill with data. |
1834 | - $_itemTemplate = $this->cObj->getSubpart($this->template, '###LISTSETS_ITEM###'); |
1835 | - |
1836 | - $content = ''; |
1837 | + // Add set list node. |
1838 | + $ListSets = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'ListSets'); |
1839 | |
1840 | while ($resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($_result)) { |
1841 | |
1842 | - $markerArray = array ( |
1843 | - '###LISTSETS_SPEC###' => htmlspecialchars($resArray['oai_name']), |
1844 | - '###LISTSETS_NAME###' => htmlspecialchars($resArray['label']) |
1845 | - ); |
1846 | - |
1847 | - $content .= $this->cObj->substituteMarkerArray($_itemTemplate, $markerArray); |
1848 | + // Add set node. |
1849 | + $set = $this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'set'); |
1850 | + |
1851 | + $set->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'setSpec', htmlspecialchars($resArray['oai_name'], ENT_NOQUOTES, 'UTF-8'))); |
1852 | + |
1853 | + $set->appendChild($this->oai->createElementNS('http://www.openarchives.org/OAI/2.0/', 'setName', htmlspecialchars($resArray['label'], ENT_NOQUOTES, 'UTF-8'))); |
1854 | + |
1855 | + $ListSets->appendChild($set); |
1856 | |
1857 | } |
1858 | |
1859 | - return $this->cObj->substituteSubpart($this->cObj->getSubpart($this->template, '###LISTSETS###'), '###LISTSETS_ITEM###', $content, TRUE); |
1860 | + return $ListSets; |
1861 | |
1862 | } |
1863 | |
1864 | |
1865 | === renamed file 'dlf/plugins/oai/template.tmpl' => 'dlf/plugins/oai/template.tmpl.THIS' |