Commit 9152debf authored by Crell's avatar Crell
Browse files

Convert View listeners to a single view subscriber.

parent d25fcbae
<?php
namespace Drupal\Core;
use Symfony\Component\HttpFoundation\Request;
/**
* Description of ContentNegotiation
*
*/
class ContentNegotiation {
public function getContentType(Request $request) {
$acceptable_content_types = $request->getAcceptableContentTypes();
if (in_array('application/json', $request->getAcceptableContentTypes())) {
return 'json';
}
if(in_array('text/html', $acceptable_content_types) || in_array('*/*', $acceptable_content_types)) {
return 'html';
}
}
}
......@@ -13,8 +13,7 @@
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\EventListener\RouterListener;
use Symfony\Component\HttpKernel\EventListener\ExceptionListener;
use Drupal\Core\EventSubscriber\HtmlSubscriber;
use Drupal\Core\EventSubscriber\JsonSubscriber;
use Drupal\Core\EventSubscriber\ViewSubscriber;
use Drupal\Core\EventSubscriber\AccessSubscriber;
use Drupal\Core\EventSubscriber\PathSubscriber;
use Drupal\Core\EventSubscriber\LegacyControllerSubscriber;
......@@ -52,11 +51,12 @@ public function __construct(EventDispatcherInterface $dispatcher, ControllerReso
$this->matcher = new UrlMatcher($context);
$this->dispatcher->addSubscriber(new RouterListener($this->matcher));
$negotiation = new ContentNegotiation();
// @todo Make this extensible rather than just hard coding some.
// @todo Add a subscriber to handle other things, too, like our Ajax
// replacement system.
$this->dispatcher->addSubscriber(new HtmlSubscriber());
$this->dispatcher->addSubscriber(new JsonSubscriber());
$this->dispatcher->addSubscriber(new ViewSubscriber($negotiation));
$this->dispatcher->addSubscriber(new AccessSubscriber());
$this->dispatcher->addSubscriber(new PathSubscriber());
$this->dispatcher->addSubscriber(new LegacyControllerSubscriber());
......@@ -67,6 +67,6 @@ public function __construct(EventDispatcherInterface $dispatcher, ControllerReso
// Either way, treat it as a server-level error and return an HTTP 500.
// By default, this will be an HTML-type response because that's a decent
// best guess if we don't know otherwise.
$this->dispatcher->addSubscriber(new ExceptionListener(array(new ExceptionController(), 'execute')));
$this->dispatcher->addSubscriber(new ExceptionListener(array(new ExceptionController($negotiation), 'execute')));
}
}
<?php
namespace Drupal\Core\EventSubscriber;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* @file
*
* Definition of Drupal\Core\EventSubscriber\HtmlSubscriber;
*/
/**
* Main subscriber for JSON-type HTTP responses.
*/
class JsonSubscriber implements EventSubscriberInterface {
/**
* Determines if we are dealing with an JSON-style response.
*
* @param GetResponseEvent $event
* The Event to process.
* @return boolean
* True if it is an event we should process as JSON, False otherwise.
*/
protected function isJsonRequestEvent(GetResponseEvent $event) {
return in_array('application/json', $event->getRequest()->getAcceptableContentTypes());
}
/**
* Processes a successful controller into an HTTP 200 response.
*
* Some controllers may not return a response object but simply the body of
* one. The VIEW event is called in that case, to allow us to mutate that
* body into a Response object. In particular we assume that the return
* from an JSON-type response is a JSON string, so just wrap it into a
* Response object.
*
* @param GetResponseEvent $event
* The Event to process.
*/
public function onView(GetResponseEvent $event) {
if ($this->isJsonRequestEvent($event)) {
$page_callback_result = $event->getControllerResult();
$response = $this->createJsonResponse();
$response->setContent($page_callback_result);
$event->setResponse($response);
}
}
/**
* Registers the methods in this class that should be listeners.
*
* @return array
* An array of event listener definitions.
*/
static function getSubscribedEvents() {
//$events[KernelEvents::EXCEPTION][] = array('onNotFoundHttpException');
//$events[KernelEvents::EXCEPTION][] = array('onAccessDeniedException');
//$events[KernelEvents::EXCEPTION][] = array('onMethodAllowedException');
$events[KernelEvents::VIEW][] = array('onView');
return $events;
}
}
......@@ -2,7 +2,6 @@
namespace Drupal\Core\EventSubscriber;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
......@@ -12,30 +11,68 @@
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\Core\DrupalKernel;
use Drupal\Core\ContentNegotiation;
/**
* @file
*
* Definition of Drupal\Core\EventSubscriber\HtmlSubscriber;
* Definition of Drupal\Core\EventSubscriber\ViewSubscriber;
*/
/**
* Main subscriber for HTML-type HTTP responses.
* Main subscriber for VIEW HTTP responses.
*/
class HtmlSubscriber implements EventSubscriberInterface {
class ViewSubscriber implements EventSubscriberInterface {
protected $negotiation;
public function __construct(ContentNegotiation $negotiation) {
$this->negotiation = $negotiation;
}
protected function createJsonResponse() {
$response = new Response();
$response->headers->set('Content-Type', 'application/json; charset=utf-8');
return $response;
}
/**
* Determines if we are dealing with an HTML-style response.
* Processes a successful controller into an HTTP 200 response.
*
* Some controllers may not return a response object but simply the body of
* one. The VIEW event is called in that case, to allow us to mutate that
* body into a Response object. In particular we assume that the return
* from an JSON-type response is a JSON string, so just wrap it into a
* Response object.
*
* @param GetResponseEvent $event
* The Event to process.
* @return boolean
* True if it is an event we should process as HTML, False otherwise.
*/
protected function isHtmlRequestEvent(GetResponseEvent $event) {
$acceptable_content_types = $event->getRequest()->getAcceptableContentTypes();
return in_array('text/html', $acceptable_content_types) || in_array('*/*', $acceptable_content_types);
public function onView(GetResponseEvent $event) {
$request = $event->getRequest();
$method = 'on' . $this->negotiation->getContentType($request);
if (method_exists($this, $method)) {
$event->setResponse($this->$method($event));
}
else {
$event->setResponse(new Response('Unsupported Media Type', 415));
}
}
public function onJson(GetResponseEvent $event) {
$page_callback_result = $event->getControllerResult();
print_r($page_callback_result);
$response = $this->createJsonResponse();
$response->setContent($page_callback_result);
return $response;
}
/**
......@@ -50,14 +87,9 @@ protected function isHtmlRequestEvent(GetResponseEvent $event) {
* @param GetResponseEvent $event
* The Event to process.
*/
public function onView(GetResponseEvent $event) {
if ($this->isHtmlRequestEvent($event)) {
$page_callback_result = $event->getControllerResult();
$event->setResponse(new Response(drupal_render_page($page_callback_result)));
}
else {
$event->setResponse(new Response('Unsupported Media Type', 415));
}
public function onHtml(GetResponseEvent $event) {
$page_callback_result = $event->getControllerResult();
return new Response(drupal_render_page($page_callback_result));
}
/**
......@@ -67,10 +99,7 @@ public function onView(GetResponseEvent $event) {
* An array of event listener definitions.
*/
static function getSubscribedEvents() {
// Since we want HTML to be our default, catch-all response type, give its
// listeners a very low priority so that they always check last.
$events[KernelEvents::VIEW][] = array('onView', -5);
$events[KernelEvents::VIEW][] = array('onView');
return $events;
}
......
<?php
namespace Drupal\Core;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Exception\FlattenException;
use Exception;
/**
* Description of ExceptionController
*
*/
class ExceptionController {
protected $negotiation;
public function __construct(ContentNegotiation $negotiation) {
$this->negotiation = $negotiation;
}
public function execute(FlattenException $exception, Request $request) {
$method = 'on' . $exception->getStatusCode() . $this->negotiation->getContentType($request);
if (method_exists($this, $method)) {
return $this->$method($exception, $request);
}
return new Response('A fatal error occurred: ' . $exception->getMessage(), $exception->getStatusCode());
}
/**
* Processes a MethodNotAllowed exception into an HTTP 405 response.
*
* @param GetResponseEvent $event
* The Event to process.
*/
public function on405Html(FlattenException $exception, Request $request) {
$event->setResponse(new Response('Method Not Allowed', 405));
}
/**
* Processes an AccessDenied exception into an HTTP 403 response.
*
* @param GetResponseEvent $event
* The Event to process.
*/
public function on403Html(FlattenException $exception, Request $request) {
return new Response('Access Denied', 403);
}
public function on404Html(FlattenException $exception, Request $request) {
watchdog('page not found', check_plain($_GET['q']), NULL, WATCHDOG_WARNING);
// Check for and return a fast 404 page if configured.
// @todo Inline this rather than using a function.
drupal_fast_404();
$system_path = $request->attributes->get('system_path');
// Keep old path for reference, and to allow forms to redirect to it.
if (!isset($_GET['destination'])) {
$_GET['destination'] = $system_path;
}
$path = drupal_get_normal_path(variable_get('site_404', ''));
if ($path && $path != $system_path) {
// @TODO: Um, how do I specify an override URL again? Totally not clear.
// Do that and sub-call the kernel rather than using meah().
$request = Request::create($path);
$kernel = new DrupalKernel();
$response = $kernel->handle($request, HttpKernelInterface::SUB_REQUEST);
$response->setStatusCode(404, 'Not Found');
}
else {
$response = new Response('Not Found', 404);
// @todo Replace this block with something cleaner.
$return = t('The requested page "@path" could not be found.', array('@path' => $request->getPathInfo()));
drupal_set_title(t('Page not found'));
drupal_set_page_content($return);
$page = element_info('page');
$content = drupal_render_page($page);
$response->setContent($content);
}
return $response;
}
protected function createJsonResponse() {
$response = new Response();
$response->headers->set('Content-Type', 'application/json; charset=utf-8');
return $response;
}
/**
* Processes an AccessDenied exception into an HTTP 403 response.
*
* @param GetResponseEvent $event
* The Event to process.
*/
public function on403Json(FlattenException $exception, Request $request) {
$response = $this->createJsonResponse();
$response->setStatusCode(403, 'Access Denied');
return $response;
}
/**
* Processes a NotFound exception into an HTTP 404 response.
*
* @param GetResponseEvent $event
* The Event to process.
*/
public function on404Json(FlattenException $exception, Request $request) {
$response = $this->createJsonResponse();
$response->setStatusCode(404, 'Not Found');
return $response;
}
/**
* Processes a MethodNotAllowed exception into an HTTP 405 response.
*
* @param GetResponseEvent $event
* The Event to process.
*/
public function on405Json(FlattenException $exception, Request $request) {
$response = $this->createJsonResponse();
$response->setStatusCode(405, 'Method Not Allowed');
return $response;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment