Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( 118576...18bf9c )
by Sebastian
14:55
created

tx_dlf_document::_getReady()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * (c) Kitodo. Key to digital objects e.V. <[email protected]>
4
 *
5
 * This file is part of the Kitodo and TYPO3 projects.
6
 *
7
 * @license GNU General Public License version 3 or later.
8
 * For the full copyright and license information, please read the
9
 * LICENSE.txt file that was distributed with this source code.
10
 */
11
12
/**
13
 * Document class 'tx_dlf_document' for the 'dlf' extension.
14
 *
15
 * @author	Sebastian Meyer <[email protected]>
16
 * @author	Henrik Lochmann <[email protected]>
17
 * @package	TYPO3
18
 * @subpackage	tx_dlf
19
 * @access	public
20
 */
21
final class tx_dlf_document {
22
23
    /**
24
     * This holds the whole XML file as string for serialization purposes
25
     * @see __sleep() / __wakeup()
26
     *
27
     * @var	string
28
     * @access protected
29
     */
30
    protected $asXML = '';
31
32
    /**
33
     * This holds the PID for the configuration
34
     *
35
     * @var	integer
36
     * @access protected
37
     */
38
    protected $cPid = 0;
39
40
    /**
41
     * This holds the XML file's dmdSec parts with their IDs as array key
42
     *
43
     * @var	array
44
     * @access protected
45
     */
46
    protected $dmdSec = array ();
47
48
    /**
49
     * Are the METS file's dmdSecs loaded?
50
     * @see $dmdSec
51
     *
52
     * @var	boolean
53
     * @access protected
54
     */
55
    protected $dmdSecLoaded = FALSE;
56
57
    /**
58
     * The extension key
59
     *
60
     * @var	string
61
     * @access public
62
     */
63
    public static $extKey = 'dlf';
64
65
    /**
66
     * This holds the file ID -> USE concordance
67
     * @see _getFileGrps()
68
     *
69
     * @var	array
70
     * @access protected
71
     */
72
    protected $fileGrps = array ();
73
74
    /**
75
     * Are the file groups loaded?
76
     * @see $fileGrps
77
     *
78
     * @var	boolean
79
     * @access protected
80
     */
81
    protected $fileGrpsLoaded = FALSE;
82
83
    /**
84
     * This holds the configuration for all supported metadata encodings
85
     * @see loadFormats()
86
     *
87
     * @var	array
88
     * @access protected
89
     */
90
    protected $formats = array (
91
        'OAI' => array (
92
            'rootElement' => 'OAI-PMH',
93
            'namespaceURI' => 'http://www.openarchives.org/OAI/2.0/',
94
        ),
95
        'METS' => array (
96
            'rootElement' => 'mets',
97
            'namespaceURI' => 'http://www.loc.gov/METS/',
98
        ),
99
        'XLINK' => array (
100
            'rootElement' => 'xlink',
101
            'namespaceURI' => 'http://www.w3.org/1999/xlink',
102
        )
103
    );
104
105
    /**
106
     * Are the available metadata formats loaded?
107
     * @see $formats
108
     *
109
     * @var	boolean
110
     * @access protected
111
     */
112
    protected $formatsLoaded = FALSE;
113
114
    /**
115
     * Are there any fulltext files available?
116
     *
117
     * @var boolean
118
     * @access protected
119
     */
120
    protected $hasFulltext = FALSE;
121
122
    /**
123
     * Last searched logical and physical page
124
     *
125
     * @var	array
126
     * @access protected
127
     */
128
    protected $lastSearchedPhysicalPage = array ('logicalPage' => NULL, 'physicalPage' => NULL);
129
130
    /**
131
     * This holds the documents location
132
     *
133
     * @var	string
134
     * @access protected
135
     */
136
    protected $location = '';
137
138
    /**
139
     * This holds the logical units
140
     *
141
     * @var	array
142
     * @access protected
143
     */
144
    protected $logicalUnits = array ();
145
146
    /**
147
     * This holds the documents' parsed metadata array with their corresponding structMap//div's ID as array key
148
     *
149
     * @var	array
150
     * @access protected
151
     */
152
    protected $metadataArray = array ();
153
154
    /**
155
     * Is the metadata array loaded?
156
     * @see $metadataArray
157
     *
158
     * @var	boolean
159
     * @access protected
160
     */
161
    protected $metadataArrayLoaded = FALSE;
162
163
    /**
164
     * This holds the XML file's METS part as SimpleXMLElement object
165
     *
166
     * @var	SimpleXMLElement
167
     * @access protected
168
     */
169
    protected $mets;
170
171
    /**
172
     * The holds the total number of pages
173
     *
174
     * @var	integer
175
     * @access protected
176
     */
177
    protected $numPages = 0;
178
179
    /**
180
     * This holds the UID of the parent document or zero if not multi-volumed
181
     *
182
     * @var	integer
183
     * @access protected
184
     */
185
    protected $parentId = 0;
186
187
    /**
188
     * This holds the physical structure
189
     *
190
     * @var	array
191
     * @access protected
192
     */
193
    protected $physicalStructure = array ();
194
195
    /**
196
     * This holds the physical structure metadata
197
     *
198
     * @var	array
199
     * @access protected
200
     */
201
    protected $physicalStructureInfo = array ();
202
203
    /**
204
     * Is the physical structure loaded?
205
     * @see $physicalStructure
206
     *
207
     * @var	boolean
208
     * @access protected
209
     */
210
    protected $physicalStructureLoaded = FALSE;
211
212
    /**
213
     * This holds the PID of the document or zero if not in database
214
     *
215
     * @var	integer
216
     * @access protected
217
     */
218
    protected $pid = 0;
219
220
    /**
221
     * Is the document instantiated successfully?
222
     *
223
     * @var	boolean
224
     * @access protected
225
     */
226
    protected $ready = FALSE;
227
228
    /**
229
     * The METS file's record identifier
230
     *
231
     * @var	string
232
     * @access protected
233
     */
234
    protected $recordId;
235
236
    /**
237
     * This holds the singleton object of the document
238
     *
239
     * @var	array (tx_dlf_document)
240
     * @access protected
241
     */
242
    protected static $registry = array ();
243
244
    /**
245
     * This holds the UID of the root document or zero if not multi-volumed
246
     *
247
     * @var	integer
248
     * @access protected
249
     */
250
    protected $rootId = 0;
251
252
    /**
253
     * Is the root id loaded?
254
     * @see $rootId
255
     *
256
     * @var	boolean
257
     * @access protected
258
     */
259
    protected $rootIdLoaded = FALSE;
260
261
    /**
262
     * This holds the smLinks between logical and physical structMap
263
     *
264
     * @var	array
265
     * @access protected
266
     */
267
    protected $smLinks = array ('l2p' => array (), 'p2l' => array ());
268
269
    /**
270
     * Are the smLinks loaded?
271
     * @see $smLinks
272
     *
273
     * @var	boolean
274
     * @access protected
275
     */
276
    protected $smLinksLoaded = FALSE;
277
278
    /**
279
     * This holds the logical structure
280
     *
281
     * @var	array
282
     * @access protected
283
     */
284
    protected $tableOfContents = array ();
285
286
    /**
287
     * Is the table of contents loaded?
288
     * @see $tableOfContents
289
     *
290
     * @var	boolean
291
     * @access protected
292
     */
293
    protected $tableOfContentsLoaded = FALSE;
294
295
    /**
296
     * This holds the document's thumbnail location.
297
     *
298
     * @var	string
299
     * @access protected
300
     */
301
    protected $thumbnail = '';
302
303
    /**
304
     * Is the document's thumbnail location loaded?
305
     * @see $thumbnail
306
     *
307
     * @var	boolean
308
     * @access protected
309
     */
310
    protected $thumbnailLoaded = FALSE;
311
312
    /**
313
     * This holds the toplevel structure's @ID
314
     *
315
     * @var	string
316
     * @access protected
317
     */
318
    protected $toplevelId = '';
319
320
    /**
321
     * This holds the UID or the URL of the document
322
     *
323
     * @var	mixed
324
     * @access protected
325
     */
326
    protected $uid = 0;
327
328
    /**
329
     * This holds the whole XML file as SimpleXMLElement object
330
     *
331
     * @var	SimpleXMLElement
332
     * @access protected
333
     */
334
    protected $xml;
335
336
    /**
337
     * This clears the static registry to prevent memory exhaustion
338
     *
339
     * @access	public
340
     *
341
     * @return	void
342
     */
343
    public static function clearRegistry() {
344
345
        // Reset registry array.
346
        self::$registry = array ();
347
348
    }
349
350
    /**
351
     * This gets the location of a file representing a physical page or track
352
     *
353
     * @access	public
354
     *
355
     * @param	string		$id: The @ID attribute of the file node
356
     *
357
     * @return	string		The file's location as URL
358
     */
359
    public function getFileLocation($id) {
360
361
        if (!empty($id) && ($location = $this->mets->xpath('./mets:fileSec/mets:fileGrp/mets:file[@ID="'.$id.'"]/mets:FLocat[@LOCTYPE="URL"]'))) {
362
363
            return (string) $location[0]->attributes('http://www.w3.org/1999/xlink')->href;
364
365
        } else {
366
367
            if (TYPO3_DLOG) {
368
369
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->getFileLocation('.$id.')] There is no file node with @ID "'.$id.'"', self::$extKey, SYSLOG_SEVERITY_WARNING);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_WARNING was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
370
371
            }
372
373
            return '';
374
375
        }
376
377
    }
378
379
    /**
380
     * This gets the MIME type of a file representing a physical page or track
381
     *
382
     * @access	public
383
     *
384
     * @param	string		$id: The @ID attribute of the file node
385
     *
386
     * @return	string		The file's MIME type
387
     */
388
    public function getFileMimeType($id) {
389
390
        if (!empty($id) && ($mimetype = $this->mets->xpath('./mets:fileSec/mets:fileGrp/mets:file[@ID="'.$id.'"]/@MIMETYPE'))) {
391
392
            return (string) $mimetype[0];
393
394
        } else {
395
396
            if (TYPO3_DLOG) {
397
398
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->getFileMimeType('.$id.')] There is no file node with @ID "'.$id.'" or no MIME type specified', self::$extKey, SYSLOG_SEVERITY_WARNING);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_WARNING was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
399
400
            }
401
402
            return '';
403
404
        }
405
406
    }
407
408
    /**
409
     * This is a singleton class, thus an instance must be created by this method
410
     *
411
     * @access	public
412
     *
413
     * @param	mixed		$uid: The unique identifier of the document to parse or URL of XML file
414
     * @param	integer		$pid: If > 0, then only document with this PID gets loaded
415
     * @param	boolean		$forceReload: Force reloading the document instead of returning the cached instance
416
     *
417
     * @return	&tx_dlf_document		Instance of this class
0 ignored issues
show
Documentation Bug introduced by
The doc comment &tx_dlf_document at position 0 could not be parsed: Unknown type name '&' at position 0 in &tx_dlf_document.
Loading history...
418
     */
