Commit 2c2c1adc authored by catch's avatar catch

Issue #1316692 by tim.plunkett, dawehner: Convert hook_admin_paths() into...

Issue #1316692 by tim.plunkett, dawehner: Convert hook_admin_paths() into declarative properties on routes.
parent 8cbab149
...@@ -276,6 +276,10 @@ services: ...@@ -276,6 +276,10 @@ services:
class: Symfony\Component\Routing\RequestContext class: Symfony\Component\Routing\RequestContext
calls: calls:
- [fromRequest, ['@request']] - [fromRequest, ['@request']]
router.admin_context:
class: Drupal\Core\Routing\AdminContext
calls:
- [setRequest, ['@?request=']]
router.route_provider: router.route_provider:
class: Drupal\Core\Routing\RouteProvider class: Drupal\Core\Routing\RouteProvider
arguments: ['@database', '@router.builder'] arguments: ['@database', '@router.builder']
......
...@@ -2127,8 +2127,8 @@ function _drupal_add_js($data = NULL, $options = NULL) { ...@@ -2127,8 +2127,8 @@ function _drupal_add_js($data = NULL, $options = NULL) {
$current_path = current_path(); $current_path = current_path();
$current_path_is_admin = FALSE; $current_path_is_admin = FALSE;
// The function path_is_admin() is not available on update.php pages. // The function path_is_admin() is not available on update.php pages.
if (!(defined('MAINTENANCE_MODE') && MAINTENANCE_MODE === 'update')) { if (!(defined('MAINTENANCE_MODE'))) {
$current_path_is_admin = path_is_admin($current_path); $current_path_is_admin = \Drupal::service('router.admin_context')->isAdminRoute();
} }
$path = array( $path = array(
'basePath' => base_path(), 'basePath' => base_path(),
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
use Drupal\Component\Utility\UrlHelper; use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\ParamConverter\ParamNotConvertedException; use Drupal\Core\ParamConverter\ParamNotConvertedException;
use Drupal\Core\Routing\RequestHelper; use Drupal\Core\Routing\RequestHelper;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
/** /**
* Check if the current page is the front page. * Check if the current page is the front page.
...@@ -131,54 +132,18 @@ function path_load($conditions) { ...@@ -131,54 +132,18 @@ function path_load($conditions) {
* @return * @return
* TRUE if the path is administrative, FALSE otherwise. * TRUE if the path is administrative, FALSE otherwise.
* *
* @see path_get_admin_paths() * @deprecated Use \Drupal::service('router.admin_context')->isAdminRoute()
* @see hook_admin_paths() * service instead.
* @see hook_admin_paths_alter()
*/ */
function path_is_admin($path) { function path_is_admin($path) {
$path_map = &drupal_static(__FUNCTION__); try {
if (!isset($path_map['admin'][$path])) { $parameters = \Drupal::service('router')->match('/' . $path);
$patterns = path_get_admin_paths(); $route = $parameters[RouteObjectInterface::ROUTE_OBJECT];
$path_map['admin'][$path] = drupal_match_path($path, $patterns['admin']); return \Drupal::service('router.admin_context')->isAdminRoute($route);
$path_map['non_admin'][$path] = drupal_match_path($path, $patterns['non_admin']);
} }
return $path_map['admin'][$path] && !$path_map['non_admin'][$path]; catch (ParamNotConvertedException $e) {
} return FALSE;
/**
* Gets a list of administrative and non-administrative paths.
*
* @return array
* An associative array containing the following keys:
* 'admin': An array of administrative paths and regular expressions
* in a format suitable for drupal_match_path().
* 'non_admin': An array of non-administrative paths and regular expressions.
*
* @see hook_admin_paths()
* @see hook_admin_paths_alter()
*/
function path_get_admin_paths() {
$patterns = &drupal_static(__FUNCTION__);
if (!isset($patterns)) {
$paths = \Drupal::moduleHandler()->invokeAll('admin_paths');
\Drupal::moduleHandler()->alter('admin_paths', $paths);
// Combine all admin paths into one array, and likewise for non-admin paths,
// for easier handling.
$patterns = array();
$patterns['admin'] = array();
$patterns['non_admin'] = array();
foreach ($paths as $path => $enabled) {
if ($enabled) {
$patterns['admin'][] = $path;
}
else {
$patterns['non_admin'][] = $path;
}
}
$patterns['admin'] = implode("\n", $patterns['admin']);
$patterns['non_admin'] = implode("\n", $patterns['non_admin']);
} }
return $patterns;
} }
/** /**
......
<?php
/**
* @file
* Contains \Drupal\Core\Routing\AdminContext.
*/
namespace Drupal\Core\Routing;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
/**
* Provides a helper class to determine whether the route is an admin one.
*/
class AdminContext {
/**
* The route object.
*
* @var \Symfony\Component\Routing\Route
*/
protected $route;
/**
* Sets the request object to use.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object.
*/
public function setRequest(Request $request) {
$this->route = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT);
}
/**
* Determines whether the active route is an admin one.
*
* @param \Symfony\Component\Routing\Route $route
* (optional) The route to determine whether it is an admin one. Per default
* this falls back to the route object on the active request.
*
* @return bool
* Returns TRUE if the route is an admin one, otherwise FALSE.
*/
public function isAdminRoute(Route $route = NULL) {
if (!$route) {
$route = $this->route;
if (!$route) {
return FALSE;
}
}
return (bool) $route->getOption('_admin_route');
}
}
...@@ -25,8 +25,7 @@ abstract class RouteSubscriberBase implements EventSubscriberInterface { ...@@ -25,8 +25,7 @@ abstract class RouteSubscriberBase implements EventSubscriberInterface {
* The provider these routes belong to. For dynamically added routes, the * The provider these routes belong to. For dynamically added routes, the
* provider name will be 'dynamic_routes'. * provider name will be 'dynamic_routes'.
*/ */
protected function alterRoutes(RouteCollection $collection, $provider) { abstract protected function alterRoutes(RouteCollection $collection, $provider);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
......
...@@ -496,18 +496,6 @@ function block_menu_delete($menu) { ...@@ -496,18 +496,6 @@ function block_menu_delete($menu) {
} }
} }
/**
* Implements hook_admin_paths().
*/
function block_admin_paths() {
$paths = array(
// Exclude the block demonstration page from admin treatment.
// This allows us to present this page in its true form, full page.
'admin/structure/block/demo/*' => FALSE,
);
return $paths;
}
/** /**
* Implements hook_language_delete(). * Implements hook_language_delete().
* *
......
...@@ -5,6 +5,8 @@ block.admin_demo: ...@@ -5,6 +5,8 @@ block.admin_demo:
requirements: requirements:
_access_theme: 'TRUE' _access_theme: 'TRUE'
_permission: 'administer blocks' _permission: 'administer blocks'
options:
_admin_route: FALSE
block.admin_block_delete: block.admin_block_delete:
path: '/admin/structure/block/manage/{block}/delete' path: '/admin/structure/block/manage/{block}/delete'
......
...@@ -170,17 +170,3 @@ function custom_block_add_body_field($block_type_id, $label = 'Block body') { ...@@ -170,17 +170,3 @@ function custom_block_add_body_field($block_type_id, $label = 'Block body') {
return $instance; return $instance;
} }
/**
* Implements hook_admin_paths().
*/
function custom_block_admin_paths() {
$paths = array(
'block/add' => TRUE,
'block/add/*' => TRUE,
'block/*' => TRUE,
'block/*/delete' => TRUE,
'admin/structure/block/custom-blocks/*' => TRUE,
);
return $paths;
}
...@@ -10,6 +10,8 @@ custom_block.add_page: ...@@ -10,6 +10,8 @@ custom_block.add_page:
defaults: defaults:
_content: 'Drupal\custom_block\Controller\CustomBlockController::add' _content: 'Drupal\custom_block\Controller\CustomBlockController::add'
_title: 'Add custom block' _title: 'Add custom block'
options:
_admin_route: TRUE
requirements: requirements:
_permission: 'administer blocks' _permission: 'administer blocks'
...@@ -18,6 +20,8 @@ custom_block.add_form: ...@@ -18,6 +20,8 @@ custom_block.add_form:
defaults: defaults:
_content: 'Drupal\custom_block\Controller\CustomBlockController::addForm' _content: 'Drupal\custom_block\Controller\CustomBlockController::addForm'
_title_callback: 'Drupal\custom_block\Controller\CustomBlockController::getAddFormTitle' _title_callback: 'Drupal\custom_block\Controller\CustomBlockController::getAddFormTitle'
options:
_admin_route: TRUE
requirements: requirements:
_permission: 'administer blocks' _permission: 'administer blocks'
...@@ -28,11 +32,15 @@ custom_block.type_delete: ...@@ -28,11 +32,15 @@ custom_block.type_delete:
_title: 'Delete' _title: 'Delete'
requirements: requirements:
_entity_access: 'custom_block_type.delete' _entity_access: 'custom_block_type.delete'
options:
_admin_route: TRUE
custom_block.edit: custom_block.edit:
path: '/block/{custom_block}' path: '/block/{custom_block}'
defaults: defaults:
_entity_form: 'custom_block.edit' _entity_form: 'custom_block.edit'
options:
_admin_route: TRUE
requirements: requirements:
_entity_access: 'custom_block.update' _entity_access: 'custom_block.update'
...@@ -40,6 +48,8 @@ custom_block.delete: ...@@ -40,6 +48,8 @@ custom_block.delete:
path: '/block/{custom_block}/delete' path: '/block/{custom_block}/delete'
defaults: defaults:
_entity_form: 'custom_block.delete' _entity_form: 'custom_block.delete'
options:
_admin_route: TRUE
requirements: requirements:
_entity_access: 'custom_block.delete' _entity_access: 'custom_block.delete'
......
...@@ -167,19 +167,6 @@ function book_menu_link_defaults() { ...@@ -167,19 +167,6 @@ function book_menu_link_defaults() {
return $links; return $links;
} }
/**
* Implements hook_admin_paths().
*/
function book_admin_paths() {
if (\Drupal::config('node.settings')->get('use_admin_theme')) {
$paths = array(
'node/*/outline' => TRUE,
'node/*/outline/remove' => TRUE,
);
return $paths;
}
}
/** /**
* Returns an array of all books. * Returns an array of all books.
* *
......
...@@ -38,6 +38,8 @@ book.outline: ...@@ -38,6 +38,8 @@ book.outline:
requirements: requirements:
_permission: 'administer book outlines' _permission: 'administer book outlines'
_entity_access: 'node.view' _entity_access: 'node.view'
options:
_node_operation_route: TRUE
book.admin_edit: book.admin_edit:
path: '/admin/structure/book/{node}' path: '/admin/structure/book/{node}'
...@@ -56,6 +58,7 @@ book.remove: ...@@ -56,6 +58,7 @@ book.remove:
_title: 'Remove from outline' _title: 'Remove from outline'
options: options:
_access_mode: 'ALL' _access_mode: 'ALL'
_node_operation_route: TRUE
requirements: requirements:
_permission: 'administer book outlines' _permission: 'administer book outlines'
_entity_access: 'node.view' _entity_access: 'node.view'
......
...@@ -37,8 +37,7 @@ function edit_page_build(&$page) { ...@@ -37,8 +37,7 @@ function edit_page_build(&$page) {
} }
// In-place editing is only supported on the front-end. // In-place editing is only supported on the front-end.
$path = \Drupal::request()->attributes->get('_system_path'); if (\Drupal::service('router.admin_context')->isAdminRoute()) {
if (path_is_admin($path)) {
return; return;
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
namespace Drupal\locale\ParamConverter; namespace Drupal\locale\ParamConverter;
use Drupal\Core\Routing\AdminContext;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\ConfigFactoryInterface;
...@@ -37,15 +38,29 @@ class LocaleAdminPathConfigEntityConverter extends EntityConverter { ...@@ -37,15 +38,29 @@ class LocaleAdminPathConfigEntityConverter extends EntityConverter {
*/ */
protected $configFactory; protected $configFactory;
/**
* The route admin context to determine whether a route is an admin one.
*
* @var \Drupal\Core\Routing\AdminContext
*/
protected $adminContext;
/** /**
* Constructs a new EntityConverter. * Constructs a new EntityConverter.
* *
* @param \Drupal\Core\Entity\EntityManagerInterface $entityManager * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager. * The entity manager.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Drupal\Core\Routing\AdminContext $admin_context
* The route admin context service.
*
*/ */
public function __construct(EntityManagerInterface $entity_manager, ConfigFactoryInterface $config_factory) { public function __construct(EntityManagerInterface $entity_manager, ConfigFactoryInterface $config_factory, AdminContext $admin_context) {
$this->configFactory = $config_factory;
parent::__construct($entity_manager); parent::__construct($entity_manager);
$this->configFactory = $config_factory;
$this->adminContext = $admin_context;
} }
/** /**
...@@ -73,9 +88,7 @@ public function applies($definition, $name, Route $route) { ...@@ -73,9 +88,7 @@ public function applies($definition, $name, Route $route) {
$entity_type_id = substr($definition['type'], strlen('entity:')); $entity_type_id = substr($definition['type'], strlen('entity:'));
$entity_type = $this->entityManager->getDefinition($entity_type_id); $entity_type = $this->entityManager->getDefinition($entity_type_id);
if ($entity_type->isSubclassOf('\Drupal\Core\Config\Entity\ConfigEntityInterface')) { if ($entity_type->isSubclassOf('\Drupal\Core\Config\Entity\ConfigEntityInterface')) {
// path_is_admin() needs the path without the leading slash. return $this->adminContext->isAdminRoute($route);
$path = ltrim($route->getPath(), '/');
return path_is_admin($path);
} }
} }
return FALSE; return FALSE;
......
...@@ -3,7 +3,7 @@ services: ...@@ -3,7 +3,7 @@ services:
class: Drupal\locale\ParamConverter\LocaleAdminPathConfigEntityConverter class: Drupal\locale\ParamConverter\LocaleAdminPathConfigEntityConverter
tags: tags:
- { name: paramconverter, priority: 5 } - { name: paramconverter, priority: 5 }
arguments: ['@entity.manager', '@config.factory'] arguments: ['@entity.manager', '@config.factory', '@router.admin_context']
locale.config.typed: locale.config.typed:
class: Drupal\locale\LocaleConfigManager class: Drupal\locale\LocaleConfigManager
arguments: ['@config.storage', '@config.storage.schema', '@config.storage.installer', '@locale.storage', '@cache.config', '@config.factory'] arguments: ['@config.storage', '@config.storage.schema', '@config.storage.installer', '@locale.storage', '@cache.config', '@config.factory']
......
<?php
/**
* @file
* Contains \Drupal\node\EventSubscriber\NodeAdminRouteSubscriber.
*/
namespace Drupal\node\EventSubscriber;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;
/**
* Sets the _admin_route for specific node-related routes.
*/
class NodeAdminRouteSubscriber extends RouteSubscriberBase {
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* Constructs a new NodeAdminRouteSubscriber.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
*/
public function __construct(ConfigFactoryInterface $config_factory) {
$this->configFactory = $config_factory;
}
/**
* {@inheritdoc}
*/
protected function alterRoutes(RouteCollection $collection, $provider) {
if ($this->configFactory->get('node.settings')->get('use_admin_theme')) {
foreach ($collection->all() as $route) {
if ($route->hasOption('_node_operation_route')) {
$route->setOption('_admin_route', TRUE);
}
}
}
}
}
...@@ -236,26 +236,6 @@ function node_uri(NodeInterface $node) { ...@@ -236,26 +236,6 @@ function node_uri(NodeInterface $node) {
); );
} }
/**
* Implements hook_admin_paths().
*/
function node_admin_paths() {
if (\Drupal::config('node.settings')->get('use_admin_theme')) {
$paths = array(
'node/*/edit' => TRUE,
'node/*/delete' => TRUE,
'node/*/revisions' => TRUE,
'node/*/revisions/*/revert' => TRUE,
'node/*/revisions/*/delete' => TRUE,
'node/*/translations' => TRUE,
'node/*/translations/*' => TRUE,
'node/add' => TRUE,
'node/add/*' => TRUE,
);
return $paths;
}
}
/** /**
* Gathers a listing of links to nodes. * Gathers a listing of links to nodes.
* *
...@@ -1318,6 +1298,7 @@ function node_form_system_themes_admin_form_submit($form, &$form_state) { ...@@ -1318,6 +1298,7 @@ function node_form_system_themes_admin_form_submit($form, &$form_state) {
\Drupal::config('node.settings') \Drupal::config('node.settings')
->set('use_admin_theme', $form_state['values']['use_admin_theme']) ->set('use_admin_theme', $form_state['values']['use_admin_theme'])
->save(); ->save();
\Drupal::service('router.builder')->setRebuildNeeded();
} }
/** /**
......
...@@ -19,6 +19,8 @@ node.page_edit: ...@@ -19,6 +19,8 @@ node.page_edit:
_entity_form: 'node.edit' _entity_form: 'node.edit'
requirements: requirements:
_entity_access: 'node.update' _entity_access: 'node.update'
options:
_node_operation_route: TRUE
node.add_page: node.add_page:
path: '/node/add' path: '/node/add'
...@@ -27,6 +29,7 @@ node.add_page: ...@@ -27,6 +29,7 @@ node.add_page:
_content: '\Drupal\node\Controller\NodeController::addPage' _content: '\Drupal\node\Controller\NodeController::addPage'
options: options:
_access_mode: 'ANY' _access_mode: 'ANY'
_node_operation_route: TRUE
requirements: requirements:
_permission: 'administer content types' _permission: 'administer content types'
_node_add_access: 'node' _node_add_access: 'node'
...@@ -38,6 +41,8 @@ node.add: ...@@ -38,6 +41,8 @@ node.add:
_title_callback: '\Drupal\node\Controller\NodeController::addPageTitle' _title_callback: '\Drupal\node\Controller\NodeController::addPageTitle'
requirements: requirements:
_node_add_access: 'node:{node_type}' _node_add_access: 'node:{node_type}'
options:
_node_operation_route: TRUE
node.view: node.view:
path: '/node/{node}' path: '/node/{node}'
...@@ -53,6 +58,8 @@ node.delete_confirm: ...@@ -53,6 +58,8 @@ node.delete_confirm:
_entity_form: 'node.delete' _entity_form: 'node.delete'
requirements: requirements:
_entity_access: 'node.delete' _entity_access: 'node.delete'
options:
_node_operation_route: TRUE
node.revision_overview: node.revision_overview:
path: '/node/{node}/revisions' path: '/node/{node}/revisions'
...@@ -61,6 +68,8 @@ node.revision_overview: ...@@ -61,6 +68,8 @@ node.revision_overview:
_content: '\Drupal\node\Controller\NodeController::revisionOverview' _content: '\Drupal\node\Controller\NodeController::revisionOverview'
requirements: requirements:
_access_node_revision: 'view' _access_node_revision: 'view'
options:
_node_operation_route: TRUE