End a Request with a Zend Framework 2 Controller Plugin

By default, Zend Framework 2 (ZF2) controller plugins cannot force the request to end. Typically, the controller action calls plugin methods and then does what it wishes with the returned value. However, there are some circumstances (such as user authentication), where you may want to end the request if certain conditions are met in the controller plugin.

For example:

Say you want to return the currently authenticated user using a controller plugin, and if there is no authenticated user, return a 401 status code. When your controller calls the plugin, you would have to check the return value every time and have boilerplate code to set the status code in the response and return the response from your controller action.

There is a better way:

Instead of having to check in your controller, wouldn’t it be better if you could just have the Plugin do the work: set the status code and return the response to the client?

This class makes that possible. By emitting MvcEvent:EVENT\_FINISH, it triggers the listeners to send the response to the client. By immediately exiting the application and ending the request, we ensure that MvcEvent:EVENT\_FINISH is emitted only once.

/**
 * Plugins interiting from this superclass will be able to terminate the request by calling sendResponse()
 *
 * Class RequestTerminationPlugin
 * @package Application\Controller\Plugin
 */
abstract class SendResponsePlugin extends AbstractPlugin
{

    /**
     * @var MvcEvent
     */
    private $event;


    /**
     * Sends the response and terminates.
     * @param ResponseInterface $response
     */
    protected function sendResponse(ResponseInterface $response)
    {
        $e = $this->getEvent();
        $e->setResponse($response);

        $e->getApplication()->getEventManager()->trigger(MvcEvent::EVENT_FINISH, $e);
        exit();
    }


    /**
     * Get the event
     *
     * @return MvcEvent
     * @throws DomainException if unable to find event
     */
    protected function getEvent()
    {
        if ($this->event) {
            return $this->event;
        }

        $controller = $this->getController();
        if (!$controller instanceof InjectApplicationEventInterface) {
            throw new DomainException(get_class($this) . ' requires a controller that implements InjectApplicationEventInterface');
        }

        $event = $controller->getEvent();
        if (!$event instanceof MvcEvent) {
            $params = $event->getParams();
            $event  = new MvcEvent();
            $event->setParams($params);
        }
        $this->event = $event;

        return $this->event;
    }

}