419
    public static function &getInstance($uid, $pid = 0, $forceReload = FALSE) {
420
421
        // Sanitize input.
422
        $pid = max(intval($pid), 0);
423
424
        if (!$forceReload) {
425
426
            $regObj = md5($uid);
427
428
            if (is_object(self::$registry[$regObj]) && self::$registry[$regObj] instanceof self) {
429
430
                // Check if instance has given PID.
431
                if (!$pid || !self::$registry[$regObj]->pid || $pid == self::$registry[$regObj]->pid) {
432
433
                    // Return singleton instance if available.
434
                    return self::$registry[$regObj];
435
436
                }
437
438
            } else {
439
440
                // Check the user's session...
441
                $sessionData = tx_dlf_helper::loadFromSession(get_called_class());
442
443
                if (is_object($sessionData[$regObj]) && $sessionData[$regObj] instanceof self) {
444
445
                    // Check if instance has given PID.
446
                    if (!$pid || !$sessionData[$regObj]->pid || $pid == $sessionData[$regObj]->pid) {
447
448
                        // ...and restore registry.
449
                        self::$registry[$regObj] = $sessionData[$regObj];
450
451
                        return self::$registry[$regObj];
452
453
                    }
454
455
                }
456
457
            }
458
459
        }
460
461
        // Create new instance...
462
        $instance = new self($uid, $pid);
463
464
        // ...and save it to registry.
465
        if ($instance->ready) {
466
467
            self::$registry[md5($instance->uid)] = $instance;
468
469
            if ($instance->uid != $instance->location) {
470
471
                self::$registry[md5($instance->location)] = $instance;
472
473
            }
474
475
            // Load extension configuration
476
            $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['dlf']);
477
478
            // Save registry to session if caching is enabled.
479
            if (!empty($extConf['caching'])) {
480
481
                tx_dlf_helper::saveToSession(self::$registry, get_class($instance));
482
483
            }
484
485
        }
486
487
        // Return new instance.
488
        return $instance;
489
490
    }
491
492
    /**
493
     * This gets details about a logical structure element
494
     *
495
     * @access	public
496
     *
497
     * @param	string		$id: The @ID attribute of the logical structure node
498
     * @param	boolean		$recursive: Whether to include the child elements
499
     *
500
     * @return	array		Array of the element's id, label, type and physical page indexes/mptr link
501
     */
502
    public function getLogicalStructure($id, $recursive = FALSE) {
503
504
        $details = array ();
505
506
        // Is the requested logical unit already loaded?
507
        if (!$recursive && !empty($this->logicalUnits[$id])) {
508
509
            // Yes. Return it.
510
            return $this->logicalUnits[$id];
511
512
        } elseif (!empty($id)) {
513
514
            // Get specified logical unit.
515
            $divs = $this->mets->xpath('./mets:structMap[@TYPE="LOGICAL"]//mets:div[@ID="'.$id.'"]');
516
517
        } else {
518
519
            // Get all logical units at top level.
520
            $divs = $this->mets->xpath('./mets:structMap[@TYPE="LOGICAL"]/mets:div');
521
522
        }
523
524
        if (!empty($divs)) {
525
526
            if (!$recursive) {
527
528
                // Get the details for the first xpath hit.
529
                $details = $this->getLogicalStructureInfo($divs[0]);
530
531
            } else {
532
533
                // Walk the logical structure recursively and fill the whole table of contents.
534
                foreach ($divs as $div) {
535
536
                    $this->tableOfContents[] = $this->getLogicalStructureInfo($div, TRUE);
537
538
                }
539
540
            }
541
542
        }
543
544
        return $details;
545
546
    }
547
548
    /**
549
     * This gets details about a logical structure element
550
     *
551
     * @access	protected
552
     *
553
     * @param	SimpleXMLElement		$structure: The logical structure node
554
     * @param	boolean		$recursive: Whether to include the child elements
555
     *
556
     * @return	array		Array of the element's id, label, type and physical page indexes/mptr link
557
     */
558
    protected function getLogicalStructureInfo(SimpleXMLElement $structure, $recursive = FALSE) {
559
560
        // Get attributes.
561
        foreach ($structure->attributes() as $attribute => $value) {
562
563
            $attributes[$attribute] = (string) $value;
564
565
        }
566
567
        // Load plugin configuration.
568
        $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][self::$extKey]);
569
570
        // Extract identity information.
571
        $details = array ();
572
573
        $details['id'] = $attributes['ID'];
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $attributes seems to be defined by a foreach iteration on line 561. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
574
575
        $details['dmdId'] = (isset($attributes['DMDID']) ? $attributes['DMDID'] : '');
576
577
        $details['label'] = (isset($attributes['LABEL']) ? $attributes['LABEL'] : '');
578
579
        $details['orderlabel'] = (isset($attributes['ORDERLABEL']) ? $attributes['ORDERLABEL'] : '');
580
581
        $details['contentIds'] = (isset($attributes['CONTENTIDS']) ? $attributes['CONTENTIDS'] : '');
582
583
        $details['volume'] = '';
584
585
        // Set volume information only if no label is set and this is the toplevel structure element.
586
        if (empty($details['label']) && $details['id'] == $this->_getToplevelId()) {
587
588
            $metadata = $this->getMetadata($details['id']);
589
590
            if (!empty($metadata['volume'][0])) {
591
592
                $details['volume'] = $metadata['volume'][0];
593
594
            }
595
596
        }
597
598
        $details['pagination'] = '';
599
600
        $details['type'] = $attributes['TYPE'];
601
602
        $details['thumbnailId'] = '';
603
604
        // Load smLinks.
605
        $this->_getSmLinks();
606
607
        // Load physical structure.
608
        $this->_getPhysicalStructure();
609
610
        // Get the physical page or external file this structure element is pointing at.
611
        $details['points'] = '';
612
613
        // Is there a mptr node?
614
        if (count($structure->children('http://www.loc.gov/METS/')->mptr)) {
615
616
            // Yes. Get the file reference.
617
            $details['points'] = (string) $structure->children('http://www.loc.gov/METS/')->mptr[0]->attributes('http://www.w3.org/1999/xlink')->href;
618
619
        // Are there any physical elements and is this logical unit linked to at least one of them?
620
        } elseif (!empty($this->physicalStructure) && array_key_exists($details['id'], $this->smLinks['l2p'])) {
621
622
            $details['points'] = max(intval(array_search($this->smLinks['l2p'][$details['id']][0], $this->physicalStructure, TRUE)), 1);
623
624
            if (!empty($this->physicalStructureInfo[$this->smLinks['l2p'][$details['id']][0]]['files'][$extConf['fileGrpThumbs']])) {
625
626
                $details['thumbnailId'] = $this->physicalStructureInfo[$this->smLinks['l2p'][$details['id']][0]]['files'][$extConf['fileGrpThumbs']];
627
628
            }
629
630
            // Get page/track number of the first page/track related to this structure element.
631
            $details['pagination'] = $this->physicalStructureInfo[$this->smLinks['l2p'][$details['id']][0]]['orderlabel'];
632
633
        // Is this the toplevel structure element?
634
        } elseif ($details['id'] == $this->_getToplevelId()) {
635
636
            // Yes. Point to itself.
637
            $details['points'] = 1;
638
639
            if (!empty($this->physicalStructure) && !empty($this->physicalStructureInfo[$this->physicalStructure[1]]['files'][$extConf['fileGrpThumbs']])) {
640
641
                $details['thumbnailId'] = $this->physicalStructureInfo[$this->physicalStructure[1]]['files'][$extConf['fileGrpThumbs']];
642
643
            }
644
645
        }
646
647
        // Get the files this structure element is pointing at.
648
        $details['files'] = array ();
649
650
        $fileUse = $this->_getFileGrps();
651
652
        // Get the file representations from fileSec node.
653
        foreach ($structure->children('http://www.loc.gov/METS/')->fptr as $fptr) {
654
655
            // Check if file has valid @USE attribute.
656
            if (!empty($fileUse[(string) $fptr->attributes()->FILEID])) {
657
658
                $details['files'][$fileUse[(string) $fptr->attributes()->FILEID]] = (string) $fptr->attributes()->FILEID;
659
660
            }
661
662
        }
663
664
        // Keep for later usage.
665
        $this->logicalUnits[$details['id']] = $details;
666
667
        // Walk the structure recursively? And are there any children of the current element?
668
        if ($recursive && count($structure->children('http://www.loc.gov/METS/')->div)) {
669
670
            $details['children'] = array ();
671
672
            foreach ($structure->children('http://www.loc.gov/METS/')->div as $child) {
673
674
                // Repeat for all children.
675
                $details['children'][] = $this->getLogicalStructureInfo($child, TRUE);
676
677
            }
678
679
        }
680
681
        return $details;
682
683
    }
684
685
    /**
686
     * This extracts all the metadata for a logical structure node
687
     *
688
     * @access	public
689
     *
690
     * @param	string		$id: The @ID attribute of the logical structure node
691
     * @param	integer		$cPid: The PID for the metadata definitions
692
     * 						(defaults to $this->cPid or $this->pid)
693
     *
694
     * @return	array		The logical structure node's parsed metadata array
695
     */
696
    public function getMetadata($id, $cPid = 0) {
697
698
        // Save parameter for logging purposes.
699
        $_cPid = $cPid;
700
701
        // Make sure $cPid is a non-negative integer.
702
        $cPid = max(intval($cPid), 0);
703
704
        // If $cPid is not given, try to get it elsewhere.
705
        if (!$cPid && ($this->cPid || $this->pid)) {
706
707
            // Retain current PID.
708
            $cPid = ($this->cPid ? $this->cPid : $this->pid);
709
710
        } elseif (!$cPid) {
711
712
            if (TYPO3_DLOG) {
713
714
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->getMetadata('.$id.', '.$_cPid.')] Invalid PID "'.$cPid.'" for metadata definitions', self::$extKey, SYSLOG_SEVERITY_ERROR);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_ERROR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
715
716
            }
717
718
            return array ();
719
720
        }
721
722
        // Get metadata from parsed metadata array if available.
723
        if (!empty($this->metadataArray[$id]) && $this->metadataArray[0] == $cPid) {
724
725
            return $this->metadataArray[$id];
726
727
        }
728
729
        // Initialize metadata array with empty values.
730
        $metadata = array (
731
            'title' => array (),
732
            'title_sorting' => array (),
733
            'author' => array (),
734
            'place' => array (),
735
            'year' => array (),
736
            'prod_id' => array (),
737
            'record_id' => array (),
738
            'opac_id' => array (),
739
            'union_id' => array (),
740
            'urn' => array (),
741
            'purl' => array (),
742
            'type' => array (),
743
            'volume' => array (),
744
            'volume_sorting' => array (),
745
            'collection' => array (),
746
            'owner' => array (),
747
        );
748
749
        // Get the logical structure node's DMDID.
750
        if (!empty($this->logicalUnits[$id])) {
751
752
            $dmdId = $this->logicalUnits[$id]['dmdId'];
753
754
        } else {
755
756
            $dmdId = $this->mets->xpath('./mets:structMap[@TYPE="LOGICAL"]//mets:div[@ID="'.$id.'"]/@DMDID');
757
758
            $dmdId = (string) $dmdId[0];
759
760
        }
