Merge lp:~sebastian-meyer/goobi-presentation/bug802031 into lp:goobi-presentation/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
Reviewer Review Type Date Requested Status
Sebastian Meyer Approve
Review via email: mp+75213@code.launchpad.net
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'

Subscribers

People subscribed via source and target branches

to all changes: