Permalink
Browse files

Add Mvc\View\SendResponseListener which will do $response->send() at …

…Application finish event.

It is not a good practice to include app logic or send response in a index.php or boostrap file. Those are meant
for initialization and running the MVC framework. Before this change, in order for a zf2 application to display
anything in the browser (or show something in console) one had to capture a Response object instance coming from
$application->run() and then invoke a send() method.

After this change, the task of sending a response is delegated to a dedicated listener. This allows for changing
sending behavior via ViewManager subclass or real-time modifications of Application EventManager stack. It also
allows modules to short-circuit, implement full-page caching, forward the response to an external storage or handler
(i.e. send it to a service, tcp port, send it to a stream, sanitizer etc.), or completely prevent sending of response
in some scenarios.
  • Loading branch information...
1 parent efa70af commit 37747bd608d9b75dc340c4ff8b991ff3706dd4de @Thinkscape committed Jul 16, 2012
@@ -18,6 +18,7 @@
use Zend\Mvc\Exception;
use Zend\Mvc\MvcEvent;
use Zend\Mvc\Router\RouteMatch;
+use Zend\Mvc\View\SendResponseListener;
use Zend\ServiceManager\ConfigurationInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\Stdlib\ArrayUtils;
@@ -139,6 +140,7 @@ public function onBootstrap($event)
$createViewModelListener = new CreateViewModelListener();
// $injectTemplateListener = new InjectTemplateListener();
$injectViewModelListener = new InjectViewModelListener();
+ $sendResponseListener = new SendResponseListener();
$this->registerMvcRenderingStrategies($events);
$this->registerViewStrategies();
@@ -147,6 +149,7 @@ public function onBootstrap($event)
// $events->attach($exceptionStrategy);
$events->attach(MvcEvent::EVENT_DISPATCH_ERROR, array($injectViewModelListener, 'injectViewModel'), -100);
$events->attach($mvcRenderingStrategy);
+ $events->attach($sendResponseListener);
$sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, array($createViewModelListener, 'createViewModelFromArray'), -80);
$sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, array($createViewModelListener, 'createViewModelFromString'), -80);
@@ -18,6 +18,7 @@
use Zend\Mvc\Exception;
use Zend\Mvc\MvcEvent;
use Zend\Mvc\Router\RouteMatch;
+use Zend\Mvc\View\SendResponseListener;
use Zend\ServiceManager\ConfigurationInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\Stdlib\ArrayUtils;
@@ -138,6 +139,7 @@ public function onBootstrap($event)
$createViewModelListener = new CreateViewModelListener();
$injectTemplateListener = new InjectTemplateListener();
$injectViewModelListener = new InjectViewModelListener();
+ $sendResponseListener = new SendResponseListener();
$this->registerMvcRenderingStrategies($events);
$this->registerViewStrategies();
@@ -146,6 +148,7 @@ public function onBootstrap($event)
$events->attach($exceptionStrategy);
$events->attach(MvcEvent::EVENT_DISPATCH_ERROR, array($injectViewModelListener, 'injectViewModel'), -100);
$events->attach($mvcRenderingStrategy);
+ $events->attach($sendResponseListener);
$sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, array($createViewModelListener, 'createViewModelFromArray'), -80);
$sharedEvents->attach('Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH, array($routeNotFoundStrategy, 'prepareNotFoundViewModel'), -90);
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Mvc
+ */
+
+namespace Zend\Mvc\View;
+
+use Zend\EventManager\EventManagerInterface;
+use Zend\EventManager\ListenerAggregateInterface;
+use Zend\Mvc\MvcEvent;
+use Zend\Stdlib\ResponseInterface as Response;
+
+/**
+ * @category Zend
+ * @package Zend_Mvc
+ * @subpackage View
+ */
+class SendResponseListener implements ListenerAggregateInterface
+{
+ /**
+ * @var \Zend\Stdlib\CallbackHandler[]
+ */
+ protected $listeners = array();
+
+ /**
+ * Attach the aggregate to the specified event manager
+ *
+ * @param EventManagerInterface $events
+ * @return void
+ */
+ public function attach(EventManagerInterface $events)
+ {
+ $this->listeners[] = $events->attach(MvcEvent::EVENT_FINISH, array($this, 'sendResponse'), -10000);
+ }
+
+ /**
+ * Detach aggregate listeners from the specified event manager
+ *
+ * @param EventManagerInterface $events
+ * @return void
+ */
+ public function detach(EventManagerInterface $events)
+ {
+ foreach ($this->listeners as $index => $listener) {
+ if ($events->detach($listener)) {
+ unset($this->listeners[$index]);
+ }
+ }
+ }
+
+ /**
+ * Send the response
+ *
+ * @param MvcEvent $e
+ * @return mixed
+ */
+ public function sendResponse(MvcEvent $e)
+ {
+ $response = $e->getResponse();
+ if (!$response instanceof Response) {
+ return false; // there is no response to send
+ }
+
+ // send the response if possible
+ if(is_callable(array($response,'send'))){
+ return $response->send();
+ }
+ }
+}

0 comments on commit 37747bd

Please sign in to comment.