761
762
        if (!empty($dmdId)) {
763
764
            // Load available metadata formats and dmdSecs.
765
            $this->loadFormats();
766
767
            $this->_getDmdSec();
768
769
            // Is this metadata format supported?
770
            if (!empty($this->formats[$this->dmdSec[$dmdId]['type']])) {
771
772
                if (!empty($this->formats[$this->dmdSec[$dmdId]['type']]['class'])) {
773
774
                    $class = $this->formats[$this->dmdSec[$dmdId]['type']]['class'];
775
776
                    // Get the metadata from class.
777
                    if (class_exists($class) && ($obj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance($class)) instanceof tx_dlf_format) {
778
779
                        $obj->extractMetadata($this->dmdSec[$dmdId]['xml'], $metadata);
780
781
                    } else {
782
783
                        if (TYPO3_DLOG) {
784
785
                            \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->getMetadata('.$id.', '.$_cPid.')] Invalid class/method "'.$class.'->extractMetadata()" for metadata format "'.$this->dmdSec[$dmdId]['type'].'"', self::$extKey, SYSLOG_SEVERITY_WARNING);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_WARNING was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
786
787
                        }
788
789
                    }
790
791
                }
792
793
            } else {
794
795
                if (TYPO3_DLOG) {
796
797
                    \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->getMetadata('.$id.', '.$_cPid.')] Unsupported metadata format "'.$this->dmdSec[$dmdId]['type'].'" in dmdSec with @ID "'.$dmdId.'"', self::$extKey, SYSLOG_SEVERITY_WARNING);
798
799
                }
800
801
                return array ();
802
803
            }
804
805
            // Get the structure's type.
806
            if (!empty($this->logicalUnits[$id])) {
807
808
                $metadata['type'] = array ($this->logicalUnits[$id]['type']);
809
810
            } else {
811
812
                $struct = $this->mets->xpath('./mets:structMap[@TYPE="LOGICAL"]//mets:div[@ID="'.$id.'"]/@TYPE');
813
814
                $metadata['type'] = array ((string) $struct[0]);
815
816
            }
817
818
            // Get the additional metadata from database.
819
            $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
820
                'tx_dlf_metadata.index_name AS index_name,tx_dlf_metadataformat.xpath AS xpath,tx_dlf_metadataformat.xpath_sorting AS xpath_sorting,tx_dlf_metadata.is_sortable AS is_sortable,tx_dlf_metadata.default_value AS default_value,tx_dlf_metadata.format AS format',
821
                'tx_dlf_metadata,tx_dlf_metadataformat,tx_dlf_formats',
822
                'tx_dlf_metadata.pid='.$cPid.' AND tx_dlf_metadataformat.pid='.$cPid.' AND ((tx_dlf_metadata.uid=tx_dlf_metadataformat.parent_id AND tx_dlf_metadataformat.encoded=tx_dlf_formats.uid AND tx_dlf_formats.type='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->dmdSec[$dmdId]['type'], 'tx_dlf_formats').') OR tx_dlf_metadata.format=0)'.tx_dlf_helper::whereClause('tx_dlf_metadata', TRUE).tx_dlf_helper::whereClause('tx_dlf_metadataformat').tx_dlf_helper::whereClause('tx_dlf_formats'),
823
                '',
824
                '',
825
                ''
826
            );
827
828
            // We need a DOMDocument here, because SimpleXML doesn't support XPath functions properly.
829
            $domNode = dom_import_simplexml($this->dmdSec[$dmdId]['xml']);
830
831
            $domXPath = new DOMXPath($domNode->ownerDocument);
832
833
            $this->registerNamespaces($domXPath);
834
835
            // OK, now make the XPath queries.
836
            while ($resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) {
837
838
                // Set metadata field's value(s).
839
                if ($resArray['format'] > 0 && !empty($resArray['xpath']) && ($values = $domXPath->evaluate($resArray['xpath'], $domNode))) {
840
841
                    if ($values instanceof DOMNodeList && $values->length > 0) {
842
843
                        $metadata[$resArray['index_name']] = array ();
844
845
                        foreach ($values as $value) {
846
847
                            $metadata[$resArray['index_name']][] = trim((string) $value->nodeValue);
848
849
                        }
850
851
                    } elseif (!($values instanceof DOMNodeList)) {
852
853
                        $metadata[$resArray['index_name']] = array (trim((string) $values));
854
855
                    }
856
857
                }
858
859
                // Set default value if applicable.
860
                // '!empty($resArray['default_value'])' is not possible, because '0' is a valid default value.
861
                // Setting an empty default value creates a lot of empty fields within the index.
862
                // These empty fields are then shown within the search facets as 'empty'.
863
                if (empty($metadata[$resArray['index_name']][0]) && strlen($resArray['default_value']) > 0) {
864
865
                    $metadata[$resArray['index_name']] = array ($resArray['default_value']);
866
867
                }
868
869
                // Set sorting value if applicable.
870
                if (!empty($metadata[$resArray['index_name']]) && $resArray['is_sortable']) {
871
872
                    if ($resArray['format'] > 0 && !empty($resArray['xpath_sorting']) && ($values = $domXPath->evaluate($resArray['xpath_sorting'], $domNode))) {
873
874
                        if ($values instanceof DOMNodeList && $values->length > 0) {
875
876
                            $metadata[$resArray['index_name'].'_sorting'][0] = trim((string) $values->item(0)->nodeValue);
877
878
                        } elseif (!($values instanceof DOMNodeList)) {
879
880
                            $metadata[$resArray['index_name'].'_sorting'][0] = trim((string) $values);
881
882
                        }
883
884
                    }
885
886
                    if (empty($metadata[$resArray['index_name'].'_sorting'][0])) {
887
888
                        $metadata[$resArray['index_name'].'_sorting'][0] = $metadata[$resArray['index_name']][0];
889
890
                    }
891
892
                }
893
894
            }
895
896
            // Set title to empty string if not present.
897
            if (empty($metadata['title'][0])) {
898
899
                $metadata['title'][0] = '';
900
901
                $metadata['title_sorting'][0] = '';
902
903
            }
904
905
        } else {
906
907
            // There is no dmdSec for this structure node.
908
            return array ();
909
910
        }
911
912
        return $metadata;
913
914
    }
915
916
    /**
917
     * This returns the first corresponding physical page number of a given logical page label
918
     *
919
     * @access	public
920
     *
921
     * @param	string		$logicalPage: The label (or a part of the label) of the logical page
922
     *
923
     * @return	integer		The physical page number
924
     */
925
    public function getPhysicalPage($logicalPage) {
926
927
        if (!empty($this->lastSearchedPhysicalPage['logicalPage']) && $this->lastSearchedPhysicalPage['logicalPage'] == $logicalPage) {
928
929
            return $this->lastSearchedPhysicalPage['physicalPage'];
930
931
        } else {
932
933
            $physicalPage = 0;
934
935
            foreach ($this->physicalStructureInfo as $page) {
936
937
                if (strpos($page['orderlabel'], $logicalPage) !== FALSE) {
938
939
                    $this->lastSearchedPhysicalPage['logicalPage'] = $logicalPage;
940
                    $this->lastSearchedPhysicalPage['physicalPage'] = $physicalPage;
941
942
                    return $physicalPage;
943
944
                }
945
946
                $physicalPage++;
947
948
            }
949
950
        }
951
952
        return 1;
953
954
    }
955
956
    /**
957
     * This determines a title for the given document
958
     *
959
     * @access	public
960
     *
961
     * @param	integer		$uid: The UID of the document
962
     * @param	boolean		$recursive: Search superior documents for a title, too?
963
     *
964
     * @return	string		The title of the document itself or a parent document
965
     */
966
    public static function getTitle($uid, $recursive = FALSE) {
967
968
        // Save parameter for logging purposes.
969
        $_uid = $uid;
970
971
        $title = '';
972
973
        // Sanitize input.
974
        $uid = max(intval($uid), 0);
975
976
        if ($uid) {
977
978
            $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
979
                'tx_dlf_documents.title,tx_dlf_documents.partof',
980
                'tx_dlf_documents',
981
                'tx_dlf_documents.uid='.$uid.tx_dlf_helper::whereClause('tx_dlf_documents'),
982
                '',
983
                '',
984
                '1'
985
            );
986
987
            if ($GLOBALS['TYPO3_DB']->sql_num_rows($result)) {
988
989
                // Get title information.
990
                list ($title, $partof) = $GLOBALS['TYPO3_DB']->sql_fetch_row($result);
991
992
                // Search parent documents recursively for a title?
993
                if ($recursive && empty($title) && intval($partof) && $partof != $uid) {
994
995
                    $title = self::getTitle($partof, TRUE);
996
997
                }
998
999
            } else {
1000
1001
                if (TYPO3_DLOG) {
1002
1003
                    \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->getTitle('.$_uid.', ['.($recursive ? 'TRUE' : 'FALSE').'])] No document with UID "'.$uid.'" found or document not accessible', self::$extKey, SYSLOG_SEVERITY_WARNING);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_WARNING was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1004
1005
                }
1006
1007
            }
1008
1009
        } else {
1010
1011
            if (TYPO3_DLOG) {
1012
1013
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->getTitle('.$_uid.', ['.($recursive ? 'TRUE' : 'FALSE').'])] Invalid UID "'.$uid.'" for document', self::$extKey, SYSLOG_SEVERITY_ERROR);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_ERROR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1014
1015
            }
1016
1017
        }
1018
1019
        return $title;
1020
1021
    }
1022
1023
    /**
1024
     * This extracts all the metadata for the toplevel logical structure node
1025
     *
1026
     * @access	public
1027
     *
1028
     * @param	integer		$cPid: The PID for the metadata definitions
1029
     *
1030
     * @return	array		The logical structure node's parsed metadata array
1031
     */
1032
    public function getTitledata($cPid = 0) {
1033
1034
        $titledata = $this->getMetadata($this->_getToplevelId(), $cPid);
1035
1036
        // Set record identifier for METS file if not present.
1037
        if (is_array($titledata) && array_key_exists('record_id', $titledata)) {
1038
1039
            if (!empty($this->recordId) && !in_array($this->recordId, $titledata['record_id'])) {
1040
1041
                array_unshift($titledata['record_id'], $this->recordId);
1042
1043
            }
1044
1045
        };
1046
1047
        return $titledata;
1048
1049
    }
1050
1051
    /**
1052
     * This sets some basic class properties
1053
     *
1054
     * @access	protected
1055
     *
1056
     * @return	void
1057
     */
1058
    protected function init() {
1059
1060
        // Get METS node from XML file.
1061
        $this->registerNamespaces($this->xml);
1062
1063
        $mets = $this->xml->xpath('//mets:mets');
1064
1065
        if ($mets) {
1066
1067
            $this->mets = $mets[0];
1068
1069
            // Register namespaces.
1070
            $this->registerNamespaces($this->mets);
1071
1072
        } else {
1073
1074
            if (TYPO3_DLOG) {
1075
1076
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->init()] No METS part found in document with UID "'.$this->uid.'"', self::$extKey, SYSLOG_SEVERITY_ERROR);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_ERROR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1077
1078
            }
1079
1080
        }
1081
1082
    }
