3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
10 namespace Zend\Mvc\View\Http
;
12 use Zend\EventManager\AbstractListenerAggregate
;
13 use Zend\EventManager\EventManagerInterface
;
14 use Zend\Http\Response
as HttpResponse
;
15 use Zend\Mvc\Application
;
16 use Zend\Mvc\MvcEvent
;
17 use Zend\Stdlib\ResponseInterface
as Response
;
18 use Zend\View\Model\ViewModel
;
20 class RouteNotFoundStrategy
extends AbstractListenerAggregate
23 * Whether or not to display exceptions related to the 404 condition
27 protected $displayExceptions = false;
30 * Whether or not to display the reason for a 404
34 protected $displayNotFoundReason = false;
37 * Template to use to report page not found conditions
41 protected $notFoundTemplate = 'error';
44 * The reason for a not-found condition
48 protected $reason = false;
53 public function attach(EventManagerInterface
$events)
55 $this->listeners
[] = $events->attach(MvcEvent
::EVENT_DISPATCH
, array($this, 'prepareNotFoundViewModel'), -90);
56 $this->listeners
[] = $events->attach(MvcEvent
::EVENT_DISPATCH_ERROR
, array($this, 'detectNotFoundError'));
57 $this->listeners
[] = $events->attach(MvcEvent
::EVENT_DISPATCH_ERROR
, array($this, 'prepareNotFoundViewModel'));
61 * Set value indicating whether or not to display exceptions related to a not-found condition
63 * @param bool $displayExceptions
64 * @return RouteNotFoundStrategy
66 public function setDisplayExceptions($displayExceptions)
68 $this->displayExceptions
= (bool) $displayExceptions;
73 * Should we display exceptions related to a not-found condition?
77 public function displayExceptions()
79 return $this->displayExceptions
;
83 * Set value indicating whether or not to display the reason for a not-found condition
85 * @param bool $displayNotFoundReason
86 * @return RouteNotFoundStrategy
88 public function setDisplayNotFoundReason($displayNotFoundReason)
90 $this->displayNotFoundReason
= (bool) $displayNotFoundReason;
95 * Should we display the reason for a not-found condition?
99 public function displayNotFoundReason()
101 return $this->displayNotFoundReason
;
105 * Get template for not found conditions
107 * @param string $notFoundTemplate
108 * @return RouteNotFoundStrategy
110 public function setNotFoundTemplate($notFoundTemplate)
112 $this->notFoundTemplate
= (string) $notFoundTemplate;
117 * Get template for not found conditions
121 public function getNotFoundTemplate()
123 return $this->notFoundTemplate
;
127 * Detect if an error is a 404 condition
129 * If a "controller not found" or "invalid controller" error type is
130 * encountered, sets the response status code to 404.
135 public function detectNotFoundError(MvcEvent
$e)
137 $error = $e->getError();
143 case Application
::ERROR_CONTROLLER_NOT_FOUND
:
144 case Application
::ERROR_CONTROLLER_INVALID
:
145 case Application
::ERROR_ROUTER_NO_MATCH
:
146 $this->reason
= $error;
147 $response = $e->getResponse();
149 $response = new HttpResponse();
150 $e->setResponse($response);
152 $response->setStatusCode(404);
160 * Create and return a 404 view model
165 public function prepareNotFoundViewModel(MvcEvent
$e)
167 $vars = $e->getResult();
168 if ($vars instanceof Response
) {
169 // Already have a response as the result
173 $response = $e->getResponse();
174 if ($response->getStatusCode() != 404) {
175 // Only handle 404 responses
179 if (!$vars instanceof ViewModel
) {
180 $model = new ViewModel();
181 if (is_string($vars)) {
182 $model->setVariable('message', $vars);
184 $model->setVariable('message', 'Page not found.');
188 if ($model->getVariable('message') === null) {
189 $model->setVariable('message', 'Page not found.');
193 $model->setTemplate($this->getNotFoundTemplate());
195 // If displaying reasons, inject the reason
196 $this->injectNotFoundReason($model);
198 // If displaying exceptions, inject
199 $this->injectException($model, $e);
201 // Inject controller if we're displaying either the reason or the exception
202 $this->injectController($model, $e);
204 $e->setResult($model);
208 * Inject the not-found reason into the model
210 * If $displayNotFoundReason is enabled, checks to see if $reason is set,
211 * and, if so, injects it into the model. If not, it injects
212 * Application::ERROR_CONTROLLER_CANNOT_DISPATCH.
214 * @param ViewModel $model
217 protected function injectNotFoundReason(ViewModel
$model)
219 if (!$this->displayNotFoundReason()) {
223 // no route match, controller not found, or controller invalid
225 $model->setVariable('reason', $this->reason
);
229 // otherwise, must be a case of the controller not being able to
231 $model->setVariable('reason', Application
::ERROR_CONTROLLER_CANNOT_DISPATCH
);
235 * Inject the exception message into the model
237 * If $displayExceptions is enabled, and an exception is found in the
238 * event, inject it into the model.
240 * @param ViewModel $model
244 protected function injectException($model, $e)
246 if (!$this->displayExceptions()) {
250 $model->setVariable('display_exceptions', true);
252 $exception = $e->getParam('exception', false);
253 if (!$exception instanceof \Exception
) {
257 $model->setVariable('exception', $exception);
261 * Inject the controller and controller class into the model
263 * If either $displayExceptions or $displayNotFoundReason are enabled,
264 * injects the controllerClass from the MvcEvent. It checks to see if a
265 * controller is present in the MvcEvent, and, if not, grabs it from
266 * the route match if present; if a controller is found, it injects it into
269 * @param ViewModel $model
273 protected function injectController($model, $e)
275 if (!$this->displayExceptions() && !$this->displayNotFoundReason()) {
279 $controller = $e->getController();
280 if (empty($controller)) {
281 $routeMatch = $e->getRouteMatch();
282 if (empty($routeMatch)) {
286 $controller = $routeMatch->getParam('controller', false);
292 $controllerClass = $e->getControllerClass();
293 $model->setVariable('controller', $controller);
294 $model->setVariable('controller_class', $controllerClass);