$row = $this->createRow();
$row->created = date('Y-m-d H:i:s'); // force creation date
$row->user_id = $user->id;
return $row;
}
/**
* Retrieve a list object.
*
* @param int $id Numeric ID for existing list.
*
* @return \VuFind\Db\Row\UserList
* @throws RecordMissingException
*/
public function getExisting($id)
{
$result = $this->select(['id' => $id])->current();
if (empty($result)) {
throw new RecordMissingException('Cannot load list ' . $id);
}
return $result;
}
/**
* Get lists containing a specific user_resource
*
* @param string $resourceId ID of record being checked.
* @param string $source Source of record to look up
* @param int $userId Optional user ID (to limit results to a particular
* user).
*
* @return array
*/
public function getListsContainingResource($resourceId,
$source = DEFAULT_SEARCH_BACKEND, $userId = null
) {
// Set up base query:
$callback = function ($select) use ($resourceId, $source, $userId) {
$select->columns(
$filters = $this->getParams()->getRawFilters();
return $filters['tags'] ?? [];
}
/**
* Get the list object associated with the current search (null if no list
* selected).
*
* @return \VuFind\Db\Row\UserList|null
*/
public function getListObject()
{
// If we haven't previously tried to load a list, do it now:
if ($this->list === false) {
// Check the filters for a list ID, and load the corresponding object
// if one is found:
$filters = $this->getParams()->getRawFilters();
$listId = $filters['lists'][0] ?? null;
$this->list = (null === $listId)
? null : $this->listTable->getExisting($listId);
}
return $this->list;
}
}
}
break;
}
}
if (isset($this->facets[$field])) {
$retVal[$field] = $this->facets[$field];
}
}
return $retVal;
}
/**
* Support method for performAndProcessSearch -- perform a search based on the
* parameters passed to the object.
*
* @return void
*/
protected function performSearch()
{
$list = $this->getListObject();
$auth = $this->getAuthorizationService();
$this->user = $auth ? $auth->getIdentity() : false;
// Make sure the user and/or list objects make it possible to view
// the current result set -- we need to check logged in status and
// list permissions.
if (null === $list && !$this->user) {
throw new ListPermissionException(
'Cannot retrieve favorites without logged in user.'
);
}
if (null !== $list && !$list->public
&& (!$this->user || $list->user_id != $this->user->id)
) {
throw new ListPermissionException(
$this->translate('list_access_denied')
);
}
// How many results were there?
$this->helpers[$key] = $value;
}
/**
* Actually execute the search.
*
* @return void
*/
public function performAndProcessSearch()
{
// Initialize variables to defaults (to ensure they don't stay null
// and cause unnecessary repeat processing):
$this->resultTotal = 0;
$this->results = [];
$this->suggestions = [];
$this->errors = [];
// Run the search:
$this->startQueryTimer();
$this->performSearch();
$this->stopQueryTimer();
}
/**
* Returns the stored list of facets for the last search
*
* @param array $filter Array of field => on-screen description listing
* all of the desired facet fields; set to null to get all configured values.
*
* @return array Facets data arrays
*/
abstract public function getFacetList($filter = null);
/**
* Abstract support method for performAndProcessSearch -- perform a search based
* on the parameters passed to the object. This method is responsible for
* filling in all of the key class properties: results, resultTotal, etc.
*
* @return void
*/
$params = $results->getParams();
$params->setLastView($lastView);
$params->initFromRequest($request);
if (is_callable($setupCallback)) {
$setupCallback($this, $params, $runningSearchId);
}
// Trigger the "configuration done" event.
$this->getEventManager()->trigger(
self::EVENT_CONFIGURED, $this,
compact('params', 'request', 'runningSearchId')
);
// Attempt to perform the search; if there is a problem, inspect any Solr
// exceptions to see if we should communicate to the user about them.
try {
// Explicitly execute search within controller -- this allows us to
// catch exceptions more reliably:
$results->performAndProcessSearch();
} catch (\VuFindSearch\Backend\Exception\BackendException $e) {
if ($e->hasTag('VuFind\Search\ParserError')) {
// We need to create and process an "empty results" object to
// ensure that recommendation modules and templates behave
// properly when displaying the error message.
$results = $this->resultsManager->get('EmptySet');
$results->setParams($params);
$results->performAndProcessSearch();
} else {
throw $e;
}
}
// Trigger the "search completed" event.
$this->getEventManager()->trigger(
self::EVENT_COMPLETE, $this, compact('results', 'runningSearchId')
);
return $results;
}
$runner = $this->serviceLocator->get(\VuFind\Search\SearchRunner::class);
// We want to merge together GET, POST and route parameters to
// initialize our search object:
$request = $this->getRequest()->getQuery()->toArray()
+ $this->getRequest()->getPost()->toArray()
+ ['id' => $this->params()->fromRoute('id')];
// Set up listener for recommendations:
$rManager = $this->serviceLocator
->get(\VuFind\Recommend\PluginManager::class);
$setupCallback = function ($runner, $params, $searchId) use ($rManager) {
$listener = new RecommendListener($rManager, $searchId);
$listener->setConfig(
$params->getOptions()->getRecommendationSettings()
);
$listener->attach($runner->getEventManager()->getSharedManager());
};
$results = $runner->run($request, 'Favorites', $setupCallback);
$listTags = [];
if ($this->listTagsEnabled()) {
if ($list = $results->getListObject()) {
foreach ($list->getListTags() as $tag) {
$listTags[$tag->id] = $tag->tag;
}
}
}
return $this->createViewModel(
[
'params' => $results->getParams(), 'results' => $results,
'listTags' => $listTags
]
);
} catch (ListPermissionException $e) {
if (!$this->getUser()) {
return $this->forceLogin();
}
throw $e;
*/
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;
}
}
/**
* Execute the request
*
* @param \Laminas\Mvc\MvcEvent $event Event
*
* @return mixed
* @throws Exception\DomainException
*/
public function onDispatch(\Laminas\Mvc\MvcEvent $event)
{
// Catch any ILSExceptions thrown during processing and display a generic
// failure message to the user (instead of going to the fatal exception
// screen). This offers a slightly more forgiving experience when there is
// an unexpected ILS issue. Note that most ILS exceptions are handled at a
// lower level in the code (see \VuFind\ILS\Connection and the config.ini
// loadNoILSOnFailure setting), but there are some rare edge cases (for
// example, when the MultiBackend driver fails over to NoILS while used in
// combination with MultiILS authentication) that could lead here.
try {
return parent::onDispatch($event);
} catch (ILSException $exception) {
// Always display generic message:
$this->flashMessenger()->addErrorMessage('ils_connection_failed');
// In development mode, also show technical failure message:
if ('development' == APPLICATION_ENV) {
$this->flashMessenger()->addErrorMessage($exception->getMessage());
}
return $this->createViewModel();
}
}
/**
* Prepare and direct the home page where it needs to go
*
* @return mixed
*/
public function homeAction()
{
// Process login request, if necessary (either because a form has been
// submitted or because we're using an external login provider):
}
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();
}