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