1083
1084
    /**
1085
     * Load XML file from URL
1086
     *
1087
     * @access	protected
1088
     *
1089
     * @param	string		$location: The URL of the file to load
1090
     *
1091
     * @return	boolean		TRUE on success or FALSE on failure
1092
     */
1093
    protected function load($location) {
1094
1095
        // Load XML file.
1096
        if (\TYPO3\CMS\Core\Utility\GeneralUtility::isValidUrl($location)) {
1097
1098
            // Load extension configuration
1099
            $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['dlf']);
1100
1101
            // Set user-agent to identify self when fetching XML data.
1102
            if (!empty($extConf['useragent'])) {
1103
1104
                @ini_set('user_agent', $extConf['useragent']);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition for ini_set(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

1104
                /** @scrutinizer ignore-unhandled */ @ini_set('user_agent', $extConf['useragent']);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1105
1106
            }
1107
1108
            // Turn off libxml's error logging.
1109
            $libxmlErrors = libxml_use_internal_errors(TRUE);
1110
1111
            // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
1112
            $previousValueOfEntityLoader = libxml_disable_entity_loader(TRUE);
1113
1114
            // Load XML from file.
1115
            $xml = simplexml_load_string(\TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($location));
0 ignored issues
show
Bug introduced by
It seems like TYPO3\CMS\Core\Utility\G...lity::getUrl($location) can also be of type mixed and false; however, parameter $data of simplexml_load_string() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

1115
            $xml = simplexml_load_string(/** @scrutinizer ignore-type */ \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($location));
Loading history...
1116
1117
            // reset entity loader setting
1118
            libxml_disable_entity_loader($previousValueOfEntityLoader);
1119
1120
            // Reset libxml's error logging.
1121
            libxml_use_internal_errors($libxmlErrors);
1122
1123
            // Set some basic properties.
1124
            if ($xml !== FALSE) {
1125
1126
                $this->xml = $xml;
1127
1128
                return TRUE;
1129
1130
            } else {
1131
1132
                if (TYPO3_DLOG) {
1133
1134
                    \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->load('.$location.')] Could not load XML file from "'.$location.'"', self::$extKey, SYSLOG_SEVERITY_ERROR);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_ERROR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1135
1136
                }
1137
1138
            }
1139
1140
        } else {
1141
1142
            if (TYPO3_DLOG) {
1143
1144
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->load('.$location.')] Invalid file location "'.$location.'" for document loading', self::$extKey, SYSLOG_SEVERITY_ERROR);
1145
1146
            }
1147
1148
        }
1149
1150
        return FALSE;
1151
1152
    }
1153
1154
    /**
1155
     * Register all available data formats
1156
     *
1157
     * @access	protected
1158
     *
1159
     * @return	void
1160
     */
1161
    protected function loadFormats() {
1162
1163
        if (!$this->formatsLoaded) {
1164
1165
            // Get available data formats from database.
1166
            $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
1167
                'tx_dlf_formats.type AS type,tx_dlf_formats.root AS root,tx_dlf_formats.namespace AS namespace,tx_dlf_formats.class AS class',
1168
                'tx_dlf_formats',
1169
                'tx_dlf_formats.pid=0'.tx_dlf_helper::whereClause('tx_dlf_formats'),
1170
                '',
1171
                '',
1172
                ''
1173
            );
1174
1175
            while ($resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) {
1176
1177
                // Update format registry.
1178
                $this->formats[$resArray['type']] = array (
1179
                    'rootElement' => $resArray['root'],
1180
                    'namespaceURI' => $resArray['namespace'],
1181
                    'class' => $resArray['class']
1182
                );
1183
1184
            }
1185
1186
            $this->formatsLoaded = TRUE;
1187
1188
        }
1189
1190
    }
1191
1192
    /**
1193
     * Register all available namespaces for a SimpleXMLElement object
1194
     *
1195
     * @access	public
1196
     *
1197
     * @param	SimpleXMLElement|DOMXPath		&$obj: SimpleXMLElement or DOMXPath object
1198
     *
1199
     * @return	void
1200
     */
1201
    public function registerNamespaces(&$obj) {
1202
1203
        $this->loadFormats();
1204
1205
        // Do we have a SimpleXMLElement or DOMXPath object?
1206
        if ($obj instanceof SimpleXMLElement) {
1207
1208
            $method = 'registerXPathNamespace';
1209
1210
        } elseif ($obj instanceof DOMXPath) {
1211
1212
            $method = 'registerNamespace';
1213
1214
        } else {
1215
1216
            if (TYPO3_DLOG) {
1217
1218
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->registerNamespaces(['.get_class($obj).'])] Given object is neither a SimpleXMLElement nor a DOMXPath instance', self::$extKey, SYSLOG_SEVERITY_ERROR);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_ERROR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1219
1220
            }
1221
1222
            return;
1223
1224
        }
1225
1226
        // Register metadata format's namespaces.
1227
        foreach ($this->formats as $enc => $conf) {
1228
1229
            $obj->$method(strtolower($enc), $conf['namespaceURI']);
1230
1231
        }
1232
1233
    }
1234
1235
    /**
1236
     * This saves the document to the database and index
1237
     *
1238
     * @access	public
1239
     *
1240
     * @param	integer		$pid: The PID of the saved record
1241
     * @param	integer		$core: The UID of the Solr core for indexing
1242
     *
1243
     * @return	boolean		TRUE on success or FALSE on failure
1244
     */
1245
    public function save($pid = 0, $core = 0) {
1246
1247
        // Save parameters for logging purposes.
1248
        $_pid = $pid;
1249
1250
        $_core = $core;
1251
1252
        if (TYPO3_MODE !== 'BE') {
1 ignored issue
show
introduced by
The condition TYPO3_MODE !== 'BE' is always false.
Loading history...
1253
1254
            if (TYPO3_DLOG) {
1255
1256
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->save('.$_pid.', '.$_core.')] Saving a document is only allowed in the backend', self::$extKey, SYSLOG_SEVERITY_ERROR);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_ERROR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1257
1258
            }
1259
1260
            return FALSE;
1261
1262
        }
1263
1264
        // Make sure $pid is a non-negative integer.
1265
        $pid = max(intval($pid), 0);
1266
1267
        // Make sure $core is a non-negative integer.
1268
        $core = max(intval($core), 0);
1269
1270
        // If $pid is not given, try to get it elsewhere.
1271
        if (!$pid && $this->pid) {
1272
1273
            // Retain current PID.
1274
            $pid = $this->pid;
1275
1276
        } elseif (!$pid) {
1277
1278
            if (TYPO3_DLOG) {
1279
1280
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->save('.$_pid.', '.$_core.')] Invalid PID "'.$pid.'" for document saving', self::$extKey, SYSLOG_SEVERITY_ERROR);
1281
1282
            }
1283
1284
            return FALSE;
1285
1286
        }
1287
1288
        // Set PID for metadata definitions.
1289
        $this->cPid = $pid;
1290
1291
        // Set UID placeholder if not updating existing record.
1292
        if ($pid != $this->pid) {
1293
1294
            $this->uid = uniqid('NEW');
1295
1296
        }
1297
1298
        // Get metadata array.
1299
        $metadata = $this->getTitledata($pid);
1300
1301
        // Check for record identifier.
1302
        if (empty($metadata['record_id'][0])) {
1303
1304
            if (TYPO3_DLOG) {
1305
1306
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->save('.$_pid.', '.$_core.')] No record identifier found to avoid duplication', self::$extKey, SYSLOG_SEVERITY_ERROR);
1307
1308
            }
1309
1310
            return FALSE;
1311
1312
        }
1313
1314
        // Load plugin configuration.
1315
        $conf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][self::$extKey]);
1316
1317
        // Get UID for user "_cli_dlf".
1318
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
1319
            'be_users.uid AS uid',
1320
            'be_users',
1321
            'username='.$GLOBALS['TYPO3_DB']->fullQuoteStr('_cli_dlf', 'be_users').\TYPO3\CMS\Backend\Utility\BackendUtility::BEenableFields('be_users').\TYPO3\CMS\Backend\Utility\BackendUtility::deleteClause('be_users'),
1322
            '',
1323
            '',
1324
            '1'
1325
        );
1326
1327
        if ($GLOBALS['TYPO3_DB']->sql_num_rows($result)) {
1328
1329
            list ($be_user) = $GLOBALS['TYPO3_DB']->sql_fetch_row($result);
1330
1331
        } else {
1332
1333
            if (TYPO3_DLOG) {
1334
1335
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->save('.$_pid.', '.$_core.')] Backend user "_cli_dlf" not found or disabled', self::$extKey, SYSLOG_SEVERITY_ERROR);
1336
1337
            }
1338
1339
            return FALSE;
1340
1341
        }
1342
1343
        // Get UID for structure type.
1344
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
1345
            'tx_dlf_structures.uid AS uid',
1346
            'tx_dlf_structures',
1347
            'tx_dlf_structures.pid='.intval($pid).' AND tx_dlf_structures.index_name='.$GLOBALS['TYPO3_DB']->fullQuoteStr($metadata['type'][0], 'tx_dlf_structures').tx_dlf_helper::whereClause('tx_dlf_structures'),
1348
            '',
1349
            '',
1350
            '1'
1351
        );
1352
1353
        if ($GLOBALS['TYPO3_DB']->sql_num_rows($result)) {
1354
1355
            list ($structure) = $GLOBALS['TYPO3_DB']->sql_fetch_row($result);
1356
1357
        } else {
1358
1359
            if (TYPO3_DLOG) {
1360
1361
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->save('.$_pid.', '.$_core.')] Could not identify document/structure type '.$GLOBALS['TYPO3_DB']->fullQuoteStr($metadata['type'][0], 'tx_dlf_structures'),
1362
                                            self::$extKey, SYSLOG_SEVERITY_ERROR);
1363
1364
            }
1365
1366
            return FALSE;
1367
1368
        }
1369
1370
        $metadata['type'][0] = $structure;
1371
1372
        // Get UIDs for collections.
1373
        $collections = array ();
1374
1375
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
1376
            'tx_dlf_collections.index_name AS index_name,tx_dlf_collections.uid AS uid',
1377
            'tx_dlf_collections',
1378
            'tx_dlf_collections.pid='.intval($pid).' AND tx_dlf_collections.sys_language_uid IN (-1,0)'.tx_dlf_helper::whereClause('tx_dlf_collections'),
1379
            '',
1380
            '',
1381
            ''
1382
        );
1383
1384
        for ($i = 0, $j = $GLOBALS['TYPO3_DB']->sql_num_rows($result); $i < $j; $i++) {
1385
1386
            $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result);
1387
1388
            $collUid[$resArray['index_name']] = $resArray['uid'];
1389
1390
        }
