/** * Place Hold * * This is responsible for both placing holds as well as placing recalls. * * @param string $recordId The id of the bib record * @param string $patronId The id of the patron * @param string $comment Any comment regarding the hold or recall * @param string $type Whether to place a hold or recall * @return mixed True if successful, false if unsuccessful * If an error occurs, return a PEAR_Error * @access public */ public function placeHold($recordId, $patronId, $comment, $type) { global $user; $hold_result = array(); $hold_result['result'] = false; //Set pickup location if (isset($_REQUEST['campus'])) { $campus = trim($_REQUEST['campus']); } else { $campus = $user->homeLocationId; //Get the code for the location $locationLookup = new Location(); $locationLookup->locationId = $campus; $locationLookup->find(); if ($locationLookup->N > 0) { $locationLookup->fetch(); $campus = $locationLookup->code; } } $campus = strtoupper($campus); //Get a specific item number to place a hold on even though we are placing a title level hold. //because.... Koha require_once ROOT_DIR . '/RecordDrivers/MarcRecord.php'; $recordDriver = new MarcRecord($recordId); if (!$recordDriver->isValid()) { $hold_result['message'] = 'Unable to find a valid record for this title. Please try your search again.'; return $hold_result; } global $configArray; $marcRecord = $recordDriver->getMarcRecord(); //Check to see if the title requires item level holds /** @var File_MARC_Data_Field[] $holdTypeFields */ $itemLevelHoldAllowed = false; $itemLevelHoldOnly = false; $holdTypeFields = $marcRecord->getFields('942'); foreach ($holdTypeFields as $holdTypeField) { if ($holdTypeField->getSubfield('r') != null) { if ($holdTypeField->getSubfield('r')->getData() == 'itemtitle') { $itemLevelHoldAllowed = true; } else { if ($holdTypeField->getSubfield('r')->getData() == 'item') { $itemLevelHoldAllowed = true; $itemLevelHoldOnly = true; } } } } //Get the items the user can place a hold on $this->loginToKoha($user); $placeHoldPage = $this->getKohaPage($configArray['Catalog']['url'] . '/cgi-bin/koha/opac-reserve.pl?biblionumber=' . $recordId); preg_match_all('/<div class="dialog alert">(.*?)<\\/div>/s', $placeHoldPage, $matches); if (count($matches) > 0 && count($matches[1]) > 0) { $hold_result['title'] = $recordDriver->getTitle(); $hold_result['result'] = false; $hold_result['message'] = ''; foreach ($matches[1] as $errorMsg) { $hold_result['message'] .= $errorMsg . '<br/>'; } return $hold_result; } if ($itemLevelHoldAllowed) { //Need to prompt for an item level hold $items = array(); if (!$itemLevelHoldOnly) { //Add a first title returned $items[-1] = array('itemNumber' => -1, 'location' => 'Next available copy', 'callNumber' => '', 'status' => ''); } //Get the item table from the page if (preg_match('/<table>\\s+<caption>Select a specific copy:<\\/caption>\\s+(.*?)<\\/table>/s', $placeHoldPage, $matches)) { $itemTable = $matches[1]; //Get the header row labels $headerLabels = array(); preg_match_all('/<th[^>]*>(.*?)<\\/th>/si', $itemTable, $tableHeaders, PREG_PATTERN_ORDER); foreach ($tableHeaders[1] as $col => $tableHeader) { $headerLabels[$col] = trim(strip_tags(strtolower($tableHeader))); } //Grab each row within the table preg_match_all('/<tr[^>]*>\\s+(<td.*?)<\\/tr>/si', $itemTable, $tableData, PREG_PATTERN_ORDER); foreach ($tableData[1] as $tableRow) { //Each row in the table represents a hold $curItem = array(); $validItem = false; //Go through each cell in the row preg_match_all('/<td[^>]*>(.*?)<\\/td>/si', $tableRow, $tableCells, PREG_PATTERN_ORDER); foreach ($tableCells[1] as $col => $tableCell) { if ($headerLabels[$col] == 'copy') { if (strpos($tableCell, 'disabled') === false) { $validItem = true; if (preg_match('/value="(\\d+)"/', $tableCell, $valueMatches)) { $curItem['itemNumber'] = $valueMatches[1]; } } } else { if ($headerLabels[$col] == 'item type') { $curItem['itemType'] = trim($tableCell); } else { if ($headerLabels[$col] == 'barcode') { $curItem['barcode'] = trim($tableCell); } else { if ($headerLabels[$col] == 'home library') { $curItem['location'] = trim($tableCell); } else { if ($headerLabels[$col] == 'call number') { $curItem['callNumber'] = trim($tableCell); } else { if ($headerLabels[$col] == 'vol info') { $curItem['volInfo'] = trim($tableCell); } else { if ($headerLabels[$col] == 'information') { $curItem['status'] = trim($tableCell); } } } } } } } } if ($validItem) { $items[$curItem['itemNumber']] = $curItem; } } } elseif (preg_match('/<div class="dialog alert">(.*?)<\\/div>/s', $placeHoldPage, $matches)) { $items = array(); $message = trim($matches[1]); } $hold_result['title'] = $recordDriver->getTitle(); $hold_result['items'] = $items; if (count($items) > 0) { $message = 'This title allows item level holds, please select an item to place a hold on.'; } else { if (!isset($message)) { $message = 'There are no holdable items for this title.'; } } $hold_result['result'] = false; $hold_result['message'] = $message; return $hold_result; } else { //Just a regular bib level hold $hold_result['title'] = $recordDriver->getTitle(); //Post the hold to koha $placeHoldPage = $configArray['Catalog']['url'] . '/cgi-bin/koha/opac-reserve.pl'; $holdParams = array('biblionumbers' => $recordId . '/', 'branch' => $campus, 'place_reserve' => 1, "reqtype_{$recordId}" => 'Any', 'reserve_mode' => 'multi', 'selecteditems' => "{$recordId}//{$campus}/", 'single_bib' => $recordId); $kohaHoldResult = $this->postToKohaPage($placeHoldPage, $holdParams); //If the hold is successful we go back to the account page and can see $hold_result['id'] = $recordId; if (preg_match('/<a href="#opac-user-holds">Holds<\\/a>/si', $kohaHoldResult)) { //We redirected to the holds page, everything seems to be good $holds = $this->getMyHolds($user, 1, -1, 'title', $kohaHoldResult); $hold_result['result'] = true; $hold_result['message'] = "Your hold was placed successfully."; //Find the correct hold (will be unavailable) foreach ($holds['holds']['unavailable'] as $holdInfo) { if ($holdInfo['id'] == $recordId) { if (isset($holdInfo['position'])) { $hold_result['message'] .= " You are number <b>" . $holdInfo['position'] . "</b> in the queue."; } break; } } } else { $hold_result['result'] = false; //Look for an alert message if (preg_match('/<div class="dialog alert">(.*?)<\\/div>/', $kohaHoldResult, $matches)) { $hold_result['message'] = 'Your hold could not be placed. ' . $matches[1]; } else { $hold_result['message'] = 'Your hold could not be placed. '; } } return $hold_result; } }