Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
31.32% |
88 / 281 |
|
44.44% |
8 / 18 |
CRAP | |
0.00% |
0 / 1 |
Backend | |
31.32% |
88 / 281 |
|
44.44% |
8 / 18 |
2655.45 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
1 | |||
search | |
47.69% |
31 / 65 |
|
0.00% |
0 / 1 |
37.19 | |||
retrieve | |
44.93% |
31 / 69 |
|
0.00% |
0 / 1 |
79.30 | |||
paramBagToEBSCOSearchModel | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
getRecordCollectionFactory | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getQueryBuilder | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
setQueryBuilder | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
autocomplete | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
createRecordCollection | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getAuthenticationToken | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
72 | |||
getAutocompleteData | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
156 | |||
getSessionToken | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
20 | |||
createEBSCOSession | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
isGuest | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
createSession | |
0.00% |
0 / 22 |
|
0.00% |
0 / 1 |
20 | |||
getInfo | |
0.00% |
0 / 31 |
|
0.00% |
0 / 1 |
182 | |||
setAuthManager | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setBackendType | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | /** |
4 | * EDS API Backend |
5 | * |
6 | * PHP version 8 |
7 | * |
8 | * Copyright (C) EBSCO Industries 2013 |
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 Search |
25 | * @author Michelle Milton <mmilton@epnet.com> |
26 | * @author Cornelius Amzar <cornelius.amzar@bsz-bw.de> |
27 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
28 | * @link https://vufind.org |
29 | */ |
30 | |
31 | namespace VuFindSearch\Backend\EDS; |
32 | |
33 | use Exception; |
34 | use Laminas\Cache\Storage\StorageInterface as CacheAdapter; |
35 | use Laminas\Config\Config; |
36 | use Laminas\Session\Container as SessionContainer; |
37 | use VuFind\Config\Feature\SecretTrait; |
38 | use VuFindSearch\Backend\AbstractBackend; |
39 | use VuFindSearch\Backend\Exception\BackendException; |
40 | use VuFindSearch\ParamBag; |
41 | use VuFindSearch\Query\AbstractQuery; |
42 | use VuFindSearch\Response\RecordCollectionFactoryInterface; |
43 | use VuFindSearch\Response\RecordCollectionInterface; |
44 | |
45 | use function in_array; |
46 | |
47 | /** |
48 | * EDS API Backend |
49 | * |
50 | * @category VuFind |
51 | * @package Search |
52 | * @author Michelle Milton <mmilton@epnet.com> |
53 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
54 | * @link https://vufind.org |
55 | */ |
56 | class Backend extends AbstractBackend |
57 | { |
58 | use SecretTrait; |
59 | |
60 | /** |
61 | * Client user to make the actually requests to the EdsApi |
62 | * |
63 | * @var Connector |
64 | */ |
65 | protected $client; |
66 | |
67 | /** |
68 | * Query builder |
69 | * |
70 | * @var QueryBuilder |
71 | */ |
72 | protected $queryBuilder; |
73 | |
74 | /** |
75 | * User name for EBSCO EDS API account if using UID Authentication |
76 | * |
77 | * @var string |
78 | */ |
79 | protected $userName; |
80 | |
81 | /** |
82 | * Password for EBSCO EDS API account if using UID Authentication |
83 | * |
84 | * @var string |
85 | */ |
86 | protected $password; |
87 | |
88 | /** |
89 | * Profile for EBSCO EDS API account (may be overridden) |
90 | * |
91 | * @var string |
92 | */ |
93 | protected $profile; |
94 | |
95 | /** |
96 | * Default profile for EBSCO EDS API account (taken from initial config and |
97 | * never changed) |
98 | * |
99 | * @var string |
100 | */ |
101 | protected $defaultProfile; |
102 | |
103 | /** |
104 | * Whether or not to use IP Authentication for communication with the EDS API |
105 | * |
106 | * @var bool |
107 | */ |
108 | protected $ipAuth; |
109 | |
110 | /** |
111 | * Organization EDS API requests are being made for |
112 | * |
113 | * @var string |
114 | */ |
115 | protected $orgId; |
116 | |
117 | /** |
118 | * VuFind Authentication manager |
119 | * |
120 | * @var \VuFind\Auth\Manager |
121 | */ |
122 | protected $authManager = null; |
123 | |
124 | /** |
125 | * Object cache (for storing authentication tokens) |
126 | * |
127 | * @var CacheAdapter |
128 | */ |
129 | protected $cache; |
130 | |
131 | /** |
132 | * Session container |
133 | * |
134 | * @var SessionContainer |
135 | */ |
136 | protected $session; |
137 | |
138 | /** |
139 | * Is the current user a guest? |
140 | * |
141 | * @var bool |
142 | */ |
143 | protected $isGuest; |
144 | |
145 | /** |
146 | * Backend type |
147 | * |
148 | * @var string |
149 | */ |
150 | protected $backendType = null; |
151 | |
152 | /** |
153 | * Constructor. |
154 | * |
155 | * @param Connector $client EdsApi client to use |
156 | * @param RecordCollectionFactoryInterface $factory Record collection factory |
157 | * @param CacheAdapter $cache Object cache |
158 | * @param SessionContainer $session Session container |
159 | * @param Config $config Object representing EDS.ini |
160 | * @param bool $isGuest Is the current user a guest? |
161 | */ |
162 | public function __construct( |
163 | Connector $client, |
164 | RecordCollectionFactoryInterface $factory, |
165 | CacheAdapter $cache, |
166 | SessionContainer $session, |
167 | Config $config = null, |
168 | $isGuest = true |
169 | ) { |
170 | // Save dependencies/incoming parameters: |
171 | $this->client = $client; |
172 | $this->setRecordCollectionFactory($factory); |
173 | $this->cache = $cache; |
174 | $this->session = $session; |
175 | $this->isGuest = $isGuest; |
176 | |
177 | // Extract key values from configuration: |
178 | $this->userName = $config->EBSCO_Account->user_name ?? null; |
179 | $this->password = $this->getSecretFromConfig($config->EBSCO_Account, 'password'); |
180 | $this->ipAuth = $config->EBSCO_Account->ip_auth ?? false; |
181 | $this->profile = $config->EBSCO_Account->profile ?? null; |
182 | $this->orgId = $config->EBSCO_Account->organization_id ?? null; |
183 | |
184 | // Save default profile value, since profile property may be overridden: |
185 | $this->defaultProfile = $this->profile; |
186 | } |
187 | |
188 | /** |
189 | * Perform a search and return record collection. |
190 | * |
191 | * @param AbstractQuery $query Search query |
192 | * @param int $offset Search offset |
193 | * @param int $limit Search limit |
194 | * @param ParamBag $params Search backend parameters |
195 | * |
196 | * @return \VuFindSearch\Response\RecordCollectionInterface |
197 | **/ |
198 | public function search( |
199 | AbstractQuery $query, |
200 | $offset, |
201 | $limit, |
202 | ParamBag $params = null |
203 | ) { |
204 | // process EDS API communication tokens. |
205 | $authenticationToken = $this->getAuthenticationToken(); |
206 | $sessionToken = $this->getSessionToken(); |
207 | $this->debug( |
208 | "Authentication Token: $authenticationToken, SessionToken: $sessionToken" |
209 | ); |
210 | |
211 | // create query parameters from VuFind data |
212 | $queryString = $query->getAllTerms(); |
213 | $paramsStr = implode('&', null !== $params ? $params->request() : []); |
214 | $this->debug( |
215 | "Query: $queryString, Limit: $limit, Offset: $offset, " |
216 | . "Params: $paramsStr" |
217 | ); |
218 | |
219 | $baseParams = $this->getQueryBuilder()->build($query); |
220 | $paramsStr = implode('&', $baseParams->request()); |
221 | $this->debug("BaseParams: $paramsStr "); |
222 | if (null !== $params) { |
223 | $baseParams->mergeWith($params); |
224 | } |
225 | $baseParams->set('resultsPerPage', $limit); |
226 | $page = $limit > 0 ? floor($offset / $limit) + 1 : 1; |
227 | $baseParams->set('pageNumber', $page); |
228 | |
229 | $searchModel = $this->paramBagToEBSCOSearchModel($baseParams); |
230 | $qs = $searchModel->convertToQueryString(); |
231 | $this->debug("Search Model query string: $qs"); |
232 | try { |
233 | $response = $this->client |
234 | ->search($searchModel, $authenticationToken, $sessionToken); |
235 | } catch (ApiException $e) { |
236 | // if the auth or session token was invalid, try once more |
237 | switch ($e->getApiErrorCode()) { |
238 | case 104: |
239 | case 108: |
240 | case 109: |
241 | try { |
242 | // For error 104, retry auth token; for 108/9, retry sess |
243 | // token: |
244 | if ($e->getApiErrorCode() == 104) { |
245 | $authenticationToken |
246 | = $this->getAuthenticationToken(true); |
247 | } else { |
248 | $sessionToken = $this->getSessionToken(true); |
249 | } |
250 | $response = $this->client->search( |
251 | $searchModel, |
252 | $authenticationToken, |
253 | $sessionToken |
254 | ); |
255 | } catch (Exception $e) { |
256 | throw new BackendException( |
257 | $e->getMessage(), |
258 | $e->getCode(), |
259 | $e |
260 | ); |
261 | } |
262 | break; |
263 | case 138: |
264 | // User requested unavailable deep search results; first extract |
265 | // the next legal position from the error message: |
266 | $parts |
267 | = explode(' ', trim($e->getApiDetailedErrorDescription())); |
268 | $legalPos = array_pop($parts); |
269 | // Now calculate the legal page number and throw an exception so |
270 | // the controller can fix it from here: |
271 | $legalPage = floor($legalPos / $limit); |
272 | throw new \VuFindSearch\Backend\Exception\DeepPagingException( |
273 | $e->getMessage(), |
274 | $e->getCode(), |
275 | $legalPage, |
276 | $e |
277 | ); |
278 | default: |
279 | $errorMessage = "Unhandled EDS API error {$e->getApiErrorCode()} : {$e->getMessage()}"; |
280 | $this->logError($errorMessage); |
281 | throw new BackendException($errorMessage, $e->getCode(), $e); |
282 | } |
283 | } catch (Exception $e) { |
284 | $this->debug('Exception found: ' . $e->getMessage()); |
285 | throw new BackendException($e->getMessage(), $e->getCode(), $e); |
286 | } |
287 | $collection = $this->createRecordCollection($response); |
288 | $this->injectSourceIdentifier($collection); |
289 | return $collection; |
290 | } |
291 | |
292 | /** |
293 | * Retrieve a single document. |
294 | * |
295 | * @param string $id Document identifier |
296 | * @param ParamBag $params Search backend parameters |
297 | * |
298 | * @return \VuFindSearch\Response\RecordCollectionInterface |
299 | */ |
300 | public function retrieve($id, ParamBag $params = null) |
301 | { |
302 | $an = $dbId = $authenticationToken = $sessionToken = $hlTerms = null; |
303 | try { |
304 | $authenticationToken = $this->getAuthenticationToken(); |
305 | // check to see if the profile is overridden |
306 | $overrideProfile = (null !== $params) ? $params->get('profile') : null; |
307 | if (isset($overrideProfile)) { |
308 | $this->profile = $overrideProfile; |
309 | } |
310 | $sessionToken = $this->getSessionToken(); |
311 | |
312 | if ('EDS' === $this->backendType) { |
313 | $parts = explode(',', $id, 2); |
314 | if (!isset($parts[1])) { |
315 | throw new BackendException( |
316 | 'Retrieval id is not in the correct format.' |
317 | ); |
318 | } |
319 | [$dbId, $an] = $parts; |
320 | $hlTerms = (null !== $params) |
321 | ? $params->get('highlightterms') : null; |
322 | $extras = []; |
323 | if ( |
324 | null !== $params |
325 | && ($eBookFormat = $params->get('ebookpreferredformat')) |
326 | ) { |
327 | $extras['ebookpreferredformat'] = $eBookFormat; |
328 | } |
329 | $response = $this->client->retrieveEdsItem( |
330 | $an, |
331 | $dbId, |
332 | $authenticationToken, |
333 | $sessionToken, |
334 | $hlTerms, |
335 | $extras |
336 | ); |
337 | } elseif ('EPF' === $this->backendType) { |
338 | $pubId = $id; |
339 | $response = $this->client->retrieveEpfItem( |
340 | $pubId, |
341 | $authenticationToken, |
342 | $sessionToken |
343 | ); |
344 | } else { |
345 | throw new BackendException( |
346 | 'Unknown backendType: ' . $this->backendType |
347 | ); |
348 | } |
349 | } catch (ApiException $e) { |
350 | // Error codes can be reviewed at |
351 | // https://connect.ebsco.com/s/article |
352 | // /EBSCO-Discovery-Service-API-Reference-Guide-Error-Codes |
353 | // if the auth or session token was invalid, try once more |
354 | switch ($e->getApiErrorCode()) { |
355 | case 104: |
356 | case 108: |
357 | case 109: |
358 | try { |
359 | // For error 104, retry auth token; for 108/9, retry sess |
360 | // token: |
361 | if ($e->getApiErrorCode() == 104) { |
362 | $authenticationToken |
363 | = $this->getAuthenticationToken(true); |
364 | } else { |
365 | $sessionToken = $this->getSessionToken(true); |
366 | } |
367 | $response = $this->client->retrieve( |
368 | $an, |
369 | $dbId, |
370 | $authenticationToken, |
371 | $sessionToken, |
372 | $hlTerms |
373 | ); |
374 | } catch (Exception $e) { |
375 | throw new BackendException( |
376 | $e->getMessage(), |
377 | $e->getCode(), |
378 | $e |
379 | ); |
380 | } |
381 | break; |
382 | case 132: |
383 | case 133: |
384 | case 135: |
385 | /* 132 Record not found |
386 | * 133 Simultaneous User Limit Reached |
387 | * 135 DbId not in profile |
388 | * -> fall through to treat as "record not found" |
389 | */ |
390 | $response = []; |
391 | break; |
392 | default: |
393 | throw $e; |
394 | } |
395 | } |
396 | $collection = $this->createRecordCollection(['Records' => $response]); |
397 | $this->injectSourceIdentifier($collection); |
398 | return $collection; |
399 | } |
400 | |
401 | /** |
402 | * Convert a ParamBag to a EdsApi Search request object. |
403 | * |
404 | * @param ParamBag $params ParamBag to convert |
405 | * |
406 | * @return SearchRequestModel |
407 | */ |
408 | protected function paramBagToEBSCOSearchModel(ParamBag $params) |
409 | { |
410 | $params = $params->getArrayCopy(); |
411 | $options = []; |
412 | // Most parameters need to be flattened from array format, but a few |
413 | // should remain as arrays: |
414 | $arraySettings = [ |
415 | 'query', 'facets', 'filters', 'groupFilters', 'rangeFilters', 'limiters', |
416 | ]; |
417 | foreach ($params as $key => $param) { |
418 | $options[$key] = in_array($key, $arraySettings) |
419 | ? $param : $param[0]; |
420 | } |
421 | return new SearchRequestModel($options); |
422 | } |
423 | |
424 | /** |
425 | * Return the record collection factory. |
426 | * |
427 | * Lazy loads a generic collection factory. |
428 | * |
429 | * @return RecordCollectionFactoryInterface |
430 | */ |
431 | public function getRecordCollectionFactory() |
432 | { |
433 | return $this->collectionFactory; |
434 | } |
435 | |
436 | /** |
437 | * Return query builder. |
438 | * |
439 | * Lazy loads an empty QueryBuilder if none was set. |
440 | * |
441 | * @return QueryBuilder |
442 | */ |
443 | public function getQueryBuilder() |
444 | { |
445 | if (!$this->queryBuilder) { |
446 | $this->queryBuilder = new QueryBuilder(); |
447 | } |
448 | return $this->queryBuilder; |
449 | } |
450 | |
451 | /** |
452 | * Set the query builder. |
453 | * |
454 | * @param QueryBuilder $queryBuilder Query builder |
455 | * |
456 | * @return void |
457 | */ |
458 | public function setQueryBuilder(QueryBuilder $queryBuilder) |
459 | { |
460 | $this->queryBuilder = $queryBuilder; |
461 | } |
462 | |
463 | /** |
464 | * Get popular terms using the autocomplete API. |
465 | * |
466 | * @param string $query Simple query string |
467 | * @param string $domain Autocomplete type (e.g. 'rawqueries' or 'holdings') |
468 | * |
469 | * @return array of terms |
470 | */ |
471 | public function autocomplete($query, $domain = 'rawqueries') |
472 | { |
473 | return $this->client |
474 | ->autocomplete($query, $domain, $this->getAutocompleteData()); |
475 | } |
476 | |
477 | /// Internal API |
478 | |
479 | /** |
480 | * Create record collection. |
481 | * |
482 | * @param array $records Records to process |
483 | * |
484 | * @return RecordCollectionInterface |
485 | */ |
486 | protected function createRecordCollection($records) |
487 | { |
488 | return $this->getRecordCollectionFactory()->factory($records); |
489 | } |
490 | |
491 | /** |
492 | * Obtain the authentication to use with the EDS API from cache if it exists. If |
493 | * not, then generate a new one. |
494 | * |
495 | * @param bool $isInvalid whether or not the the current token is invalid |
496 | * |
497 | * @return string |
498 | */ |
499 | protected function getAuthenticationToken($isInvalid = false) |
500 | { |
501 | $token = null; |
502 | if ($this->ipAuth) { |
503 | return $token; |
504 | } |
505 | if ($isInvalid) { |
506 | $this->cache->setItem('edsAuthenticationToken', null); |
507 | } |
508 | $authTokenData = $this->cache->getItem('edsAuthenticationToken'); |
509 | if (isset($authTokenData)) { |
510 | $currentToken = $authTokenData['token'] ?? ''; |
511 | $expirationTime = $authTokenData['expiration'] ?? 0; |
512 | $this->debug( |
513 | 'Cached Authentication data: ' |
514 | . "$currentToken, expiration time: $expirationTime" |
515 | ); |
516 | |
517 | // Check to see if the token expiration time is greater than the current |
518 | // time. If the token is expired or within 5 minutes of expiring, |
519 | // generate a new one. |
520 | if (!empty($currentToken) && (time() <= ($expirationTime - (60 * 5)))) { |
521 | return $currentToken; |
522 | } |
523 | } |
524 | |
525 | $username = $this->userName; |
526 | $password = $this->password; |
527 | $orgId = $this->orgId; |
528 | if (!empty($username) && !empty($password)) { |
529 | $this->debug( |
530 | 'Calling Authenticate with username: ' |
531 | . "$username, password: XXXXXXXX, orgid: $orgId " |
532 | ); |
533 | $results = $this->client->authenticate($username, $password, $orgId); |
534 | $token = $results['AuthToken']; |
535 | $timeout = $results['AuthTimeout'] + time(); |
536 | $authTokenData = ['token' => $token, 'expiration' => $timeout]; |
537 | $this->cache->setItem('edsAuthenticationToken', $authTokenData); |
538 | } |
539 | return $token; |
540 | } |
541 | |
542 | /** |
543 | * Obtain the autocomplete authentication to use with the EDS API from cache |
544 | * if it exists. If not, then generate a new set. |
545 | * |
546 | * @param bool $isInvalid whether or not the the current autocomplete data |
547 | * is invalid and should be regenerated |
548 | * |
549 | * @return array autocomplete data |
550 | */ |
551 | protected function getAutocompleteData($isInvalid = false) |
552 | { |
553 | // Autocomplete is currently unsupported with IP authentication |
554 | if ($this->ipAuth) { |
555 | return null; |
556 | } |
557 | if ($isInvalid) { |
558 | $this->cache->setItem('edsAutocomplete', null); |
559 | } |
560 | $autocompleteData = $this->cache->getItem('edsAutocomplete'); |
561 | if (!empty($autocompleteData)) { |
562 | $currentToken = $autocompleteData['token'] ?? ''; |
563 | $expirationTime = $autocompleteData['expiration'] ?? 0; |
564 | |
565 | // Check to see if the token expiration time is greater than the current |
566 | // time. If the token is expired or within 5 minutes of expiring, |
567 | // generate a new one. |
568 | if (!empty($currentToken) && (time() <= ($expirationTime - (60 * 5)))) { |
569 | return $autocompleteData; |
570 | } |
571 | } |
572 | |
573 | $username = $this->userName; |
574 | $password = $this->password; |
575 | if (!empty($username) && !empty($password)) { |
576 | $results = $this->client |
577 | ->authenticate($username, $password, $this->orgId, ['autocomplete']); |
578 | $autoresult = $results['Autocomplete'] ?? []; |
579 | if ( |
580 | isset($autoresult['Token']) && isset($autoresult['TokenTimeOut']) |
581 | && isset($autoresult['CustId']) && isset($autoresult['Url']) |
582 | ) { |
583 | $token = $autoresult['Token']; |
584 | $expiration = $autoresult['TokenTimeOut'] + time(); |
585 | $custid = $autoresult['CustId']; |
586 | $url = $autoresult['Url']; |
587 | |
588 | $autocompleteData = compact('token', 'expiration', 'url', 'custid'); |
589 | // store token, expiration, url and custid in cache. |
590 | $this->cache->setItem('edsAutocomplete', $autocompleteData); |
591 | } |
592 | } |
593 | return $autocompleteData; |
594 | } |
595 | |
596 | /** |
597 | * Obtain the session token from the Session container. If it doesn't exist, |
598 | * generate a new one. |
599 | * |
600 | * @param bool $isInvalid If a session token is invalid, generate a new one |
601 | * regardless of what is in the session container |
602 | * |
603 | * @return string |
604 | */ |
605 | public function getSessionToken($isInvalid = false) |
606 | { |
607 | // check to see if the user has logged in/out between the creation |
608 | // of this session token and now |
609 | if ( |
610 | !$isInvalid && !empty($this->session->sessionID) |
611 | && $this->session->sessionGuest == $this->isGuest() |
612 | ) { |
613 | return $this->session->sessionID; |
614 | } |
615 | return $this->createEBSCOSession(); |
616 | } |
617 | |
618 | /** |
619 | * Generate a new session token and store it in the Session container. |
620 | * |
621 | * @return string |
622 | */ |
623 | protected function createEBSCOSession() |
624 | { |
625 | // if there is no profile passed, restore the default from the config file |
626 | $this->session->profileID = (null == $this->profile) |
627 | ? $this->defaultProfile : $this->profile; |
628 | $this->session->sessionGuest = $this->isGuest(); |
629 | $this->session->sessionID = $this->createSession( |
630 | $this->session->sessionGuest, |
631 | $this->session->profileID |
632 | ); |
633 | return $this->session->sessionID; |
634 | } |
635 | |
636 | /** |
637 | * Is the current user a guest? If so, return 'y' else 'n'. |
638 | * |
639 | * @return string |
640 | */ |
641 | protected function isGuest() |
642 | { |
643 | return $this->isGuest ? 'y' : 'n'; |
644 | } |
645 | |
646 | /** |
647 | * Obtain the session to use with the EDS API from cache if it exists. If not, |
648 | * then generate a new one. |
649 | * |
650 | * @param bool $isGuest Whether or not this session will be a guest session |
651 | * @param string $profile Authentication to use for generating a new session |
652 | * if necessary |
653 | * |
654 | * @return string |
655 | */ |
656 | public function createSession($isGuest, $profile = '') |
657 | { |
658 | try { |
659 | $authToken = $this->getAuthenticationToken(); |
660 | $results = $this->client->createSession($profile, $isGuest, $authToken); |
661 | } catch (ApiException $e) { |
662 | $errorCode = $e->getApiErrorCode(); |
663 | $desc = $e->getApiErrorDescription(); |
664 | $this->debug( |
665 | 'Error in create session request. Error code: ' |
666 | . "$errorCode, message: $desc, e: $e" |
667 | ); |
668 | if ($e->getApiErrorCode() == 104) { |
669 | try { |
670 | $authToken = $this->getAuthenticationToken(true); |
671 | $results = $this->client |
672 | ->createSession($this->profile, $isGuest, $authToken); |
673 | } catch (Exception $e) { |
674 | throw new BackendException( |
675 | $e->getMessage(), |
676 | $e->getCode(), |
677 | $e |
678 | ); |
679 | } |
680 | } else { |
681 | throw $e; |
682 | } |
683 | } |
684 | $sessionToken = $results['SessionToken']; |
685 | return $sessionToken; |
686 | } |
687 | |
688 | /** |
689 | * Obtain data from the INFO method |
690 | * |
691 | * @param string $sessionToken Session token (optional) |
692 | * |
693 | * @return array |
694 | */ |
695 | public function getInfo($sessionToken = null) |
696 | { |
697 | // Use a different cache key for guests, just in case info differs: |
698 | $cacheKey = $this->isGuest ? 'edsGuestInfo' : 'edsLoggedInInfo'; |
699 | if ($data = $this->cache->getItem($cacheKey)) { |
700 | return $data; |
701 | } |
702 | $authenticationToken = $this->getAuthenticationToken(); |
703 | if (null == $sessionToken) { |
704 | try { |
705 | $sessionToken = $this->getSessionToken(); |
706 | } catch (ApiException $e) { |
707 | // Retry once to work around occasional 106 errors: |
708 | $sessionToken = $this->getSessionToken(); |
709 | } |
710 | } |
711 | try { |
712 | $response = $this->client->info($authenticationToken, $sessionToken); |
713 | } catch (ApiException $e) { |
714 | // if the auth or session token was invalid, try once more |
715 | switch ($e->getApiErrorCode()) { |
716 | case 104: |
717 | case 108: |
718 | case 109: |
719 | try { |
720 | // For error 104, retry auth token; for 108/9, retry sess |
721 | // token: |
722 | if ($e->getApiErrorCode() == 104) { |
723 | $authenticationToken |
724 | = $this->getAuthenticationToken(true); |
725 | } else { |
726 | $sessionToken = $this->getSessionToken(true); |
727 | } |
728 | $response = $this->client |
729 | ->info($authenticationToken, $sessionToken); |
730 | } catch (Exception $e) { |
731 | throw new BackendException( |
732 | $e->getMessage(), |
733 | $e->getCode(), |
734 | $e |
735 | ); |
736 | } |
737 | break; |
738 | default: |
739 | $response = []; |
740 | } |
741 | } |
742 | if (!empty($response)) { |
743 | $this->cache->setItem($cacheKey, $response); |
744 | } |
745 | return $response; |
746 | } |
747 | |
748 | /** |
749 | * Set the VuFind Authentication Manager |
750 | * |
751 | * @param \VuFind\Auth\Manager $authManager Authentication Manager |
752 | * |
753 | * @return void |
754 | */ |
755 | public function setAuthManager($authManager) |
756 | { |
757 | $this->authManager = $authManager; |
758 | } |
759 | |
760 | /** |
761 | * Set the EBSCO backend type. Backend/EDS is used for both EDS and EPF. |
762 | * |
763 | * @param string $backendType 'EDS' or 'EPF' |
764 | * |
765 | * @return void |
766 | */ |
767 | public function setBackendType($backendType) |
768 | { |
769 | $this->backendType = $backendType; |
770 | } |
771 | } |