1
|
|
|
<?php |
2
|
|
|
namespace Kitodo\Dlf\Common; |
3
|
|
|
|
4
|
|
|
/** |
5
|
|
|
* (c) Kitodo. Key to digital objects e.V. <[email protected]> |
6
|
|
|
* |
7
|
|
|
* This file is part of the Kitodo and TYPO3 projects. |
8
|
|
|
* |
9
|
|
|
* @license GNU General Public License version 3 or later. |
10
|
|
|
* For the full copyright and license information, please read the |
11
|
|
|
* LICENSE.txt file that was distributed with this source code. |
12
|
|
|
*/ |
13
|
|
|
|
14
|
|
|
use Flow\JSONPath\JSONPath; |
15
|
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility; |
16
|
|
|
use Ubl\Iiif\Presentation\Common\Model\Resources\AnnotationContainerInterface; |
17
|
|
|
use Ubl\Iiif\Presentation\Common\Model\Resources\AnnotationInterface; |
18
|
|
|
use Ubl\Iiif\Presentation\Common\Model\Resources\CanvasInterface; |
19
|
|
|
use Ubl\Iiif\Presentation\Common\Model\Resources\ContentResourceInterface; |
20
|
|
|
use Ubl\Iiif\Presentation\Common\Model\Resources\IiifResourceInterface; |
21
|
|
|
use Ubl\Iiif\Presentation\Common\Model\Resources\ManifestInterface; |
22
|
|
|
use Ubl\Iiif\Presentation\Common\Model\Resources\RangeInterface; |
23
|
|
|
use Ubl\Iiif\Presentation\Common\Vocabulary\Motivation; |
24
|
|
|
use Ubl\Iiif\Presentation\V1\Model\Resources\AbstractIiifResource1; |
25
|
|
|
use Ubl\Iiif\Presentation\V2\Model\Resources\AbstractIiifResource2; |
26
|
|
|
use Ubl\Iiif\Presentation\V3\Model\Resources\AbstractIiifResource3; |
27
|
|
|
use Ubl\Iiif\Services\AbstractImageService; |
28
|
|
|
use Ubl\Iiif\Services\Service; |
29
|
|
|
use Ubl\Iiif\Tools\IiifHelper; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* IiifManifest class for the 'dlf' extension. This class |
33
|
|
|
* represents a IIIF manifest in the conext of this TYPO3 extension. |
34
|
|
|
* |
35
|
|
|
* @author Lutz Helm <[email protected]> |
36
|
|
|
* @package TYPO3 |
37
|
|
|
* @subpackage tx_dlf |
38
|
|
|
* @access public |
39
|
|
|
*/ |
40
|
|
|
final class IiifManifest extends Document |
41
|
|
|
{ |
42
|
|
|
/** |
43
|
|
|
* This holds the manifest file as string for serialization purposes |
44
|
|
|
* @see __sleep() / __wakeup() |
45
|
|
|
* |
46
|
|
|
* @var string |
47
|
|
|
* @access protected |
48
|
|
|
*/ |
49
|
|
|
protected $asJson = ''; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* A PHP object representation of a IIIF manifest. |
53
|
|
|
* @var ManifestInterface |
54
|
|
|
* @access protected |
55
|
|
|
*/ |
56
|
|
|
protected $iiif; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* 'IIIF1', 'IIIF2' or 'IIIF3', depending on the API $this->iiif confrms to: |
60
|
|
|
* IIIF Metadata API 1, IIIF Presentation API 2 or 3 |
61
|
|
|
* @var string |
62
|
|
|
* @access protected |
63
|
|
|
*/ |
64
|
|
|
protected $iiifVersion; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Document has already been analyzed if it contains fulltext for the Solr index |
68
|
|
|
* @var boolean |
69
|
|
|
* @access protected |
70
|
|
|
*/ |
71
|
|
|
protected $hasFulltextSet = false; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* This holds the original manifest's parsed metadata array with their corresponding |
75
|
|
|
* resource (Manifest / Sequence / Range) ID as array key |
76
|
|
|
* |
77
|
|
|
* @var array |
78
|
|
|
* @access protected |
79
|
|
|
*/ |
80
|
|
|
protected $originalMetadataArray = array (); |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* Holds the mime types of linked resources in the manifest (extreacted during parsing) for later use. |
84
|
|
|
* @var array |
85
|
|
|
* @access protected |
86
|
|
|
*/ |
87
|
|
|
protected $mimeTypes = []; |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* The extension key |
91
|
|
|
* |
92
|
|
|
* @var string |
93
|
|
|
* @static |
94
|
|
|
* @access public |
95
|
|
|
*/ |
96
|
|
|
public static $extKey = 'dlf'; |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* {@inheritDoc} |
100
|
|
|
* @see Document::establishRecordId() |
101
|
|
|
*/ |
102
|
|
|
protected function establishRecordId($pid) |
103
|
|
|
{ |
104
|
|
|
if ($this->iiif !== null) { |
105
|
|
|
/* |
106
|
|
|
* FIXME This will not consistently work because we can not be sure to have the pid at hand. It may miss |
107
|
|
|
* if the plugin that actually loads the manifest allows content from other pages. |
108
|
|
|
* Up until now the cPid is only set after the document has been initialized. We need it before to |
109
|
|
|
* check the configuration. |
110
|
|
|
* TODO Saving / indexing should still work - check! |
111
|
|
|
*/ |
112
|
|
|
$result = $GLOBALS['TYPO3_DB']->exec_SELECTquery( |
113
|
|
|
'tx_dlf_metadataformat.xpath AS querypath', |
114
|
|
|
'tx_dlf_metadata,tx_dlf_metadataformat,tx_dlf_formats', |
115
|
|
|
'tx_dlf_metadata.pid='.intval($pid) |
116
|
|
|
.' AND tx_dlf_metadataformat.pid='.intval($pid) |
117
|
|
|
.' AND ((tx_dlf_metadata.uid=tx_dlf_metadataformat.parent_id AND tx_dlf_metadataformat.encoded=tx_dlf_formats.uid' |
118
|
|
|
.' AND tx_dlf_metadata.index_name="record_id" AND tx_dlf_formats.type='.$GLOBALS['TYPO3_DB']->fullQuoteStr($this->getIiifVersion(), 'tx_dlf_formats').') OR tx_dlf_metadata.format=0)' |
119
|
|
|
.Helper::whereClause('tx_dlf_metadata', TRUE) |
120
|
|
|
.Helper::whereClause('tx_dlf_metadataformat') |
121
|
|
|
.Helper::whereClause('tx_dlf_formats') |
122
|
|
|
); |
123
|
|
|
if ($GLOBALS['TYPO3_DB']->sql_num_rows($result) > 0) { |
124
|
|
|
for ($i = 0, $j = $GLOBALS['TYPO3_DB']->sql_num_rows($result); $i < $j; $i++) { |
125
|
|
|
$resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result); |
126
|
|
|
$recordIdPath = $resArray['querypath']; |
127
|
|
|
if (!empty($recordIdPath)) { |
128
|
|
|
$this->recordId = $this->iiif->jsonPath($recordIdPath); |
|
|
|
|
129
|
|
|
} |
130
|
|
|
} |
131
|
|
|
} |
132
|
|
|
// For now, it's a hardcoded ID, not only as a fallback |
133
|
|
|
if (!isset($this->recordId)) { |
134
|
|
|
$this->recordId = $this->iiif->getId(); |
135
|
|
|
} |
136
|
|
|
} |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* {@inheritDoc} |
141
|
|
|
* @see Document::getDocument() |
142
|
|
|
*/ |
143
|
|
|
protected function getDocument() |
144
|
|
|
{ |
145
|
|
|
return $this->iiif; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Returns a string representing the Metadata / Presentation API version which the IIIF resource |
150
|
|
|
* conforms to. This is used for example to extract metadata according to configured patterns. |
151
|
|
|
* |
152
|
|
|
* @access public |
153
|
|
|
* |
154
|
|
|
* @return string 'IIIF1' if the resource is a Metadata API 1 resource, 'IIIF2' / 'IIIF3' if |
155
|
|
|
* the resource is a Presentation API 2 / 3 resource |
156
|
|
|
*/ |
157
|
|
|
public function getIiifVersion() { |
158
|
|
|
if (!isset($this->iiifVersion)) { |
159
|
|
|
if ($this->iiif instanceof AbstractIiifResource1) { |
160
|
|
|
$this->iiifVersion = 'IIIF1'; |
161
|
|
|
} elseif ($this->iiif instanceof AbstractIiifResource2) { |
162
|
|
|
$this->iiifVersion = 'IIIF2'; |
163
|
|
|
} elseif ($this->iiif instanceof AbstractIiifResource3) { |
164
|
|
|
$this->iiifVersion = 'IIIF3'; |
165
|
|
|
} |
166
|
|
|
} |
167
|
|
|
return $this->iiifVersion; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* True if getUseGroups() has been called and $this-useGrps is loaded |
172
|
|
|
* |
173
|
|
|
* @var boolean |
174
|
|
|
* @access protected |
175
|
|
|
*/ |
176
|
|
|
protected $useGrpsLoaded; |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* Holds the configured useGrps as array. |
180
|
|
|
* |
181
|
|
|
* @var array |
182
|
|
|
* @access protected |
183
|
|
|
*/ |
184
|
|
|
protected $useGrps; |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* IiifManifest also populates the physical stucture array entries for matching |
188
|
|
|
* 'fileGrp's. To do that, the configuration has to be loaded; afterwards configured |
189
|
|
|
* 'fileGrp's for thumbnails, downloads, audio, fulltext and the 'fileGrp's for images |
190
|
|
|
* can be requested with this method. |
191
|
|
|
* |
192
|
|
|
* @access protected |
193
|
|
|
* |
194
|
|
|
* @param string $use |
195
|
|
|
* |
196
|
|
|
* @return array|string |
197
|
|
|
*/ |
198
|
|
|
protected function getUseGroups($use) |
199
|
|
|
{ |
200
|
|
|
if (!$this->useGrpsLoaded) { |
201
|
|
|
// Get configured USE attributes. |
202
|
|
|
$extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][self::$extKey]); |
203
|
|
|
if (!empty($extConf['fileGrps'])) { |
204
|
|
|
$this->useGrps['fileGrps'] = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $extConf['fileGrps']); |
205
|
|
|
} |
206
|
|
|
if (!empty($extConf['fileGrpThumbs'])) { |
207
|
|
|
$this->useGrps['fileGrpThumbs'] = $extConf['fileGrpThumbs']; |
208
|
|
|
} |
209
|
|
|
if (!empty($extConf['fileGrpDownload'])) { |
210
|
|
|
$this->useGrps['fileGrpDownload'] = $extConf['fileGrpDownload']; |
211
|
|
|
} |
212
|
|
|
if (!empty($extConf['fileGrpFulltext'])) { |
213
|
|
|
$this->useGrps['fileGrpFulltext'] = $extConf['fileGrpFulltext']; |
214
|
|
|
} |
215
|
|
|
if (!empty($extConf['fileGrpAudio'])) { |
216
|
|
|
$this->useGrps['fileGrpAudio'] = $extConf['fileGrpAudio']; |
217
|
|
|
} |
218
|
|
|
} |
219
|
|
|
return array_key_exists($use, $this->useGrps) ? $this->useGrps[$use] : []; |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* {@inheritDoc} |
224
|
|
|
* @see Document::_getPhysicalStructure() |
225
|
|
|
*/ |
226
|
|
|
protected function _getPhysicalStructure() |
227
|
|
|
{ |
228
|
|
|
// Is there no physical structure array yet? |
229
|
|
|
if (!$this->physicalStructureLoaded) { |
230
|
|
|
if ($this->iiif == null || !($this->iiif instanceof ManifestInterface)) { |
231
|
|
|
return null; |
232
|
|
|
} |
233
|
|
|
$extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][self::$extKey]); |
234
|
|
|
$iiifId = $this->iiif->getId(); |
235
|
|
|
$physSeq[0] = $iiifId; |
|
|
|
|
236
|
|
|
$this->physicalStructureInfo[$physSeq[0]]['id'] = $iiifId; |
237
|
|
|
$this->physicalStructureInfo[$physSeq[0]]['dmdId'] = $iiifId; |
238
|
|
|
$this->physicalStructureInfo[$physSeq[0]]['label'] = $this->iiif->getLabelForDisplay(); |
239
|
|
|
$this->physicalStructureInfo[$physSeq[0]]['orderlabel'] = $this->iiif->getLabelForDisplay(); |
240
|
|
|
$this->physicalStructureInfo[$physSeq[0]]['type'] = 'physSequence'; |
241
|
|
|
$this->physicalStructureInfo[$physSeq[0]]['contentIds'] = null; |
242
|
|
|
$fileUseDownload = $this->getUseGroups('fileGrpDownload'); |
243
|
|
|
$fileUseFulltext = $this->getUseGroups('fileGrpFulltext'); |
244
|
|
|
$fileUseThumbs = $this->getUseGroups('fileGrpThumbs'); |
245
|
|
|
$fileUses = $this->getUseGroups('fileGrps'); |
246
|
|
|
if (isset($fileUseDownload)) { |
247
|
|
|
$docPdfRendering = $this->iiif->getRenderingUrlsForFormat('application/pdf'); |
248
|
|
|
if (!empty($docPdfRendering)) { |
249
|
|
|
$this->physicalStructureInfo[$physSeq[0]]['files'][$fileUseDownload] = $docPdfRendering[0]; |
250
|
|
|
} |
251
|
|
|
} |
252
|
|
|
if (isset($fileUseFulltext)) { |
253
|
|
|
$iiifAlto = $this->iiif->getSeeAlsoUrlsForFormat("application/alto+xml"); |
254
|
|
|
if (empty($iiifAlto)) { |
255
|
|
|
$iiifAlto = $this->iiif->getSeeAlsoUrlsForProfile("http://www.loc.gov/standards/alto/", true); |
256
|
|
|
} |
257
|
|
|
if (!empty($iiifAlto)) { |
258
|
|
|
// TODO use multiple possible alto files? |
259
|
|
|
$this->mimeTypes[$iiifAlto[0]] = "application/alto+xml"; |
260
|
|
|
$this->physicalStructureInfo[$physSeq[0]]['files'][$fileUseFulltext] = $iiifAlto[0]; |
261
|
|
|
$this->hasFulltext = true; |
262
|
|
|
$this->hasFulltextSet = true; |
263
|
|
|
} |
264
|
|
|
} |
265
|
|
|
if (!empty($this->iiif->getDefaultCanvases())) { |
266
|
|
|
// canvases have not order property, but the context defines canveses as @list with a specific order, so we can provide an alternative |
267
|
|
|
$canvasOrder = 0; |
268
|
|
|
foreach ($this->iiif->getDefaultCanvases() as $canvas) { |
269
|
|
|
$canvasOrder++; |
270
|
|
|
$thumbnailUrl = $canvas->getThumbnailUrl(); |
271
|
|
|
// put thumbnails in thumbnail filegroup |
272
|
|
|
if (isset($thumbnailUrl)) { |
273
|
|
|
$this->physicalStructureInfo[$physSeq[0]]['files'][$fileUseThumbs] = $thumbnailUrl; |
274
|
|
|
} |
275
|
|
|
$image = $canvas->getImageAnnotations()[0]; |
276
|
|
|
// put images in all non specific filegroups |
277
|
|
|
if (isset($fileUses)) { |
278
|
|
|
foreach ($fileUses as $fileUse) { |
279
|
|
|
if ($image->getBody() != null && $image->getBody() instanceof ContentResourceInterface) { |
280
|
|
|
$this->physicalStructureInfo[$physSeq[0]]['files'][$fileUse] = $image->getBody()->getId(); |
281
|
|
|
} |
282
|
|
|
} |
283
|
|
|
} |
284
|
|
|
// populate structural metadata info |
285
|
|
|
$elements[$canvasOrder] = $canvas->getId(); |
286
|
|
|
$this->physicalStructureInfo[$elements[$canvasOrder]]['id']=$canvas->getId(); |
287
|
|
|
$this->physicalStructureInfo[$elements[$canvasOrder]]['dmdId']=null; |
288
|
|
|
$this->physicalStructureInfo[$elements[$canvasOrder]]['label']=$canvas->getLabelForDisplay(); |
289
|
|
|
$this->physicalStructureInfo[$elements[$canvasOrder]]['orderlabel']=$canvas->getLabelForDisplay(); |
290
|
|
|
// assume that a canvas always represents a page |
291
|
|
|
$this->physicalStructureInfo[$elements[$canvasOrder]]['type']='page'; |
292
|
|
|
$this->physicalStructureInfo[$elements[$canvasOrder]]['contentIds']=null; |
293
|
|
|
$this->physicalStructureInfo[$elements[$canvasOrder]]['annotationContainers'] = null; |
294
|
|
|
if (!empty($canvas->getPossibleTextAnnotationContainers(Motivation::PAINTING))) { |
|
|
|
|
295
|
|
|
$this->physicalStructureInfo[$elements[$canvasOrder]]['annotationContainers'] = array(); |
296
|
|
|
$this->physicalStructureInfo[$physSeq[0]]['annotationContainers'] = array(); |
297
|
|
|
foreach ($canvas->getPossibleTextAnnotationContainers(Motivation::PAINTING) as $annotationContainer) { |
298
|
|
|
$this->physicalStructureInfo[$elements[$canvasOrder]]['annotationContainers'][] = $annotationContainer->getId(); |
299
|
|
|
if ($extConf['indexAnnotations']) { |
300
|
|
|
$this->hasFulltext = true; |
301
|
|
|
$this->hasFulltextSet = true; |
302
|
|
|
} |
303
|
|
|
} |
304
|
|
|
} |
305
|
|
|
if (isset($fileUseFulltext)) { |
306
|
|
|
$alto = $canvas->getSeeAlsoUrlsForFormat("application/alto+xml"); |
307
|
|
|
if (empty($alto)) { |
308
|
|
|
$alto = $canvas->getSeeAlsoUrlsForProfile("http://www.loc.gov/standards/alto/", true); |
309
|
|
|
} |
310
|
|
|
if (!empty($alto)) { |
311
|
|
|
// TODO use all possible alto files? |
312
|
|
|
$this->mimeTypes[$alto[0]] = "application/alto+xml"; |
313
|
|
|
$this->physicalStructureInfo[$elements[$canvasOrder]]['files'][$fileUseFulltext] = $alto[0]; |
314
|
|
|
$this->hasFulltext = true; |
315
|
|
|
$this->hasFulltextSet = true; |
316
|
|
|
} |
317
|
|
|
} |
318
|
|
|
if (isset($fileUses)) { |
319
|
|
|
foreach ($fileUses as $fileUse) { |
320
|
|
|
if ($image->getBody() != null && $image->getBody() instanceof ContentResourceInterface) { |
321
|
|
|
$this->physicalStructureInfo[$elements[$canvasOrder]]['files'][$fileUse] = $image->getBody()->getId(); |
322
|
|
|
} |
323
|
|
|
} |
324
|
|
|
} |
325
|
|
|
if (isset($thumbnailUrl)) { |
326
|
|
|
$this->physicalStructureInfo[$elements[$canvasOrder]]['files'][$fileUseThumbs] = $thumbnailUrl; |
327
|
|
|
} |
328
|
|
|
if (isset($fileUseDownload)) { |
329
|
|
|
$pdfRenderingUrls = $canvas->getRenderingUrlsForFormat('application/pdf'); |
330
|
|
|
if (!empty($pdfRenderingUrls)) { |
331
|
|
|
$this->physicalStructureInfo[$elements[$canvasOrder]]['files'][$fileUseDownload] = $pdfRenderingUrls[0]; |
332
|
|
|
} |
333
|
|
|
} |
334
|
|
|
} |
335
|
|
|
$this->numPages = $canvasOrder; |
336
|
|
|
// Merge and re-index the array to get nice numeric indexes. |
337
|
|
|
$this->physicalStructure = array_merge($physSeq, $elements); |
|
|
|
|
338
|
|
|
} |
339
|
|
|
$this->physicalStructureLoaded = TRUE; |
340
|
|
|
} |
341
|
|
|
return $this->physicalStructure; |
342
|
|
|
} |
343
|
|
|
|
344
|
|
|
/** |
345
|
|
|
* {@inheritDoc} |
346
|
|
|
* @see Document::getDownloadLocation() |
347
|
|
|
*/ |
348
|
|
|
public function getDownloadLocation($id) { |
349
|
|
|
$fileLocation = $this->getFileLocation($id); |
350
|
|
|
$resource = $this->iiif->getContainedResourceById($fileLocation); |
351
|
|
|
if ($resource instanceof AbstractImageService) { |
352
|
|
|
return $resource->getImageUrl(); |
353
|
|
|
} |
354
|
|
|
return $fileLocation; |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
/** |
358
|
|
|
* {@inheritDoc} |
359
|
|
|
* @see Document::getFileLocation() |
360
|
|
|
*/ |
361
|
|
|
public function getFileLocation($id) |
362
|
|
|
{ |
363
|
|
|
if ($id == null) { |
364
|
|
|
return null; |
365
|
|
|
} |
366
|
|
|
$resource = $this->iiif->getContainedResourceById($id); |
367
|
|
|
if (isset($resource)) { |
368
|
|
|
if ($resource instanceof CanvasInterface) { |
369
|
|
|
return (!empty($resource->getImageAnnotations()) && $resource->getImageAnnotations()->getSingleService() != null) ? $resource->getImageAnnotations()[0]->getSingleService()->getId() : $id; |
370
|
|
|
} elseif ($resource instanceof ContentResourceInterface) { |
371
|
|
|
return $resource->getSingleService() != null && $resource->getSingleService() instanceof Service ? $resource->getSingleService()->getId() : $id; |
372
|
|
|
} elseif ($resource instanceof AbstractImageService) { |
373
|
|
|
return $resource->getId(); |
374
|
|
|
} elseif ($resource instanceof AnnotationContainerInterface) { |
375
|
|
|
return $id; |
376
|
|
|
} |
377
|
|
|
} else { |
378
|
|
|
return $id; |
379
|
|
|
} |
380
|
|
|
} |
381
|
|
|
|
382
|
|
|
/** |
383
|
|
|
* {@inheritDoc} |
384
|
|
|
* @see Document::getFileMimeType() |
385
|
|
|
*/ |
386
|
|
|
public function getFileMimeType($id) |
387
|
|
|
{ |
388
|
|
|
$fileResource = $this->iiif->getContainedResourceById($id); |
389
|
|
|
if ($fileResource instanceof CanvasInterface) { |
390
|
|
|
$format = "application/vnd.kitodo.iiif"; |
391
|
|
|
} elseif ($fileResource instanceof AnnotationInterface) { |
392
|
|
|
$format = "application/vnd.kitodo.iiif"; |
393
|
|
|
} elseif ($fileResource instanceof ContentResourceInterface) { |
394
|
|
|
if ($fileResource->isText() || $fileResource->isImage() && ($fileResource->getSingleService() == null || !($fileResource->getSingleService() instanceof AbstractImageService))) { |
395
|
|
|
// Support static images without an image service |
396
|
|
|
return $fileResource->getFormat(); |
397
|
|
|
} |
398
|
|
|
$format = "application/vnd.kitodo.iiif"; |
399
|
|
|
} elseif ($fileResource instanceof AbstractImageService) { |
400
|
|
|
$format = "application/vnd.kitodo.iiif"; |
401
|
|
|
} else { |
402
|
|
|
// Assumptions: this can only be the thumbnail and the thumbnail is a jpeg - TODO determine mimetype |
403
|
|
|
$format = "image/jpeg"; |
404
|
|
|
} |
405
|
|
|
return $format; |
406
|
|
|
} |
407
|
|
|
|
408
|
|
|
/** |
409
|
|
|
* {@inheritDoc} |
410
|
|
|
* @see Document::getLogicalStructure() |
411
|
|
|
*/ |
412
|
|
|
public function getLogicalStructure($id, $recursive = FALSE) |
413
|
|
|
{ |
414
|
|
|
$details = array (); |
415
|
|
|
if (!$recursive && !empty($this->logicalUnits[$id])) { |
416
|
|
|
return $this->logicalUnits[$id]; |
417
|
|
|
} elseif (!empty($id)) { |
418
|
|
|
$logUnits[] = $this->iiif->getContainedResourceById($id); |
|
|
|
|
419
|
|
|
} else { |
420
|
|
|
$logUnits[] = $this->iiif; |
421
|
|
|
} |
422
|
|
|
if (!empty($logUnits)) { |
423
|
|
|
if (!$recursive) { |
424
|
|
|
$details = $this->getLogicalStructureInfo($logUnits[0]); |
425
|
|
|
} else { |
426
|
|
|
// cache the ranges - they might occure multiple times in the structures "tree" - with full data as well as referenced as id |
427
|
|
|
$processedStructures = array(); |
428
|
|
|
foreach ($logUnits as $logUnit) { |
429
|
|
|
if (array_search($logUnit->getId(), $processedStructures) == false) { |
|
|
|
|
430
|
|
|
$this->tableOfContents[] = $this->getLogicalStructureInfo($logUnit, TRUE, $processedStructures); |
431
|
|
|
} |
432
|
|
|
} |
433
|
|
|
} |
434
|
|
|
} |
435
|
|
|
return $details; |
436
|
|
|
} |
437
|
|
|
|
438
|
|
|
/** |
439
|
|
|
* Get the details about a IIIF resource (manifest or range) in the logical structure |
440
|
|
|
* |
441
|
|
|
* @access protected |
442
|
|
|
* |
443
|
|
|
* @param IiifResourceInterface $resource: IIIF resource, either a manifest or range. |
444
|
|
|
* @param boolean $recursive: Whether to include the child elements |
445
|
|
|
* @param array $processedStructures: IIIF resources that already have been processed |
446
|
|
|
* @return array Logical structure array |
447
|
|
|
*/ |
448
|
|
|
protected function getLogicalStructureInfo(IiifResourceInterface $resource, $recursive = false, &$processedStructures = array()) { |
449
|
|
|
$details = array (); |
450
|
|
|
$details['id'] = $resource->getId(); |
451
|
|
|
$details['dmdId'] = ''; |
452
|
|
|
$details['label'] = $resource->getLabelForDisplay() !== null ? $resource->getLabelForDisplay() : ''; |
|
|
|
|
453
|
|
|
$details['orderlabel'] = $resource->getLabelForDisplay() !== null ? $resource->getLabelForDisplay() : ''; |
|
|
|
|
454
|
|
|
$details['contentIds'] = ''; |
455
|
|
|
$details['volume'] = ''; |
456
|
|
|
$details['pagination'] = ''; |
457
|
|
|
$cPid = ($this->cPid ? $this->cPid : $this->pid); |
458
|
|
|
if ($details['id'] == $this->_getToplevelId()) { |
459
|
|
|
$metadata = $this->getMetadata($details['id'], $cPid); |
460
|
|
|
if (!empty($metadata['type'][0])) { |
461
|
|
|
$details['type'] = $metadata['type'][0]; |
462
|
|
|
} |
463
|
|
|
} |
464
|
|
|
$details['thumbnailId'] = $resource->getThumbnailUrl(); |
465
|
|
|
$details['points'] = ''; |
466
|
|
|
// Load strucural mapping |
467
|
|
|
$this->_getSmLinks(); |
468
|
|
|
// Load physical structure. |
469
|
|
|
$this-> _getPhysicalStructure(); |
470
|
|
|
$canvases = array(); |
471
|
|
|
if ($resource instanceof ManifestInterface) { |
472
|
|
|
$startCanvas = $resource->getStartCanvasOrFirstCanvas(); |
473
|
|
|
$canvases = $resource->getDefaultCanvases(); |
|
|
|
|
474
|
|
|
} elseif ($resource instanceof RangeInterface) { |
475
|
|
|
$startCanvas = $resource->getStartCanvasOrFirstCanvas(); |
476
|
|
|
$canvases = $resource->getAllCanvases(); |
477
|
|
|
} |
478
|
|
|
if ($startCanvas != null) { |
|
|
|
|
479
|
|
|
$details['pagination'] = $startCanvas->getLabel(); |
480
|
|
|
$startCanvasIndex = array_search($startCanvas, $this->iiif->getDefaultCanvases()); |
481
|
|
|
if ($startCanvasIndex!==false) { |
482
|
|
|
$details['points'] = $startCanvasIndex + 1; |
483
|
|
|
} |
484
|
|
|
} |
485
|
|
|
$useGroups = $this->getUseGroups('fileGrps'); |
486
|
|
|
if (is_string($useGroups)) { |
487
|
|
|
$useGroups = array($useGroups); |
|
|
|
|
488
|
|
|
} |
489
|
|
|
// Keep for later usage. |
490
|
|
|
$this->logicalUnits[$details['id']] = $details; |
491
|
|
|
// Walk the structure recursively? And are there any children of the current element? |
492
|
|
|
if ($recursive) { |
493
|
|
|
$processedStructures[] = $resource->getId(); |
494
|
|
|
$details['children'] = array (); |
495
|
|
|
if ($resource instanceof ManifestInterface && $resource->getRootRanges() != null) { |
496
|
|
|
$rangesToAdd = []; |
497
|
|
|
$rootRanges = []; |
498
|
|
|
if (sizeof($this->iiif->getRootRanges()) == 1 && $this->iiif->getRootRanges()[0]->isTopRange()) { |
499
|
|
|
$rangesToAdd = $this->iiif->getRootRanges()[0]->getMemberRangesAndRanges(); |
|
|
|
|
500
|
|
|
} else { |
501
|
|
|
$rangesToAdd = $this->iiif->getRootRanges(); |
502
|
|
|
} |
503
|
|
|
foreach ($rangesToAdd as $range) { |
504
|
|
|
$rootRanges[] = $range; |
505
|
|
|
} |
506
|
|
|
foreach ($rootRanges as $range) { |
507
|
|
|
if ((array_search($range->getId(), $processedStructures) == false)) { |
|
|
|
|
508
|
|
|
$details['children'][] = $this->getLogicalStructureInfo($range, TRUE, $processedStructures); |
509
|
|
|
} |
510
|
|
|
} |
511
|
|
|
} elseif ($resource instanceof RangeInterface) { |
512
|
|
|
if (!empty($resource->getAllRanges())) { |
513
|
|
|
foreach ($resource->getAllRanges() as $range) { |
514
|
|
|
if ((array_search($range->getId(), $processedStructures) == false)) { |
|
|
|
|
515
|
|
|
$details['children'][] = $this->getLogicalStructureInfo($range, TRUE, $processedStructures); |
516
|
|
|
} |
517
|
|
|
} |
518
|
|
|
} |
519
|
|
|
} |
520
|
|
|
} |
521
|
|
|
return $details; |
522
|
|
|
} |
523
|
|
|
|
524
|
|
|
/** |
525
|
|
|
* Returns metadata for IIIF resources with the ID $id in there original form in |
526
|
|
|
* the manifest, but prepared for display to the user. |
527
|
|
|
* |
528
|
|
|
* @access public |
529
|
|
|
* |
530
|
|
|
* @param string $id: the ID of the IIIF resource |
531
|
|
|
* @param number $cPid: the configuration folder's id |
532
|
|
|
* @param boolean $withDescription: add description / summary to the return value |
533
|
|
|
* @param boolean $withRights: add attribution and license / rights and requiredStatement to the return value |
534
|
|
|
* @param boolean $withRelated: add related links / homepage to the return value |
535
|
|
|
* |
536
|
|
|
* @return array |
537
|
|
|
* |
538
|
|
|
* @todo This method is still in experimental; the method signature may change. |
539
|
|
|
*/ |
540
|
|
|
public function getManifestMetadata($id, $cPid = 0, $withDescription = true, $withRights = true, $withRelated = true) { |
|
|
|
|
541
|
|
|
if (!empty($this->originalMetadataArray[$id])) { |
542
|
|
|
return $this->originalMetadataArray[$id]; |
543
|
|
|
} |
544
|
|
|
$iiifResource = $this->iiif->getContainedResourceById($id); |
545
|
|
|
$result = array(); |
546
|
|
|
if ($iiifResource != null) { |
547
|
|
|
if ($iiifResource->getLabel()!=null && $iiifResource->getLabel() != "") { |
548
|
|
|
$result['label'] = $iiifResource->getLabel(); |
549
|
|
|
} |
550
|
|
|
if (!empty($iiifResource->getMetadata())) { |
551
|
|
|
$result['metadata'] = []; |
552
|
|
|
foreach ($iiifResource->getMetadataForDisplay() as $metadata) { |
553
|
|
|
$result['metadata'][$metadata['label']] = $metadata['value']; |
554
|
|
|
} |
555
|
|
|
} |
556
|
|
|
if ($withDescription && !empty($iiifResource->getSummary())) { |
557
|
|
|
$result["description"] = $iiifResource->getSummaryForDisplay(); |
558
|
|
|
} |
559
|
|
|
if ($withRights) { |
560
|
|
|
if (!empty($iiifResource->getRights())) { |
561
|
|
|
$result["rights"] = $iiifResource->getRights(); |
562
|
|
|
} |
563
|
|
|
if (!empty($iiifResource->getRequiredStatement())) { |
564
|
|
|
$result["requiredStatement"] = $iiifResource->getRequiredStatementForDisplay(); |
565
|
|
|
} |
566
|
|
|
} |
567
|
|
|
if ($withRelated && !empty($iiifResource->getWeblinksForDisplay())) { |
568
|
|
|
$result["weblinks"] = []; |
569
|
|
|
foreach ($iiifResource->getWeblinksForDisplay() as $link) { |
570
|
|
|
$key = array_key_exists("label", $link) ? $link["label"] : $link["@id"]; |
571
|
|
|
$result["weblinks"][$key] = $link["@id"]; |
572
|
|
|
} |
573
|
|
|
} |
574
|
|
|
} |
575
|
|
|
return $result; |
576
|
|
|
} |
577
|
|
|
|
578
|
|
|
/** |
579
|
|
|
* {@inheritDoc} |
580
|
|
|
* @see Document::getMetadata() |
581
|
|
|
*/ |
582
|
|
|
public function getMetadata($id, $cPid = 0) |
583
|
|
|
{ |
584
|
|
|
if (!empty($this->metadataArray[$id]) && $this->metadataArray[0] == $cPid) { |
585
|
|
|
return $this->metadataArray[$id]; |
586
|
|
|
} |
587
|
|
|
// Initialize metadata array with empty values. |
588
|
|
|
// TODO initialize metadata in abstract class |
589
|
|
|
$metadata = array ( |
590
|
|
|
'title' => array (), |
591
|
|
|
'title_sorting' => array (), |
592
|
|
|
'author' => array (), |
593
|
|
|
'place' => array (), |
594
|
|
|
'year' => array (), |
595
|
|
|
'prod_id' => array (), |
596
|
|
|
'record_id' => array (), |
597
|
|
|
'opac_id' => array (), |
598
|
|
|
'union_id' => array (), |
599
|
|
|
'urn' => array (), |
600
|
|
|
'purl' => array (), |
601
|
|
|
'type' => array (), |
602
|
|
|
'volume' => array (), |
603
|
|
|
'volume_sorting' => array (), |
604
|
|
|
'collection' => array (), |
605
|
|
|
'owner' => array (), |
606
|
|
|
); |
607
|
|
|
$metadata['document_format'][] = 'IIIF'; |
608
|
|
|
$result = $GLOBALS['TYPO3_DB']->exec_SELECTquery( |
609
|
|
|
'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', |
610
|
|
|
'tx_dlf_metadata,tx_dlf_metadataformat,tx_dlf_formats', |
611
|
|
|
'tx_dlf_metadata.pid='.intval($cPid) |
612
|
|
|
.' AND tx_dlf_metadataformat.pid='.intval($cPid) |
613
|
|
|
.' 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->getIiifVersion(), 'tx_dlf_formats').') OR tx_dlf_metadata.format=0)' |
614
|
|
|
.Helper::whereClause('tx_dlf_metadata', TRUE).Helper::whereClause('tx_dlf_metadataformat').Helper::whereClause('tx_dlf_formats') |
615
|
|
|
); |
616
|
|
|
$iiifResource = $this->iiif->getContainedResourceById($id); |
617
|
|
|
while ($resArray = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) { |
618
|
|
|
// Set metadata field's value(s). |
619
|
|
|
if ($resArray['format'] > 0 && !empty($resArray['xpath']) && ($values = $iiifResource->jsonPath($resArray['xpath'])) != null) { |
620
|
|
|
if (is_string($values)) { |
621
|
|
|
$metadata[$resArray['index_name']] = array (trim((string) $values)); |
622
|
|
|
} elseif ($values instanceof JSONPath && is_array($values->data()) && count($values->data())>1 ) { |
623
|
|
|
$metadata[$resArray['index_name']] = array (); |
624
|
|
|
foreach ($values->data() as $value) { |
625
|
|
|
$metadata[$resArray['index_name']][] = trim((string) $value); |
626
|
|
|
} |
627
|
|
|
} |
628
|
|
|
} |
629
|
|
|
// Set default value if applicable. |
630
|
|
|
if (empty($metadata[$resArray['index_name']][0]) && strlen($resArray['default_value']) > 0) { |
631
|
|
|
$metadata[$resArray['index_name']] = array ($resArray['default_value']); |
632
|
|
|
} |
633
|
|
|
// Set sorting value if applicable. |
634
|
|
|
if (!empty($metadata[$resArray['index_name']]) && $resArray['is_sortable']) { |
635
|
|
|
if ($resArray['format'] > 0 && !empty($resArray['xpath_sorting']) |
636
|
|
|
&& ($values = $iiifResource->jsonPath($resArray['xpath_sorting']) != null)) { |
637
|
|
|
if ($values instanceof string) { |
|
|
|
|
638
|
|
|
$metadata[$resArray['index_name'].'_sorting'][0] = array (trim((string) $values)); |
639
|
|
|
} elseif ($values instanceof JSONPath && is_array($values->data()) && count($values->data()>1 )) { |
|
|
|
|
640
|
|
|
$metadata[$resArray['index_name']] = array (); |
641
|
|
|
foreach ($values->data() as $value) { |
642
|
|
|
$metadata[$resArray['index_name'].'_sorting'][0] = trim((string) $value); |
643
|
|
|
} |
644
|
|
|
} |
645
|
|
|
} |
646
|
|
|
if (empty($metadata[$resArray['index_name'].'_sorting'][0])) { |
647
|
|
|
$metadata[$resArray['index_name'].'_sorting'][0] = $metadata[$resArray['index_name']][0]; |
648
|
|
|
} |
649
|
|
|
} |
650
|
|
|
} |
651
|
|
|
return $metadata; |
652
|
|
|
} |
653
|
|
|
|
654
|
|
|
/** |
655
|
|
|
* {@inheritDoc} |
656
|
|
|
* @see Document::_getSmLinks() |
657
|
|
|
*/ |
658
|
|
|
protected function _getSmLinks() { |
659
|
|
|
if (!$this->smLinksLoaded && isset($this->iiif) && $this->iiif instanceof ManifestInterface) { |
660
|
|
|
if (!empty($this->iiif->getDefaultCanvases())) { |
661
|
|
|
foreach ($this->iiif->getDefaultCanvases() as $canvas) { |
662
|
|
|
$this->smLinkCanvasToResource($canvas, $this->iiif); |
663
|
|
|
} |
664
|
|
|
} |
665
|
|
|
if (!empty($this->iiif->getStructures())) { |
666
|
|
|
foreach ($this->iiif->getStructures() as $range) { |
667
|
|
|
$this->smLinkRangeCanvasesRecursively($range); |
668
|
|
|
} |
669
|
|
|
} |
670
|
|
|
$this->smLinksLoaded = true; |
671
|
|
|
} |
672
|
|
|
return $this->smLinks; |
673
|
|
|
} |
674
|
|
|
|
675
|
|
|
/** |
676
|
|
|
* Construct a link between a range and it's sub ranges and all contained canvases. |
677
|
|
|
* |
678
|
|
|
* @access private |
679
|
|
|
* |
680
|
|
|
* @param RangeInterface $range: Current range whose canvases shall be linked |
681
|
|
|
*/ |
682
|
|
|
private function smLinkRangeCanvasesRecursively(RangeInterface $range) { |
683
|
|
|
// map range's canvases including all child ranges' canvases |
684
|
|
|
if (!$range->isTopRange()) { |
685
|
|
|
foreach ($range->getAllCanvasesRecursively() as $canvas) { |
686
|
|
|
$this->smLinkCanvasToResource($canvas, $range); |
687
|
|
|
} |
688
|
|
|
} |
689
|
|
|
// recursive call for all ranges |
690
|
|
|
if (!empty($range->getAllRanges())) { |
691
|
|
|
foreach ($range->getAllRanges() as $childRange) { |
692
|
|
|
$this->smLinkRangeCanvasesRecursively($childRange); |
693
|
|
|
} |
694
|
|
|
} |
695
|
|
|
} |
696
|
|
|
|
697
|
|
|
/** |
698
|
|
|
* Link a single canvas to a containing range |
699
|
|
|
* |
700
|
|
|
* @access private |
701
|
|
|
* |
702
|
|
|
* @param CanvasInterface $canvas |
703
|
|
|
* @param IiifResourceInterface $resource |
704
|
|
|
*/ |
705
|
|
|
private function smLinkCanvasToResource(CanvasInterface $canvas, IiifResourceInterface $resource) |
706
|
|
|
{ |
707
|
|
|
$this->smLinks['l2p'][$resource->getId()][] = $canvas->getId(); |
708
|
|
|
if (!is_array($this->smLinks['p2l'][$canvas->getId()]) || !in_array($resource->getId(), $this->smLinks['p2l'][$canvas->getId()])) { |
709
|
|
|
$this->smLinks['p2l'][$canvas->getId()][] = $resource->getId(); |
710
|
|
|
} |
711
|
|
|
} |
712
|
|
|
|
713
|
|
|
/** |
714
|
|
|
* Currently not supported for IIIF. Multivolume works _could_ be modelled |
715
|
|
|
* as IIIF Collections, but we can't tell them apart from actual collections. |
716
|
|
|
* |
717
|
|
|
* @access protected |
718
|
|
|
* |
719
|
|
|
* @see Document::getParentDocumentUidForSaving() |
720
|
|
|
*/ |
721
|
|
|
protected function getParentDocumentUidForSaving($pid, $core) |
722
|
|
|
{ |
723
|
|
|
// Do nothing. |
724
|
|
|
} |
725
|
|
|
|
726
|
|
|
/** |
727
|
|
|
* {@inheritDoc} |
728
|
|
|
* @see Document::getRawText() |
729
|
|
|
*/ |
730
|
|
|
public function getRawText($id) { |
731
|
|
|
$rawText = ''; |
732
|
|
|
// Get text from raw text array if available. |
733
|
|
|
if (!empty($this->rawTextArray[$id])) { |
734
|
|
|
return $this->rawTextArray[$id]; |
735
|
|
|
} |
736
|
|
|
$this->ensureHasFulltextIsSet(); |
737
|
|
|
if ($this->hasFulltext) { |
738
|
|
|
// Load physical structure ... |
739
|
|
|
$this->_getPhysicalStructure(); |
740
|
|
|
// ... and extension configuration. |
741
|
|
|
$extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][self::$extKey]); |
742
|
|
|
if (!empty($this->physicalStructureInfo[$id])) { |
743
|
|
|
if (!empty($this->physicalStructureInfo[$id]['files'][$extConf['fileGrpFulltext']])) { |
744
|
|
|
$rawText = parent::getRawTextFromXml($id); |
745
|
|
|
} |
746
|
|
|
if ($extConf['indexAnnotations'] == 1) { |
747
|
|
|
$iiifResource = $this->iiif->getContainedResourceById($id); |
748
|
|
|
// Get annotation containers |
749
|
|
|
$annotationContainerIds = $this->physicalStructureInfo[$id]['annotationContainers']; |
750
|
|
|
if (!empty($annotationContainerIds)) { |
751
|
|
|
$annotationTexts = array(); |
752
|
|
|
foreach ($annotationContainerIds as $annotationListId) { |
753
|
|
|
$annotationContainer = $this->iiif->getContainedResourceById($annotationListId); |
754
|
|
|
/* @var $annotationContainer \Ubl\Iiif\Presentation\Common\Model\Resources\AnnotationContainerInterface */ |
755
|
|
|
foreach ($annotationContainer->getTextAnnotations(Motivation::PAINTING) as $annotation) { |
|
|
|
|
756
|
|
|
if ($annotation->getTargetResourceId() == $iiifResource->getId() && |
757
|
|
|
$annotation->getBody()!=null && $annotation->getBody()->getChars()!=null) { |
758
|
|
|
$annotationTexts[] = $annotation->getBody()->getChars(); |
759
|
|
|
} |
760
|
|
|
} |
761
|
|
|
} |
762
|
|
|
$rawText .= implode(' ', $annotationTexts); |
763
|
|
|
} |
764
|
|
|
} |
765
|
|
|
} else { |
766
|
|
|
Helper::devLog('Invalid structure resource @id "'.$id.'"', DEVLOG_SEVERITY_WARNING); |
767
|
|
|
return $rawText; |
768
|
|
|
} |
769
|
|
|
$this->rawTextArray[$id] = $rawText; |
770
|
|
|
} |
771
|
|
|
return $rawText; |
772
|
|
|
} |
773
|
|
|
|
774
|
|
|
/** |
775
|
|
|
* Returns the underlying IiifResourceInterface. |
776
|
|
|
* |
777
|
|
|
* @access public |
778
|
|
|
* |
779
|
|
|
* @return IiifResourceInterface |
780
|
|
|
*/ |
781
|
|
|
public function getIiif() |
782
|
|
|
{ |
783
|
|
|
return $this->iiif; |
784
|
|
|
} |
785
|
|
|
|
786
|
|
|
/** |
787
|
|
|
* {@inheritDoc} |
788
|
|
|
* @see Document::init() |
789
|
|
|
*/ |
790
|
|
|
protected function init() |
791
|
|
|
{ |
792
|
|
|
// Nothing to do here, at the moment |
793
|
|
|
} |
794
|
|
|
|
795
|
|
|
/** |
796
|
|
|
* {@inheritDoc} |
797
|
|
|
* @see Document::loadLocation() |
798
|
|
|
*/ |
799
|
|
|
protected function loadLocation($location) |
800
|
|
|
{ |
801
|
|
|
$content = GeneralUtility::getUrl($location); |
802
|
|
|
$conf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][self::$extKey]); |
803
|
|
|
IiifHelper::setUrlReader(IiifUrlReader::getInstance()); |
804
|
|
|
IiifHelper::setMaxThumbnailHeight($conf['iiifThumbnailHeight']); |
805
|
|
|
IiifHelper::setMaxThumbnailWidth($conf['iiifThumbnailWidth']); |
806
|
|
|
$resource = IiifHelper::loadIiifResource($content); |
|
|
|
|
807
|
|
|
if ($resource != null ) { |
808
|
|
|
if ($resource instanceof ManifestInterface) { |
809
|
|
|
$this->iiif = $resource; |
810
|
|
|
return true; |
811
|
|
|
} |
812
|
|
|
} else { |
813
|
|
|
Helper::devLog('Could not load IIIF manifest from "'.$location.'"', self::$extKey, SYSLOG_SEVERITY_ERROR); |
|
|
|
|
814
|
|
|
} |
815
|
|
|
} |
816
|
|
|
|
817
|
|
|
/** |
818
|
|
|
* {@inheritDoc} |
819
|
|
|
* @see \Kitodo\Dlf\Common\Document::prepareMetadataArray() |
820
|
|
|
*/ |
821
|
|
|
protected function prepareMetadataArray($cPid) |
822
|
|
|
{ |
823
|
|
|
$id = $this->iiif->getId(); |
824
|
|
|
$this->metadataArray[(string) $id] = $this->getMetadata((string) $id, $cPid); |
825
|
|
|
} |
826
|
|
|
|
827
|
|
|
/** |
828
|
|
|
* {@inheritDoc} |
829
|
|
|
* @see Document::setPreloadedDocument() |
830
|
|
|
*/ |
831
|
|
|
protected function setPreloadedDocument($preloadedDocument) { |
832
|
|
|
if ($preloadedDocument instanceof ManifestInterface) { |
833
|
|
|
$this->iiif = $preloadedDocument; |
834
|
|
|
return true; |
835
|
|
|
} |
836
|
|
|
return false; |
837
|
|
|
} |
838
|
|
|
|
839
|
|
|
/** |
840
|
|
|
* {@inheritDoc} |
841
|
|
|
* @see Document::ensureHasFulltextIsSet() |
842
|
|
|
*/ |
843
|
|
|
protected function ensureHasFulltextIsSet() |
844
|
|
|
{ |
845
|
|
|
/* |
846
|
|
|
* TODO Check annotations and annotation lists of canvas for ALTO documents. |
847
|
|
|
* Example: |
848
|
|
|
* https://digi.ub.uni-heidelberg.de/diglit/iiif/hirsch_hamburg1933_04_25/manifest.json links |
849
|
|
|
* https://digi.ub.uni-heidelberg.de/diglit/iiif/hirsch_hamburg1933_04_25/list/0001.json |
850
|
|
|
*/ |
851
|
|
|
if (!$this->hasFulltextSet && $this->iiif instanceof ManifestInterface) { |
852
|
|
|
$manifest = $this->iiif; |
853
|
|
|
$canvases = $manifest->getDefaultCanvases(); |
854
|
|
|
foreach ($canvases as $canvas) { |
855
|
|
|
if (!empty($canvas->getSeeAlsoUrlsForFormat("application/alto+xml")) || |
856
|
|
|
!empty($canvas->getSeeAlsoUrlsForProfile("http://www.loc.gov/standards/alto/"))) { |
857
|
|
|
$this->hasFulltextSet = true; |
858
|
|
|
$this->hasFulltext = true; |
859
|
|
|
return; |
860
|
|
|
} |
861
|
|
|
$extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][self::$extKey]); |
862
|
|
|
if ($extConf['indexAnnotations'] == 1 && !empty($canvas->getPossibleTextAnnotationContainers(Motivation::PAINTING))) { |
|
|
|
|
863
|
|
|
foreach ($canvas->getPossibleTextAnnotationContainers(Motivation::PAINTING) as $annotationContainer) { |
864
|
|
|
if (($textAnnotations = $annotationContainer->getTextAnnotations(Motivation::PAINTING)) != null) { |
865
|
|
|
foreach ($textAnnotations as $annotation) { |
866
|
|
|
if ($annotation->getBody() != null && |
867
|
|
|
$annotation->getBody()->getFormat() == "text/plain" && |
868
|
|
|
$annotation->getBody()->getChars() != null) { |
869
|
|
|
$this->hasFulltextSet = true; |
870
|
|
|
$this->hasFulltext = true; |
871
|
|
|
return; |
872
|
|
|
} |
873
|
|
|
} |
874
|
|
|
} |
875
|
|
|
} |
876
|
|
|
} |
877
|
|
|
} |
878
|
|
|
$this->hasFulltextSet = true; |
879
|
|
|
} |
880
|
|
|
} |
881
|
|
|
|
882
|
|
|
/** |
883
|
|
|
* {@inheritDoc} |
884
|
|
|
* @see \Kitodo\Dlf\Common\Document::_getThumbnail() |
885
|
|
|
*/ |
886
|
|
|
protected function _getThumbnail($forceReload = FALSE) |
887
|
|
|
{ |
888
|
|
|
return $this->iiif->getThumbnailUrl(); |
889
|
|
|
} |
890
|
|
|
|
891
|
|
|
/** |
892
|
|
|
* {@inheritDoc} |
893
|
|
|
* @see \Kitodo\Dlf\Common\Document::_getToplevelId() |
894
|
|
|
*/ |
895
|
|
|
protected function _getToplevelId() |
896
|
|
|
{ |
897
|
|
|
if (empty($this->toplevelId)) { |
898
|
|
|
if (isset($this->iiif)) { |
899
|
|
|
$this->toplevelId = $this->iiif->getId(); |
900
|
|
|
} |
901
|
|
|
} |
902
|
|
|
return $this->toplevelId; |
903
|
|
|
} |
904
|
|
|
|
905
|
|
|
/** |
906
|
|
|
* This magic method is executed after the object is deserialized |
907
|
|
|
* @see __sleep() |
908
|
|
|
* |
909
|
|
|
* @access public |
910
|
|
|
* |
911
|
|
|
* @return void |
912
|
|
|
*/ |
913
|
|
|
public function __wakeup() { |
914
|
|
|
$conf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][self::$extKey]); |
915
|
|
|
IiifHelper::setUrlReader(IiifUrlReader::getInstance()); |
916
|
|
|
IiifHelper::setMaxThumbnailHeight($conf['iiifThumbnailHeight']); |
917
|
|
|
IiifHelper::setMaxThumbnailWidth($conf['iiifThumbnailWidth']); |
918
|
|
|
$resource = IiifHelper::loadIiifResource($this->asJson); |
919
|
|
|
if ($resource != null && $resource instanceof ManifestInterface) { |
920
|
|
|
$this->asJson=''; |
921
|
|
|
$this->iiif = $resource; |
922
|
|
|
$this->init(); |
923
|
|
|
} else { |
924
|
|
|
Helper::devLog('Could not load IIIF after deserialization', self::$extKey, SYSLOG_SEVERITY_ERROR); |
|
|
|
|
925
|
|
|
} |
926
|
|
|
} |
927
|
|
|
|
928
|
|
|
/** |
929
|
|
|
* |
930
|
|
|
* @return string[] |
931
|
|
|
*/ |
932
|
|
|
public function __sleep() { |
933
|
|
|
// TODO implement serializiation in IIIF library |
934
|
|
|
$jsonArray = $this->iiif->getOriginalJsonArray(); |
935
|
|
|
$this->asJson = json_encode($jsonArray); |
936
|
|
|
return array ('uid', 'pid', 'recordId', 'parentId', 'asJson'); |
937
|
|
|
} |
938
|
|
|
} |
939
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.