Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
project
drupal
Commits
d6f33f14
Commit
d6f33f14
authored
Mar 31, 2012
by
Crell
Browse files
Merge branch 'kernel-fabpot-review' into kernel
parents
e13dd9cb
14881552
Changes
105
Hide whitespace changes
Inline
Side-by-side
core/includes/common.inc
View file @
d6f33f14
...
...
@@ -716,6 +716,7 @@ function drupal_not_found() {
throw
new
NotFoundHttpException
();
// @todo Remove this line.
//drupal_deliver_page(MENU_NOT_FOUND);
}
...
...
@@ -732,6 +733,7 @@ function drupal_access_denied() {
throw
new
AccessDeniedException
();
// @todo Remove this line.
//drupal_deliver_page(MENU_ACCESS_DENIED);
}
...
...
core/lib/Drupal/Core/ContentNegotiation.php
0 → 100644
View file @
d6f33f14
<?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'
;
}
}
}
core/lib/Drupal/Core/DrupalKernel.php
View file @
d6f33f14
...
...
@@ -5,17 +5,15 @@
use
Symfony\Component\HttpFoundation\Request
;
use
Symfony\Component\HttpFoundation\Response
;
use
Symfony\Component\Routing\RequestContext
;
use
Symfony\Component\HttpKernel\HttpKernelInterface
;
use
Symfony\Component\HttpKernel\HttpKernel
;
use
Symfony\Component\HttpKernel\KernelEvents
;
use
Symfony\Component\HttpKernel\Controller\ControllerResolver
;
use
Symfony\Component\EventDispatcher\EventDispatcher
;
use
Symfony\Component\EventDispatcher\EventDispatcherInterface
;
use
Symfony\Component\EventDispatcher\Event
;
use
Symfony\Component\HttpKernel\Controller\ControllerResolverInterface
;
use
Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent
;
use
Symfony\Component\HttpKernel\EventListener\RouterListener
;
use
Drupal\Core\EventSubscriber\HtmlSubscriber
;
use
Drupal\Core\EventSubscriber\JsonSubscriber
;
use
Symfony\Component\HttpKernel\EventListener\ExceptionListener
;
use
Drupal\Core\EventSubscriber\ViewSubscriber
;
use
Drupal\Core\EventSubscriber\AccessSubscriber
;
use
Drupal\Core\EventSubscriber\PathSubscriber
;
use
Drupal\Core\EventSubscriber\LegacyControllerSubscriber
;
...
...
@@ -31,80 +29,44 @@
/**
* The DrupalApp class is the core of Drupal itself.
*/
class
DrupalKernel
implements
HttpKernelInterface
{
/**
*
* @param Request $request
* The request to process.
* @return Response
* The response object to return to the requesting user agent.
*/
function
handle
(
Request
$request
,
$type
=
self
::
MASTER_REQUEST
,
$catch
=
true
)
{
try
{
$dispatcher
=
$this
->
getDispatcher
();
class
DrupalKernel
extends
HttpKernel
{
protected
$dispatcher
;
protected
$resolver
;
/**
* Constructor
*
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
* @param ControllerResolverInterface $resolver A ControllerResolverInterface instance
*
* @api
*/
public
function
__construct
(
EventDispatcherInterface
$dispatcher
,
ControllerResolverInterface
$resolver
)
{
parent
::
__construct
(
$dispatcher
,
$resolver
);
$this
->
dispatcher
=
$dispatcher
;
$this
->
resolver
=
$resolver
;
$context
=
new
RequestContext
();
$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
ViewSubscriber
(
$negotiation
));
$this
->
dispatcher
->
addSubscriber
(
new
AccessSubscriber
());
$this
->
dispatcher
->
addSubscriber
(
new
PathSubscriber
());
$this
->
dispatcher
->
addSubscriber
(
new
LegacyControllerSubscriber
());
$matcher
=
$this
->
getMatcher
(
$request
);
$dispatcher
->
addSubscriber
(
new
RouterListener
(
$matcher
));
$dispatcher
->
addSubscriber
(
new
AccessSubscriber
());
$dispatcher
->
addSubscriber
(
new
PathSubscriber
());
$dispatcher
->
addSubscriber
(
new
LegacyControllerSubscriber
());
$resolver
=
new
ControllerResolver
();
$kernel
=
new
HttpKernel
(
$dispatcher
,
$resolver
);
$response
=
$kernel
->
handle
(
$request
);
}
catch
(
Exception
$e
)
{
// Some other form of error occured that wasn't handled by another kernel
// listener. That could mean that it's a method/mime-type/error
// combination that is not accounted for, or some other type of error.
// 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.
$
response
=
new
Response
(
'A fatal error occurred: '
.
$e
->
getMessage
(),
500
);
$
this
->
dispatcher
->
addSubscriber
(
new
ExceptionListener
(
array
(
new
ExceptionController
(
$this
,
$negotiation
),
'execute'
))
);
}
return
$response
;
}
/**
* Returns an EventDispatcher for the Kernel to use.
*
* The EventDispatcher is pre-wired with some event listeners/subscribers.
*
* @todo Make the listeners that get attached extensible, but without using
* hooks.
*
* @return EventDispatcher
*/
protected
function
getDispatcher
()
{
$dispatcher
=
new
EventDispatcher
();
// @todo Make this extensible rather than just hard coding some.
// @todo Add a subscriber to handle other things, too, like our Ajax
// replacement system.
$dispatcher
->
addSubscriber
(
new
HtmlSubscriber
());
$dispatcher
->
addSubscriber
(
new
JsonSubscriber
());
return
$dispatcher
;
}
/**
* Returns a UrlMatcher object for the specified request.
*
* @param Request $request
* The request object for this matcher to use.
* @return UrlMatcher
*/
protected
function
getMatcher
(
Request
$request
)
{
// Resolve a routing context(path, etc) using the routes object to a
// Set a routing context to translate.
$context
=
new
RequestContext
();
$context
->
fromRequest
(
$request
);
$matcher
=
new
UrlMatcher
(
$context
);
return
$matcher
;
}
}
core/lib/Drupal/Core/EventSubscriber/AccessSubscriber.php
View file @
d6f33f14
...
...
@@ -23,7 +23,7 @@
class
AccessSubscriber
implements
EventSubscriberInterface
{
/**
* Verif
y
s that the current user can access the requested path.
* Verif
ie
s that the current user can access the requested path.
*
* @todo This is a total hack to keep our current access system working. It
* should be replaced with something robust and injected at some point.
...
...
@@ -35,8 +35,8 @@ public function onKernelRequestAccessCheck(GetResponseEvent $event) {
$router_item
=
$event
->
getRequest
()
->
attributes
->
get
(
'drupal_menu_item'
);
if
(
!
$router_item
[
'access'
])
{
throw
new
AccessDeniedHttpException
(
$message
);
if
(
isset
(
$router_item
[
'access'
])
&&
!
$router_item
[
'access'
])
{
throw
new
AccessDeniedHttpException
();
}
}
...
...
core/lib/Drupal/Core/EventSubscriber/HtmlSubscriber.php
deleted
100644 → 0
View file @
e13dd9cb
<?php
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
;
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
;
use
Drupal\Core\DrupalKernel
;
/**
* @file
*
* Definition of Drupal\Core\EventSubscriber\HtmlSubscriber;
*/
/**
* Main subscriber for HTML-type HTTP responses.
*/
class
HtmlSubscriber
implements
EventSubscriberInterface
{
/**
* Determines if we are dealing with an HTML-style response.
*
* @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
);
}
/**
* Processes an AccessDenied exception into an HTTP 403 response.
*
* @param GetResponseEvent $event
* The Event to process.
*/
public
function
onAccessDeniedException
(
GetResponseEvent
$event
)
{
if
(
$this
->
isHtmlRequestEvent
(
$event
)
&&
$event
->
getException
()
instanceof
AccessDeniedHttpException
)
{
$event
->
setResponse
(
new
Response
(
'Access Denied'
,
403
));
}
}
/**
* Processes a NotFound exception into an HTTP 404 response.
*
* @param GetResponseEvent $event
* The Event to process.
*/
public
function
onNotFoundHttpException
(
GetResponseEvent
$event
)
{
if
(
$this
->
isHtmlRequestEvent
(
$event
)
&&
$event
->
getException
()
instanceof
NotFoundHttpException
)
{
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
=
$event
->
getRequest
()
->
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
,
DrupalKernel
::
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'
=>
$event
->
getRequest
()
->
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
);
}
$event
->
setResponse
(
$response
);
}
}
/**
* Processes a MethodNotAllowed exception into an HTTP 405 response.
*
* @param GetResponseEvent $event
* The Event to process.
*/
public
function
onMethodAllowedException
(
GetResponseEvent
$event
)
{
if
(
$this
->
isHtmlRequestEvent
(
$event
)
&&
$event
->
getException
()
instanceof
MethodNotAllowedException
)
{
$event
->
setResponse
(
new
Response
(
'Method Not Allowed'
,
405
));
}
}
/**
* 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 HTML-type response is a render array from a legacy page callback
* and render it.
*
* @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
));
}
}
/**
* Registers the methods in this class that should be listeners.
*
* @return array
* 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
::
EXCEPTION
][]
=
array
(
'onNotFoundHttpException'
,
-
5
);
$events
[
KernelEvents
::
EXCEPTION
][]
=
array
(
'onAccessDeniedException'
,
-
5
);
$events
[
KernelEvents
::
EXCEPTION
][]
=
array
(
'onMethodAllowedException'
,
-
5
);
$events
[
KernelEvents
::
VIEW
][]
=
array
(
'onView'
,
-
5
);
return
$events
;
}
}
core/lib/Drupal/Core/EventSubscriber/LegacyControllerSubscriber.php
View file @
d6f33f14
...
...
@@ -42,7 +42,7 @@ public function onKernelControllerLegacy(FilterControllerEvent $event) {
$controller
=
$event
->
getController
();
// This BC logic applies only to functions. Otherwise, skip it.
if
(
function_exists
(
$controller
))
{
if
(
is_string
(
$controller
)
&&
function_exists
(
$controller
))
{
$new_controller
=
function
()
use
(
$router_item
)
{
return
call_user_func_array
(
$router_item
[
'page_callback'
],
$router_item
[
'page_arguments'
]);
};
...
...
core/lib/Drupal/Core/EventSubscriber/
Json
Subscriber.php
→
core/lib/Drupal/Core/EventSubscriber/
View
Subscriber.php
View file @
d6f33f14
...
...
@@ -11,27 +11,23 @@
use
Symfony\Component\Routing\Exception\MethodNotAllowedException
;
use
Symfony\Component\EventDispatcher\EventSubscriberInterface
;
use
Drupal\Core\ContentNegotiation
;
/**
* @file
*
* Definition of Drupal\Core\EventSubscriber\
Html
Subscriber;
* Definition of Drupal\Core\EventSubscriber\
View
Subscriber;
*/
/**
* Main subscriber for
JSON-type
HTTP responses.
* Main subscriber for
VIEW
HTTP responses.
*/
class
Json
Subscriber
implements
EventSubscriberInterface
{
class
View
Subscriber
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
());
protected
$negotiation
;
public
function
__construct
(
ContentNegotiation
$negotiation
)
{
$this
->
negotiation
=
$negotiation
;
}
protected
function
createJsonResponse
()
{
...
...
@@ -41,46 +37,42 @@ protected function createJsonResponse() {
return
$response
;
}
/**
* Processes an AccessDenied exception into an HTTP 403 response.
*
* @param GetResponseEvent $event
* The Event to process.
*/
public
function
onAccessDeniedException
(
GetResponseEvent
$event
)
{
if
(
$this
->
isJsonRequestEvent
(
$event
)
&&
$event
->
getException
()
instanceof
AccessDeniedHttpException
)
{
$response
=
$this
->
createJsonResponse
();
$response
->
setStatusCode
(
403
,
'Access Denied'
);
$event
->
setResponse
(
$response
);
}
}
/**
* Processes a NotFound exception into an HTTP 404 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.
*/
public
function
onNotFoundHttpException
(
GetResponseEvent
$event
)
{
if
(
$this
->
isJsonRequestEvent
(
$event
)
&&
$event
->
getException
()
instanceof
NotFoundHttpException
)
{
$response
=
$this
->
createJsonResponse
();
$response
->
setStatusCode
(
404
,
'Not Found'
);
$event
->
setResponse
(
$response
);
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
));
}
}
/**
* Processes a MethodNotAllowed exception into an HTTP 405 response.
*
* @param GetResponseEvent $event
* The Event to process.
*/
public
function
onMethodAllowedException
(
GetResponseEvent
$event
)
{
if
(
$this
->
isJsonRequestEvent
(
$event
)
&&
$event
->
getException
()
instanceof
MethodNotAllowedException
)
{
$response
=
$this
->
createJsonResponse
();
$response
->
setStatusCode
(
405
,
'Method Not Allowed'
);
$event
->
setResponse
(
$response
);
}
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
;
}
/**
...
...
@@ -89,21 +81,15 @@ public function onMethodAllowedException(GetResponseEvent $event) {
* 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 objec
t.
* from an
HTML
-type response is a
render array from a legacy page callback
*
and render i
t.
*
* @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
);
}
public
function
onHtml
(
GetResponseEvent
$event
)
{
$page_callback_result
=
$event
->
getControllerResult
();
return
new
Response
(
drupal_render_page
(
$page_callback_result
));
}
/**
...
...
@@ -113,10 +99,6 @@ public function onView(GetResponseEvent $event) {
* 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
;
...
...
core/lib/Drupal/Core/ExceptionController.php
0 → 100644
View file @
d6f33f14
<?php
namespace
Drupal\Core
;
use
Symfony\Component\HttpFoundation\Request
;
use
Symfony\Component\HttpFoundation\Response
;
use
Symfony\Component\HttpKernel\HttpKernelInterface
;
use
Symfony\Component\EventDispatcher\EventDispatcher
;
use
Symfony\Component\HttpKernel\Controller\ControllerResolver
;
use
Symfony\Component\HttpKernel\Exception\FlattenException
;
use
Exception
;
/**
* Description of ExceptionController
*
*/
class
ExceptionController
{
protected
$kernel
;
protected
$negotiation
;
public
function
__construct
(
HttpKernelInterface
$kernel
,
ContentNegotiation
$negotiation
)
{
$this
->
kernel
=
$kernel
;
$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
)
{
$system_path
=
$request
->
attributes
->
get
(
'system_path'
);
$path
=
drupal_get_normal_path
(
variable_get
(
'site_403'
,
''
));
if
(
$path
&&
$path
!=
$system_path
)
{
// Keep old path for reference, and to allow forms to redirect to it.
if
(
!
isset
(
$_GET
[
'destination'
]))
{
$_GET
[
'destination'
]
=
$system_path
;
}
$subrequest
=
Request
::
create
(
'/'
.
$path
,
'get'
,
array
(
'destination'
=>
$system_path
),
$request
->
cookies
->
all
(),
array
(),
$request
->
server
->
all
());
$response
=
$this
->
kernel
->
handle
(
$subrequest
,
DrupalKernel
::
SUB_REQUEST
);
$response
->
setStatusCode
(
403
,
'Access denied'
);
}
else
{
$response
=
new
Response
(
'Access Denied'
,
403
);
// @todo Replace this block with something cleaner.
$return
=
t
(
'You are not authorized to access this page.'
);
drupal_set_title
(
t
(
'Access denied'
));
drupal_set_page_content
(
$return
);
$page
=
element_info
(
'page'
);
$content
=
drupal_render_page
(
$page
);
$response
->
setContent
(
$content
);
}
return
$response
;
}
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'
);