Issue #2106709 by tim.plunkett: Remove legacy router backwards compatibility layer.

8.0.x
Nathaniel Catchpole 2013-10-08 18:04:42 +01:00
parent dc436055f7
commit 652c334234
12 changed files with 8 additions and 493 deletions

View File

@ -255,19 +255,11 @@ services:
router.dynamic:
class: Symfony\Cmf\Component\Routing\DynamicRouter
arguments: ['@router.request_context', '@router.matcher', '@url_generator']
legacy_generator:
class: Drupal\Core\Routing\NullGenerator
legacy_url_matcher:
class: Drupal\Core\LegacyUrlMatcher
legacy_router:
class: Symfony\Cmf\Component\Routing\DynamicRouter
arguments: ['@router.request_context', '@legacy_url_matcher', '@legacy_generator']
router:
class: Symfony\Cmf\Component\Routing\ChainRouter
calls:
- [setContext, ['@router.request_context']]
- [add, ['@router.dynamic']]
- [add, ['@legacy_router']]
entity.query:
class: Drupal\Core\Entity\Query\QueryFactory
arguments: ['@entity.manager']
@ -383,10 +375,6 @@ services:
tags:
- { name: event_subscriber }
arguments: ['@content_negotiation']
legacy_access_subscriber:
class: Drupal\Core\EventSubscriber\LegacyAccessSubscriber
tags:
- { name: event_subscriber }
private_key:
class: Drupal\Core\PrivateKey
arguments: ['@state']
@ -436,10 +424,6 @@ services:
class: Drupal\Core\EventSubscriber\LegacyRequestSubscriber
tags:
- { name: event_subscriber }
legacy_controller_subscriber:
class: Drupal\Core\EventSubscriber\LegacyControllerSubscriber
tags:
- { name: event_subscriber }
finish_response_subscriber:
class: Drupal\Core\EventSubscriber\FinishResponseSubscriber
tags:

View File

@ -204,9 +204,9 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
* $commands[] = ajax_command_replace('#object-1', 'some html here');
* // Add a visual "changed" marker to the '#object-1' element.
* $commands[] = ajax_command_changed('#object-1');
* // Menu 'page callback' and #ajax['callback'] functions are supposed to
* // return render arrays. If returning an Ajax commands array, it must be
* // encapsulated in a render array structure.
* // #ajax['callback'] functions are supposed to return render arrays. If
* // returning an Ajax commands array, it must be encapsulated in a render
* // array structure.
* return array('#type' => 'ajax', '#commands' => $commands);
* @endcode
*

View File

@ -976,7 +976,7 @@ function menu_item_route_access(Route $route, $href, &$map) {
// Attempt to match this path to provide a fully built request to the
// access checker.
try {
$request->attributes->add(\Drupal::service('router.dynamic')->matchRequest($request));
$request->attributes->add(\Drupal::service('router')->matchRequest($request));
}
catch (NotFoundHttpException $e) {
return FALSE;

View File

@ -178,17 +178,8 @@ class AuthenticationManager implements AuthenticationProviderInterface, Authenti
public function handleException(GetResponseForExceptionEvent $event) {
$request = $event->getRequest();
// Legacy routes won't have a Route object; they have drupal_menu_item
// instead. Assume those were authenticated by cookie, because the legacy
// router didn't support anything else.
// @todo Remove this check once the old router is fully removed.
if ($request->attributes->has('_drupal_menu_item')) {
$active_providers = array('cookie');
}
else {
$route = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT);
$active_providers = ($route && $route->getOption('_auth')) ? $route->getOption('_auth') : array($this->defaultProviderId());
}
$route = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT);
$active_providers = ($route && $route->getOption('_auth')) ? $route->getOption('_auth') : array($this->defaultProviderId());
// Get the sorted list of active providers for the given route.
$providers = array_intersect($active_providers, array_keys($this->providers));

View File

@ -32,11 +32,5 @@ class RegisterRouteEnhancersPass implements CompilerPassInterface {
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
$router->addMethodCall('addRouteEnhancer', array(new Reference($id), $priority));
}
$legacy_router = $container->getDefinition('legacy_router');
foreach ($container->findTaggedServiceIds('legacy_route_enhancer') as $id => $attributes) {
$priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
$legacy_router->addMethodCall('addRouteEnhancer', array(new Reference($id), $priority));
}
}
}