1391
1392
        foreach ($metadata['collection'] as $collection) {
1393
1394
            if (!empty($collUid[$collection])) {
1395
1396
                // Add existing collection's UID.
1397
                $collections[] = $collUid[$collection];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $collUid does not seem to be defined for all execution paths leading up to this point.
Loading history...
1398
1399
            } else {
1400
1401
                // Insert new collection.
1402
                $collNewUid = uniqid('NEW');
1403
1404
                $collData['tx_dlf_collections'][$collNewUid] = array (
1405
                    'pid' => $pid,
1406
                    'label' => $collection,
1407
                    'index_name' => $collection,
1408
                    'oai_name' => (!empty($conf['publishNewCollections']) ? $collection : ''),
1409
                    'description' => '',
1410
                    'documents' => 0,
1411
                    'owner' => 0,
1412
                    'status' => 0,
1413
                );
1414
1415
                $substUid = tx_dlf_helper::processDB($collData);
1416
1417
                // Prevent double insertion.
1418
                unset ($collData);
1419
1420
                // Add new collection's UID.
1421
                $collections[] = $substUid[$collNewUid];
1422
1423
                if (!defined('TYPO3_cliMode')) {
1424
1425
                    $message = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
1426
                        'TYPO3\\CMS\\Core\\Messaging\\FlashMessage',
1427
                        htmlspecialchars(sprintf(tx_dlf_helper::getLL('flash.newCollection'), $collection, $substUid[$collNewUid])),
1428
                        tx_dlf_helper::getLL('flash.attention', TRUE),
1429
                        \TYPO3\CMS\Core\Messaging\FlashMessage::INFO,
1430
                        TRUE
1431
                    );
1432
1433
                    tx_dlf_helper::addMessage($message);
1434
1435
                }
1436
1437
            }
1438
1439
        }
1440
1441
        // Preserve user-defined collections.
1442
        $result = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query(
1443
            'tx_dlf_collections.uid AS uid',
1444
            'tx_dlf_documents',
1445
            'tx_dlf_relations',
1446
            'tx_dlf_collections',
1447
            'AND tx_dlf_documents.pid='.intval($pid).' AND tx_dlf_collections.pid='.intval($pid).' AND tx_dlf_documents.uid='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->uid, 'tx_dlf_documents').' AND NOT (tx_dlf_collections.cruser_id='.intval($be_user).' AND tx_dlf_collections.fe_cruser_id=0) AND tx_dlf_relations.ident='.$GLOBALS['TYPO3_DB']->fullQuoteStr('docs_colls', 'tx_dlf_relations'),
1448
            '',
1449
            '',
1450
            ''
1451
        );
1452
1453
        for ($i = 0, $j = $GLOBALS['TYPO3_DB']->sql_num_rows($result); $i < $j; $i++) {
1454
1455
            list ($collections[]) = $GLOBALS['TYPO3_DB']->sql_fetch_row($result);
1456
1457
        }
1458
1459
        $metadata['collection'] = $collections;
1460
1461
        // Get UID for owner.
1462
        $owner = !empty($metadata['owner'][0]) ? $metadata['owner'][0] : 'default';
1463
1464
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
1465
            'tx_dlf_libraries.uid AS uid',
1466
            'tx_dlf_libraries',
1467
            'tx_dlf_libraries.pid='.intval($pid).' AND tx_dlf_libraries.index_name='.$GLOBALS['TYPO3_DB']->fullQuoteStr($owner, 'tx_dlf_libraries').tx_dlf_helper::whereClause('tx_dlf_libraries'),
1468
            '',
1469
            '',
1470
            '1'
1471
        );
1472
1473
        if ($GLOBALS['TYPO3_DB']->sql_num_rows($result)) {
1474
1475
            list ($ownerUid) = $GLOBALS['TYPO3_DB']->sql_fetch_row($result);
1476
1477
        } else {
1478
1479
            // Insert new library.
1480
            $libNewUid = uniqid('NEW');
1481
1482
            $libData['tx_dlf_libraries'][$libNewUid] = array (
1 ignored issue
show
Comprehensibility Best Practice introduced by
$libData was never initialized. Although not strictly required by PHP, it is generally a good practice to add $libData = array(); before regardless.
Loading history...
1483
                'pid' => $pid,
1484
                'label' => $owner,
1485
                'index_name' => $owner,
1486
                'website' => '',
1487
                'contact' => '',
1488
                'image' => '',
1489
                'oai_label' => '',
1490
                'oai_base' => '',
1491
                'opac_label' => '',
1492
                'opac_base' => '',
1493
                'union_label' => '',
1494
                'union_base' => '',
1495
            );
1496
1497
            $substUid = tx_dlf_helper::processDB($libData);
1498
1499
            // Add new library's UID.
1500
            $ownerUid = $substUid[$libNewUid];
1501
1502
            if (!defined('TYPO3_cliMode')) {
1503
1504
                $message = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
1505
                    'TYPO3\\CMS\\Core\\Messaging\\FlashMessage',
1506
                    htmlspecialchars(sprintf(tx_dlf_helper::getLL('flash.newLibrary'), $owner, $ownerUid)),
1507
                    tx_dlf_helper::getLL('flash.attention', TRUE),
1508
                    \TYPO3\CMS\Core\Messaging\FlashMessage::INFO,
1509
                    TRUE
1510
                );
1511
1512
                tx_dlf_helper::addMessage($message);
1513
1514
            }
1515
1516
        }
1517
1518
        $metadata['owner'][0] = $ownerUid;
1519
1520
        // Get UID of parent document.
1521
        $partof = 0;
1522
1523
        // Get the closest ancestor of the current document which has a MPTR child.
1524
        $parentMptr = $this->mets->xpath('./mets:structMap[@TYPE="LOGICAL"]//mets:div[@ID="'.$this->_getToplevelId().'"]/ancestor::mets:div[./mets:mptr][1]/mets:mptr');
1525
1526
        if (!empty($parentMptr[0])) {
1527
1528
            $parentLocation = (string) $parentMptr[0]->attributes('http://www.w3.org/1999/xlink')->href;
1529
1530
            if ($parentLocation != $this->location) {
1531
1532
                $parentDoc = & tx_dlf_document::getInstance($parentLocation, $pid);
1533
1534
                if ($parentDoc->ready) {
1535
1536
                    if ($parentDoc->pid != $pid) {
1537
1538
                        $parentDoc->save($pid, $core);
1539
1540
                    }
1541
1542
                    $partof = $parentDoc->uid;
1543
1544
                }
1545
1546
            }
1547
1548
        }
1549
1550
        // Use the date of publication or title as alternative sorting metric for parts of multi-part works.
1551
        if (!empty($partof)) {
1552
1553
            if (empty($metadata['volume'][0]) && !empty($metadata['year'][0])) {
1554
1555
                $metadata['volume'] = $metadata['year'];
1556
1557
            }
1558
1559
            if (empty($metadata['volume_sorting'][0])) {
1560
1561
                if (!empty($metadata['year_sorting'][0])) {
1562
1563
                    $metadata['volume_sorting'][0] = $metadata['year_sorting'][0];
1564
1565
                } elseif (!empty($metadata['year'][0])) {
1566
1567
                    $metadata['volume_sorting'][0] = $metadata['year'][0];
1568
1569
                }
1570
1571
            }
1572
1573
            // If volume_sorting is still empty, try to use title_sorting finally (workaround for newspapers)
1574
            if (empty($metadata['volume_sorting'][0])) {
1575
1576
                if (!empty($metadata['title_sorting'][0])) {
1577
1578
                    $metadata['volume_sorting'][0] = $metadata['title_sorting'][0];
1579
1580
                }
1581
            }
1582
1583
        }
1584
1585
        // Get metadata for lists and sorting.
1586
        $listed = array ();
1587
1588
        $sortable = array ();
1589
1590
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
1591
            'tx_dlf_metadata.index_name AS index_name,tx_dlf_metadata.is_listed AS is_listed,tx_dlf_metadata.is_sortable AS is_sortable',
1592
            'tx_dlf_metadata',
1593
            '(tx_dlf_metadata.is_listed=1 OR tx_dlf_metadata.is_sortable=1) AND tx_dlf_metadata.pid='.intval($pid).tx_dlf_helper::whereClause('tx_dlf_metadata'),
1594
            '',
1595
            '',
1596
            ''
1597
        );
1598
1599
        while ($resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) {
1600
1601
            if (!empty($metadata[$resArray['index_name']])) {
1602
1603
                if ($resArray['is_listed']) {
1604
1605
                    $listed[$resArray['index_name']] = $metadata[$resArray['index_name']];
1606
1607
                }
1608
1609
                if ($resArray['is_sortable']) {
1610
1611
                    $sortable[$resArray['index_name']] = $metadata[$resArray['index_name']][0];
1612
1613
                }
1614
1615
            }
1616
1617
        }
1618
1619
        // Fill data array.
1620
        $data['tx_dlf_documents'][$this->uid] = array (
1 ignored issue
show
Comprehensibility Best Practice introduced by
$data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data = array(); before regardless.
Loading history...
1621
            'pid' => $pid,
1622
            $GLOBALS['TCA']['tx_dlf_documents']['ctrl']['enablecolumns']['starttime'] => 0,
1623
            $GLOBALS['TCA']['tx_dlf_documents']['ctrl']['enablecolumns']['endtime'] => 0,
1624
            'prod_id' => $metadata['prod_id'][0],
1625
            'location' => $this->location,
1626
            'record_id' => $metadata['record_id'][0],
1627
            'opac_id' => $metadata['opac_id'][0],
1628
            'union_id' => $metadata['union_id'][0],
1629
            'urn' => $metadata['urn'][0],
1630
            'purl' => $metadata['purl'][0],
1631
            'title' => $metadata['title'][0],
1632
            'title_sorting' => $metadata['title_sorting'][0],
1633
            'author' => implode('; ', $metadata['author']),
1634
            'year' => implode('; ', $metadata['year']),
1635
            'place' => implode('; ', $metadata['place']),
1636
            'thumbnail' => $this->_getThumbnail(TRUE),
1637
            'metadata' => serialize($listed),
1638
            'metadata_sorting' => serialize($sortable),
1639
            'structure' => $metadata['type'][0],
1640
            'partof' => $partof,
1641
            'volume' => $metadata['volume'][0],
1642
            'volume_sorting' => $metadata['volume_sorting'][0],
1643
            'collections' => $metadata['collection'],
1644
            'owner' => $metadata['owner'][0],
1645
            'solrcore' => $core,
1646
            'status' => 0,
1647
        );
1648
1649
        // Unhide hidden documents.
1650
        if (!empty($conf['unhideOnIndex'])) {
1651
1652
            $data['tx_dlf_documents'][$this->uid][$GLOBALS['TCA']['tx_dlf_documents']['ctrl']['enablecolumns']['disabled']] = 0;
1653
1654
        }
1655
1656
        // Process data.
1657
        $newIds = tx_dlf_helper::processDB($data);
1658
1659
        // Replace placeholder with actual UID.
1660
        if (strpos($this->uid, 'NEW') === 0) {
1661
1662
            $this->uid = $newIds[$this->uid];
1663
1664
            $this->pid = $pid;
1665
1666
            $this->parentId = $partof;
1667
1668
        }
1669
1670
        if (!defined('TYPO3_cliMode')) {
1671
1672
            $message = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
1673
                'TYPO3\\CMS\\Core\\Messaging\\FlashMessage',
1674
                htmlspecialchars(sprintf(tx_dlf_helper::getLL('flash.documentSaved'), $metadata['title'][0], $this->uid)),
1675
                tx_dlf_helper::getLL('flash.done', TRUE),
1676
                \TYPO3\CMS\Core\Messaging\FlashMessage::OK,
1677
                TRUE
1678
            );
