diff --git a/module/finc/src/finc/ILS/Driver/FincLibero.php b/module/finc/src/finc/ILS/Driver/FincLibero.php index 8f562ec316f6d5d3018d1cb9004bc719fdbd4adf..8c552e7387710567d5bbd0afafb0fb8b81e6b827 100644 --- a/module/finc/src/finc/ILS/Driver/FincLibero.php +++ b/module/finc/src/finc/ILS/Driver/FincLibero.php @@ -1,6 +1,6 @@ <?php /** - * Finc specific Libero ILS Driver for VuFind, using PAIA, DAIA and LiberoDing + * Finc specific Libero ILS Driver for VuFind, using PAIA, DAIA and LiberoWachtl * services. * * PHP version 5 @@ -30,9 +30,10 @@ namespace finc\ILS\Driver; use VuFind\I18n\Translator\TranslatorAwareTrait; use VuFind\I18n\Translator\TranslatorAwareInterface, VuFind\Exception\ILS as ILSException; +use VuFindSearch\Query\Query; /** - * Finc specific Libero ILS Driver for VuFind, using PAIA, DAIA and LiberoDing + * Finc specific Libero ILS Driver for VuFind, using PAIA, DAIA and LiberoWachtl * services. * * @category VuFind2 @@ -45,7 +46,7 @@ class FincLibero extends FincILS implements TranslatorAwareInterface { const DELETE_NOTIFICATIONS_SUCCESS = '1'; const DELETE_NOTIFICATIONS_ERROR = '0'; - use LiberoDingTrait; + use LiberoWachtlTrait; use TranslatorAwareTrait; /** @@ -106,6 +107,25 @@ class FincLibero extends FincILS implements TranslatorAwareInterface */ protected $readingRoomURIs = []; + /** + * Regex pattern to detect bound item ID + * @var string + */ + protected $boundItemIdPattern; + + /** + * Regex pattern to detect bound item label + * @var string + */ + protected $boundItemLabelPattern; + + public function init() + { + parent::init(); + $this->boundItemIdPattern = $this->config['General']['bound_item_id_pattern'] ?? null; + $this->boundItemLabelPattern = $this->config['General']['bound_item_label_pattern'] ?? null; + } + /** * Helper function to extract the Namespace from the DAIA URI prefix. * @@ -701,14 +721,199 @@ class FincLibero extends FincILS implements TranslatorAwareInterface return $pickUpLocations; } + /** - * TODO: check status of this function - * de_15 -> getBoundItemId() vs. de_l152 -> getBoundItemInfo() - * @param $item - * @return array + * Helper method to check whether this item is bound with another item and needs + * to be ordered via this bound item + * + * @param array $item Array with DAIA item data + * + * @return null */ protected function getBoundItemId($item) { - return []; + if (!isset($this->boundItemIdPattern)) return null; + $availabilities = ['available', 'unavailable']; + + // start logic to check if we have a bound item that needs to be ordered + // via another record (see https://intern.finc.info/issues/5068) + foreach ($availabilities as $availability) { + if (isset($item[$availability])) { + foreach ($item[$availability] as $available) { + if (isset($available['limitation'])) { + foreach ($available['limitation'] as $limitation) { + if (in_array($limitation['id'], $this->awlLimitations)) { + // items with limitations identifying the record for + // being bound to another item contain the RSN of the + // bound item in their current available service href + if (isset($available['href']) + && preg_match($this->boundItemIdPattern, + $available['href'], + $matches + ) + ) { + return $this->queryBoundItem($matches['id']); + } + } + } + } + } + } + } + + // if we made it this far this item definitely is not bound to another item + return null; + } + + + /** + * Helper method to query bound item by rsn for record_id + * + * @param string $key + * + * @return string record_id + */ + protected function queryBoundItem($key) { + + $query = $this->getBoundItemQueryString($key); + if (empty($query)) { + return null; + } + try { + // let's search with the built query + $result = $this->searchService + ->search('VuFind', new Query($query)); + if (count($result) === 0) { + $this->debug('Problem retrieving rsn ' . + 'for record with query:' . $query); + return null; + } + // pass the id from the first found record as + // awlRecordId to the controller + return current($result->getRecords()) + ->getUniqueId(); + } catch (\Exception $e) { + $this->debug($e); + return null; + } + } + + /** + * Check if item is a pretended dummy to signify there is a title order + * possible. + * + * @param array $item DAIA item + * + * @return mixed + */ + public function isTitleHold($item) + { + foreach ($this->titleHoldLimitations as $limitation) { + $regex = '/^' . trim($limitation) . '$/'; + if (0 < preg_match($regex, $item['id'])) { + return true; + } + } + return null; + } + + /** + * Place Title Hold + * + * Attempts to place a hold or recall on a particular item and returns + * an array with result details + * + * Make a request on a specific record + * + * @param array $holdDetails An array of item and patron data + * + * @return mixed An array of data on the request including + * whether or not it was successful and a system message (if available) + */ + public function placeTitleHold($holdDetails) + { + $item = $holdDetails['item_id']; + $patron = $holdDetails['patron']; + $doc = []; + $doc['item'] = stripslashes($item); + if ($confirm = $this->getConfirmations( + $this->extendPickUpLocation($holdDetails) + )) { + $doc["confirm"] = $confirm; + } + $post_data['doc'][] = $doc; + try { + $array_response = $this->paiaPostAsArray( + 'core/'.$patron['cat_username'].'/request', $post_data + ); + } catch (Exception $e) { + $this->debug($e->getMessage()); + return [ + 'success' => false, + 'sysMessage' => $e->getMessage(), + ]; + } + $details = []; + if (array_key_exists('error', $array_response)) { + $details = [ + 'success' => false, + 'sysMessage' => $array_response['error_description'] + ]; + } else { + $elements = $array_response['doc']; + foreach ($elements as $element) { + if (array_key_exists('error', $element)) { + $details = [ + 'success' => false, + 'sysMessage' => $element['error'] + ]; + } else { + // FincLibero supports more expressive responses from paialibero + // which should be shown instead to the user (localIlsStatus) + $details = [ + 'success' => true, + 'sysMessage' => isset($element['localIlsStatus']) + ? $element['localIlsStatus'] : 'Successfully requested' + ]; + // if caching is enabled for DAIA remove the cached data for the + // current item otherwise the changed status will not be shown + // before the cache expires + if ($this->daiaCacheEnabled) { + $this->removeCachedData($holdDetails['doc_id']); + } + } + } + } + return $details; + } + + /** + * Extend pickup location with base department URI + * + * @param array $holdDetails An array of item and patron data. + * + * @return array $holdDetails; + */ + protected function extendPickUpLocation($holdDetails) + { + if (isset($holdDetails['pickUpLocation'])) { + $holdDetails['pickUpLocation'] + = $this->departmentLocationBase . $holdDetails['pickUpLocation']; + } + return $holdDetails; + } + + /** + * Helper function for queryBoundItem. Prepares instance specific query string + * to get the ID of the bound item + * + * Override in inherited FincLibero + * + * @param $key string ID to search for + * @return string SOLR query to be used as q parameter + */ + protected function getBoundItemQueryString($key) + { + return ''; } } diff --git a/module/finc/src/finc/ILS/Driver/LiberoDingTrait.php b/module/finc/src/finc/ILS/Driver/LiberoWachtlTrait.php similarity index 80% rename from module/finc/src/finc/ILS/Driver/LiberoDingTrait.php rename to module/finc/src/finc/ILS/Driver/LiberoWachtlTrait.php index 3940de37c6ff605239895f050f3ee746be7f826f..6a2b1d3622ebc67ae082b7cce492fcdaeeb84a57 100644 --- a/module/finc/src/finc/ILS/Driver/LiberoDingTrait.php +++ b/module/finc/src/finc/ILS/Driver/LiberoWachtlTrait.php @@ -1,7 +1,7 @@ <?php /** - * Finc specific LiberoDing trait providing all the functions necessary for - * communicating with the LiberoDing. + * Finc specific LiberoWachtl trait providing all the functions necessary for + * communicating with the LiberoWachtl. * * PHP version 5 * @@ -32,8 +32,8 @@ use VuFind\Exception\ILS as ILSException; use Zend\Log\LoggerAwareInterface as LoggerAwareInterface; /** - * Finc specific LiberoDing trait providing all the functions necessary for - * communicating with the LiberoDing. + * Finc specific LiberoWachtl trait providing all the functions necessary for + * communicating with the LiberoWachtl. * * @category VuFind * @package ILS_Drivers @@ -41,8 +41,13 @@ use Zend\Log\LoggerAwareInterface as LoggerAwareInterface; * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link https://vufind.org/wiki/development:plugins:ils_drivers Wiki */ -trait LiberoDingTrait +trait LiberoWachtlTrait { + /** + * @var $liberoWachtlUrl string URL of wachtl API + */ + protected $liberoWachtlUrl; + /** * Get connection timeout of Libero request. * @@ -53,9 +58,9 @@ trait LiberoDingTrait */ protected function getConnectTimeout($connectTimeout = 500) { - return $test = (isset($this->config['LiberoDing']['connectTimeout']) - && is_numeric($this->config['LiberoDing']['connectTimeout'])) - ? $this->config['LiberoDing']['connectTimeout'] + return $test = (isset($this->config['LiberoWachtl']['connectTimeout']) + && is_numeric($this->config['LiberoWachtl']['connectTimeout'])) + ? $this->config['LiberoWachtl']['connectTimeout'] : $connectTimeout; } @@ -69,25 +74,28 @@ trait LiberoDingTrait */ protected function getResponseTimeout($responseTimeout = 1000) { - return (isset($this->config['LiberoDing']['responseTimeout']) - && is_numeric($this->config['LiberoDing']['responseTimeout'])) - ? $this->config['LiberoDing']['responseTimeout'] + return (isset($this->config['LiberoWachtl']['responseTimeout']) + && is_numeric($this->config['LiberoWachtl']['responseTimeout'])) + ? $this->config['LiberoWachtl']['responseTimeout'] : $responseTimeout; } /** - * gets the webscraper url from config + * gets the LiberoWachtl url from config * * @return string - * @throws \Exception Webscraper url not defined + * @throws \Exception LiberoWachtl url not defined */ - protected function getWebScraperUrl() + protected function getLiberoWachtlUrl() { - if (!isset($this->config['LiberoDing']['webScraperUrl'])) { - throw new \Exception('no webscraper url defined'); + if (!isset($this->liberoWachtlUrl)) { + if (!isset($this->config['LiberoWachtl']['liberoWachtlUrl'])) { + throw new \Exception('no LiberoWachtl url defined'); + } + $this->liberoWachtlUrl = $this->config['LiberoWachtl']['liberoWachtlUrl']; } - return $this->config['LiberoDing']['webScraperUrl']; + return $this->liberoWachtlUrl; } /** @@ -98,11 +106,11 @@ trait LiberoDingTrait */ protected function getDbName() { - if (!isset($this->config['LiberoDing']['databaseName'])) { + if (!isset($this->config['LiberoWachtl']['databaseName'])) { throw new \Exception('no database name defined'); } - return $this->config['LiberoDing']['databaseName']; + return $this->config['LiberoWachtl']['databaseName']; } /** @@ -112,7 +120,7 @@ trait LiberoDingTrait * @return boolean Returns true if a connection exists * @throws \Exception Throws ILSException */ - public function checkLiberoDingConnection() + public function checkLiberoWachtlConnection() { $http_header['User-Agent'] = 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)'; @@ -125,7 +133,7 @@ trait LiberoDingTrait try { $result = $this->httpService->post( - $this->getWebScraperUrl() .'liberoPing.jsp', + $this->getLiberoWachtlUrl() .'liberoPing.jsp', http_build_query($params), 'application/json; charset=UTF-8', null, @@ -162,17 +170,17 @@ trait LiberoDingTrait */ public function balanceFinesOfUser($patron, $amount) { - $params = $this->getLiberoDingRequestParams(); + $params = $this->getLiberoWachtlRequestParams(); $params['memberCode'] = $patron['cat_username']; $params['password'] = $patron['cat_password']; $params['amount'] = $amount; try { $result = $this->httpService->get( - $this->getWebScraperUrl() .'payAnyFee.jsp', + $this->getLiberoWachtlUrl() .'payAnyFee.jsp', $params, null, - $this->getLiberoDingRequestHeaders() + $this->getLiberoWachtlRequestHeaders() ); } catch (\Exception $e) { throw new ILSException($e->getMessage()); @@ -189,7 +197,7 @@ trait LiberoDingTrait // reload PAIA session by paia login again $this->refreshLogin($patron['cat_username'], $patron['cat_password']); - return $this->getLiberoDingResultBool($result); + return $this->getLiberoWachtlResultBool($result); } /** @@ -203,16 +211,16 @@ trait LiberoDingTrait */ protected function getSystemMessages($patron) { - $params = $this->getLiberoDingRequestParams(); + $params = $this->getLiberoWachtlRequestParams(); $params['memberCode'] = $patron['cat_username']; $params['password'] = $patron['cat_password']; try { $result = $this->httpService->get( - $this->getWebScraperUrl() .'getMySystemMessages.jsp', + $this->getLiberoWachtlUrl() .'getMySystemMessages.jsp', $params, null, - $this->getLiberoDingRequestHeaders() + $this->getLiberoWachtlRequestHeaders() ); } catch (\Exception $e) { throw new ILSException($e->getMessage()); @@ -227,7 +235,7 @@ trait LiberoDingTrait return false; } - return $this->getLiberoDingResult($result, 'getMySystemMessages'); + return $this->getLiberoWachtlResult($result, 'getMySystemMessages'); } /** @@ -248,7 +256,7 @@ trait LiberoDingTrait $messageIdList = null, $toDate = null ) { - $params = $this->getLiberoDingRequestParams(); + $params = $this->getLiberoWachtlRequestParams(); $params['memberCode'] = $patron['cat_username']; $params['password'] = $patron['cat_password']; @@ -261,10 +269,10 @@ trait LiberoDingTrait try { $result = $this->httpService->get( - $this->getWebScraperUrl() .'removeMySystemMessages.jsp', + $this->getLiberoWachtlUrl() .'removeMySystemMessages.jsp', $params, null, - $this->getLiberoDingRequestHeaders() + $this->getLiberoWachtlRequestHeaders() ); } catch (\Exception $e) { throw new ILSException($e->getMessage()); @@ -279,7 +287,7 @@ trait LiberoDingTrait return false; } - return $this->getLiberoDingResult($result, 'removeMySystemMessages'); + return $this->getLiberoWachtlResult($result, 'removeMySystemMessages'); } /** @@ -293,15 +301,15 @@ trait LiberoDingTrait */ public function setLockMyAccount($patron) { - $params = $this->getLiberoDingRequestParams(); + $params = $this->getLiberoWachtlRequestParams(); $params['memberCode'] = $patron['cat_username']; $params['password'] = $patron['cat_password']; try { $result = $this->httpService->get( - $this->getWebScraperUrl() .'lockMyAccount.jsp', + $this->getLiberoWachtlUrl() .'lockMyAccount.jsp', $params, null, - $this->getLiberoDingRequestHeaders() + $this->getLiberoWachtlRequestHeaders() ); } catch (\Exception $e) { throw new ILSException($e->getMessage()); @@ -315,7 +323,7 @@ trait LiberoDingTrait return false; } // Log error for debugging - if( true === ($bool = $this->getLiberoDingResultBool($result))) { + if( true === ($bool = $this->getLiberoWachtlResultBool($result))) { // Remove explicitly session vars of PAIA connection // Compliance security issue $session = $this->getSession(); @@ -357,7 +365,7 @@ trait LiberoDingTrait { $map = self::profileDataMapper(true); - $params = $this->getLiberoDingRequestParams(); + $params = $this->getLiberoWachtlRequestParams(); $params['memberCode'] = $patron['cat_username']; $params['password'] = $patron['cat_password']; @@ -376,10 +384,10 @@ trait LiberoDingTrait try { $result = $this->httpService->get( - $this->getWebScraperUrl() .'setMyProfile.jsp', + $this->getLiberoWachtlUrl() .'setMyProfile.jsp', $params, null, - $this->getLiberoDingRequestHeaders() + $this->getLiberoWachtlRequestHeaders() ); } catch (\Exception $e) { throw new ILSException($e->getMessage()); @@ -394,7 +402,7 @@ trait LiberoDingTrait return false; } - return $this->getLiberoDingResultBool($result); + return $this->getLiberoWachtlResultBool($result); } /** @@ -404,8 +412,8 @@ trait LiberoDingTrait */ public function getIgnoredProfileFields() { - return isset($this->config['LiberoDing']['ignoredProfileFields']) ? - $this->config['LiberoDing']['ignoredProfileFields'] : []; + return isset($this->config['LiberoWachtl']['ignoredProfileFields']) ? + $this->config['LiberoWachtl']['ignoredProfileFields'] : []; } /** @@ -415,8 +423,8 @@ trait LiberoDingTrait */ public function getRestrictedUserGroups() { - return isset($this->config['LiberoDing']['restrictedUserGroups']) ? - $this->config['LiberoDing']['restrictedUserGroups'] : []; + return isset($this->config['LiberoWachtl']['restrictedUserGroups']) ? + $this->config['LiberoWachtl']['restrictedUserGroups'] : []; } /** @@ -427,12 +435,12 @@ trait LiberoDingTrait */ public function getItemsPerViewLoanHistory() { - return isset($this->config['LiberoDing']['itemsPerPageLoanHistory']) ? - $this->config['LiberoDing']['itemsPerPageLoanHistory'] : 20; + return isset($this->config['LiberoWachtl']['itemsPerPageLoanHistory']) ? + $this->config['LiberoWachtl']['itemsPerPageLoanHistory'] : 20; } /** - * This method queries the LiberoDing-ILS for a patron's current profile + * This method queries the LiberoWachtl-ILS for a patron's current profile * information. * * @param array $patron Patron array returned by patronLogin method. @@ -443,18 +451,18 @@ trait LiberoDingTrait * @see For content variables see method profileDataMapper * @throws \Exception Throws ILSException */ - protected function getLiberoDingProfile($patron, $mapped = true) + protected function getLiberoWachtlProfile($patron, $mapped = true) { - $params = $this->getLiberoDingRequestParams(); + $params = $this->getLiberoWachtlRequestParams(); $params['memberCode'] = $patron['cat_username']; $params['password'] = $patron['cat_password']; try { $result = $this->httpService->get( - $this->getWebScraperUrl() .'getMyProfile.jsp', + $this->getLiberoWachtlUrl() .'getMyProfile.jsp', $params, null, - $this->getLiberoDingRequestHeaders() + $this->getLiberoWachtlRequestHeaders() ); } catch (\Exception $e) { throw new ILSException($e->getMessage()); @@ -473,7 +481,7 @@ trait LiberoDingTrait // define of disabled fields $mappeddata = []; $map = self::profileDataMapper(); - $data = $this->getLiberoDingResult($result, 'getMyProfile'); + $data = $this->getLiberoWachtlResult($result, 'getMyProfile'); foreach ($data as $key => $value) { if ($key == 'disabledInputs') { @@ -492,12 +500,12 @@ trait LiberoDingTrait return $mappeddata; } - return $this->getLiberoDingResult($result, 'getMyProfile'); + return $this->getLiberoWachtlResult($result, 'getMyProfile'); } /** - * This method sends a PIN changing request to the LiberoDing. + * This method sends a PIN changing request to the LiberoWachtl. * * @param string $newPin New pin. * @param array $patron Patron array returned by patronLogin method. @@ -507,17 +515,17 @@ trait LiberoDingTrait */ public function changeUserPin($newPin, $patron) { - $params = $this->getLiberoDingRequestParams(); + $params = $this->getLiberoWachtlRequestParams(); $params['memberCode'] = $patron['cat_username']; $params['password'] = $patron['cat_password']; $params['newPin'] = $newPin; try { $result = $this->httpService->get( - $this->getWebScraperUrl() .'changeUserPin.jsp', + $this->getLiberoWachtlUrl() .'changeUserPin.jsp', $params, null, - $this->getLiberoDingRequestHeaders() + $this->getLiberoWachtlRequestHeaders() ); } catch (\Exception $e) { throw new ILSException($e->getMessage()); @@ -532,7 +540,7 @@ trait LiberoDingTrait return false; } - return $this->getLiberoDingResult($result, 'changeUserPinOk'); + return $this->getLiberoWachtlResult($result, 'changeUserPinOk'); } /** @@ -575,11 +583,11 @@ trait LiberoDingTrait } /** - * Private Helper function to return LiberoDing request parameters + * Private Helper function to return LiberoWachtl request parameters * * @return array */ - private function getLiberoDingRequestParams() + private function getLiberoWachtlRequestParams() { return [ 'dbName' => $this->getDbName(), @@ -589,11 +597,11 @@ trait LiberoDingTrait } /** - * Private Helper function to return LiberoDing request headers + * Private Helper function to return LiberoWachtl request headers * * @return array */ - private function getLiberoDingRequestHeaders() + private function getLiberoWachtlRequestHeaders() { return [ 'User-Agent' => 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)' @@ -609,7 +617,7 @@ trait LiberoDingTrait * * @return mixed */ - private function getLiberoDingResult($result, $resultKey) + private function getLiberoWachtlResult($result, $resultKey) { // get result as array $details = json_decode($result->getBody(), true); @@ -630,7 +638,7 @@ trait LiberoDingTrait * @return array * @access private */ - private function getLiberoDingResultBool($result) + private function getLiberoWachtlResultBool($result) { // get result as array $details = json_decode($result->getBody(), true); @@ -646,7 +654,7 @@ trait LiberoDingTrait * Customized getMyLoanHistory * * @param array $patron Array returned from patronLogin() - * @param int $lastLine Integer until LiberoDing should process history + * @param int $lastLine Integer until LiberoWachtl should process history * incrementally * * @return array $retval @@ -657,16 +665,16 @@ trait LiberoDingTrait */ public function getMyLoanHistory($patron, $lastLine) { - $params = $this->getLiberoDingRequestParams(); + $params = $this->getLiberoWachtlRequestParams(); $params['memberCode'] = $patron['cat_username']; $params['password'] = $patron['cat_password']; $params['pageNumber'] = 1; try { $result = $this->httpService->get( - $this->getWebScraperUrl() . 'getMyLoanHistory.jsp', + $this->getLiberoWachtlUrl() . 'getMyLoanHistory.jsp', $params, null, - $this->getLiberoDingRequestHeaders() + $this->getLiberoWachtlRequestHeaders() ); } catch (\Exception $e) { throw new ILSException($e->getMessage()); @@ -699,10 +707,10 @@ trait LiberoDingTrait $params['pageNumber'] = $page; try { $result = $this->httpService->get( - $this->getWebScraperUrl() . 'getMyLoanHistory.jsp', + $this->getLiberoWachtlUrl() . 'getMyLoanHistory.jsp', $params, null, - $this->getLiberoDingRequestHeaders() + $this->getLiberoWachtlRequestHeaders() ); } catch (\Exception $e) { throw new ILSException($e->getMessage()); @@ -718,7 +726,7 @@ trait LiberoDingTrait // merge with previous request $retval['items'] = array_merge( $retval['items'], - $this->getLiberoDingResult($result, 'getMyLoanHistory') + $this->getLiberoWachtlResult($result, 'getMyLoanHistory') ); // If there are requested lines collected break the iteration if (count($retval['items']) > $lastLine) { @@ -748,16 +756,16 @@ trait LiberoDingTrait */ public function getMyLoanHistoryItems($patron) { - $params = $this->getLiberoDingRequestParams(); + $params = $this->getLiberoWachtlRequestParams(); $params['memberCode'] = $patron['cat_username']; $params['password'] = $patron['cat_password']; $params['pageNumber'] = 1; try { $result = $this->httpService->get( - $this->getWebScraperUrl() . 'getMyLoanHistory.jsp', + $this->getLiberoWachtlUrl() . 'getMyLoanHistory.jsp', $params, null, - $this->getLiberoDingRequestHeaders() + $this->getLiberoWachtlRequestHeaders() ); } catch (\Exception $e) { throw new ILSException($e->getMessage());