Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
75.68% |
112 / 148 |
|
50.00% |
7 / 14 |
CRAP | |
0.00% |
0 / 1 |
Base | |
75.68% |
112 / 148 |
|
50.00% |
7 / 14 |
76.45 | |
0.00% |
0 / 1 |
__construct | |
75.00% |
12 / 16 |
|
0.00% |
0 / 1 |
9.00 | |||
info | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
createSession | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 | |||
retrieve | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 | |||
retrieveEdsItem | |
88.89% |
8 / 9 |
|
0.00% |
0 / 1 |
2.01 | |||
retrieveEpfItem | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
search | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
4 | |||
parseAutocomplete | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
4 | |||
autocomplete | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
2 | |||
authenticate | |
93.75% |
15 / 16 |
|
0.00% |
0 / 1 |
5.01 | |||
createQSFromArray | |
31.58% |
6 / 19 |
|
0.00% |
0 / 1 |
28.50 | |||
call | |
100.00% |
21 / 21 |
|
100.00% |
1 / 1 |
3 | |||
process | |
33.33% |
3 / 9 |
|
0.00% |
0 / 1 |
5.67 | |||
setTokens | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
httpRequest | n/a |
0 / 0 |
n/a |
0 / 0 |
0 |
1 | <?php |
2 | |
3 | /** |
4 | * EBSCO Search API abstract base class |
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 EBSCOIndustries |
24 | * @package EBSCO |
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 http://edswiki.ebscohost.com/EDS_API_Documentation |
29 | */ |
30 | |
31 | namespace VuFindSearch\Backend\EDS; |
32 | |
33 | use Laminas\Log\LoggerAwareInterface; |
34 | |
35 | use function is_array; |
36 | |
37 | /** |
38 | * EBSCO Search API abstract base class |
39 | * |
40 | * @category EBSCOIndustries |
41 | * @package EBSCO |
42 | * @author Michelle Milton <mmilton@epnet.com> |
43 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
44 | * @link http://edswiki.ebscohost.com/EDS_API_Documentation |
45 | */ |
46 | abstract class Base implements LoggerAwareInterface |
47 | { |
48 | use \VuFind\Log\LoggerAwareTrait; |
49 | |
50 | /** |
51 | * EDS or EPF API host. |
52 | * |
53 | * @var string |
54 | */ |
55 | protected $apiHost; |
56 | |
57 | /** |
58 | * Auth host |
59 | * |
60 | * @var string |
61 | */ |
62 | protected $authHost = 'https://eds-api.ebscohost.com/authservice/rest'; |
63 | |
64 | /** |
65 | * Session host. |
66 | * |
67 | * @var string |
68 | */ |
69 | protected $sessionHost = 'https://eds-api.ebscohost.com/edsapi/rest'; |
70 | |
71 | /** |
72 | * The organization id use for authentication |
73 | * |
74 | * @var ?string |
75 | */ |
76 | protected $orgId; |
77 | |
78 | /** |
79 | * Accept header |
80 | * |
81 | * @var string |
82 | */ |
83 | protected $accept = 'application/json'; |
84 | |
85 | /** |
86 | * Content type header |
87 | * |
88 | * @var string |
89 | */ |
90 | protected $contentType = 'application/json'; |
91 | |
92 | /** |
93 | * Search HTTP method |
94 | * |
95 | * @var string |
96 | */ |
97 | protected $searchHttpMethod = 'POST'; |
98 | |
99 | /** |
100 | * Constructor |
101 | * |
102 | * Sets up the EDS API Client |
103 | * |
104 | * @param array $settings Associative array of setting to use in |
105 | * conjunction with the EDS API |
106 | * <ul> |
107 | * <li>orgid - Organization making calls to the EDS API </li> |
108 | * <li>search_http_method - HTTP method for search API calls</li> |
109 | * </ul> |
110 | */ |
111 | public function __construct($settings = []) |
112 | { |
113 | if (is_array($settings)) { |
114 | foreach ($settings as $key => $value) { |
115 | switch ($key) { |
116 | case 'api_url': |
117 | $this->apiHost = $value; |
118 | break; |
119 | case 'auth_url': |
120 | $this->authHost = $value; |
121 | break; |
122 | case 'session_url': |
123 | $this->sessionHost = $value; |
124 | break; |
125 | case 'orgid': |
126 | $this->orgId = $value; |
127 | break; |
128 | case 'search_http_method': |
129 | $this->searchHttpMethod = $value; |
130 | } |
131 | } |
132 | } |
133 | } |
134 | |
135 | /** |
136 | * Obtain edsapi search criteria and application related settings |
137 | * |
138 | * @param string $authenticationToken Authentication token |
139 | * @param string $sessionToken Session token |
140 | * |
141 | * @return array |
142 | */ |
143 | public function info($authenticationToken = null, $sessionToken = null) |
144 | { |
145 | $this->debug('Info'); |
146 | $url = $this->apiHost . '/info'; |
147 | $headers = $this->setTokens($authenticationToken, $sessionToken); |
148 | return $this->call($url, $headers); |
149 | } |
150 | |
151 | /** |
152 | * Creates a new session |
153 | * |
154 | * @param string $profile Profile to use |
155 | * @param string $isGuest Whether or not this session will be a guest session |
156 | * @param string $authToken Authentication token |
157 | * |
158 | * @return array |
159 | */ |
160 | public function createSession( |
161 | $profile = null, |
162 | $isGuest = null, |
163 | $authToken = null |
164 | ) { |
165 | $this->debug( |
166 | 'Create Session for profile: ' |
167 | . "$profile, guest: $isGuest, authToken: $authToken " |
168 | ); |
169 | $qs = ['profile' => $profile, 'guest' => $isGuest]; |
170 | $url = $this->sessionHost . '/createsession'; |
171 | $headers = $this->setTokens($authToken, null); |
172 | return $this->call($url, $headers, $qs, 'GET', null, '', false); |
173 | } |
174 | |
175 | /** |
176 | * Retrieves an EDS record specified by its identifiers |
177 | * |
178 | * @param string $an An of the record to retrieve from the |
179 | * EdsApi |
180 | * @param string $dbId Database identifier of the record to |
181 | * retrieve from the EdsApi |
182 | * @param string $authenticationToken Authentication token |
183 | * @param string $sessionToken Session token |
184 | * @param string $highlightTerms Comma separated list of terms to highlight |
185 | * in the retrieved record responses |
186 | * @param array $extraQueryParams Extra query string parameters |
187 | * |
188 | * @return array The requested record |
189 | * |
190 | * @deprecated Use retrieveEdsItem |
191 | */ |
192 | public function retrieve( |
193 | $an, |
194 | $dbId, |
195 | $authenticationToken, |
196 | $sessionToken, |
197 | $highlightTerms = null, |
198 | $extraQueryParams = [] |
199 | ) { |
200 | return $this->retrieveEdsItem( |
201 | $an, |
202 | $dbId, |
203 | $authenticationToken, |
204 | $sessionToken, |
205 | $highlightTerms, |
206 | $extraQueryParams |
207 | ); |
208 | } |
209 | |
210 | /** |
211 | * Retrieves an EDS record specified by its identifiers |
212 | * |
213 | * @param string $an An of the record to retrieve from the |
214 | * EdsApi |
215 | * @param string $dbId Database identifier of the record to |
216 | * retrieve from the EdsApi |
217 | * @param string $authenticationToken Authentication token |
218 | * @param string $sessionToken Session token |
219 | * @param string $highlightTerms Comma separated list of terms to highlight |
220 | * in the retrieved record responses |
221 | * @param array $extraQueryParams Extra query string parameters |
222 | * |
223 | * @return array The requested record |
224 | */ |
225 | public function retrieveEdsItem( |
226 | $an, |
227 | $dbId, |
228 | $authenticationToken, |
229 | $sessionToken, |
230 | $highlightTerms = null, |
231 | $extraQueryParams = [] |
232 | ) { |
233 | $this->debug( |
234 | "Get Record. an: $an, dbid: $dbId, $highlightTerms: $highlightTerms" |
235 | ); |
236 | $qs = $extraQueryParams + ['an' => $an, 'dbid' => $dbId]; |
237 | if (null != $highlightTerms) { |
238 | $qs['highlightterms'] = $highlightTerms; |
239 | } |
240 | $url = $this->apiHost . '/retrieve'; |
241 | $headers = $this->setTokens($authenticationToken, $sessionToken); |
242 | return $this->call($url, $headers, $qs); |
243 | } |
244 | |
245 | /** |
246 | * Retrieves an EPF record specified by its identifiers |
247 | * |
248 | * @param string $pubId Id of the record to retrieve from the |
249 | * EpfApi |
250 | * @param string $authenticationToken Authentication token |
251 | * @param string $sessionToken Session token |
252 | * |
253 | * @return array The requested record |
254 | */ |
255 | public function retrieveEpfItem( |
256 | $pubId, |
257 | $authenticationToken, |
258 | $sessionToken |
259 | ) { |
260 | $this->debug( |
261 | "Get Record. pubId: $pubId" |
262 | ); |
263 | $qs = ['id' => $pubId]; |
264 | $url = $this->apiHost . '/retrieve'; |
265 | $headers = $this->setTokens($authenticationToken, $sessionToken); |
266 | return $this->call($url, $headers, $qs); |
267 | } |
268 | |
269 | /** |
270 | * Execute an EdsApi search |
271 | * |
272 | * @param SearchRequestModel $query Search request object |
273 | * @param string $authenticationToken Authentication token |
274 | * @param string $sessionToken Session token |
275 | * |
276 | * @return array An array of query results as returned from the api |
277 | */ |
278 | public function search($query, $authenticationToken, $sessionToken) |
279 | { |
280 | // Query String Parameters |
281 | $method = $this->searchHttpMethod; |
282 | $json = $method === 'GET' ? null : $query->convertToSearchRequestJSON(); |
283 | $qs = $method === 'GET' ? $query->convertToQueryStringParameterArray() : []; |
284 | $this->debug( |
285 | 'Query: ' . ($method === 'GET' ? $this->varDump($qs) : $json) |
286 | ); |
287 | $url = $this->apiHost . '/search'; |
288 | $headers = $this->setTokens($authenticationToken, $sessionToken); |
289 | return $this->call($url, $headers, $qs, $method, $json); |
290 | } |
291 | |
292 | /** |
293 | * Parse autocomplete response from API in an array of terms |
294 | * |
295 | * @param array $msg Response from API |
296 | * |
297 | * @return array of terms |
298 | */ |
299 | protected function parseAutocomplete($msg) |
300 | { |
301 | $result = []; |
302 | if (isset($msg['terms']) && is_array($msg['terms'])) { |
303 | foreach ($msg['terms'] as $value) { |
304 | $result[] = $value['term']; |
305 | } |
306 | } |
307 | return $result; |
308 | } |
309 | |
310 | /** |
311 | * Execute an EdsApi autocomplete |
312 | * |
313 | * @param string $query Search term |
314 | * @param string $type Autocomplete type (e.g. 'rawqueries' or 'holdings') |
315 | * @param array $data Autocomplete API details (from authenticating with |
316 | * 'autocomplete' option set -- requires token, custid and url keys). |
317 | * @param bool $raw Should we return the results raw (true) or processed |
318 | * (false)? |
319 | * |
320 | * @return array An array of autocomplete terns as returned from the api |
321 | */ |
322 | public function autocomplete($query, $type, $data, $raw = false) |
323 | { |
324 | // $filters is an array of filter objects |
325 | // filter objects consist of name and an array of values (customer ids) |
326 | $filters = [['name' => 'custid', 'values' => [$data['custid']]]]; |
327 | |
328 | $params = [ |
329 | 'idx' => $type, |
330 | 'token' => $data['token'], |
331 | 'filters' => json_encode($filters), |
332 | 'term' => $query, |
333 | ]; |
334 | |
335 | $url = $data['url'] . '?' . http_build_query($params); |
336 | |
337 | $this->debug('Autocomplete URL: ' . $url); |
338 | $response = $this->call($url, null, null, 'GET', null); |
339 | return $raw ? $response : $this->parseAutocomplete($response); |
340 | } |
341 | |
342 | /** |
343 | * Generate an authentication token with a valid EBSCO EDS Api account |
344 | * |
345 | * @param string $username username associated with an EBSCO EdsApi account |
346 | * @param string $password password associated with an EBSCO EdsApi account |
347 | * @param string $orgid Organization id the request is initiated from |
348 | * @param array $params optional params (autocomplete) |
349 | * |
350 | * @return array |
351 | */ |
352 | public function authenticate( |
353 | $username = null, |
354 | $password = null, |
355 | $orgid = null, |
356 | $params = null |
357 | ) { |
358 | $this->debug( |
359 | "Authenticating: username: $username, password: XXXXXXX, orgid: $orgid" |
360 | ); |
361 | $url = $this->authHost . '/uidauth'; |
362 | $org = $orgid ?? $this->orgId; |
363 | $authInfo = []; |
364 | if (isset($username)) { |
365 | $authInfo['UserId'] = $username; |
366 | } |
367 | if (isset($password)) { |
368 | $authInfo['Password'] = $password; |
369 | } |
370 | if (isset($org)) { |
371 | $authInfo['orgid'] = $org; |
372 | } |
373 | if (isset($params)) { |
374 | $authInfo['Options'] = $params; |
375 | } |
376 | $messageBody = json_encode($authInfo); |
377 | return $this->call($url, null, null, 'POST', $messageBody, '', false); |
378 | } |
379 | |
380 | /** |
381 | * Convert an array of search parameters to EDS API querystring parameters |
382 | * |
383 | * @param array $params Parameters to convert to querystring parameters |
384 | * |
385 | * @return array |
386 | */ |
387 | protected function createQSFromArray($params) |
388 | { |
389 | $queryParameters = []; |
390 | if (null != $params && is_array($params)) { |
391 | foreach ($params as $key => $value) { |
392 | if (is_array($value)) { |
393 | $parameterName = $key; |
394 | if (SearchRequestModel::isParameterIndexed($parameterName)) { |
395 | $parameterName = SearchRequestModel::getIndexedParameterName( |
396 | $parameterName |
397 | ); |
398 | } |
399 | $cnt = 0; |
400 | foreach ($value as $subValue) { |
401 | $cnt = $cnt + 1; |
402 | $finalParameterName = $parameterName; |
403 | if (SearchRequestModel::isParameterIndexed($key)) { |
404 | $finalParameterName = $parameterName . '-' . $cnt; |
405 | } |
406 | $queryParameters[] |
407 | = $finalParameterName . '=' . urlencode($subValue); |
408 | } |
409 | } else { |
410 | $queryParameters[] = $key . '=' . urlencode($value ?? ''); |
411 | } |
412 | } |
413 | } |
414 | return $queryParameters; |
415 | } |
416 | |
417 | /** |
418 | * Submit REST Request |
419 | * |
420 | * @param string $baseUrl URL of service |
421 | * @param array $headerParams An array of headers to add to the request |
422 | * @param array $params An array of parameters for the request |
423 | * @param string $method The HTTP Method to use |
424 | * @param string $message Message to POST if $method is POST |
425 | * @param string $messageFormat Format of request $messageBody and responses |
426 | * @param bool $cacheable Whether the request is cacheable |
427 | * |
428 | * @throws ApiException |
429 | * @return object EDS API response (or an Error object). |
430 | */ |
431 | protected function call( |
432 | $baseUrl, |
433 | $headerParams, |
434 | $params = [], |
435 | $method = 'GET', |
436 | $message = null, |
437 | $messageFormat = '', |
438 | $cacheable = true |
439 | ) { |
440 | // Build Query String Parameters |
441 | $queryParameters = $this->createQSFromArray($params); |
442 | $queryString = implode('&', $queryParameters); |
443 | $this->debug("Querystring to use: $queryString "); |
444 | // Build headers |
445 | $headers = [ |
446 | 'Accept' => $this->accept, |
447 | 'Content-Type' => $this->contentType, |
448 | 'Accept-Encoding' => 'gzip,deflate', |
449 | ]; |
450 | if (null != $headerParams) { |
451 | foreach ($headerParams as $key => $value) { |
452 | $headers[$key] = $value; |
453 | } |
454 | } |
455 | $response = $this->httpRequest( |
456 | $baseUrl, |
457 | $method, |
458 | $queryString, |
459 | $headers, |
460 | $message, |
461 | $messageFormat, |
462 | $cacheable |
463 | ); |
464 | return $this->process($response); |
465 | } |
466 | |
467 | /** |
468 | * Process EDS API response message |
469 | * |
470 | * @param string $input The raw response from EDS API |
471 | * |
472 | * @throws ApiException |
473 | * @return array The processed response from EDS API |
474 | */ |
475 | protected function process($input) |
476 | { |
477 | //process response. |
478 | try { |
479 | $result = json_decode($input, true); |
480 | } catch (\Exception $e) { |
481 | throw new ApiException( |
482 | 'An error occurred when processing EDS Api response: ' |
483 | . $e->getMessage() |
484 | ); |
485 | } |
486 | if (!isset($result)) { |
487 | throw new ApiException('Unknown error processing response'); |
488 | } |
489 | return $result; |
490 | } |
491 | |
492 | /** |
493 | * Populate an associative array of session and authentication parameters to |
494 | * send to the EDS API |
495 | * |
496 | * @param string $authenticationToken Authentication token to add |
497 | * @param string $sessionToken Session token to add |
498 | * |
499 | * @return array Associative array of header parameters to add. |
500 | */ |
501 | protected function setTokens($authenticationToken = null, $sessionToken = null) |
502 | { |
503 | $headers = []; |
504 | if (!empty($authenticationToken)) { |
505 | $headers['x-authenticationToken'] = $authenticationToken; |
506 | } |
507 | if (!empty($sessionToken)) { |
508 | $headers['x-sessionToken'] = $sessionToken; |
509 | } |
510 | return $headers; |
511 | } |
512 | |
513 | /** |
514 | * Perform an HTTP request. |
515 | * |
516 | * @param string $baseUrl Base URL for request |
517 | * @param string $method HTTP method for request (GET, POST, etc.) |
518 | * @param string $queryString Query string to append to URL |
519 | * @param array $headers HTTP headers to send |
520 | * @param string $messageBody Message body to for HTTP Request |
521 | * @param string $messageFormat Format of request $messageBody and responses |
522 | * @param bool $cacheable Whether the request is cacheable |
523 | * |
524 | * @return string HTTP response body |
525 | */ |
526 | abstract protected function httpRequest( |
527 | $baseUrl, |
528 | $method, |
529 | $queryString, |
530 | $headers, |
531 | $messageBody, |
532 | $messageFormat, |
533 | $cacheable = true |
534 | ); |
535 | } |