diff --git a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php index a4b3e9e..92c4a41 100644 --- a/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php +++ b/core/modules/menu/lib/Drupal/menu/Tests/MenuTest.php @@ -17,7 +17,7 @@ class MenuTest extends MenuWebTestBase { * * @var array */ - public static $modules = array('block', 'test_page_test', 'contextual', 'path'); + public static $modules = array('block', 'test_page_test', 'contextual', 'path', 'help'); protected $big_user; protected $std_user; diff --git a/core/modules/system/lib/Drupal/system/Controller/SystemController.php b/core/modules/system/lib/Drupal/system/Controller/SystemController.php index 7054e95..12458d8 100644 --- a/core/modules/system/lib/Drupal/system/Controller/SystemController.php +++ b/core/modules/system/lib/Drupal/system/Controller/SystemController.php @@ -8,20 +8,39 @@ namespace Drupal\system\Controller; use Drupal\Core\Controller\ControllerInterface; +use Drupal\system\SystemManager; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; - /** * Returns responses for System routes. */ class SystemController implements ControllerInterface { /** + * The system manager. + * + * @var \Drupal\system\SystemManager + */ + protected $systemManager; + + /** + * Constructs a new SystemController. + * + * @param \Drupal\system\SystemManager $system_manager + * The system manager. + */ + public function __construct(SystemManager $system_manager) { + $this->systemManager = $system_manager; + } + + /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { - return new static(); + return new static( + $container->get('system.manager') + ); } /** @@ -37,4 +56,11 @@ function compactPage($mode) { return new RedirectResponse(url('', array('absolute' => TRUE))); } + /** + * Provides a single block from the administration menu as a page. + */ + public function systemAdminMenuBlockPage() { + return $this->systemManager->getBlockContents(); + } + } diff --git a/core/modules/system/lib/Drupal/system/SystemManager.php b/core/modules/system/lib/Drupal/system/SystemManager.php index 2712169..619642e 100644 --- a/core/modules/system/lib/Drupal/system/SystemManager.php +++ b/core/modules/system/lib/Drupal/system/SystemManager.php @@ -6,6 +6,8 @@ namespace Drupal\system; +use Drupal\Component\Utility\Unicode; +use Drupal\Core\Entity\EntityManager; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\Core\Database\Connection; use Drupal\Core\Extension\ModuleHandlerInterface; @@ -30,6 +32,20 @@ class SystemManager { protected $database; /** + * The menu link storage. + * + * @var \Drupal\menu_link\MenuLinkStorageControllerInterface + */ + protected $menuLinkStorage; + + /** + * A static cache of menu items. + * + * @var array + */ + protected $menuItems; + + /** * Requirement severity -- Requirement successfully met. */ const REQUIREMENT_OK = 0; @@ -46,10 +62,18 @@ class SystemManager { /** * Constructs a SystemManager object. + * + * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler + * The module handler. + * @param \Drupal\Core\Database\Connection $database + * The database connection. + * @param \Drupal\Core\Entity\EntityManager $entity_manager + * The entity manager. */ - public function __construct(ModuleHandlerInterface $module_handler, Connection $database) { + public function __construct(ModuleHandlerInterface $module_handler, Connection $database, EntityManager $entity_manager) { $this->moduleHandler = $module_handler; $this->database = $database; + $this->menuLinkStorage = $entity_manager->getStorageController('menu_link'); } /** @@ -124,4 +148,83 @@ public function getMaxSeverity(&$requirements) { return $severity; } + /** + * Loads the contents of a menu block. + * + * This function is often a destination for these blocks. + * For example, 'admin/structure/types' needs to have a destination to be + * valid in the Drupal menu system, but too much information there might be + * hidden, so we supply the contents of the block. + * + * @return array + * A render array suitable for drupal_render. + */ + public function getBlockContents() { + $item = menu_get_item(); + if ($content = $this->getAdminBlock($item)) { + $output = array( + '#theme' => 'admin_block_content', + '#content' => $content, + ); + } + else { + $output = array( + '#type' => 'markup', + '#markup' => t('You do not have any administrative items.'), + ); + } + return $output; + } + + /** + * Provide a single block on the administration overview page. + * + * @param \Drupal\menu_link\MenuLinkInterface|array $item + * The menu item to be displayed. + * + * @return array + * An array of menu items, as expected by theme_admin_block_content(). + */ + public function getAdminBlock($item) { + // If we are calling this function for a menu item that corresponds to a + // local task (for example, admin/tasks), then we want to retrieve the + // parent item's child links, not this item's (since this item won't have + // any). + if ($item['tab_root'] != $item['path']) { + $item = menu_get_item($item['tab_root_href']); + } + + if (!isset($item['mlid'])) { + $menu_links = $this->menuLinkStorage->loadByProperties(array('router_path' => $item['path'], 'module' => 'system')); + $menu_link = reset($menu_links); + $item['mlid'] = $menu_link->id(); + $item['menu_name'] = $menu_link->menu_name; + } + + if (isset($this->menuItems[$item['mlid']])) { + return $this->menuItems[$item['mlid']]; + } + + $content = array(); + $menu_links = $this->menuLinkStorage->loadByProperties(array('plid' => $item['mlid'], 'menu_name' => $item['menu_name'], 'hidden' => 0)); + foreach ($menu_links as $link) { + _menu_link_translate($link); + if ($link['access']) { + // The link description, either derived from 'description' in + // hook_menu() or customized via menu module is used as title attribute. + if (!empty($link['localized_options']['attributes']['title'])) { + $link['description'] = $link['localized_options']['attributes']['title']; + unset($link['localized_options']['attributes']['title']); + } + // Prepare for sorting as in function _menu_tree_check_access(). + // The weight is offset so it is always positive, with a uniform 5-digits. + $key = (50000 + $link['weight']) . ' ' . Unicode::strtolower($link['title']) . ' ' . $link['mlid']; + $content[$key] = $link; + } + } + ksort($content); + $this->menuItems[$item['mlid']] = $content; + return $content; + } + } diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index 050cdd7..ec1f96c 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -16,7 +16,8 @@ function system_admin_config_page() { // Check for status report errors. // @todo Use depedancy injection in http://drupal.org/node/1987810. - if (Drupal::service('system.manager')->checkRequirements() && user_access('administer site configuration')) { + $system_manager = Drupal::service('system.manager'); + if ($system_manager->checkRequirements() && user_access('administer site configuration')) { drupal_set_message(t('One or more problems were detected with your Drupal installation. Check the status report for more information.', array('@status' => url('admin/reports/status'))), 'error'); } $blocks = array(); @@ -44,7 +45,7 @@ function system_admin_config_page() { } $block = $item; $block['content'] = ''; - $block['content'] .= theme('admin_block_content', array('content' => system_admin_menu_block($item))); + $block['content'] .= theme('admin_block_content', array('content' => $system_manager->getAdminBlock($item))); if (!empty($block['content'])) { $block['show'] = TRUE; } @@ -65,28 +66,6 @@ function system_admin_config_page() { } /** - * Provide a single block from the administration menu as a page. - * - * This function is often a destination for these blocks. - * For example, 'admin/structure/types' needs to have a destination to be valid - * in the Drupal menu system, but too much information there might be - * hidden, so we supply the contents of the block. - * - * @return - * The output HTML. - */ -function system_admin_menu_block_page() { - $item = menu_get_item(); - if ($content = system_admin_menu_block($item)) { - $output = theme('admin_block_content', array('content' => $content)); - } - else { - $output = t('You do not have any administrative items.'); - } - return $output; -} - -/** * Menu callback; displays a listing of all themes. */ function system_themes_page() { diff --git a/core/modules/system/system.module b/core/modules/system/system.module index bd58f93..674ee26 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -621,11 +621,9 @@ function system_menu() { ); $items['admin'] = array( 'title' => 'Administration', - 'access arguments' => array('access administration pages'), - 'page callback' => 'system_admin_menu_block_page', + 'route_name' => 'system_admin', 'weight' => 9, 'menu_name' => 'admin', - 'file' => 'system.admin.inc', ); $items['admin/tasks'] = array( 'title' => 'Tasks', @@ -645,9 +643,7 @@ function system_menu() { 'description' => 'Administer blocks, content types, menus, etc.', 'position' => 'right', 'weight' => -8, - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access administration pages'), - 'file' => 'system.admin.inc', + 'route_name' => 'system_admin_structure', ); // Appearance. $items['admin/appearance'] = array( @@ -738,9 +734,7 @@ function system_menu() { 'description' => 'Media tools.', 'position' => 'left', 'weight' => -10, - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access administration pages'), - 'file' => 'system.admin.inc', + 'route_name' => 'system_admin_config_media', ); $items['admin/config/media/file-system'] = array( 'title' => 'File system', @@ -761,9 +755,7 @@ function system_menu() { 'description' => 'Tools related to web services.', 'position' => 'right', 'weight' => 0, - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access administration pages'), - 'file' => 'system.admin.inc', + 'route_name' => 'system_admin_config_services', ); $items['admin/config/services/rss-publishing'] = array( 'title' => 'RSS publishing', @@ -777,9 +769,7 @@ function system_menu() { 'description' => 'Development tools.', 'position' => 'right', 'weight' => -10, - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access administration pages'), - 'file' => 'system.admin.inc', + 'route_name' => 'system_admin_config_development', ); $items['admin/config/development/maintenance'] = array( 'title' => 'Maintenance mode', @@ -806,9 +796,7 @@ function system_menu() { 'description' => 'Regional settings, localization and translation.', 'position' => 'left', 'weight' => -5, - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access administration pages'), - 'file' => 'system.admin.inc', + 'route_name' => 'system_admin_config_regional', ); $items['admin/config/regional/settings'] = array( 'title' => 'Regional settings', @@ -846,9 +834,7 @@ function system_menu() { 'description' => 'Local site search, metadata and SEO.', 'position' => 'left', 'weight' => -10, - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access administration pages'), - 'file' => 'system.admin.inc', + 'route_name' => 'system_admin_config_search', ); // System settings. @@ -857,9 +843,7 @@ function system_menu() { 'description' => 'General system related configuration.', 'position' => 'right', 'weight' => -20, - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access administration pages'), - 'file' => 'system.admin.inc', + 'route_name' => 'system_admin_config_system', ); $items['admin/config/system/site-information'] = array( 'title' => 'Site information', @@ -878,9 +862,7 @@ function system_menu() { 'title' => 'User interface', 'description' => 'Tools that enhance the user interface.', 'position' => 'right', - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access administration pages'), - 'file' => 'system.admin.inc', + 'route_name' => 'system_admin_config_ui', 'weight' => -15, ); $items['admin/config/workflow'] = array( @@ -888,29 +870,23 @@ function system_menu() { 'description' => 'Content workflow, editorial workflow tools.', 'position' => 'right', 'weight' => 5, - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access administration pages'), - 'file' => 'system.admin.inc', + 'route_name' => 'system_admin_config_workflow', ); $items['admin/config/content'] = array( 'title' => 'Content authoring', 'description' => 'Settings related to formatting and authoring content.', 'position' => 'left', 'weight' => -15, - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access administration pages'), - 'file' => 'system.admin.inc', + 'route_name' => 'system_admin_config_content', ); // Reports. $items['admin/reports'] = array( 'title' => 'Reports', 'description' => 'View reports, updates, and errors.', - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access site reports'), + 'route_name' => 'system_admin_reports', 'weight' => 5, 'position' => 'left', - 'file' => 'system.admin.inc', ); $items['admin/reports/status'] = array( 'title' => 'Status report', @@ -2330,48 +2306,11 @@ function system_preprocess_block(&$variables) { * * @param $item * The menu item to be displayed. + * + * @deprecated Use \Drupal\system\SystemManager::getAdminBlock(). */ function system_admin_menu_block($item) { - $cache = &drupal_static(__FUNCTION__, array()); - // If we are calling this function for a menu item that corresponds to a - // local task (for example, admin/tasks), then we want to retrieve the - // parent item's child links, not this item's (since this item won't have - // any). - if ($item['tab_root'] != $item['path']) { - $item = menu_get_item($item['tab_root_href']); - } - - if (!isset($item['mlid'])) { - $menu_links = entity_load_multiple_by_properties('menu_link', array('router_path' => $item['path'], 'module' => 'system')); - $menu_link = reset($menu_links); - $item['mlid'] = $menu_link->id(); - $item['menu_name'] = $menu_link->menu_name; - } - - if (isset($cache[$item['mlid']])) { - return $cache[$item['mlid']]; - } - - $content = array(); - $menu_links = entity_load_multiple_by_properties('menu_link', array('plid' => $item['mlid'], 'menu_name' => $item['menu_name'], 'hidden' => 0)); - foreach ($menu_links as $link) { - _menu_link_translate($link); - if ($link['access']) { - // The link description, either derived from 'description' in - // hook_menu() or customized via menu module is used as title attribute. - if (!empty($link['localized_options']['attributes']['title'])) { - $link['description'] = $link['localized_options']['attributes']['title']; - unset($link['localized_options']['attributes']['title']); - } - // Prepare for sorting as in function _menu_tree_check_access(). - // The weight is offset so it is always positive, with a uniform 5-digits. - $key = (50000 + $link['weight']) . ' ' . drupal_strtolower($link['title']) . ' ' . $link['mlid']; - $content[$key] = $link; - } - } - ksort($content); - $cache[$item['mlid']] = $content; - return $content; + return Drupal::service('system.manager')->getAdminBlock($item); } /** diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml index f12ba8a..3a86be2 100644 --- a/core/modules/system/system.routing.yml +++ b/core/modules/system/system.routing.yml @@ -4,6 +4,91 @@ system.ajax: _controller: '\Drupal\system\Controller\FormAjaxController::content' requirements: _access: 'TRUE' + +system_admin: + pattern: '/admin' + defaults: + _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' + requirements: + _permission: 'access administration pages' + +system_admin_structure: + pattern: '/admin/structure' + defaults: + _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' + requirements: + _permission: 'access administration pages' + +system_admin_reports: + pattern: '/admin/reports' + defaults: + _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' + requirements: + _permission: 'access site reports' + +system_admin_config_media: + pattern: '/admin/config/media' + defaults: + _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' + requirements: + _permission: 'access administration pages' + +system_admin_config_services: + pattern: '/admin/config/services' + defaults: + _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' + requirements: + _permission: 'access administration pages' + +system_admin_config_development: + pattern: '/admin/config/development' + defaults: + _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' + requirements: + _permission: 'access administration pages' + +system_admin_config_regional: + pattern: '/admin/config/regional' + defaults: + _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' + requirements: + _permission: 'access administration pages' + +system_admin_config_search: + pattern: '/admin/config/search' + defaults: + _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' + requirements: + _permission: 'access administration pages' + +system_admin_config_system: + pattern: '/admin/config/system' + defaults: + _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' + requirements: + _permission: 'access administration pages' + +system_admin_config_ui: + pattern: '/admin/config/user-interface' + defaults: + _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' + requirements: + _permission: 'access administration pages' + +system_admin_config_workflow: + pattern: '/admin/config/workflow' + defaults: + _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' + requirements: + _permission: 'access administration pages' + +system_admin_config_content: + pattern: '/admin/config/content' + defaults: + _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' + requirements: + _permission: 'access administration pages' + system.cron: pattern: '/cron/{key}' defaults: diff --git a/core/modules/system/system.services.yml b/core/modules/system/system.services.yml index 08d67ad..f1838b5 100644 --- a/core/modules/system/system.services.yml +++ b/core/modules/system/system.services.yml @@ -5,7 +5,7 @@ services: - { name: access_check } system.manager: class: Drupal\system\SystemManager - arguments: ['@module_handler', '@database'] + arguments: ['@module_handler', '@database', '@entity.manager'] system.breadcrumb.legacy: class: Drupal\system\LegacyBreadcrumbBuilder tags: diff --git a/core/modules/system/tests/modules/menu_test/menu_test.module b/core/modules/system/tests/modules/menu_test/menu_test.module index 02fa65b..030dac1 100644 --- a/core/modules/system/tests/modules/menu_test/menu_test.module +++ b/core/modules/system/tests/modules/menu_test/menu_test.module @@ -24,14 +24,12 @@ function menu_test_menu() { 'type' => MENU_CALLBACK, 'access arguments' => array('access content'), ); - // This item uses system_admin_menu_block_page() to list child items. + // This item uses SystemController::systemAdminMenuBlockPage() to list child + // items. $items['menu_callback_description'] = array( 'title' => 'Menu item title', - 'page callback' => 'system_admin_menu_block_page', 'description' => 'Menu item description parent', - 'access arguments' => array('access content'), - 'file' => 'system.admin.inc', - 'file path' => drupal_get_path('module', 'system'), + 'route_name' => 'menu_callback_description', ); // This item tests the description key. $items['menu_callback_description/description-plain'] = array( @@ -296,14 +294,6 @@ function menu_test_menu() { 'access arguments' => array('access content'), ); - // File inheritance tests. This menu item should inherit the page callback - // system_admin_menu_block_page() and therefore render its children as links - // on the page. - $items['admin/config/development/file-inheritance'] = array( - 'title' => 'File inheritance', - 'description' => 'Test file inheritance', - 'access arguments' => array('access content'), - ); $items['admin/config/development/file-inheritance/inherit'] = array( 'title' => 'Inherit', 'description' => 'File inheritance test description', diff --git a/core/modules/system/tests/modules/menu_test/menu_test.routing.yml b/core/modules/system/tests/modules/menu_test/menu_test.routing.yml index 2d701dc..47d3a87 100644 --- a/core/modules/system/tests/modules/menu_test/menu_test.routing.yml +++ b/core/modules/system/tests/modules/menu_test/menu_test.routing.yml @@ -4,6 +4,14 @@ menu_login_callback: _content: '\Drupal\menu_test\TestControllers::testLogin' requirements: _access: 'TRUE' + +menu_callback_description: + pattern: 'menu_callback_description' + defaults: + _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' + requirements: + _permission: 'access content' + menu_router_test1: pattern: '/foo/{bar}' defaults: diff --git a/core/modules/user/user.module b/core/modules/user/user.module index 62ccfd6..e492826 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -893,15 +893,13 @@ function user_menu() { // Administration pages. $items['admin/config/people'] = array( - 'title' => 'People', - 'description' => 'Configure user accounts.', - 'position' => 'left', - 'weight' => -20, - 'page callback' => 'system_admin_menu_block_page', - 'access arguments' => array('access administration pages'), - 'file' => 'system.admin.inc', - 'file path' => drupal_get_path('module', 'system'), + 'title' => 'People', + 'description' => 'Configure user accounts.', + 'position' => 'left', + 'weight' => -20, + 'route_name' => 'user_admin_index', ); + $items['admin/config/people/accounts'] = array( 'title' => 'Account settings', 'description' => 'Configure default behavior of users, including registration requirements, e-mails, and fields.', diff --git a/core/modules/user/user.routing.yml b/core/modules/user/user.routing.yml index 90570ea..8bf9b91 100644 --- a/core/modules/user/user.routing.yml +++ b/core/modules/user/user.routing.yml @@ -26,6 +26,13 @@ user_autocomplete_anonymous: requirements: _permission: 'access user profiles' +user_admin_index: + pattern: '/admin/config/people' + defaults: + _content: '\Drupal\system\Controller\SystemController::systemAdminMenuBlockPage' + requirements: + _permission: 'access administration pages' + user_account_settings: pattern: '/admin/config/people/accounts' defaults: