Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 86 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 1 |
TitleHolds | |
0.00% |
0 / 86 |
|
0.00% |
0 / 7 |
1406 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
getHold | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
56 | |||
getHoldings | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
checkOverrideMode | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
56 | |||
driverHold | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
42 | |||
generateHold | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
90 | |||
getHoldDetails | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | |
3 | /** |
4 | * Title Hold Logic Class |
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_Logic |
25 | * @author Demian Katz <demian.katz@villanova.edu> |
26 | * @author Luke O'Sullivan <l.osullivan@swansea.ac.uk> |
27 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
28 | * @link https://vufind.org/wiki/development Wiki |
29 | */ |
30 | |
31 | namespace VuFind\ILS\Logic; |
32 | |
33 | use VuFind\Exception\ILS as ILSException; |
34 | use VuFind\ILS\Connection as ILSConnection; |
35 | |
36 | use function in_array; |
37 | use function is_array; |
38 | use function is_bool; |
39 | |
40 | /** |
41 | * Title Hold Logic Class |
42 | * |
43 | * @category VuFind |
44 | * @package ILS_Logic |
45 | * @author Demian Katz <demian.katz@villanova.edu> |
46 | * @author Luke O'Sullivan <l.osullivan@swansea.ac.uk> |
47 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
48 | * @link https://vufind.org/wiki/development Wiki |
49 | */ |
50 | class TitleHolds |
51 | { |
52 | /** |
53 | * ILS authenticator |
54 | * |
55 | * @var \VuFind\Auth\ILSAuthenticator |
56 | */ |
57 | protected $ilsAuth; |
58 | |
59 | /** |
60 | * Catalog connection object |
61 | * |
62 | * @var ILSConnection |
63 | */ |
64 | protected $catalog; |
65 | |
66 | /** |
67 | * HMAC generator |
68 | * |
69 | * @var \VuFind\Crypt\HMAC |
70 | */ |
71 | protected $hmac; |
72 | |
73 | /** |
74 | * VuFind configuration |
75 | * |
76 | * @var \Laminas\Config\Config |
77 | */ |
78 | protected $config; |
79 | |
80 | /** |
81 | * Holding locations to hide from display |
82 | * |
83 | * @var array |
84 | */ |
85 | protected $hideHoldings = []; |
86 | |
87 | /** |
88 | * Constructor |
89 | * |
90 | * @param \VuFind\Auth\ILSAuthenticator $ilsAuth ILS authenticator |
91 | * @param ILSConnection $ils A catalog connection |
92 | * @param \VuFind\Crypt\HMAC $hmac HMAC generator |
93 | * @param \Laminas\Config\Config $config VuFind configuration |
94 | */ |
95 | public function __construct( |
96 | \VuFind\Auth\ILSAuthenticator $ilsAuth, |
97 | ILSConnection $ils, |
98 | \VuFind\Crypt\HMAC $hmac, |
99 | \Laminas\Config\Config $config |
100 | ) { |
101 | $this->ilsAuth = $ilsAuth; |
102 | $this->hmac = $hmac; |
103 | $this->config = $config; |
104 | |
105 | if (isset($this->config->Record->hide_holdings)) { |
106 | foreach ($this->config->Record->hide_holdings as $current) { |
107 | $this->hideHoldings[] = $current; |
108 | } |
109 | } |
110 | |
111 | $this->catalog = $ils; |
112 | } |
113 | |
114 | /** |
115 | * Public method for getting title level holds |
116 | * |
117 | * @param string $id A Bib ID |
118 | * |
119 | * @return string|bool URL to place hold, or false if hold option unavailable |
120 | * |
121 | * @todo Indicate login failure or ILS connection failure somehow? |
122 | */ |
123 | public function getHold($id) |
124 | { |
125 | // Get Holdings Data |
126 | if ($this->catalog) { |
127 | $mode = $this->catalog->getTitleHoldsMode(); |
128 | if ($mode == 'disabled') { |
129 | return false; |
130 | } elseif ($mode == 'driver') { |
131 | try { |
132 | $patron = $this->ilsAuth->storedCatalogLogin(); |
133 | if (!$patron) { |
134 | return false; |
135 | } |
136 | return $this->driverHold($id, $patron); |
137 | } catch (ILSException $e) { |
138 | return false; |
139 | } |
140 | } else { |
141 | try { |
142 | $patron = $this->ilsAuth->storedCatalogLogin(); |
143 | } catch (ILSException $e) { |
144 | $patron = false; |
145 | } |
146 | $mode = $this->checkOverrideMode($id, $mode); |
147 | return $this->generateHold($id, $mode, $patron); |
148 | } |
149 | } |
150 | return false; |
151 | } |
152 | |
153 | /** |
154 | * Get holdings for a particular record. |
155 | * |
156 | * @param string $id ID to retrieve |
157 | * |
158 | * @return array |
159 | */ |
160 | protected function getHoldings($id) |
161 | { |
162 | // Cache results in a static array since the same holdings may be requested |
163 | // multiple times during a run through the class: |
164 | static $holdings = []; |
165 | |
166 | if (!isset($holdings[$id])) { |
167 | $holdings[$id] = $this->catalog->getHolding($id)['holdings']; |
168 | } |
169 | return $holdings[$id]; |
170 | } |
171 | |
172 | /** |
173 | * Support method for getHold to determine if we should override the configured |
174 | * holds mode. |
175 | * |
176 | * @param string $id Record ID to check |
177 | * @param string $mode Current mode |
178 | * |
179 | * @return string |
180 | */ |
181 | protected function checkOverrideMode($id, $mode) |
182 | { |
183 | if ( |
184 | isset($this->config->Catalog->allow_holds_override) |
185 | && $this->config->Catalog->allow_holds_override |
186 | ) { |
187 | $holdings = $this->getHoldings($id); |
188 | |
189 | // For title holds, the most important override feature to handle |
190 | // is to prevent displaying a link if all items are disabled. We |
191 | // may eventually want to address other scenarios as well. |
192 | $allDisabled = true; |
193 | foreach ($holdings as $holding) { |
194 | if ( |
195 | !isset($holding['holdOverride']) |
196 | || 'disabled' != $holding['holdOverride'] |
197 | ) { |
198 | $allDisabled = false; |
199 | } |
200 | } |
201 | $mode = (true == $allDisabled) ? 'disabled' : $mode; |
202 | } |
203 | return $mode; |
204 | } |
205 | |
206 | /** |
207 | * Protected method for driver defined title holds |
208 | * |
209 | * @param string $id A Bib ID |
210 | * @param array $patron An Array of patron data |
211 | * |
212 | * @return mixed A url on success, boolean false on failure |
213 | */ |
214 | protected function driverHold($id, $patron) |
215 | { |
216 | // Get Hold Details |
217 | $checkHolds = $this->catalog->checkFunction( |
218 | 'Holds', |
219 | compact('id', 'patron') |
220 | ); |
221 | |
222 | if (isset($checkHolds['HMACKeys'])) { |
223 | $data = ['id' => $id, 'level' => 'title']; |
224 | $result = $this->catalog->checkRequestIsValid($id, $data, $patron); |
225 | if ( |
226 | (is_array($result) && $result['valid']) |
227 | || (is_bool($result) && $result) |
228 | ) { |
229 | return $this->getHoldDetails($data, $checkHolds['HMACKeys']); |
230 | } |
231 | } |
232 | return false; |
233 | } |
234 | |
235 | /** |
236 | * Protected method for vufind (i.e. User) defined holds |
237 | * |
238 | * @param string $id A Bib ID |
239 | * @param string $type The holds mode to be applied from: |
240 | * (disabled, always, availability, driver) |
241 | * @param array $patron Patron |
242 | * |
243 | * @return mixed A url on success, boolean false on failure |
244 | */ |
245 | protected function generateHold($id, $type, $patron) |
246 | { |
247 | $any_available = false; |
248 | $addlink = false; |
249 | |
250 | $data = [ |
251 | 'id' => $id, |
252 | 'level' => 'title', |
253 | ]; |
254 | |
255 | // Are holds allows? |
256 | $checkHolds = $this->catalog->checkFunction( |
257 | 'Holds', |
258 | compact('id', 'patron') |
259 | ); |
260 | |
261 | if ($checkHolds != false) { |
262 | if ($type == 'always') { |
263 | $addlink = true; |
264 | } elseif ($type == 'availability') { |
265 | $holdings = $this->getHoldings($id); |
266 | foreach ($holdings as $holding) { |
267 | if ( |
268 | $holding['availability']->isAvailable() |
269 | && !in_array($holding['location'], $this->hideHoldings) |
270 | ) { |
271 | $any_available = true; |
272 | } |
273 | } |
274 | $addlink = !$any_available; |
275 | } |
276 | |
277 | if ($addlink) { |
278 | if ($checkHolds['function'] == 'getHoldLink') { |
279 | // Return opac link |
280 | return $this->catalog->getHoldLink($id, $data); |
281 | } else { |
282 | // Return non-opac link |
283 | return $this->getHoldDetails($data, $checkHolds['HMACKeys']); |
284 | } |
285 | } |
286 | } |
287 | return false; |
288 | } |
289 | |
290 | /** |
291 | * Get Hold Link |
292 | * |
293 | * Supplies the form details required to place a hold |
294 | * |
295 | * @param array $data An array of item data |
296 | * @param array $HMACKeys An array of keys to hash |
297 | * |
298 | * @return array Details for generating URL |
299 | */ |
300 | protected function getHoldDetails($data, $HMACKeys) |
301 | { |
302 | // Generate HMAC |
303 | $HMACkey = $this->hmac->generate($HMACKeys, $data); |
304 | |
305 | // Add Params |
306 | $queryString = []; |
307 | foreach ($data as $key => $param) { |
308 | $needle = in_array($key, $HMACKeys); |
309 | if ($needle) { |
310 | $queryString[] = $key . '=' . urlencode($param); |
311 | } |
312 | } |
313 | |
314 | // Add HMAC |
315 | $queryString[] = 'hashKey=' . urlencode($HMACkey); |
316 | $queryString = implode('&', $queryString); |
317 | |
318 | // Build Params |
319 | return [ |
320 | 'action' => 'Hold', 'record' => $data['id'], 'query' => $queryString, |
321 | 'anchor' => '#tabnav', |
322 | ]; |
323 | } |
324 | } |