View File

@ -1,62 +0,0 @@
<?php
/**
* @file
* Contains Drupal\Core\EventSubscriber\LegacyAccessSubscriber.
*/
namespace Drupal\Core\EventSubscriber;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Access subscriber for legacy controller requests.
*/
class LegacyAccessSubscriber implements EventSubscriberInterface {
/**
* Verifies 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.
*
* @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
* The Event to process.
*
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
*/
public function onKernelRequestAccessCheck(GetResponseEvent $event) {
$request_attributes = $event->getRequest()->attributes;
$router_item = $request_attributes->get('_drupal_menu_item');
// For legacy routes we do not allow any user not authenticated by cookie
// provider.
$provider = $request_attributes->get('_authentication_provider');
if ($request_attributes->get('_legacy') && $provider && $provider != 'cookie') {
$GLOBALS['user'] = drupal_anonymous_user();
$request_attributes->set('_account', $GLOBALS['user']);
throw new AccessDeniedHttpException();
}
if (isset($router_item['access']) && !$router_item['access']) {
throw new AccessDeniedHttpException();
}
}
/**
* Registers the methods in this class that should be listeners.
*
* @return array
* An array of event listener definitions.
*/
static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = array('onKernelRequestAccessCheck', 30);
return $events;
}
}

View File

@ -1,63 +0,0 @@
<?php
/**
* @file
* Definition of Drupal\Core\EventSubscriber\LegacyControllerSubscriber.
*/
namespace Drupal\Core\EventSubscriber;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Access subscriber for controller requests.
*/
class LegacyControllerSubscriber implements EventSubscriberInterface {
/**
* Wraps legacy controllers in a closure to handle old-style arguments.
*
* This is a backward compatibility layer only. This is a rather ugly way
* to piggyback Drupal's existing menu router items onto the Symfony model,
* but it works for now. If we did not do this, any menu router item with
* a variable number of arguments would fail to work. This bypasses Symfony's
* controller argument handling entirely and lets the old-style approach work.
*
* @todo Convert Drupal to use the IETF-draft-RFC style {placeholders}. That
* will allow us to use the native Symfony conversion, including
* out-of-order argument mapping, name-based mapping, and with another
* listener auto-conversion of parameters to full objects. That may
* necessitate not using func_get_args()-based controllers. That is likely
* for the best, as those are quite hard to document anyway.
*
* @param Symfony\Component\HttpKernel\Event\FilterControllerEvent $event
* The Event to process.
*/
public function onKernelControllerLegacy(FilterControllerEvent $event) {
$request = $event->getRequest();
// If we're dealing with a legacy route, wrap the controller in a closure
// so parameters still work.
if ($request->attributes->get('_legacy')) {
$router_item = $request->attributes->get('_drupal_menu_item');
$new_controller = function() use ($router_item) {
return call_user_func_array($router_item['page_callback'], $router_item['page_arguments']);
};
$event->setController($new_controller);
}
}
/**
* Registers the methods in this class that should be listeners.
*
* @return array
* An array of event listener definitions.
*/
static function getSubscribedEvents() {
$events[KernelEvents::CONTROLLER][] = array('onKernelControllerLegacy', 30);
return $events;
}
}

View File

