/**
* If an unexpected exception type was received, wrap it in a generic
* BackendException to standardize upstream handling.
*
* @param \Exception $ex Exception
*
* @return \Exception
*/
protected function forceToBackendException($ex)
{
// Don't wrap specific backend exceptions....
if (
$ex instanceof RemoteErrorException
|| $ex instanceof RequestErrorException
|| $ex instanceof HttpErrorException
) {
return $ex;
}
return
new BackendException('Problem connecting to Solr.', $ex->getCode(), $ex);
}
/**
* Try all Solr URLs until we find one that works (or throw an exception).
*
* @param string $method HTTP method to use
* @param string $urlSuffix Suffix to append to all URLs tried
* @param ?callable $callback Callback to configure client (null for none)
* @param bool $cacheable Whether the request is cacheable
*
* @return string Response body
*
* @throws RemoteErrorException SOLR signaled a server error (HTTP 5xx)
* @throws RequestErrorException SOLR signaled a client error (HTTP 4xx)
*/
protected function trySolrUrls(
$method,
$urlSuffix,
$callback = null,
bool $cacheable = false
Arguments
"Problem connecting to Solr."
return $result;
}
}
try {
$result = $this->send($client);
if ($cacheKey) {
$this->putCachedData($cacheKey, $result);
}
return $result;
} catch (\Exception $ex) {
if ($this->isRethrowableSolrException($ex)) {
throw $this->forceToBackendException($ex);
}
$exception = $ex;
}
}
// If we got this far, everything failed -- throw a BackendException with
// the most recent exception caught above set as the previous exception.
throw $this->forceToBackendException($exception);
}
/**
* Extract the Solr core from the connector's URL.
*
* @return string
*/
public function getCore(): string
{
$url = rtrim($this->getUrl(), '/');
$parts = explode('/', $url);
return array_pop($parts);
}
/**
* Send request the SOLR and return the response.
*
* @param HttpClient $client Prepared HTTP client
*
* @return string Response body
throw new AdapterException\InvalidArgumentException(sprintf(
'integer or numeric string expected, got %s',
gettype($connectTimeout)
));
}
ErrorHandler::start();
$this->socket = stream_socket_client(
$host . ':' . $port,
$errno,
$errstr,
(int) $connectTimeout,
$flags,
$context
);
$error = ErrorHandler::stop();
if (! $this->socket) {
$this->close();
throw new AdapterException\RuntimeException(
sprintf(
'Unable to connect to %s:%d%s',
$host,
$port,
$error ? ' . Error #' . $error->getCode() . ': ' . $error->getMessage() : ''
),
0,
$error
);
}
// Set the stream timeout
if (! stream_set_timeout($this->socket, (int) $this->config['timeout'])) {
throw new AdapterException\RuntimeException('Unable to set the connection timeout');
}
if ($secure || $this->config['sslusecontext']) {
if ($this->setSslCryptoMethod) {
try {
$this->enableCryptoTransport($this->config['ssltransport'], $this->socket, $host);
Arguments
"Unable to connect to localhost:8983 . Error #0: stream_socket_client(): Unable to connect to localhost:8983 (Connection refused)"
$flags = STREAM_CLIENT_CONNECT;
if ($this->config['persistent']) {
$flags |= STREAM_CLIENT_PERSISTENT;
}
if (isset($this->config['connecttimeout'])) {
$connectTimeout = $this->config['connecttimeout'];
} else {
$connectTimeout = $this->config['timeout'];
}
if ($connectTimeout !== null && ! is_numeric($connectTimeout)) {
throw new AdapterException\InvalidArgumentException(sprintf(
'integer or numeric string expected, got %s',
gettype($connectTimeout)
));
}
ErrorHandler::start();
$this->socket = stream_socket_client(
$host . ':' . $port,
$errno,
$errstr,
(int) $connectTimeout,
$flags,
$context
);
$error = ErrorHandler::stop();
if (! $this->socket) {
$this->close();
throw new AdapterException\RuntimeException(
sprintf(
'Unable to connect to %s:%d%s',
$host,
$port,
$error ? ' . Error #' . $error->getCode() . ': ' . $error->getMessage() : ''
),
0,
$error
Arguments
"stream_socket_client(): Unable to connect to localhost:8983 (Connection refused)"
$flags = STREAM_CLIENT_CONNECT;
if ($this->config['persistent']) {
$flags |= STREAM_CLIENT_PERSISTENT;
}
if (isset($this->config['connecttimeout'])) {
$connectTimeout = $this->config['connecttimeout'];
} else {
$connectTimeout = $this->config['timeout'];
}
if ($connectTimeout !== null && ! is_numeric($connectTimeout)) {
throw new AdapterException\InvalidArgumentException(sprintf(
'integer or numeric string expected, got %s',
gettype($connectTimeout)
));
}
ErrorHandler::start();
$this->socket = stream_socket_client(
$host . ':' . $port,
$errno,
$errstr,
(int) $connectTimeout,
$flags,
$context
);
$error = ErrorHandler::stop();
if (! $this->socket) {
$this->close();
throw new AdapterException\RuntimeException(
sprintf(
'Unable to connect to %s:%d%s',
$host,
$port,
$error ? ' . Error #' . $error->getCode() . ': ' . $error->getMessage() : ''
),
0,
$error
}
return $parameters;
}
/**
* Separating this from send method allows subclasses to wrap
* the interaction with the adapter
*
* @param string $method
* @param bool $secure
* @param array $headers
* @param string $body
* @return string the raw response
* @throws Exception\RuntimeException
*/
protected function doRequest(Http $uri, $method, $secure = false, $headers = [], $body = '')
{
// Open the connection, send the request and read the response
$this->adapter->connect($uri->getHost(), $uri->getPort(), $secure);
if ($this->config['outputstream']) {
if ($this->adapter instanceof Client\Adapter\StreamInterface) {
$this->streamHandle = $this->openTempStream();
$this->adapter->setOutputStream($this->streamHandle);
} else {
throw new Exception\RuntimeException('Adapter does not support streaming');
}
}
// HTTP connection
$this->lastRawRequest = $this->adapter->write(
$method,
$uri,
$this->config['httpversion'],
$headers,
$body
);
return $this->adapter->read();
}
// headers
$headers = $this->prepareHeaders($body, $uri);
$secure = $uri->getScheme() === 'https';
// cookies
$cookie = $this->prepareCookies($uri->getHost(), $uri->getPath(), $secure);
if ($cookie->getFieldValue()) {
$headers['Cookie'] = $cookie->getFieldValue();
}
// check that adapter supports streaming before using it
if (is_resource($body) && ! $adapter instanceof Client\Adapter\StreamInterface) {
throw new RuntimeException('Adapter does not support streaming');
}
$this->streamHandle = null;
// calling protected method to allow extending classes
// to wrap the interaction with the adapter
$response = $this->doRequest($uri, $method, $secure, $headers, $body);
$stream = $this->streamHandle;
$this->streamHandle = null;
if (! $response) {
if ($stream !== null) {
fclose($stream);
}
throw new Exception\RuntimeException('Unable to read response, or response is empty');
}
if ($this->config['storeresponse']) {
$this->lastRawResponse = $response;
} else {
$this->lastRawResponse = null;
}
if ($this->config['outputstream']) {
if ($stream === null) {
$stream = $this->getStream();
if (! is_resource($stream) && is_string($stream)) {
/**
* Send request the SOLR and return the response.
*
* @param HttpClient $client Prepared HTTP client
*
* @return string Response body
*
* @throws RemoteErrorException SOLR signaled a server error (HTTP 5xx)
* @throws RequestErrorException SOLR signaled a client error (HTTP 4xx)
*/
protected function send(HttpClient $client)
{
$this->debug(
sprintf('=> %s %s', $client->getMethod(), $client->getUri())
);
$this->lastUrl = $client->getUri();
$time = microtime(true);
$response = $client->send();
$time = microtime(true) - $time;
$this->debug(
sprintf(
'<= %s %s',
$response->getStatusCode(),
$response->getReasonPhrase()
),
['time' => $time]
);
if (!$response->isSuccess()) {
// Return a more detailed error message for a 400 error:
if ($response->getStatusCode() === 400) {
$json = json_decode($response->getBody(), true);
$msgParts = ['400', $response->getReasonPhrase()];
if ($msg = $json['error']['msg'] ?? '') {
$msgParts[] = $msg;
}
throw new RequestErrorException(
$exception = new \Exception('Unexpected exception.');
// Loop through all base URLs and try them in turn until one works.
$cacheKey = null;
foreach ((array)$this->url as $base) {
$client = ($this->clientFactory)($base . $urlSuffix);
$client->setMethod($method);
if (is_callable($callback)) {
$callback($client);
}
// Always create the cache key from the first server, and only after any
// callback has been called above.
if ($cacheable && $this->cache && null === $cacheKey) {
$cacheKey = $this->getCacheKey($client);
if ($result = $this->getCachedData($cacheKey)) {
return $result;
}
}
try {
$result = $this->send($client);
if ($cacheKey) {
$this->putCachedData($cacheKey, $result);
}
return $result;
} catch (\Exception $ex) {
if ($this->isRethrowableSolrException($ex)) {
throw $this->forceToBackendException($ex);
}
$exception = $ex;
}
}
// If we got this far, everything failed -- throw a BackendException with
// the most recent exception caught above set as the previous exception.
throw $this->forceToBackendException($exception);
}
/**
* Extract the Solr core from the connector's URL.
*
*/
public function query($handler, ParamBag $params, bool $cacheable = false)
{
$urlSuffix = '/' . $handler;
$paramString = implode('&', $params->request());
if (strlen($paramString) > self::MAX_GET_URL_LENGTH) {
$method = Request::METHOD_POST;
$callback = function ($client) use ($paramString): void {
$client->setRawBody($paramString);
$client->setEncType(HttpClient::ENC_URLENCODED);
$client->setHeaders(['Content-Length' => strlen($paramString)]);
};
} else {
$method = Request::METHOD_GET;
$urlSuffix .= '?' . $paramString;
$callback = null;
}
$this->debug(sprintf('Query %s', $paramString));
return $this->trySolrUrls($method, $urlSuffix, $callback, $cacheable);
}
/**
* Call a method with provided options for the HTTP client
*
* @param array $options HTTP client options
* @param string $method Method to call
* @param array ...$args Method parameters
*
* @return mixed
*/
public function callWithHttpOptions(
array $options,
string $method,
...$args
) {
$reflectionMethod = new \ReflectionMethod($this, $method);
if (!$reflectionMethod->isPublic()) {
throw new InvalidArgumentException("Method '$method' is not public");
}
}
/**
* Return document specified by id.
*
* @param string $id Document identifier
* @param ?ParamBag $params Search backend parameters
*
* @return string
*/
public function retrieve($id, ?ParamBag $params = null)
{
$params = $params ?: new ParamBag();
$params
->set('q', sprintf('%s:"%s"', $this->uniqueKey, addcslashes($id, '"')));
$handler = $this->map->getHandler(__FUNCTION__);
$this->map->prepare(__FUNCTION__, $params);
return $this->query($handler, $params, true);
}
/**
* Return records similar to a given record specified by id.
*
* Uses MoreLikeThis Request Component or MoreLikeThis Handler
*
* @param string $id ID of given record (not currently used, but
* retained for legacy backward compatibility / extensibility).
* @param ParamBag $params Parameters
*
* @return string
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function similar($id, ParamBag $params)
{
$handler = $this->map->getHandler(__FUNCTION__);
$this->map->prepare(__FUNCTION__, $params);
$sort = "{$random}_random asc";
$params->set('sort', $sort);
return $this->search($query, 0, $limit, $params);
}
/**
* Retrieve a single document.
*
* @param string $id Document identifier
* @param ?ParamBag $params Search backend parameters
*
* @return RecordCollectionInterface
*/
public function retrieve($id, ?ParamBag $params = null)
{
$params = $params ?: new ParamBag();
$this->injectResponseWriter($params);
$response = $this->connector->retrieve($id, $params);
$collection = $this->createRecordCollection($response);
$this->injectSourceIdentifier($collection);
return $collection;
}
/**
* Retrieve a batch of documents.
*
* @param array $ids Array of document identifiers
* @param ?ParamBag $params Search backend parameters
*
* @return RecordCollectionInterface
*/
public function retrieveBatch($ids, ?ParamBag $params = null)
{
$params = $params ?: new ParamBag();
// Callback function for formatting IDs:
$formatIds = function ($i) {
return '"' . addcslashes($i, '"') . '"';
*
* @return CommandInterface Command instance for method chaining
*/
public function execute(BackendInterface $backend): CommandInterface
{
$this->validateBackend($backend);
if (
!($backend instanceof $this->interface)
|| !method_exists($this->interface, $this->method)
) {
throw new BackendException(
"$this->backendId does not support $this->method()"
);
}
$args = $this->getArguments();
if ($backend instanceof ExtraRequestDetailsInterface) {
$backend->resetExtraRequestDetails();
}
$this->finalizeExecution(
call_user_func([$backend, $this->method], ...$args)
);
if ($backend instanceof ExtraRequestDetailsInterface) {
$this->extraRequestDetails = $backend->getExtraRequestDetails();
}
return $this;
}
}
*
* @return CommandInterface Command instance for method chaining
*/
public function execute(BackendInterface $backend): CommandInterface
{
$this->validateBackend($backend);
if (
!($backend instanceof $this->interface)
|| !method_exists($this->interface, $this->method)
) {
throw new BackendException(
"$this->backendId does not support $this->method()"
);
}
$args = $this->getArguments();
if ($backend instanceof ExtraRequestDetailsInterface) {
$backend->resetExtraRequestDetails();
}
$this->finalizeExecution(
call_user_func([$backend, $this->method], ...$args)
);
if ($backend instanceof ExtraRequestDetailsInterface) {
$this->extraRequestDetails = $backend->getExtraRequestDetails();
}
return $this;
}
}
}
/**
* Invoke a command.
*
* @param CommandInterface $command Command
*
* @return CommandInterface
*/
public function invoke(CommandInterface $command)
{
// The backend instance is no longer added as an event parameter.
// All other legacy event parameters are accessible via the command object.
$args = ['command' => $command];
$backend = $this->resolve($command->getTargetIdentifier(), $args);
$this->triggerPre($this, $args);
try {
$command->execute($backend);
} catch (BackendException $e) {
$args['error'] = $e;
$this->triggerError($this, $args);
throw $e;
}
$this->triggerPost($this, $args);
return $command;
}
/**
* Resolve a backend.
*
* @param string $backendId Backend name
* @param array|ArrayAccess $args Service function arguments
*
* @return BackendInterface
*
* @throws Exception\RuntimeException Unable to resolve backend
*/
* @return \VuFind\RecordDriver\AbstractBase
*/
public function load(
$id,
$source = DEFAULT_SEARCH_BACKEND,
$tolerateMissing = false,
?ParamBag $params = null
) {
if (null !== $id && '' !== $id) {
$results = [];
if (
null !== $this->recordCache
&& $this->recordCache->isPrimary($source)
) {
$results = $this->recordCache->lookup($id, $source);
}
if (empty($results)) {
try {
$command = new RetrieveCommand($source, $id, $params);
$results = $this->searchService->invoke($command)
->getResult()->getRecords();
} catch (BackendException $e) {
if (!$tolerateMissing) {
throw $e;
}
}
}
if (
empty($results) && null !== $this->recordCache
&& $this->recordCache->isFallback($source)
) {
$results = $this->recordCache->lookup($id, $source);
if (!empty($results)) {
$results[0]->setExtraDetail('cached_record', true);
}
}
if (!empty($results)) {
return $results[0];
}
*
* @param ?ParamBag $params Search backend parameters
* @param bool $force Set to true to force a reload of the record, even if
* already loaded (useful if loading a record using different parameters)
*
* @return AbstractRecordDriver
*/
protected function loadRecord(?ParamBag $params = null, bool $force = false)
{
// Only load the record if it has not already been loaded. Note that
// when determining record ID, we check both the route match (the most
// common scenario) and the GET parameters (a fallback used by some
// legacy routes).
if ($force || !is_object($this->driver)) {
$recordLoader = $this->getRecordLoader();
$cacheContext = $this->getRequest()->getQuery()->get('cacheContext');
if (isset($cacheContext)) {
$recordLoader->setCacheContext($cacheContext);
}
$this->driver = $recordLoader->load(
$this->params()->fromRoute('id', $this->params()->fromQuery('id')),
$this->sourceId,
false,
$params
);
}
return $this->driver;
}
/**
* Redirect the user to the main record view.
*
* @param string $params Parameters to append to record URL.
* @param string $tab Record tab to display (null for default).
*
* @return mixed
*/
protected function redirectToRecord($params = '', $tab = null)
{
$details = $this->getRecordRouter()
*
* @return mixed
*/
protected function redirectToRecord($params = '', $tab = null)
{
$details = $this->getRecordRouter()
->getTabRouteDetails($this->loadRecord(), $tab);
$target = $this->url()->fromRoute($details['route'], $details['params']);
return $this->redirect()->toUrl($target . $params);
}
/**
* Support method to load tab information from the RecordTab PluginManager.
*
* @return void
*/
protected function loadTabDetails()
{
$driver = $this->loadRecord();
$request = $this->getRequest();
$manager = $this->getRecordTabManager();
$details = $manager
->getTabDetailsForRecord($driver, $request, $this->fallbackDefaultTab);
$this->allTabs = $details['tabs'];
$this->defaultTab = $details['default'] ? $details['default'] : false;
$this->backgroundTabs = $manager->getBackgroundTabNames($driver);
$this->tabsExtraScripts = $manager->getExtraScripts();
}
/**
* Get default tab for a given driver
*
* @return string
*/
protected function getDefaultTab()
{
// Load default tab if not already retrieved:
if (null === $this->defaultTab) {
$this->loadTabDetails();
$request = $this->getRequest();
$manager = $this->getRecordTabManager();
$details = $manager
->getTabDetailsForRecord($driver, $request, $this->fallbackDefaultTab);
$this->allTabs = $details['tabs'];
$this->defaultTab = $details['default'] ? $details['default'] : false;
$this->backgroundTabs = $manager->getBackgroundTabNames($driver);
$this->tabsExtraScripts = $manager->getExtraScripts();
}
/**
* Get default tab for a given driver
*
* @return string
*/
protected function getDefaultTab()
{
// Load default tab if not already retrieved:
if (null === $this->defaultTab) {
$this->loadTabDetails();
}
return $this->defaultTab;
}
/**
* Get all tab information for a given driver.
*
* @return array
*/
protected function getAllTabs()
{
if (null === $this->allTabs) {
$this->loadTabDetails();
}
return $this->allTabs;
}
/**
* Get names of tabs to be loaded in the background.
*
if (true === $driver->tryMethod('isCollection')) {
$params = $this->params()->fromQuery()
+ $this->params()->fromRoute();
// Disable path normalization since it can unencode e.g. encoded
// slashes in record id's
$options = [
'normalize_path' => false,
];
if ($sid = $this->getSearchMemory()->getCurrentSearchId()) {
$options['query'] = compact('sid');
}
$collectionUrl = $this->url()
->fromRoute($collectionRoute, $params, $options);
return $this->redirect()->toUrl($collectionUrl);
}
}
}
return $this->showTab(
$this->params()->fromRoute('tab', $this->getDefaultTab())
);
}
/**
* AJAX tab action -- render a tab without surrounding context.
*
* @return mixed
*/
public function ajaxtabAction()
{
$this->disableSessionWrites();
$this->loadRecord();
// Set layout to render content only:
$this->layout()->setTemplate('layout/lightbox');
$this->layout()->setVariable('layoutContext', 'tabs');
return $this->showTab(
$this->params()->fromPost('tab', $this->getDefaultTab()),
true
);
}
*/
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 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 (is_callable($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__,
get_debug_type($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(static fn($test): bool => $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->request;
);
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($controller::class);
$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 (is_callable($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__,
get_debug_type($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
$vufindProfiler = getenv('VUFIND_PROFILER_XHPROF');
if (!empty($vufindProfiler)) {
include __DIR__ . '/../module/VuFind/functions/profiler.php';
enableVuFindProfiling($vufindProfiler);
}
// Run the application!
$app = include __DIR__ . '/../config/application.php';
if (PHP_SAPI === 'cli') {
return $app->getServiceManager()
->get(\VuFindConsole\ConsoleRunner::class)->run();
} else {
// Setup remote code coverage if enabled:
if (getenv('VUFIND_CODE_COVERAGE')) {
$modules = $app->getServiceManager()
->get(\Laminas\ModuleManager\ModuleManager::class)->getModules();
include __DIR__ . '/../module/VuFind/functions/codecoverage.php';
setupVuFindRemoteCodeCoverage($modules);
}
$app->run();
}