1679
1680
            tx_dlf_helper::addMessage($message);
1681
1682
        }
1683
1684
        // Add document to index.
1685
        if ($core) {
1686
1687
            tx_dlf_indexing::add($this, $core);
1688
1689
        } else {
1690
1691
            if (TYPO3_DLOG) {
1692
1693
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->save('.$_pid.', '.$_core.')] Invalid UID "'.$core.'" for Solr core', self::$extKey, SYSLOG_SEVERITY_NOTICE);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_NOTICE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1694
1695
            }
1696
1697
        }
1698
1699
        return TRUE;
1700
1701
    }
1702
1703
    /**
1704
     * This returns $this->cPid via __get()
1705
     *
1706
     * @access	protected
1707
     *
1708
     * @return	integer		The PID of the metadata definitions
1709
     */
1710
    protected function _getCPid() {
1711
1712
        return $this->cPid;
1713
1714
    }
1715
1716
    /**
1717
     * This builds an array of the document's dmdSecs
1718
     *
1719
     * @access	protected
1720
     *
1721
     * @return	array		Array of dmdSecs with their IDs as array key
1722
     */
1723
    protected function _getDmdSec() {
1724
1725
        if (!$this->dmdSecLoaded) {
1726
1727
            // Get available data formats.
1728
            $this->loadFormats();
1729
1730
            // Get dmdSec nodes from METS.
1731
            $dmdIds = $this->mets->xpath('./mets:dmdSec/@ID');
1732
1733
            foreach ($dmdIds as $dmdId) {
1734
1735
                if ($type = $this->mets->xpath('./mets:dmdSec[@ID="'.(string) $dmdId.'"]/mets:mdWrap[not(@MDTYPE="OTHER")]/@MDTYPE')) {
1736
1737
                    if (!empty($this->formats[(string) $type[0]])) {
1738
1739
                        $type = (string) $type[0];
1740
1741
                        $xml = $this->mets->xpath('./mets:dmdSec[@ID="'.(string) $dmdId.'"]/mets:mdWrap[@MDTYPE="'.$type.'"]/mets:xmlData/'.strtolower($type).':'.$this->formats[$type]['rootElement']);
1742
1743
                    }
1744
1745
                } elseif ($type = $this->mets->xpath('./mets:dmdSec[@ID="'.(string) $dmdId.'"]/mets:mdWrap[@MDTYPE="OTHER"]/@OTHERMDTYPE')) {
1746
1747
                    if (!empty($this->formats[(string) $type[0]])) {
1748
1749
                        $type = (string) $type[0];
1750
1751
                        $xml = $this->mets->xpath('./mets:dmdSec[@ID="'.(string) $dmdId.'"]/mets:mdWrap[@MDTYPE="OTHER"][@OTHERMDTYPE="'.$type.'"]/mets:xmlData/'.strtolower($type).':'.$this->formats[$type]['rootElement']);
1752
1753
                    }
1754
1755
                }
1756
1757
                if ($xml) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $xml does not seem to be defined for all execution paths leading up to this point.
Loading history...
1758
1759
                    $this->dmdSec[(string) $dmdId]['type'] = $type;
1760
1761
                    $this->dmdSec[(string) $dmdId]['xml'] = $xml[0];
1762
1763
                    $this->registerNamespaces($this->dmdSec[(string) $dmdId]['xml']);
1764
1765
                }
1766
1767
            }
1768
1769
            $this->dmdSecLoaded = TRUE;
1770
1771
        }
1772
1773
        return $this->dmdSec;
1774
1775
    }
1776
1777
    /**
1778
     * This builds the file ID -> USE concordance
1779
     *
1780
     * @access	protected
1781
     *
1782
     * @return	array		Array of file use groups with file IDs
1783
     */
1784
    protected function _getFileGrps() {
1785
1786
        if (!$this->fileGrpsLoaded) {
1787
1788
            // Get configured USE attributes.
1789
            $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][self::$extKey]);
1790
1791
            $useGrps = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $extConf['fileGrps']);
1792
1793
            if (!empty($extConf['fileGrpThumbs'])) {
1794
1795
                $useGrps[] = $extConf['fileGrpThumbs'];
1796
1797
            }
1798
1799
            if (!empty($extConf['fileGrpDownload'])) {
1800
1801
                $useGrps[] = $extConf['fileGrpDownload'];
1802
1803
            }
1804
1805
            if (!empty($extConf['fileGrpFulltext'])) {
1806
1807
                $useGrps[] = $extConf['fileGrpFulltext'];
1808
1809
            }
1810
1811
            if (!empty($extConf['fileGrpAudio'])) {
1812
1813
                $useGrps[] = $extConf['fileGrpAudio'];
1814
1815
            }
1816
1817
            // Get all file groups.
1818
            $fileGrps = $this->mets->xpath('./mets:fileSec/mets:fileGrp');
1819
1820
            // Build concordance for configured USE attributes.
1821
            foreach ($fileGrps as $fileGrp) {
1822
1823
                if (in_array((string) $fileGrp['USE'], $useGrps)) {
1824
1825
                    foreach ($fileGrp->children('http://www.loc.gov/METS/')->file as $file) {
1826
1827
                        $this->fileGrps[(string) $file->attributes()->ID] = (string) $fileGrp['USE'];
1828
1829
                    }
1830
1831
                }
1832
1833
            }
1834
1835
            // Are there any fulltext files available?
1836
            if (!empty($extConf['fileGrpFulltext']) && in_array($extConf['fileGrpFulltext'], $this->fileGrps)) {
1837
1838
                $this->hasFulltext = TRUE;
1839
1840
            }
1841
1842
            $this->fileGrpsLoaded = TRUE;
1843
1844
        }
1845
1846
        return $this->fileGrps;
1847
1848
    }
1849
1850
    /**
1851
     * This returns $this->hasFulltext via __get()
1852
     *
1853
     * @access	protected
1854
     *
1855
     * @return	boolean		Are there any fulltext files available?
1856
     */
1857
    protected function _getHasFulltext() {
1858
1859
        // Are the fileGrps already loaded?
1860
        if (!$this->fileGrpsLoaded) {
1861
1862
            $this->_getFileGrps();
1863
1864
        }
1865
1866
        return $this->hasFulltext;
1867
1868
    }
1869
1870
    /**
1871
     * This returns $this->location via __get()
1872
     *
1873
     * @access	protected
1874
     *
1875
     * @return	string		The location of the document
1876
     */
1877
    protected function _getLocation() {
1878
1879
        return $this->location;
1880
1881
    }
1882
1883
    /**
1884
     * This builds an array of the document's metadata
1885
     *
1886
     * @access	protected
1887
     *
1888
     * @return	array		Array of metadata with their corresponding logical structure node ID as key
1889
     */
1890
    protected function _getMetadataArray() {
1891
1892
        // Set metadata definitions' PID.
1893
        $cPid = ($this->cPid ? $this->cPid : $this->pid);
1894
1895
        if (!$cPid) {
1896
1897
            if (TYPO3_DLOG) {
1898
1899
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->getMetadataArray()] Invalid PID "'.$cPid.'" for metadata definitions', self::$extKey, SYSLOG_SEVERITY_ERROR);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_ERROR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1900
1901
            }
1902
1903
            return array ();
1904
1905
        }
1906
1907
        if (!$this->metadataArrayLoaded || $this->metadataArray[0] != $cPid) {
1908
1909
            // Get all logical structure nodes with metadata.
1910
            if (($ids = $this->mets->xpath('./mets:structMap[@TYPE="LOGICAL"]//mets:div[@DMDID]/@ID'))) {
1911
1912
                foreach ($ids as $id) {
1913
1914
                    $this->metadataArray[(string) $id] = $this->getMetadata((string) $id, $cPid);
1915
1916
                }
1917
1918
            }
1919
1920
            // Set current PID for metadata definitions.
1921
            $this->metadataArray[0] = $cPid;
1922
1923
            $this->metadataArrayLoaded = TRUE;
1924
1925
        }
1926
1927
        return $this->metadataArray;
1928
1929
    }
1930
1931
    /**
1932
     * This returns $this->mets via __get()
1933
     *
1934
     * @access	protected
1935
     *
1936
     * @return	SimpleXMLElement		The XML's METS part as SimpleXMLElement object
1937
     */
1938
    protected function _getMets() {
1939
1940
        return $this->mets;
1941
1942
    }
1943
1944
    /**
1945
     * This returns $this->numPages via __get()
1946
     *
1947
     * @access	protected
1948
     *
1949
     * @return	integer		The total number of pages and/or tracks
1950
     */
1951
    protected function _getNumPages() {
1952
1953
        $this->_getPhysicalStructure();
1954
1955
        return $this->numPages;
1956
1957
    }
1958
1959
    /**
1960
     * This returns $this->parentId via __get()
1961
     *
1962
     * @access	protected
1963
     *
1964
     * @return	integer		The UID of the parent document or zero if not applicable
1965
     */
1966
    protected function _getParentId() {
1967
1968
        return $this->parentId;
1969
1970
    }
1971
1972
    /**
1973
     * This builds an array of the document's physical structure
1974
     *
1975
     * @access	protected
1976
     *
1977
     * @return	array		Array of physical elements' id, type, label and file representations ordered by @ORDER attribute
1978
     */
