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

Commit

Permalink
Merge branch 'hotfix/4542'
Browse files Browse the repository at this point in the history
Close #4542
  • Loading branch information
weierophinney committed Jun 10, 2013
2 parents 43faeed + 5741094 commit a92f8a3
Show file tree
Hide file tree
Showing 2 changed files with 285 additions and 2 deletions.
61 changes: 59 additions & 2 deletions library/Zend/Mvc/View/Console/ExceptionStrategy.php
Expand Up @@ -39,9 +39,22 @@ class ExceptionStrategy extends AbstractListenerAggregate
:stack
======================================================================
Previous Exception(s):
======================================================================
:previous
EOT;

/**
* A template for message to show in console when an exception has previous exceptions.
* @var string
*/
protected $previousMessage = <<<EOT
======================================================================
:className
:message
----------------------------------------------------------------------
:file::line
:stack
EOT;

/**
Expand Down Expand Up @@ -111,6 +124,26 @@ public function setMessage($message)
return $this;
}

/**
* Sets template for previous message that will be shown in Console.
*
* @param string $previousMessage
* @return ExceptionStrategy
*/
public function setPreviousMessage($previousMessage)
{
$this->previousMessage = $previousMessage;
return $this;
}

/**
* @return callable|string
*/
public function getPreviousMessage()
{
return $this->previousMessage;
}

/**
* Create an exception view model, and set the HTTP status code
*
Expand Down Expand Up @@ -152,6 +185,30 @@ public function prepareExceptionViewModel(MvcEvent $e)
$callback = $this->message;
$message = (string) $callback($exception, $this->displayExceptions);
} elseif ($this->displayExceptions && $exception instanceof \Exception) {
$previous = '';
$previousException = $exception->getPrevious();
while($previousException) {
$previous .= str_replace(
array(
':className',
':message',
':code',
':file',
':line',
':stack',
),array(
get_class($previousException),
$previousException->getMessage(),
$previousException->getCode(),
$previousException->getFile(),
$previousException->getLine(),
$exception->getTraceAsString(),
),
$this->previousMessage
);
$previousException = $previousException->getPrevious();
}

/* @var $exception \Exception */
$message = str_replace(
array(
Expand All @@ -169,7 +226,7 @@ public function prepareExceptionViewModel(MvcEvent $e)
$exception->getFile(),
$exception->getLine(),
$exception->getTraceAsString(),
$exception->getPrevious(),
$previous
),
$this->message
);
Expand Down
226 changes: 226 additions & 0 deletions tests/ZendTest/Mvc/View/Console/ExceptionStrategyTest.php
@@ -0,0 +1,226 @@
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @package Zend_Mvc
*/

namespace ZendTest\Mvc\View\Console;

use PHPUnit_Framework_TestCase as TestCase;
use Zend\Console\Response;
use Zend\EventManager\EventManager;
use Zend\Mvc\Application;
use Zend\Mvc\MvcEvent;
use Zend\Mvc\View\Console\ExceptionStrategy;
use Zend\View\Model;
use Zend\View\Model\ConsoleModel;

