Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
65.14% |
256 / 393 |
|
51.28% |
20 / 39 |
CRAP | |
0.00% |
0 / 1 |
DAIA | |
65.14% |
256 / 393 |
|
51.28% |
20 / 39 |
1601.69 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
init | |
72.22% |
26 / 36 |
|
0.00% |
0 / 1 |
13.59 | |||
getCacheKey | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getConfig | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getHoldLink | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
getStatus | |
50.00% |
7 / 14 |
|
0.00% |
0 / 1 |
13.12 | |||
getStatuses | |
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
210 | |||
getHolding | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getPurchaseHistory | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
convertDate | |
40.00% |
2 / 5 |
|
0.00% |
0 / 1 |
2.86 | |||
convertDatetime | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
doHTTPRequest | |
34.69% |
17 / 49 |
|
0.00% |
0 / 1 |
16.03 | |||
generateURI | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
generateMultiURIs | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
parseDaiaDoc | |
40.00% |
2 / 5 |
|
0.00% |
0 / 1 |
2.86 | |||
extractDaiaDoc | |
54.55% |
12 / 22 |
|
0.00% |
0 / 1 |
32.41 | |||
convertDaiaXmlToJson | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
15 | |||
parseDaiaArray | |
96.88% |
31 / 32 |
|
0.00% |
0 / 1 |
7 | |||
getItemStatus | |
80.23% |
69 / 86 |
|
0.00% |
0 / 1 |
31.22 | |||
getCustomData | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getStatusString | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
checkIsRecallable | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
11 | |||
checkIsStorageRetrievalRequest | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
11 | |||
getHoldType | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
getItemLimitation | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
getItemDepartment | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
4 | |||
getItemDepartmentId | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
3 | |||
getItemDepartmentLink | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getItemStorage | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
4 | |||
getItemStorageId | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
3 | |||
getItemStorageLink | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
3 | |||
getItemLimitationContent | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
getItemLimitationTypes | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
3.07 | |||
getItemNumber | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getItemBarcode | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getItemReserveStatus | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getItemCallnumber | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
getAvailableItemServices | |
85.71% |
6 / 7 |
|
0.00% |
0 / 1 |
5.07 | |||
logMessages | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | |
3 | /** |
4 | * ILS Driver for VuFind to query availability information via DAIA. |
5 | * |
6 | * Based on the proof-of-concept-driver by Till Kinstler, GBV. |
7 | * Relaunch of the daia driver developed by Oliver Goldschmidt. |
8 | * |
9 | * PHP version 8 |
10 | * |
11 | * Copyright (C) Jochen Lienhard 2014. |
12 | * |
13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License version 2, |
15 | * as published by the Free Software Foundation. |
16 | * |
17 | * This program is distributed in the hope that it will be useful, |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | * GNU General Public License for more details. |
21 | * |
22 | * You should have received a copy of the GNU General Public License |
23 | * along with this program; if not, write to the Free Software |
24 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
25 | * |
26 | * @category VuFind |
27 | * @package ILS_Drivers |
28 | * @author Jochen Lienhard <lienhard@ub.uni-freiburg.de> |
29 | * @author Oliver Goldschmidt <o.goldschmidt@tu-harburg.de> |
30 | * @author André Lahmann <lahmann@ub.uni-leipzig.de> |
31 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
32 | * @link https://vufind.org/wiki/development:plugins:ils_drivers Wiki |
33 | */ |
34 | |
35 | namespace VuFind\ILS\Driver; |
36 | |
37 | use DOMDocument; |
38 | use Laminas\Log\LoggerAwareInterface as LoggerAwareInterface; |
39 | use VuFind\Exception\ILS as ILSException; |
40 | use VuFindHttp\HttpServiceAwareInterface as HttpServiceAwareInterface; |
41 | |
42 | use function count; |
43 | use function in_array; |
44 | use function is_array; |
45 | use function strlen; |
46 | |
47 | /** |
48 | * ILS Driver for VuFind to query availability information via DAIA. |
49 | * |
50 | * @category VuFind |
51 | * @package ILS_Drivers |
52 | * @author Jochen Lienhard <lienhard@ub.uni-freiburg.de> |
53 | * @author Oliver Goldschmidt <o.goldschmidt@tu-harburg.de> |
54 | * @author André Lahmann <lahmann@ub.uni-leipzig.de> |
55 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
56 | * @link https://vufind.org/wiki/development:plugins:ils_drivers Wiki |
57 | */ |
58 | class DAIA extends AbstractBase implements |
59 | HttpServiceAwareInterface, |
60 | LoggerAwareInterface |
61 | { |
62 | use \VuFind\Cache\CacheTrait { |
63 | getCacheKey as protected getBaseCacheKey; |
64 | } |
65 | use \VuFindHttp\HttpServiceAwareTrait; |
66 | use \VuFind\Log\LoggerAwareTrait; |
67 | |
68 | /** |
69 | * Base URL for DAIA Service |
70 | * |
71 | * @var string |
72 | */ |
73 | protected $baseUrl; |
74 | |
75 | /** |
76 | * Timeout in seconds to be used for DAIA http requests |
77 | * |
78 | * @var string |
79 | */ |
80 | protected $daiaTimeout = null; |
81 | |
82 | /** |
83 | * Flag to switch on/off caching for DAIA items |
84 | * |
85 | * @var bool |
86 | */ |
87 | protected $daiaCacheEnabled = false; |
88 | |
89 | /** |
90 | * DAIA query identifier prefix |
91 | * |
92 | * @var string |
93 | */ |
94 | protected $daiaIdPrefix; |
95 | |
96 | /** |
97 | * DAIA response format |
98 | * |
99 | * @var string |
100 | */ |
101 | protected $daiaResponseFormat; |
102 | |
103 | /** |
104 | * Flag to enable multiple DAIA-queries |
105 | * |
106 | * @var bool |
107 | */ |
108 | protected $multiQuery = false; |
109 | |
110 | /** |
111 | * Acceptable ContentTypes delivered by DAIA server in HTTP header |
112 | * |
113 | * @var array |
114 | */ |
115 | protected $contentTypesResponse; |
116 | |
117 | /** |
118 | * ContentTypes to use in DAIA HTTP requests in HTTP header |
119 | * |
120 | * @var array |
121 | */ |
122 | protected $contentTypesRequest = [ |
123 | 'xml' => 'application/xml', |
124 | 'json' => 'application/json', |
125 | ]; |
126 | |
127 | /** |
128 | * Date converter object |
129 | * |
130 | * @var \VuFind\Date\Converter |
131 | */ |
132 | protected $dateConverter; |
133 | |
134 | /** |
135 | * Constructor |
136 | * |
137 | * @param \VuFind\Date\Converter $converter Date converter |
138 | */ |
139 | public function __construct(\VuFind\Date\Converter $converter) |
140 | { |
141 | $this->dateConverter = $converter; |
142 | } |
143 | |
144 | /** |
145 | * Initialize the driver. |
146 | * |
147 | * Validate configuration and perform all resource-intensive tasks needed to |
148 | * make the driver active. |
149 | * |
150 | * @throws ILSException |
151 | * @return void |
152 | */ |
153 | public function init() |
154 | { |
155 | if (isset($this->config['DAIA']['baseUrl'])) { |
156 | $this->baseUrl = $this->config['DAIA']['baseUrl']; |
157 | } elseif (isset($this->config['Global']['baseUrl'])) { |
158 | throw new ILSException( |
159 | 'Deprecated [Global] section in DAIA.ini present, but no [DAIA] ' . |
160 | 'section found: please update DAIA.ini (cf. config/vufind/DAIA.ini).' |
161 | ); |
162 | } else { |
163 | throw new ILSException('DAIA/baseUrl configuration needs to be set.'); |
164 | } |
165 | // use DAIA specific timeout setting for http requests if configured |
166 | if ((isset($this->config['DAIA']['timeout']))) { |
167 | $this->daiaTimeout = $this->config['DAIA']['timeout']; |
168 | } |
169 | if (isset($this->config['DAIA']['daiaResponseFormat'])) { |
170 | $this->daiaResponseFormat = strtolower( |
171 | $this->config['DAIA']['daiaResponseFormat'] |
172 | ); |
173 | } else { |
174 | $this->debug('No daiaResponseFormat setting found, using default: xml'); |
175 | $this->daiaResponseFormat = 'xml'; |
176 | } |
177 | if (isset($this->config['DAIA']['daiaIdPrefix'])) { |
178 | $this->daiaIdPrefix = $this->config['DAIA']['daiaIdPrefix']; |
179 | } else { |
180 | $this->debug('No daiaIdPrefix setting found, using default: ppn:'); |
181 | $this->daiaIdPrefix = 'ppn:'; |
182 | } |
183 | if (isset($this->config['DAIA']['multiQuery'])) { |
184 | $this->multiQuery = $this->config['DAIA']['multiQuery']; |
185 | } else { |
186 | $this->debug('No multiQuery setting found, using default: false'); |
187 | } |
188 | if (isset($this->config['DAIA']['daiaContentTypes'])) { |
189 | $this->contentTypesResponse = $this->config['DAIA']['daiaContentTypes']; |
190 | } else { |
191 | $this->debug('No ContentTypes for response defined. Accepting any.'); |
192 | } |
193 | if (isset($this->config['DAIA']['daiaCache'])) { |
194 | $this->daiaCacheEnabled = $this->config['DAIA']['daiaCache']; |
195 | } else { |
196 | $this->debug('Caching not enabled, disabling it by default.'); |
197 | } |
198 | if ( |
199 | isset($this->config['General']) |
200 | && isset($this->config['General']['cacheLifetime']) |
201 | ) { |
202 | $this->cacheLifetime = $this->config['General']['cacheLifetime']; |
203 | } else { |
204 | $this->debug( |
205 | 'Cache lifetime not set, using VuFind\ILS\Driver\AbstractBase ' . |
206 | 'default value.' |
207 | ); |
208 | } |
209 | } |
210 | |
211 | /** |
212 | * DAIA specific override of method to ensure uniform cache keys for cached |
213 | * VuFind objects. |
214 | * |
215 | * @param string|null $suffix Optional suffix that will get appended to the |
216 | * object class name calling getCacheKey() |
217 | * |
218 | * @return string |
219 | */ |
220 | protected function getCacheKey($suffix = null) |
221 | { |
222 | return $this->getBaseCacheKey(md5($this->baseUrl) . $suffix); |
223 | } |
224 | |
225 | /** |
226 | * Public Function which retrieves renew, hold and cancel settings from the |
227 | * driver ini file. |
228 | * |
229 | * @param string $function The name of the feature to be checked |
230 | * @param array $params Optional feature-specific parameters (array) |
231 | * |
232 | * @return array An array with key-value pairs. |
233 | * |
234 | * @SuppressWarnings(PHPMD.UnusedFormalParameter) |
235 | */ |
236 | public function getConfig($function, $params = []) |
237 | { |
238 | return $this->config[$function] ?? false; |
239 | } |
240 | |
241 | /** |
242 | * Get Hold Link |
243 | * |
244 | * The goal for this method is to return a URL to a "place hold" web page on |
245 | * the ILS OPAC. This is used for ILSs that do not support an API or method |
246 | * to place Holds. |
247 | * |
248 | * @param string $id The id of the bib record |
249 | * @param array $details Item details from getHoldings return array |
250 | * |
251 | * @return string URL to ILS's OPAC's place hold screen. |
252 | * |
253 | * @SuppressWarnings(PHPMD.UnusedFormalParameter) |
254 | */ |
255 | public function getHoldLink($id, $details) |
256 | { |
257 | return (isset($details['ilslink']) && $details['ilslink'] != '') |
258 | ? $details['ilslink'] |
259 | : null; |
260 | } |
261 | |
262 | /** |
263 | * Get Status |
264 | * |
265 | * This is responsible for retrieving the status information of a certain |
266 | * record. |
267 | * |
268 | * @param string $id The record id to retrieve the holdings for |
269 | * |
270 | * @return mixed On success, an associative array with the following keys: |
271 | * id, availability (boolean), status, location, reserve, callnumber. |
272 | */ |
273 | public function getStatus($id) |
274 | { |
275 | // check ids for existing availability data in cache and skip these ids |
276 | if ( |
277 | $this->daiaCacheEnabled |
278 | && $item = $this->getCachedData($this->generateURI($id)) |
279 | ) { |
280 | if ($item != null) { |
281 | return $item; |
282 | } |
283 | } |
284 | |
285 | // let's retrieve the DAIA document by URI |
286 | try { |
287 | $rawResult = $this->doHTTPRequest($this->generateURI($id)); |
288 | // extract the DAIA document for the current id from the |
289 | // HTTPRequest's result |
290 | $doc = $this->extractDaiaDoc($id, $rawResult); |
291 | if (null !== $doc) { |
292 | // parse the extracted DAIA document and return the status info |
293 | $data = $this->parseDaiaDoc($id, $doc); |
294 | // cache the status information |
295 | if ($this->daiaCacheEnabled) { |
296 | $this->putCachedData($this->generateURI($id), $data); |
297 | } |
298 | return $data; |
299 | } |
300 | } catch (ILSException $e) { |
301 | $this->debug($e->getMessage()); |
302 | } |
303 | |
304 | return []; |
305 | } |
306 | |
307 | /** |
308 | * Get Statuses |
309 | * |
310 | * This is responsible for retrieving the status information for a |
311 | * collection of records. |
312 | * As the DAIA Query API supports querying multiple ids simultaneously |
313 | * (all ids divided by "|") getStatuses(ids) would call getStatus(id) only |
314 | * once, id containing the list of ids to be retrieved. This would cause some |
315 | * trouble as the list of ids does not necessarily correspond to the VuFind |
316 | * Record-id. Therefore getStatuses(ids) has its own logic for multiQuery-support |
317 | * and performs the HTTPRequest itself, retrieving one DAIA response for all ids |
318 | * and uses helper functions to split this one response into documents |
319 | * corresponding to the queried ids. |
320 | * |
321 | * @param array $ids The array of record ids to retrieve the status for |
322 | * |
323 | * @return array An array of status information values on success. |
324 | */ |
325 | public function getStatuses($ids) |
326 | { |
327 | $status = []; |
328 | |
329 | // check cache for given ids and skip these ids if availability data is found |
330 | foreach ($ids as $key => $id) { |
331 | if ( |
332 | $this->daiaCacheEnabled |
333 | && $item = $this->getCachedData($this->generateURI($id)) |
334 | ) { |
335 | if ($item != null) { |
336 | $status[] = $item; |
337 | unset($ids[$key]); |
338 | } |
339 | } |
340 | } |
341 | |
342 | // only query DAIA service if we have some ids left |
343 | if (count($ids) > 0) { |
344 | try { |
345 | if ($this->multiQuery) { |
346 | // perform one DAIA query with multiple URIs |
347 | $rawResult = $this |
348 | ->doHTTPRequest($this->generateMultiURIs($ids)); |
349 | // the id used in VuFind can differ from the document-URI |
350 | // (depending on how the URI is generated) |
351 | foreach ($ids as $id) { |
352 | // it is assumed that each DAIA document has a unique URI, |
353 | // so get the document with the corresponding id |
354 | $doc = $this->extractDaiaDoc($id, $rawResult); |
355 | if (null !== $doc) { |
356 | // a document with the corresponding id exists, which |
357 | // means we got status information for that record |
358 | $data = $this->parseDaiaDoc($id, $doc); |
359 | // cache the status information |
360 | if ($this->daiaCacheEnabled) { |
361 | $this->putCachedData($this->generateURI($id), $data); |
362 | } |
363 | $status[] = $data; |
364 | } |
365 | unset($doc); |
366 | } |
367 | } else { |
368 | // multiQuery is not supported, so retrieve DAIA documents one by |
369 | // one |
370 | foreach ($ids as $id) { |
371 | $rawResult = $this->doHTTPRequest($this->generateURI($id)); |
372 | // extract the DAIA document for the current id from the |
373 | // HTTPRequest's result |
374 | $doc = $this->extractDaiaDoc($id, $rawResult); |
375 | if (null !== $doc) { |
376 | // parse the extracted DAIA document and save the status |
377 | // info |
378 | $data = $this->parseDaiaDoc($id, $doc); |
379 | // cache the status information |
380 | if ($this->daiaCacheEnabled) { |
381 | $this->putCachedData($this->generateURI($id), $data); |
382 | } |
383 | $status[] = $data; |
384 | } |
385 | } |
386 | } |
387 | } catch (ILSException $e) { |
388 | $this->debug($e->getMessage()); |
389 | } |
390 | } |
391 | return $status; |
392 | } |
393 | |
394 | /** |
395 | * Get Holding |
396 | * |
397 | * This is responsible for retrieving the holding information of a certain |
398 | * record. |
399 | * |
400 | * @param string $id The record id to retrieve the holdings for |
401 | * @param array $patron Patron data |
402 | * @param array $options Extra options (not currently used) |
403 | * |
404 | * @return array On success, an associative array with the following |
405 | * keys: id, availability (boolean), status, location, reserve, callnumber, |
406 | * duedate, number, barcode. |
407 | * |
408 | * @SuppressWarnings(PHPMD.UnusedFormalParameter) |
409 | */ |
410 | public function getHolding($id, array $patron = null, array $options = []) |
411 | { |
412 | return $this->getStatus($id); |
413 | } |
414 | |
415 | /** |
416 | * Get Purchase History |
417 | * |
418 | * This is responsible for retrieving the acquisitions history data for the |
419 | * specific record (usually recently received issues of a serial). |
420 | * |
421 | * @param string $id The record id to retrieve the info for |
422 | * |
423 | * @throws ILSException |
424 | * @return array An array with the acquisitions data on success. |
425 | */ |
426 | public function getPurchaseHistory($id) |
427 | { |
428 | return []; |
429 | } |
430 | |
431 | /** |
432 | * Support method to handle date uniformly |
433 | * |
434 | * @param string $date String representing a date |
435 | * |
436 | * @return string Formatted date |
437 | */ |
438 | protected function convertDate($date) |
439 | { |
440 | try { |
441 | return $this->dateConverter |
442 | ->convertToDisplayDate('Y-m-d', $date); |
443 | } catch (\Exception $e) { |
444 | $this->debug('Date conversion failed: ' . $e->getMessage()); |
445 | return ''; |
446 | } |
447 | } |
448 | |
449 | /** |
450 | * Support method to handle datetime uniformly |
451 | * |
452 | * @param string $datetime String representing a datetime |
453 | * |
454 | * @return string Formatted datetime |
455 | */ |
456 | protected function convertDatetime($datetime) |
457 | { |
458 | return $this->convertDate($datetime); |
459 | } |
460 | |
461 | /** |
462 | * Perform an HTTP request. |
463 | * |
464 | * @param string $id id for query in daia |
465 | * |
466 | * @return xml or json object |
467 | * @throws ILSException |
468 | */ |
469 | protected function doHTTPRequest($id) |
470 | { |
471 | $http_headers = [ |
472 | 'Content-type: ' . $this->contentTypesRequest[$this->daiaResponseFormat], |
473 | 'Accept: ' . $this->contentTypesRequest[$this->daiaResponseFormat], |
474 | ]; |
475 | |
476 | $params = [ |
477 | 'id' => $id, |
478 | 'format' => $this->daiaResponseFormat, |
479 | ]; |
480 | |
481 | try { |
482 | $result = $this->httpService->get( |
483 | $this->baseUrl, |
484 | $params, |
485 | $this->daiaTimeout, |
486 | $http_headers |
487 | ); |
488 | } catch (\Exception $e) { |
489 | $msg = 'HTTP request exited with Exception ' . $e->getMessage() . |
490 | ' for record: ' . $id; |
491 | $this->throwAsIlsException($e, $msg); |
492 | } |
493 | |
494 | if (!$result->isSuccess()) { |
495 | throw new ILSException( |
496 | 'HTTP status ' . $result->getStatusCode() . |
497 | ' received, retrieving availability information for record: ' . $id |
498 | ); |
499 | } |
500 | |
501 | // check if result matches daiaResponseFormat |
502 | if ($this->contentTypesResponse != null) { |
503 | if ($this->contentTypesResponse[$this->daiaResponseFormat]) { |
504 | $contentTypesResponse = array_map( |
505 | 'trim', |
506 | explode( |
507 | ',', |
508 | $this->contentTypesResponse[$this->daiaResponseFormat] |
509 | ) |
510 | ); |
511 | [$responseMediaType] = array_pad( |
512 | explode( |
513 | ';', |
514 | $result->getHeaders()->get('Content-type')->getFieldValue(), |
515 | 2 |
516 | ), |
517 | 2, |
518 | null |
519 | ); // workaround to avoid notices if encoding is not set in header |
520 | if (!in_array(trim($responseMediaType), $contentTypesResponse)) { |
521 | throw new ILSException( |
522 | 'DAIA-ResponseFormat not supported. Received: ' . |
523 | $responseMediaType . ' - ' . |
524 | 'Expected: ' . |
525 | $this->contentTypesResponse[$this->daiaResponseFormat] |
526 | ); |
527 | } |
528 | } |
529 | } |
530 | |
531 | return $result->getBody(); |
532 | } |
533 | |
534 | /** |
535 | * Generate a DAIA URI necessary for the query |
536 | * |
537 | * @param string $id Id of the record whose DAIA document should be queried |
538 | * |
539 | * @return string URI of the DAIA document |
540 | * |
541 | * @see http://gbv.github.io/daia/daia.html#query-parameters |
542 | */ |
543 | protected function generateURI($id) |
544 | { |
545 | return $this->daiaIdPrefix . $id; |
546 | } |
547 | |
548 | /** |
549 | * Combine several ids to DAIA Query API conform URIs |
550 | * |
551 | * @param array $ids Array of ids which shall be converted into URIs and |
552 | * combined for querying multiple DAIA documents. |
553 | * |
554 | * @return string Combined URIs (delimited by "|") |
555 | * |
556 | * @see http://gbv.github.io/daia/daia.html#query-parameters |
557 | */ |
558 | protected function generateMultiURIs($ids) |
559 | { |
560 | $multiURI = ''; |
561 | foreach ($ids as $id) { |
562 | $multiURI .= $this->generateURI($id) . '|'; |
563 | } |
564 | return rtrim($multiURI, '|'); |
565 | } |
566 | |
567 | /** |
568 | * Parse a DAIA document depending on its type. |
569 | * |
570 | * Parse a DAIA document depending on its type and return a VuFind |
571 | * compatible array of status information. |
572 | * Supported types are: |
573 | * - array (for JSON results) |
574 | * |
575 | * @param string $id Record Id corresponding to the DAIA document |
576 | * @param mixed $daiaDoc The DAIA document, only array is supported |
577 | * |
578 | * @return array An array with status information for the record |
579 | * @throws ILSException |
580 | */ |
581 | protected function parseDaiaDoc($id, $daiaDoc) |
582 | { |
583 | if (is_array($daiaDoc)) { |
584 | return $this->parseDaiaArray($id, $daiaDoc); |
585 | } else { |
586 | throw new ILSException( |
587 | 'Unsupported document type (did not match Array or DOMNode).' |
588 | ); |
589 | } |
590 | } |
591 | |
592 | /** |
593 | * Extract a DAIA document identified by an id |
594 | * |
595 | * This method loops through all the existing DAIA document-elements in |
596 | * the given DAIA response and returns the first document whose id matches |
597 | * the given id. |
598 | * |
599 | * @param string $id Record Id of the DAIA document in question. |
600 | * @param string $daiaResponse Raw response from DAIA request. |
601 | * |
602 | * @return Array|DOMNode|null The DAIA document identified by id and |
603 | * type depending on daiaResponseFormat. |
604 | * @throws ILSException |
605 | */ |
606 | protected function extractDaiaDoc($id, $daiaResponse) |
607 | { |
608 | $docs = []; |
609 | if ($this->daiaResponseFormat == 'xml') { |
610 | try { |
611 | $docs = $this->convertDaiaXmlToJson($daiaResponse); |
612 | } catch (\Exception $e) { |
613 | $this->throwAsIlsException($e); |
614 | } |
615 | } elseif ($this->daiaResponseFormat == 'json') { |
616 | $docs = json_decode($daiaResponse, true); |
617 | } |
618 | |
619 | if (count($docs)) { |
620 | // check for error messages and write those to log |
621 | if (isset($docs['message'])) { |
622 | $this->logMessages($docs['message'], 'document'); |
623 | } |
624 | |
625 | // do DAIA documents exist? |
626 | if (isset($docs['document']) && $this->multiQuery) { |
627 | // now loop through the found DAIA documents |
628 | foreach ($docs['document'] as $doc) { |
629 | // DAIA documents should use URIs as value for id |
630 | if ( |
631 | isset($doc['id']) |
632 | && $doc['id'] == $this->generateURI($id) |
633 | ) { |
634 | // we've found the document element with the matching URI |
635 | // if the document has an item, then we return it |
636 | if (isset($doc['item'])) { |
637 | return $doc; |
638 | } |
639 | } |
640 | } |
641 | } elseif (isset($docs['document'])) { |
642 | // since a document exists but multiQuery is disabled, the first |
643 | // document is returned if it contains an item |
644 | $doc = array_shift($docs['document']); |
645 | if (isset($doc['item'])) { |
646 | return $doc; |
647 | } |
648 | } |
649 | // no (id matching) document element found |
650 | return null; |
651 | } else { |
652 | throw new ILSException('Unsupported document format.'); |
653 | } |
654 | } |
655 | |
656 | /** |
657 | * Converts a DAIA XML response to an array identical with a DAIA JSON response |
658 | * for the sent query. |
659 | * |
660 | * @param string $daiaResponse Response in XML format from DAIA service |
661 | * |
662 | * @return mixed |
663 | */ |
664 | protected function convertDaiaXmlToJson($daiaResponse) |
665 | { |
666 | $dom = new DOMDocument(); |
667 | $dom->loadXML($daiaResponse); |
668 | |
669 | // prepare DOMDocument as json_encode does not support save attributes if |
670 | // elements have values (see http://stackoverflow.com/a/20506281/2115462) |
671 | $prepare = function ($domNode) use (&$prepare) { |
672 | foreach ($domNode->childNodes as $node) { |
673 | if ($node->hasChildNodes()) { |
674 | $prepare($node); |
675 | } else { |
676 | if ( |
677 | ($domNode->hasAttributes() && strlen($domNode->nodeValue)) |
678 | || (in_array( |
679 | $domNode->nodeName, |
680 | ['storage', 'limitation', 'department', 'institution'] |
681 | ) && strlen($domNode->nodeValue)) |
682 | ) { |
683 | if (trim($node->textContent)) { |
684 | $domNode->setAttribute('content', $node->textContent); |
685 | $node->nodeValue = ''; |
686 | } |
687 | } |
688 | } |
689 | } |
690 | }; |
691 | $prepare($dom); |
692 | |
693 | // now let json_encode/decode convert XML into an array |
694 | $daiaArray = json_decode( |
695 | json_encode(simplexml_load_string($dom->saveXML())), |
696 | true |
697 | ); |
698 | |
699 | // merge @attributes fields in parent array |
700 | $merge = function ($array) use (&$merge) { |
701 | foreach ($array as $key => $value) { |
702 | if (is_array($value)) { |
703 | $value = $merge($value); |
704 | } |
705 | if ($key === '@attributes') { |
706 | $array = array_merge($array, $value); |
707 | unset($array[$key]); |
708 | } else { |
709 | $array[$key] = $value; |
710 | } |
711 | } |
712 | return $array; |
713 | }; |
714 | $daiaArray = $merge($daiaArray); |
715 | |
716 | // restructure the array, moving single elements to their parent's index [0] |
717 | $restructure = function ($array) use (&$restructure) { |
718 | $elements = [ |
719 | 'document', 'item', 'available', 'unavailable', 'limitation', |
720 | 'message', |
721 | ]; |
722 | foreach ($array as $key => $value) { |
723 | if (is_array($value)) { |
724 | $value = $restructure($value); |
725 | } |
726 | if ( |
727 | in_array($key, $elements, true) |
728 | && !isset($array[$key][0]) |
729 | ) { |
730 | unset($array[$key]); |
731 | $array[$key][] = $value; |
732 | } else { |
733 | $array[$key] = $value; |
734 | } |
735 | } |
736 | return $array; |
737 | }; |
738 | $daiaArray = $restructure($daiaArray); |
739 | |
740 | return $daiaArray; |
741 | } |
742 | |
743 | /** |
744 | * Parse an array with DAIA status information. |
745 | * |
746 | * @param string $id Record id for the DAIA array. |
747 | * @param array $daiaArray Array with raw DAIA status information. |
748 | * |
749 | * @return array Array with VuFind compatible status information. |
750 | */ |
751 | protected function parseDaiaArray($id, $daiaArray) |
752 | { |
753 | $result = []; |
754 | $doc_id = null; |
755 | $doc_href = null; |
756 | if (isset($daiaArray['id'])) { |
757 | $doc_id = $daiaArray['id']; |
758 | } |
759 | if (isset($daiaArray['href'])) { |
760 | // url of the document (not needed for VuFind) |
761 | $doc_href = $daiaArray['href']; |
762 | } |
763 | if (isset($daiaArray['message'])) { |
764 | // log messages for debugging |
765 | $this->logMessages($daiaArray['message'], 'document'); |
766 | } |
767 | // if one or more items exist, iterate and build result-item |
768 | if (isset($daiaArray['item']) && is_array($daiaArray['item'])) { |
769 | $number = 0; |
770 | foreach ($daiaArray['item'] as $item) { |
771 | $result_item = []; |
772 | $result_item['id'] = $id; |
773 | // custom DAIA field |
774 | $result_item['doc_id'] = $doc_id; |
775 | $result_item['item_id'] = $item['id']; |
776 | // custom DAIA field used in getHoldLink() |
777 | $result_item['ilslink'] |
778 | = ($item['href'] ?? $doc_href); |
779 | // count items |
780 | $number++; |
781 | $result_item['number'] = $this->getItemNumber($item, $number); |
782 | // set default value for barcode |
783 | $result_item['barcode'] = $this->getItemBarcode($item); |
784 | // set default value for reserve |
785 | $result_item['reserve'] = $this->getItemReserveStatus($item); |
786 | // get callnumber |
787 | $result_item['callnumber'] = $this->getItemCallnumber($item); |
788 | // get location |
789 | $result_item['location'] = $this->getItemDepartment($item); |
790 | // custom DAIA field |
791 | $result_item['locationid'] = $this->getItemDepartmentId($item); |
792 | // get location link |
793 | $result_item['locationhref'] = $this->getItemDepartmentLink($item); |
794 | // custom DAIA field |
795 | $result_item['storage'] = $this->getItemStorage($item); |
796 | // custom DAIA field |
797 | $result_item['storageid'] = $this->getItemStorageId($item); |
798 | // custom DAIA field |
799 | $result_item['storagehref'] = $this->getItemStorageLink($item); |
800 | // status and availability will be calculated in own function |
801 | $result_item = $this->getItemStatus($item) + $result_item; |
802 | // add result_item to the result array |
803 | $result[] = $result_item; |
804 | } // end iteration on item |
805 | } |
806 | |
807 | return $result; |
808 | } |
809 | |
810 | /** |
811 | * Returns an array with status information for provided item. |
812 | * |
813 | * @param array $item Array with DAIA item data |
814 | * |
815 | * @return array |
816 | */ |
817 | protected function getItemStatus($item) |
818 | { |
819 | $return = []; |
820 | $availability = false; |
821 | $duedate = null; |
822 | $serviceLink = ''; |
823 | $queue = ''; |
824 | $item_notes = []; |
825 | $item_limitation_types = []; |
826 | $services = []; |
827 | |
828 | if (isset($item['available'])) { |
829 | // check if item is loanable or presentation |
830 | foreach ($item['available'] as $available) { |
831 | if ( |
832 | isset($available['service']) |
833 | && in_array($available['service'], ['loan', 'presentation']) |
834 | ) { |
835 | $services['available'][] = $available['service']; |
836 | } |
837 | // attribute service can be set once or not |
838 | if ( |
839 | isset($available['service']) |
840 | && in_array( |
841 | $available['service'], |
842 | ['loan', 'presentation', 'openaccess'] |
843 | ) |
844 | ) { |
845 | // set item available if service is loan, presentation or |
846 | // openaccess |
847 | $availability = true; |
848 | if ( |
849 | $available['service'] == 'loan' |
850 | && isset($available['href']) |
851 | ) { |
852 | // save the link to the ils if we have a href for loan |
853 | // service |
854 | $serviceLink = $available['href']; |
855 | } |
856 | } |
857 | |
858 | // use limitation element for status string |
859 | if (isset($available['limitation'])) { |
860 | $item_notes = array_merge( |
861 | $item_notes, |
862 | $this->getItemLimitationContent($available['limitation']) |
863 | ); |
864 | $item_limitation_types = array_merge( |
865 | $item_limitation_types, |
866 | $this->getItemLimitationTypes($available['limitation']) |
867 | ); |
868 | } |
869 | |
870 | // log messages for debugging |
871 | if (isset($available['message'])) { |
872 | $this->logMessages($available['message'], 'item->available'); |
873 | } |
874 | } |
875 | } |
876 | |
877 | if (isset($item['unavailable'])) { |
878 | foreach ($item['unavailable'] as $unavailable) { |
879 | if ( |
880 | isset($unavailable['service']) |
881 | && in_array($unavailable['service'], ['loan', 'presentation']) |
882 | ) { |
883 | $services['unavailable'][] = $unavailable['service']; |
884 | } |
885 | // attribute service can be set once or not |
886 | if ( |
887 | isset($unavailable['service']) |
888 | && in_array( |
889 | $unavailable['service'], |
890 | ['loan', 'presentation', 'openaccess'] |
891 | ) |
892 | ) { |
893 | if ( |
894 | $unavailable['service'] == 'loan' |
895 | && isset($unavailable['href']) |
896 | ) { |
897 | //save the link to the ils if we have a href for loan service |
898 | $serviceLink = $unavailable['href']; |
899 | } |
900 | |
901 | // use limitation element for status string |
902 | if (isset($unavailable['limitation'])) { |
903 | $item_notes = array_merge( |
904 | $item_notes, |
905 | $this->getItemLimitationContent( |
906 | $unavailable['limitation'] |
907 | ) |
908 | ); |
909 | $item_limitation_types = array_merge( |
910 | $item_limitation_types, |
911 | $this->getItemLimitationTypes($unavailable['limitation']) |
912 | ); |
913 | } |
914 | } |
915 | // attribute expected is mandatory for unavailable element |
916 | if (!empty($unavailable['expected'])) { |
917 | try { |
918 | $duedate = $this->dateConverter |
919 | ->convertToDisplayDate( |
920 | 'Y-m-d', |
921 | $unavailable['expected'] |
922 | ); |
923 | } catch (\Exception $e) { |
924 | $this->debug('Date conversion failed: ' . $e->getMessage()); |
925 | $duedate = null; |
926 | } |
927 | } |
928 | |
929 | // attribute queue can be set |
930 | if (isset($unavailable['queue'])) { |
931 | $queue = $unavailable['queue']; |
932 | } |
933 | |
934 | // log messages for debugging |
935 | if (isset($unavailable['message'])) { |
936 | $this->logMessages($unavailable['message'], 'item->unavailable'); |
937 | } |
938 | } |
939 | } |
940 | |
941 | /*'returnDate' => '', // false if not recently returned(?)*/ |
942 | |
943 | if (!empty($serviceLink)) { |
944 | $return['ilslink'] = $serviceLink; |
945 | } |
946 | |
947 | $return['item_notes'] = $item_notes; |
948 | $return['status'] = $this->getStatusString($item); |
949 | $return['availability'] = $availability; |
950 | $return['duedate'] = $duedate; |
951 | $return['requests_placed'] = $queue; |
952 | $return['services'] = $this->getAvailableItemServices($services); |
953 | |
954 | // In this DAIA driver implementation addLink and is_holdable are assumed |
955 | // Boolean as patron based availability requires either a patron-id or -type. |
956 | // This should be handled in a custom DAIA driver |
957 | $return['addLink'] = $this->checkIsRecallable($item); |
958 | $return['is_holdable'] = $this->checkIsRecallable($item); |
959 | $return['holdtype'] = $this->getHoldType($item); |
960 | |
961 | // Check if we the item is available for storage retrieval request if it is |
962 | // not holdable. |
963 | $return['addStorageRetrievalRequestLink'] = !$return['is_holdable'] |
964 | ? $this->checkIsStorageRetrievalRequest($item) : false; |
965 | |
966 | // add a custom Field to allow passing custom DAIA data to the frontend in |
967 | // order to use it for more precise display of availability |
968 | $return['customData'] = $this->getCustomData($item); |
969 | |
970 | $return['limitation_types'] = $item_limitation_types; |
971 | |
972 | return $return; |
973 | } |
974 | |
975 | /** |
976 | * Helper function to allow custom data in status array. |
977 | * |
978 | * @param array $item Array with DAIA item data |
979 | * |
980 | * @return array |
981 | */ |
982 | protected function getCustomData($item) |
983 | { |
984 | return []; |
985 | } |
986 | |
987 | /** |
988 | * Helper function to return an appropriate status string for current item. |
989 | * |
990 | * @param array $item Array with DAIA item data |
991 | * |
992 | * @return string |
993 | */ |
994 | protected function getStatusString($item) |
995 | { |
996 | // status cannot be null as this will crash the translator |
997 | return ''; |
998 | } |
999 | |
1000 | /** |
1001 | * Helper function to determine if item is recallable. |
1002 | * DAIA does not genuinly allow distinguishing between holdable and recallable |
1003 | * items. This could be achieved by usage of limitations but this would not be |
1004 | * shared functionality between different DAIA implementations (thus should be |
1005 | * implemented in custom drivers). Therefore this returns whether an item |
1006 | * is recallable based on unavailable services and the existence of an href. |
1007 | * |
1008 | * @param array $item Array with DAIA item data |
1009 | * |
1010 | * @return bool |
1011 | */ |
1012 | protected function checkIsRecallable($item) |
1013 | { |
1014 | // This basic implementation checks the item for being unavailable for loan |
1015 | // and presentation but with an existing href (as a flag for further action). |
1016 | $services = ['available' => [], 'unavailable' => []]; |
1017 | $href = false; |
1018 | if (isset($item['available'])) { |
1019 | // check if item is loanable or presentation |
1020 | foreach ($item['available'] as $available) { |
1021 | if ( |
1022 | isset($available['service']) |
1023 | && in_array($available['service'], ['loan', 'presentation']) |
1024 | ) { |
1025 | $services['available'][] = $available['service']; |
1026 | } |
1027 | } |
1028 | } |
1029 | |
1030 | if (isset($item['unavailable'])) { |
1031 | foreach ($item['unavailable'] as $unavailable) { |
1032 | if ( |
1033 | isset($unavailable['service']) |
1034 | && in_array($unavailable['service'], ['loan', 'presentation']) |
1035 | ) { |
1036 | $services['unavailable'][] = $unavailable['service']; |
1037 | // attribute href is used to determine whether item is recallable |
1038 | // or not |
1039 | $href = isset($unavailable['href']) ? true : $href; |
1040 | } |
1041 | } |
1042 | } |
1043 | |
1044 | // Check if we have at least one service unavailable and a href field is set |
1045 | // (either as flag or as actual value for the next action). |
1046 | return $href && count( |
1047 | array_diff($services['unavailable'], $services['available']) |
1048 | ); |
1049 | } |
1050 | |
1051 | /** |
1052 | * Helper function to determine if the item is available as storage retrieval. |
1053 | * |
1054 | * @param array $item Array with DAIA item data |
1055 | * |
1056 | * @return bool |
1057 | */ |
1058 | protected function checkIsStorageRetrievalRequest($item) |
1059 | { |
1060 | // This basic implementation checks the item for being available for loan |
1061 | // and presentation but with an existing href (as a flag for further action). |
1062 | $services = ['available' => [], 'unavailable' => []]; |
1063 | $href = false; |
1064 | if (isset($item['available'])) { |
1065 | // check if item is loanable or presentation |
1066 | foreach ($item['available'] as $available) { |
1067 | if ( |
1068 | isset($available['service']) |
1069 | && in_array($available['service'], ['loan', 'presentation']) |
1070 | ) { |
1071 | $services['available'][] = $available['service']; |
1072 | // attribute href is used to determine whether item is |
1073 | // requestable or not |
1074 | $href = isset($available['href']) ? true : $href; |
1075 | } |
1076 | } |
1077 | } |
1078 | |
1079 | if (isset($item['unavailable'])) { |
1080 | foreach ($item['unavailable'] as $unavailable) { |
1081 | if ( |
1082 | isset($unavailable['service']) |
1083 | && in_array($unavailable['service'], ['loan', 'presentation']) |
1084 | ) { |
1085 | $services['unavailable'][] = $unavailable['service']; |
1086 | } |
1087 | } |
1088 | } |
1089 | |
1090 | // Check if we have at least one service unavailable and a href field is set |
1091 | // (either as flag or as actual value for the next action). |
1092 | return $href && count( |
1093 | array_diff($services['available'], $services['unavailable']) |
1094 | ); |
1095 | } |
1096 | |
1097 | /** |
1098 | * Helper function to determine the holdtype available for current item. |
1099 | * DAIA does not genuinly allow distinguishing between holdable and recallable |
1100 | * items. This could be achieved by usage of limitations but this would not be |
1101 | * shared functionality between different DAIA implementations (thus should be |
1102 | * implemented in custom drivers). Therefore getHoldType always returns recall. |
1103 | * |
1104 | * @param array $item Array with DAIA item data |
1105 | * |
1106 | * @return string 'recall'|null |
1107 | */ |
1108 | protected function getHoldType($item) |
1109 | { |
1110 | // return holdtype (hold, recall or block if patron is not allowed) for item |
1111 | return $this->checkIsRecallable($item) ? 'recall' : null; |
1112 | } |
1113 | |
1114 | /** |
1115 | * Returns the evaluated value of the provided limitation element |
1116 | * |
1117 | * @param array $limitations Array with DAIA limitation data |
1118 | * |
1119 | * @return array |
1120 | */ |
1121 | protected function getItemLimitation($limitations) |
1122 | { |
1123 | $itemLimitation = []; |
1124 | foreach ($limitations as $limitation) { |
1125 | // return the first limitation with content set |
1126 | if (isset($limitation['content'])) { |
1127 | $itemLimitation[] = $limitation['content']; |
1128 | } |
1129 | } |
1130 | return $itemLimitation; |
1131 | } |
1132 | |
1133 | /** |
1134 | * Returns the value of item.department.content (e.g. to be used in VuFind |
1135 | * getStatus/getHolding array as location) |
1136 | * |
1137 | * @param array $item Array with DAIA item data |
1138 | * |
1139 | * @return string |
1140 | */ |
1141 | protected function getItemDepartment($item) |
1142 | { |
1143 | return isset($item['department']) && isset($item['department']['content']) |
1144 | && !empty($item['department']['content']) |
1145 | ? $item['department']['content'] |
1146 | : 'Unknown'; |
1147 | } |
1148 | |
1149 | /** |
1150 | * Returns the value of item.department.id (e.g. to be used in VuFind |
1151 | * getStatus/getHolding array as location) |
1152 | * |
1153 | * @param array $item Array with DAIA item data |
1154 | * |
1155 | * @return string |
1156 | */ |
1157 | protected function getItemDepartmentId($item) |
1158 | { |
1159 | return isset($item['department']) && isset($item['department']['id']) |
1160 | ? $item['department']['id'] : ''; |
1161 | } |
1162 | |
1163 | /** |
1164 | * Returns the value of item.department.href (e.g. to be used in VuFind |
1165 | * getStatus/getHolding array for linking the location) |
1166 | * |
1167 | * @param array $item Array with DAIA item data |
1168 | * |
1169 | * @return string |
1170 | */ |
1171 | protected function getItemDepartmentLink($item) |
1172 | { |
1173 | return $item['department']['href'] ?? false; |
1174 | } |
1175 | |
1176 | /** |
1177 | * Returns the value of item.storage.content (e.g. to be used in VuFind |
1178 | * getStatus/getHolding array as location) |
1179 | * |
1180 | * @param array $item Array with DAIA item data |
1181 | * |
1182 | * @return string |
1183 | */ |
1184 | protected function getItemStorage($item) |
1185 | { |
1186 | return isset($item['storage']) && isset($item['storage']['content']) |
1187 | && !empty($item['storage']['content']) |
1188 | ? $item['storage']['content'] |
1189 | : 'Unknown'; |
1190 | } |
1191 | |
1192 | /** |
1193 | * Returns the value of item.storage.id (e.g. to be used in VuFind |
1194 | * getStatus/getHolding array as location) |
1195 | * |
1196 | * @param array $item Array with DAIA item data |
1197 | * |
1198 | * @return string |
1199 | */ |
1200 | protected function getItemStorageId($item) |
1201 | { |
1202 | return isset($item['storage']) && isset($item['storage']['id']) |
1203 | ? $item['storage']['id'] : ''; |
1204 | } |
1205 | |
1206 | /** |
1207 | * Returns the value of item.storage.href (e.g. to be used in VuFind |
1208 | * getStatus/getHolding array for linking the location) |
1209 | * |
1210 | * @param array $item Array with DAIA item data |
1211 | * |
1212 | * @return string |
1213 | */ |
1214 | protected function getItemStorageLink($item) |
1215 | { |
1216 | return isset($item['storage']) && isset($item['storage']['href']) |
1217 | ? $item['storage']['href'] : ''; |
1218 | } |
1219 | |
1220 | /** |
1221 | * Returns the evaluated values of the provided limitations element |
1222 | * |
1223 | * @param array $limitations Array with DAIA limitation data |
1224 | * |
1225 | * @return array |
1226 | */ |
1227 | protected function getItemLimitationContent($limitations) |
1228 | { |
1229 | $itemLimitationContent = []; |
1230 | foreach ($limitations as $limitation) { |
1231 | // return the first limitation with content set |
1232 | if (isset($limitation['content'])) { |
1233 | $itemLimitationContent[] = $limitation['content']; |
1234 | } |
1235 | } |
1236 | return $itemLimitationContent; |
1237 | } |
1238 | |
1239 | /** |
1240 | * Returns the evaluated values of the provided limitations element |
1241 | * |
1242 | * @param array $limitations Array with DAIA limitation data |
1243 | * |
1244 | * @return array |
1245 | */ |
1246 | protected function getItemLimitationTypes($limitations) |
1247 | { |
1248 | $itemLimitationTypes = []; |
1249 | foreach ($limitations as $limitation) { |
1250 | // return the first limitation with content set |
1251 | if (isset($limitation['id'])) { |
1252 | $itemLimitationTypes[] = $limitation['id']; |
1253 | } |
1254 | } |
1255 | return $itemLimitationTypes; |
1256 | } |
1257 | |
1258 | /** |
1259 | * Returns the value for "number" in VuFind getStatus/getHolding array |
1260 | * |
1261 | * @param array $item Array with DAIA item data |
1262 | * @param int $counter Integer counting items as alternative return value |
1263 | * |
1264 | * @return mixed |
1265 | */ |
1266 | protected function getItemNumber($item, $counter) |
1267 | { |
1268 | return $counter; |
1269 | } |
1270 | |
1271 | /** |
1272 | * Returns the value for "location" in VuFind getStatus/getHolding array |
1273 | * |
1274 | * @param array $item Array with DAIA item data |
1275 | * |
1276 | * @return string |
1277 | */ |
1278 | protected function getItemBarcode($item) |
1279 | { |
1280 | return '1'; |
1281 | } |
1282 | |
1283 | /** |
1284 | * Returns the value for "reserve" in VuFind getStatus/getHolding array |
1285 | * |
1286 | * @param array $item Array with DAIA item data |
1287 | * |
1288 | * @return string |
1289 | */ |
1290 | protected function getItemReserveStatus($item) |
1291 | { |
1292 | return 'N'; |
1293 | } |
1294 | |
1295 | /** |
1296 | * Returns the value for "callnumber" in VuFind getStatus/getHolding array |
1297 | * |
1298 | * @param array $item Array with DAIA item data |
1299 | * |
1300 | * @return string |
1301 | */ |
1302 | protected function getItemCallnumber($item) |
1303 | { |
1304 | return isset($item['label']) && !empty($item['label']) |
1305 | ? $item['label'] |
1306 | : 'Unknown'; |
1307 | } |
1308 | |
1309 | /** |
1310 | * Returns the available services of the given set of available and unavailable |
1311 | * services |
1312 | * |
1313 | * @param array $services Array with DAIA services available/unavailable |
1314 | * |
1315 | * @return array |
1316 | */ |
1317 | protected function getAvailableItemServices($services) |
1318 | { |
1319 | $availableServices = []; |
1320 | if (isset($services['available'])) { |
1321 | foreach ($services['available'] as $service) { |
1322 | if ( |
1323 | !isset($services['unavailable']) |
1324 | || !in_array($service, $services['unavailable']) |
1325 | ) { |
1326 | $availableServices[] = $service; |
1327 | } |
1328 | } |
1329 | } |
1330 | return array_intersect(['loan', 'presentation'], $availableServices); |
1331 | } |
1332 | |
1333 | /** |
1334 | * Logs content of message elements in DAIA response for debugging |
1335 | * |
1336 | * @param array $messages Array with message elements to be logged |
1337 | * @param string $context Description of current message context |
1338 | * |
1339 | * @return void |
1340 | */ |
1341 | protected function logMessages($messages, $context) |
1342 | { |
1343 | foreach ($messages as $message) { |
1344 | if (isset($message['content'])) { |
1345 | $this->debug( |
1346 | 'Message in DAIA response (' . (string)$context . '): ' . |
1347 | $message['content'] |
1348 | ); |
1349 | } |
1350 | } |
1351 | } |
1352 | } |