/** * init * * Establishes base settings for making recommendations. * * @param string $settings Settings from config.ini * @param \VuFind\RecordDriver\AbstractBase $driver Record driver object * * @return void */ public function init($settings, $driver) { $sm = $this->getSearchManager(); $params = $sm->setSearchClassId('Solr')->getParams(); $searcher = $sm->setSearchClassId('Solr')->getResults($params); $this->results = $searcher->getSimilarRecords($driver->getUniqueId()); }
/** * Try to build an array of OCLC Number, ISBN or ISSN-based sub-queries by * using OCLC X-services against a record driver object. * * @param \VuFind\RecordDriver\AbstractBase $driver Record driver object * * @return array */ protected function getQueryParts($driver) { $parts = []; $oclcNum = $driver->tryMethod('getCleanOCLCNum'); if (!empty($oclcNum)) { $oclcList = $this->wcUtils->getXOCLCNUM($oclcNum); if (!empty($oclcList)) { $parts[] = '(srw.no any "' . implode(' ', $oclcList) . '")'; } } $isbn = $driver->tryMethod('getCleanISBN'); if (!empty($isbn)) { $isbnList = $this->wcUtils->getXISBN($isbn); if (!empty($isbnList)) { $parts[] = '(srw.bn any "' . implode(' ', $isbnList) . '")'; } } $issn = $driver->tryMethod('getCleanISSN'); if (!empty($issn)) { $issnList = $this->wcUtils->getXISSN($issn); if (!empty($issnList)) { $parts[] = '(srw.sn any "' . implode(' ', $issnList) . '")'; } } return $parts; }
/** * Pull the search parameters from the query and set up additional options using * a record driver representing a collection. * * @param \VuFind\RecordDriver\AbstractBase $driver Record driver * * @return void */ public function initFromRecordDriver($driver) { $this->collectionID = $driver->getUniqueID(); if ($hierarchyDriver = $driver->getHierarchyDriver()) { switch ($hierarchyDriver->getCollectionLinkType()) { case 'All': $this->collectionField = 'hierarchy_parent_id'; break; case 'Top': $this->collectionField = 'hierarchy_top_id'; break; } } if (null === $this->collectionID) { throw new \Exception('Collection ID missing'); } if (null === $this->collectionField) { throw new \Exception('Collection field missing'); } // We don't spellcheck this screen; it's not for free user input anyway $options = $this->getOptions(); $options->spellcheckEnabled(false); // Prepare the search $safeId = addcslashes($this->collectionID, '"'); $options->addHiddenFilter($this->collectionField . ':"' . $safeId . '"'); $options->addHiddenFilter('!id:"' . $safeId . '"'); }
/** * Support method to turn a record driver object into an RSS entry. * * @param Feed $feed Feed to update * @param \VuFind\RecordDriver\AbstractBase $record Record to add to feed * * @return void */ protected function addEntry($feed, $record) { $entry = $feed->createEntry(); $title = $record->tryMethod('getTitle'); $title = empty($title) ? $record->getBreadcrumb() : $title; $entry->setTitle(empty($title) ? $this->translate('Title not available') : $title); $serverUrl = $this->getView()->plugin('serverurl'); $recordLink = $this->getView()->plugin('recordlink'); try { $url = $serverUrl($recordLink->getUrl($record)); } catch (\Zend\Mvc\Router\Exception\RuntimeException $e) { // No route defined? See if we can get a URL out of the driver. // Useful for web results, among other things. $url = $record->tryMethod('getUrl'); if (empty($url) || !is_string($url)) { throw new \Exception('Cannot find URL for record.'); } } $entry->setLink($url); $date = $this->getDateModified($record); if (!empty($date)) { $entry->setDateModified($date); } $author = $record->tryMethod('getPrimaryAuthor'); if (!empty($author)) { $entry->addAuthor(['name' => $author]); } $authors = $record->tryMethod('getSecondaryAuthors'); if (is_array($authors)) { foreach ($authors as $author) { $entry->addAuthor(['name' => $author]); } } $formats = $record->tryMethod('getFormats'); if (is_array($formats)) { // Take only the most specific format and get rid of level indicator // and trailing slash $format = end($formats); $format = implode('/', array_slice(explode('/', $format), 1, -1)); $entry->addDCFormat($format); } $dcDate = $this->getDcDate($record); if (!empty($dcDate)) { $entry->setDCDate($dcDate); } $urlHelper = $this->getView()->plugin('url'); $recordHelper = $this->getView()->plugin('record'); $recordImage = $this->getView()->plugin('recordImage'); $imageUrl = $recordImage($recordHelper($record))->getLargeImage(); $entry->setEnclosure(['uri' => $serverUrl($imageUrl), 'type' => 'image/jpeg', 'length' => 1]); $entry->setCommentCount(count($record->getComments())); $summaries = $record->tryMethod('getSummary'); if (!empty($summaries)) { $entry->setDescription(implode(' -- ', $summaries)); } $feed->addEntry($entry); }
/** * Pull the search parameters from the query and set up additional options using * a record driver representing a collection. * * @param \VuFind\RecordDriver\AbstractBase $driver Record driver * @param \Zend\StdLib\Parameters $request Parameter object * representing user request. * * @return void */ public function initFromRecordDriver($driver, $request) { $this->collectionID = $driver->getUniqueID(); if ($hierarchyDriver = $driver->getHierarchyDriver()) { switch ($hierarchyDriver->getCollectionLinkType()) { case 'All': $this->collectionField = 'hierarchy_parent_id'; break; case 'Top': $this->collectionField = 'hierarchy_top_id'; break; } } $this->initFromRequest($request); }
/** * Generate a thumbnail URL (return false if unsupported). * * @param RecordDriver $driver Record driver * @param string $size Size of thumbnail (small, medium or large -- * small is default). * * @return string|bool */ public function getUrl(RecordDriver $driver, $size = 'small') { // Try to build thumbnail: $thumb = $driver->tryMethod('getThumbnail', [$size]); // No thumbnail? Return false: if (empty($thumb)) { return false; } // Array? It's parameters to send to the cover generator: if (is_array($thumb)) { return $this->dynamicUrl . '?' . http_build_query($thumb); } // Default case -- return fixed string: return $thumb; }
/** * Establishes base settings for making recommendations. * * @param string $settings Settings from config.ini * @param \VuFind\RecordDriver\AbstractBase $driver Record driver object * * @return void */ public function init($settings, $driver) { // Create array of query parts: $parts = []; // Add Dewey class to query $deweyClass = $driver->tryMethod('getDeweyCallNumber'); if (!empty($deweyClass)) { // Skip "English Fiction" Dewey class -- this won't give us useful // matches because there's too much of it and it's too broad. if (substr($deweyClass, 0, 3) != '823') { $parts[] = 'srw.dd any "' . $deweyClass . '"'; } } // Add author to query $author = $driver->getPrimaryAuthor(); if (!empty($author)) { $parts[] = 'srw.au all "' . $author . '"'; } // Add subjects to query $subjects = $driver->getAllSubjectHeadings(); foreach ($subjects as $current) { $parts[] = 'srw.su all "' . implode(' ', $current) . '"'; } // Add title to query $title = $driver->getTitle(); if (!empty($title)) { $parts[] = 'srw.ti any "' . str_replace('"', '', $title) . '"'; } // Build basic query: $query = '(' . implode(' or ', $parts) . ')'; // Not current record ID if this is already a WorldCat record: if ($driver->getSourceIdentifier() == 'WorldCat') { $id = $driver->getUniqueId(); $query .= " not srw.no all \"{$id}\""; } // Perform the search and save results: $queryObj = new \VuFindSearch\Query\Query($query); $result = $this->searchService->search('WorldCat', $queryObj, 0, 5); $this->results = $result->getRecords(); }
/** * Construct volume/issue/date portion of APA citation. Returns an array with * three elements: volume, issue and date (since these end up in different areas * of the final citation, we don't return a single string, but since their * determination is related, we need to do the work in a single function). * * @return array */ protected function getAPANumbersAndDate() { $vol = $this->driver->tryMethod('getContainerVolume'); $num = $this->driver->tryMethod('getContainerIssue'); $date = $this->details['pubDate']; if (strlen($date) > 4) { try { $year = $this->dateConverter->convertFromDisplayDate('Y', $date); $month = $this->dateConverter->convertFromDisplayDate('F', $date); $day = $this->dateConverter->convertFromDisplayDate('j', $date); } catch (DateException $e) { // If conversion fails, use raw date as year -- not ideal, // but probably better than nothing: $year = $date; $month = $day = ''; } } else { $year = $date; $month = $day = ''; } // We need to supply additional date information if no vol/num: if (!empty($vol) || !empty($num)) { // If only the number is non-empty, move the value to the volume to // simplify template behavior: if (empty($vol) && !empty($num)) { $vol = $num; $num = ''; } return [$vol, $num, $year]; } else { // Right now, we'll assume if day == 1, this is a monthly publication; // that's probably going to result in some bad citations, but it's the // best we can do without writing extra record driver methods. $finalDate = $year . (empty($month) ? '' : ', ' . $month) . ($day > 1 ? ' ' . $day : ''); return ['', '', $finalDate]; } }
/** * Get all the links associated with this record. Returns an array of * associative arrays each containing 'desc' and 'url' keys. * * @return array */ public function getLinkDetails() { // See if there are any links available: $urls = $this->driver->tryMethod('getURLs'); if (empty($urls)) { return []; } // If we found links, we may need to convert from the "route" format // to the "full URL" format. $urlHelper = $this->getView()->plugin('url'); $serverUrlHelper = $this->getView()->plugin('serverurl'); $formatLink = function ($link) use($urlHelper, $serverUrlHelper) { // Error if route AND URL are missing at this point! if (!isset($link['route']) && !isset($link['url'])) { throw new \Exception('Invalid URL array.'); } // Build URL from route/query details if missing: if (!isset($link['url'])) { $routeParams = isset($link['routeParams']) ? $link['routeParams'] : []; $link['url'] = $serverUrlHelper($urlHelper($link['route'], $routeParams)); if (isset($link['queryString'])) { $link['url'] .= $link['queryString']; } } // Apply prefix if found if (isset($link['prefix'])) { $link['url'] = $link['prefix'] . $link['url']; } // Use URL as description if missing: if (!isset($link['desc'])) { $link['desc'] = $link['url']; } return $link; }; return array_map($formatLink, $urls); }
/** * Get the previous/next record in the last search * result set relative to the current one, also return * the position of the current record in the result set. * Return array('previousRecord'=>previd, 'nextRecord'=>nextid, * 'currentPosition'=>number, 'resultTotal'=>number). * * @param \VuFind\RecordDriver\AbstractBase $driver Driver for the record * currently being displayed * * @return array */ public function getScrollData($driver) { $retVal = ['previousRecord' => null, 'nextRecord' => null, 'currentPosition' => null, 'resultTotal' => null]; // Do nothing if disabled or data missing: if ($this->enabled && isset($this->data->currIds) && isset($this->data->searchId) && ($lastSearch = $this->restoreLastSearch())) { // Make sure expected data elements are populated: if (!isset($this->data->prevIds)) { $this->data->prevIds = null; } if (!isset($this->data->nextIds)) { $this->data->nextIds = null; } // Store total result set size: $retVal['resultTotal'] = isset($this->data->total) ? $this->data->total : 0; // build a full ID string using the driver: $id = $driver->getResourceSource() . '|' . $driver->getUniqueId(); // find where this record is in the current result page $pos = is_array($this->data->currIds) ? array_search($id, $this->data->currIds) : false; if ($pos !== false) { // OK, found this record in the current result page // calculate its position relative to the result set $retVal['currentPosition'] = ($this->data->page - 1) * $this->data->limit + $pos + 1; // count how many records in the current result page $count = count($this->data->currIds); if ($pos > 0 && $pos < $count - 1) { // the current record is somewhere in the middle of the current // page, ie: not first or last return $this->scrollOnCurrentPage($retVal, $pos); } else { if ($pos == 0) { // this record is first record on the current page return $this->fetchPreviousPage($retVal, $lastSearch, $pos, $count); } else { if ($pos == $count - 1) { // this record is last record on the current page return $this->fetchNextPage($retVal, $lastSearch, $pos); } } } } else { // the current record is not on the current page // if there is something on the previous page if (!empty($this->data->prevIds)) { // check if current record is on the previous page $pos = is_array($this->data->prevIds) ? array_search($id, $this->data->prevIds) : false; if ($pos !== false) { return $this->scrollToPreviousPage($retVal, $lastSearch, $pos); } } // if there is something on the next page if (!empty($this->data->nextIds)) { // check if current record is on the next page $pos = is_array($this->data->nextIds) ? array_search($id, $this->data->nextIds) : false; if ($pos !== false) { return $this->scrollToNextPage($retVal, $lastSearch, $pos); } } } } return $retVal; }
/** * Get a list of related records modules. * * @param \VuFind\RecordDriver\AbstractBase $driver Record driver * * @return array */ public function getList(\VuFind\RecordDriver\AbstractBase $driver) { return $driver->getRelated($this->pluginManager); }
/** * Process the submission of the edit favorite form. * * @param \VuFind\Db\Row\User $user Logged-in user * @param \VuFind\RecordDriver\AbstractBase $driver Record driver for favorite * @param int $listID List being edited (null * if editing all favorites) * * @return object */ protected function processEditSubmit($user, $driver, $listID) { $lists = $this->params()->fromPost('lists'); $tagParser = $this->getServiceLocator()->get('VuFind\\Tags'); foreach ($lists as $list) { $tags = $this->params()->fromPost('tags' . $list); $driver->saveToFavorites(['list' => $list, 'mytags' => $tagParser->parse($tags), 'notes' => $this->params()->fromPost('notes' . $list)], $user); } // add to a new list? $addToList = $this->params()->fromPost('addToList'); if ($addToList > -1) { $driver->saveToFavorites(['list' => $addToList], $user); } $this->flashMessenger()->setNamespace('info')->addMessage('edit_list_success'); $newUrl = is_null($listID) ? $this->url()->fromRoute('myresearch-favorites') : $this->url()->fromRoute('userList', ['id' => $listID]); return $this->redirect()->toUrl($newUrl); }
/** * Support method to extract modified date from a record driver object. * * @param \VuFind\RecordDriver\AbstractBase $record Record to pull date from. * * @return int|DateTime|null */ protected function getDateModified($record) { // Best case -- "last indexed" date is available: $date = $record->tryMethod('getLastIndexed'); if (!empty($date)) { return strtotime($date); } // Next, try publication date: $date = $record->tryMethod('getPublicationDates'); if (isset($date[0])) { // Extract first string of numbers -- this should be a year: preg_match('/[^0-9]*([0-9]+).*/', $date[0], $matches); $date = new DateTime(); $date->setDate($matches[1], 1, 1); return $date; } // If we got this far, no date is available: return null; }
/** * Get the default subject line for sendRecord() * * @param \VuFind\RecordDriver\AbstractBase $record Record being emailed * * @return string */ public function getDefaultRecordSubject($record) { return $this->translate('Library Catalog Record') . ': ' . $record->getBreadcrumb(); }
/** * Establishes base settings for making recommendations. * * @param string $settings Settings from config.ini * @param \VuFind\RecordDriver\AbstractBase $driver Record driver object * * @return void */ public function init($settings, $driver) { $this->results = $this->searchService->similar($driver->getSourceIdentifier(), $driver->getUniqueId()); }
/** * Establishes base settings for making recommendations. * * @param string $settings Settings from config.ini * @param \VuFind\RecordDriver\AbstractBase $driver Record driver object * * @return void */ public function init($settings, $driver) { $this->results = $this->searchService->similar('Solr', $driver->getUniqueId()); }
/** * Given a record driver, generate a URL to fetch all child records for it. * * @param \VuFind\RecordDriver\AbstractBase $driver Host Record. * * @return string */ public function getChildRecordSearchUrl($driver) { $urlHelper = $this->getView()->plugin('url'); $url = $urlHelper('search-results') . '?lookfor=' . urlencode(addcslashes($driver->getUniqueID(), '"')) . '&type=ParentID'; // Make sure everything is properly HTML encoded: $escaper = $this->getView()->plugin('escapehtml'); return $escaper($url); }
/** * Try to build an array of OCLC Number, ISBN or ISSN-based sub-queries by * using OCLC X-services against a record driver object. * * @param \VuFind\RecordDriver\AbstractBase $driver Record driver object * * @return array */ protected function getQueryParts($driver) { $parts = []; $oclcNum = $driver->tryMethod('getCleanOCLCNum'); if (!empty($oclcNum)) { $oclcList = $this->wcUtils->getXOCLCNUM($oclcNum); foreach ($oclcList as $current) { $parts[] = "oclc_num:" . $current; } } $isbn = $driver->tryMethod('getCleanISBN'); if (!empty($isbn)) { $isbnList = $this->wcUtils->getXISBN($isbn); foreach ($isbnList as $current) { $parts[] = 'isbn:' . $current; } } $issn = $driver->tryMethod('getCleanISSN'); if (!empty($issn)) { $issnList = $this->wcUtils->getXISSN($issn); foreach ($issnList as $current) { $parts[] = 'issn:' . $current; } } return $parts; }
/** * Get the previous/next record in the last search * result set relative to the current one, also return * the position of the current record in the result set. * Return array('previousRecord'=>previd, 'nextRecord'=>nextid, * 'currentPosition'=>number, 'resultTotal'=>number). * * @param \VuFind\RecordDriver\AbstractBase $driver Driver for the record * currently being displayed * * @return array */ public function getScrollData($driver) { $retVal = array('previousRecord' => null, 'nextRecord' => null, 'currentPosition' => null, 'resultTotal' => null); // Do nothing if disabled: if (!$this->enabled) { return $retVal; } if (isset($this->data->currIds) && isset($this->data->searchId)) { // build a full ID string using the driver: $id = $driver->getResourceSource() . '|' . $driver->getUniqueId(); // we need to restore the last search object // to fetch either the previous/next page of results $lastSearch = $this->restoreLastSearch(); // give up if we can not restore the last search if (!$lastSearch) { return $retVal; } if (!isset($this->data->prevIds)) { $this->data->prevIds = null; } if (!isset($this->data->nextIds)) { $this->data->nextIds = null; } $retVal['resultTotal'] = isset($this->data->total) ? $this->data->total : 0; // find where this record is in the current result page $pos = is_array($this->data->currIds) ? array_search($id, $this->data->currIds) : false; if ($pos !== false) { // OK, found this record in the current result page // calculate it's position relative to the result set $retVal['currentPosition'] = ($this->data->page - 1) * $this->data->limit + $pos + 1; // count how many records in the current result page $count = count($this->data->currIds); // if the current record is somewhere in the middle of the current // page, ie: not first or last, then it is easy if ($pos > 0 && $pos < $count - 1) { $retVal['previousRecord'] = $this->data->currIds[$pos - 1]; $retVal['nextRecord'] = $this->data->currIds[$pos + 1]; // and we're done return $retVal; } // if this record is first record on the current page if ($pos == 0) { // if the current page is NOT the first page, and // the previous page has not been fetched before, then // fetch the previous page if ($this->data->page > 1 && $this->data->prevIds == null) { $this->data->prevIds = $this->fetchPage($lastSearch, $this->data->page - 1); } // if there is something on the previous page, then the previous // record is the last record on the previous page if (!empty($this->data->prevIds)) { $retVal['previousRecord'] = $this->data->prevIds[count($this->data->prevIds) - 1]; } // if it is not the last record on the current page, then // we also have a next record on the current page if ($pos < $count - 1) { $retVal['nextRecord'] = $this->data->currIds[$pos + 1]; } // and we're done return $retVal; } // if this record is last record on the current page if ($pos == $count - 1) { // if the next page has not been fetched, then // fetch the next page if ($this->data->nextIds == null) { $this->data->nextIds = $this->fetchPage($lastSearch, $this->data->page + 1); } // if there is something on the next page, then the next // record is the first record on the next page if (!empty($this->data->nextIds)) { $retVal['nextRecord'] = $this->data->nextIds[0]; } // if it is not the first record on the current page, then // we also have a previous record on the current page if ($pos > 0) { $retVal['previousRecord'] = $this->data->currIds[$pos - 1]; } // and we're done return $retVal; } } else { // the current record is not on the current page // if there is something on the previous page if (!empty($this->data->prevIds)) { // check if current record is on the previous page $pos = is_array($this->data->prevIds) ? array_search($id, $this->data->prevIds) : false; if ($pos !== false) { // decrease the page in the session because // we're now sliding into the previous page // (-- doesn't work on ArrayObjects) $this->data->page = $this->data->page - 1; // shift pages to the right $tmp = $this->data->currIds; $this->data->currIds = $this->data->prevIds; $this->data->nextIds = $tmp; $this->data->prevIds = null; // now we can set the previous/next record if ($pos > 0) { $retVal['previousRecord'] = $this->data->currIds[$pos - 1]; } $retVal['nextRecord'] = $this->data->nextIds[0]; // recalculate the current position $retVal['currentPosition'] = ($this->data->page - 1) * $this->data->limit + $pos + 1; // update the search URL in the session $lastSearch->getParams()->setPage($this->data->page); $this->rememberSearch($lastSearch); // and we're done return $retVal; } } // if there is something on the next page if (!empty($this->data->nextIds)) { // check if current record is on the next page $pos = is_array($this->data->nextIds) ? array_search($id, $this->data->nextIds) : false; if ($pos !== false) { // increase the page in the session because // we're now sliding into the next page // (++ doesn't work on ArrayObjects) $this->data->page = $this->data->page + 1; // shift pages to the left $tmp = $this->data->currIds; $this->data->currIds = $this->data->nextIds; $this->data->prevIds = $tmp; $this->data->nextIds = null; // now we can set the previous/next record $retVal['previousRecord'] = $this->data->prevIds[count($this->data->prevIds) - 1]; if ($pos < count($this->data->currIds) - 1) { $retVal['nextRecord'] = $this->data->currIds[$pos + 1]; } // recalculate the current position $retVal['currentPosition'] = ($this->data->page - 1) * $this->data->limit + $pos + 1; // update the search URL in the session $lastSearch->getParams()->setPage($this->data->page); $this->rememberSearch($lastSearch); // and we're done return $retVal; } } } } return $retVal; }
/** * Establishes base settings for making recommendations. * * @param string $settings Settings from config.ini * @param \VuFind\RecordDriver\AbstractBase $driver Record driver object * * @return void */ public function init($settings, $driver) { $this->recordId = $driver->getUniqueID(); }
/** * Does the specified record support the specified export format? * * @param \VuFind\RecordDriver\AbstractBase $driver Record driver * @param string $format Format to check * * @return bool */ public function recordSupportsFormat($driver, $format) { // Check if the driver explicitly disallows the format: if ($driver->tryMethod('exportDisabled', [$format])) { return false; } // Check the requirements for export in the requested format: if (isset($this->exportConfig->{$format})) { if (isset($this->exportConfig->{$format}->requiredMethods)) { foreach ($this->exportConfig->{$format}->requiredMethods as $method) { // If a required method is missing, give up now: if (!is_callable([$driver, $method])) { return false; } } } // If we got this far, we didn't encounter a problem, and the // requested export format is valid, so we can report success! return true; } // If we got this far, we couldn't find evidence of support: return false; }
/** * Get a sortable title for the record (i.e. no leading articles). * * @return string */ public function getSortTitle() { return isset($this->fields['title_sort']) ? $this->fields['title_sort'] : parent::getSortTitle(); }
/** * Use a record driver to assign metadata to the current row. Return the * current object to allow fluent interface. * * @param \VuFind\RecordDriver\AbstractBase $driver The record driver * @param \VuFind\Date\Converter $converter Date converter * * @return \VuFind\Db\Row\Resource */ public function assignMetadata($driver, \VuFind\Date\Converter $converter) { // Grab title -- we have to have something in this field! $this->title = $driver->tryMethod('getSortTitle'); if (empty($this->title)) { $this->title = $driver->getBreadcrumb(); } // Try to find an author; if not available, just leave the default null: $author = $driver->tryMethod('getPrimaryAuthor'); if (!empty($author)) { $this->author = $author; } // Try to find a year; if not available, just leave the default null: $dates = $driver->tryMethod('getPublicationDates'); if (isset($dates[0]) && strlen($dates[0]) > 4) { try { $year = $converter->convertFromDisplayDate('Y', $dates[0]); } catch (DateException $e) { // If conversion fails, don't store a date: $year = ''; } } else { $year = isset($dates[0]) ? $dates[0] : ''; } if (!empty($year)) { $this->year = intval($year); } return $this; }
/** * Send an email message representing a record. * * @param string $to Recipient email address * @param string $from Sender email address * @param string $msg User notes to include in * message * @param \VuFind\RecordDriver\AbstractBase $record Record being emailed * @param \Zend\View\Renderer\RendererInterface $view View object (used to * render email templates) * * @throws MailException * @return void */ public function sendRecord($to, $from, $msg, $record, $view) { $subject = $this->translate('Library Catalog Record') . ': ' . $record->getBreadcrumb(); $body = $view->partial('Email/record.phtml', array('driver' => $record, 'to' => $to, 'from' => $from, 'message' => $msg)); return $this->send($to, $from, $subject, $body); }