/**
* @category Zend
* @package Zend_Mvc
* @subpackage UnitTest
*/
class ExceptionStrategyTest extends TestCase
{
protected $strategy;

public function setUp()
{
$this->strategy = new ExceptionStrategy();
}

public function testEventListeners()
{
$events = new EventManager();
$events->attachAggregate($this->strategy);

$listeners = $events->getListeners(MvcEvent::EVENT_DISPATCH_ERROR);
$expectedCallback = array($this->strategy, 'prepareExceptionViewModel');
$expectedPriority = 1;
$found = false;
foreach ($listeners as $listener) {
$callback = $listener->getCallback();
if ($callback === $expectedCallback) {
if ($listener->getMetadatum('priority') == $expectedPriority) {
$found = true;
break;
}
}
}
$this->assertTrue($found, 'MvcEvent::EVENT_DISPATCH_ERROR not found');


$listeners = $events->getListeners(MvcEvent::EVENT_RENDER_ERROR);
$expectedCallback = array($this->strategy, 'prepareExceptionViewModel');
$expectedPriority = 1;
$found = false;
foreach ($listeners as $listener) {
$callback = $listener->getCallback();
if ($callback === $expectedCallback) {
if ($listener->getMetadatum('priority') == $expectedPriority) {
$found = true;
break;
}
}
}
$this->assertTrue($found, 'MvcEvent::EVENT_RENDER_ERROR not found');
}

public function testDefaultDisplayExceptions()
{
$this->assertTrue($this->strategy->displayExceptions(), 'displayExceptions should be true by default');
}

public function messageTokenProvider()
{
return array(
array(':className', true),
array(':message', true),
array(':code', false),
array(':file', true),
array(':line', true),
array(':stack', true),
);
}

/**
* @dataProvider messageTokenProvider
*/
public function testMessageTokens($token, $found)
{
if ($found) {
$this->assertContains($token, $this->strategy->getMessage(), sprintf('%s token not in message', $token));
} else {
$this->assertNotContains($token, $this->strategy->getMessage(), sprintf('%s token in message', $token));
}
}

public function previousMessageTokenProvider()
{
return array(
array(':className', true),
array(':message', true),
array(':code', false),
array(':file', true),
array(':line', true),
array(':stack', true),
array(':previous', true),
);
}

/**
* @dataProvider previousMessageTokenProvider
*/
public function testPreviousMessageTokens($token, $found)
{
if ($found) {
$this->assertContains($token, $this->strategy->getMessage(), sprintf('%s token not in previousMessage', $token));
} else {
$this->assertNotContains($token, $this->strategy->getMessage(), sprintf('%s token in previousMessage', $token));
}
}

public function testCanSetMessage()
{
$this->strategy->setMessage('something else');

$this->assertEquals('something else', $this->strategy->getMessage());
}

public function testCanSetPreviousMessage()
{
$this->strategy->setPreviousMessage('something else');

$this->assertEquals('something else', $this->strategy->getPreviousMessage());
}

public function testPrepareExceptionViewModelNoErrorInResultGetsSameResult()
{
$events = new EventManager();
$events->attachAggregate($this->strategy);

$event = new MvcEvent(MvcEvent::EVENT_DISPATCH_ERROR);

$event->setResult('something');
$this->assertEquals('something', $event->getResult(), 'When no error has been set on the event getResult should not be modified');
}

public function testPrepareExceptionViewModelResponseObjectInResultGetsSameResult()
{
$events = new EventManager();
$events->attachAggregate($this->strategy);

$event = new MvcEvent(MvcEvent::EVENT_DISPATCH_ERROR);

$result = new Response();
$event->setResult($result);
$this->assertEquals($result, $event->getResult(), 'When a response object has been set on the event getResult should not be modified');
}

public function testPrepareExceptionViewModelErrorsThatMustGetSameResult()
{
$errors = array(Application::ERROR_CONTROLLER_NOT_FOUND, Application::ERROR_CONTROLLER_INVALID, Application::ERROR_ROUTER_NO_MATCH);

foreach($errors as $error) {
$events = new EventManager();
$events->attachAggregate($this->strategy);

$exception = new \Exception('some exception');
$event = new MvcEvent(MvcEvent::EVENT_DISPATCH_ERROR, null, array('exception'=>$exception));
$event->setResult('something');
$event->setError($error);

$events->trigger($event, null, array('exception'=>$exception));

$this->assertEquals('something', $event->getResult(), sprintf('With an error of %s getResult should not be modified', $error));
}
}

public function testPrepareExceptionViewModelErrorException()
{
$errors = array(Application::ERROR_EXCEPTION, 'user-defined-error');

foreach($errors as $error) {
$events = new EventManager();
$events->attachAggregate($this->strategy);

$exception = new \Exception('message foo');
$event = new MvcEvent(MvcEvent::EVENT_DISPATCH_ERROR, null, array('exception'=>$exception));

$event->setError($error);

$this->strategy->prepareExceptionViewModel($event);

$this->assertInstanceOf('Zend\View\Model\ConsoleModel', $event->getResult());
$this->assertNotEquals('something', $event->getResult()->getResult(), sprintf('With an error of %s getResult should have been modified', $error));
$this->assertContains('message foo', $event->getResult()->getResult(), sprintf('With an error of %s getResult should have been modified', $error));
}
}

public function testPrepareExceptionRendersPreviousMessages()
{
$events = new EventManager();
$events->attachAggregate($this->strategy);

$messages = array('message foo', 'message bar', 'deepest message');
$exception = null;
$i = 0;
do {
$exception = new \Exception($messages[$i], null, $exception);
$i++;
} while($i < count($messages));

$event = new MvcEvent(MvcEvent::EVENT_DISPATCH_ERROR, null, array('exception'=>$exception));
$event->setError('user-defined-error');

$events->trigger($event, null, array('exception'=>$exception)); //$this->strategy->prepareExceptionViewModel($event);

foreach($messages as $message) {
$this->assertContains($message, $event->getResult()->getResult(), sprintf('Not all errors are rendered'));
}
}
}

0 comments on commit a92f8a3

Please sign in to comment.