*
* @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;
}
}
*
* @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;
}
}
$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');
$recordLinker = $this->getView()->plugin('recordLinker');
try {
$url = $serverUrl($recordLinker->getUrl($record));
} catch (\Laminas\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]);
}
$formats = $record->tryMethod('getFormats');
if (is_array($formats)) {
foreach ($formats as $format) {
$entry->addDCFormat($format);
}
}
$dcDate = $this->getDcDate($record);
if (!empty($dcDate)) {
$entry->setDCDate($dcDate);
}
$feed->addEntry($entry);
}
->setPage($params->getPage() + 1)->getParams(false),
'next',
$params->getView()
);
}
$feed->addOpensearchLink(
$baseUrl . $results->getUrlQuery()->setPage($lastPage)->getParams(false),
'last',
$params->getView()
);
// add opensearch fields
$feed->setOpensearchTotalResults($results->getResultTotal());
$feed->setOpensearchItemsPerPage($params->getLimit());
$feed->setOpensearchStartIndex($results->getStartRecord() - 1);
$feed->setOpensearchSearchTerms($params->getQuery()->getAllTerms());
$records = $results->getResults();
foreach ($records as $current) {
$this->addEntry($feed, $current);
}
return $feed;
}
/**
* Support method to extract a date from a record driver. Return empty string
* if no valid match is found.
*
* @param \VuFind\RecordDriver\AbstractBase $record Record to read from
*
* @return string
*/
protected function getDcDate($record)
{
// See if we can extract a date that's pre-formatted in a DC-friendly way:
$dates = (array)$record->tryMethod('getPublicationDates');
$regex = '/[0-9]{4}(\-[01][0-9])?(\-[0-3][0-9])?/';
foreach ($dates as $date) {
if (preg_match($regex, $date, $matches)) {
if ($this->saveToHistory) {
$this->saveSearchToHistory($results);
}
// Set up results scroller:
if ($this->resultScrollerActive()) {
$this->resultScroller()->init($results);
}
foreach ($results->getErrors() as $error) {
$this->flashMessenger()->addErrorMessage($error);
}
}
// Special case: If we're in RSS view, we need to render differently:
if (isset($view->params) && $view->params->getView() == 'rss') {
$response = $this->getResponse();
$response->getHeaders()->addHeaderLine('Content-type', 'text/xml');
$feed = $this->getViewRenderer()->plugin('resultfeed');
$response->setContent($feed($view->results)->export('rss'));
return $response;
}
// Search toolbar
$config = $this->serviceLocator->get(\VuFind\Config\PluginManager::class)
->get('config');
$view->showBulkOptions = isset($config->Site->showBulkOptions)
&& $config->Site->showBulkOptions;
return $view;
}
/**
* Process the jumpto parameter -- either redirect to a specific record and
* return view model, or ignore the parameter and return false.
*
* @param \VuFind\Search\Base\Results $results Search results object.
*
* @return bool|\Laminas\View\Model\ViewModel
*/
throw new \Exception('Unrecoverable deep paging error.');
}
$request['page'] = $page;
$this->flashMessenger()->addErrorMessage(
[
'msg' => 'deep_paging_failure',
'tokens' => ['%%page%%' => $page],
]
);
return $this->redirect()->toUrl('?' . http_build_query($request));
}
/**
* Send search results to results view
*
* @return \Laminas\View\Model\ViewModel
*/
public function resultsAction()
{
return $this->getSearchResultsView();
}
/**
* Perform a search and send results to a results view
*
* @param callable $setupCallback Optional setup callback that overrides the
* default one
*
* @return \Laminas\View\Model\ViewModel
*/
protected function getSearchResultsView($setupCallback = null)
{
$view = $this->createViewModel();
// Handle saved search requests:
$savedId = $this->params()->fromQuery('saved', false);
if ($savedId !== false) {
return $this->redirectToSavedSearch($savedId);
}
return parent::facetListAction();
}
/**
* Sets the configuration for displaying author results
*
* @return mixed
*/
public function resultsAction()
{
$this->searchClassId = 'SolrAuthor';
// Save author searches if next_prev_navigation is enabled - otherwise
// there are wacky results when trying to page through results (the
// next/prev links only appear for records which were included in the
// results for the previous keyword search, and the next/prev links will
// iterate you through that search).
$this->saveToHistory = $this->resultScrollerActive();
return parent::resultsAction();
}
/**
* Sets the configuration for performing an author search
*
* @return mixed
*/
public function searchAction()
{
$this->searchClassId = 'SolrAuthorFacets';
$this->saveToHistory = false;
$this->rememberSearch = false;
return parent::resultsAction();
}
/**
* Displays the proper page for a search action
*
* @return mixed
*/
*/
public function onDispatch(MvcEvent $e)
{
$routeMatch = $e->getRouteMatch();
if (! $routeMatch) {
/**
* @todo Determine requirements for when route match is missing.
* Potentially allow pulling directly from request metadata?
*/
throw new Exception\DomainException('Missing route matches; unsure how to retrieve action');
}
$action = $routeMatch->getParam('action', 'not-found');
$method = static::getMethodFromAction($action);
if (! method_exists($this, $method)) {
$method = 'notFoundAction';
}
$actionResponse = $this->$method();
$e->setResult($actionResponse);
return $actionResponse;
}
}
}
if ($this->sharedManager) {
foreach ($this->sharedManager->getListeners($this->identifiers, $name) as $priority => $listeners) {
$listOfListenersByPriority[$priority][] = $listeners;
}
}
// Sort by priority in reverse order
krsort($listOfListenersByPriority);
// Initial value of stop propagation flag should be false
$event->stopPropagation(false);
// Execute listeners
$responses = new ResponseCollection();
foreach ($listOfListenersByPriority as $listOfListeners) {
foreach ($listOfListeners as $listeners) {
foreach ($listeners as $listener) {
$response = $listener($event);
$responses->push($response);
// If the event was asked to stop propagating, do so
if ($event->propagationIsStopped()) {
$responses->setStopped(true);
return $responses;
}
// If the result causes our validation callback to return true,
// stop propagation
if ($callback && $callback($response)) {
$responses->setStopped(true);
return $responses;
}
}
}
}
return $responses;
}
$event->setParams($argv);
}
return $this->triggerListeners($event, $callback);
}
/**
* @inheritDoc
*/
public function triggerEvent(EventInterface $event)
{
return $this->triggerListeners($event);
}
/**
* @inheritDoc
*/
public function triggerEventUntil(callable $callback, EventInterface $event)
{
return $this->triggerListeners($event, $callback);
}
/**
* @inheritDoc
*/
public function attach($eventName, callable $listener, $priority = 1)
{
if (! is_string($eventName)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects a string for the event; received %s',
__METHOD__,
(is_object($eventName) ? get_class($eventName) : gettype($eventName))
));
}
$this->events[$eventName][(int) $priority][0][] = $listener;
return $listener;
}
/**
* @events dispatch.pre, dispatch.post
* @param Request $request
* @param null|Response $response
* @return Response|mixed
*/
public function dispatch(Request $request, Response $response = null)
{
$this->request = $request;
if (! $response) {
$response = new HttpResponse();
}
$this->response = $response;
$e = $this->getEvent();
$e->setName(MvcEvent::EVENT_DISPATCH);
$e->setRequest($request);
$e->setResponse($response);
$e->setTarget($this);
$result = $this->getEventManager()->triggerEventUntil(function ($test) {
return ($test instanceof Response);
}, $e);
if ($result->stopped()) {
return $result->last();
}
return $e->getResult();
}
/**
* Get request object
*
* @return Request
*/
public function getRequest()
{
if (! $this->request) {
$this->request = new HttpRequest();
}
// Allow passing parameters to seed the RouteMatch with & copy matched route name
if ($params !== null) {
$routeMatch = new RouteMatch($params);
$routeMatch->setMatchedRouteName($event->getRouteMatch()->getMatchedRouteName());
$event->setRouteMatch($routeMatch);
}
if ($this->numNestedForwards > $this->maxNestedForwards) {
throw new Exception\DomainException(
"Circular forwarding detected: greater than $this->maxNestedForwards nested forwards"
);
}
$this->numNestedForwards++;
// Detach listeners that may cause problems during dispatch:
$sharedEvents = $event->getApplication()->getEventManager()->getSharedManager();
$listeners = $this->detachProblemListeners($sharedEvents);
$return = $controller->dispatch($event->getRequest(), $event->getResponse());
// If we detached any listeners, reattach them now:
$this->reattachProblemListeners($sharedEvents, $listeners);
$this->numNestedForwards--;
return $return;
}
/**
* Detach problem listeners specified by getListenersToDetach() and return an array of information that will
* allow them to be reattached.
*
* @param SharedEvents $sharedEvents Shared event manager
* @return array
*/
protected function detachProblemListeners(SharedEvents $sharedEvents)
{
// Convert the problem list from two-dimensional array to more convenient id => event => class format:
$formattedProblems = [];
return $translate($msg, $tokens, $default);
}
/**
* Convenience method to make invocation of forward() helper less verbose.
*
* @param string $controller Controller to invoke
* @param string $action Action to invoke
* @param array $params Extra parameters for the RouteMatch object (no
* need to provide action here, since $action takes care of that)
*
* @return mixed
*/
public function forwardTo($controller, $action, $params = [])
{
// Inject action into the RouteMatch parameters
$params['action'] = $action;
// Dispatch the requested controller/action:
return $this->forward()->dispatch($controller, $params);
}
/**
* Check to see if a form was submitted from its post value
* Also validate the Captcha, if it's activated
*
* @param string $submitElement Name of the post field of the submit button
* @param bool $useCaptcha Are we using captcha in this situation?
*
* @return bool
*/
protected function formWasSubmitted(
$submitElement = 'submit',
$useCaptcha = false
) {
// Fail if the expected submission element was missing from the POST:
// Form was submitted; if CAPTCHA is expected, validate it now.
return $this->params()->fromPost($submitElement, false)
&& (!$useCaptcha || $this->captcha()->verify());
}
public function searchAction()
{
$this->searchClassId = 'SolrAuthorFacets';
$this->saveToHistory = false;
$this->rememberSearch = false;
return parent::resultsAction();
}
/**
* Displays the proper page for a search action
*
* @return mixed
*/
public function homeAction()
{
// If an author was requested, forward to the results page; otherwise,
// display the search form:
$author = $this->params()->fromQuery('author');
return !empty($author)
? $this->forwardTo('Author', 'Results') : parent::homeAction();
}
/**
* Is the result scroller active?
*
* @return bool
*/
protected function resultScrollerActive()
{
$config = $this->serviceLocator->get(\VuFind\Config\PluginManager::class)
->get('config');
return isset($config->Record->next_prev_navigation)
&& $config->Record->next_prev_navigation;
}
}
*/
public function onDispatch(MvcEvent $e)
{
$routeMatch = $e->getRouteMatch();
if (! $routeMatch) {
/**
* @todo Determine requirements for when route match is missing.
* Potentially allow pulling directly from request metadata?
*/
throw new Exception\DomainException('Missing route matches; unsure how to retrieve action');
}
$action = $routeMatch->getParam('action', 'not-found');
$method = static::getMethodFromAction($action);
if (! method_exists($this, $method)) {
$method = 'notFoundAction';
}
$actionResponse = $this->$method();
$e->setResult($actionResponse);
return $actionResponse;
}
}
}
if ($this->sharedManager) {
foreach ($this->sharedManager->getListeners($this->identifiers, $name) as $priority => $listeners) {
$listOfListenersByPriority[$priority][] = $listeners;
}
}
// Sort by priority in reverse order
krsort($listOfListenersByPriority);
// Initial value of stop propagation flag should be false
$event->stopPropagation(false);
// Execute listeners
$responses = new ResponseCollection();
foreach ($listOfListenersByPriority as $listOfListeners) {
foreach ($listOfListeners as $listeners) {
foreach ($listeners as $listener) {
$response = $listener($event);
$responses->push($response);
// If the event was asked to stop propagating, do so
if ($event->propagationIsStopped()) {
$responses->setStopped(true);
return $responses;
}
// If the result causes our validation callback to return true,
// stop propagation
if ($callback && $callback($response)) {
$responses->setStopped(true);
return $responses;
}
}
}
}
return $responses;
}
$event->setParams($argv);
}
return $this->triggerListeners($event, $callback);
}
/**
* @inheritDoc
*/
public function triggerEvent(EventInterface $event)
{
return $this->triggerListeners($event);
}
/**
* @inheritDoc
*/
public function triggerEventUntil(callable $callback, EventInterface $event)
{
return $this->triggerListeners($event, $callback);
}
/**
* @inheritDoc
*/
public function attach($eventName, callable $listener, $priority = 1)
{
if (! is_string($eventName)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects a string for the event; received %s',
__METHOD__,
(is_object($eventName) ? get_class($eventName) : gettype($eventName))
));
}
$this->events[$eventName][(int) $priority][0][] = $listener;
return $listener;
}
/**
* @events dispatch.pre, dispatch.post
* @param Request $request
* @param null|Response $response
* @return Response|mixed
*/
public function dispatch(Request $request, Response $response = null)
{
$this->request = $request;
if (! $response) {
$response = new HttpResponse();
}
$this->response = $response;
$e = $this->getEvent();
$e->setName(MvcEvent::EVENT_DISPATCH);
$e->setRequest($request);
$e->setResponse($response);
$e->setTarget($this);
$result = $this->getEventManager()->triggerEventUntil(function ($test) {
return ($test instanceof Response);
}, $e);
if ($result->stopped()) {
return $result->last();
}
return $e->getResult();
}
/**
* Get request object
*
* @return Request
*/
public function getRequest()
{
if (! $this->request) {
$this->request = new HttpRequest();
}
);
return $this->complete($return, $e);
} catch (\Throwable $exception) {
$return = $this->marshalBadControllerEvent($controllerName, $e, $application, $exception);
return $this->complete($return, $e);
} catch (\Exception $exception) { // @TODO clean up once PHP 7 requirement is enforced
$return = $this->marshalBadControllerEvent($controllerName, $e, $application, $exception);
return $this->complete($return, $e);
}
if ($controller instanceof InjectApplicationEventInterface) {
$controller->setEvent($e);
}
$request = $e->getRequest();
$response = $application->getResponse();
$caughtException = null;
try {
$return = $controller->dispatch($request, $response);
} catch (\Throwable $ex) {
$caughtException = $ex;
} catch (\Exception $ex) { // @TODO clean up once PHP 7 requirement is enforced
$caughtException = $ex;
}
if ($caughtException !== null) {
$e->setName(MvcEvent::EVENT_DISPATCH_ERROR);
$e->setError($application::ERROR_EXCEPTION);
$e->setController($controllerName);
$e->setControllerClass(get_class($controller));
$e->setParam('exception', $caughtException);
$return = $application->getEventManager()->triggerEvent($e)->last();
if (! $return) {
$return = $e->getResult();
}
}
return $this->complete($return, $e);
}
if ($this->sharedManager) {
foreach ($this->sharedManager->getListeners($this->identifiers, $name) as $priority => $listeners) {
$listOfListenersByPriority[$priority][] = $listeners;
}
}
// Sort by priority in reverse order
krsort($listOfListenersByPriority);
// Initial value of stop propagation flag should be false
$event->stopPropagation(false);
// Execute listeners
$responses = new ResponseCollection();
foreach ($listOfListenersByPriority as $listOfListeners) {
foreach ($listOfListeners as $listeners) {
foreach ($listeners as $listener) {
$response = $listener($event);
$responses->push($response);
// If the event was asked to stop propagating, do so
if ($event->propagationIsStopped()) {
$responses->setStopped(true);
return $responses;
}
// If the result causes our validation callback to return true,
// stop propagation
if ($callback && $callback($response)) {
$responses->setStopped(true);
return $responses;
}
}
}
}
return $responses;
}
$event->setParams($argv);
}
return $this->triggerListeners($event, $callback);
}
/**
* @inheritDoc
*/
public function triggerEvent(EventInterface $event)
{
return $this->triggerListeners($event);
}
/**
* @inheritDoc
*/
public function triggerEventUntil(callable $callback, EventInterface $event)
{
return $this->triggerListeners($event, $callback);
}
/**
* @inheritDoc
*/
public function attach($eventName, callable $listener, $priority = 1)
{
if (! is_string($eventName)) {
throw new Exception\InvalidArgumentException(sprintf(
'%s expects a string for the event; received %s',
__METHOD__,
(is_object($eventName) ? get_class($eventName) : gettype($eventName))
));
}
$this->events[$eventName][(int) $priority][0][] = $listener;
return $listener;
}
/**
$response = $result->last();
if ($response instanceof ResponseInterface) {
$event->setName(MvcEvent::EVENT_FINISH);
$event->setTarget($this);
$event->setResponse($response);
$event->stopPropagation(false); // Clear before triggering
$events->triggerEvent($event);
$this->response = $response;
return $this;
}
}
if ($event->getError()) {
return $this->completeRequest($event);
}
// Trigger dispatch event
$event->setName(MvcEvent::EVENT_DISPATCH);
$event->stopPropagation(false); // Clear before triggering
$result = $events->triggerEventUntil($shortCircuit, $event);
// Complete response
$response = $result->last();
if ($response instanceof ResponseInterface) {
$event->setName(MvcEvent::EVENT_FINISH);
$event->setTarget($this);
$event->setResponse($response);
$event->stopPropagation(false); // Clear before triggering
$events->triggerEvent($event);
$this->response = $response;
return $this;
}
$response = $this->response;
$event->setResponse($response);
return $this->completeRequest($event);
}
/**
* Complete the request
$pathParts[] = APPLICATION_PATH . '/vendor';
$pathParts[] = get_include_path();
set_include_path(implode(PATH_SEPARATOR, $pathParts));
// Composer autoloading
if (file_exists('vendor/autoload.php')) {
$loader = include 'vendor/autoload.php';
}
if (!class_exists('Laminas\Loader\AutoloaderFactory')) {
throw new RuntimeException('Unable to load Laminas autoloader.');
}
// Run the application!
$app = Laminas\Mvc\Application::init(require 'config/application.config.php');
if (PHP_SAPI === 'cli') {
return $app->getServiceManager()
->get(\VuFindConsole\ConsoleRunner::class)->run();
} else {
$app->run();
}