View Source

<p>Currently we have Zend\Mvc\Application attaching 3 Listeners:<br />
RouteListener, DisptachListener and ViewManager.<br />
The ViewManager registers the SendResponseListener and the latter does:</p>
<ac:macro ac:name="code"><ac:parameter ac:name="language">php</ac:parameter><ac:plain-text-body><![CDATA[
if (is_callable(array($response,'send'))) {
return $response->send();
}
]]></ac:plain-text-body></ac:macro>
<p>As Zend\Http\PhpEnvironment\Response and Console\Response are the only response objects, which have a send() method, these are the only responses you can send in zf2.</p>

<p>However you can return any response object in your controller, the mvc dispatch will get short-circuited and you end up in the MvcEvent::EVENT_FINISH event. No response will be send. So when you return a StreamResponse in your controller (for file download in secured area f.e.), the stream will not get send.</p>

<p>The whole work-flow is a bit ugly. First the SendResponseListener should not be in Zend\Mvc\View and instead in Zend\Mvc. Sending a response is not part of the view layer. It's part of the mvc layer. The response object should not be responsible for sending itself. We have a SendResponseListener, it should be it's job.</p>

<p>Implementation changes:</p>

<p>1) Move the SendResponseListener one level up (Mvc Package, no View subpackage).<br />
2) Mark the send() method from Environment\Response and Console\Response as deprecated<br />
3) SendResponseListener triggers sendResponse event, additional listener (PhpEnvironmentResponseSender, CliResponseSender) will get attached to the sendrepsonselistener by default.<br />
4) Remove the registration of the SendResponseListener from ViewManager<br />
5) Add the SendResponseListener registration in Zend\Mvc\Application</p>

<p>Example use case:</p>

<ac:macro ac:name="code"><ac:parameter ac:name="language">php</ac:parameter><ac:plain-text-body><![CDATA[
<?php

namespace Application\Controller;

use Zend\Http\Headers;
use Zend\Http\Response\Stream;
use Zend\Mvc\Controller\AbstractActionController;

class FileController extends AbstractActionController
{
public function fileAction()
{
// some more code

$response = new Stream();
$response->setStream($file->getResource());

$headers = new Headers();
$headers->addHeaders(array(
'Content-Disposition' => 'attachment; filename="' . $file->getFilename() .'"',
'Content-Type' => 'application/octet-stream'
));
$response->setHeaders($headers);
return $response;
}
}
]]></ac:plain-text-body></ac:macro>