1979
    protected function _getPhysicalStructure() {
1980
1981
        // Is there no physical structure array yet?
1982
        if (!$this->physicalStructureLoaded) {
1983
1984
            // Does the document have a structMap node of type "PHYSICAL"?
1985
            $elementNodes = $this->mets->xpath('./mets:structMap[@TYPE="PHYSICAL"]/mets:div[@TYPE="physSequence"]/mets:div');
1986
1987
            if ($elementNodes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $elementNodes of type SimpleXMLElement[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
1988
1989
                // Get file groups.
1990
                $fileUse = $this->_getFileGrps();
1991
1992
                // Get the physical sequence's metadata.
1993
                $physNode = $this->mets->xpath('./mets:structMap[@TYPE="PHYSICAL"]/mets:div[@TYPE="physSequence"]');
1994
1995
                $physSeq[0] = (string) $physNode[0]['ID'];
1 ignored issue
show
Comprehensibility Best Practice introduced by
$physSeq was never initialized. Although not strictly required by PHP, it is generally a good practice to add $physSeq = array(); before regardless.
Loading history...
1996
1997
                $this->physicalStructureInfo[$physSeq[0]]['id'] = $physNode[0]['ID'];
1998
1999
                $this->physicalStructureInfo[$physSeq[0]]['dmdId'] = (isset($physNode[0]['DMDID']) ? (string) $physNode[0]['DMDID'] : '');
2000
2001
                $this->physicalStructureInfo[$physSeq[0]]['label'] = (isset($physNode[0]['LABEL']) ? (string) $physNode[0]['LABEL'] : '');
2002
2003
                $this->physicalStructureInfo[$physSeq[0]]['orderlabel'] = (isset($physNode[0]['ORDERLABEL']) ? (string) $physNode[0]['ORDERLABEL'] : '');
2004
2005
                $this->physicalStructureInfo[$physSeq[0]]['type'] = (string) $physNode[0]['TYPE'];
2006
2007
                $this->physicalStructureInfo[$physSeq[0]]['contentIds'] = (isset($physNode[0]['CONTENTIDS']) ? (string) $physNode[0]['CONTENTIDS'] : '');
2008
2009
                // Get the file representations from fileSec node.
2010
                foreach ($physNode[0]->children('http://www.loc.gov/METS/')->fptr as $fptr) {
2011
2012
                    // Check if file has valid @USE attribute.
2013
                    if (!empty($fileUse[(string) $fptr->attributes()->FILEID])) {
2014
2015
                        $this->physicalStructureInfo[$physSeq[0]]['files'][$fileUse[(string) $fptr->attributes()->FILEID]] = (string) $fptr->attributes()->FILEID;
2016
2017
                    }
2018
2019
                }
2020
2021
                // Build the physical elements' array from the physical structMap node.
2022
                foreach ($elementNodes as $elementNode) {
2023
2024
                    $elements[(int) $elementNode['ORDER']] = (string) $elementNode['ID'];
2025
2026
                    $this->physicalStructureInfo[$elements[(int) $elementNode['ORDER']]]['id'] = $elementNode['ID'];
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $elements seems to be defined later in this foreach loop on line 2024. Are you sure it is defined here?
Loading history...
2027
2028
                    $this->physicalStructureInfo[$elements[(int) $elementNode['ORDER']]]['dmdId'] = (isset($elementNode['DMDID']) ? (string) $elementNode['DMDID'] : '');
2029
2030
                    $this->physicalStructureInfo[$elements[(int) $elementNode['ORDER']]]['label'] = (isset($elementNode['LABEL']) ? (string) $elementNode['LABEL'] : '');
2031
2032
                    $this->physicalStructureInfo[$elements[(int) $elementNode['ORDER']]]['orderlabel'] = (isset($elementNode['ORDERLABEL']) ? (string) $elementNode['ORDERLABEL'] : '');
2033
2034
                    $this->physicalStructureInfo[$elements[(int) $elementNode['ORDER']]]['type'] = (string) $elementNode['TYPE'];
2035
2036
                    $this->physicalStructureInfo[$elements[(int) $elementNode['ORDER']]]['contentIds'] = (isset($elementNode['CONTENTIDS']) ? (string) $elementNode['CONTENTIDS'] : '');
2037
2038
                    // Get the file representations from fileSec node.
2039
                    foreach ($elementNode->children('http://www.loc.gov/METS/')->fptr as $fptr) {
2040
2041
                        // Check if file has valid @USE attribute.
2042
                        if (!empty($fileUse[(string) $fptr->attributes()->FILEID])) {
2043
2044
                            $this->physicalStructureInfo[$elements[(int) $elementNode['ORDER']]]['files'][$fileUse[(string) $fptr->attributes()->FILEID]] = (string) $fptr->attributes()->FILEID;
2045
2046
                        }
2047
2048
                    }
2049
2050
                }
2051
2052
                // Sort array by keys (= @ORDER).
2053
                if (ksort($elements)) {
2054
2055
                    // Set total number of pages/tracks.
2056
                    $this->numPages = count($elements);
2057
2058
                    // Merge and re-index the array to get nice numeric indexes.
2059
                    $this->physicalStructure = array_merge($physSeq, $elements);
2060
2061
                }
2062
2063
            }
2064
2065
            $this->physicalStructureLoaded = TRUE;
2066
2067
        }
2068
2069
        return $this->physicalStructure;
2070
2071
    }
2072
2073
    /**
2074
     * This gives an array of the document's physical structure metadata
2075
     *
2076
     * @access	protected
2077
     *
2078
     * @return	array		Array of elements' type, label and file representations ordered by @ID attribute
2079
     */
2080
    protected function _getPhysicalStructureInfo() {
2081
2082
        // Is there no physical structure array yet?
2083
        if (!$this->physicalStructureLoaded) {
2084
2085
            // Build physical structure array.
2086
            $this->_getPhysicalStructure();
2087
2088
        }
2089
2090
        return $this->physicalStructureInfo;
2091
2092
    }
2093
2094
    /**
2095
     * This returns $this->pid via __get()
2096
     *
2097
     * @access	protected
2098
     *
2099
     * @return	integer		The PID of the document or zero if not in database
2100
     */
2101
    protected function _getPid() {
2102
2103
        return $this->pid;
2104
2105
    }
2106
2107
    /**
2108
     * This returns $this->ready via __get()
2109
     *
2110
     * @access	protected
2111
     *
2112
     * @return	boolean		Is the document instantiated successfully?
2113
     */
2114
    protected function _getReady() {
2115
2116
        return $this->ready;
2117
2118
    }
2119
2120
    /**
2121
     * This returns $this->recordId via __get()
2122
     *
2123
     * @access	protected
2124
     *
2125
     * @return	mixed		The METS file's record identifier
2126
     */
2127
    protected function _getRecordId() {
2128
2129
        return $this->recordId;
2130
2131
    }
2132
2133
    /**
2134
     * This returns $this->rootId via __get()
2135
     *
2136
     * @access	protected
2137
     *
2138
     * @return	integer		The UID of the root document or zero if not applicable
2139
     */
2140
    protected function _getRootId() {
2141
2142
        if (!$this->rootIdLoaded) {
2143
2144
            if ($this->parentId) {
2145
2146
                $parent = self::getInstance($this->parentId, $this->pid);
2147
2148
                $this->rootId = $parent->rootId;
2149
2150
            }
2151
2152
            $this->rootIdLoaded = TRUE;
2153
2154
        }
2155
2156
        return $this->rootId;
2157
2158
    }
2159
2160
    /**
2161
     * This returns the smLinks between logical and physical structMap
2162
     *
2163
     * @access	protected
2164
     *
2165
     * @return	array		The links between logical and physical nodes
2166
     */
2167
    protected function _getSmLinks() {
2168
2169
        if (!$this->smLinksLoaded) {
2170
2171
            $smLinks = $this->mets->xpath('./mets:structLink/mets:smLink');
2172
2173
            foreach ($smLinks as $smLink) {
2174
2175
                $this->smLinks['l2p'][(string) $smLink->attributes('http://www.w3.org/1999/xlink')->from][] = (string) $smLink->attributes('http://www.w3.org/1999/xlink')->to;
2176
2177
                $this->smLinks['p2l'][(string) $smLink->attributes('http://www.w3.org/1999/xlink')->to][] = (string) $smLink->attributes('http://www.w3.org/1999/xlink')->from;
2178
2179
            }
2180
2181
            $this->smLinksLoaded = TRUE;
2182
2183
        }
2184
2185
        return $this->smLinks;
2186
2187
    }
2188
2189
    /**
2190
     * This builds an array of the document's logical structure
2191
     *
2192
     * @access	protected
2193
     *
2194
     * @return	array		Array of structure nodes' id, label, type and physical page indexes/mptr link with original hierarchy preserved
2195
     */
2196
    protected function _getTableOfContents() {
2197
2198
        // Is there no logical structure array yet?
2199
        if (!$this->tableOfContentsLoaded) {
2200
2201
            // Get all logical structures.
2202
            $this->getLogicalStructure('', TRUE);
2203
2204
            $this->tableOfContentsLoaded = TRUE;
2205
2206
        }
2207
2208
        return $this->tableOfContents;
2209
2210
    }
2211
2212
    /**
2213
     * This returns the document's thumbnail location
2214
     *
2215
     * @access	protected
2216
     *
2217
     * @param	boolean		$forceReload: Force reloading the thumbnail instead of returning the cached value
2218
     *
2219
     * @return	string		The document's thumbnail location
2220
     */
2221
    protected function _getThumbnail($forceReload = FALSE) {
2222
2223
        if (!$this->thumbnailLoaded || $forceReload) {
2224
2225
            // Retain current PID.
2226
            $cPid = ($this->cPid ? $this->cPid : $this->pid);
2227
2228
            if (!$cPid) {
2229
2230
                if (TYPO3_DLOG) {
2231
2232
                    \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->_getThumbnail()] Invalid PID "'.$cPid.'" for structure definitions', self::$extKey, SYSLOG_SEVERITY_ERROR);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_ERROR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2233
2234
                }
2235
2236
                $this->thumbnailLoaded = TRUE;
2237
2238
                return $this->thumbnail;
2239
2240
            }
2241
2242
            // Load extension configuration.
2243
            $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][self::$extKey]);
2244
2245
            if (empty($extConf['fileGrpThumbs'])) {
2246
2247
                if (TYPO3_DLOG) {
2248
2249
                    \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->_getThumbnail()] No fileGrp for thumbnails specified', self::$extKey, SYSLOG_SEVERITY_WARNING);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_WARNING was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2250
2251
                }
2252
2253
                $this->thumbnailLoaded = TRUE;
2254
2255
                return $this->thumbnail;
2256
2257
            }
2258
2259
            $strctId = $this->_getToplevelId();
2260
2261
            $metadata = $this->getTitledata($cPid);
2262
2263
            // Get structure element to get thumbnail from.
2264
            $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
2265
                'tx_dlf_structures.thumbnail AS thumbnail',
2266
                'tx_dlf_structures',
2267
                'tx_dlf_structures.pid='.intval($cPid).' AND tx_dlf_structures.index_name='.$GLOBALS['TYPO3_DB']->fullQuoteStr($metadata['type'][0], 'tx_dlf_structures').tx_dlf_helper::whereClause('tx_dlf_structures'),
2268
                '',
2269
                '',
2270
                '1'
2271
            );
2272
2273
            if ($GLOBALS['TYPO3_DB']->sql_num_rows($result) > 0) {
2274
2275
                $resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result);
2276
2277
                // Get desired thumbnail structure if not the toplevel structure itself.
2278
                if (!empty($resArray['thumbnail'])) {
2279
2280
                    $strctType = tx_dlf_helper::getIndexName($resArray['thumbnail'], 'tx_dlf_structures', $cPid);
2281
2282
                    // Check if this document has a structure element of the desired type.
2283
                    $strctIds = $this->mets->xpath('./mets:structMap[@TYPE="LOGICAL"]//mets:div[@TYPE="'.$strctType.'"]/@ID');
2284
2285
                    if (!empty($strctIds)) {
2286
2287
                        $strctId = (string) $strctIds[0];
2288
2289
                    }
2290
2291
                }
2292
2293
                // Load smLinks.
2294
                $this->_getSmLinks();
2295
2296
                // Get thumbnail location.
2297
                if ($this->_getPhysicalStructure() && !empty($this->smLinks['l2p'][$strctId])) {
2298
2299
                    $this->thumbnail = $this->getFileLocation($this->physicalStructureInfo[$this->smLinks['l2p'][$strctId][0]]['files'][$extConf['fileGrpThumbs']]);
2300
2301
                } else {
2302
2303
                    $this->thumbnail = $this->getFileLocation($this->physicalStructureInfo[$this->physicalStructure[1]]['files'][$extConf['fileGrpThumbs']]);
2304
2305
                }
2306
2307
            } elseif (TYPO3_DLOG) {
2308
2309
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->_getThumbnail()] No structure of type "'.$metadata['type'][0].'" found in database', self::$extKey, SYSLOG_SEVERITY_ERROR);
2310
2311
            }
