diff --git a/core/lib/Drupal/Core/Routing/RouteCompiler.php b/core/lib/Drupal/Core/Routing/RouteCompiler.php index bd6c7b4..6e845cc 100644 --- a/core/lib/Drupal/Core/Routing/RouteCompiler.php +++ b/core/lib/Drupal/Core/Routing/RouteCompiler.php @@ -124,7 +124,7 @@ public static function getFit($path) { * @return string * The path string, stripped of placeholders that have default values. */ - protected static function getPathWithoutDefaults(Route $route) { + public static function getPathWithoutDefaults(Route $route) { $path = $route->getPattern(); $defaults = $route->getDefaults(); diff --git a/core/modules/user/lib/Drupal/user/Controller/UserAdmin.php b/core/modules/user/lib/Drupal/user/Controller/UserAdmin.php new file mode 100644 index 0000000..58d503e --- /dev/null +++ b/core/modules/user/lib/Drupal/user/Controller/UserAdmin.php @@ -0,0 +1,161 @@ +connection = $connection; + $this->moduleHandler = $module_handler; + $this->storageController = $storage_controller; + $this->query = $query; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('database'), + $container->get('module_handler'), + $container->get('plugin.manager.entity')->getStorageController('user'), + $container->get('entity.query')->get('user') + ); + } + + /** + * User administrative listing. + * + * @return array + * A render array as expected by drupal_render(). + */ + public function userList() { + $header = array( + 'username' => array('data' => t('Username'), 'field' => 'name', 'specifier' => 'name'), + 'status' => array('data' => t('Status'), 'field' => 'status', 'specifier' => 'status', 'class' => array(RESPONSIVE_PRIORITY_LOW)), + 'roles' => array('data' => t('Roles'), 'class' => array(RESPONSIVE_PRIORITY_LOW)), + 'member_for' => array('data' => t('Member for'), 'field' => 'created', 'specifier' => 'created', 'sort' => 'desc', 'class' => array(RESPONSIVE_PRIORITY_LOW)), + 'access' => array('data' => t('Last access'), 'field' => 'access', 'specifier' => 'access', 'class' => array(RESPONSIVE_PRIORITY_LOW)), + 'operations' => t('Operations'), + ); + + $this->query->condition('uid', 0, '<>'); + $this->query->pager(50); + $this->query->tableSort($header); + $uids = $this->query->execute(); + $accounts = $this->storageController->loadMultiple($uids); + + $destination = drupal_get_destination(); + $status = array(t('blocked'), t('active')); + $roles = array_map('Drupal\Component\Utility\String::checkPlain', user_role_names(TRUE)); + unset($roles[DRUPAL_AUTHENTICATED_RID]); + $options = array(); + foreach ($accounts as $account) { + $users_roles = array(); + foreach ($account->getRoles() as $role) { + if (isset($roles[$role])) { + $users_roles[] = $roles[$role]; + } + } + asort($users_roles); + $options[$account->id()]['username']['data'] = array( + '#theme' => 'username', + '#account' => $account, + ); + $options[$account->id()]['status'] = $status[$account->status->value]; + $options[$account->id()]['roles']['data'] = array( + '#theme' => 'item_list', + '#items' => $users_roles, + ); + $options[$account->id()]['member_for'] = format_interval(REQUEST_TIME - $account->created->value); + $options[$account->id()]['access'] = $account->access ? t('@time ago', array('@time' => format_interval(REQUEST_TIME - $account->access->value))) : t('never'); + $links = array(); + $links['edit'] = array( + 'title' => t('Edit'), + 'href' => 'user/' . $account->id() . '/edit', + 'query' => $destination, + ); + if ($this->moduleHandler->invoke('content_translation', 'translate_access', array($account))) { + $links['translate'] = array( + 'title' => t('Translate'), + 'href' => 'user/' . $account->id() . '/translations', + 'query' => $destination, + ); + } + $options[$account->id()]['operations']['data'] = array( + '#type' => 'operations', + '#links' => $links, + ); + } + + $build['accounts'] = array( + '#theme' => 'table', + '#header' => $header, + '#rows' => $options, + '#empty' => t('No people available.'), + ); + $build['pager'] = array( + '#theme' =>'pager', + ); + + return $build; + } + +} diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc index bb486ff..4382045 100644 --- a/core/modules/user/user.admin.inc +++ b/core/modules/user/user.admin.inc @@ -6,97 +6,6 @@ */ /** - * Page callback: User administration page. - */ -function user_admin_account() { - $header = array( - 'username' => array('data' => t('Username'), 'field' => 'u.name'), - 'status' => array('data' => t('Status'), 'field' => 'u.status', 'class' => array(RESPONSIVE_PRIORITY_LOW)), - 'roles' => array('data' => t('Roles'), 'class' => array(RESPONSIVE_PRIORITY_LOW)), - 'member_for' => array('data' => t('Member for'), 'field' => 'u.created', 'sort' => 'desc', 'class' => array(RESPONSIVE_PRIORITY_LOW)), - 'access' => array('data' => t('Last access'), 'field' => 'u.access', 'class' => array(RESPONSIVE_PRIORITY_LOW)), - 'operations' => t('Operations'), - ); - - $query = db_select('users', 'u'); - $query->condition('u.uid', 0, '<>'); - - $count_query = clone $query; - $count_query->addExpression('COUNT(u.uid)'); - - $query = $query - ->extend('Drupal\Core\Database\Query\PagerSelectExtender') - ->extend('Drupal\Core\Database\Query\TableSortExtender'); - $query - ->fields('u', array('uid', 'name', 'status', 'created', 'access')) - ->limit(50) - ->orderByHeader($header) - ->setCountQuery($count_query); - $result = $query->execute(); - - $destination = drupal_get_destination(); - $status = array(t('blocked'), t('active')); - $roles = array_map('check_plain', user_role_names(TRUE)); - $accounts = array(); - foreach ($result as $account) { - $account = user_load($account->uid); - $users_roles = array(); - $roles_result = db_query('SELECT rid FROM {users_roles} WHERE uid = :uid', array(':uid' => $account->id())); - foreach ($roles_result as $user_role) { - $users_roles[] = $roles[$user_role->rid]; - } - asort($users_roles); - $username = array( - '#theme' => 'username', - '#account' => $account, - ); - $item_list = array( - '#theme' => 'item_list', - '#items' => $users_roles, - ); - $options[$account->id()] = array( - 'username' => drupal_render($username), - 'status' => $status[$account->status], - 'roles' => drupal_render($item_list), - 'member_for' => format_interval(REQUEST_TIME - $account->created), - 'access' => $account->access ? t('@time ago', array('@time' => format_interval(REQUEST_TIME - $account->access))) : t('never'), - ); - $links = array(); - $links['edit'] = array( - 'title' => t('Edit'), - 'href' => 'user/' . $account->id() . '/edit', - 'query' => $destination, - ); - if (module_invoke('content_translation', 'translate_access', $account)) { - $links['translate'] = array( - 'title' => t('Translate'), - 'href' => 'user/' . $account->id() . '/translations', - 'query' => $destination, - ); - } - $options[$account->id()]['operations']['data'] = array( - '#type' => 'operations', - '#links' => $links, - ); - - $options[$account->id()]['title']['data']['#title'] = check_plain($account->name); - - } - - $form['accounts'] = array( - '#theme' => 'table', - '#header' => $header, - '#rows' => $options, - '#empty' => t('No people available.'), - ); - $form['pager'] = array( - '#theme' =>'pager', - ); - - return $form; -} - -/** * Menu callback: administer permissions. * * @ingroup forms diff --git a/core/modules/user/user.module b/core/modules/user/user.module index cb1ab7e..6e5ad8e 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -873,11 +873,13 @@ function user_menu() { $items['admin/people'] = array( 'title' => 'People', 'description' => 'Manage user accounts, roles, and permissions.', - 'page callback' => 'user_admin_account', - 'access arguments' => array('administer users'), + 'route_name' => 'user_admin_account', 'position' => 'left', 'weight' => -4, - 'file' => 'user.admin.inc', + ); + $items['admin/people/list'] = array( + 'title' => 'List', + 'type' => MENU_DEFAULT_LOCAL_TASK, ); // Permissions and role forms. $items['admin/people/permissions'] = array( @@ -917,9 +919,8 @@ function user_menu() { ); $items['admin/people/create'] = array( - 'title' => 'Add user', 'route_name' => 'user_admin_create', - 'type' => MENU_LOCAL_ACTION, + 'type' => MENU_SIBLING_LOCAL_TASK, ); $items['admin/people/cancel'] = array( 'title' => 'Cancel user', @@ -994,6 +995,22 @@ function user_menu() { } /** + * Implements hook_local_actions(). + */ +function user_local_actions() { + return array( + array( + 'route_name' => 'user_admin_create', + 'title' => t('Add user'), + 'appears_on' => array( + 'user_admin_account', + 'view.user_admin_people.page_1', + ), + ), + ); +} + +/** * Implements hook_menu_link_presave(). */ function user_menu_link_presave(MenuLink $menu_link) { diff --git a/core/modules/user/user.routing.yml b/core/modules/user/user.routing.yml index 10ec95d..243911d 100644 --- a/core/modules/user/user.routing.yml +++ b/core/modules/user/user.routing.yml @@ -33,6 +33,13 @@ user_account_settings: requirements: _permission: 'administer users' +user_admin_account: + pattern: '/admin/people' + defaults: + _controller: '\Drupal\user\Controller\UserAdmin::userList' + requirements: + _permission: 'administer users' + user_admin_create: pattern: '/admin/people/create' defaults: diff --git a/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php b/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php index e3dbde3..0c66e82 100644 --- a/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php +++ b/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php @@ -22,6 +22,7 @@ class RouteSubscriber implements EventSubscriberInterface { */ public static function getSubscribedEvents() { $events[RoutingEvents::DYNAMIC] = 'dynamicRoutes'; + $events[RoutingEvents::ALTER] = 'alterRoutes'; return $events; } @@ -46,4 +47,23 @@ public function dynamicRoutes(RouteBuildEvent $event) { } } + /** + * Alters existing routes. + * + * @param \Drupal\Core\Routing\RouteBuildEvent $event + * The route building event. + */ + public function alterRoutes(RouteBuildEvent $event) { + $views = views_get_applicable_views('uses_route'); + foreach ($views as $data) { + list($view, $display_id) = $data; + if ($view->setDisplay($display_id) && $display = $view->displayHandlers->get($display_id)) { + if ($display instanceof DisplayRouterInterface) { + $display->alterRoutes($event->getRouteCollection()); + } + } + $view->destroy(); + } + } + } diff --git a/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php b/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php index abef195..38591d8 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php +++ b/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php @@ -317,6 +317,17 @@ public function getExportProperties() { /** * {@inheritdoc} + * + * Figures out which routes are overridden l + * @param EntityStorageControllerInterface $storage_controller + */ + public function preSave(EntityStorageControllerInterface $storage_controller) { + parent::preSave($storage_controller); + } + + + /** + * {@inheritdoc} */ public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) { views_invalidate_cache(); diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayRouterInterface.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayRouterInterface.php index 68cbe68..85457e8 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayRouterInterface.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayRouterInterface.php @@ -25,4 +25,6 @@ */ public function collectRoutes(RouteCollection $collection); + public function alterRoutes(RouteCollection $collection); + } diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php index 57691f1..b8a6ece 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php @@ -7,8 +7,11 @@ namespace Drupal\views\Plugin\views\display; +use Drupal\Core\Routing\RouteCompiler; +use Drupal\Core\Routing\RouteProviderInterface; use Drupal\views\Views; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Routing\Route; @@ -20,6 +23,33 @@ abstract class PathPluginBase extends DisplayPluginBase implements DisplayRouterInterface { /** + * Constructs a PathPluginBase object. + * + * @param array $configuration + * A configuration array containing information about the plugin instance. + * @param string $plugin_id + * The plugin_id for the plugin instance. + * @param array $plugin_definition + * The plugin implementation definition. + * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider + * The route provider + */ + public function __construct(array $configuration, $plugin_id, array $plugin_definition, RouteProviderInterface $route_provider) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + + $this->routeProvider = $route_provider; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) { + return new static($configuration, $plugin_id, $plugin_definition, + $container->get('router.route_provider') + ); + } + + /** * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::hasPath(). */ public function hasPath() { @@ -60,12 +90,17 @@ protected function defineOptions() { } /** - * {@inheritdoc} + * Generate a route entry for a given view and display. + * + * @param string $view_id + * The ID of the view. + * @param string $display_id + * The current display ID. + * + * @return \Symfony\Component\Routing\Route + * The route for the view. */ - public function collectRoutes(RouteCollection $collection) { - $view_id = $this->view->storage->id(); - $display_id = $this->display['id']; - + protected function getRoute($view_id, $display_id) { $defaults = array( '_controller' => 'Drupal\views\Routing\ViewPageController::handle', 'view_id' => $view_id, @@ -126,11 +161,39 @@ public function collectRoutes(RouteCollection $collection) { $access_plugin = Views::pluginManager('access')->createInstance('none'); } $access_plugin->alterRouteDefinition($route); + return $route; + } + + /** + * {@inheritdoc} + */ + public function collectRoutes(RouteCollection $collection) { + $view_id = $this->view->storage->id(); + $display_id = $this->display['id']; + + $route = $this->getRoute($view_id, $display_id); $collection->add("view.$view_id.$display_id", $route); } /** + * {@inheritdoc} + */ + public function alterRoutes(RouteCollection $collection) { + foreach ($collection->all() as $name => $route) { + // Find all paths which match the path of the current display.. + $route_path = RouteCompiler::getPathWithoutDefaults($route); + $route_path = RouteCompiler::getPatternOutline($route_path); + if (!$route->hasDefault('view_id') && '/' . $this->getPath() == $route_path) { + // @todo Figure out whether we need to merge some settings (like + // requirements). + // Replace the existing route with a new one based on views. + $collection->remove($name); + } + } + } + + /** * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::executeHookMenu(). */ public function executeHookMenu($callbacks) { diff --git a/core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php b/core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php new file mode 100644 index 0000000..f1e846a --- /dev/null +++ b/core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php @@ -0,0 +1,74 @@ + 'Display: Path plugin base.', + 'description' => 'Tests the abstract base class for path based display plugins.', + 'group' => 'Views Plugins', + ); + } + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface'); + $this->pathPlugin = $this->getMockBuilder('Drupal\views\Plugin\views\display\PathPluginBase') + ->setConstructorArgs(array(array(), 'path_base', array(), $this->routeProvider)) + ->setMethods(NULL) + ->getMock(); + } + + /** + * Tests the alter route method. + */ + public function testAlterRoute() { + $collection = new RouteCollection(); + $collection->add('test_route', new Route('test_route', array('_controller' => 'Drupal\Tests\Core\Controller\TestController'))); + $collection->add('test_route_2', new Route('test_route/example', array('_controller' => 'Drupal\Tests\Core\Controller\TestController'))); + + $view = $this->getMock('Drupal\views\ViewExecutable'); + $display = array(); + $display['display_plugin'] = 'page'; + $display['id'] = 'page_1'; + $display['display_options'] = array( + + ); + $this->pathPlugin->initDisplay($view, $display, $options); + } + +} diff --git a/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewListControllerTest.php b/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewListControllerTest.php index 9dd1295..5aff65e 100644 --- a/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewListControllerTest.php +++ b/core/modules/views_ui/tests/Drupal/views_ui/Tests/ViewListControllerTest.php @@ -77,9 +77,10 @@ public function testBuildRowEntityList() { array('initDisplay'), array(array(), 'default', $display_manager->getDefinition('default')) ); + $route_provider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface'); $page_display = $this->getMock('Drupal\views\Plugin\views\display\Page', array('initDisplay', 'getPath'), - array(array(), 'default', $display_manager->getDefinition('page')) + array(array(), 'default', $display_manager->getDefinition('page'), $route_provider) ); $page_display->expects($this->any()) ->method('getPath')