/** * Load status (holdings) for a record and filter them based on the logged in user information. * * Format of return array is: * key = {section#}{location}-### where ### is the holding iteration * * value = array ( * id = The id of the bib * number = The position of the holding within the original list of holdings * section = A description of the section * sectionId = a numeric id of the section for sorting * type = holding * status * statusfull * availability * holdable * nonHoldableReason * reserve * holdQueueLength * duedate * location * libraryDisplayName * locationCode * locationLink * callnumber * link = array * linkText * isDownload * ) * * Includes both physical titles as well as titles on order * * @param string $id the id of the record * @return array A list of holdings for the record */ public function getHolding($id) { if (array_key_exists($id, HorizonAPI::$loadedStatus)) { return HorizonAPI::$loadedStatus[$id]; } global $configArray; global $library; //Get location information so we can put things into sections global $locationSingleton; /** @var $locationSingleton Location */ $physicalLocation = $locationSingleton->getPhysicalLocation(); if ($physicalLocation != null) { $physicalBranch = $physicalLocation->holdingBranchLabel; } else { $physicalBranch = ''; } $homeBranch = ''; $homeBranchId = 0; $nearbyBranch1 = ''; $nearbyBranch1Id = 0; $nearbyBranch2 = ''; $nearbyBranch2Id = 0; //Set location information based on the user login. This will override information based if (isset($user) && $user != false) { $homeBranchId = $user->homeLocationId; $nearbyBranch1Id = $user->myLocation1Id; $nearbyBranch2Id = $user->myLocation2Id; } else { //Check to see if the cookie for home location is set. if (isset($_COOKIE['home_location']) && is_numeric($_COOKIE['home_location'])) { $cookieLocation = new Location(); $locationId = $_COOKIE['home_location']; $cookieLocation->whereAdd("locationId = '{$locationId}'"); $cookieLocation->find(); if ($cookieLocation->N == 1) { $cookieLocation->fetch(); $homeBranchId = $cookieLocation->locationId; $nearbyBranch1Id = $cookieLocation->nearbyLocation1; $nearbyBranch2Id = $cookieLocation->nearbyLocation2; } } } //Load the holding label for the user's home location. $userLocation = new Location(); $userLocation->whereAdd("locationId = '{$homeBranchId}'"); $userLocation->find(); if ($userLocation->N == 1) { $userLocation->fetch(); $homeBranch = $userLocation->holdingBranchLabel; } //Load nearby branch 1 $nearbyLocation1 = new Location(); $nearbyLocation1->whereAdd("locationId = '{$nearbyBranch1Id}'"); $nearbyLocation1->find(); if ($nearbyLocation1->N == 1) { $nearbyLocation1->fetch(); $nearbyBranch1 = $nearbyLocation1->holdingBranchLabel; } //Load nearby branch 2 $nearbyLocation2 = new Location(); $nearbyLocation2->whereAdd(); $nearbyLocation2->whereAdd("locationId = '{$nearbyBranch2Id}'"); $nearbyLocation2->find(); if ($nearbyLocation2->N == 1) { $nearbyLocation2->fetch(); $nearbyBranch2 = $nearbyLocation2->holdingBranchLabel; } //Get a list of items from Horizon $lookupTitleInfoUrl = $configArray['Catalog']['webServiceUrl'] . '/standard/lookupTitleInfo?clientID=' . $configArray['Catalog']['clientId'] . '&titleKey=' . $id . '&includeItemInfo=true&includeHoldCount=true'; $lookupTitleInfoResponse = $this->getWebServiceResponse($lookupTitleInfoUrl); $holdings = array(); if ($lookupTitleInfoResponse->titleInfo) { $i = 0; foreach ($lookupTitleInfoResponse->titleInfo->itemInfo as $itemInfo) { if (!isset($itemInfo->locationID)) { //Suppress anything without a location code continue; } $i++; $holding = array('id' => $id, 'number' => $i++, 'type' => 'holding', 'status' => isset($itemInfo->statusID) ? (string) $itemInfo->statusID : 'Unknown', 'statusfull' => isset($itemInfo->statusDescription) ? (string) $itemInfo->statusDescription : 'Unknown', 'availability' => isset($itemInfo->available) ? (string) $itemInfo->available == "true" : false, 'holdable' => true, 'reserve' => 'N', 'holdQueueLength' => (int) $lookupTitleInfoResponse->titleInfo->holdCount, 'dueDate' => isset($itemInfo->dueDate) ? (string) $itemInfo->dueDate : 'Unknown', 'locationCode' => (string) $itemInfo->locationID, 'location' => (string) $itemInfo->locationDescription, 'callnumber' => (string) $itemInfo->callNumber, 'isDownload' => false, 'barcode' => (string) $itemInfo->barcode, 'isLocalItem' => false, 'isLibraryItem' => true, 'locationLabel' => (string) $itemInfo->locationDescription, 'shelfLocation' => (string) $itemInfo->locationDescription); $holding['groupedStatus'] = mapValue('item_grouped_status', $holding['status']); $paddedNumber = str_pad($i, 3, '0', STR_PAD_LEFT); $sortString = $holding['location'] . '-' . $paddedNumber; //$sortString = $holding['location'] . $holding['callnumber']. $i; if (strlen($physicalBranch) > 0 && stripos($holding['location'], $physicalBranch) !== false) { //If the user is in a branch, those holdings come first. $holding['section'] = 'In this library'; $holding['sectionId'] = 1; $holding['isLocalItem'] = true; $sorted_array['1' . $sortString] = $holding; } else { if (strlen($homeBranch) > 0 && stripos($holding['location'], $homeBranch) !== false) { //Next come the user's home branch if the user is logged in or has the home_branch cookie set. $holding['section'] = 'Your library'; $holding['sectionId'] = 2; $holding['isLocalItem'] = true; $sorted_array['2' . $sortString] = $holding; } else { if (strlen($nearbyBranch1) > 0 && stripos($holding['location'], $nearbyBranch1) !== false) { //Next come nearby locations for the user $holding['section'] = 'Nearby Libraries'; $holding['sectionId'] = 3; $sorted_array['3' . $sortString] = $holding; } else { if (strlen($nearbyBranch2) > 0 && stripos($holding['location'], $nearbyBranch2) !== false) { //Next come nearby locations for the user $holding['section'] = 'Nearby Libraries'; $holding['sectionId'] = 4; $sorted_array['4' . $sortString] = $holding; //MDN 11/17 - taken out because all Horizon libraries are single institution (so far) /*} else if (strlen($libraryLocationLabels) > 0 && preg_match($libraryLocationLabels, $holding['location'])){ //Next come any locations within the same system we are in. $holding['section'] = $library->displayName; $holding['sectionId'] = 5; $sorted_array['5' . $sortString] = $holding; */ } else { //Finally, all other holdings are shown sorted alphabetically. $holding['section'] = $library->displayName; $holding['sectionId'] = 5; $sorted_array['5' . $sortString] = $holding; } } } } $holdings[] = $holding; } } return $holdings; }
public function parseHoldsPage($pageContents) { //global $logger; $availableHolds = array(); $unavailableHolds = array(); $holds = array('available' => $availableHolds, 'unavailable' => $unavailableHolds); //Get the headers from the table preg_match_all('/<th\\s+class="patFuncHeaders">\\s*([\\w\\s]*?)\\s*<\\/th>/si', $pageContents, $result, PREG_SET_ORDER); $sKeys = array(); for ($matchi = 0; $matchi < count($result); $matchi++) { $sKeys[] = $result[$matchi][1]; } //Get the rows for the table preg_match_all('/<tr\\s+class="patFuncEntry(?: on_ice)?">(.*?)<\\/tr>/si', $pageContents, $result, PREG_SET_ORDER); $sRows = array(); for ($matchi = 0; $matchi < count($result); $matchi++) { $sRows[] = $result[$matchi][1]; } $sCount = 0; foreach ($sRows as $sRow) { preg_match_all('/<td[^>]*>(.*?)<\\/td>/si', $sRow, $result, PREG_SET_ORDER); $sCols = array(); for ($matchi = 0; $matchi < count($result); $matchi++) { $sCols[] = $result[$matchi][1]; } //$sCols = preg_split("/<t(h|d)([^>]*)>/",$sRow); $curHold = array(); $curHold['create'] = null; $curHold['reqnum'] = null; $curHold['holdSource'] = 'ILS'; //Holds page occasionally has a header with number of items checked out. for ($i = 0; $i < sizeof($sCols); $i++) { $sCols[$i] = str_replace(" ", " ", $sCols[$i]); $sCols[$i] = preg_replace("/<br+?>/", " ", $sCols[$i]); $sCols[$i] = html_entity_decode(trim($sCols[$i])); //print_r($scols[$i]); /*if ($sCount <= 1) { $sKeys[$i] = $sCols[$i]; } else if ($sCount > 1) {*/ if ($sKeys[$i] == "CANCEL") { //Only check Cancel key, not Cancel if not filled by //Extract the id from the checkbox $matches = array(); $numMatches = preg_match_all('/.*?cancel(.*?)x(\\d\\d).*/s', $sCols[$i], $matches); if ($numMatches > 0) { $curHold['renew'] = "BOX"; $curHold['cancelable'] = true; $curHold['itemId'] = $matches[1][0]; $curHold['xnum'] = $matches[2][0]; $curHold['cancelId'] = $matches[1][0] . '~' . $matches[2][0]; } else { $curHold['cancelable'] = false; } } if (stripos($sKeys[$i], "TITLE") > -1) { if (preg_match('/.*?<a href=\\"\\/record=(.*?)(?:~S\\d{1,2})\\">(.*?)<\\/a>.*/', $sCols[$i], $matches)) { $shortId = $matches[1]; $bibid = '.' . $matches[1] . $this->driver->getCheckDigit($shortId); $title = strip_tags($matches[2]); } elseif (preg_match('/.*<a href=".*?\\/record\\/C__R(.*?)\\?.*?">(.*?)<\\/a>.*/si', $sCols[$i], $matches)) { $shortId = $matches[1]; $bibid = '.' . $matches[1] . $this->driver->getCheckDigit($shortId); $title = strip_tags($matches[2]); } else { //This happens for prospector titles $bibid = ''; $shortId = ''; $title = trim($sCols[$i]); /*global $configArray; if ($configArray['System']['debug']){ echo("Unexpected format in title column. Got " . htmlentities($sCols[$i]) . "<br/>"); }*/ } $curHold['id'] = $bibid; $curHold['recordId'] = $bibid; $curHold['shortId'] = $shortId; $curHold['title'] = $title; } if (stripos($sKeys[$i], "Ratings") > -1) { $curHold['request'] = "STARS"; } if (stripos($sKeys[$i], "PICKUP LOCATION") > -1) { //Extract the current location for the hold if possible $matches = array(); if (preg_match('/<select\\s+name=loc(.*?)x(\\d\\d).*?<option\\s+value="([a-z]{1,5})[+ ]*"\\s+selected="selected">.*/s', $sCols[$i], $matches)) { $curHold['locationId'] = $matches[1]; $curHold['locationXnum'] = $matches[2]; $curPickupBranch = new Location(); $curPickupBranch->whereAdd("code = '{$matches[3]}'"); $curPickupBranch->find(1); if ($curPickupBranch->N > 0) { $curPickupBranch->fetch(); $curHold['currentPickupId'] = $curPickupBranch->locationId; $curHold['currentPickupName'] = $curPickupBranch->displayName; $curHold['location'] = $curPickupBranch->displayName; } $curHold['locationUpdateable'] = true; //Return the full select box for reference. $curHold['locationSelect'] = $sCols[$i]; } else { $curHold['location'] = $sCols[$i]; //Trim the carrier code if any if (preg_match('/.*\\s[\\w\\d]{4}/', $curHold['location'])) { $curHold['location'] = substr($curHold['location'], 0, strlen($curHold['location']) - 5); } $curHold['currentPickupName'] = $curHold['location']; $curHold['locationUpdateable'] = false; } } if (stripos($sKeys[$i], "STATUS") > -1) { $status = trim(strip_tags($sCols[$i])); $status = strtolower($status); $status = ucwords($status); if ($status != " ") { $curHold['status'] = $status; if (preg_match('/READY.*(\\d{2}-\\d{2}-\\d{2})/i', $status, $matches)) { $curHold['status'] = 'Ready'; //Get expiration date $exipirationDate = $matches[1]; $expireDate = DateTime::createFromFormat('m-d-y', $exipirationDate); $curHold['expire'] = $expireDate->getTimestamp(); } elseif (preg_match('/READY\\sFOR\\sPICKUP/i', $status, $matches)) { $curHold['status'] = 'Ready'; } else { $curHold['status'] = $status; } } else { $curHold['status'] = "Pending {$status}"; } $matches = array(); $curHold['renewError'] = false; if (preg_match('/.*DUE\\s(\\d{2}-\\d{2}-\\d{2}).*(?:<font color="red">\\s*(.*)<\\/font>).*/s', $sCols[$i], $matches)) { //Renew error $curHold['renewError'] = $matches[2]; $curHold['statusMessage'] = $matches[2]; } else { if (preg_match('/.*DUE\\s(\\d{2}-\\d{2}-\\d{2})\\s(.*)?/s', $sCols[$i], $matches)) { $curHold['statusMessage'] = $matches[2]; } } //$logger->log('Status for item ' . $curHold['id'] . '=' . $sCols[$i], PEAR_LOG_INFO); } if (stripos($sKeys[$i], "CANCEL IF NOT FILLED BY") > -1) { //$curHold['expire'] = strip_tags($scols[$i]); } if (stripos($sKeys[$i], "FREEZE") > -1) { $matches = array(); $curHold['frozen'] = false; if (preg_match('/<input.*name="freeze(.*?)"\\s*(\\w*)\\s*\\/>/', $sCols[$i], $matches)) { $curHold['freezeable'] = true; if (strlen($matches[2]) > 0) { $curHold['frozen'] = true; $curHold['status'] = 'Frozen'; } } elseif (preg_match('/This hold can\\s?not be frozen/i', $sCols[$i], $matches)) { //If we detect an error Freezing the hold, save it so we can report the error to the user later. $shortId = str_replace('.b', 'b', $curHold['id']); $_SESSION['freezeResult'][$shortId]['message'] = $sCols[$i]; $_SESSION['freezeResult'][$shortId]['result'] = false; } else { $curHold['freezeable'] = false; } } //} } //End of columns //if ($sCount > 1) { if (!isset($curHold['status']) || strcasecmp($curHold['status'], "ready") != 0) { $holds['unavailable'][] = $curHold; } else { $holds['available'][] = $curHold; } //} $sCount++; } //End of the row return $holds; }
public function getItemsFast() { global $configArray; if ($this->fastItems == null) { $searchLibrary = Library::getSearchLibrary(); if ($searchLibrary) { $libraryLocationCode = $searchLibrary->ilsCode; } $searchLocation = Location::getSearchLocation(); if ($searchLocation) { $homeLocationCode = $searchLocation->code; } else { $homeLocation = Location::getUserHomeLocation(); if ($homeLocation) { $homeLocationCode = $homeLocation->code; } } $this->fastItems = array(); if ($this->itemsFromIndex) { $this->fastItems = array(); foreach ($this->itemsFromIndex as $itemData) { $isLocalItem = false; $isLibraryItem = false; if (array_key_exists('item', $itemData)) { $itemId = $itemData['item'][0]; $locationCode = $itemData['item'][1]; $shelfLocation = mapValue('shelf_location', $locationCode); $sharing = $itemData['item'][3]; $source = $itemData['item'][4]; $fileOrUrl = ''; if (count($itemData['item']) > 5) { $fileOrUrl = $itemData['item'][5]; } if (array_key_exists('scope', $itemData)) { $isLocalItem = $itemData['scope'][1] == 'true'; $isLibraryItem = $itemData['scope'][2] == 'true'; } } else { $itemId = $itemData[1]; $locationCode = $itemData[2]; $shelfLocation = mapValue('shelf_location', $itemData[2]); $sharing = $itemData[4]; $source = $itemData[5]; $fileOrUrl = ''; if (count($itemData) > 6) { $fileOrUrl = $itemData[6]; } $isLocalItem = isset($libraryLocationCode) && strlen($libraryLocationCode) > 0 && strpos($locationCode, $libraryLocationCode) === 0; $isLibraryItem = isset($homeLocationCode) && strlen($homeLocationCode) > 0 && strpos($locationCode, $homeLocationCode) === 0; } $actions = $this->getActionsForItem($itemId, $fileOrUrl, null); $libraryLabelObj = new Library(); $libraryLabelObj->whereAdd("'{$locationCode}' LIKE CONCAT(ilsCode, '%') and ilsCode <> ''"); $libraryLabelObj->selectAdd(); $libraryLabelObj->selectAdd('displayName'); if ($libraryLabelObj->find(true)) { $libraryLabel = $libraryLabelObj->displayName; } else { $libraryLabel = $locationCode . ' Online'; } //TODO: Get the correct number of available copies $totalCopies = 1; $this->fastItems[] = array('itemId' => $itemId, 'location' => $locationCode, 'callnumber' => '', 'availability' => $this->isItemAvailable($itemId, $totalCopies), 'holdable' => $this->isEContentHoldable($locationCode, $itemData), 'inLibraryUseOnly' => false, 'isLocalItem' => $isLocalItem, 'isLibraryItem' => $isLibraryItem, 'locationLabel' => 'Online', 'libraryLabel' => $libraryLabel, 'shelfLocation' => $shelfLocation, 'source' => 'Online ' . $source, 'sharing' => $sharing, 'actions' => $actions); } } else { /** @var File_MARC_Data_Field[] $itemFields */ $itemFields = $this->getMarcRecord()->getFields('989'); foreach ($itemFields as $itemField) { $locationCode = trim($itemField->getSubfield('d') != null ? $itemField->getSubfield('d')->getData() : ''); //Each item can have multiple item fields /** @var File_MARC_Subfield[] $eContentFields */ $eContentFields = $itemField->getSubfields('w'); $itemId = $itemField->getSubfield('1')->getData(); $iType = $itemField->getSubfield($configArray['Reindex']['iTypeSubfield'])->getData(); foreach ($eContentFields as $eContentField) { $eContentData = trim($eContentField->getData() != null ? $eContentField->getData() : ''); if ($eContentData && strpos($eContentData, ':') > 0) { $eContentFieldData = explode(':', $eContentData); $source = trim($eContentFieldData[0]); $protectionType = strtolower(trim($eContentFieldData[1])); $totalCopies = 1; if ($this->isValidProtectionType($protectionType)) { if ($this->isValidForUser($locationCode, $eContentFieldData)) { $libraryLabelObj = new Library(); $libraryLabelObj->whereAdd("'{$locationCode}' LIKE CONCAT(ilsCode, '%') and ilsCode <> ''"); $libraryLabelObj->selectAdd(); $libraryLabelObj->selectAdd('displayName'); if ($libraryLabelObj->find(true)) { $libraryLabel = $libraryLabelObj->displayName; } else { $libraryLabel = $locationCode . ' Online'; } $locationLabelObj = new Location(); $locationLabelObj->whereAdd("'{$locationCode}' LIKE CONCAT(code, '%') and code <> ''"); if ($locationLabelObj->find(true)) { $locationLabel = $locationLabelObj->displayName; } else { $locationLabel = $locationCode . ' Online'; } //Get the file or url that is related to this item. $fileOrUrl = ''; $acsId = null; if ($protectionType == 'external') { $urlSubfield = $itemField->getSubfield('u'); if ($urlSubfield != null) { $fileOrUrl = $urlSubfield->getData(); } else { //Get from the 856 field /** @var File_MARC_Data_Field[] $linkFields */ $linkFields = $this->getMarcRecord()->getFields('856'); foreach ($linkFields as $link) { $urlSubfield = $link->getSubfield('u'); if ($urlSubfield != null) { $fileOrUrl = $urlSubfield->getData(); } } } } else { if (count($eContentFieldData) > 3) { $fileOrUrl = trim($eContentFieldData[3]); } if (count($eContentFieldData) > 4) { $acsId = trim($eContentFieldData[4]); } if (count($eContentFieldData) > 5) { $totalCopies = trim($eContentFieldData[5]); } } $fileOrUrl = trim($fileOrUrl); $actions = $this->getActionsForItem($itemId, $fileOrUrl, $acsId); $format = $this->getEContentFormat($fileOrUrl, $iType); $sharing = $this->getSharing($locationCode, $eContentFieldData); //Add an item $item = array('itemId' => $itemId, 'location' => $locationCode, 'locationLabel' => $locationLabel, 'libraryLabel' => $libraryLabel, 'callnumber' => '', 'availability' => $this->isItemAvailable($itemId, $totalCopies), 'holdable' => $this->isEContentHoldable($locationCode, $eContentFieldData), 'isLocalItem' => $this->isLocalItem($locationCode, $eContentFieldData), 'isLibraryItem' => $this->isLibraryItem($locationCode, $eContentFieldData), 'shelfLocation' => 'Online ' . $source, 'source' => $source, 'sharing' => $sharing, 'fileOrUrl' => $fileOrUrl, 'format' => $format, 'helpText' => $this->getHelpText($fileOrUrl), 'usageNotes' => $this->getUsageRestrictions($sharing, $libraryLabel, $locationLabel), 'formatNotes' => $this->getFormatNotes($fileOrUrl), 'size' => $this->getFileSize($fileOrUrl), 'actions' => $actions); $this->fastItems[] = $item; } } } } } } } return $this->fastItems; }
protected function _updateVuFindPatronInfo() { global $user; //Validate that the input data is correct if (isset($_POST['myLocation1']) && preg_match('/^\\d{1,3}$/', $_POST['myLocation1']) == 0) { PEAR_Singleton::raiseError('The 1st location had an incorrect format.'); } if (isset($_POST['myLocation2']) && preg_match('/^\\d{1,3}$/', $_POST['myLocation2']) == 0) { PEAR_Singleton::raiseError('The 2nd location had an incorrect format.'); } if (isset($_REQUEST['bypassAutoLogout'])) { if ($_REQUEST['bypassAutoLogout'] == 'yes') { $user->bypassAutoLogout = 1; } else { $user->bypassAutoLogout = 0; } } if (isset($_REQUEST['promptForOverdriveEmail'])) { if ($_REQUEST['promptForOverdriveEmail'] == 'yes') { $user->promptForOverdriveEmail = 1; } else { $user->promptForOverdriveEmail = 0; } } if (isset($_REQUEST['overdriveEmail'])) { $user->overdriveEmail = strip_tags($_REQUEST['overdriveEmail']); } //Make sure the selected location codes are in the database. if (isset($_POST['myLocation1'])) { $location = new Location(); $location->whereAdd("locationId = '{$_POST['myLocation1']}'"); $location->find(); if ($location->N != 1) { PEAR_Singleton::raiseError('The 1st location could not be found in the database.'); } $user->myLocation1Id = $_POST['myLocation1']; } if (isset($_POST['myLocation2'])) { $location = new Location(); $location->whereAdd(); $location->whereAdd("locationId = '{$_POST['myLocation2']}'"); $location->find(); if ($location->N != 1) { PEAR_Singleton::raiseError('The 2nd location could not be found in the database.'); } $user->myLocation2Id = $_POST['myLocation2']; } $user->update(); //Update the serialized instance stored in the session $_SESSION['userinfo'] = serialize($user); }
protected static function getSortingDataForHoldings() { if (self::$holdingSortingData == null) { global $user; global $library; global $locationSingleton; /** @var $locationSingleton Location */ $holdingSortingData = array(); //Get location information so we can put things into sections $physicalLocation = $locationSingleton->getPhysicalLocation(); if ($physicalLocation != null) { $holdingSortingData['physicalBranch'] = $physicalLocation->holdingBranchLabel; } else { $holdingSortingData['physicalBranch'] = ''; } $holdingSortingData['homeBranch'] = ''; $homeBranchId = 0; $holdingSortingData['nearbyBranch1'] = ''; $nearbyBranch1Id = 0; $holdingSortingData['nearbyBranch2'] = ''; $nearbyBranch2Id = 0; //Set location information based on the user login. This will override information based if (isset($user) && $user != false) { $homeBranchId = $user->homeLocationId; $nearbyBranch1Id = $user->myLocation1Id; $nearbyBranch2Id = $user->myLocation2Id; } else { //Check to see if the cookie for home location is set. if (isset($_COOKIE['home_location']) && is_numeric($_COOKIE['home_location'])) { $cookieLocation = new Location(); $locationId = $_COOKIE['home_location']; $cookieLocation->whereAdd("locationId = '{$locationId}'"); $cookieLocation->find(); if ($cookieLocation->N == 1) { $cookieLocation->fetch(); $homeBranchId = $cookieLocation->locationId; $nearbyBranch1Id = $cookieLocation->nearbyLocation1; $nearbyBranch2Id = $cookieLocation->nearbyLocation2; } } } //Load the holding label for the user's home location. $userLocation = new Location(); $userLocation->whereAdd("locationId = '{$homeBranchId}'"); $userLocation->find(); if ($userLocation->N == 1) { $userLocation->fetch(); $holdingSortingData['homeBranch'] = $userLocation->holdingBranchLabel; } //Load nearby branch 1 $nearbyLocation1 = new Location(); $nearbyLocation1->whereAdd("locationId = '{$nearbyBranch1Id}'"); $nearbyLocation1->find(); if ($nearbyLocation1->N == 1) { $nearbyLocation1->fetch(); $holdingSortingData['nearbyBranch1'] = $nearbyLocation1->holdingBranchLabel; } //Load nearby branch 2 $nearbyLocation2 = new Location(); $nearbyLocation2->whereAdd(); $nearbyLocation2->whereAdd("locationId = '{$nearbyBranch2Id}'"); $nearbyLocation2->find(); if ($nearbyLocation2->N == 1) { $nearbyLocation2->fetch(); $holdingSortingData['nearbyBranch2'] = $nearbyLocation2->holdingBranchLabel; } //Get a list of the display names for all locations based on holding label. $locationLabels = array(); $location = new Location(); $location->find(); $holdingSortingData['libraryLocationLabels'] = array(); $locationCodes = array(); $suppressedLocationCodes = array(); while ($location->fetch()) { if (strlen($location->holdingBranchLabel) > 0 && $location->holdingBranchLabel != '???') { if ($library && $library->libraryId == $location->libraryId) { $cleanLabel = str_replace('/', '\\/', $location->holdingBranchLabel); $libraryLocationLabels[] = str_replace('.', '\\.', $cleanLabel); } $locationLabels[$location->holdingBranchLabel] = $location->displayName; $locationCodes[$location->code] = $location->holdingBranchLabel; if ($location->suppressHoldings == 1) { $suppressedLocationCodes[$location->code] = $location->code; } } } if (count($holdingSortingData['libraryLocationLabels']) > 0) { $holdingSortingData['libraryLocationLabels'] = '/^(' . join('|', $holdingSortingData['libraryLocationLabels']) . ').*/i'; } else { $holdingSortingData['libraryLocationLabels'] = ''; } self::$holdingSortingData = $holdingSortingData; global $timer; $timer->logTime("Finished loading sorting information for holdings"); } return self::$holdingSortingData; }
/** * Get Patron Profile * * This is responsible for retrieving the profile for a specific patron. * Interface defined in CatalogConnection.php * * @param array $patron The patron array * @param boolean $forceReload Whether or not we should force a reload of the data * @return array Array of the patron's profile data * If an error occurs, return a PEAR_Error * @access public */ public function getMyProfile($patron, $forceReload = false) { global $timer; global $configArray; /** @var Memcache $memCache */ global $memCache; global $serverName; $memCacheProfileKey = "patronProfile_{$serverName}_"; if (is_object($patron)) { $patron = get_object_vars($patron); $memCacheProfileKey .= $patron['username']; $id2 = $this->_getBarcode($patron); } else { global $user; $memCacheProfileKey .= $user->username; $id2 = $patron['cat_password']; } if (!$forceReload && !isset($_REQUEST['reload'])) { $patronProfile = $memCache->get($memCacheProfileKey); if ($patronProfile) { $timer->logTime('Retrieved Cached Profile for Patron'); return $patronProfile; } } global $user; if ($configArray['Catalog']['offline'] == true) { $fullName = $patron['cat_username']; $Address1 = ""; $City = ""; $State = ""; $Zip = ""; $finesVal = 0; $expireClose = false; $homeBranchCode = ''; $numHoldsAvailable = '?'; $numHoldsRequested = '?'; if (!$user) { $user = new User(); $user->cat_password = $id2; if ($user->find(true)) { $location = new Location(); $location->locationId = $user->homeLocationId; $location->find(1); $homeBranchCode = $location->code; } } } else { //Load the raw information about the patron $patronDump = $this->_getPatronDump($id2); if (isset($patronDump['ADDRESS'])) { $fullAddress = $patronDump['ADDRESS']; $addressParts = explode('$', $fullAddress); $Address1 = $addressParts[0]; $City = isset($addressParts[1]) ? $addressParts[1] : ''; $State = isset($addressParts[2]) ? $addressParts[2] : ''; $Zip = isset($addressParts[3]) ? $addressParts[3] : ''; if (preg_match('/(.*?),\\s+(.*)\\s+(\\d*(?:-\\d*)?)/', $City, $matches)) { $City = $matches[1]; $State = $matches[2]; $Zip = $matches[3]; } else { if (preg_match('/(.*?)\\s+(\\w{2})\\s+(\\d*(?:-\\d*)?)/', $City, $matches)) { $City = $matches[1]; $State = $matches[2]; $Zip = $matches[3]; } } } else { $Address1 = ""; $City = ""; $State = ""; $Zip = ""; } $fullName = $patronDump['PATRN_NAME']; //Get additional information about the patron's home branch for display. $location = null; if (isset($patronDump['HOME_LIBR']) || isset($patronDump['HOLD_LIBR'])) { $homeBranchCode = isset($patronDump['HOME_LIBR']) ? $patronDump['HOME_LIBR'] : $patronDump['HOLD_LIBR']; $homeBranchCode = str_replace('+', '', $homeBranchCode); //Translate home branch to plain text $location = new Location(); $location->whereAdd("code = '{$homeBranchCode}'"); $location->find(1); if ($location->N == 0) { unset($location); } } if ($user) { if (isset($location)) { if ($user->homeLocationId == 0) { $user->homeLocationId = $location->locationId; if ($location->nearbyLocation1 > 0) { $user->myLocation1Id = $location->nearbyLocation1; } else { $user->myLocation1Id = $location->locationId; } if ($location->nearbyLocation2 > 0) { $user->myLocation2Id = $location->nearbyLocation2; } else { $user->myLocation2Id = $location->locationId; } if ($user instanceof User) { //Update the database $user->update(); //Update the serialized instance stored in the session $_SESSION['userinfo'] = serialize($user); } } else { if ($location->locationId != $user->homeLocationId) { $user->homeLocationId = $location->locationId; //Update the database $user->update(); //Update the serialized instance stored in the session $_SESSION['userinfo'] = serialize($user); } } } } //see if expiration date is close if (trim($patronDump['EXP_DATE']) != '- -') { list($monthExp, $dayExp, $yearExp) = explode("-", $patronDump['EXP_DATE']); $timeExpire = strtotime($monthExp . "/" . $dayExp . "/" . $yearExp); $timeNow = time(); $timeToExpire = $timeExpire - $timeNow; $expired = 0; if ($timeToExpire <= 30 * 24 * 60 * 60) { if ($timeToExpire <= 0) { $expired = 1; } $expireClose = 1; } else { $expireClose = 0; } } else { $expired = 0; $expireClose = 0; } $finesVal = floatval(preg_replace('/[^\\d.]/', '', $patronDump['MONEY_OWED'])); $numHoldsAvailable = 0; $numHoldsRequested = 0; $availableStatusRegex = isset($configArray['Catalog']['patronApiAvailableHoldsRegex']) ? $configArray['Catalog']['patronApiAvailableHoldsRegex'] : "/ST=(105|98),/"; if (isset($patronDump) && isset($patronDump['HOLD']) && count($patronDump['HOLD']) > 0) { foreach ($patronDump['HOLD'] as $hold) { if (preg_match("{$availableStatusRegex}", $hold)) { $numHoldsAvailable++; } else { $numHoldsRequested++; } } } } $nameParts = explode(', ', $fullName); $lastName = $nameParts[0]; $secondName = isset($nameParts[1]) ? $nameParts[1] : ''; if (strpos($secondName, ' ')) { $nameParts2 = explode(' ', $secondName); $firstName = $nameParts2[0]; } else { $firstName = $secondName; } if ($user) { //Get display name for preferred location 1 $myLocation1 = new Location(); $myLocation1->whereAdd("locationId = '{$user->myLocation1Id}'"); $myLocation1->find(1); //Get display name for preferred location 1 $myLocation2 = new Location(); $myLocation2->whereAdd("locationId = '{$user->myLocation2Id}'"); $myLocation2->find(1); } $noticeLabels = array('-' => '', 'a' => 'Mail', 'p' => 'Telephone', 'z' => 'E-mail'); $profile = array('lastname' => $lastName, 'firstname' => $firstName, 'fullname' => $fullName, 'address1' => $Address1, 'address2' => $City . ', ' . $State, 'city' => $City, 'state' => $State, 'zip' => $Zip, 'email' => $user && $user->email ? $user->email : (isset($patronDump) && isset($patronDump['EMAIL_ADDR']) ? $patronDump['EMAIL_ADDR'] : ''), 'overdriveEmail' => $user ? $user->overdriveEmail : (isset($patronDump) && isset($patronDump['EMAIL_ADDR']) ? $patronDump['EMAIL_ADDR'] : ''), 'promptForOverdriveEmail' => $user ? $user->promptForOverdriveEmail : 1, 'phone' => isset($patronDump) && isset($patronDump['TELEPHONE']) ? $patronDump['TELEPHONE'] : (isset($patronDump['HOME_PHONE']) ? $patronDump['HOME_PHONE'] : ''), 'workPhone' => isset($patronDump) && isset($patronDump['G/WK_PHONE']) ? $patronDump['G/WK_PHONE'] : '', 'mobileNumber' => isset($patronDump) && isset($patronDump['MOBILE_NO']) ? $patronDump['MOBILE_NO'] : '', 'fines' => isset($patronDump) ? $patronDump['MONEY_OWED'] : '0', 'finesval' => $finesVal, 'expires' => isset($patronDump) ? $patronDump['EXP_DATE'] : '', 'expireclose' => $expireClose, 'expired' => $expired, 'homeLocationCode' => isset($homeBranchCode) ? trim($homeBranchCode) : '', 'homeLocationId' => isset($location) ? $location->locationId : 0, 'homeLocation' => isset($location) ? $location->displayName : '', 'myLocation1Id' => $user ? $user->myLocation1Id : -1, 'myLocation1' => isset($myLocation1) ? $myLocation1->displayName : '', 'myLocation2Id' => $user ? $user->myLocation2Id : -1, 'myLocation2' => isset($myLocation2) ? $myLocation2->displayName : '', 'numCheckedOut' => isset($patronDump) ? $patronDump['CUR_CHKOUT'] : '?', 'numHolds' => isset($patronDump) ? isset($patronDump['HOLD']) ? count($patronDump['HOLD']) : 0 : '?', 'numHoldsAvailable' => $numHoldsAvailable, 'numHoldsRequested' => $numHoldsRequested, 'bypassAutoLogout' => $user ? $user->bypassAutoLogout : 0, 'ptype' => $user && $user->patronType ? $user->patronType : (isset($patronDump) ? $patronDump['P_TYPE'] : 0), 'notices' => isset($patronDump) ? $patronDump['NOTICE_PREF'] : '-', 'web_note' => isset($patronDump) ? isset($patronDump['WEB_NOTE']) ? $patronDump['WEB_NOTE'] : '' : ''); if (array_key_exists($profile['notices'], $noticeLabels)) { $profile['noticePreferenceLabel'] = $noticeLabels[$profile['notices']]; } else { $profile['noticePreferenceLabel'] = 'Unknown'; } //Get eContent info as well require_once ROOT_DIR . '/Drivers/EContentDriver.php'; $eContentDriver = new EContentDriver(); $eContentAccountSummary = $eContentDriver->getAccountSummary(); $profile = array_merge($profile, $eContentAccountSummary); require_once ROOT_DIR . '/Drivers/OverDriveDriverFactory.php'; $overDriveDriver = OverDriveDriverFactory::getDriver(); if ($overDriveDriver->isUserValidForOverDrive($user)) { $overDriveSummary = $overDriveDriver->getOverDriveSummary($user); $profile['numOverDriveCheckedOut'] = $overDriveSummary['numCheckedOut']; $profile['numOverDriveHoldsAvailable'] = $overDriveSummary['numAvailableHolds']; $profile['numOverDriveHoldsRequested'] = $overDriveSummary['numUnavailableHolds']; $profile['canUseOverDrive'] = true; } else { $profile['numOverDriveCheckedOut'] = 0; $profile['numOverDriveHoldsAvailable'] = 0; $profile['numOverDriveHoldsRequested'] = 0; $profile['canUseOverDrive'] = false; } $profile['numCheckedOutTotal'] = $profile['numCheckedOut'] + $profile['numOverDriveCheckedOut'] + $eContentAccountSummary['numEContentCheckedOut']; $profile['numHoldsAvailableTotal'] = $profile['numHoldsAvailable'] + $profile['numOverDriveHoldsAvailable'] + $eContentAccountSummary['numEContentAvailableHolds']; $profile['numHoldsRequestedTotal'] = $profile['numHoldsRequested'] + $profile['numOverDriveHoldsRequested'] + $eContentAccountSummary['numEContentUnavailableHolds']; $profile['numHoldsTotal'] = $profile['numHoldsAvailableTotal'] + $profile['numHoldsRequestedTotal']; //Get a count of the materials requests for the user if ($user) { $materialsRequest = new MaterialsRequest(); $materialsRequest->createdBy = $user->id; $homeLibrary = Library::getPatronHomeLibrary(); $statusQuery = new MaterialsRequestStatus(); $statusQuery->isOpen = 1; $statusQuery->libraryId = $homeLibrary->libraryId; $materialsRequest->joinAdd($statusQuery); $materialsRequest->find(); $profile['numMaterialsRequests'] = $materialsRequest->N; } $timer->logTime("Got Patron Profile"); $memCache->set($memCacheProfileKey, $profile, 0, $configArray['Caching']['patron_profile']); return $profile; }
/** * Update the configuration array as needed based on scoping rules defined * by the subdomain. * * @param array $configArray the existing main configuration options. * * @return array the configuration options adjusted based on the scoping rules. */ function updateConfigForScoping($configArray) { global $timer; //Get the subdomain for the request global $serverName; //split the servername based on global $subdomain; $subdomain = null; if (strpos($_SERVER['SERVER_NAME'], '.')) { $serverComponents = explode('.', $_SERVER['SERVER_NAME']); if (count($serverComponents) >= 3) { //URL is probably of the form subdomain.marmot.org or subdomain.opac.marmot.org $subdomain = $serverComponents[0]; } else { if (count($serverComponents) == 2) { //URL could be either subdomain.localhost or marmot.org. Only use the subdomain //If the second component is localhost. if (strcasecmp($serverComponents[1], 'localhost') == 0) { $subdomain = $serverComponents[0]; } } } //Trim off test indicator when doing lookups for library/location if (substr($subdomain, -1) == '2' || substr($subdomain, -1) == '3') { $subdomain = substr($subdomain, 0, -1); } } $timer->logTime('got subdomain'); //Load the library system information global $library; global $locationSingleton; if (isset($_SESSION['library']) && isset($_SESSION['location'])) { $library = $_SESSION['library']; $locationSingleton = $_SESSION['library']; } else { $Library = new Library(); $Library->whereAdd("subdomain = '{$subdomain}'"); $Library->find(); if ($Library->N == 1) { $Library->fetch(); //Make the library information global so we can work with it later. $library = $Library; } else { //The subdomain can also indicate a location. $Location = new Location(); $Location->whereAdd("code = '{$subdomain}'"); $Location->find(); if ($Location->N == 1) { $Location->fetch(); //We found a location for the subdomain, get the library. /** @var Library $librarySingleton */ global $librarySingleton; $library = $librarySingleton->getLibraryForLocation($Location->locationId); $locationSingleton->setActiveLocation(clone $Location); } else { //Check to see if there is only one library in the system $Library = new Library(); $Library->find(); if ($Library->N == 1) { $Library->fetch(); $library = $Library; } } } } if (isset($library) && $library != null) { //Update the title $configArray['Site']['theme'] = $library->themeName . ',' . $configArray['Site']['theme'] . ',default'; $configArray['Site']['title'] = $library->displayName; $location = $locationSingleton->getActiveLocation(); //Add an extra css file for the location if it exists. $themes = explode(',', $library->themeName); foreach ($themes as $themeName) { if ($location != null && file_exists('./interface/themes/' . $themeName . '/images/' . $location->code . '_logo_responsive.png')) { $configArray['Site']['responsiveLogo'] = '/interface/themes/' . $themeName . '/images/' . $location->code . '_logo_responsive.png'; } if ($subdomain != null && file_exists('./interface/themes/' . $themeName . '/images/' . $subdomain . '_logo_responsive.png')) { $configArray['Site']['responsiveLogo'] = '/interface/themes/' . $themeName . '/images/' . $subdomain . '_logo_responsive.png'; } if ($location != null && file_exists('./interface/themes/' . $themeName . '/images/' . $location->code . '_logo_small.png')) { $configArray['Site']['smallLogo'] = '/interface/themes/' . $themeName . '/images/' . $location->code . '_logo_small.png'; } if ($location != null && file_exists('./interface/themes/' . $themeName . '/images/' . $location->code . '_logo_large.png')) { $configArray['Site']['largeLogo'] = '/interface/themes/' . $themeName . '/images/' . $location->code . '_logo_large.png'; } } } $timer->logTime('finished update config for scoping'); return $configArray; }
/** * Load status (holdings) for a record and filter them based on the logged in user information. * * Format of return array is: * key = {section#}{location}-### where ### is the holding iteration * * value = array ( * id = The id of the bib * number = The position of the holding within the original list of holdings * section = A description of the section * sectionId = a numeric id of the section for sorting * type = holding * status * statusfull * availability * holdable * nonHoldableReason * reserve * holdQueueLength * duedate * location * libraryDisplayName * locationLink * callnumber * link = array * linkText * isDownload * ) * * Includes both physical titles as well as titles on order * * @param string $id the id of the record * @return array A list of holdings for the record */ public function getStatus($id) { if (array_key_exists($id, MillenniumStatusLoader::$loadedStatus)) { return MillenniumStatusLoader::$loadedStatus[$id]; } global $library; global $user; global $timer; global $logger; global $configArray; $pType = $this->driver->getPType(); $scope = $this->driver->getMillenniumScope(); if (!$configArray['Catalog']['offline']) { //Get information about holdings, order information, and issue information $millenniumInfo = $this->driver->getMillenniumRecordInfo($id); //Get the number of holds if ($millenniumInfo->framesetInfo) { if (preg_match('/(\\d+) hold(s?) on .*? of \\d+ (copies|copy)/', $millenniumInfo->framesetInfo, $matches)) { $holdQueueLength = $matches[1]; } else { $holdQueueLength = 0; } } // Load Record Page $r = substr($millenniumInfo->holdingsInfo, stripos($millenniumInfo->holdingsInfo, 'bibItems')); $r = substr($r, strpos($r, ">") + 1); $r = substr($r, 0, stripos($r, "</table")); $rows = preg_split("/<tr([^>]*)>/", $r); } else { $rows = array(); $millenniumInfo = null; } //Load item information from marc record $matchItemsWithMarcItems = $configArray['Catalog']['matchItemsWithMarcItems']; if ($matchItemsWithMarcItems) { // Load the full marc record so we can get the iType for each record. $marcRecord = MarcLoader::loadMarcRecordByILSId($id); $marcItemField = isset($configArray['Reindex']['itemTag']) ? $configArray['Reindex']['itemTag'] : '989'; $itemFields = $marcRecord->getFields($marcItemField); $marcItemData = array(); //TODO: Don't hardcode item subfields $statusSubfield = $configArray['Reindex']['statusSubfield']; $dueDateSubfield = $configArray['Reindex']['dueDateSubfield']; $locationSubfield = $configArray['Reindex']['locationSubfield']; $iTypeSubfield = $configArray['Reindex']['iTypeSubfield']; $callNumberPrestampSubfield = $configArray['Reindex']['callNumberPrestampSubfield']; $callNumberSubfield = $configArray['Reindex']['callNumberSubfield']; $callNumberCutterSubfield = $configArray['Reindex']['callNumberCutterSubfield']; $callNumberPoststampSubfield = $configArray['Reindex']['callNumberPoststampSubfield']; $volumeSubfield = $configArray['Reindex']['volumeSubfield']; $lastCheckinDateSubfield = $configArray['Reindex']['lastCheckinDateSubfield']; // added plb 3-24-2015 foreach ($itemFields as $itemField) { /** @var $itemField File_MARC_Data_Field */ $fullCallNumber = $itemField->getSubfield($callNumberPrestampSubfield) != null ? $itemField->getSubfield($callNumberPrestampSubfield)->getData() . ' ' : ''; $fullCallNumber .= $itemField->getSubfield($callNumberSubfield) != null ? $itemField->getSubfield($callNumberSubfield)->getData() : ''; $fullCallNumber .= $itemField->getSubfield($callNumberCutterSubfield) != null ? ' ' . $itemField->getSubfield($callNumberCutterSubfield)->getData() : ''; $fullCallNumber .= $itemField->getSubfield($callNumberPoststampSubfield) != null ? ' ' . $itemField->getSubfield($callNumberPoststampSubfield)->getData() : ''; $fullCallNumber .= $itemField->getSubfield($volumeSubfield) != null ? ' ' . $itemField->getSubfield($volumeSubfield)->getData() : ''; $fullCallNumber = str_replace(' ', ' ', $fullCallNumber); $itemData['callnumber'] = $fullCallNumber; $itemData['location'] = $itemField->getSubfield($locationSubfield) != null ? trim($itemField->getSubfield($locationSubfield)->getData()) : '?????'; $itemData['iType'] = $itemField->getSubfield($iTypeSubfield) != null ? $itemField->getSubfield($iTypeSubfield)->getData() : '-1'; $itemData['matched'] = false; $itemData['status'] = $itemField->getSubfield($statusSubfield) != null ? $itemField->getSubfield($statusSubfield)->getData() : '-'; $itemData['dueDate'] = $itemField->getSubfield($dueDateSubfield) != null ? trim($itemField->getSubfield($dueDateSubfield)->getData()) : null; $lastCheckinDate = $itemField->getSubfield($lastCheckinDateSubfield); // added plb 3-24-2015 if ($lastCheckinDate) { // convert to timestamp for ease of display in template $lastCheckinDate = trim($lastCheckinDate->getData()); $lastCheckinDate = DateTime::createFromFormat('m-d-Y G:i', $lastCheckinDate); if ($lastCheckinDate) { $lastCheckinDate = $lastCheckinDate->getTimestamp(); } } $itemData['lastCheckinDate'] = $lastCheckinDate ? $lastCheckinDate : null; $marcItemData[] = $itemData; } } else { $marcItemData = array(); $marcRecord = null; } if (!$configArray['Catalog']['offline']) { //Process each row in the callnumber table. $ret = $this->parseHoldingRows($id, $rows); if (count($ret) == 0) { //Also check the frameset for links if (preg_match('/<div class="bibDisplayUrls">.*?<table.*?>(.*?)<\\/table>.*?<\\/div>/si', $millenniumInfo->framesetInfo, $displayUrlInfo)) { $linksTable = $displayUrlInfo[1]; preg_match_all('/<td.*?>.*?<a href="(.*?)".*?>(.*?)<\\/a>.*?<\\/td>/si', $linksTable, $linkData, PREG_SET_ORDER); for ($i = 0; $i < count($linkData); $i++) { $linkText = $linkData[$i][2]; if ($linkText != 'Latest Received') { $newHolding = array('type' => 'holding', 'link' => array(), 'status' => 'Online', 'location' => 'Online'); $newHolding['link'][] = array('link' => $linkData[$i][1], 'linkText' => $linkText, 'isDownload' => true); $ret[] = $newHolding; } } } } $timer->logTime('processed all holdings rows'); } else { $ret = null; } global $locationSingleton; /** @var $locationSingleton Location */ $physicalLocation = $locationSingleton->getPhysicalLocation(); if ($physicalLocation != null) { $physicalBranch = $physicalLocation->holdingBranchLabel; } else { $physicalBranch = ''; } $homeBranch = ''; $homeBranchId = 0; $nearbyBranch1 = ''; $nearbyBranch1Id = 0; $nearbyBranch2 = ''; $nearbyBranch2Id = 0; //Set location information based on the user login. This will override information based if (isset($user) && $user != false) { $homeBranchId = $user->homeLocationId; $nearbyBranch1Id = $user->myLocation1Id; $nearbyBranch2Id = $user->myLocation2Id; } else { //Check to see if the cookie for home location is set. if (isset($_COOKIE['home_location']) && is_numeric($_COOKIE['home_location'])) { $cookieLocation = new Location(); $locationId = $_COOKIE['home_location']; $cookieLocation->whereAdd("locationId = '{$locationId}'"); $cookieLocation->find(); if ($cookieLocation->N == 1) { $cookieLocation->fetch(); $homeBranchId = $cookieLocation->locationId; $nearbyBranch1Id = $cookieLocation->nearbyLocation1; $nearbyBranch2Id = $cookieLocation->nearbyLocation2; } } } //Load the holding label for the user's home location. $userLocation = new Location(); $userLocation->whereAdd("locationId = '{$homeBranchId}'"); $userLocation->find(); if ($userLocation->N == 1) { $userLocation->fetch(); $homeBranch = $userLocation->holdingBranchLabel; } //Load nearby branch 1 $nearbyLocation1 = new Location(); $nearbyLocation1->whereAdd("locationId = '{$nearbyBranch1Id}'"); $nearbyLocation1->find(); if ($nearbyLocation1->N == 1) { $nearbyLocation1->fetch(); $nearbyBranch1 = $nearbyLocation1->holdingBranchLabel; } //Load nearby branch 2 $nearbyLocation2 = new Location(); $nearbyLocation2->whereAdd(); $nearbyLocation2->whereAdd("locationId = '{$nearbyBranch2Id}'"); $nearbyLocation2->find(); if ($nearbyLocation2->N == 1) { $nearbyLocation2->fetch(); $nearbyBranch2 = $nearbyLocation2->holdingBranchLabel; } $sorted_array = array(); //Get a list of the display names for all locations based on holding label. $locationLabels = array(); $location = new Location(); $location->find(); $libraryLocationLabels = array(); $locationCodes = array(); $suppressedLocationCodes = array(); while ($location->fetch()) { if (strlen($location->holdingBranchLabel) > 0 && $location->holdingBranchLabel != '???') { if ($library && $library->libraryId == $location->libraryId) { $cleanLabel = str_replace('/', '\\/', $location->holdingBranchLabel); $libraryLocationLabels[] = str_replace('.', '\\.', $cleanLabel); } $locationLabels[$location->holdingBranchLabel] = $location->displayName; $locationCodes[$location->code] = $location->holdingBranchLabel; if ($location->suppressHoldings == 1) { $suppressedLocationCodes[$location->code] = $location->code; } } } if (count($libraryLocationLabels) > 0) { $libraryLocationLabels = '/^(' . join('|', $libraryLocationLabels) . ').*/i'; } else { $libraryLocationLabels = ''; } //Get the current Ptype for later usage. $timer->logTime('setup for additional holdings processing.'); //Now that we have the holdings, we need to filter and sort them according to scoping rules. if (!$configArray['Catalog']['offline']) { $i = 0; foreach ($ret as $holdingKey => $holding) { $holding['type'] = 'holding'; //Process holdings without call numbers - Need to show items without call numbers //because they may have links, etc. Also show if there is a status. Since some //In process items may not have a call number yet. if ((!isset($holding['callnumber']) || strlen($holding['callnumber']) == 0) && (!isset($holding['link']) || count($holding['link']) == 0) && !isset($holding['status'])) { continue; } //Determine if the holding is available or not. //First check the status if (preg_match('/^(' . $this->driver->availableStatiRegex . ')$/', $holding['status'])) { $holding['availability'] = 1; } else { $holding['availability'] = 0; } if (preg_match('/^(' . $this->driver->holdableStatiRegex . ')$/', $holding['status'])) { $holding['holdable'] = 1; } else { $holding['holdable'] = 0; $holding['nonHoldableReason'] = "This item is not currently available for Patron Holds"; } if (!isset($holding['libraryDisplayName'])) { $holding['libraryDisplayName'] = $holding['location']; } //Get the location id for this holding $holding['locationCode'] = '?????'; foreach ($locationCodes as $locationCode => $holdingLabel) { if (strlen($locationCode) > 0 && preg_match("~{$holdingLabel}~i", $holding['location'])) { $holding['locationCode'] = $locationCode; break; } } if ($holding['locationCode'] == '?????') { $logger->log("Did not find location code for " . $holding['location'] . " record {$id}", PEAR_LOG_DEBUG); } if (array_key_exists($holding['locationCode'], $suppressedLocationCodes)) { $logger->log("Location " . $holding['locationCode'] . " is suppressed", PEAR_LOG_DEBUG); continue; } //Now that we have the location code, try to match with the marc record $holding['iType'] = 0; if ($matchItemsWithMarcItems) { foreach ($marcItemData as $itemKey => $itemData) { if ($itemData['matched'] === false) { // ensure not checked already $locationMatched = strpos($itemData['location'], $holding['locationCode']) === 0; $itemCallNumber = isset($itemData['callnumber']) ? $itemData['callnumber'] : ''; $holdingCallNumber = isset($holding['callnumber']) ? $holding['callnumber'] : ''; if (strlen($itemCallNumber) == 0 || strlen($holding['callnumber']) == 0) { $callNumberMatched = strlen($itemCallNumber) == strlen($holdingCallNumber); } else { $callNumberMatched = strpos($itemCallNumber, $holdingCallNumber) >= 0; } if ($locationMatched && $callNumberMatched) { $holding['iType'] = $itemData['iType']; $holding['lastCheckinDate'] = $itemData['lastCheckinDate']; // if the marc record matches up, include the last checkin date in the holding info. //Get the more specific location code if (strlen($holding['locationCode']) < strlen($itemData['location'])) { $holding['locationCode'] = $itemData['location']; } $itemData['matched'] = true; $marcItemData[$itemKey] = $itemData; // add matched sub-array element back to original array being looped over. break; } } } //Check to see if this item can be held by the current patron. Only important when //we know what pType is in use and we are showing all items. if ($scope == $this->driver->getDefaultScope() && $pType >= 0) { //Never remove the title if it is owned by the current library (could be in library use only) if (isset($library) && strlen($library->ilsCode) > 0 && strpos($holding['locationCode'], $library->ilsCode) === 0) { //$logger->log("Cannot remove holding because it belongs to the active library", PEAR_LOG_DEBUG); } else { if (!$this->driver->isItemHoldableToPatron($holding['locationCode'], $holding['iType'], $pType)) { //$logger->log("Removing item $holdingKey because it is not usable by the current patronType $pType, iType is {$holding['iType']}, location is {$holding['locationCode']}", PEAR_LOG_DEBUG); //echo("Removing item $holdingKey because it is not usable by the current patronType $pType, iType is {$holding['iType']}, location is {$holding['locationCode']}"); unset($ret[$holdingKey]); continue; } } } else { if ($pType >= 0 && $holding['holdable'] == 1) { //We won't want to remove titles based on holdability, but we do want to check if it is holdable if (!$this->driver->isItemHoldableToPatron($holding['locationCode'], $holding['iType'], $pType)) { $holding['holdable'] = 0; } } } } //Set the hold queue length $holding['holdQueueLength'] = isset($holdQueueLength) ? $holdQueueLength : null; //Add the holding to the sorted array to determine $paddedNumber = str_pad($i, 3, '0', STR_PAD_LEFT); $sortString = $holding['location'] . '-' . $paddedNumber; //$sortString = $holding['location'] . $holding['callnumber']. $i; if (strlen($physicalBranch) > 0 && stripos($holding['location'], $physicalBranch) !== false) { //If the user is in a branch, those holdings come first. $holding['section'] = 'In this library'; $holding['sectionId'] = 1; $sorted_array['1' . $sortString] = $holding; } else { if (strlen($homeBranch) > 0 && stripos($holding['location'], $homeBranch) !== false) { //Next come the user's home branch if the user is logged in or has the home_branch cookie set. $holding['section'] = 'Your library'; $holding['sectionId'] = 2; $sorted_array['2' . $sortString] = $holding; } else { if (strlen($nearbyBranch1) > 0 && stripos($holding['location'], $nearbyBranch1) !== false) { //Next come nearby locations for the user $holding['section'] = 'Nearby Libraries'; $holding['sectionId'] = 3; $sorted_array['3' . $sortString] = $holding; } else { if (strlen($nearbyBranch2) > 0 && stripos($holding['location'], $nearbyBranch2) !== false) { //Next come nearby locations for the user $holding['section'] = 'Nearby Libraries'; $holding['sectionId'] = 4; $sorted_array['4' . $sortString] = $holding; } else { if (strlen($libraryLocationLabels) > 0 && preg_match($libraryLocationLabels, $holding['location'])) { //Next come any locations within the same system we are in. $holding['section'] = $library->displayName; $holding['sectionId'] = 5; $sorted_array['5' . $sortString] = $holding; } else { //Finally, all other holdings are shown sorted alphabetically. $holding['section'] = 'Other Locations'; $holding['sectionId'] = 6; $sorted_array['6' . $sortString] = $holding; } } } } } $i++; } } else { $i = 0; //Offline circ, process each item in the marc record foreach ($marcItemData as $marcData) { $i++; $holding = array(); $holding['type'] = 'holding'; $holding['locationCode'] = $marcData['location']; $holding['callnumber'] = $marcData['callnumber']; $holding['statusfull'] = $this->translateStatusCode($marcData['status'], $marcData['dueDate']); $holding['lastCheckinDate'] = $marcData['lastCheckinDate']; //Try to translate the location code at least to location $location = new Location(); $location->whereAdd("LOCATE(code, '{$marcData['location']}') = 1"); if ($location->find(true)) { $holding['location'] = $location->displayName; } else { $holding['location'] = $marcData['location']; } if (array_key_exists($holding['locationCode'], $suppressedLocationCodes)) { $logger->log("Location " . $holding['locationCode'] . " is suppressed", PEAR_LOG_DEBUG); continue; } $holding['iType'] = $marcData['iType']; if ($marcData['status'] == '-' && $marcData['dueDate'] == null) { $holding['availability'] = 1; } else { $holding['availability'] = 0; } //Check to see if this item can be held by the current patron. Only important when //we know what pType is in use and we are showing all items. if ($scope == $this->driver->getDefaultScope() && $pType > 0) { //Never remove the title if it is owned by the current library (could be in library use only) if (isset($library) && strlen($library->ilsCode) > 0 && strpos($holding['locationCode'], $library->ilsCode) === 0) { //$logger->log("Cannot remove holding because it belongs to the active library", PEAR_LOG_DEBUG); } else { if (!$this->driver->isItemHoldableToPatron($holding['locationCode'], $holding['iType'], $pType)) { //$logger->log("Removing item because it is not usable by the current patronType $pType, iType is {$holding['iType']}, location is {$holding['locationCode']}", PEAR_LOG_DEBUG); //echo("Removing item $holdingKey because it is not usable by the current patronType $pType, iType is {$holding['iType']}, location is {$holding['locationCode']}"); continue; } } } $paddedNumber = str_pad($i, 3, '0', STR_PAD_LEFT); $sortString = $holding['location'] . '-' . $paddedNumber; if (strlen($physicalBranch) > 0 && stripos($holding['location'], $physicalBranch) !== false) { //If the user is in a branch, those holdings come first. $holding['section'] = 'In this library'; $holding['sectionId'] = 1; $sorted_array['1' . $sortString] = $holding; } else { if (strlen($homeBranch) > 0 && stripos($holding['location'], $homeBranch) !== false) { //Next come the user's home branch if the user is logged in or has the home_branch cookie set. $holding['section'] = 'Your library'; $holding['sectionId'] = 2; $sorted_array['2' . $sortString] = $holding; } else { if (strlen($nearbyBranch1) > 0 && stripos($holding['location'], $nearbyBranch1) !== false) { //Next come nearby locations for the user $holding['section'] = 'Nearby Libraries'; $holding['sectionId'] = 3; $sorted_array['3' . $sortString] = $holding; } else { if (strlen($nearbyBranch2) > 0 && stripos($holding['location'], $nearbyBranch2) !== false) { //Next come nearby locations for the user $holding['section'] = 'Nearby Libraries'; $holding['sectionId'] = 4; $sorted_array['4' . $sortString] = $holding; } else { if (strlen($libraryLocationLabels) > 0 && preg_match($libraryLocationLabels, $holding['location'])) { //Next come any locations within the same system we are in. $holding['section'] = $library->displayName; $holding['sectionId'] = 5; $sorted_array['5' . $sortString] = $holding; } else { //Finally, all other holdings are shown sorted alphabetically. $holding['section'] = 'Other Locations'; $holding['sectionId'] = 6; $sorted_array['6' . $sortString] = $holding; } } } } } } } $timer->logTime('finished processing holdings'); //Check to see if the title is holdable $holdable = $this->driver->isRecordHoldable($marcRecord); foreach ($sorted_array as $key => $holding) { //Do not override holdability based on status if (isset($holding['holdable']) && $holding['holdable'] == 1) { $holding['holdable'] = $holdable ? 1 : 0; $sorted_array[$key] = $holding; } } if (!$configArray['Catalog']['offline']) { //Load order records, these only show in the full page view, not the item display $orderMatches = array(); if (preg_match_all('/<tr\\s+class="bibOrderEntry">.*?<td\\s*>(.*?)<\\/td>/s', $millenniumInfo->framesetInfo, $orderMatches)) { for ($i = 0; $i < count($orderMatches[1]); $i++) { $location = trim($orderMatches[1][$i]); $location = preg_replace('/\\sC\\d{3}\\w{0,2}[\\s\\.]/', '', $location); //Remove courier code if any $sorted_array['7' . $location . $i] = array('location' => $location, 'section' => 'On Order', 'sectionId' => 7, 'holdable' => 1); } } $timer->logTime('loaded order records'); } ksort($sorted_array); //Check to see if we can remove the sections. //We can if all section keys are the same. $removeSection = true; $lastKeyIndex = ''; foreach ($sorted_array as $key => $holding) { $currentKey = substr($key, 0, 1); if ($lastKeyIndex == '') { $lastKeyIndex = $currentKey; } else { if ($lastKeyIndex != $currentKey) { $removeSection = false; break; } } } foreach ($sorted_array as $key => $holding) { if ($removeSection == true) { $holding['section'] = ''; $sorted_array[$key] = $holding; } } if (!$configArray['Catalog']['offline']) { $issueSummaries = $this->driver->getIssueSummaries($millenniumInfo); } else { $issueSummaries = null; } $timer->logTime('loaded issue summaries'); if (!is_null($issueSummaries)) { krsort($sorted_array); //Group holdings under the issue issue summary that is related. foreach ($sorted_array as $key => $holding) { //Have issue summary = false $haveIssueSummary = false; $issueSummaryKey = null; foreach ($issueSummaries as $issueKey => $issueSummary) { if ($issueSummary['location'] == $holding['location']) { $haveIssueSummary = true; $issueSummaryKey = $issueKey; break; } } if ($haveIssueSummary) { $issueSummaries[$issueSummaryKey]['holdings'][strtolower($key)] = $holding; } else { //Need to automatically add a summary so we don't lose data $issueSummaries[$holding['location']] = array('location' => $holding['location'], 'type' => 'issue', 'holdings' => array(strtolower($key) => $holding)); } } foreach ($issueSummaries as $key => $issueSummary) { if (isset($issueSummary['holdings']) && is_array($issueSummary['holdings'])) { krsort($issueSummary['holdings']); $issueSummaries[$key] = $issueSummary; } } ksort($issueSummaries); $status = $issueSummaries; } else { $status = $sorted_array; } MillenniumStatusLoader::$loadedStatus[$id] = $status; return $status; }
function updateCatalogOptions() { //Validate that the input data is correct if (isset($_POST['myLocation1']) && preg_match('/^\\d{1,3}$/', $_POST['myLocation1']) == 0) { PEAR_Singleton::raiseError('The 1st location had an incorrect format.'); } if (isset($_POST['myLocation2']) && preg_match('/^\\d{1,3}$/', $_POST['myLocation2']) == 0) { PEAR_Singleton::raiseError('The 2nd location had an incorrect format.'); } if (isset($_REQUEST['bypassAutoLogout']) && ($_REQUEST['bypassAutoLogout'] == 'yes' || $_REQUEST['bypassAutoLogout'] == 'on')) { $this->bypassAutoLogout = 1; } else { $this->bypassAutoLogout = 0; } //Make sure the selected location codes are in the database. if (isset($_POST['myLocation1'])) { $location = new Location(); $location->whereAdd("locationId = '{$_POST['myLocation1']}'"); $location->find(); if ($location->N != 1) { PEAR_Singleton::raiseError('The 1st location could not be found in the database.'); } $this->myLocation1Id = $_POST['myLocation1']; } if (isset($_POST['myLocation2'])) { $location = new Location(); $location->whereAdd(); $location->whereAdd("locationId = '{$_POST['myLocation2']}'"); $location->find(); if ($location->N != 1) { PEAR_Singleton::raiseError('The 2nd location could not be found in the database.'); } $this->myLocation2Id = $_POST['myLocation2']; } $this->update(); //Update the serialized instance stored in the session $_SESSION['userinfo'] = serialize($this); /** @var Memcache $memCache */ global $memCache; global $serverName; $memCache->delete("patronProfile_{$serverName}_" . $this->username); }
public function parseHoldsPage($sResult) { global $logger; $availableHolds = array(); $unavailableHolds = array(); $holds = array('available' => $availableHolds, 'unavailable' => $unavailableHolds); $sResult = preg_replace("/<[^<]+?>\\W<[^<]+?>\\W\\d* HOLD.?\\W<[^<]+?>\\W<[^<]+?>/", "", $sResult); //$logger->log('Hold information = ' . $sresult, PEAR_LOG_INFO); $s = substr($sResult, stripos($sResult, 'patFunc')); $s = substr($s, strpos($s, ">") + 1); $s = substr($s, 0, stripos($s, "</table")); $s = preg_replace("/<br \\/>/", "", $s); $sRows = preg_split("/<tr([^>]*)>/", $s); $sCount = 0; $sKeys = array_pad(array(), 10, ""); foreach ($sRows as $sRow) { $sCols = preg_split("/<t(h|d)([^>]*)>/", $sRow); $curHold = array(); $curHold['create'] = null; $curHold['reqnum'] = null; //Holds page occassionally has a header with number of items checked out. for ($i = 0; $i < sizeof($sCols); $i++) { $sCols[$i] = str_replace(" ", " ", $sCols[$i]); $sCols[$i] = preg_replace("/<br+?>/", " ", $sCols[$i]); $sCols[$i] = html_entity_decode(trim(substr($sCols[$i], 0, stripos($sCols[$i], "</t")))); //print_r($scols[$i]); if ($sCount <= 1) { $sKeys[$i] = $sCols[$i]; } else { if ($sCount > 1) { if ($sKeys[$i] == "CANCEL") { //Only check Cancel key, not Cancel if not filled by //Extract the id from the checkbox $matches = array(); $numMatches = preg_match_all('/.*?cancel(.*?)x(\\d\\d).*/s', $sCols[$i], $matches); if ($numMatches > 0) { $curHold['renew'] = "BOX"; $curHold['cancelable'] = true; $curHold['itemId'] = $matches[1][0]; $curHold['xnum'] = $matches[2][0]; $curHold['cancelId'] = $matches[1][0] . '~' . $matches[2][0]; } else { $curHold['cancelable'] = false; } } if (stripos($sKeys[$i], "TITLE") > -1) { if (preg_match('/.*?<a href=\\"\\/record=(.*?)(?:~S\\d{1,2})\\">(.*?)<\\/a>.*/', $sCols[$i], $matches)) { $shortId = $matches[1]; $bibid = '.' . $matches[1]; //Technically, this isn't corrcect since the check digit is missing $title = $matches[2]; } else { $bibid = ''; $shortId = ''; $title = trim($sCols[$i]); } $curHold['id'] = $bibid; $curHold['shortId'] = $shortId; $curHold['title'] = $title; } if (stripos($sKeys[$i], "Ratings") > -1) { $curHold['request'] = "STARS"; } if (stripos($sKeys[$i], "PICKUP LOCATION") > -1) { //Extract the current location for the hold if possible $matches = array(); if (preg_match('/<select\\s+name=loc(.*?)x(\\d\\d).*?<option\\s+value="([a-z]{1,5})[+ ]*"\\s+selected="selected">.*/s', $sCols[$i], $matches)) { $curHold['locationId'] = $matches[1]; $curHold['locationXnum'] = $matches[2]; $curPickupBranch = new Location(); $curPickupBranch->whereAdd("code = '{$matches[3]}'"); $curPickupBranch->find(1); if ($curPickupBranch->N > 0) { $curPickupBranch->fetch(); $curHold['currentPickupId'] = $curPickupBranch->locationId; $curHold['currentPickupName'] = $curPickupBranch->displayName; $curHold['location'] = $curPickupBranch->displayName; } $curHold['locationUpdateable'] = true; //Return the full select box for reference. $curHold['locationSelect'] = $sCols[$i]; } else { $curHold['location'] = $sCols[$i]; //Trim the carrier code if any if (preg_match('/.*\\s[\\w\\d]{4}/', $curHold['location'])) { $curHold['location'] = substr($curHold['location'], 0, strlen($curHold['location']) - 5); } $curHold['currentPickupName'] = $curHold['location']; $curHold['locationUpdateable'] = false; } } if (stripos($sKeys[$i], "STATUS") > -1) { $status = trim(strip_tags($sCols[$i])); $status = strtolower($status); $status = ucwords($status); if ($status != " ") { $curHold['status'] = $status; if (preg_match('/READY.*(\\d{2}-\\d{2}-\\d{2})/i', $status, $matches)) { $curHold['status'] = 'Ready'; //Get expiration date $exipirationDate = $matches[1]; $expireDate = DateTime::createFromFormat('m-d-y', $exipirationDate); $curHold['expire'] = $expireDate->getTimestamp(); } elseif (preg_match('/READY\\sFOR\\sPICKUP/i', $status, $matches)) { $curHold['status'] = 'Ready'; } else { $curHold['status'] = $status; } } else { $curHold['status'] = "Pending {$status}"; } $matches = array(); $curHold['renewError'] = false; if (preg_match('/.*DUE\\s(\\d{2}-\\d{2}-\\d{2}).*(?:<font color="red">\\s*(.*)<\\/font>).*/s', $sCols[$i], $matches)) { //Renew error $curHold['renewError'] = $matches[2]; $curHold['statusMessage'] = $matches[2]; } else { if (preg_match('/.*DUE\\s(\\d{2}-\\d{2}-\\d{2})\\s(.*)?/s', $sCols[$i], $matches)) { $curHold['statusMessage'] = $matches[2]; } } $logger->log('Status for item ' . $curHold['id'] . '=' . $sCols[$i], PEAR_LOG_INFO); } if (stripos($sKeys[$i], "CANCEL IF NOT FILLED BY") > -1) { //$curHold['expire'] = strip_tags($scols[$i]); } if (stripos($sKeys[$i], "FREEZE") > -1) { $matches = array(); $curHold['frozen'] = false; if (preg_match('/<input.*name="freeze(.*?)"\\s*(\\w*)\\s*\\/>/', $sCols[$i], $matches)) { $curHold['freezeable'] = true; if (strlen($matches[2]) > 0) { $curHold['frozen'] = true; $curHold['status'] = 'Frozen'; } } elseif (preg_match('/This hold can\\s?not be frozen/i', $sCols[$i], $matches)) { //If we detect an error Freezing the hold, save it so we can report the error to the user later. $shortId = str_replace('.b', 'b', $curHold['id']); $_SESSION['freezeResult'][$shortId]['message'] = $sCols[$i]; $_SESSION['freezeResult'][$shortId]['result'] = false; } else { $curHold['freezeable'] = false; } } } } } //End of columns if ($sCount > 1) { if (!isset($curHold['status']) || strcasecmp($curHold['status'], "ready") != 0) { $holds['unavailable'][] = $curHold; } else { $holds['available'][] = $curHold; } } $sCount++; } //End of the row return $holds; }
/** * Load status (holdings) for a record and filter them based on the logged in user information. * * @param string $id the id of the record * @return array A list of holdings for the record */ public function getStatus($id) { global $library; global $user; global $timer; global $logger; //Get information about holdings, order information, and issue information $millenniumInfo = $this->driver->getMillenniumRecordInfo($id); //Get the number of holds if ($millenniumInfo->framesetInfo) { if (preg_match('/(\\d+) hold(s?) on .*? of \\d+ (copies|copy)/', $millenniumInfo->framesetInfo, $matches)) { $holdQueueLength = $matches[1]; } else { $holdQueueLength = 0; } } // Load Record Page $r = substr($millenniumInfo->holdingsInfo, stripos($millenniumInfo->holdingsInfo, 'bibItems')); $r = substr($r, strpos($r, ">") + 1); $r = substr($r, 0, stripos($r, "</table")); $rows = preg_split("/<tr([^>]*)>/", $r); // Load the full marc record so we can get the iType for each record. $marcRecord = MarcLoader::loadMarcRecordByILSId($id); $itemFields = $marcRecord->getFields("989"); $marcItemData = array(); $pType = $this->driver->getPType(); $scope = $this->driver->getMillenniumScope(); //Load item information from marc record foreach ($itemFields as $itemField) { /** @var $itemField File_MARC_Data_Field */ $fullCallNumber = $itemField->getSubfield('s') != null ? $itemField->getSubfield('s')->getData() . ' ' : ''; $fullCallNumber .= $itemField->getSubfield('a') != null ? $itemField->getSubfield('a')->getData() : ''; $fullCallNumber .= $itemField->getSubfield('r') != null ? ' ' . $itemField->getSubfield('r')->getData() : ''; $itemData['callnumber'] = $fullCallNumber; $itemData['location'] = $itemField->getSubfield('d') != null ? $itemField->getSubfield('d')->getData() : ($itemField->getSubfield('p') != null ? $itemField->getSubfield('p')->getData() : '?????'); $itemData['iType'] = $itemField->getSubfield('j') != null ? $itemField->getSubfield('j')->getData() : '0'; $itemData['matched'] = false; $marcItemData[] = $itemData; } //Process each row in the callnumber table. $ret = $this->parseHoldingRows($id, $rows); $timer->logTime('processed all holdings rows'); global $locationSingleton; /** @var $locationSingleton Location */ $physicalLocation = $locationSingleton->getPhysicalLocation(); if ($physicalLocation != null) { $physicalBranch = $physicalLocation->holdingBranchLabel; } else { $physicalBranch = ''; } $homeBranch = ''; $homeBranchId = 0; $nearbyBranch1 = ''; $nearbyBranch1Id = 0; $nearbyBranch2 = ''; $nearbyBranch2Id = 0; //Set location information based on the user login. This will override information based if (isset($user) && $user != false) { $homeBranchId = $user->homeLocationId; $nearbyBranch1Id = $user->myLocation1Id; $nearbyBranch2Id = $user->myLocation2Id; } else { //Check to see if the cookie for home location is set. if (isset($_COOKIE['home_location']) && is_numeric($_COOKIE['home_location'])) { $cookieLocation = new Location(); $locationId = $_COOKIE['home_location']; $cookieLocation->whereAdd("locationId = '{$locationId}'"); $cookieLocation->find(); if ($cookieLocation->N == 1) { $cookieLocation->fetch(); $homeBranchId = $cookieLocation->locationId; $nearbyBranch1Id = $cookieLocation->nearbyLocation1; $nearbyBranch2Id = $cookieLocation->nearbyLocation2; } } } //Load the holding label for the user's home location. $userLocation = new Location(); $userLocation->whereAdd("locationId = '{$homeBranchId}'"); $userLocation->find(); if ($userLocation->N == 1) { $userLocation->fetch(); $homeBranch = $userLocation->holdingBranchLabel; } //Load nearby branch 1 $nearbyLocation1 = new Location(); $nearbyLocation1->whereAdd("locationId = '{$nearbyBranch1Id}'"); $nearbyLocation1->find(); if ($nearbyLocation1->N == 1) { $nearbyLocation1->fetch(); $nearbyBranch1 = $nearbyLocation1->holdingBranchLabel; } //Load nearby branch 2 $nearbyLocation2 = new Location(); $nearbyLocation2->whereAdd(); $nearbyLocation2->whereAdd("locationId = '{$nearbyBranch2Id}'"); $nearbyLocation2->find(); if ($nearbyLocation2->N == 1) { $nearbyLocation2->fetch(); $nearbyBranch2 = $nearbyLocation2->holdingBranchLabel; } $sorted_array = array(); //Get a list of the display names for all locations based on holding label. $locationLabels = array(); $location = new Location(); $location->find(); $libraryLocationLabels = array(); $locationCodes = array(); $suppressedLocationCodes = array(); while ($location->fetch()) { if (strlen($location->holdingBranchLabel) > 0 && $location->holdingBranchLabel != '???') { if ($library && $library->libraryId == $location->libraryId) { $cleanLabel = str_replace('/', '\\/', $location->holdingBranchLabel); $libraryLocationLabels[] = str_replace('.', '\\.', $cleanLabel); } $locationLabels[$location->holdingBranchLabel] = $location->displayName; $locationCodes[$location->code] = $location->holdingBranchLabel; if ($location->suppressHoldings == 1) { $suppressedLocationCodes[$location->code] = $location->code; } } } if (count($libraryLocationLabels) > 0) { $libraryLocationLabels = '/^(' . join('|', $libraryLocationLabels) . ').*/i'; } else { $libraryLocationLabels = ''; } //Get the current Ptype for later usage. $timer->logTime('setup for additional holdings processing.'); //Now that we have the holdings, we need to filter and sort them according to scoping rules. $i = 0; foreach ($ret as $holdingKey => $holding) { $holding['type'] = 'holding'; //Process holdings without call numbers - Need to show items without call numbers //because they may have links, etc. Also show if there is a status. Since some //In process items may not have a call number yet. if ((!isset($holding['callnumber']) || strlen($holding['callnumber']) == 0) && (!isset($holding['link']) || count($holding['link']) == 0) && !isset($holding['status'])) { continue; } //Determine if the holding is available or not. //First check the status if (preg_match('/^(' . $this->driver->availableStatiRegex . ')$/', $holding['status'])) { $holding['availability'] = 1; } else { $holding['availability'] = 0; } if (preg_match('/^(' . $this->driver->holdableStatiRegex . ')$/', $holding['status'])) { $holding['holdable'] = 1; } else { $holding['holdable'] = 0; $holding['nonHoldableReason'] = "This item is not currently available for Patron Holds"; } if (!isset($holding['libraryDisplayName'])) { $holding['libraryDisplayName'] = $holding['location']; } //Get the location id for this holding $holding['locationCode'] = '?????'; foreach ($locationCodes as $locationCode => $holdingLabel) { if (strlen($locationCode) > 0 && preg_match("~{$holdingLabel}~i", $holding['location'])) { $holding['locationCode'] = $locationCode; } } if ($holding['locationCode'] == '?????') { $logger->log("Did not find location code for " . $holding['location'], PEAR_LOG_DEBUG); } if (array_key_exists($holding['locationCode'], $suppressedLocationCodes)) { $logger->log("Location " . $holding['locationCode'] . " is suppressed", PEAR_LOG_DEBUG); continue; } //Now that we have the location code, try to match with the marc record $holding['iType'] = 0; foreach ($marcItemData as $itemData) { if (!$itemData['matched']) { $locationMatched = strpos($itemData['location'], $holding['locationCode']) === 0; if (strlen($itemData['callnumber']) == 0 || strlen($holding['callnumber']) == 0) { $callNumberMatched = strlen($holding['callnumber']) == strlen($holding['callnumber']); } else { $callNumberMatched = strpos($itemData['callnumber'], $holding['callnumber']) >= 0; } if ($locationMatched && $callNumberMatched) { $holding['iType'] = $itemData['iType']; $itemData['matched'] = true; } } } //Check to see if this item can be held by the current patron. Only important when //we know what pType is in use and we are showing all items. if ($scope == 93 && $pType > 0) { //Never remove the title if it is owned by the current library (could be in library use only) if (isset($library) && strlen($library->ilsCode) > 0 && strpos($holding['locationCode'], $library->ilsCode) === 0) { $logger->log("Cannot remove holding because it belongs to the active library", PEAR_LOG_DEBUG); } else { if (!$this->driver->isItemHoldableToPatron($holding['locationCode'], $holding['iType'], $pType)) { $logger->log("Removing item {$holdingKey} because it is not usable by the current patronType {$pType}, iType is {$holding['iType']}, location is {$holding['locationCode']}", PEAR_LOG_DEBUG); //echo("Removing item $holdingKey because it is not usable by the current patronType $pType, iType is {$holding['iType']}, location is {$holding['locationCode']}"); unset($ret[$holdingKey]); continue; } } } //Set the hold queue length $holding['holdQueueLength'] = isset($holdQueueLength) ? $holdQueueLength : null; //Add the holding to the sorted array to determine $sortString = $holding['location'] . '-' . $i; //$sortString = $holding['location'] . $holding['callnumber']. $i; if (strlen($physicalBranch) > 0 && stripos($holding['location'], $physicalBranch) !== false) { //If the user is in a branch, those holdings come first. $holding['section'] = 'In this library'; $holding['sectionId'] = 1; $sorted_array['1' . $sortString] = $holding; } else { if (strlen($homeBranch) > 0 && stripos($holding['location'], $homeBranch) !== false) { //Next come the user's home branch if the user is logged in or has the home_branch cookie set. $holding['section'] = 'Your library'; $holding['sectionId'] = 2; $sorted_array['2' . $sortString] = $holding; } else { if (strlen($nearbyBranch1) > 0 && stripos($holding['location'], $nearbyBranch1) !== false) { //Next come nearby locations for the user $holding['section'] = 'Nearby Libraries'; $holding['sectionId'] = 3; $sorted_array['3' . $sortString] = $holding; } else { if (strlen($nearbyBranch2) > 0 && stripos($holding['location'], $nearbyBranch2) !== false) { //Next come nearby locations for the user $holding['section'] = 'Nearby Libraries'; $holding['sectionId'] = 4; $sorted_array['4' . $sortString] = $holding; } else { if (strlen($libraryLocationLabels) > 0 && preg_match($libraryLocationLabels, $holding['location'])) { //Next come any locations within the same system we are in. $holding['section'] = $library->displayName; $holding['sectionId'] = 5; $sorted_array['5' . $sortString] = $holding; } else { //Finally, all other holdings are shown sorted alphabetically. $holding['section'] = 'Other Locations'; $holding['sectionId'] = 6; $sorted_array['6' . $sortString] = $holding; } } } } } $i++; } $timer->logTime('finished processing holdings'); //Check to see if the title is holdable $holdable = $this->driver->isRecordHoldable($marcRecord); foreach ($sorted_array as $key => $holding) { $holding['holdable'] = $holdable ? 1 : 0; $sorted_array[$key] = $holding; } //Load order records, these only show in the full page view, not the item display $orderMatches = array(); if (preg_match_all('/<tr\\s+class="bibOrderEntry">.*?<td\\s*>(.*?)<\\/td>/s', $millenniumInfo->framesetInfo, $orderMatches)) { for ($i = 0; $i < count($orderMatches[1]); $i++) { $location = trim($orderMatches[1][$i]); $location = preg_replace('/\\sC\\d{3}[\\s\\.]/', '', $location); //Remove courier code if any $sorted_array['7' . $location . $i] = array('location' => $location, 'section' => 'On Order', 'sectionId' => 7, 'holdable' => 1); } } $timer->logTime('loaded order records'); ksort($sorted_array); //Check to see if we can remove the sections. //We can if all section keys are the same. $removeSection = true; $lastKeyIndex = ''; foreach ($sorted_array as $key => $holding) { $currentKey = substr($key, 0, 1); if ($lastKeyIndex == '') { $lastKeyIndex = $currentKey; } else { if ($lastKeyIndex != $currentKey) { $removeSection = false; break; } } } foreach ($sorted_array as $key => $holding) { if ($removeSection == true) { $holding['section'] = ''; $sorted_array[$key] = $holding; } } $issueSummaries = $this->driver->getIssueSummaries($millenniumInfo); $timer->logTime('loaded issue summaries'); if (!is_null($issueSummaries)) { krsort($sorted_array); //Group holdings under the issue issue summary that is related. foreach ($sorted_array as $key => $holding) { //Have issue summary = false $haveIssueSummary = false; $issueSummaryKey = null; foreach ($issueSummaries as $issueKey => $issueSummary) { if ($issueSummary['location'] == $holding['location']) { $haveIssueSummary = true; $issueSummaryKey = $issueKey; break; } } if ($haveIssueSummary) { $issueSummaries[$issueSummaryKey]['holdings'][strtolower($key)] = $holding; } else { //Need to automatically add a summary so we don't lose data $issueSummaries[$holding['location']] = array('location' => $holding['location'], 'type' => 'issue', 'holdings' => array(strtolower($key) => $holding)); } } foreach ($issueSummaries as $key => $issueSummary) { if (isset($issueSummary['holdings']) && is_array($issueSummary['holdings'])) { krsort($issueSummary['holdings']); $issueSummaries[$key] = $issueSummary; } } ksort($issueSummaries); return $issueSummaries; } else { return $sorted_array; } }
/** * In Sierra, all status information is up to date within the MARC record * due to the export so we don't need to screen scrape! * * Format of return array is: * key = {section#}{location}-### where ### is the holding iteration * * value = array ( * id = The id of the bib * number = The position of the holding within the original list of holdings * section = A description of the section * sectionId = a numeric id of the section for sorting * type = holding * status * statusfull * reserve * holdQueueLength * duedate * location * locationLink * callnumber * link = array * linkText * isDownload * ) * * Includes both physical titles as well as titles on order * * @param string $id the id of the record * @return array A list of holdings for the record */ public function getStatus($id) { $recordDriver = RecordDriverFactory::initRecordDriverById('ils:' . $id); $format = $recordDriver->getFormat(); if ($format[0] == 'Journal') { return parent::getStatus($id); } if (array_key_exists($id, SierraStatusLoader::$loadedStatus)) { return SierraStatusLoader::$loadedStatus[$id]; } //Load local information global $library; global $locationSingleton; /** @var $locationSingleton Location */ global $user; $physicalLocation = $locationSingleton->getPhysicalLocation(); if ($physicalLocation != null) { $physicalBranch = $physicalLocation->holdingBranchLabel; } else { $physicalBranch = ''; } $homeBranch = ''; $homeBranchId = 0; $nearbyBranch1 = ''; $nearbyBranch1Id = 0; $nearbyBranch2 = ''; $nearbyBranch2Id = 0; //Set location information based on the user login. This will override information based if (isset($user) && $user != false) { $homeBranchId = $user->homeLocationId; $nearbyBranch1Id = $user->myLocation1Id; $nearbyBranch2Id = $user->myLocation2Id; } else { //Check to see if the cookie for home location is set. if (isset($_COOKIE['home_location']) && is_numeric($_COOKIE['home_location'])) { $cookieLocation = new Location(); $locationId = $_COOKIE['home_location']; $cookieLocation->whereAdd("locationId = '{$locationId}'"); $cookieLocation->find(); if ($cookieLocation->N == 1) { $cookieLocation->fetch(); $homeBranchId = $cookieLocation->locationId; $nearbyBranch1Id = $cookieLocation->nearbyLocation1; $nearbyBranch2Id = $cookieLocation->nearbyLocation2; } } } //Load the holding label for the user's home location. $userLocation = new Location(); $userLocation->whereAdd("locationId = '{$homeBranchId}'"); $userLocation->find(); if ($userLocation->N == 1) { $userLocation->fetch(); $homeBranch = $userLocation->holdingBranchLabel; } //Load nearby branch 1 $nearbyLocation1 = new Location(); $nearbyLocation1->whereAdd("locationId = '{$nearbyBranch1Id}'"); $nearbyLocation1->find(); if ($nearbyLocation1->N == 1) { $nearbyLocation1->fetch(); $nearbyBranch1 = $nearbyLocation1->holdingBranchLabel; } //Load nearby branch 2 $nearbyLocation2 = new Location(); $nearbyLocation2->whereAdd(); $nearbyLocation2->whereAdd("locationId = '{$nearbyBranch2Id}'"); $nearbyLocation2->find(); if ($nearbyLocation2->N == 1) { $nearbyLocation2->fetch(); $nearbyBranch2 = $nearbyLocation2->holdingBranchLabel; } //Get a list of the display names for all locations based on holding label. $locationLabels = array(); $location = new Location(); $location->find(); $libraryLocationLabels = array(); $locationCodes = array(); $suppressedLocationCodes = array(); while ($location->fetch()) { if (strlen($location->holdingBranchLabel) > 0 && $location->holdingBranchLabel != '???') { if ($library && $library->libraryId == $location->libraryId) { $cleanLabel = str_replace('/', '\\/', $location->holdingBranchLabel); $libraryLocationLabels[] = str_replace('.', '\\.', $cleanLabel); } $locationLabels[$location->holdingBranchLabel] = $location->displayName; $locationCodes[$location->code] = $location->holdingBranchLabel; if ($location->suppressHoldings == 1) { $suppressedLocationCodes[$location->code] = $location->code; } } } if (count($libraryLocationLabels) > 0) { $libraryLocationLabels = '/^(' . join('|', $libraryLocationLabels) . ').*/i'; } else { $libraryLocationLabels = ''; } //In Sierra, we can just load data from the MARC Record/Index $items = $recordDriver->getItemsFast(); $holdQueueLength = $recordDriver->getNumHolds(); $itemStatus = array(); $i = 0; foreach ($items as $item) { //Determine what section this holding is in $sectionId = 1; $location = $item['shelfLocation']; if (strlen($physicalBranch) > 0 && stripos($location, $physicalBranch) !== false) { //If the user is in a branch, those holdings come first. $section = 'In this library'; $sectionId = 1; } else { if (strlen($homeBranch) > 0 && stripos($location, $homeBranch) !== false) { //Next come the user's home branch if the user is logged in or has the home_branch cookie set. $section = 'Your library'; $sectionId = 2; } else { if (strlen($nearbyBranch1) > 0 && stripos($location, $nearbyBranch1) !== false) { //Next come nearby locations for the user $section = 'Nearby Libraries'; $sectionId = 3; } else { if (strlen($nearbyBranch2) > 0 && stripos($location, $nearbyBranch2) !== false) { //Next come nearby locations for the user $section = 'Nearby Libraries'; $sectionId = 4; } else { if (strlen($libraryLocationLabels) > 0 && preg_match($libraryLocationLabels, $location)) { //Next come any locations within the same system we are in. $section = $library->displayName; $sectionId = 5; } else { //Finally, all other holdings are shown sorted alphabetically. $section = 'Other Locations'; $sectionId = 6; } } } } } $holding = array('location' => $item['shelfLocation'], 'reserve' => stripos($item['shelfLocation'], 'reserve') !== false ? 'Y' : 'N', 'callnumber' => $item['callnumber'], 'status' => $item['status'], 'duedate' => $item['dueDate'], 'lastCheckinDate' => $item['lastCheckinDate'], 'statusfull' => $this->translateStatusCode($item['status'], $item['dueDate']), 'id' => $id, 'number' => $i++, 'holdQueueLength' => $holdQueueLength, 'type' => 'holding', 'availability' => $item['availability'], 'holdable' => $item['holdable'] ? 1 : 0, 'libraryDisplayName' => $item['shelfLocation'], 'locationCode' => $item['location'], 'iType' => $item['iType'], 'section' => $section, 'sectionId' => $sectionId); $paddedNumber = str_pad($i, 3, '0', STR_PAD_LEFT); $holdingKey = $sectionId . $holding['location'] . $paddedNumber; $itemStatus[$holdingKey] = $holding; } ksort($itemStatus); SierraStatusLoader::$loadedStatus[$id] = $itemStatus; return $itemStatus; }