Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

Commit

Permalink
[#1] Added ability to inject reason for triggering 404
Browse files Browse the repository at this point in the history
- if displayNotFoundReason is enabled, will inject a "reason" variable
  into the 404 view model returned, with one of the following constant
  values:
  - Application::ERROR_CONTROLLER_CANNOT_DISPATCH (controller cannot
    dispatch the request)
  - Application::ERROR_CONTROLLER_NOT_FOUND (controller class does not
    exist)
  - Application::ERROR_CONTROLLER_INVALID (controller requested is not
    dispatchable)
  - Application::ERROR_ROUTER_NO_MATCH (routing returned no match, or no
    controller in the matches)
  • Loading branch information
weierophinney committed Feb 28, 2012
1 parent 65c1de4 commit 5d8919a
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 5 deletions.
8 changes: 5 additions & 3 deletions library/Zend/Mvc/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@
*/
class Application implements AppContext
{
const ERROR_CONTROLLER_NOT_FOUND = 404;
const ERROR_CONTROLLER_INVALID = 404;
const ERROR_EXCEPTION = 500;
const ERROR_CONTROLLER_CANNOT_DISPATCH = 'error-controller-cannot-dispatch';
const ERROR_CONTROLLER_NOT_FOUND = 'error-controller-not-found';
const ERROR_CONTROLLER_INVALID = 'error-controller-invalid';
const ERROR_EXCEPTION = 'error-exception';
const ERROR_ROUTER_NO_MATCH = 'error-router-no-match';

protected $event;
protected $events;
Expand Down
6 changes: 6 additions & 0 deletions library/Zend/Mvc/Bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@ protected function setupLocator(AppContext $application)
),
),
'Zend\Mvc\View\RouteNotFoundStrategy' => array(
'setDisplayNotFoundReason' => array(
'displayNotFoundReason' => array(
'required' => false,
'type' => false,
),
),
'setNotFoundTemplate' => array(
'notFoundTemplate' => array(
'required' => false,
Expand Down
59 changes: 59 additions & 0 deletions library/Zend/Mvc/View/RouteNotFoundStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,27 @@ class RouteNotFoundStrategy implements ListenerAggregate
*/
protected $listeners = array();

/**
* Whether or not to display the reason for a 404
*
* @var bool
*/
protected $displayNotFoundReason = false;

/**
* Template to use to report page not found conditions
*
* @var string
*/
protected $notFoundTemplate = 'error';

/**
* The reason for a not-found condition
*
* @var false|string
*/
protected $reason = false;

/**
* Attach the aggregate to the specified event manager
*
Expand Down Expand Up @@ -78,6 +92,28 @@ public function detach(EventCollection $events)
}
}

/**
* Set value indicating whether or not to display the reason for a not-found condition
*
* @param bool $displayNotFoundReason
* @return RouteNotFoundStrategy
*/
public function setDisplayNotFoundReason($displayNotFoundReason)
{
$this->displayNotFoundReason = (bool) $displayNotFoundReason;
return $this;
}

/**
* Should we display the reason for a not-found condition?
*
* @return bool
*/
public function displayNotFoundReason()
{
return $this->displayNotFoundReason;
}

/**
* Get template for not found conditions
*
Expand Down Expand Up @@ -119,6 +155,8 @@ public function detectNotFoundError(MvcEvent $e)
switch ($error) {
case Application::ERROR_CONTROLLER_NOT_FOUND:
case Application::ERROR_CONTROLLER_INVALID:
case Application::ERROR_ROUTER_NO_MATCH:
$this->reason = $error;
$response = $e->getResponse();
if (!$response) {
$response = new HttpResponse();
Expand Down Expand Up @@ -154,6 +192,27 @@ public function prepareNotFoundViewModel(MvcEvent $e)
$model = new ViewModel\ViewModel();
$model->setVariable('message', 'Page not found.');
$model->setTemplate($this->getNotFoundTemplate());

// If displaying reasons, inject the reason
$this->injectNotFoundReason($model);

$e->setResult($model);
}

protected function injectNotFoundReason($model)
{
if (!$this->displayNotFoundReason()) {
return;
}

// no route match, controller not found, or controller invalid
if ($this->reason) {
$model->setVariable('reason', $this->reason);
return;
}

// otherwise, must be a case of the controller not being able to
// dispatch itself.
$model->setVariable('reason', Application::ERROR_CONTROLLER_CANNOT_DISPATCH);
}
}
57 changes: 55 additions & 2 deletions tests/Zend/Mvc/View/RouteNotFoundStrategyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ public function test404ErrorsInject404ResponseStatusCode()
$response = new Response();
$event = new MvcEvent();
$errors = array(
'not-found' => Application::ERROR_CONTROLLER_NOT_FOUND,
'invalid' => Application::ERROR_CONTROLLER_INVALID,
'error-controller-not-found' => Application::ERROR_CONTROLLER_NOT_FOUND,
'error-controller-invalid' => Application::ERROR_CONTROLLER_INVALID,
'error-router-no-match' => Application::ERROR_ROUTER_NO_MATCH,
);
$event->setResponse($response);
foreach ($errors as $key => $error) {
Expand All @@ -61,6 +62,36 @@ public function test404ErrorsInject404ResponseStatusCode()
}
}

public function testRouterAndDispatchErrorsInjectReasonInViewModelWhenAllowed()
{
$response = new Response();
$event = new MvcEvent();
$errors = array(
'error-controller-not-found' => Application::ERROR_CONTROLLER_NOT_FOUND,
'error-controller-invalid' => Application::ERROR_CONTROLLER_INVALID,
'error-router-no-match' => Application::ERROR_ROUTER_NO_MATCH,
);
$event->setResponse($response);
foreach (array(true, false) as $allow) {
$this->strategy->setDisplayNotFoundReason($allow);
foreach ($errors as $key => $error) {
$response->setStatusCode(200);
$event->setError($error);
$this->strategy->detectNotFoundError($event);
$this->strategy->prepareNotFoundViewModel($event);
$viewModel = $event->getResult();
$this->assertInstanceOf('Zend\View\Model', $viewModel);
$variables = $viewModel->getVariables();
if ($allow) {
$this->assertTrue(isset($variables['reason']));
$this->assertEquals($key, $variables['reason']);
} else {
$this->assertFalse(isset($variables['reason']));
}
}
}
}

public function testNon404ErrorsInjectNoStatusCode()
{
$response = new Response();
Expand Down Expand Up @@ -125,6 +156,28 @@ public function test404ResponsePrepares404ViewModelWithTemplateFromStrategy()
$this->assertTrue(isset($variables['message']));
}

public function test404ResponsePrepares404ViewModelWithReasonWhenAllowed()
{
$response = new Response();
$event = new MvcEvent();

foreach (array(true, false) as $allow) {
$this->strategy->setDisplayNotFoundReason($allow);
$response->setStatusCode(404);
$event->setResponse($response);
$this->strategy->prepareNotFoundViewModel($event);
$model = $event->getResult();
$this->assertInstanceOf('Zend\View\Model', $model);
$variables = $model->getVariables();
if ($allow) {
$this->assertTrue(isset($variables['reason']));
$this->assertEquals(Application::ERROR_CONTROLLER_CANNOT_DISPATCH, $variables['reason']);
} else {
$this->assertFalse(isset($variables['reason']));
}
}
}

public function testInjectsHttpResponseIntoEventIfNoneAlreadyPresent()
{
$event = new MvcEvent();
Expand Down

0 comments on commit 5d8919a

Please sign in to comment.