@ -1,177 +0,0 @@
<?php
/**
* @file
* Definition of Drupal\Core\LegacyUrlMatcher.
*/
namespace Drupal\Core;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
use Symfony\Component\Routing\RequestContextAwareInterface;
use Symfony\Component\Routing\RequestContext;
/**
* UrlMatcher matches URL based on a set of routes.
*/
class LegacyUrlMatcher implements RequestMatcherInterface, RequestContextAwareInterface {
/**
* The request context for this matcher.
*
* @var Symfony\Component\Routing\RequestContext
*/
protected $context;
/**
* The request object for this matcher.
*
* @var Symfony\Component\HttpFoundation\Request
*/
protected $request;
/**
* Constructor.
*/
public function __construct() {
// We will not actually use this object, but it's needed to conform to
// the interface.
$this->context = new RequestContext();
}
/**
* Sets the request context.
*
* This method is just to satisfy the interface, and is largely vestigial.
* The request context object does not contain the information we need, so
* we will use the original request object.
*
* @param Symfony\Component\Routing\RequestContext $context
* The context.
*
* @api
*/
public function setContext(RequestContext $context) {
$this->context = $context;
}
/**
* Gets the request context.
*
* This method is just to satisfy the interface, and is largely vestigial.
* The request context object does not contain the information we need, so
* we will use the original request object.
*
* @return Symfony\Component\Routing\RequestContext
* The context.
*/
public function getContext() {
return $this->context;
}
/**
* Sets the request object to use.
*
* This is used by the RouterListener to make additional request attributes
* available.
*
* @param Symfony\Component\HttpFoundation\Request $request
* The request object.
*/
public function setRequest(Request $request) {
$this->request = $request;
}
/**
* Gets the request object.
*
* @return Symfony\Component\HttpFoundation\Request $request
* The request object.
*/
public function getRequest() {
return $this->request;
}
/**
* {@inheritDoc}
*
* @api
*/
public function matchRequest(Request $request) {
if ($router_item = $this->matchDrupalItem($request->attributes->get('_system_path'))) {
$ret = $this->convertDrupalItem($router_item);
// Stash the router item in the attributes while we're transitioning.
$ret['_drupal_menu_item'] = $router_item;
// Most legacy controllers (aka page callbacks) are in a separate file,
// so we have to include that.
if ($router_item['include_file']) {
require_once DRUPAL_ROOT . '/' . $router_item['include_file'];
}
// Flag this as a legacy request. We need to use this for subrequest
// handling so that we can treat older page callbacks and new routes
// differently.
// @todo Remove this line as soon as possible.
$ret['_legacy'] = TRUE;
return $ret;
}
// This matcher doesn't differentiate by method, so don't bother with those
// exceptions.
throw new ResourceNotFoundException();
}
/**
* Get a Drupal menu item.
*
* @todo Make this return multiple possible candidates for the resolver to
* consider.
*
* @param string $path
* The path being looked up by
*/
protected function matchDrupalItem($path) {
// For now we can just proxy our procedural method. At some point this will
// become more complicated because we'll need to get back candidates for a
// path and them resolve them based on things like method and scheme which
// we currently can't do.
return menu_get_item($path);
}
/**
* Converts a Drupal menu item to a route array.
*
* @param array $router_item
* The Drupal menu item.
*
* @return
* An array of parameters.
*/
protected function convertDrupalItem($router_item) {
$route = array(
'_controller' => $router_item['page_callback']
);
// A few menu items have a fake page callback temporarily. Skip those,
// we aren't going to route them.
if ($router_item['page_callback'] == 'USES_ROUTE') {
throw new ResourceNotFoundException();
}
// @todo menu_get_item() does not unserialize page arguments when the access
// is denied. Remove this temporary hack that always does that.
if (!is_array($router_item['page_arguments'])) {
$router_item['page_arguments'] = unserialize($router_item['page_arguments']);
}
// Place argument defaults on the route.
foreach ($router_item['page_arguments'] as $k => $v) {
$route[$k] = $v;
}
return $route;
}
}

View File

