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 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 | $errorMessage = "Unhandled EDS API error {$e->getApiErrorCode()} : {$e->getMessage()}"; |
277 | $this->logError($errorMessage); |
278 | throw new BackendException($errorMessage, $e->getCode(), $e); |
279 | } |
280 | } catch (Exception $e) { |
281 | $this->debug('Exception found: ' . $e->getMessage()); |
282 | throw new BackendException($e->getMessage(), $e->getCode(), $e); |
283 | } |
284 | $collection = $this->createRecordCollection($response); |
285 | $this->injectSourceIdentifier($collection); |
286 | return $collection; |
287 | } |
288 | |
289 | /** |
290 | * Retrieve a single document. |
291 | * |
292 | * @param string $id Document identifier |
293 | * @param ParamBag $params Search backend parameters |
294 | * |
295 | * @return \VuFindSearch\Response\RecordCollectionInterface |
296 | */ |
297 | public function retrieve($id, ParamBag $params = null) |
298 | { |
299 | $an = $dbId = $authenticationToken = $sessionToken = $hlTerms = null; |
300 | try { |
301 | $authenticationToken = $this->getAuthenticationToken(); |
302 | // check to see if the profile is overridden |
303 | $overrideProfile = (null !== $params) ? $params->get('profile') : null; |
304 | if (isset($overrideProfile)) { |
305 | $this->profile = $overrideProfile; |
306 | } |
307 | $sessionToken = $this->getSessionToken(); |
308 | |
309 | if ('EDS' === $this->backendType) { |
310 | $parts = explode(',', $id, 2); |
311 | if (!isset($parts[1])) { |
312 | throw new BackendException( |
313 | 'Retrieval id is not in the correct format.' |
314 | ); |
315 | } |
316 | [$dbId, $an] = $parts; |
317 | $hlTerms = (null !== $params) |
318 | ? $params->get('highlightterms') : null; |
319 | $extras = []; |
320 | if ( |
321 | null !== $params |
322 | && ($eBookFormat = $params->get('ebookpreferredformat')) |
323 | ) { |
324 | $extras['ebookpreferredformat'] = $eBookFormat; |
325 | } |
326 | $response = $this->client->retrieveEdsItem( |
327 | $an, |
328 | $dbId, |
329 | $authenticationToken, |
330 | $sessionToken, |
331 | $hlTerms, |
332 | $extras |
333 | ); |
334 | } elseif ('EPF' === $this->backendType) { |
335 | $pubId = $id; |
336 | $response = $this->client->retrieveEpfItem( |
337 | $pubId, |
338 | $authenticationToken, |
339 | $sessionToken |
340 | ); |
341 | } else { |
342 | throw new BackendException( |
343 | 'Unknown backendType: ' . $this->backendType |
344 | ); |
345 | } |
346 | } catch (ApiException $e) { |
347 | // Error codes can be reviewed at |
348 | // https://connect.ebsco.com/s/article |
349 | // /EBSCO-Discovery-Service-API-Reference-Guide-Error-Codes |
350 | // if the auth or session token was invalid, try once more |
351 | switch ($e->getApiErrorCode()) { |
352 | case 104: |
353 | case 108: |
354 | case 109: |
355 | try { |
356 | // For error 104, retry auth token; for 108/9, retry sess |
357 | // token: |
358 | if ($e->getApiErrorCode() == 104) { |
359 | $authenticationToken |
360 | = $this->getAuthenticationToken(true); |
361 | } else { |
362 | $sessionToken = $this->getSessionToken(true); |
363 | } |
364 | $response = $this->client->retrieve( |
365 | $an, |
366 | $dbId, |
367 | $authenticationToken, |
368 | $sessionToken, |
369 | $hlTerms |
370 | ); |
371 | } catch (Exception $e) { |
372 | throw new BackendException( |
373 | $e->getMessage(), |
374 | $e->getCode(), |
375 | $e |
376 | ); |
377 | } |
378 | break; |
379 | case 132: |
380 | case 133: |
381 | case 135: |
382 | /* 132 Record not found |
383 | * 133 Simultaneous User Limit Reached |
384 | * 135 DbId not in profile |
385 | * -> fall through to treat as "record not found" |
386 | */ |
387 | $response = []; |
388 | break; |
389 | default: |
390 | throw $e; |
391 | } |
392 | } |
393 | $collection = $this->createRecordCollection(['Records' => $response]); |
394 | $this->injectSourceIdentifier($collection); |
395 | return $collection; |
396 | } |
397 | |
398 | /** |
399 | * Convert a ParamBag to a EdsApi Search request object. |
400 | * |
401 | * @param ParamBag $params ParamBag to convert |
402 | * |
403 | * @return SearchRequestModel |
404 | */ |
405 | protected function paramBagToEBSCOSearchModel(ParamBag $params) |
406 | { |
407 | $params = $params->getArrayCopy(); |
408 | $options = []; |
409 | // Most parameters need to be flattened from array format, but a few |
410 | // should remain as arrays: |
411 | $arraySettings = [ |
412 | 'query', 'facets', 'filters', 'groupFilters', 'rangeFilters', 'limiters', |
413 | ]; |
414 | foreach ($params as $key => $param) { |
415 | $options[$key] = in_array($key, $arraySettings) |
416 | ? $param : $param[0]; |
417 | } |
418 | return new SearchRequestModel($options); |
419 | } |
420 | |
421 | /** |
422 | * Return the record collection factory. |
423 | * |
424 | * Lazy loads a generic collection factory. |
425 | * |
426 | * @return RecordCollectionFactoryInterface |
427 | */ |
428 | public function getRecordCollectionFactory() |
429 | { |
430 | return $this->collectionFactory; |
431 | } |
432 | |
433 | /** |
434 | * Return query builder. |
435 | * |
436 | * Lazy loads an empty QueryBuilder if none was set. |
437 | * |
438 | * @return QueryBuilder |
439 | */ |
440 | public function getQueryBuilder() |
441 | { |
442 | if (!$this->queryBuilder) { |
443 | $this->queryBuilder = new QueryBuilder(); |
444 | } |
445 | return $this->queryBuilder; |
446 | } |
447 | |
448 | /** |
449 | * Set the query builder. |
450 | * |
451 | * @param QueryBuilder $queryBuilder Query builder |
452 | * |
453 | * @return void |
454 | */ |
455 | public function setQueryBuilder(QueryBuilder $queryBuilder) |
456 | { |
457 | $this->queryBuilder = $queryBuilder; |
458 | } |
459 | |
460 | /** |
461 | * Get popular terms using the autocomplete API. |
462 | * |
463 | * @param string $query Simple query string |
464 | * @param string $domain Autocomplete type (e.g. 'rawqueries' or 'holdings') |
465 | * |
466 | * @return array of terms |
467 | */ |
468 | public function autocomplete($query, $domain = 'rawqueries') |
469 | { |
470 | return $this->client |
471 | ->autocomplete($query, $domain, $this->getAutocompleteData()); |
472 | } |
473 | |
474 | /// Internal API |
475 | |
476 | /** |
477 | * Create record collection. |
478 | * |
479 | * @param array $records Records to process |
480 | * |
481 | * @return RecordCollectionInterface |
482 | */ |
483 | protected function createRecordCollection($records) |
484 | { |
485 | return $this->getRecordCollectionFactory()->factory($records); |
486 | } |
487 | |
488 | /** |
489 | * Obtain the authentication to use with the EDS API from cache if it exists. If |
490 | * not, then generate a new one. |
491 | * |
492 | * @param bool $isInvalid whether or not the the current token is invalid |
493 | * |
494 | * @return string |
495 | */ |
496 | protected function getAuthenticationToken($isInvalid = false) |
497 | { |
498 | $token = null; |
499 | if ($this->ipAuth) { |
500 | return $token; |
501 | } |
502 | if ($isInvalid) { |
503 | $this->cache->setItem('edsAuthenticationToken', null); |
504 | } |
505 | $authTokenData = $this->cache->getItem('edsAuthenticationToken'); |
506 | if (isset($authTokenData)) { |
507 | $currentToken = $authTokenData['token'] ?? ''; |
508 | $expirationTime = $authTokenData['expiration'] ?? 0; |
509 | $this->debug( |
510 | 'Cached Authentication data: ' |
511 | . "$currentToken, expiration time: $expirationTime" |
512 | ); |
513 | |
514 | // Check to see if the token expiration time is greater than the current |
515 | // time. If the token is expired or within 5 minutes of expiring, |
516 | // generate a new one. |
517 | if (!empty($currentToken) && (time() <= ($expirationTime - (60 * 5)))) { |
518 | return $currentToken; |
519 | } |
520 | } |
521 | |
522 | $username = $this->userName; |
523 | $password = $this->password; |
524 | $orgId = $this->orgId; |
525 | if (!empty($username) && !empty($password)) { |
526 | $this->debug( |
527 | 'Calling Authenticate with username: ' |
528 | . "$username, password: XXXXXXXX, orgid: $orgId " |
529 | ); |
530 | $results = $this->client->authenticate($username, $password, $orgId); |
531 | $token = $results['AuthToken']; |
532 | $timeout = $results['AuthTimeout'] + time(); |
533 | $authTokenData = ['token' => $token, 'expiration' => $timeout]; |
534 | $this->cache->setItem('edsAuthenticationToken', $authTokenData); |
535 | } |
536 | return $token; |
537 | } |
538 | |
539 | /** |
540 | * Obtain the autocomplete authentication to use with the EDS API from cache |
541 | * if it exists. If not, then generate a new set. |
542 | * |
543 | * @param bool $isInvalid whether or not the the current autocomplete data |
544 | * is invalid and should be regenerated |
545 | * |
546 | * @return array autocomplete data |
547 | */ |
548 | protected function getAutocompleteData($isInvalid = false) |
549 | { |
550 | // Autocomplete is currently unsupported with IP authentication |
551 | if ($this->ipAuth) { |
552 | return null; |
553 | } |
554 | if ($isInvalid) { |
555 | $this->cache->setItem('edsAutocomplete', null); |
556 | } |
557 | $autocompleteData = $this->cache->getItem('edsAutocomplete'); |
558 | if (!empty($autocompleteData)) { |
559 | $currentToken = $autocompleteData['token'] ?? ''; |
560 | $expirationTime = $autocompleteData['expiration'] ?? 0; |
561 | |
562 | // Check to see if the token expiration time is greater than the current |
563 | // time. If the token is expired or within 5 minutes of expiring, |
564 | // generate a new one. |
565 | if (!empty($currentToken) && (time() <= ($expirationTime - (60 * 5)))) { |
566 | return $autocompleteData; |
567 | } |
568 | } |
569 | |
570 | $username = $this->userName; |
571 | $password = $this->password; |
572 | if (!empty($username) && !empty($password)) { |
573 | $results = $this->client |
574 | ->authenticate($username, $password, $this->orgId, ['autocomplete']); |
575 | $autoresult = $results['Autocomplete'] ?? []; |
576 | if ( |
577 | isset($autoresult['Token']) && isset($autoresult['TokenTimeOut']) |
578 | && isset($autoresult['CustId']) && isset($autoresult['Url']) |
579 | ) { |
580 | $token = $autoresult['Token']; |
581 | $expiration = $autoresult['TokenTimeOut'] + time(); |
582 | $custid = $autoresult['CustId']; |
583 | $url = $autoresult['Url']; |
584 | |
585 | $autocompleteData = compact('token', 'expiration', 'url', 'custid'); |
586 | // store token, expiration, url and custid in cache. |
587 | $this->cache->setItem('edsAutocomplete', $autocompleteData); |
588 | } |
589 | } |
590 | return $autocompleteData; |
591 | } |
592 | |
593 | /** |
594 | * Obtain the session token from the Session container. If it doesn't exist, |
595 | * generate a new one. |
596 | * |
597 | * @param bool $isInvalid If a session token is invalid, generate a new one |
598 | * regardless of what is in the session container |
599 | * |
600 | * @return string |
601 | */ |
602 | public function getSessionToken($isInvalid = false) |
603 | { |
604 | // check to see if the user has logged in/out between the creation |
605 | // of this session token and now |
606 | if ( |
607 | !$isInvalid && !empty($this->session->sessionID) |
608 | && $this->session->sessionGuest == $this->isGuest() |
609 | ) { |
610 | return $this->session->sessionID; |
611 | } |
612 | return $this->createEBSCOSession(); |
613 | } |
614 | |
615 | /** |
616 | * Generate a new session token and store it in the Session container. |
617 | * |
618 | * @return string |
619 | */ |
620 | protected function createEBSCOSession() |
621 | { |
622 | // if there is no profile passed, restore the default from the config file |
623 | $this->session->profileID = (null == $this->profile) |
624 | ? $this->defaultProfile : $this->profile; |
625 | $this->session->sessionGuest = $this->isGuest(); |
626 | $this->session->sessionID = $this->createSession( |
627 | $this->session->sessionGuest, |
628 | $this->session->profileID |
629 | ); |
630 | return $this->session->sessionID; |
631 | } |
632 | |
633 | /** |
634 | * Is the current user a guest? If so, return 'y' else 'n'. |
635 | * |
636 | * @return string |
637 | */ |
638 | protected function isGuest() |
639 | { |
640 | return $this->isGuest ? 'y' : 'n'; |
641 | } |
642 | |
643 | /** |
644 | * Obtain the session to use with the EDS API from cache if it exists. If not, |
645 | * then generate a new one. |
646 | * |
647 | * @param bool $isGuest Whether or not this sesssion will be a guest session |
648 | * @param string $profile Authentication to use for generating a new session |
649 | * if necessary |
650 | * |
651 | * @return string |
652 | */ |
653 | public function createSession($isGuest, $profile = '') |
654 | { |
655 | try { |
656 | $authToken = $this->getAuthenticationToken(); |
657 | $results = $this->client->createSession($profile, $isGuest, $authToken); |
658 | } catch (ApiException $e) { |
659 | $errorCode = $e->getApiErrorCode(); |
660 | $desc = $e->getApiErrorDescription(); |
661 | $this->debug( |
662 | 'Error in create session request. Error code: ' |
663 | . "$errorCode, message: $desc, e: $e" |
664 | ); |
665 | if ($e->getApiErrorCode() == 104) { |
666 | try { |
667 | $authToken = $this->getAuthenticationToken(true); |
668 | $results = $this->client |
669 | ->createSession($this->profile, $isGuest, $authToken); |
670 | } catch (Exception $e) { |
671 | throw new BackendException( |
672 | $e->getMessage(), |
673 | $e->getCode(), |
674 | $e |
675 | ); |
676 | } |
677 | } else { |
678 | throw $e; |
679 | } |
680 | } |
681 | $sessionToken = $results['SessionToken']; |
682 | return $sessionToken; |
683 | } |
684 | |
685 | /** |
686 | * Obtain data from the INFO method |
687 | * |
688 | * @param string $sessionToken Session token (optional) |
689 | * |
690 | * @return array |
691 | */ |
692 | public function getInfo($sessionToken = null) |
693 | { |
694 | // Use a different cache key for guests, just in case info differs: |
695 | $cacheKey = $this->isGuest ? 'edsGuestInfo' : 'edsLoggedInInfo'; |
696 | if ($data = $this->cache->getItem($cacheKey)) { |
697 | return $data; |
698 | } |
699 | $authenticationToken = $this->getAuthenticationToken(); |
700 | if (null == $sessionToken) { |
701 | try { |
702 | $sessionToken = $this->getSessionToken(); |
703 | } catch (ApiException $e) { |
704 | // Retry once to work around occasional 106 errors: |
705 | $sessionToken = $this->getSessionToken(); |
706 | } |
707 | } |
708 | try { |
709 | $response = $this->client->info($authenticationToken, $sessionToken); |
710 | } catch (ApiException $e) { |
711 | // if the auth or session token was invalid, try once more |
712 | switch ($e->getApiErrorCode()) { |
713 | case 104: |
714 | case 108: |
715 | case 109: |
716 | try { |
717 | // For error 104, retry auth token; for 108/9, retry sess |
718 | // token: |
719 | if ($e->getApiErrorCode() == 104) { |
720 | $authenticationToken |
721 | = $this->getAuthenticationToken(true); |
722 | } else { |
723 | $sessionToken = $this->getSessionToken(true); |
724 | } |
725 | $response = $this->client |
726 | ->info($authenticationToken, $sessionToken); |
727 | } catch (Exception $e) { |
728 | throw new BackendException( |
729 | $e->getMessage(), |
730 | $e->getCode(), |
731 | $e |
732 | ); |
733 | } |
734 | break; |
735 | default: |
736 | $response = []; |
737 | } |
738 | } |
739 | if (!empty($response)) { |
740 | $this->cache->setItem($cacheKey, $response); |
741 | } |
742 | return $response; |
743 | } |
744 | |
745 | /** |
746 | * Set the VuFind Authentication Manager |
747 | * |
748 | * @param \VuFind\Auth\Manager $authManager Authentication Manager |
749 | * |
750 | * @return void |
751 | */ |
752 | public function setAuthManager($authManager) |
753 | { |
754 | $this->authManager = $authManager; |
755 | } |
756 | |
757 | /** |
758 | * Set the EBSCO backend type. Backend/EDS is used for both EDS and EPF. |
759 | * |
760 | * @param str $backendType 'EDS' or 'EPF' |
761 | * |
762 | * @return void |
763 | */ |
764 | public function setBackendType($backendType) |
765 | { |
766 | $this->backendType = $backendType; |
767 | } |
768 | } |