Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
32.94% covered (danger)
32.94%
28 / 85
45.00% covered (danger)
45.00%
9 / 20
CRAP
0.00% covered (danger)
0.00%
0 / 1
NoILS
32.94% covered (danger)
32.94%
28 / 85
45.00% covered (danger)
45.00%
9 / 20
404.41
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 init
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getConfig
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getIdPrefix
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSolrRecord
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 getStatus
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
12
 getStatuses
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 getHolding
80.95% covered (warning)
80.95%
17 / 21
0.00% covered (danger)
0.00%
0 / 1
3.06
 getFormattedMarcDetails
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
42
 hasHoldings
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 getPurchaseHistory
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getNewItems
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getOfflineMode
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 loginIsHidden
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 patronLogin
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFunds
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDepartments
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getInstructors
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getCourses
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 findReserves
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3/**
4 * Driver for offline/missing ILS.
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 2007.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2,
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 * @category VuFind
24 * @package  ILS_Drivers
25 * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
26 * @author   Demian Katz <demian.katz@villanova.edu>
27 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
28 * @link     https://vufind.org/wiki/development:plugins:ils_drivers Wiki
29 */
30
31namespace VuFind\ILS\Driver;
32
33use VuFind\Exception\ILS as ILSException;
34use VuFind\I18n\Translator\TranslatorAwareInterface;
35
36use function strlen;
37
38/**
39 * Driver for offline/missing ILS.
40 *
41 * @category VuFind
42 * @package  ILS_Drivers
43 * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
44 * @author   Demian Katz <demian.katz@villanova.edu>
45 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
46 * @link     https://vufind.org/wiki/development:plugins:ils_drivers Wiki
47 */
48class NoILS extends AbstractBase implements TranslatorAwareInterface
49{
50    use \VuFind\I18n\Translator\TranslatorAwareTrait;
51
52    /**
53     * Record loader
54     *
55     * @var \VuFind\Record\Loader
56     */
57    protected $recordLoader;
58
59    /**
60     * Constructor
61     *
62     * @param \VuFind\Record\Loader $loader Record loader
63     */
64    public function __construct(\VuFind\Record\Loader $loader)
65    {
66        $this->recordLoader = $loader;
67    }
68
69    /**
70     * Initialize the driver.
71     *
72     * Validate configuration and perform all resource-intensive tasks needed to
73     * make the driver active.
74     *
75     * @throws ILSException
76     * @return void
77     */
78    public function init()
79    {
80        // No special processing needed here.
81    }
82
83    /**
84     * Public Function which retrieves renew, hold and cancel settings from the
85     * driver ini file.
86     *
87     * @param string $function The name of the feature to be checked
88     * @param array  $params   Optional feature-specific parameters (array)
89     *
90     * @return array An array with key-value pairs.
91     *
92     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
93     */
94    public function getConfig($function, $params = [])
95    {
96        return $this->config[$function] ?? false;
97    }
98
99    /**
100     * Get the ID prefix from the configuration, if set.
101     *
102     * @return string
103     */
104    protected function getIdPrefix()
105    {
106        return $this->config['settings']['idPrefix'] ?? null;
107    }
108
109    /**
110     * Get a Solr record.
111     *
112     * @param string $id ID of record to retrieve
113     *
114     * @return \VuFind\RecordDriver\AbstractBase
115     */
116    protected function getSolrRecord($id)
117    {
118        // Add idPrefix condition
119        $idPrefix = $this->getIdPrefix();
120        return $this->recordLoader->load(
121            strlen($idPrefix) ? $idPrefix . $id : $id,
122            DEFAULT_SEARCH_BACKEND,
123            true    // tolerate missing records
124        );
125    }
126
127    /**
128     * Get Status
129     *
130     * This is responsible for retrieving the status information of a certain
131     * record.
132     *
133     * @param string $id The record id to retrieve the holdings for
134     *
135     * @throws ILSException
136     * @return mixed     On success, an associative array with the following keys:
137     * id, availability (boolean), status, location, reserve, callnumber.
138     */
139    public function getStatus($id)
140    {
141        $useStatus = $this->config['settings']['useStatus'] ?? 'none';
142        if ($useStatus == 'custom') {
143            $status = $this->translate($this->config['Status']['status'] ?? '');
144            return [
145                [
146                    'id' => $id,
147                    'availability' => $this->config['Status']['availability'] ?? false,
148                    'status' => $status,
149                    'use_unknown_message' => (bool)($this->config['Status']['use_unknown_message'] ?? false),
150                    'status_array' => [$status],
151                    'location' => $this->translate($this->config['Status']['location'] ?? ''),
152                    'reserve' => $this->config['Status']['reserve'] ?? 'N',
153                    'callnumber' => $this->translate($this->config['Status']['callnumber'] ?? ''),
154                ],
155            ];
156        } elseif ($useStatus == 'marc') {
157            // Retrieve record from index:
158            $recordDriver = $this->getSolrRecord($id);
159            return $this->getFormattedMarcDetails($recordDriver, 'MarcStatus');
160        }
161        return [];
162    }
163
164    /**
165     * Get Statuses
166     *
167     * This is responsible for retrieving the status information for a
168     * collection of records.
169     *
170     * @param array $idList The array of record ids to retrieve the status for
171     *
172     * @throws ILSException
173     * @return array        An array of getStatus() return values on success.
174     */
175    public function getStatuses($idList)
176    {
177        $useStatus = $this->config['settings']['useStatus'] ?? 'none';
178        if ($useStatus == 'custom' || $useStatus == 'marc') {
179            $status = [];
180            foreach ($idList as $id) {
181                $status[] = $this->getStatus($id);
182            }
183            return $status;
184        }
185        return [];
186    }
187
188    /**
189     * Get Holding
190     *
191     * This is responsible for retrieving the holding information of a certain
192     * record.
193     *
194     * @param string $id      The record id to retrieve the holdings for
195     * @param array  $patron  Patron data
196     * @param array  $options Extra options (not currently used)
197     *
198     * @throws ILSException
199     * @return array         On success, an associative array with the following
200     * keys: id, availability (boolean), status, location, reserve, callnumber,
201     * duedate, number, barcode.
202     *
203     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
204     */
205    public function getHolding($id, array $patron = null, array $options = [])
206    {
207        $useHoldings = $this->config['settings']['useHoldings'] ?? 'none';
208        if ($useHoldings == 'custom') {
209            return [
210                [
211                    'id' => $id,
212                    'number' => $this->translate($this->config['Holdings']['number'] ?? ''),
213                    'availability' => $this->config['Holdings']['availability'] ?? false,
214                    'status' => $this->translate($this->config['Holdings']['status'] ?? ''),
215                    'use_unknown_message' => (bool)($this->config['Holdings']['use_unknown_message'] ?? false),
216                    'location' => $this->translate($this->config['Holdings']['location'] ?? ''),
217                    'reserve' => $this->config['Holdings']['reserve'] ?? 'N',
218                    'callnumber' => $this->translate($this->config['Holdings']['callnumber'] ?? ''),
219                    'barcode' => $this->config['Holdings']['barcode'] ?? '',
220                    'notes' => $this->config['Holdings']['notes'] ?? [],
221                    'summary' => $this->config['Holdings']['summary'] ?? [],
222                ],
223            ];
224        } elseif ($useHoldings == 'marc') {
225            // Retrieve record from index:
226            $recordDriver = $this->getSolrRecord($id);
227            return $this->getFormattedMarcDetails($recordDriver, 'MarcHoldings');
228        }
229
230        return [];
231    }
232
233    /**
234     * This is responsible for retrieving the status or holdings information of a
235     * certain record from a Marc Record.
236     *
237     * @param object $recordDriver  A RecordDriver Object
238     * @param string $configSection Section of driver config containing data
239     * on how to extract details from MARC.
240     *
241     * @return array An Array of Holdings Information
242     */
243    protected function getFormattedMarcDetails($recordDriver, $configSection)
244    {
245        $marcStatus = $this->config[$configSection] ?? false;
246        if ($marcStatus) {
247            $field = $marcStatus['marcField'];
248            unset($marcStatus['marcField']);
249            $result = $recordDriver->tryMethod(
250                'getFormattedMarcDetails',
251                [$field, $marcStatus]
252            );
253            // If the details coming back from the record driver include the
254            // ID prefix, strip it off!
255            $idPrefix = $this->getIdPrefix();
256            if (
257                isset($result[0]['id'])
258                && '' !== $idPrefix
259                && str_starts_with($result[0]['id'], $idPrefix)
260            ) {
261                $result[0]['id'] = substr($result[0]['id'], strlen($idPrefix));
262            }
263            return empty($result) ? [] : $result;
264        }
265        return [];
266    }
267
268    /**
269     * Has Holdings
270     *
271     * This is responsible for determining if holdings exist for a particular
272     * bibliographic id
273     *
274     * @param string $id The record id to retrieve the holdings for
275     *
276     * @return bool True if holdings exist, False if they do not
277     *
278     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
279     */
280    public function hasHoldings($id)
281    {
282        // If the ILS is offline, we should if we can look up details:
283        $useHoldings = $this->config['settings']['useHoldings'] ?? '';
284
285        // "none" will be processed differently in the config depending
286        // on whether it's in or out of quotes; handle both cases.
287        return $useHoldings != 'none' && !empty($useHoldings)
288            && !empty($this->getHolding($id));
289    }
290
291    /**
292     * Get Purchase History
293     *
294     * This is responsible for retrieving the acquisitions history data for the
295     * specific record (usually recently received issues of a serial).
296     *
297     * @param string $id The record id to retrieve the info for
298     *
299     * @return array
300     */
301    public function getPurchaseHistory($id)
302    {
303        return [];
304    }
305
306    /**
307     * Get New Items
308     *
309     * Retrieve the IDs of items recently added to the catalog.
310     *
311     * @param int $page    Page number of results to retrieve (counting starts at 1)
312     * @param int $limit   The size of each page of results to retrieve
313     * @param int $daysOld The maximum age of records to retrieve in days (max. 30)
314     * @param int $fundId  optional fund ID to use for limiting results (use a value
315     * returned by getFunds, or exclude for no limit); note that "fund" may be a
316     * misnomer - if funds are not an appropriate way to limit your new item
317     * results, you can return a different set of values from getFunds. The
318     * important thing is that this parameter supports an ID returned by getFunds,
319     * whatever that may mean.
320     *
321     * @return array       Associative array with 'count' and 'results' keys
322     *
323     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
324     */
325    public function getNewItems($page, $limit, $daysOld, $fundId = null)
326    {
327        return [];
328    }
329
330    /**
331     * Get Offline Mode
332     *
333     * This is responsible for returning the offline mode
334     *
335     * @return string "ils-offline" for systems where the main ILS is offline,
336     * "ils-none" for systems which do not use an ILS
337     */
338    public function getOfflineMode()
339    {
340        return $this->config['settings']['mode'] ?? 'ils-offline';
341    }
342
343    /**
344     * Get Hidden Login Mode
345     *
346     * This is responsible for indicating whether login should be hidden.
347     *
348     * @return bool true if the login should be hidden, false if not
349     */
350    public function loginIsHidden()
351    {
352        return $this->config['settings']['hideLogin'] ?? false;
353    }
354
355    /**
356     * Patron Login
357     *
358     * This is responsible for authenticating a patron against the catalog.
359     *
360     * @param string $username Patron username
361     * @param string $password Patron password
362     *
363     * @throws ILSException
364     * @return mixed          Associative array of patron info on successful login,
365     * null on unsuccessful login.
366     *
367     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
368     */
369    public function patronLogin($username, $password)
370    {
371        // Block authentication:
372        return null;
373    }
374
375    /**
376     * Get Funds
377     *
378     * Return a list of funds which may be used to limit the getNewItems list.
379     *
380     * @throws ILSException
381     * @return array An associative array with key = fund ID, value = fund name.
382     */
383    public function getFunds()
384    {
385        // Does not work while ILS offline:
386        return [];
387    }
388
389    /**
390     * Get Departments
391     *
392     * Obtain a list of departments for use in limiting the reserves list.
393     *
394     * @throws ILSException
395     * @return array An associative array with key = dept. ID, value = dept. name.
396     */
397    public function getDepartments()
398    {
399        // Does not work while ILS offline:
400        return [];
401    }
402
403    /**
404     * Get Instructors
405     *
406     * Obtain a list of instructors for use in limiting the reserves list.
407     *
408     * @throws ILSException
409     * @return array An associative array with key = ID, value = name.
410     */
411    public function getInstructors()
412    {
413        // Does not work while ILS offline:
414        return [];
415    }
416
417    /**
418     * Get Courses
419     *
420     * Obtain a list of courses for use in limiting the reserves list.
421     *
422     * @throws ILSException
423     * @return array An associative array with key = ID, value = name.
424     */
425    public function getCourses()
426    {
427        // Does not work while ILS offline:
428        return [];
429    }
430
431    /**
432     * Find Reserves
433     *
434     * Obtain information on course reserves.
435     *
436     * This version of findReserves was contributed by Matthew Hooper and includes
437     * support for electronic reserves (though eReserve support is still a work in
438     * progress).
439     *
440     * @param string $course ID from getCourses (empty string to match all)
441     * @param string $inst   ID from getInstructors (empty string to match all)
442     * @param string $dept   ID from getDepartments (empty string to match all)
443     *
444     * @throws ILSException
445     * @return array An array of associative arrays representing reserve items.
446     *
447     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
448     */
449    public function findReserves($course, $inst, $dept)
450    {
451        // Does not work while ILS offline:
452        return [];
453    }
454}