diff --git a/modules/roblib_search_eds/src/Lib/EBSCOAPI.php b/modules/roblib_search_eds/src/Lib/EBSCOAPI.php new file mode 100644 index 0000000..ed9faa4 --- /dev/null +++ b/modules/roblib_search_eds/src/Lib/EBSCOAPI.php @@ -0,0 +1,818 @@ + '', + 'AllFields' => '', + 'Abstract' => 'AB', + 'Author' => 'AU', + 'Source' => 'SO', + 'Subject' => 'SU', + 'Title' => 'TI', + 'ISBN' => 'IB', + 'ISSN' => 'IS', + ); + + + /** + * EBSCO sort options . + * + * @global array + */ + private static $sort_options = array( + 'relevance', + 'date', + 'date2', + 'source', + ); + + + /** + * VuFind sort types mapped to EBSCO sort types + * used for urls in Search results / Detailed view. + * + * @global array + */ + private static $mapped_sort_options = array( + '' => 'relevance', + 'relevance' => 'relevance', + 'subject' => 'date', + 'date' => 'date2', + 'date_asc' => 'date2', + 'date_desc' => 'date', + 'callnumber' => 'date', + 'author' => 'author', + 'title' => 'date', + ); + + /** + * Constructor. + * + * @param array config + * + * @access public + */ + public function __construct($config) { + $this->config = $config; + } + + /** + * Setter / Getter for authentication token. + * + * @param string The authentication token + * + * @return string or none + * + * @access public + */ + + + public function authenticationToken(){ + + $autocompleteTokenTimeOut = time(); + $authenticationTimeout = 0; + //$authenticationTimeout; + // $autocompleteUrl = ''; + // $token = ''; + // $timeout = ''; + // $autoToken = ''; + // //$autocompleteTokenTimeOut = ''; + // //$autocompleteTokenTimeOut; + // $autocompleteTokenTimeOut = 0; + // $autocompleteCustId =''; + + if (isset($_SESSION["authenticationToken"])){ + $token = $_SESSION["authenticationToken"]; + $authenticationTimeout = $_SESSION["authenticationTimeout"]-600; + $timeout = $_SESSION["authenticationTimeout"]; + $autocompleteUrl = $_SESSION["autocompleteUrl"]; + $autoToken = $_SESSION["autocompleteToken"]; + $autocompleteTokenTimeOut = $_SESSION["autocompleteTokenTimeOut"]; + $autocompleteCustId = $_SESSION["autocompleteCustId"]; + }else{ + $result = $this->apiAuthenticationToken(); + $_SESSION["authenticationToken"]= $result['authenticationToken']; + $_SESSION["authenticationTimeout"]= $result['authenticationTimeout']; + $_SESSION['autocompleteUrl'] = $result['autocompleteUrl']; + $_SESSION['autocompleteToken'] = $result['autocompleteToken']; + $_SESSION["autocompleteTokenTimeOut"]= $result['autocompleteTokenTimeOut']; + $_SESSION['autocompleteCustId'] = $result['autocompleteCustId']; + } + + if(time()-$autocompleteTokenTimeOut >= $authenticationTimeout){ + $result = $this->apiAuthenticationToken(); + $_SESSION["authenticationToken"]= $result['authenticationToken']; + $_SESSION["authenticationTimeout"]= $result['authenticationTimeout']; + $_SESSION['autocompleteUrl'] = $result['autocompleteUrl']; + $_SESSION['autocompleteToken'] = $result['autocompleteToken']; + $_SESSION["autocompleteTokenTimeOut"]= $result['autocompleteTokenTimeOut']; + $_SESSION['autocompleteCustId'] = $result['autocompleteCustId']; + + + + + $result = array( + 'authenticationToken' => $token, + 'authenticationTimeout' => $timeout, + 'autocompleteUrl' => $autocompleteUrl, + 'autocompleteToken' => $autoToken, + 'autocompleteTokenTimeOut' => $autocompleteTokenTimeOut, + 'autocompleteCustId' => $autocompleteCustId + ); + + return $result['authenticationToken']; + }else{ + return $this->token; + } + } + + /** + * Setter / Getter for session token. + * + * @param string The session token + * + * @return string or none + * + * @access public + */ + public function sessionToken($token = NULL) { + if (empty($token)) { + $token = $this->readSession('sessionToken'); + return !empty($token) ? $token : $this->sessionToken; + } + else { + $this->sessionToken = $token; + $this->writeSession('sessionToken', $token); + } + } + + /** + * Getter for isGuest. + * + * @param string 'y' or 'n' + * + * @return string or none + * + * @access public + */ + public function isGuest($boolean = NULL) { + if (empty($boolean)) { + return $this->readSession('isGuest'); + } + else { + $this->writeSession('isGuest', $boolean); + } + } + + /** + * Create a new EBSCOConnector object or reuse an existing one. + * + * @param none + * + * @return EBSCOConnector object + * + * @access public + */ + public function connector() { + if (empty($this->connector)) { + $this->connector = new EBSCOConnector($this->config); + } + return $this->connector; + } + + /** + * Create a new EBSCOResponse object. + * + * @param object $response + * + * @return EBSCOResponse object + * + * @access public + */ + public function response($response) { + $responseObj = new EBSCOResponse($response); + return $responseObj; + } + + /** + * Request authentication and session tokens, then send the API request. + * Retry the request if authentication errors occur. + * + * @param string $action + * The EBSCOConnector method name. + * @param array $params + * The parameters of the HTTP request. + * @param int $attempts + * The number of retries. + * + * @return object SimpleXml DOM or PEAR Error + * + * @access protected + */ + protected function request($action, $params = NULL, $attempts = 5) { + $authenticationToken = $this->authenticationToken(); + $sessionToken = $this->sessionToken(); + + // If authentication token is missing then the session token is missing too, so get both tokens + // If session token is missing then the authentication token may be invalid, so get both tokens. + if (empty($authenticationToken) || empty($sessionToken)) { + $result = $this->apiAuthenticationAndSessionToken(); + if ($this->isError($result)) { + // Any error should terminate the request immediately + // in order to prevent infinite recursion. + return $result; + } + } + + // Any change of the isGuest should request a new session + // (and don't terminate the current request if there was an error during the session request + // since it's not that important) + if ($this->isGuest() != $this->connector()->isGuest()) { + $this->apiSessionToken(); + } + + $headers = array( + 'x-authenticationToken: '.$this->authenticationToken(), + 'x-sessionToken: '.$this->sessionToken(), + ); + + $response = call_user_func_array(array($this->connector(), "request{$action}"), array($params, $headers)); + if ($this->isError($response)) { + // Retry the request if there were authentication errors. + $code = $response->getCode(); + switch ($code) { + // If authentication token is invalid then the session token is invalid too, so get both tokens + // If session token is invalid then the authentication token may be invalid too, so get both tokens. + case EBSCOConnector::EDS_AUTH_TOKEN_INVALID: + $result = $this->apiAuthenticationToken(); + if ($this->isError($result)) { + // Any error should terminate the request immediately + // in order to prevent infinite recursion. + return $result; + } + if ($attempts > 0) { + $result = $this->request($action, $params, --$attempts); + } + break; + + case EBSCOConnector::EDS_SESSION_TOKEN_INVALID: + $result = $this->apiAuthenticationAndSessionToken(); + if ($this->isError($result)) { + // Any error should terminate the request immediately + // in order to prevent infinite recursion. + return $result; + } + if ($attempts > 0) { + $result = $this->request($action, $params, --$attempts); + } + break; + + default: + $result = $this->handleError($response); + break; + } + } + else { + $result = $this->response($response)->result(); + } + + return $result; + } + + /** + * Wrapper for authentication API call. + * + * @param none + * + * @access public + */ + + public function apiAuthenticationToken() { + $response = $this->connector()->requestAuthenticationToken(); + $result = $this->response($response)->result(); + + return $result; + } + + /** + * Wrapper for session API call. + * + * @param none + * + * @access public + */ + public function apiSessionToken() { + // Add authentication tokens to headers. + $headers = array( + 'x-authenticationToken: '.$this->authenticationToken(), + ); + + $response = $this->connector()->requestSessionToken($headers); + // Raise the exception so that any code running this method should exit immediately. + if ($this->isError($response)) { + return $response; + } + else { + $result = $this->response($response)->result(); + if (is_string($result)) { + $this->sessionToken($result); + return $result; + } + else { + return new EBSCOException("No session token was found in the response."); + } + } + } + + /** + * Initialize the authentication and session tokens. + * + * @param none + * + * @access public + */ + public function apiAuthenticationAndSessionToken() { + $authenticationToken = $this->apiAuthenticationToken(); + if ($this->isError($authenticationToken)) { + // An authentication error should terminate the request immediately. + return $authenticationToken; + } + + $sessionToken = $this->apiSessionToken(); + if ($this->isError($sessionToken)) { + // A session error should terminate the request immediately. + return $sessionToken; + } + + // We don't have to return anything, both tokens can be accessed using the getters. + return TRUE; + } + + /** + * Wrapper for search API call. + * + * @param array $search + * The search terms. + * @param array $filters + * The facet filters. + * @param string $start + * The page to start with. + * @param string $limit + * The number of records to return. + * @param string $sortBy + * The value to be used by for sorting. + * @param string $amount + * The amount of data to be returned. + * @param string $mode + * The search mode. + * + * @throws object PEAR Error + * + * @return array An array of query results + * + * @access public + */ + public function apiSearch($search, + $filters, + $start = 1, + $limit = 10, + $sortBy = 'relevance', + $amount = 'detailed', + $mode = 'all', + $rs = FALSE, + $emp = FALSE, + $autosuggest = FALSE, + $includeimagequickview = FALSE, + $styles = '', + $IllustrationInfo = FALSE, + $autoComplete = FALSE + ) { + $query = array(); + + // Basic search. + if (!empty($search['lookfor'])) { + $lookfor = $search['lookfor']; + $type = isset($search['index']) && !empty($search['index']) ? $search['index'] : 'AllFields'; + + // Escape some characters from lookfor term. + $term = str_replace(array(',', ':', '(', ')'), array('\,', '\:', '\(', '\)'), $lookfor); + // Replace multiple consecutive empty spaces with one empty space. + $term = preg_replace("/\s+/", ' ', $term); + + // Search terms + // Complex search term. + if (preg_match('/(.*) (AND|OR) (.*)/i', $term)) { + $query['query'] = $term; + } + else { + $tag = self::$search_tags[$type]; + $op = 'AND'; + $query_str = implode(',', array($op, $tag)); + $query_str = implode(($tag ? ':' : ''), array($query_str, $term)); + $query['query-1'] = $query_str; + } + + // Advanced search. + } + elseif (!empty($search['group'])) { + + $counter = 1; + foreach ($search['group'] as $group) { + $type = $group['type']; + if (isset($group['lookfor'])) { + $term = $group['lookfor']; + $op = isset($group['bool'])?$group['bool']:"AND"; + $tag = $type && isset(self::$search_tags[$type]) ? self::$search_tags[$type] : ''; + + // Escape some characters from lookfor term. + $term = str_replace(array(',', ':', '(', ')'), array('\,', '\:', '\(', '\)'), $term); + // Replace multiple consecutive empty spaces with one empty space. + $term = preg_replace("/\s+/", ' ', $term); + if (!empty($term)) { + $query_str = implode(',', array($op, $tag)); + $query_str = implode(($tag ? ':' : ''), array($query_str, $term)); + $query["query-$counter"] = $query_str; + $counter++; + } + } + } + + // No search term, return an empty array. + } + else { + $results = array( + 'recordCount' => 0, + 'numFound' => 0, + 'start' => 0, + 'documents' => array(), + 'facets' => array(), + ); + return $results; + } + + // Add filters. + $limiters = array(); $expanders = array(); $facets = array(); + foreach ($filters as $filter) { + if (preg_match('/addlimiter/', $filter)) { + list($action, $str) = explode('(', $filter, 2); + // e.g. FT:y or GZ:Student Research, Projects and Publications. + $field_and_value = substr($str, 0, -1); + list($field, $value) = explode(':', $field_and_value, 2); + $limiters[$field][] = $value; + } + elseif (preg_match('/addexpander/', $filter)) { + list($action, $str) = explode('(', $filter, 2); + // Expanders don't have value. + $field = substr($str, 0, -1); + $expanders[] = $field; + } + elseif (preg_match('/addfacetfilter/', $filter)) { + list($action, $str) = explode('(', $filter, 2); + // e.g. ZG:FRANCE. + $field_and_value = substr($str, 0, -1); + list($field, $value) = explode(':', $field_and_value, 2); + $facets[$field][] = $field_and_value; + } + } + if (!empty($limiters)) { + $query['limiter']=''; + foreach ($limiters as $field => $limiter) { + // e.g. LA99:English,French,German. + $query['limiter'].= $field . ':' . implode(',', $limiter); + } + } + if (!empty($expanders)) { + // e.g. fulltext, thesaurus. + $query['expander'] = implode(',', $expanders); + } + if (!empty($facets)) { + $groupId = 1; + foreach ($facets as $field => $facet) { + // e.g. 1,DE:Math,DE:History. + $query['facetfilter'] = $groupId . ',' . implode(',', $facet); + $groupId += 1; + } + } + + // 2014-03-26 - new action to jump to page. + if ($start > 1) { + $query['action'] = "GoToPage(" . $start . ")"; + } + + // Add the sort option. + $sortBy = in_array($sortBy, self::$sort_options) ? $sortBy : self::$mapped_sort_options[$sortBy]; + + // Add the HTTP query params. + $params = array( + // Specifies the sort. Valid options are: + // relevance, date, date2 + // date = Date descending + // date2 = Date ascending. + 'sort' => $sortBy, + // Specifies the search mode. Valid options are: + // bool, any, all, smart. + 'searchmode' => $mode, + // Specifies the amount of data to return with the response + // Valid options are: + // title: Title only + // brief: Title + Source, Subjects + // detailed: Brief + full abstract. + 'view' => $amount, + // Specifies whether or not to include facets. + 'includefacets' => 'y', + 'resultsperpage' => $limit, + + // 2014-03-26 RF. + 'pagenumber' => $start, + // 'pagenumber' => 1, + // Specifies whether or not to include highlighting in the search results. + 'highlight' => 'y', + + + 'includeimagequickview' => $includeimagequickview, + + + 'format' => 'ris', + + 'styles' => $styles, + + + ); + + if ($autosuggest == TRUE) { + $params["autosuggest"] = "y"; + } + + if ($rs == TRUE) { + $params["relatedcontent"] = "rs"; + } + + if ($emp == TRUE) { + if (isset($params["relatedcontent"])) { + $params["relatedcontent"] .= ",emp"; + } + else { + $params["relatedcontent"] = "emp"; + } + } + + if ($includeimagequickview == TRUE) { + $params["includeimagequickview"] = "y"; + } + + if ($styles == 'all') { + $params["styles"] = "all"; + } + + if ($autoComplete == TRUE) { + $params["autocomplete"] = "y"; + } + + $params = array_merge($params, $query); + + + $result = $this->request('Search', $params); + + return $result; + } + + /** + * Wrapper for retrieve API call. + * + * @param array $an + * The accession number. + * @param string $start + * The short database name. + * + * @throws object PEAR Error + * + * @return array An associative array of data + * + * @access public + */ + public function apiRetrieve($an, $db) { + // Add the HTTP query params. + //$includeimagequickviewDetail = FALSE; + $params = array( + 'an' => $an, + 'dbid' => $db, + 'highlight' => 'y', + //'includeimagequickview' => $includeimagequickviewDetail, + //'IllustrationInfo' => 'y', + 'IllustrationInfo' => $IllustrationInfo, + 'format' => 'ris', + 'styles' => $styles, + ); + + $result = $this->request('Retrieve', $params); + + return $result; + + } + + + + public function apiExport($an, $db) { + + $params = array( + 'an' => $an, + 'dbid' => $db, + 'format' => 'ris' + ); + + $result = $this->request('Export', $params); + + return $result; + + } + + public function apiCitationStyles($an, $db, $styles) { + + $params = array( + 'an' => $an, + 'dbid' => $db, + 'styles' => $styles + ); + + $result = $this->request('CitationStyles', $params); + + return $result; + + } + + + /** + * Wrapper for info API call. + * + * @throws object PEAR Error + * + * @return array An associative array of data + * + * @access public + */ + public function apiInfo() { + if ($result = $this->readSession('info')) { + return $result; + } + $result = $this->request('Info'); + + if (!$this->isError($result)) { + $this->writeSession('info', $result); + } + return $result; + } + + public function apiAutoComplete(){ + if(self::$autocomplete == 'y'){ + // var_dump($autocomplete); + // die(); + return true; + } + else{ + return false; + } + } + + + /** + * Handle a PEAR_Error. Return : + * - if the error is critical : an associative array with the current error message + * - if the error is not critical : the error message . + * + * @param Pear_Error $exception + * + * @return array or the Pear_Error exception + * + * @access protected + */ + private function handleError($error) { + $errorCode = $error->getCode(); + switch ($errorCode) { + // This kind of error was generated by user , so display it to user. + case EBSCOConnector::EDS_INVALID_ARGUMENT_VALUE: + // Any other errors are system errors, don't display them to user. + default: + $errorMessage = 'An error occurred when getting the data.'; + break; + } + $result = array( + 'errors' => $errorMessage, + 'recordCount' => 0, + 'numFound' => 0, + 'start' => 0, + 'documents' => array(), + 'facets' => array(), + ); + return $result; + } + + /** + * Store the given object into session. + * + * @param string $key + * The key used for reading the value. + * @param object $value + * The object stored in session. + * + * @return none + * + * @access protected + */ + protected function writeSession($key, $value) { + if (!empty($key) && !empty($value)) { + $_SESSION['EBSCO'][$key] = $value; + } + } + + /** + * Read from session the object having the given key. + * + * @param string $key + * The key used for reading the object. + * + * @return object + * + * @access protected + */ + protected function readSession($key) { + $value = isset($_SESSION['EBSCO'][$key]) ? $_SESSION['EBSCO'][$key] : ''; + return $value; + } + + /** + * Check if given object is an EBSCOException object. + * + * @param object $object + * + * @return bool + * + * @access protected + */ + protected function isError($object) { + return is_a($object, 'EBSCOException'); + } + +} diff --git a/modules/roblib_search_eds/src/Lib/EBSCOConnector.php b/modules/roblib_search_eds/src/Lib/EBSCOConnector.php new file mode 100644 index 0000000..ae0d736 --- /dev/null +++ b/modules/roblib_search_eds/src/Lib/EBSCOConnector.php @@ -0,0 +1,577 @@ +password = $config['password']; + $this->userId = $config['user']; + $this->interfaceId = $config['interface']; + $this->profileId = $config['profile']; + $this->autoComplete = $config['autocomplete']; + $this->orgId = $config['organization']; + $this->local_ip_address = $config['local_ip_address']; + $this->isGuest = (\Drupal::currentUser()->isAuthenticated() || $this->isGuestIPAddress($_SERVER["REMOTE_ADDR"])) ? 'n' : 'y'; + $this->logAPIRequests = ($config['log'] == 1); + + } + + /** + * Detects if the user is authorized based on the IP address. + * + * @return string + */ + public function isGuestIPAddress($ipUser) { + $s = $this->local_ip_address; + + if (trim($s) == "") { + return FALSE; + } + // Break records. + $m = explode(",", $s); + + foreach ($m as $ip) { + if (strcmp(substr($ipUser, 0, strlen(trim($ip))), trim($ip)) == 0) { + // Inside of ip address range of customer. + return TRUE; + } + } + return FALSE; + } + + /** + * Public getter for private isGuest . + * + * @param none + * + * @return string isGuest + * + * @access public + */ + public function isGuest() { + return $this->isGuest; + } + + /** + * Request the authentication token. + * + * @param none + * + * @return object SimpleXml or PEAR_Error + * + * @access public + */ + public function requestAuthenticationToken() { + $url = self::$authentication_end_point . '/uidauth'; + + // Add the body of the request. + $params = '' + .''.$this->userId.'' + .''.$this->password.'' + .'wsapi' + .' + + ' + .''; + + $response = $this->request($url,$params, array(), 'POST'); + + return $response; + } + + /** + * Request the session token. + * + * @param array $headers + * Authentication token. + * + * @return object SimpleXml or PEAR_Error + * + * @access public + */ + public function requestSessionToken($headers) { + $url = self::$end_point . '/CreateSession'; + + // Add the HTTP query params. + $params = array( + 'profile' => $this->profileId, + 'org' => $this->orgId, + 'guest' => $this->isGuest + ); + + $response = $this->request($url, $params, $headers); + + return $response; + } + + /** + * Request the search records. + * + * @param array $params + * Search specific parameters. + * @param array $headers + * Authentication and session tokens. + * + * @return object SimpleXml or PEAR_Error + * + * @access public + */ + public function requestSearch($params, $headers) { + $url = self::$end_point . '/Search'; + + $response = $this->request($url, $params, $headers); + return $response; + } + + /** + * Request a specific record. + * + * @param array $params + * Retrieve specific parameters. + * @param array $headers + * Authentication and session tokens. + * + * @return object SimpleXml or PEAR_Error + * + * @access public + */ + public function requestRetrieve($params, $headers) { + $url = self::$end_point . '/Retrieve'; + + $response = $this->request($url, $params, $headers); + + return $response; + } + + /** + * Export a specific record. + * + * @param array $params + * Export specific parameters. + * @param array $headers + * Authentication and session tokens. + * + * @return object SimpleXml or PEAR_Error + * + * @access public + */ + public function requestExport($params, $headers) { + $url = self::$end_point . '/ExportFormat'; + + $response = $this->request($url, $params, $headers); + + return $response; + } + + /** + * CitationStyles a specific record. + * + * @param array $params + * CitationStyles specific parameters. + * @param array $headers + * Authentication and session tokens. + * + * @return object SimpleXml or PEAR_Error + * + * @access public + */ + public function requestCitationStyles($params, $headers) { + $url = self::$end_point . '/CitationStyles'; + + + $responseCitation = $this->request($url, $params, $headers); + $response = $responseCitation->Citations; + + return $response; + + } + + + /** + * Request the info data. + * + * @param null $params + * Not used. + * @param array $headers + * Authentication and session tokens. + * + * @return object SimpleXml or PEAR_Error + * + * @access public + */ + public function requestInfo($params, $headers) { + $url = self::$end_point . '/Info'; + + + $response = $this->request($url, $params, $headers); + return $response; + } + + /** + * Send an HTTP request and inspect the response. + * + * @param string $url + * The url of the HTTP request. + * @param array $params + * The parameters of the HTTP request. + * @param array $headers + * The headers of the HTTP request. + * @param array $body + * The body of the HTTP request. + * @param string $method + * The HTTP method, default is 'GET'. + * + * @return object SimpleXml or PEAR_Error + * + * @access protected + */ + protected function request($url, $params, $headers = array(), $method = 'GET') { + $xml = FALSE; + $return = FALSE; + $data = NULL; + + // Add compression in case its not there. + array_push($headers, 'Content-Type: text/xml'); + $data=$params; + // Send the request. + $response=null; + + + try { + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_MAXREDIRS, 10 ); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); + curl_setopt($curl, CURLOPT_TIMEOUT, 10); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + + switch ($method) + { + case 'GET': + if ($data) { $url = sprintf('%s?%s', $url, http_build_query($data)); } + curl_setopt($curl, CURLOPT_URL, $url); + break; + + case 'POST': + if ($data) { + curl_setopt($curl,CURLOPT_POST, 1); + curl_setopt($curl,CURLOPT_POSTFIELDS, $data); + } + break; + + case 'DELETE': + if ($data) { + if (count($headers)>0) { + curl_setopt($curl,CURLOPT_HTTPHEADER, $headers); + } + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE"); + } + break; + } + + + $response = curl_exec($curl); + $code = curl_getinfo($curl, CURLINFO_HTTP_CODE); + curl_close($curl); + + switch ($code) { + case self::HTTP_OK: + + $xml_str = $response; + + try { + // Clean EMP namespace. + $xml_str = str_replace(array("ErrorNumber) || isset($xml->ErrorCode); + if ($isError) { + $error = ''; $code = 0; + if (isset($xml->DetailedErrorDescription) && !empty($xml->DetailedErrorDescription)) { + $error = (string) $xml->DetailedErrorDescription; + } + elseif (isset($xml->ErrorDescription)) { + $error = (string) $xml->ErrorDescription; + } + elseif (isset($xml->Reason)) { + $error = (string) $xml->Reason; + } + if (isset($xml->ErrorNumber)) { + $code = (integer) $xml->ErrorNumber; + } + elseif (isset($xml->ErrorCode)) { + $code = (integer) $xml->ErrorCode; + } + $return = new EBSCOException($error, $code); + } + else { + $return = new EBSCOException("HTTP {$code} : The request could not be understood by the server due to malformed syntax. Modify your search before retrying."); + } + } + catch (Exception $e) { + $return = new EBSCOException($xml); + } + break; + + case self::HTTP_NOT_FOUND: + $return = new EBSCOException("HTTP {$code} : The resource you are looking for might have been removed, had its name changed, or is temporarily unavailable."); + break; + + case self::HTTP_INTERNAL_SERVER_ERROR: + $return = new EBSCOException("HTTP {$code} : The server encountered an unexpected condition which prevented it from fulfilling the request."); + break; + + default: + $return = new EBSCOException("HTTP {$code} : Unexpected HTTP error."); + break; + } + } + catch (Exception $e) { + // Or $this->toString($response) + $message = $this->toString($e); + \Drupal::logger('ebsco')->error($message); + $return = new EBSCOException($response); + } + + // Log any error + if ($this->logAPIRequests) { + // $client = both the HTTP request and response + // $response = only the HTTP response + $message = $this->toString($client); // or $this->toString($response) + \Drupal::logger('ebsco')->error($client); + } + + return $return; + } + + /** + * Capture the output of print_r into a string. + * + * @param object Any object + * + * @access private + */ + private function toString($object) { + ob_start(); + print_r($object); + return ob_get_clean(); + } + +} diff --git a/modules/roblib_search_eds/src/Lib/EBSCODocument.php b/modules/roblib_search_eds/src/Lib/EBSCODocument.php new file mode 100644 index 0000000..3ebc8c6 --- /dev/null +++ b/modules/roblib_search_eds/src/Lib/EBSCODocument.php @@ -0,0 +1,1050 @@ + 10, + 20 => 20, + 30 => 30, + 40 => 40, + 50 => 50, + ); + + /** + * Sort options + * global array. + */ + private static $sort_options = array( + 'relevance' => 'Relevance', + 'date_desc' => 'Date Descending', + 'date_asc' => 'Date Ascending', + ); + + /** + * Amount options + * global array. + */ + private static $amount_options = array( + 'detailed' => 'Detailed', + 'brief' => 'Brief', + 'title' => 'Title Only', + ); + + /** + * Bool options + * global array. + */ + private static $bool_options = array( + 'AND' => 'AND', + 'OR' => 'OR', + 'NOT' => 'NOT', + ); + + /** + * Search mode options + * global array. + */ + private static $mode_options = array( + 'all' => 'All search terms', + 'bool' => 'Boolean / Phrase', + 'any' => 'Any search terms', + 'smart' => 'SmartText Searching', + ); + + /** + * Basic search type options + * global array. + */ + private static $basic_search_type_options = array( + 'AllFields' => 'All Text', + 'Title' => 'Title', + 'Author' => 'Author', + 'Subject' => 'Subject terms', + 'Source' => 'Source', + 'Abstract' => 'Abstract', + ); + + /** + * Advanced search type options + * global array. + */ + private static $advanced_search_type_options = array( + 'AllFields' => 'All Text', + 'Title' => 'Title', + 'Author' => 'Author', + 'Subject' => 'Subject terms', + 'Source' => 'Journal Title/Source', + 'Abstract' => 'Abstract', + 'ISBN' => 'ISBN', + 'ISSN' => 'ISSN', + ); + + private $local_ips = ""; + + + /** + * PagerManager service object. + * + * @var \Drupal\Core\Pager\PagerManagerInterface + */ + private $pagerManager; + + /** + * Constructor. + * + * @param array $data + * Raw data from the EBSCO search representing the record. + */ + public function __construct($params = NULL) { + + $this->eds = new EBSCOAPI(array( + 'password' => \Drupal::config('ebsco.settings')->get('ebsco_password'), + 'user' => \Drupal::config('ebsco.settings')->get('ebsco_user'), + 'profile' => \Drupal::config('ebsco.settings')->get('ebsco_profile'), + 'interface' => \Drupal::config('ebsco.settings')->get('ebsco_interface'), + 'autocomplete' => \Drupal::config('ebsco.settings')->get('ebsco_autocomplete'), + 'organization' => \Drupal::config('ebsco.settings')->get('ebsco_organization'), + 'local_ip_address' => \Drupal::config('ebsco.settings')->get('ebsco_local_ips'), + 'guest' => \Drupal::config('ebsco.settings')->get('ebsco_guest'), + 'log' => \Drupal::config('ebsco.settings')->get('ebsco_log')?\Drupal::config('ebsco.settings')->get('ebsco_log'):false, + )); + + $this->params = $params ? $params : $_REQUEST; + + + $this->limit = \Drupal::config('ebsco.settings')->get('ebsco_default_limit') ? \Drupal::config('ebsco.settings')->get('ebsco_default_limit') : $this->limit; + + $this->amount = \Drupal::config('ebsco.settings')->get('ebsco_default_amount') ? \Drupal::config('ebsco.settings')->get('ebsco_default_amount') : $this->amount; + } + + /** + * Perform the API Info call. + * + * @return array + */ + public function info() { + $this->info = $this->eds->apiInfo(); + + return $this->info; + + + } + + /** + * Perform the API Retrieve call. + * + * @return array + */ + public function retrieve() { + list($an, $db) = isset($this->params['id']) ? explode('|', $this->params['id'], 2) : array(NULL, NULL); + $this->result = $this->eds->apiRetrieve($an, $db); + + return $this->result; + + } + + /** + * Perform the API Export call. + * + * @return array + */ + public function export() { + list($an, $db) = isset($this->params['id']) ? explode('|', $this->params['id'], 2) : array(NULL, NULL); + + $this->result = $this->eds->apiExport($an, $db, 'format=ris'); + + return $this->result; + + } + + /** + * Perform the API CitationStyles call. + * + * @return array + */ + public function citation() { + list($an, $db, $styles) = isset($this->params['id']) ? explode('|', $this->params['id'], 3) : array(NULL, NULL, NULL); + + $this->result = $this->eds->apiCitationStyles($an, $db, $styles); + + return $this->result; + + } + + public function autocomplete() { + $autocompleteUrl = ''; + $this->result = $this->eds->apiAuthenticationToken($autocompleteUrl); + return $this->result; + } + + /** + * Perform the API Search call. + * + * @return array + */ + public function search() { + $search = array(); + + if (isset($this->params['lookfor']) && isset($this->params['type'])) { + $search = array( + 'lookfor' => $this->params['lookfor'], + 'index' => $this->params['type'], + ); + + } + + elseif (isset($this->params['group'])) { + $search = $this->params; + + }else { + return array(); + } + + + + $filter = isset($this->params['filter']) ? $this->params['filter'] : array(); + $page = isset($this->params['page']) ? $this->params['page'] + 1 : 1; + $limit = $this->limit; + $sort = isset($this->params['sort']) ? $this->params['sort'] : 'relevance'; + $amount = isset($this->params['amount']) ? $this->params['amount'] : 'brief'; + $mode = isset($this->params['mode']) ? $this->params['mode'] : 'all'; + + // Check if research starters , EMP are active. + $info = $this->info(); + + if ($info instanceof EBSCOException) { + return array(); + } + $rs = FALSE; + $emp = FALSE; + + if (isset($info["relatedContent"])) { + foreach ($info["relatedContent"] as $related) { + if (($related["Type"] == "rs") and ($related["DefaultOn"] == "y")) { + $rs = TRUE; + } + if (($related["Type"] == "emp") and ($related["DefaultOn"] == "y")) { + $emp = TRUE; + } + } + } + $autosug = FALSE; + if (isset($info["didYouMean"])) { + if ($info["didYouMean"][0]["DefaultOn"] == "y") { + $autosug = TRUE; + } + } + + $iqv = FALSE; + if (isset($info["includeImageQuickView"])) { + + if ($info["includeImageQuickView"][0]["DefaultOn"] == "y") { + $iqv = TRUE; + } + } + + $stylesItem = ''; + if (isset($info["styles"])) { + + if ($info["styles"] == "all") { + $stylesItem = TRUE; + } + } + + $this->results = $this->eds->apiSearch($search, $filter, $page, $limit, $sort, $amount, $mode, $rs, $emp, $autosug, $iqv, $stylesItem); + + + return $this->results; + } + + /** + * Get the EBSCORecord model for the result. + * + * * @return array. + */ + public function record() { + if (empty($this->record) && !(empty($this->result))) { + $this->record = new EBSCORecord($this->result); + + } + + return $this->record; + } + + + + /** + * Get the EBSCORecord models array from results array. + * + * * @return array. + */ + public function records() { + if ($this->record instanceof EBSCOException) { + + return NULL; + } + if ($this->results instanceof EBSCOException) { + return NULL; + } + if (empty($this->records) && !empty($this->results)) { + $record_count = !empty($this->results) ? $this->results['recordCount'] : 0; + $_SESSION['search_total'] = $record_count; + foreach ($this->results['documents'] as $result) { + $this->records[] = new EBSCORecord($result); + } + } + + return $this->records; + } + + /** + * + */ + public function relatedContent() { + if ($this->results instanceof EBSCOException) { + return NULL; + } + $this->relatedContent = isset($this->results['relatedContent']) ? $this->results['relatedContent'] : array(); + + return $this->relatedContent; + } + + /** + * + */ + public function autoSuggestTerms() { + $this->autoSuggestTerms = isset($this->results['autoSuggestTerms']) ? $this->results['autoSuggestTerms'] : NULL; + return $this->autoSuggestTerms; + } + + + + + + public function imageQuickViewTerms() { + $this->imageQuickViewTerms = isset($this->results['imageQuickViewTerms']) ? $this->results['imageQuickViewTerms'] : NULL; + return $this->imageQuickViewTerms; + } + + public function citationStylesTerms() { + $this->citationStylesTerms = isset($this->results['citationStylesTerms']) ? $this->results['citationStylesTerms'] : NULL; + return $this->citationStylesTerms; + } + + + + /** + * Get the pagination HTML string. + * + * * @return HTML string. + */ + public function pager() { + $pager = NULL; + + try { + if (!empty($this->has_records())) { + + \Drupal::service('pager.manager')->createPager($this->record_count() / $this->limit, 1)->getCurrentPage(); + + $pageId = 1; + if (isset($_REQUEST["page"])) + { + if ($pageId>($this->record_count() * $this->limit)) + { + $pageId=(int)($this->record_count() * $this->limit); + } + else + { + $pageId=(int)urldecode($_REQUEST["page"]); + } + } + + + + $pagerVars = [ + '#type' => 'pager', + '#tags' => [], + '#route_name' => "ebsco.results", + '#parameters' => array(), + '#quantity' => self::$page_links + ]; + + $arrayExample = [ + '#type' => 'pager', + '#element' => 0, + '#parameters' => [], + '#quantity' => 5, + '#tags' => [], + '#route_name' => 'ebsco.results', + + ]; + + $renderer = \Drupal::service('renderer'); + $renderer->render($pagerVars); + + $pager = $pagerVars; + + + // remove last page navigation. Does not make sense in discovery navigation + $pi=@stripos((string)$pager,'
  • '); + if ($pi!==false) + { + $pf=stripos((string)$pager,'
  • ',$pi)-1; + $s=substr($pager,1,$pi-1).substr($pager,$pf+6,strlen($pager)-($pf+6)); + $pager=$s; + } + + } + + } + catch (Exception $e) { + } + return $pager; + } + + + + + /******************************************************** + * + * Getters (class methods) + * + ********************************************************/ + + /** + * Getter for sort options. + * + * @return array + */ + public static function limit_options() { + return self::$limit_options; + } + + /** + * Getter for sort options. + * + * @return array + */ + public static function sort_options() { + return self::$sort_options; + } + + /** + * Getter for amount options. + * + * @return array + */ + public static function amount_options() { + return self::$amount_options; + } + + /** + * Getter for boolean options. + * + * @return array + */ + public static function bool_options() { + return self::$bool_options; + } + + /** + * Getter for search mode options. + * + * @return array + */ + public static function mode_options() { + return self::$mode_options; + } + + /** + * Getter for Basic search type options. + * + * @return array + */ + public static function basic_search_type_options() { + return self::$basic_search_type_options; + } + + /** + * Getter for Advanced search type options. + * + * @return array + */ + public static function advanced_search_type_options() { + return self::$advanced_search_type_options; + } + + /******************************************************** + * + * Helper methods + * + ********************************************************/ + + /** + * Get the expanders. + * + * @return array + */ + public function expanders() { + $expanders = array(); + try { + if ($this->info instanceof EBSCOException) { + return $expanders; + } + $actions = array(); + $filters = $this->filters(); + foreach ($filters as $filter) { + $actions[] = $filter['action']; + } + + $expanders = isset($this->info['expanders']) ? $this->info['expanders'] : array(); + foreach ($expanders as $key => $expander) { + if (in_array($expander['Action'], $actions)) { + $expanders[$key]['selected'] = TRUE; + } + } + + } + catch (Exception $e) { + } + + return $expanders; + } + + /** + * Get the facets. + * + * @return array + */ + public function facets() { + if ($this->results instanceof EBSCOException) { + return array(); + } + + $actions = array(); + foreach ($this->filters as $filter) { + $actions[] = $filter['action']; + } + + $facets = isset($this->results['facets']) ? $this->results['facets'] : array(); + foreach ($facets as $key => $cluster) { + foreach ($cluster['Values'] as $k => $facet) { + $is_applied = FALSE; + if (in_array($facet['Action'], $actions)) { + $is_applied = TRUE; + } + $facets[$key]['Values'][$k]['applied'] = $is_applied; + } + } + + return $facets; + } + + /** + * Get the filters. + * + * @return array + */ + public function filters() { + if (!empty($_REQUEST['filter'])) { + $labels = array(); + foreach ($this->info['limiters'] as $limiter) { + $labels[$limiter['Id']] = $limiter['Label']; + } + $this->filters = array(); + foreach ($_REQUEST['filter'] as $filter) { + if (!empty($filter)) { + $temp = str_replace(array('addfacetfilter(', 'addlimiter(', 'addexpander('), array('', '', ''), $filter); + if (substr($temp, -1, 1) == ')') { + $temp = substr($temp, 0, -1); + } + // Do not display addfacetfilter, addlimiter or addexpander strings. + if (preg_match('/\:/', $filter)) { + list($field, $value) = explode(':', $temp, 2); + $displayField = isset($labels[$field]) ? $labels[$field] : $field; + $displayValue = $value == 'y' ? 'yes' : $value; + } + elseif (preg_match('/addexpander/', $filter)) { + $field = $temp; + $value = 'y'; + $displayField = isset($labels[$field]) ? $labels[$field] : $field; + $displayValue = 'yes'; + } + else { + $field = $value = $displayField = $displayValue = $filter; + } + + $this->filters[] = array( + 'field' => $field, + 'value' => $value, + 'action' => $filter, + 'displayField' => $displayField, + 'displayValue' => $displayValue, + ); + } + } + } + return $this->filters; + } + + /** + * Get the limiters. + * + * @return array + */ + public function limiters() { + $actions = array(); $ids = array(); + if ($this->info instanceof EBSCOException) { + return array(); + } + $filters = $this->filters(); + foreach ($filters as $filter) { + $actions[] = $filter['action']; + $ids[] = $filter['field']; + } + + $limiters = isset($this->info['limiters']) ? $this->info['limiters'] : array(); + foreach ($limiters as $key => $cluster) { + // Multi select limiter. + if (!empty($cluster['Values'])) { + foreach ($cluster['Values'] as $limiter) { + $action = $limiter['Action']; + if (in_array($action, $actions)) { + $limiters[$key]['selected'][] = $limiter['Action']; + } + } + // Date limiter. + } + elseif ($cluster['Type'] == 'ymrange') { + $id = $cluster['Id']; + if (($k = array_search($id, $ids)) !== FALSE) { + $limiters[$key]['selected'] = $filters[$k]['action']; + } + // Other limiters. + } + else { + $action = str_replace('value', 'y', $cluster['Action']); + if (in_array($action, $actions)) { + $limiters[$key]['selected'] = TRUE; + } + } + } + + return $limiters; + } + + /** + * Get the total number of records. + * + * @return int + */ + public function record_count() { + if ($this->results instanceof EBSCOException) { + return 0; + } + return !empty($this->results) ? $this->results['recordCount'] : 0; + } + + /** + * Get the number of end record. + * + * @return int + */ + public function record_end() { + if ($this->results instanceof EBSCOException) { + return -1; + } + $count = !empty($this->results) ? count($this->results['documents']) : 0; + $start = !empty($this->results) ? $this->results['start'] : 0; + return $start + $count; + } + + /** + * Get the number of start record. + * + * @return int + */ + public function record_start() { + if ($this->results instanceof EBSCOException) { + return NULL; + } + return !empty($this->results) ? $this->results['start'] + 1 : 0; + } + + /** + * Get the search time. + * + * @return decimal number + */ + public function search_time() { + if ($this->results instanceof EBSCOException) { + return 0; + } + return !empty($this->results) && + isset($this->results['searchTime']) ? $this->results['searchTime'] : 0; + } + + /** + * Get the search view : basic or advanced. + * + * @return string + */ + public function search_view() { + if (isset($_REQUEST['group'])) { + return 'advanced'; + } + else { + return 'basic'; + } + } + + /** + * Hidden params used by UpdateForm. + * + * @return array + */ + public function search_params() { + $params = $this->link_search_params(); + // Filter the params that have same values as sidebar checkboxes, otherwise they will produce duplicates. + $not_allowed_values = array( + 'addexpander(thesaurus)', + 'addexpander(fulltext)', + 'addlimiter(FT:y)', + 'addlimiter(RV:y)', + 'addlimiter(SO:y)', + ); + + $params = $this->array_filter_recursive($params, function ($item) use ($not_allowed_values) { + return !($item && in_array($item, $not_allowed_values)); + }); + + return array_filter($params); + } + + /** + * Hidden params used by UpdateForm. + * + * @return array + */ + public function link_search_params() { + // Filter the page parameter. + $not_allowed_keys = array('page', 'ui', 'has_js', 'op', 'submit', 'form_id', 'form_build_id'); + + $query = ""; + if (isset($_SERVER['QUERY_STRING'])) { + $query = urldecode($_SERVER['QUERY_STRING']); + } + parse_str($query, $params); + + $params = $this->array_unset_recursive($params, $not_allowed_keys); + + return $params; + } + + /** + * Check if there are records in results array. + * + * * @return boolean. + */ + public function has_records() { + if ($this->results instanceof EBSCOException) { + return FALSE; + } + return !empty($this->results) && !empty($this->results['documents']); + } + + /** + * Create the last search data. + * + * @return void + */ + public function search_create($query = NULL) { + if ($this->results instanceof EBSCOException) { + return array(); + } + $last_search = array(); + if (!empty($this->results)) { + $results_identifiers = array(); + foreach ($this->results['documents'] as $result) { + $results_identifiers[] = $result['id']; + } + $last_search['query'] = $query ? $query : $_SERVER['QUERY_STRING']; + $last_search['records'] = serialize($results_identifiers); + $last_search['count'] = $this->record_count(); + $_SESSION['count'] = $this->record_count(); + } + + return $last_search; + } + + /** + * Save last search data in session. + * + * @return void + */ + public function search_write($query = NULL) { + $_SESSION['EBSCO']['last-search'] = $this->search_create($query); + } + + /** + * Load last search data from session. + * + * @return array + */ + public function search_read($id = NULL, $op = NULL) { + $params = array(); + $lastSearchParams = $_SESSION['EBSCO']['redirect']['destination']; + if ($lastSearchParams) { + $lastSearch['records'] = $_SESSION['records']; + if ($id) { + + parse_str($lastSearchParams, $params); + $params['page'] = (int) (isset($params['page']) ? $params['page'] : 0); + // $index = array_search($id, $lastSearch['records']); + $index = $this->getIndexOfRecordInArrayWithId($lastSearch['records'], $id); + + // If this is not the first scroll and if this is not a page refresh. + if (isset($lastSearch['current']) && $lastSearch['current'] != $id) { + // If we change page. + if (($op == 'Next' && $index % $this->limit === 0) || + ($op == 'Previous' && $index % $this->limit === 9)) { + $params['page'] = ($op == 'Next') ? $params['page'] + 1 : $params['page'] - 1; + $query= \Drupal\Component\Utility\UrlHelper::buildQuery($params); + $lastSearch['query'] = $_SESSION['EBSCO']['last-search']['query'] = $query; + } + } + $start = $params['page']; + + if (count($lastSearch['records']) > 10) { + $records = array_slice($lastSearch['records'], $index - $index % $this->limit, $this->limit); + } + else { + $records = $lastSearch['records']; + } + + if (!isset($lastSearch['records'][$index + 1])) { + $params['page'] += 1; + $driver = new EBSCODocument($params); + $driver->search(); + $query= \Drupal\Component\Utility\UrlHelper::buildQuery($params); + $newSearch = $driver->search_create($query); + $newSearch['records'] = @unserialize($newSearch['records']); + $lastSearch['records'] = @array_merge($lastSearch['records'], $newSearch['records']); + $_SESSION['EBSCO']['last-search']['records'] = serialize($lastSearch['records']); + if ($op == 'Next') { + $lastSearch['previous'] = isset($records[8]) ? $records[8] : ''; + } + $lastSearch['next'] = isset($newSearch['records'][0]) ? $newSearch['records'][0] : ''; + } + else { + $lastSearch['next'] = $lastSearch['records'][$index + 1]; + } + + if (!isset($lastSearch['records'][$index - 1])) { + if ($params['page'] > 0) { + $params['page'] -= 1; + $driver = new EBSCODocument($params); + $driver->search(); + $query= \Drupal\Component\Utility\UrlHelper::buildQuery($params); + $newSearch = $driver->search_create($query); + $newSearch['records'] = @unserialize($newSearch['records']); + $lastSearch['records'] = @array_merge($lastSearch['records'], $newSearch['records']); + $_SESSION['EBSCO']['last-search']['records'] = serialize($lastSearch['records']); + $lastSearch['previous'] = isset($newSearch['records'][9]) ? $newSearch['records'][9] : ''; + if ($op == 'Previous') { + $lastSearch['next'] = isset($records[1]) ? $records[1] : ''; + } + } + else { + $lastSearch['previous'] = ''; + } + } + else { + $lastSearch['previous'] = $lastSearch['records'][$index - 1]; + } + + $lastSearch['current_index'] = $start * $this->limit + $index % $this->limit + 1; + $lastSearch['current'] = $id; + } + } + + $_SESSION['EBSCO']['last-search']['current'] = $id; + return $lastSearch; + } + + /** + * A recursive array_filter. + * + * @return array + */ + private function array_filter_recursive($input, $callback = NULL) { + foreach ($input as &$value) { + if (is_array($value)) { + $value = $this->array_filter_recursive($value, $callback); + } + } + return array_filter($input, $callback); + } + + /** + * Recursive filter an array using the given $keys. + * + * @return array + */ + private function array_unset_recursive($input, $keys) { + foreach ($keys as $key) { + if (isset($input[$key])) { + unset($input[$key]); + } + } + + if (is_array($input)) { + foreach ($input as $key => $value) { + $input[$key] = is_array($value) ? $this->array_unset_recursive($value, $keys) : $value; + } + } + + return array_filter($input); + } + + /** + * @param $array + * @param $value + * @return int|null|string + */ + private function getIndexOfRecordInArrayWithId($array, $value) { + foreach($array as $index=>$arrayInf) { + if($arrayInf->record_id == $value) { + return $index; + } + } + return null; + } + +} diff --git a/modules/roblib_search_eds/src/Lib/EBSCORecord.php b/modules/roblib_search_eds/src/Lib/EBSCORecord.php new file mode 100644 index 0000000..8909075 --- /dev/null +++ b/modules/roblib_search_eds/src/Lib/EBSCORecord.php @@ -0,0 +1,528 @@ +data = $data; + $this->record_id = $this->record_id(); + $this->result_id = $this->result_id(); + $this->title = $this->title(); + $this->summary = $this->summary(); + $this->authors = $this->authors(); + $this->subjects = $this->subjects(); + $this->custom_links = $this->custom_links(); + $this->db_label = $this->db_label(); + $this->full_text_availability = $this->full_text_availability(); + $this->full_text = $this->full_text(); + $this->items = $this->items(); + $this->p_link = $this->p_link(); + $this->publication_type = $this->publication_type(); + $this->pdf_availability = $this->pdf_availability(); + $this->pdf_link = $this->pdf_link(); + $this->small_thumb_link = $this->thumb_link(); + $this->medium_thumb_link = $this->thumb_link('medium'); + $this->source = $this->source(); + $this->access_level = $this->access_level(); + $this->image_quick_view = $this->image_quick_view(); + $this->image_quick_view_type_2 = $this->image_quick_view_type_2(); + $this->image_quick_url = $this->image_quick_url(); + $this->illustrationinfo = $this->illustrationinfo(); + $this->type = $this->type(); + $this->cite = $this->cite(); + $this->permission = $this->permission(); + $this->imgtitle = $this->imgtitle(); + $this->citationStylesRecord = $this->citationStylesRecord(); + + + } + + + + /******************************************************** + * + * Getters + * + ********************************************************/ + + /** + * Get the summary of the record. + * + * @return string + */ + public function access_level() { + return isset($this->data['AccessLevel']) ? + $this->data['AccessLevel'] : ''; + } + + /** + * Get the summary of the record. + * + * @return string + */ + public function summary() { + return isset($this->data['Items']['Abstract']) ? + $this->data['Items']['Abstract']['Data'] : ''; + } + + /** + * Get the authors of the record. + * + * @return string + */ + public function authors() { + return isset($this->data['Items']['Author']) ? + $this->data['Items']['Author']['Data'] : ''; + } + + /** + * Get the custom links of the record. + * + * @return array + */ + public function custom_links() { + return isset($this->data['CustomLinks']) ? + $this->data['CustomLinks'] : array(); + } + + /** + * Get the database label of the record. + * + * @return string + */ + public function db_label() { + return isset($this->data['DbLabel']) ? + $this->data['DbLabel'] : ''; + } + + /** + * Get the full text availability of the record. + * + * @return bool + */ + public function full_text() { + return isset($this->data['FullText']) && + isset($this->data['FullText']['Value']) ? $this->data['FullText']['Value'] : ''; + } + + /** + * Get the full text availability of the record. + * + * @return bool + */ + public function full_text_availability() { + return isset($this->data['FullText']) && + $this->data['FullText']['Availability']; + } + + /** + * Get the items of the record. + * + * @return array + */ + public function items() { + return isset($this->data['Items']) ? $this->data['Items'] : array(); + } + + /** + * Get the external url of the record. + * + * @return string + */ + public function p_link() { + return isset($this->data['PLink']) ? $this->data['PLink'] : ''; + } + + /** + * Get the publication type of the record. + * + * @return string + */ + public function publication_type() { + return isset($this->data['PubType']) ? $this->data['PubType'] : ''; + } + + /** + * Get the PDF availability of the record. + * + * @return bool + */ + public function pdf_availability() { + return isset($this->data['FullText']) && + isset($this->data['FullText']['Links']) && + isset($this->data['FullText']['Links']['pdflink']) && + $this->data['FullText']['Links']['pdflink']; + } + + /** + * Get the PDF url of the record. + * + * @return string + */ + public function pdf_link() { + return isset($this->data['FullText']) && + isset($this->data['FullText']['Links']) && + isset($this->data['FullText']['Links']['pdflink']) ? + $this->data['FullText']['Links']['pdflink'] : + ''; + } + + /** + * Get the result id of the record. + * + * @return int + */ + public function result_id() { + return isset($this->data['ResultId']) ? + $this->data['ResultId'] : ''; + } + + /** + * Get the subject data of the record. + * + * @return string + */ + public function subjects() { + return isset($this->data['Items']['Subject']) ? + $this->data['Items']['Subject']['Data'] : ''; + } + + /** + * Return a URL to a thumbnail preview of the record, if available; false + * otherwise. + * + * @param string $size + * Size of thumbnail (small, medium or large -- small is + * default). + * + * @return string + */ + public function thumb_link($size = 'small') { + $imageInfo = isset($this->data['ImageInfo']) ? $this->data['ImageInfo'] : ''; + if ($imageInfo && isset($imageInfo['thumb'])) { + switch ($size) { + case 'large': + case 'medium': + return $imageInfo['medium']; + + break; + + case 'small': + default: + return $imageInfo['thumb']; + + break; + } + } + return FALSE; + } + + /** + * Get the title of the record. + * + * @return string + */ + public function title() { + return isset($this->data['Items']['Title']) ? + $this->data['Items']['Title']['Data'] : ''; + } + + /** + * Get the source of the record. + * + * @return string + */ + public function source() { + return isset($this->data['Items']['TitleSource']) ? + $this->data['Items']['TitleSource']['Data'] : ''; + } + + /** + * Return the identifier of this record within the EBSCO databases. + * + * @return string Unique identifier. + */ + public function record_id() { + return isset($this->data['id']) ? + $this->data['id'] : ''; + } + + /** + * Get the image quick view of the record. + * + * @return string + */ + + public function image_quick_view() { + return isset($this->data['iqv']) ? $this->data['iqv'] : array(); + } + + public function image_quick_url() { + return isset($this->data['iqv']) ? $this->data['iqv'] : array(); + + } + + + public function image_quick_view_type_2() { + return isset($this->data['ImageQuickViewItems']) && + isset($this->data['ImageQuickViewItems']['iqv']) && + isset($this->data['ImageQuickViewItems']['iqv']['DbId']) && + isset($this->data['ImageQuickViewItems']['iqv']['An']) && + isset($this->data['ImageQuickViewItems']['iqv']['Type']) && + isset($this->data['ImageQuickViewItems']['iqv']['Url']) ? + $this->data['ImageQuickViewItems']['iqv']['DbId']['An']['Type']['Url'] : ''; + } + + public function illustrationinfo() { + return isset($this->data['IllustrationInfo'][0]) ? $this->data['IllustrationInfo'][0] : array(); + } + + + public function type() { + + return isset($this->data['Items']['type']) ? + $this->data['Items']['type'] : ''; + } + + public function cite() { + return isset($this->data['Items']['Cite']) ? + $this->data['Items']['Cite'] : ''; + } + + public function permission() { + return isset($this->data['Items']['Permission']) ? + $this->data['Items']['Permission'] : ''; + } + + + public function imgtitle() { + return isset($this->data['Items']['imgTitle']) ? + $this->data['Items']['imgTitle'] : ''; + } + + public function citationStylesRecord() { + return isset($this->data['Citation']) ? $this->data['Citation'] : array(); + + } + +} diff --git a/modules/roblib_search_eds/src/Lib/EBSCOResponse.php b/modules/roblib_search_eds/src/Lib/EBSCOResponse.php new file mode 100644 index 0000000..ba3f6b9 --- /dev/null +++ b/modules/roblib_search_eds/src/Lib/EBSCOResponse.php @@ -0,0 +1,1036 @@ +response = $response; + + } + + /** + * Returns the XML as an associative array of data. + * + * @param none + * + * @return array An associative array of data + * + * @access public + */ + public function result() + { + + if (!empty($this->response->AuthToken)) { + return $this->buildAuthenticationToken(); + } elseif (!empty($this->response->SessionToken)) { + return (string) $this->response->SessionToken; + } elseif (!empty($this->response->AutocompleteToken)) { + return (string) $this->response->AutocompleteToken; + } elseif (!empty($this->response->SearchResult)) { + return $this->buildSearch(); + + } elseif (!empty($this->response->Record)) { + return $this->buildRetrieve(); + } elseif (!empty($this->response->AvailableSearchCriteria)) { + return $this->buildInfo(); + } elseif (!empty($this->response->Format) && $this->response->Format == 'RIS') { + return $this->response->Data; + } elseif (!empty($this->response)) { + return $this->buildCitationStyles(); + + } + // Should not happen, it may be an exception. + else { + + return $this->response; + } + + } + + /** + * Parse the SimpleXml object when an AuthenticationToken API call was executed. + * + * @param none + * + * @return array An associative array of data + * + * @access private + */ + private function buildAuthenticationToken() + { + $token = (string) $this->response->AuthToken; + $timeout = (integer) $this->response->AuthTimeout; + $autocompleteUrl = (string) $this->response->Autocomplete->Url; + $autoToken = (string) $this->response->Autocomplete->Token; + $autocompleteTokenTimeOut = (integer) $this->response->Autocomplete->TokenTimeOut; + $autocompleteCustId = (string) $this->response->Autocomplete->CustId; + + $result = array( + 'authenticationToken' => $token, + 'authenticationTimeout' => $timeout, + 'autocompleteUrl' => $autocompleteUrl, + 'autocompleteToken' => $autoToken, + 'autocompleteTokenTimeOut' => $autocompleteTokenTimeOut, + 'autocompleteCustId' => $autocompleteCustId, + ); + + return $result; + } + + /** + * Parse a SimpleXml object and + * return it as an associative array. + * + * @param none + * + * @return array An associative array of data + * + * @access private + */ + private function buildSearch() + { + $hits = (integer) $this->response->SearchResult->Statistics->TotalHits; + $searchTime = (integer) $this->response->SearchResult->Statistics->TotalSearchTime / 1000; + $records = array(); + $facets = array(); + if ($hits > 0) { + $records = $this->buildRecords(); + $facets = $this->buildFacets(); + } + + // Research Starters & emp. + $relatedC = null; + if ($this->response->SearchResult->RelatedContent) { + $result = json_decode(json_encode($this->response->SearchResult->RelatedContent), true); + $relatedC = $result; + } + + // Did you mean / auto suggest. + $autoSuggestTerms = null; + if ($this->response->SearchResult->AutoSuggestedTerms) { + $result = json_decode(json_encode($this->response->SearchResult->AutoSuggestedTerms), true); + $autoSuggestTerms = $result; + } + + //quickimageview + $imageQuickViewTerms = null; + if ($this->response->SearchResult->imageQuickViewedTerms) { + $result = json_decode(json_encode($this->response->SearchResult->imageQuickViewedTerms), true); + $imageQuickViewTerms = $result; + } + + $citationStylesTerms = null; + if ($this->response->SearchResult->citationStylesTerms) { + $result = json_decode(json_encode($this->response->SearchResult->citationStylesTerms), true); + $citationStylesTerms = $result; + } + + $results = array( + 'recordCount' => $hits, + 'searchTime' => $searchTime, + 'numFound' => $hits, + 'start' => 0, + 'documents' => $records, + 'relatedContent' => $relatedC, + 'autoSuggestTerms' => $autoSuggestTerms, + 'facets' => $facets, + 'imageQuickViewTerms' => $imageQuickViewTerms, + 'citationStylesTerms' => $citationStylesTerms, + ); + + return $results; + } + + /** + * Parse a SimpleXml object and + * return it as an associative array. + * + * @param none + * + * @return array An associative array of data + * + * @access private + */ + private function buildRecords() { + + $results = array(); + $records = $this->response->SearchResult->Data->Records->Record; + foreach ($records as $record) { + $result = array(); + $result['ResultId'] = $record->ResultId ? (integer) $record->ResultId : ''; + $result['DbId'] = $record->Header->DbId ? (string) $record->Header->DbId : ''; + $result['DbLabel'] = $record->Header->DbLabel ? (string) $record->Header->DbLabel : ''; + $result['An'] = $record->Header->An ? (string) $record->Header->An : ''; + $result['PubType'] = $record->Header->PubType ? (string) $record->Header->PubType : ''; + $result['AccessLevel'] = $record->Header->AccessLevel ? (string) $record->Header->AccessLevel : ''; + $result['id'] = $result['An'] . '|' . $result['DbId']; + $result['PLink'] = $record->PLink ? (string) $record->PLink : ''; + + if (!empty($record->ImageInfo->CoverArt)) { + foreach ($record->ImageInfo->CoverArt as $image) { + $size = (string) $image->Size; + $target = (string) $image->Target; + $result['ImageInfo'][$size] = $target; + } + } else { + $result['ImageInfo'] = ''; + } + + if ($record->FullText) { + + $availability = (integer) $record->FullText->Text->Availability == 1; + $links = array(); + // RF 2012-12-18. + if (isset($record->FullText->Links)) { + foreach ($record->FullText->Links->Link as $link) { + $type = (string) $link->Type; + $url = (string) $link->Url; + // If we have an empty url when type is pdflink then just return something so + // that the UI check for empty string will pass. + $url = empty($url) && $type == 'pdflink' ? 'https://content.ebscohost.com' : $url; + $links[$type] = $url; + } + } + $result['FullText'] = array( + 'Availability' => $availability, + 'Links' => $links, + ); + } + + if ($record->CustomLinks) { + + $result['CustomLinks'] = array(); + foreach ($record->CustomLinks->CustomLink as $customLink) { + $category = $customLink->Category ? (string) $customLink->Category : ''; + $icon = $customLink->Icon ? (string) $customLink->Icon : ''; + $mouseOverText = $customLink->MouseOverText ? (string) $customLink->MouseOverText : ''; + $name = $customLink->Name ? (string) $customLink->Name : ''; + $text = $customLink->Text ? (string) $customLink->Text : ''; + $url = $customLink->Url ? (string) $customLink->Url : ''; + $result['CustomLinks'][] = array( + 'Category' => $category, + 'Icon' => $icon, + 'MouseOverText' => $mouseOverText, + 'Name' => $name, + 'Text' => $text, + 'Url' => $url, + ); + } + } + + if ($record->Items) { + $result['Items'] = array(); + foreach ($record->Items->Item as $item) { + $name = $item->Name ? (string) $item->Name : ''; + $label = $item->Label ? (string) $item->Label : ''; + $group = $item->Group ? (string) $item->Group : ''; + $data = $item->Data ? (string) $item->Data : ''; + $result['Items'][$name] = array( + 'Name' => $name, + 'Label' => $label, + 'Group' => $group, + 'Data' => $this->toHTML($data, $group), + ); + } + } + + if ($record->RecordInfo) { + $result['RecordInfo'] = array(); + $result['RecordInfo']['BibEntity'] = array( + 'Identifiers' => array(), + 'Languages' => array(), + 'PhysicalDescription' => array(), + 'Subjects' => array(), + 'Titles' => array(), + ); + + if ($record->RecordInfo->BibRecord->BibEntity->Identifiers) { + foreach ($record->RecordInfo->BibRecord->BibEntity->Identifiers->Identifier as $identifier) { + $type = $identifier->Type ? (string) $identifier->Type : ''; + $value = $identifier->Value ? (string) $identifier->Value : ''; + $result['RecordInfo']['BibEntity']['Identifiers'][] = array( + 'Type' => $type, + 'Value' => $value, + ); + } + } + + if ($record->RecordInfo->BibRecord->BibEntity->Languages) { + foreach ($record->RecordInfo->BibRecord->BibEntity->Languages->Language as $language) { + $code = $language->Code ? (string) $language->Code : ''; + $text = $language->Text ? (string) $language->Text : ''; + $result['RecordInfo']['BibEntity']['Languages'][] = array( + 'Code' => $code, + 'Text' => $text, + ); + } + } + + if ($record->RecordInfo->BibRecord->BibEntity->PhysicalDescription) { + $pageCount = $record->RecordInfo->BibRecord->BibEntity->PhysicalDescription->Pagination->PageCount ? (string) $record->RecordInfo->BibRecord->BibEntity->PhysicalDescription->Pagination->PageCount : ''; + $startPage = $record->RecordInfo->BibRecord->BibEntity->PhysicalDescription->Pagination->StartPage ? (string) $record->RecordInfo->BibRecord->BibEntity->PhysicalDescription->Pagination->StartPage : ''; + $result['RecordInfo']['BibEntity']['PhysicalDescription']['Pagination'] = $pageCount; + $result['RecordInfo']['BibEntity']['PhysicalDescription']['StartPage'] = $startPage; + } + + if ($record->RecordInfo->BibRecord->BibEntity->Subjects) { + foreach ($record->RecordInfo->BibRecord->BibEntity->Subjects->Subject as $subject) { + $subjectFull = $subject->SubjectFull ? (string) $subject->SubjectFull : ''; + $type = $subject->Type ? (string) $subject->Type : ''; + $result['RecordInfo']['BibEntity']['Subjects'][] = array( + 'SubjectFull' => $subjectFull, + 'Type' => $type, + ); + } + } + + if ($record->RecordInfo->BibRecord->BibEntity->Titles) { + foreach ($record->RecordInfo->BibRecord->BibEntity->Titles->Title as $title) { + $titleFull = $title->TitleFull ? (string) $title->TitleFull : ''; + $type = $title->Type ? (string) $title->Type : ''; + $result['RecordInfo']['BibEntity']['Titles'][] = array( + 'TitleFull' => $titleFull, + 'Type' => $type, + ); + } + } + + $result['RecordInfo']['BibRelationships'] = array( + 'HasContributorRelationships' => array(), + 'IsPartOfRelationships' => array(), + ); + + if (isset($record->RecordInfo->BibRecord->BibRelationships->HasContributorRelationships)) { + foreach ($record->RecordInfo->BibRecord->BibRelationships->HasContributorRelationships->HasContributor as $contributor) { + $nameFull = $contributor->PersonEntity->Name->NameFull ? + (string) $contributor->PersonEntity->Name->NameFull : ''; + + $result['RecordInfo']['BibRelationships']['HasContributorRelationships'][] = array( + 'NameFull' => $nameFull, + ); + + } + } + + if ($record->RecordInfo->BibRecord->BibRelationships) { + foreach ($record->RecordInfo->BibRecord->BibRelationships->IsPartOfRelationships->IsPartOf as $relationship) { + if ($relationship->BibEntity->Dates) { + foreach ($relationship->BibEntity->Dates->Date as $date) { + $d = $date->D ? (string) $date->D : ''; + $m = $date->M ? (string) $date->M : ''; + $type = $date->Type ? (string) $date->Type : ''; + $y = $date->Y ? (string) $date->Y : ''; + $result['RecordInfo']['BibRelationships']['IsPartOfRelationships']['date'][] = array( + 'D' => $d, + 'M' => $m, + 'Type' => $type, + 'Y' => $y, + ); + } + } + + if ($relationship->BibEntity->Identifiers) { + foreach ($relationship->BibEntity->Identifiers->Identifier as $identifier) { + $type = $identifier->Type ? (string) $identifier->Type : ''; + $value = $identifier->Value ? (string) $identifier->Value : ''; + $result['RecordInfo']['BibRelationships']['IsPartOfRelationships']['Identifiers'][] = array( + 'Type' => $type, + 'Value' => $value, + ); + } + } + + if ($relationship->BibEntity->Titles) { + foreach ($relationship->BibEntity->Titles->Title as $title) { + $titleFull = $title->TitleFull ? (string) $title->TitleFull : ''; + $type = $title->Type ? (string) $title->Type : ''; + $result['RecordInfo']['BibRelationships']['IsPartOfRelationships']['Titles'][] = array( + 'TitleFull' => $titleFull, + 'Type' => $type, + ); + } + } + + if ($relationship->BibEntity->Numbering) { + foreach ($relationship->BibEntity->Numbering->Number as $number) { + $type = (string) $number->Type; + $value = (string) $number->Value; + $result['RecordInfo']['BibRelationships']['IsPartOfRelationships']['numbering'][] = array( + 'Type' => $type, + 'Value' => $value, + ); + } + } + + } + } + } + + if ($record->ImageQuickViewItems->ImageQuickViewItem) { + $result['iqv'] = array(); + foreach ($record->ImageQuickViewItems->ImageQuickViewItem as $iqv) { + $dbid = $iqv->DbId ? (string) $iqv->DbId : ''; + $an = $iqv->An ? (string) $iqv->An : ''; + $type = $iqv->Type ? (string) $iqv->Type : ''; + $url = $iqv->Url ? (string) $iqv->Url : ''; + $result['iqv'][] = array( + 'DbId' => $dbid, + 'An' => $an, + 'Type' => $type, + 'Url' => $url, + ); + } + } + + $results[] = $result; + + } + + return $results; + + } + + /** + * Parse a SimpleXml object and + * return it as an associative array. + * + * @param none + * + * @return array An associative array of data + * + * @access private + */ + private function buildFacets() + { + $results = array(); + if(!empty($facets = $this->response->SearchResult->AvailableFacets->AvailableFacet)) { + if ($facets) { + foreach ($facets as $facet) { + $values = array(); + foreach ($facet->AvailableFacetValues->AvailableFacetValue as $value) { + $this_value = (string) $value->Value; + $this_value = str_replace(array('\(', '\)'), array('(', ')'), $this_value); + $this_action = (string) $value->AddAction; + $this_action = str_replace(array('\(', '\)'), array('(', ')'), $this_action); + $values[] = array( + 'Value' => $this_value, + 'Action' => $this_action, + 'Count' => (string) $value->Count, + ); + } + $id = (string) $facet->Id; + $label = (string) $facet->Label; + if (!empty($label)) { + $results[] = array( + 'Id' => $id, + 'Label' => $label, + 'Values' => $values, + 'isApplied' => false, + ); + } + } + } + } + + + return $results; + } + + /** + * Parse a SimpleXml object and + * return it as an associative array. + * + * @param none + * + * @return array An associative array of data + * + * @access private + */ + private function buildInfo() { + // Sort options. + $sort = array(); + $elements = $this->response->AvailableSearchCriteria->AvailableSorts->AvailableSort; + foreach ($elements as $element) { + $sort[] = array( + 'Id' => (string) $element->Id, + 'Label' => (string) $element->Label, + 'Action' => (string) $element->AddAction, + ); + } + + + // Search fields. + $tags = array(); + $elements = $this->response->AvailableSearchCriteria->AvailableSearchFields->AvailableSearchField; + foreach ($elements as $element) { + $tags[] = array( + 'Label' => (string) $element->Label, + 'Code' => (string) $element->FieldCode, + ); + } + + + $expanders = array(); + // Expanders. + $elements = $this->response->AvailableSearchCriteria->AvailableExpanders->AvailableExpander; + foreach ($elements as $element) { + $expanders[] = array( + 'Id' => (string) $element->Id, + 'Label' => (string) $element->Label, + 'Action' => (string) $element->AddAction, + // Added because of the checkboxes. + 'selected' => false, + ); + } + + + + + // RelatedContent. + // add !empty to check bug + $relatedContent = array(); + $elements = $this->response->AvailableSearchCriteria->AvailableRelatedContent->AvailableRelatedContent; + $elementsRelatedContent = $this->response->AvailableSearchCriteria->AvailableRelatedContent->AvailableRelatedContent; + + foreach ($elementsRelatedContent as $element) { + $relatedContent[] = array( + 'Type' => (string) $element->Type, + 'Label' => (string) $element->Label, + 'Action' => (string) $element->AddAction, + 'DefaultOn' => (string) $element->DefaultOn, + ); + } + $relatedContent = array(); + $elements = $this->response->AvailableSearchCriteria->AvailableRelatedContent->AvailableRelatedContent; + + foreach ($elements as $element) { + $relatedContent[] = array( + 'Type' => (string) $element->Type, + 'Label' => (string) $element->Label, + 'Action' => (string) $element->AddAction, + 'DefaultOn' => (string) $element->DefaultOn, + ); + } + + + + + + // Did you mean. + $didYouMean = array(); + $elements = $this->response->AvailableSearchCriteria->AvailableDidYouMeanOptions->AvailableDidYouMeanOption; + foreach ($elements as $element) { + $didYouMean[] = array( + 'Id' => (string) $element->Id, + 'Label' => (string) $element->Label, + 'DefaultOn' => (string) $element->DefaultOn, + ); + } + + + + //ImageQuickView + $includeImageQuickView = array(); + $elements = $this->response->AvailableIncludeImageQuickView->IncludeImageQuickViewOptions->IncludeImageQuickViewOption; + foreach ($this->response->ViewResultSettings->IncludeImageQuickView as $element) { + $includeImageQuickView[] = array( + 'Label' => (string) $element->Label, + 'Id' => (string) $element->Id, + 'DefaultOn' => (string) $element->DefaultOn, + ); + } + + + + // Limiters. + $limiters = array(); + $values = array(); + $elements = $this->response->AvailableSearchCriteria->AvailableLimiters->AvailableLimiter; + foreach ($elements as $element) { + if ($element->LimiterValues) { + $items = $element->LimiterValues->LimiterValue; + foreach ($items as $item) { + $values[] = array( + 'Value' => (string) $item->Value, + 'Action' => (string) $item->AddAction, + // Added because of the checkboxes. + 'selected' => false, + ); + } + } + $limiters[] = array( + 'Id' => (string) $element->Id, + 'Label' => (string) $element->Label, + 'Action' => (string) $element->AddAction, + 'Type' => (string) $element->Type, + 'Values' => $values, + 'selected' => false, + ); + } + + + + $result = array( + 'sort' => $sort, + 'tags' => $tags, + 'expanders' => $expanders, + 'limiters' => $limiters, + 'relatedContent' => $relatedContent, + 'didYouMean' => $didYouMean, + 'includeImageQuickView' => $includeImageQuickView, + ); + + return $result; + + } + + /** + * Parse a SimpleXml object and + * return it as an associative array. + * + * @param none + * + * @return array An associative array of data + * + * @access private + */ + private function buildRetrieve() + { + + $record = $this->response->Record; + + if ($record) { + // There is only one record. + $record = $record[0]; + } + + $result = array(); + $result['DbId'] = $record->Header->DbId ? (string) $record->Header->DbId : ''; + $result['DbLabel'] = $record->Header->DbLabel ? (string) $record->Header->DbLabel : ''; + $result['An'] = $record->Header->An ? (string) $record->Header->An : ''; + $result['id'] = $result['An'] . '|' . $result['DbId']; + $result['PubType'] = $record->Header->PubType ? (string) $record->Header->PubType : ''; + $result['AccessLevel'] = $record->Header->AccessLevel ? (string) $record->Header->AccessLevel : ''; + $result['PLink'] = $record->PLink ? (string) $record->PLink : ''; + $result['IllustrationInfo'] = $record->IllustrationInfo ? (string) $record->IllustrationInfo : ''; + $result['Type'] = $record->ImageQuickViewItems->Type ? (string) $record->ImageQuickViewItems->Type : ''; + + if (!empty($record->ImageInfo->CoverArt)) { + foreach ($record->ImageInfo->CoverArt as $image) { + $size = (string) $image->Size; + $target = (string) $image->Target; + $result['ImageInfo'][$size] = $target; + } + } else { + $result['ImageInfo'] = ''; + } + + if ($record->FullText) { + $availability = (integer) ($record->FullText->Text->Availability) == 1; + $links = array(); + if (isset($record->FullText->Links->Link)) { + + foreach ($record->FullText->Links->Link as $link) { + $type = (string) $link->Type; + $url = (string) $link->Url; + // If we have an empty url when type is pdflink then just return something so + // that the UI check for empty string will pass. + $url = empty($url) && $type == 'pdflink' ? 'https://content.ebscohost.com' : $url; + $links[$type] = $url; + } + } + $value = $this->toHTML($record->FullText->Text->Value); + $result['FullText'] = array( + 'Availability' => $availability, + 'Links' => $links, + 'Value' => $value, + ); + } + + if ($record->CustomLinks) { + $result['CustomLinks'] = array(); + foreach ($record->CustomLinks->CustomLink as $customLink) { + $category = $customLink->Category ? (string) $customLink->Category : ''; + $icon = $customLink->Icon ? (string) $customLink->Icon : ''; + $mouseOverText = $customLink->MouseOverText ? (string) $customLink->MouseOverText : ''; + $name = $customLink->Name ? (string) $customLink->Name : ''; + $text = $customLink->Text ? (string) $customLink->Text : ''; + $url = $customLink->Url ? (string) $customLink->Url : ''; + $result['CustomLinks'][] = array( + 'Category' => $category, + 'Icon' => $icon, + 'MouseOverText' => $mouseOverText, + 'Name' => $name, + 'Text' => $text, + 'Url' => $url, + ); + } + } + + if ($record->Items) { + $result['Items'] = array(); + foreach ($record->Items->Item as $item) { + $name = $item->Name ? (string) $item->Name : ''; + $label = $item->Label ? (string) $item->Label : ''; + $group = $item->Group ? (string) $item->Group : ''; + $data = $item->Data ? (string) $item->Data : ''; + $result['Items'][$name] = array( + 'Name' => $name, + 'Label' => $label, + 'Group' => $group, + 'Data' => $this->toHTML($data, $group), + ); + } + } + + if ($record->RecordInfo) { + $result['RecordInfo'] = array(); + $result['RecordInfo']['BibEntity'] = array( + 'Identifiers' => array(), + 'Languages' => array(), + 'PhysicalDescription' => array(), + 'Subjects' => array(), + 'Titles' => array(), + ); + + if ($record->RecordInfo->BibRecord->BibEntity->Identifiers) { + foreach ($record->RecordInfo->BibRecord->BibEntity->Identifiers->Identfier as $identifier) { + $type = $identifier->Type ? (string) $identifier->Type : ''; + $value = $identifier->Value ? (string) $identifier->Value : ''; + $result['RecordInfo']['BibEntity']['Identifiers'][] = array( + 'Type' => $type, + 'Value' => $value, + ); + } + } + + if ($record->RecordInfo->BibRecord->BibEntity->Languages) { + foreach ($record->RecordInfo->BibRecord->BibEntity->Languages->Language as $language) { + $code = $language->Code ? (string) $language->Code : ''; + $text = $language->Text ? (string) $language->Text : ''; + $result['RecordInfo']['BibEntity']['Languages'][] = array( + 'Code' => $code, + 'Text' => $text, + ); + } + } + + if ($record->RecordInfo->BibRecord->BibEntity->PhysicalDescription) { + $pageCount = $record->RecordInfo->BibRecord->BibEntity->PhysicalDescription->Pagination->PageCount ? (string) $record->RecordInfo->BibRecord->BibEntity->PhysicalDescription->Pagination->PageCount : ''; + $startPage = $record->RecordInfo->BibRecord->BibEntity->PhysicalDescription->Pagination->StartPage ? (string) $record->RecordInfo->BibRecord->BibEntity->PhysicalDescription->Pagination->StartPage : ''; + $result['RecordInfo']['BibEntity']['PhysicalDescription']['Pagination'] = $pageCount; + $result['RecordInfo']['BibEntity']['PhysicalDescription']['StartPage'] = $startPage; + } + + if ($record->RecordInfo->BibRecord->BibEntity->Subjects) { + foreach ($record->RecordInfo->BibRecord->BibEntity->Subjects->Subject as $subject) { + $subjectFull = $subject->SubjectFull ? (string) $subject->SubjectFull : ''; + $type = $subject->Type ? (string) $subject->Type : ''; + $result['RecordInfo']['BibEntity']['Subjects'][] = array( + 'SubjectFull' => $subjectFull, + 'Type' => $type, + ); + } + } + + if ($record->RecordInfo->BibRecord->BibEntity->Titles) { + foreach ($record->RecordInfo->BibRecord->BibEntity->Titles->Title as $title) { + $titleFull = $title->TitleFull ? (string) $title->TitleFull : ''; + $type = $title->Type ? (string) $title->Type : ''; + $result['RecordInfo']['BibEntity']['Titles'][] = array( + 'TitleFull' => $titleFull, + 'Type' => $type, + ); + } + } + + $result['RecordInfo']['BibRelationships'] = array( + 'HasContributorRelationships' => array(), + 'IsPartOfRelationships' => array(), + ); + + if ($record->RecordInfo->BibRecord->BibRelationships->HasContributorRelationships) { + foreach ($record->RecordInfo->BibRecord->BibRelationships->HasContributorRelationships->HasContributor as $contributor) { + $nameFull = $contributor->PersonEntity->Name->NameFull ? (string) $contributor->PersonEntity->Name->NameFull : ''; + $result['RecordInfo']['BibRelationships']['HasContributorRelationships'][] = array( + 'NameFull' => $nameFull, + ); + } + } + + if ($record->RecordInfo->BibRecord->BibRelationships) { + foreach ($record->RecordInfo->BibRecord->BibRelationships->IsPartOfRelationships->IsPartOf as $relationship) { + if ($relationship->BibEntity->Dates) { + foreach ($relationship->BibEntity->Dates->Date as $date) { + $d = $date->D ? (string) $date->D : ''; + $m = $date->M ? (string) $date->M : ''; + $type = $date->Type ? (string) $date->Type : ''; + $y = $date->Y ? (string) $date->Y : ''; + $result['RecordInfo']['BibRelationships']['IsPartOfRelationships']['date'][] = array( + 'D' => $d, + 'M' => $m, + 'Type' => $type, + 'Y' => $y, + ); + } + } + + if ($relationship->BibEntity->Identifiers) { + foreach ($relationship->BibEntity->Identifiers->Identfier as $identifier) { + $type = $identifier->Type ? (string) $identifier->Type : ''; + $value = $identifier->Value ? (string) $identifier->Value : ''; + $result['RecordInfo']['BibRelationships']['IsPartOfRelationships']['Identifiers'][] = array( + 'Type' => $type, + 'Value' => $value, + ); + } + } + + if ($relationship->BibEntity->Numbering) { + foreach ($relationship->BibEntity->Numbering->Number as $number) { + $type = (string) $number->Type; + $value = (string) $number->Value; + $result['RecordInfo']['BibRelationships']['IsPartOfRelationships']['numbering'][] = array( + 'Type' => $type, + 'Value' => $value, + ); + } + } + + if ($relationship->BibEntity->Titles) { + foreach ($relationship->BibEntity->Titles->Title as $title) { + $titleFull = $title->TitleFull ? (string) $title->TitleFull : ''; + $type = $title->Type ? (string) $title->Type : ''; + $result['RecordInfo']['BibRelationships']['IsPartOfRelationships']['Titles'][] = array( + 'TitleFull' => $titleFull, + 'Type' => $type, + ); + } + } + } + } + + } + + if ($record->ImageQuickViewItems->ImageQuickViewItem) { + $result['iqv'] = array(); + foreach ($record->ImageQuickViewItems->ImageQuickViewItem as $iqv) { + $dbcode = $iqv->DbId ? (string) $iqv->DbId : ''; + $an = $iqv->An ? (string) $iqv->An : ''; + $type = $iqv->Type ? (string) $iqv->Type : ''; + $url = $iqv->Url ? (string) $iqv->Url : ''; + $result['iqv'][] = array( + 'DbId' => $dbcode, + 'An' => $an, + 'Type' => $type, + 'url' => $url, + ); + } + } + + if ($record->IllustrationInfo) { + $result['IllustrationInfo'] = array(); + foreach ($record->IllustrationInfo->Images->Image as $img) { + $size = $img->Size ? (string) $img->Size : ''; + $target = $img->Target ? (string) $img->Target : ''; + $result['IllustrationInfo'][] = array( + 'Size' => $size, + 'Target' => $target, + ); + } + } + + return $result; + + } + + private function buildCitationStyles() + { + + $recordCitation = $this->response; + + $result = array(); + + if ($recordCitation) { + + $result['Citation'] = array(); + + foreach ($recordCitation->Citation as $key => $citationItem) { + + $id = $citationItem->Id ? (string) $citationItem->Id : ''; + $label = $citationItem->Label ? (string) $citationItem->Label : ''; + $sectionLabel = $citationItem->SectionLabel ? (string) $citationItem->SectionLabel : ''; + $data = $citationItem->Data ? (string) $citationItem->Data : ''; + $caption = $citationItem->Caption ? (string) $citationItem->Caption : ''; + $result['Citation'][] = array( + 'Id' => $id, + 'Label' => $label, + 'SectionLabel' => $sectionLabel, + 'Data' => $data, + 'Caption' => $caption, + ); + } + } + + return $result; + + } + + /** + * Parse a SimpleXml element and + * return it's inner XML as an HTML string. + * + * @param SimpleXml $element + * A SimpleXml DOM. + * + * @return string The HTML string + * + * @access protected + */ + private function toHTML($data, $group = null) + { + + // Any group can be added here, but we only use Au (Author) + // Other groups, not present here, won't be transformed to HTML links. + $allowed_searchlink_groups = array('au'); + + // Map xml tags to the HTML tags + // This is just a small list, the total number of xml tags is far more greater. + $xml_to_html_tags = array( + ' ' ' ' '' => '', + ' '', + ' ' ' ' ' ' ' '

    ' ' ' ' '', + ' ' ' ' ' '

    ' ' ' ' ' '

    ' ' ' ' ' ' ' 'Author', + 'su' => 'Subject', + ); + + // The XML data is XML escaped, let's unescape html entities (e.g. < => <) + $data = html_entity_decode($data); + + // Start parsing the xml data. + if (!empty($data)) { + // Replace the XML tags with HTML tags. + $search = array_keys($xml_to_html_tags); + $replace = array_values($xml_to_html_tags); + $data = str_replace($search, $replace, $data); + + // Temporary : fix unclosed tags. + $data = preg_replace('/<\/highlight/', '', $data); + $data = preg_replace('/<\/span>>/', '', $data); + $data = preg_replace('/<\/searchLink/', '', $data); + $data = preg_replace('/<\/searchLink>>/', '', $data); + + // Parse searchLinks. + if (!empty($group)) { + $group = strtolower($group); + if (in_array($group, $allowed_searchlink_groups)) { + $type = $xml_to_search_types[$group]; + $path = \Drupal\Core\Url::fromRoute('ebsco.results', array('type' => $type))->toString(); + $link_xml = '//'; + $link_html = ""; + $data = preg_replace($link_xml, $link_html, $data); + $data = str_replace('', '', $data); + } + } + + // Replace the rest of searchLinks with simple spans. + $link_xml = '//'; + $link_html = ''; + $data = preg_replace($link_xml, $link_html, $data); + $data = str_replace('', '', $data); + + // Parse bibliography (anchors and links) + $data = preg_replace('/sanitize($data); + + return $data; + } + +} diff --git a/modules/roblib_search_eds/src/Lib/RoblibEBSCOAPI.php b/modules/roblib_search_eds/src/Lib/RoblibEBSCOAPI.php new file mode 100644 index 0000000..a15a3c9 --- /dev/null +++ b/modules/roblib_search_eds/src/Lib/RoblibEBSCOAPI.php @@ -0,0 +1,14 @@ +config = $config; + } +} diff --git a/modules/roblib_search_eds/src/Lib/sanitizer.class.php b/modules/roblib_search_eds/src/Lib/sanitizer.class.php new file mode 100644 index 0000000..42d4e80 --- /dev/null +++ b/modules/roblib_search_eds/src/Lib/sanitizer.class.php @@ -0,0 +1,446 @@ +. +// All rights reserved. +// +// HTML Sanitizer is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// HTML Sanitizer 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 Lesser General Public License +// along with HTML Sanitizer; if not, see . +// +// ***** END LICENSE BLOCK *****. +/** + * Sanitize HTML contents : + * Remove dangerous tags and attributes that can lead to security issues like + * XSS or HTTP response splitting. + * + * @author Frederic Minne + * @copyright Copyright © 2005-2011, Frederic Minne + * @license https://www.gnu.org/licenses/lgpl.txt GNU Lesser General Public License version 3 or later + * @version 1.1 + */ + + +class HTML_Sanitizer { + /** + * Private fields. + */ + private $_allowedTags; + private $_allowJavascriptEvents; + private $_allowJavascriptInUrls; + private $_allowObjects; + private $_allowScript; + private $_allowStyle; + private $_additionalTags; + + /** + * Constructor. + */ + public function __construct() { + $this->resetAll(); + } + + /** + * (re)set all options to default value. + */ + public function resetAll() { + $this->_allowDOMEvents = FALSE; + $this->_allowJavascriptInUrls = FALSE; + $this->_allowStyle = FALSE; + $this->_allowScript = FALSE; + $this->_allowObjects = FALSE; + $this->_allowStyle = FALSE; + + $this->_allowedTags = '

    ' + . '
    1. ' + . '

      ' + . '

        ' + . ''; + + $this->_additionalTags = ''; + } + + /** + * Add additional tags to allowed tags. + * + * @param string + * + * @access public + */ + public function addAdditionalTags($tags) { + $this->_additionalTags .= $tags; + } + + /** + * Allow iframes. + * + * @access public + */ + public function allowIframes() { + $this->addAdditionalTags('