2312
2313
            $this->thumbnailLoaded = TRUE;
2314
2315
        }
2316
2317
        return $this->thumbnail;
2318
2319
    }
2320
2321
    /**
2322
     * This returns the ID of the toplevel logical structure node
2323
     *
2324
     * @access	protected
2325
     *
2326
     * @return	string		The logical structure node's ID
2327
     */
2328
    protected function _getToplevelId() {
2329
2330
        if (empty($this->toplevelId)) {
2331
2332
            // Get all logical structure nodes with metadata, but without associated METS-Pointers.
2333
            if (($divs = $this->mets->xpath('./mets:structMap[@TYPE="LOGICAL"]//mets:div[@DMDID and not(./mets:mptr)]'))) {
2334
2335
                // Load smLinks.
2336
                $this->_getSmLinks();
2337
2338
                foreach ($divs as $div) {
2339
2340
                    $id = (string) $div['ID'];
2341
2342
                    // Are there physical structure nodes for this logical structure?
2343
                    if (array_key_exists($id, $this->smLinks['l2p'])) {
2344
2345
                        // Yes. That's what we're looking for.
2346
                        $this->toplevelId = $id;
2347
2348
                        break;
2349
2350
                    } elseif (empty($this->toplevelId)) {
2351
2352
                        // No. Remember this anyway, but keep looking for a better one.
2353
                        $this->toplevelId = $id;
2354
2355
                    }
2356
2357
                }
2358
2359
            }
2360
2361
        }
2362
2363
        return $this->toplevelId;
2364
2365
    }
2366
2367
    /**
2368
     * This returns $this->uid via __get()
2369
     *
2370
     * @access	protected
2371
     *
2372
     * @return	mixed		The UID or the URL of the document
2373
     */
2374
    protected function _getUid() {
2375
2376
        return $this->uid;
2377
2378
    }
2379
2380
    /**
2381
     * This sets $this->cPid via __set()
2382
     *
2383
     * @access	protected
2384
     *
2385
     * @param	integer		$value: The new PID for the metadata definitions
2386
     *
2387
     * @return	void
2388
     */
2389
    protected function _setCPid($value) {
2390
2391
        $this->cPid = max(intval($value), 0);
2392
2393
    }
2394
2395
    /**
2396
     * This magic method is invoked each time a clone is called on the object variable
2397
     * (This method is defined as private/protected because singleton objects should not be cloned)
2398
     *
2399
     * @access	protected
2400
     *
2401
     * @return	void
2402
     */
2403
    protected function __clone() {}
2404
2405
    /**
2406
     * This is a singleton class, thus the constructor should be private/protected
2407
     *
2408
     * @access	protected
2409
     *
2410
     * @param	integer		$uid: The UID of the document to parse or URL to XML file
2411
     * @param	integer		$pid: If > 0, then only document with this PID gets loaded
2412
     *
2413
     * @return	void
2414
     */
2415
    protected function __construct($uid, $pid) {
2416
2417
        // Prepare to check database for the requested document.
2418
        if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($uid)) {
2419
2420
            $whereClause = 'tx_dlf_documents.uid='.intval($uid).tx_dlf_helper::whereClause('tx_dlf_documents');
2421
2422
        } else {
2423
2424
            // Cast to string for safety reasons.
2425
            $location = (string) $uid;
2426
2427
            // Try to load METS file.
2428
            if (\TYPO3\CMS\Core\Utility\GeneralUtility::isValidUrl($location) && $this->load($location)) {
2429
2430
                // Initialize core METS object.
2431
                $this->init();
2432
2433
                if ($this->mets !== NULL) {
2434
2435
                    // Check for METS object @ID.
2436
                    if (!empty($this->mets['OBJID'])) {
2437
2438
                        $this->recordId = (string) $this->mets['OBJID'];
2439
2440
                    }
2441
2442
                    // Get hook objects.
2443
                    $hookObjects = tx_dlf_helper::getHookObjects('common/class.tx_dlf_document.php');
2444
2445
                    // Apply hooks.
2446
                    foreach ($hookObjects as $hookObj) {
2447
2448
                        if (method_exists($hookObj, 'construct_postProcessRecordId')) {
2449
2450
                            $hookObj->construct_postProcessRecordId($this->xml, $this->recordId);
2451
2452
                        }
2453
2454
                    }
2455
2456
                } else {
2457
2458
                    // No METS part found.
2459
                    return;
2460
2461
                }
2462
2463
            } else {
2464
2465
                // Loading failed.
2466
                return;
2467
2468
            }
2469
2470
            if (!empty($this->recordId)) {
2471
2472
                $whereClause = 'tx_dlf_documents.record_id='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->recordId, 'tx_dlf_documents').tx_dlf_helper::whereClause('tx_dlf_documents');
2473
2474
            } else {
2475
2476
                // There is no record identifier and there should be no hit in the database.
2477
                $whereClause = '1=-1';
2478
2479
            }
2480
2481
        }
2482
2483
        // Check for PID if needed.
2484
        if ($pid) {
2485
2486
            $whereClause .= ' AND tx_dlf_documents.pid='.intval($pid);
2487
2488
        }
2489
2490
        // Get document PID and location from database.
2491
        $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
2492
            'tx_dlf_documents.uid AS uid,tx_dlf_documents.pid AS pid,tx_dlf_documents.record_id AS record_id,tx_dlf_documents.partof AS partof,tx_dlf_documents.thumbnail AS thumbnail,tx_dlf_documents.location AS location',
2493
            'tx_dlf_documents',
2494
            $whereClause,
2495
            '',
2496
            '',
2497
            '1'
2498
        );
2499
2500
        if ($GLOBALS['TYPO3_DB']->sql_num_rows($result) > 0) {
2501
2502
            list ($this->uid, $this->pid, $this->recordId, $this->parentId, $this->thumbnail, $this->location) = $GLOBALS['TYPO3_DB']->sql_fetch_row($result);
2503
2504
            $this->thumbnailLoaded = TRUE;
2505
2506
            // Load XML file if necessary...
2507
            if ($this->mets === NULL && $this->load($this->location)) {
2508
2509
                // ...and set some basic properties.
2510
                $this->init();
2511
2512
            }
2513
2514
            // Do we have a METS object now?
2515
            if ($this->mets !== NULL) {
2516
2517
                // Set new location if necessary.
2518
                if (!empty($location)) {
2519
2520
                    $this->location = $location;
2521
2522
                }
2523
2524
                // Document ready!
2525
                $this->ready = TRUE;
2526
2527
            }
2528
2529
        } elseif ($this->mets !== NULL) {
2530
2531
            // Set location as UID for documents not in database.
2532
            $this->uid = $location;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $location does not seem to be defined for all execution paths leading up to this point.
Loading history...
2533
2534
            $this->location = $location;
2535
2536
            // Document ready!
2537
            $this->ready = TRUE;
2538
2539
        } else {
2540
2541
            if (TYPO3_DLOG) {
2542
2543
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->__construct('.$uid.', '.$pid.')] No document with UID "'.$uid.'" found or document not accessible', self::$extKey, SYSLOG_SEVERITY_ERROR);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_ERROR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2544
2545
            }
2546
2547
        }
2548
2549
    }
2550
2551
    /**
2552
     * This magic method is called each time an invisible property is referenced from the object
2553
     *
2554
     * @access	public
2555
     *
2556
     * @param	string		$var: Name of variable to get
2557
     *
2558
     * @return	mixed		Value of $this->$var
2559
     */
2560
    public function __get($var) {
2561
2562
        $method = '_get'.ucfirst($var);
2563
2564
        if (!property_exists($this, $var) || !method_exists($this, $method)) {
2565
2566
            if (TYPO3_DLOG) {
2567
2568
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->__get('.$var.')] There is no getter function for property "'.$var.'"', self::$extKey, SYSLOG_SEVERITY_WARNING);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_WARNING was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2569
2570
            }
2571
2572
            return;
2573
2574
        } else {
2575
2576
            return $this->$method();
2577
2578
        }
2579
2580
    }
2581
2582
    /**
2583
     * This magic method is called each time an invisible property is referenced from the object
2584
     *
2585
     * @access	public
2586
     *
2587
     * @param	string		$var: Name of variable to set
2588
     * @param	mixed		$value: New value of variable
2589
     *
2590
     * @return	void
2591
     */
2592
    public function __set($var, $value) {
2593
2594
        $method = '_set'.ucfirst($var);
2595
2596
        if (!property_exists($this, $var) || !method_exists($this, $method)) {
2597
2598
            if (TYPO3_DLOG) {
2599
2600
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->__set('.$var.', '.$value.')] There is no setter function for property "'.$var.'"', self::$extKey, SYSLOG_SEVERITY_WARNING);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_WARNING was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2601
2602
            }
2603
2604
        } else {
2605
2606
            $this->$method($value);
2607
2608
        }
2609
2610
    }
2611
2612
    /**
2613
     * This magic method is executed prior to any serialization of the object
2614
     * @see __wakeup()
2615
     *
2616
     * @access	public
2617
     *
2618
     * @return	array		Properties to be serialized
2619
     */
2620
    public function __sleep() {
2621
2622
        // SimpleXMLElement objects can't be serialized, thus save the XML as string for serialization
2623
        $this->asXML = $this->xml->asXML();
2624
2625
        return array ('uid', 'pid', 'recordId', 'parentId', 'asXML');
2626
2627
    }
2628
2629
    /**
2630
     * This magic method is used for setting a string value for the object
2631
     *
2632
     * @access	public
2633
     *
2634
     * @return	string		String representing the METS object
2635
     */
2636
    public function __toString() {
2637
2638
        $xml = new DOMDocument('1.0', 'utf-8');
2639
2640
        $xml->appendChild($xml->importNode(dom_import_simplexml($this->mets), TRUE));
2641
2642
        $xml->formatOutput = TRUE;
2643
2644
        return $xml->saveXML();
2645
2646
    }
2647
2648
    /**
2649
     * This magic method is executed after the object is deserialized
2650
     * @see __sleep()
2651
     *
2652
     * @access	public
2653
     *
2654
     * @return	void
2655
     */
2656
    public function __wakeup() {
2657
2658
        // Turn off libxml's error logging.
2659
        $libxmlErrors = libxml_use_internal_errors(TRUE);
2660
2661
        // Reload XML from string.
2662
        $xml = @simplexml_load_string($this->asXML);
2663
2664
        // Reset libxml's error logging.
2665
        libxml_use_internal_errors($libxmlErrors);
2666
2667
        if ($xml !== FALSE) {
2668
2669
            $this->asXML = '';
2670
2671
            $this->xml = $xml;
2672
2673
            // Rebuild the unserializable properties.
2674
            $this->init();
2675
2676
        } else {
2677
2678
            if (TYPO3_DLOG) {
2679
2680
                \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[tx_dlf_document->__wakeup()] Could not load XML after deserialization', self::$extKey, SYSLOG_SEVERITY_ERROR);
0 ignored issues
show
Bug introduced by
The constant SYSLOG_SEVERITY_ERROR was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2681
2682
            }
2683
2684
        }
2685
2686
    }
2687
2688
}
2689