@ -583,10 +583,7 @@ class MenuLink extends Entity implements \ArrayAccess, MenuLinkInterface {
$request = Request::create('/' . $link_path);
$request->attributes->set('_system_path', $link_path);
try {
// Use router.dynamic instead of router, because router will call the
// legacy router which will call hook_menu() and you will get back to
// this method.
$result = \Drupal::service('router.dynamic')->matchRequest($request);
$result = \Drupal::service('router')->matchRequest($request);
$return = array();
$return[] = isset($result['_route']) ? $result['_route'] : '';
$return[] = $result['_raw_variables']->all();

View File

@ -40,7 +40,7 @@ class MenuLinkTest extends UnitTestCase {
public function testFindRouteNameParameters() {
$router = $this->getMock('Symfony\Component\Routing\Matcher\RequestMatcherInterface');
$container = new ContainerBuilder();
$container->set('router.dynamic', $router);
$container->set('router', $router);
\Drupal::setContainer($container);
$router->expects($this->at(0))

View File

@ -136,16 +136,6 @@ class PathBasedBreadcrumbBuilder extends BreadcrumbBuilderBase {
$title = $this->titleResolver->getTitle($route_request, $route_request->attributes->get(RouteObjectInterface::ROUTE_OBJECT));
}
}
// @todo - remove this once all of core is converted to the new router.
else {
$menu_item = $route_request->attributes->get('_drupal_menu_item');
// Skip the breadcrumb step for menu items linking to the parent item.
if (($menu_item['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT) {
continue;
}
$access = $menu_item['access'];
$title = $menu_item['title'];
}
if ($access) {
if (!$title) {
// Fallback to using the raw path component as the title if the

View File

@ -504,145 +504,6 @@ function hook_menu_get_item_alter(&$router_item, $path, $original_map) {
* paths and whose values are an associative array of properties for each
* path. (The complete list of properties is in the return value section below.)
*
* @section sec_callback_funcs Callback Functions
* The definition for each path may include a page callback function, which is
* invoked when the registered path is requested. If there is no other
* registered path that fits the requested path better, any further path
* components are passed to the callback function. For example, your module
* could register path 'abc/def':
* @code
* function mymodule_menu() {
* $items['abc/def'] = array(
* 'page callback' => 'mymodule_abc_view',
* );
* return $items;
* }
*
* function mymodule_abc_view($ghi = 0, $jkl = '') {
* // ...
* }
* @endcode
* When path 'abc/def' is requested, no further path components are in the
* request, and no additional arguments are passed to the callback function (so
* $ghi and $jkl would take the default values as defined in the function
* signature). When 'abc/def/123/foo' is requested, $ghi will be '123' and
* $jkl will be 'foo'. Note that this automatic passing of optional path
* arguments applies only to page and theme callback functions.
*
* @subsection sub_callback_arguments Callback Arguments
* In addition to optional path arguments, the page callback and other callback
* functions may specify argument lists as arrays. These argument lists may
* contain both fixed/hard-coded argument values and integers that correspond
* to path components. When integers are used and the callback function is
* called, the corresponding path components will be substituted for the
* integers. That is, the integer 0 in an argument list will be replaced with
* the first path component, integer 1 with the second, and so on (path
* components are numbered starting from zero). To pass an integer without it
* being replaced with its respective path component, use the string value of
* the integer (e.g., '1') as the argument value. This substitution feature
* allows you to re-use a callback function for several different paths. For
* example:
* @code
* function mymodule_menu() {
* $items['abc/def'] = array(
* 'page callback' => 'mymodule_abc_view',
* 'page arguments' => array(1, 'foo'),
* );
* return $items;
* }
* @endcode
* When path 'abc/def' is requested, the page callback function will get 'def'
* as the first argument and (always) 'foo' as the second argument.
*
* If a page callback function uses an argument list array, and its path is
* requested with optional path arguments, then the list array's arguments are
* passed to the callback function first, followed by the optional path
* arguments. Using the above example, when path 'abc/def/bar/baz' is requested,
* mymodule_abc_view() will be called with 'def', 'foo', 'bar' and 'baz' as
* arguments, in that order.
*
* Special care should be taken for the page callback drupal_get_form(), because
* your specific form callback function will always receive $form and
* &$form_state as the first function arguments:
* @code
* function mymodule_abc_form($form, &$form_state) {
* // ...
* return $form;
* }
* @endcode
* See @link form_api Form API documentation @endlink for details.
*
* @section sec_path_wildcards Wildcards in Paths
* @subsection sub_simple_wildcards Simple Wildcards
* Wildcards within paths also work with integer substitution. For example,
* your module could register path 'my-module/%/edit':
* @code
* $items['my-module/%/edit'] = array(
* 'page callback' => 'mymodule_abc_edit',
* 'page arguments' => array(1),
* );
* @endcode
* When path 'my-module/foo/edit' is requested, integer 1 will be replaced
* with 'foo' and passed to the callback function. Note that wildcards may not
* be used as the first component.
*
* @subsection sub_autoload_wildcards Auto-Loader Wildcards
* Registered paths may also contain special "auto-loader" wildcard components
* in the form of '%mymodule_abc', where the '%' part means that this path
* component is a wildcard, and the 'mymodule_abc' part defines the prefix for a
* load function, which here would be named mymodule_abc_load(). When a matching
* path is requested, your load function will receive as its first argument the
* path component in the position of the wildcard; load functions may also be
* passed additional arguments (see "load arguments" in the return value
* section below). For example, your module could register path
* 'my-module/%mymodule_abc/edit':
* @code
* $items['my-module/%mymodule_abc/edit'] = array(
* 'page callback' => 'mymodule_abc_edit',
* 'page arguments' => array(1),
* );
* @endcode
* When path 'my-module/123/edit' is requested, your load function
* mymodule_abc_load() will be invoked with the argument '123', and should
* load and return an "abc" object with internal id 123:
* @code
* function mymodule_abc_load($abc_id) {
* return db_query("SELECT * FROM {mymodule_abc} WHERE abc_id = :abc_id", array(':abc_id' => $abc_id))->fetchObject();
* }
* @endcode
* This 'abc' object will then be passed into the callback functions defined
* for the menu item, such as the page callback function mymodule_abc_edit()
* to replace the integer 1 in the argument array. Note that a load function
* should return NULL when it is unable to provide a loadable object. For
* example, the node_load() function for the 'node/%node/edit' menu item will
* return NULL for the path 'node/999/edit' if a node with a node ID of 999
* does not exist. The menu routing system will return a 404 error in this case.
*
* @subsection sub_argument_wildcards Argument Wildcards
* You can also define a %wildcard_to_arg() function (for the example menu
* entry above this would be 'mymodule_abc_to_arg()'). The _to_arg() function
* is invoked to retrieve a value that is used in the path in place of the
* wildcard. A good example is user.module, which defines
* user_uid_optional_to_arg() (corresponding to the menu entry
* 'tracker/%user_uid_optional'). This function returns the user ID of the
* current user.
*
* The _to_arg() function will get called with three arguments:
* - $arg: A string representing whatever argument may have been supplied by
* the caller (this is particularly useful if you want the _to_arg()
* function only supply a (default) value if no other value is specified,
* as in the case of user_uid_optional_to_arg().
* - $map: An array of all path fragments (e.g. array('node','123','edit') for
* 'node/123/edit').
* - $index: An integer indicating which element of $map corresponds to $arg.
*
* _load() and _to_arg() functions may seem similar at first glance, but they
* have different purposes and are called at different times. _load()
* functions are called when the menu system is collecting arguments to pass
* to the callback functions defined for the menu item. _to_arg() functions
* are called when the menu system is generating links to related paths, such
* as the tabs for a set of MENU_LOCAL_TASK items.
*
* @section sec_render_tabs Rendering Menu Items As Tabs
* You can also make groups of menu items to be rendered (by default) as tabs
* on a page. To do that, first create one menu item of type MENU_NORMAL_ITEM,