zendframework/zf2 — pull request #1685 by Slamdunk (2012-06-30 06:02:42+00:00)
Title: Pass the original MvcEvent to dispatch.error listeners

Hi, the purpose of this PR is to let `dispatch.error` listeners to manipulate the original MvcEvent like `dispatch` listeners do.

I'll show an example: assume you want to render a custom `ViewModel` on `dispatch.error`, you'll probably do something like:

```php
events()->attach('dispatch.error', function(MvcEvent $e) {
$model = new ViewModel();
$e->setResult($model);
});
```

But currently this is not feasable.

Hey, wait, this is exactly what `Zend\Mvc\View\ExceptionStrategy` do, and it seems it works. Well, yes it works but it's a bug.

```php
trigger('dispatch.error', $error);

// Zend\Mvc\View\ExceptionStrategy:162 sets the new result
$model = new ViewModel();
$error->setResult($model);

// Now, at last Zend\Mvc\View\InjectViewModelListener:90 is triggered
// in the dispatch.error listeners list
$model = $error->getViewModel();

if ($result->terminate()) {
$error->setViewModel($result);
return;
}

$model->addChild($result);

// But in the past 6 lines note that

$error !== $e;
$model === $error->getViewModel();
$model === $e->getViewModel();

// Because clone clones the main object but not child, so the
// reference to the layout ViewModel is the same

// So, if I do not set my new ViewModel as Terminal, everything
// goes ok because

$model->addChild($result);

// it's applied by reference to the original ViewModel of the original MvcEvent
// but if I want to set my ViewModel as Terminal

if ($result->terminate()) {
$error->setViewModel($result);
return;
}

// this sets the new ViewModel only in the cloned MvcEvent, and not in the original one.
// So, when all triggers are complete, in Zend\Mvc\DispatchListener:164

$results = $events->trigger('dispatch.error', $error);
if (count($results)) {
$return = $results->last();
} else {
$return = $error->getParams();
}

return $this->complete($return, $e);

// $error has in memory the new result and the new ViewModel, but
// $e hasn't !
```

I've made a test to prove it, but it does not explain clearly all the logic behind this bug, so I preferred to document it on this PR.