Newer
Older
<?php
/**
* Copyright (C) Leipzig University Library 2019.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* @category VuFind
* @package Resolver
* @author Gregor Gawol <gawol@ub.uni-leipzig.de>
* @license http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
* @link https://vufind.org/wiki/development Wiki
*/
namespace fid\VuFind\Resolver\Driver;
use DOMDocument;
use DOMXpath;
use finc\Resolver\Driver\Ezb as BaseEzb;
use Zend\Config\Config;
/**
* Class Ezb
* @category VuFind
* @package Resolver
* @author Gregor Gawol <gawol@ub.uni-leipzig.de>
* @license http://opensource.org/licenses/gpl-2.0.php GNU GPLv2
* @link https://vufind.org/wiki/development Wiki
*/
class Ezb extends BaseEzb
{
/**
* @var Config
*/
protected $config;
/**
* ILS connection
*
* @var Connection
*/
protected $ils;
/**
* FID API Client
*
* @var \fid\Service\Client
*/
protected $fidClient;
/**
* Base URL EZB Resolver
*
* @var string
*/
protected $baseUrl;
/**
* Setter for $config
*
* @param Config $config resolver configuration
*
* @return void
*/
public function setConfig(Config $config): void
{
$this->config = $config;
}
/**
* Setter for $fidClient
*
* @param Client $fidClient fid client
*
* @return void
*/
public function setFidClient(Client $fidClient): void
{
$this->fidClient = $fidClient;
}
/**
* Setter for $ils
*
* @param Connection $ils ILS connection
*
* @return void
*/
public function setIls(Connection $ils): void
{
$this->ils = $ils;
}
/**
* Setter for $baseUrl
*
* @param string $baseUrl resolver's base URL
*
* @return void
*/
public function setBaseUrl(string $baseUrl): void
{
$this->baseUrl = $baseUrl;
}
/**
* Parse Links
*
* Parses an XML file returned by a link resolver
* and converts it to a standardised format for display
*
* @param string $xmlstr Raw XML returned by resolver
*
* @return array Array of values
*/
public function parseLinks($xmlstr)
{
$records = []; // array to return
$xml = new DOMDocument();
if (!@$xml->loadXML($xmlstr)) {
return $records;
}
$xpath = new DOMXpath($xml);
// get results for online
$this->getElectronicResults('0', 'Free', $records, $xpath);
$this->getElectronicResults('1', 'Partially free', $records, $xpath);
$this->getElectronicResults('2', 'Licensed', $records, $xpath);
$this->getElectronicResults('3', 'Partially licensed', $records, $xpath);
$this->getElectronicResults('4', 'Not free', $records, $xpath);
$this->getElectronicResults('10', 'Not free', $records, $xpath);
$this->getElectronicResults('-1', 'Not free', $records, $xpath);
// get results for print, only if available
$this->getPrintResults('2', 'Print available', $records, $xpath);
$this->getPrintResults('3', 'Print partially available', $records, $xpath);
$records['messages'] = $this->messages;
$records['stateOfResults'] = $this->stateOfResults;
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/**
* Get Resolver Url
*
* Transform the OpenURL as needed to get a working link to the resolver.
*
* Extends VuFind EZB Resolver
*
* @param string $openURL openURL (url-encoded)
*
* @return string Returns resolver specific url
*/
public function getResolverUrl($openURL)
{
// Unfortunately the EZB-API only allows OpenURL V0.1 and
// breaks when sending a non expected parameter (like an ISBN).
// So we do have to 'downgrade' the OpenURL-String from V1.0 to V0.1
// and exclude all parameters that are not compliant with the EZB.
// Parse OpenURL into associative array:
$tmp = explode('&', $openURL);
$parsed = [];
foreach ($tmp as $current) {
$tmp2 = explode('=', $current, 2);
$parsed[$tmp2[0]] = $tmp2[1];
}
// Downgrade 1.0 to 0.1
if ($parsed['ctx_ver'] == 'Z39.88-2004') {
$openURL = $this->downgradeOpenUrl($parsed);
}
// use ils for dynamic resolver data
// fid specific adaption
if (isset($this->config->useILS) && $this->config->useILS) {
if ($this->fidClient->isLoggedOn()) {
$user = $this->fidClient->requestUserDetails();
$libraries = $this->fidClient->requestLibraryList();
$homeLibrary = $user->getHomeLibrary();
// Obtain user information from ILS:
$libInfo = $libraries[$homeLibrary] ?? $libraries['AAAAA'];
$bibId = $libInfo->getEzb();
$isil = $libInfo->getIsil();
} else {
// standard bibid in EZB resolver
$bibId = 'AAAAA';
}
$openURL .= '&pid=' .
'bibid%3D' . $bibId .
(!empty($isil) ? '%26isil%3D' . $isil : '');
} elseif (isset($this->config->bibid)) {
$openURL .= '&pid=' .
'bibid%3D' . $this->config->bibid;
} elseif (isset($this->config->useClientIp)
&& $this->config->useClientIp
) {
// make the request IP-based to allow automatic
// indication on institution level
$openURL .= '&pid=client_ip%3D' . $_SERVER['REMOTE_ADDR'];
}
// fid specific adaption - END
$openURL .= isset($parsed['zdbid']) ?
'%26zdbid%3D' . $parsed['zdbid'] : '';
// Make the call to the EZB and load results
$url = $this->baseUrl . '?' . $openURL;
return $url;
}
/**
* Extract electronic results from the EZB response and inject them into the
* $records array.
*
* @param string $state The state attribute value to extract
* @param string $coverage The coverage string to associate with the state
* @param array $records The array of results to update
* @param DOMXpath $xpath The XPath object containing parsed XML
*
* @return void
*/
protected function getElectronicResults($state, $coverage, &$records, $xpath)
{
$results = $xpath->query(
"/OpenURLResponseXML/Full/ElectronicData/ResultList/Result[@state=" .
$state . "]"
);
$accessLevel_mapping = [
'article' => 'article',
'issue' => 'issue',
'volume' => 'default',
'year' => 'default',
'homepage' => 'default',
'abstract' => 'abstract'
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
];
$i = 0;
foreach ($results as $result) {
$record = [];
$accessLevelXP = "/OpenURLResponseXML/Full/ElectronicData/ResultList/" .
"Result[@state={$state}][".($i+1)."]/AccessLevel";
$accessLevel = $xpath->query($accessLevelXP, $result)->item(0);
if (isset($accessLevel)) {
$record['title']
= $accessLevel_mapping[strip_tags($accessLevel->nodeValue)];
}
$accessUrlXP = "/OpenURLResponseXML/Full/ElectronicData/ResultList/" .
"Result[@state={$state}][".($i+1)."]/AccessURL";
$accessUrl = $xpath->query($accessUrlXP, $result)->item(0);
$journalUrlXP = "/OpenURLResponseXML/Full/ElectronicData/ResultList/" .
"Result[@state={$state}][".($i+1)."]/JournalURL";
$journalUrl = $xpath->query($journalUrlXP, $result)->item(0);
if (isset($accessUrl->nodeValue)) {
$record['href'] = $accessUrl->nodeValue;
} elseif (isset($journalUrl)) {
$record['href'] = $journalUrl->nodeValue;
}
$stateOfResultXP = "/OpenURLResponseXML/Full/ElectronicData/ResultList/"
. "Result/@state";
$stateOfResult = $xpath->query($stateOfResultXP, $result)->item(0);
if (isset($stateOfResult->nodeValue)) {
$this->stateOfResults[] = $stateOfResult->nodeValue;
}
$record['access'] = $this->electronic_state_access_mapping[$state];
// Service type needs to be hard-coded for calling code to properly
// categorize links. The commented code below picks a more appropriate
// value but won't work for now -- retained for future reference.
//$service_typeXP = "/OpenURLResponseXML/Full/ElectronicData/ResultList/"
// . "Result[@state={$state}][".($i+1)."]/AccessLevel";
//$record['service_type']
// = $xpath->query($service_typeXP, $result)->item(0)->nodeValue;
$record['service_type'] = 'getFullTxt';
array_push($records, $record);
$i++;
}
}
/**
* Extract print results from the EZB response and inject them into the
* $records array.
*
* @param string $state The state attribute value to extract
* @param string $coverage The coverage string to associate with the state
* @param array $records The array of results to update
* @param DOMXpath $xpath The XPath object containing parsed XML
*
* @return void
*/
protected function getPrintResults($state, $coverage, &$records, $xpath)
{
$results = $xpath->query(
"/OpenURLResponseXML/Full/PrintData/ResultList/Result[@state={$state}]"
);
/* override state 3 from 'limited' to 'open' */
$this->print_state_access_mapping['3'] = 'open';
$i = 0;
foreach ($results as $result) {
$record = [];
$resultXP = "/OpenURLResponseXML/Full/PrintData/ResultList/" .
"Result[@state={$state}][" . ($i + 1) . "]";
$resultElements = [
'Title', 'Location', 'Signature', 'Period', 'Holding_comment'
];
// store data in separate array field fid-specific
foreach ($resultElements as $element) {
$elem = $xpath->query($resultXP . "/" . $element, $result)->item(0);
if (isset($elem->nodeValue)) {
$record[$element] = strip_tags($elem->nodeValue);
}
}
/* messages depends on access state and will be build within templates */
$record['access'] = $this->print_state_access_mapping[$state];
// Service type needs to be hard-coded for calling code to properly
// categorize links. The commented code below picks a more appropriate
// value but won't work for now -- retained for future reference.
//$service_typeXP = "/OpenURLResponseXML/Full/PrintData/References"
// . "/Reference/Label";
//$record['service_type']
// = $xpath->query($service_typeXP, $result)->item($i)->nodeValue;
$record['service_type'] = 'getHolding';
array_push($records, $record);
$i++;
}
}