diff --git a/core/includes/menu.inc b/core/includes/menu.inc index fb11da25308..08181b19dc5 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -774,7 +774,7 @@ function _menu_translate(&$router_item, $map, $to_arg = FALSE) { // Attempt to match this path to provide a fully built request to the // acccess checker. try { - $request->attributes->add(Drupal::service('router')->matchRequest($request)); + $request->attributes->add(Drupal::service('router.dynamic')->matchRequest($request)); $router_item['access'] = Drupal::service('access_manager')->check($route, $request); } catch (NotFoundHttpException $e) { diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php index dd4ffcc847d..769d2961c50 100644 --- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php +++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkStorageController.php @@ -10,6 +10,7 @@ namespace Drupal\menu_link; use Drupal\Core\Entity\DatabaseStorageController; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityStorageException; +use Symfony\Component\HttpFoundation\Request; /** * Controller class for menu links. @@ -216,6 +217,36 @@ class MenuLinkStorageController extends DatabaseStorageController { $entity->router_path = _menu_find_router_path($entity->link_path); } } + // Find the route_name. + if (!isset($entity->route_name)) { + $entity->route_name = $this->findRouteName($entity->link_path); + } + } + + /** + * Returns the route_name matching a URL. + * + * @param string $link_path + * The link path to find a route name for. + * + * @return string + * The route name. + */ + protected function findRouteName($link_path) { + // Look up the route_name used for the given path. + $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); + return isset($result['_route']) ? $result['_route'] : ''; + } + catch (\Exception $e) { + return ''; + } + } /** diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeRSSContentTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeRSSContentTest.php index ea7c5075d23..34b35ae3044 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeRSSContentTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeRSSContentTest.php @@ -72,10 +72,6 @@ class NodeRSSContentTest extends NodeTestBase { // viewing node. $this->drupalGet("node/$node->nid"); $this->assertNoText($rss_only_content, 'Node content designed for RSS does not appear when viewing node.'); - - // Check that the node feed page does not try to interpret additional path - // components as arguments for node_feed() and returns default content. - $this->drupalGet('rss.xml/' . $this->randomName() . '/' . $this->randomName()); - $this->assertText($rss_only_content, 'Ignore page arguments when delivering rss.xml.'); } + } diff --git a/core/modules/node/lib/Drupal/node/Tests/Views/NodeIntegrationTest.php b/core/modules/node/lib/Drupal/node/Tests/Views/NodeIntegrationTest.php new file mode 100644 index 00000000000..1e57b5e094e --- /dev/null +++ b/core/modules/node/lib/Drupal/node/Tests/Views/NodeIntegrationTest.php @@ -0,0 +1,74 @@ + 'Node: Views data', + 'description' => 'Tests the node integration into views.', + 'group' => 'Views module integration', + ); + } + + /** + * Tests basic node view with a node type argument. + */ + public function testNodeViewTypeArgument() { + // Create two content types with three nodes each. + $types = array(); + $all_nids = array(); + for ($i = 0; $i < 2; $i++) { + $type = $this->drupalCreateContentType(); + $types[] = $type; + + for ($j = 0; $j < 5; $j++) { + // Ensure the right order of the nodes. + $node = $this->drupalCreateNode(array('type' => $type->type, 'created' => REQUEST_TIME - ($i * 5 + $j))); + $nodes[$type->type][$node->id()] = $node; + $all_nids[] = $node->id(); + } + } + + $this->drupalGet('test-node-view'); + $this->assertResponse(404); + + $this->drupalGet('test-node-view/all'); + $this->assertResponse(200); + $this->assertNids($all_nids); + + foreach ($types as $type) { + $this->drupalGet("test-node-view/{$type->type}"); + $this->assertNids(array_keys($nodes[$type->type])); + } + } + + /** + * Ensures that a list of nodes appear on the page. + * + * @param array $expected_nids + * An array of node IDs. + */ + protected function assertNids(array $expected_nids = array()) { + $result = $this->xpath('//span[@class="field-content"]'); + $nids = array(); + foreach ($result as $element) { + $nids[] = (int) $element; + } + $this->assertEqual($nids, $expected_nids); + } + +} diff --git a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_view.yml b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_view.yml new file mode 100644 index 00000000000..4b82a313e4b --- /dev/null +++ b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_view.yml @@ -0,0 +1,195 @@ +base_field: nid +base_table: node +core: 8.x +description: '' +status: '1' +display: + page_1: + display_plugin: page + id: page_1 + display_title: Page + position: '' + display_options: + path: test-node-view + default: + display_plugin: default + id: default + display_title: Master + position: '' + display_options: + access: + type: perm + options: + perm: 'access content' + cache: + type: none + options: { } + query: + type: views_query + options: + disable_sql_rewrite: '0' + distinct: '0' + slave: '0' + query_comment: '' + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: '0' + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: '1' + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: full + options: + items_per_page: '10' + offset: '0' + id: '0' + total_pages: '' + expose: + items_per_page: '0' + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 20, 40, 60' + items_per_page_options_all: '0' + items_per_page_options_all_label: '- All -' + offset: '0' + offset_label: Offset + tags: + previous: '‹ previous' + next: 'next ›' + first: '« first' + last: 'last »' + quantity: '9' + style: + type: default + row: + type: fields + fields: + nid: + id: nid + table: node + field: nid + relationship: none + group_type: group + admin_label: '' + label: Nid + exclude: '0' + alter: + alter_text: '0' + text: '' + make_link: '0' + path: '' + absolute: '0' + external: '0' + replace_spaces: '0' + path_case: none + trim_whitespace: '0' + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: '0' + max_length: '' + word_boundary: '1' + ellipsis: '1' + more_link: '0' + more_link_text: '' + more_link_path: '' + strip_tags: '0' + trim: '0' + preserve_tags: '' + html: '0' + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: '1' + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: '1' + empty: '' + hide_empty: '0' + empty_zero: '0' + hide_alter_empty: '1' + link_to_node: '0' + plugin_id: node + filters: + status: + value: '1' + table: node + field: status + id: status + expose: + operator: '0' + group: '1' + sorts: + created: + id: created + table: node + field: created + order: DESC + relationship: none + group_type: group + admin_label: '' + exposed: '0' + expose: + label: '' + granularity: second + title: test_node_view + header: { } + footer: { } + empty: { } + relationships: { } + arguments: + type: + id: type + table: node + field: type + relationship: none + group_type: group + admin_label: '' + default_action: 'not found' + exception: + value: all + title_enable: '0' + title: All + title_enable: '0' + title: '' + breadcrumb_enable: '0' + breadcrumb: '' + default_argument_type: fixed + default_argument_options: + argument: '' + default_argument_skip_url: '0' + summary_options: + base_path: '' + count: '1' + items_per_page: '25' + override: '0' + summary: + sort_order: asc + number_of_records: '0' + format: default_summary + specify_validation: '0' + validate: + type: none + fail: 'not found' + validate_options: { } + glossary: '0' + limit: '0' + case: none + path_case: none + transform_dash: '0' + break_phrase: '0' + plugin_id: node_type +label: test_node_view +module: views +id: test_node_view +tag: '' +uuid: 377e9d79-57ea-4836-a100-a255c58e40ca +langcode: en diff --git a/core/modules/rest/lib/Drupal/rest/Plugin/views/display/RestExport.php b/core/modules/rest/lib/Drupal/rest/Plugin/views/display/RestExport.php index ea43d9d981b..b263f71d44c 100644 --- a/core/modules/rest/lib/Drupal/rest/Plugin/views/display/RestExport.php +++ b/core/modules/rest/lib/Drupal/rest/Plugin/views/display/RestExport.php @@ -23,7 +23,7 @@ use Drupal\views\Plugin\views\display\PathPluginBase; * module = "rest", * title = @Translation("REST export"), * help = @Translation("Create a REST export resource."), - * uses_hook_menu = TRUE, + * uses_route = TRUE, * admin = @Translation("REST export") * ) */ diff --git a/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestControllers.php b/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestControllers.php index adb5c345e0f..86342d501b8 100644 --- a/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestControllers.php +++ b/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestControllers.php @@ -14,6 +14,10 @@ use Symfony\Component\HttpFoundation\Response; */ class TestControllers { + public function test() { + return new Response('test'); + } + public function test1() { return new Response('test1'); } diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/access/Permission.php b/core/modules/user/lib/Drupal/user/Plugin/views/access/Permission.php index 5b4004ddb0e..3ce45921d9e 100644 --- a/core/modules/user/lib/Drupal/user/Plugin/views/access/Permission.php +++ b/core/modules/user/lib/Drupal/user/Plugin/views/access/Permission.php @@ -10,6 +10,7 @@ namespace Drupal\user\Plugin\views\access; use Drupal\Component\Annotation\Plugin; use Drupal\views\Plugin\views\access\AccessPluginBase; use Drupal\Core\Annotation\Translation; +use Symfony\Component\Routing\Route; /** * Access plugin that provides permission-based access control. @@ -30,11 +31,14 @@ class Permission extends AccessPluginBase { protected $usesOptions = TRUE; public function access($account) { - return views_check_perm($this->options['perm'], $account); + return user_access($this->options['perm'], $account) || user_access('access all views', $account); } - function get_access_callback() { - return array('views_check_perm', array($this->options['perm'])); + /** + * {@inheritdoc} + */ + public function alterRouteDefinition(Route $route) { + $route->setRequirement('_permission', $this->options['perm']); } public function summaryTitle() { diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/access/Role.php b/core/modules/user/lib/Drupal/user/Plugin/views/access/Role.php index 6448df48616..23ece461423 100644 --- a/core/modules/user/lib/Drupal/user/Plugin/views/access/Role.php +++ b/core/modules/user/lib/Drupal/user/Plugin/views/access/Role.php @@ -10,6 +10,7 @@ namespace Drupal\user\Plugin\views\access; use Drupal\Component\Annotation\Plugin; use Drupal\views\Plugin\views\access\AccessPluginBase; use Drupal\Core\Annotation\Translation; +use Symfony\Component\Routing\Route; /** * Access plugin that provides role-based access control. @@ -29,12 +30,18 @@ class Role extends AccessPluginBase { */ protected $usesOptions = TRUE; + /** + * {@inheritdoc} + */ public function access($account) { - return views_check_roles(array_filter($this->options['role']), $account); + return user_access('access all views', $account) || array_intersect(array_filter($this->options['role']), $account->roles); } - function get_access_callback() { - return array('views_check_roles', array(array_filter($this->options['role']))); + /** + * {@inheritdoc} + */ + public function alterRouteDefinition(Route $route) { + $route->setRequirement('_role_id', $this->options['role']); } public function summaryTitle() { diff --git a/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php b/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php new file mode 100644 index 00000000000..e3dbde33487 --- /dev/null +++ b/core/modules/views/lib/Drupal/views/EventSubscriber/RouteSubscriber.php @@ -0,0 +1,49 @@ +getRouteCollection(); + + $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->collectRoutes($collection); + } + } + $view->destroy(); + } + } + +} diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/access/AccessPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/access/AccessPluginBase.php index 0d70b4c10a1..18d3cfe7405 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/access/AccessPluginBase.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/access/AccessPluginBase.php @@ -9,13 +9,14 @@ namespace Drupal\views\Plugin\views\access; use Drupal\views\Plugin\views\PluginBase; use Drupal\views\ViewExecutable; +use Symfony\Component\Routing\Route; /** * @defgroup views_access_plugins Views access plugins * @{ * The base plugin to handle access to a view. * - * Therefore it primarily has to implement the access and the get_access_callback + * Therefore it primarily has to implement the access and the alterRouteDefinition * method. */ @@ -65,18 +66,15 @@ abstract class AccessPluginBase extends PluginBase { abstract public function access($account); /** - * Determine the access callback and arguments. + * Allows access plugins to alter the route definition of a view. * - * This information will be embedded in the menu in order to reduce - * performance hits during menu item access testing, which happens - * a lot. + * Likely the access plugin will add new requirements, so its custom access + * checker can be applied. * - * @return array - * The first item of the array should be the function to call,and the - * second item should be an array of arguments. The first item may also be - * TRUE (bool only) which will indicate no access control. + * @param \Symfony\Component\Routing\Route $route + * The route to change. */ - abstract function get_access_callback(); + abstract public function alterRouteDefinition(Route $route); } diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/access/None.php b/core/modules/views/lib/Drupal/views/Plugin/views/access/None.php index 55e1c808b0b..522c472b15f 100644 --- a/core/modules/views/lib/Drupal/views/Plugin/views/access/None.php +++ b/core/modules/views/lib/Drupal/views/Plugin/views/access/None.php @@ -10,6 +10,8 @@ namespace Drupal\views\Plugin\views\access; use Drupal\Core\Annotation\Translation; use Drupal\Component\Annotation\Plugin; +use Symfony\Component\Routing\Route; + /** * Access plugin that provides no access control at all. * @@ -36,11 +38,10 @@ class None extends AccessPluginBase { } /** - * Implements Drupal\views\Plugin\views\access\AccessPluginBase::get_access_callback(). + * {@inheritdoc} */ - public function get_access_callback() { - // No access control. - return TRUE; + public function alterRouteDefinition(Route $route) { + $route->setRequirement('_access', 'TRUE'); } } 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 new file mode 100644 index 00000000000..68cbe688ee0 --- /dev/null +++ b/core/modules/views/lib/Drupal/views/Plugin/views/display/DisplayRouterInterface.php @@ -0,0 +1,28 @@ +view->getTitle()), PASS_THROUGH); - return $render; + $response = $this->view->getResponse(); + $response->setContent(drupal_render_page($render)); + + return $response; } /** 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 51b905a4054..bb0508037bb 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 @@ -8,13 +8,16 @@ namespace Drupal\views\Plugin\views\display; use Drupal\views\Views; + use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\Routing\Route; +use Symfony\Component\Routing\RouteCollection; /** * The base display plugin for path/callbacks. This is used for pages and feeds. */ -abstract class PathPluginBase extends DisplayPluginBase { +abstract class PathPluginBase extends DisplayPluginBase implements DisplayRouterInterface { /** * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::hasPath(). @@ -33,6 +36,69 @@ abstract class PathPluginBase extends DisplayPluginBase { return $options; } + /** + * {@inheritdoc} + */ + public function collectRoutes(RouteCollection $collection) { + $view_id = $this->view->storage->id(); + $display_id = $this->display['id']; + + $defaults = array( + '_controller' => 'Drupal\views\Routing\ViewPageController::handle', + 'view_id' => $view_id, + 'display_id' => $display_id, + ); + + // @todo How do we apply argument validation? + $bits = explode('/', $this->getOption('path')); + // @todo Figure out validation/argument loading. + // Replace % with %views_arg for menu autoloading and add to the + // page arguments so the argument actually comes through. + $arg_counter = 0; + + $this->view->initHandlers(); + $view_arguments = $this->view->argument; + + $argument_ids = array_keys($view_arguments); + $total_arguments = count($argument_ids); + + // Replace arguments in the views UI (defined via %) with parameters in + // routes (defined via {}). As a name for the parameter use arg_$key, so + // it can be pulled in the views controller from the request. + foreach ($bits as $pos => $bit) { + if ($bit == '%') { + // Generate the name of the parameter using the key of the argument + // handler. + $arg_id = 'arg_' . $argument_ids[$arg_counter++]; + $bits[$pos] = '{' . $arg_id . '}'; + } + } + + // Add missing arguments not defined in the path, but added as handler. + while (($total_arguments - $arg_counter) > 0) { + $arg_id = 'arg_' . $argument_ids[$arg_counter++]; + $bit = '{' . $arg_id . '}'; + // In contrast to the previous loop add the defaults here, as % was not + // specified, which means the argument is optional. + $defaults[$arg_id] = NULL; + $bits[] = $bit; + } + + $route_path = '/' . implode('/', $bits); + + $route = new Route($route_path, $defaults); + + // Add access check parameters to the route. + $access_plugin = $this->getPlugin('access'); + if (!isset($access_plugin)) { + // @todo Do we want to support a default plugin in getPlugin itself? + $access_plugin = Views::pluginManager('access')->createInstance('none'); + } + $access_plugin->alterRouteDefinition($route); + + $collection->add("view.$view_id.$display_id", $route); + } + /** * Overrides \Drupal\views\Plugin\views\display\DisplayPluginBase::executeHookMenu(). */ @@ -60,49 +126,9 @@ abstract class PathPluginBase extends DisplayPluginBase { $path = implode('/', $bits); - $access_plugin = $this->getPlugin('access'); - if (!isset($access_plugin)) { - $access_plugin = Views::pluginManager('access')->createInstance('none'); - } - - // Get access callback might return an array of the callback + the dynamic - // arguments. - $access_plugin_callback = $access_plugin->get_access_callback(); - - if (is_array($access_plugin_callback)) { - $access_arguments = array(); - - // Find the plugin arguments. - $access_plugin_method = array_shift($access_plugin_callback); - $access_plugin_arguments = array_shift($access_plugin_callback); - if (!is_array($access_plugin_arguments)) { - $access_plugin_arguments = array(); - } - - $access_arguments[0] = array($access_plugin_method, &$access_plugin_arguments); - - // Move the plugin arguments to the access arguments array. - $i = 1; - foreach ($access_plugin_arguments as $key => $value) { - if (is_int($value)) { - $access_arguments[$i] = $value; - $access_plugin_arguments[$key] = $i; - $i++; - } - } - } - else { - $access_arguments = array($access_plugin_callback); - } - if ($path) { $items[$path] = array( - // Default views page entry. - 'page callback' => 'views_page', - 'page arguments' => $page_arguments, - // Default access check (per display). - 'access callback' => 'views_access', - 'access arguments' => $access_arguments, + 'route_name' => "view.{$this->view->storage->id()}.{$this->display['id']}", // Identify URL embedded arguments and correlate them to a handler. 'load arguments' => array($this->view->storage->id(), $this->display['id'], '%index'), ); @@ -159,11 +185,6 @@ abstract class PathPluginBase extends DisplayPluginBase { $default_path = implode('/', $bits); $items[$default_path] = array( // Default views page entry. - 'page callback' => 'views_page', - 'page arguments' => $page_arguments, - // Default access check (per display). - 'access callback' => 'views_access', - 'access arguments' => $access_arguments, // Identify URL embedded arguments and correlate them to a // handler. 'load arguments' => array($this->view->storage->id(), $this->display['id'], '%index'), diff --git a/core/modules/views/lib/Drupal/views/Routing/ViewPageController.php b/core/modules/views/lib/Drupal/views/Routing/ViewPageController.php new file mode 100644 index 00000000000..727ebbbf216 --- /dev/null +++ b/core/modules/views/lib/Drupal/views/Routing/ViewPageController.php @@ -0,0 +1,86 @@ +storageController = $storage_controller; + $this->executableFactory = $executable_factory; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('plugin.manager.entity')->getStorageController('view'), + $container->get('views.executable') + ); + } + + /** + * Handles a response for a view. + */ + public function handle(Request $request) { + $view_id = $request->attributes->get('view_id'); + $display_id = $request->attributes->get('display_id'); + + $entities = $this->storageController->load(array($view_id)); + $entity = reset($entities); + if (empty($entity)) { + throw new NotFoundHttpException(format_string('Page controller for view %id requested, but view was not found.', array('%id' => $view_id))); + } + $view = $this->executableFactory->get($entity); + $view->setDisplay($display_id); + $view->initHandlers(); + + $args = array(); + foreach (array_keys((array) $view->argument) as $argument_id) { + $arg = $request->attributes->get('arg_' . $argument_id); + if (isset($arg)) { + $args[] = $arg; + } + } + + return $view->executeDisplay($display_id, $args); + } + +} diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/AccessTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/AccessTest.php index b4c5118888e..03dbbad9f21 100644 --- a/core/modules/views/lib/Drupal/views/Tests/Plugin/AccessTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/AccessTest.php @@ -7,6 +7,8 @@ namespace Drupal\views\Tests\Plugin; +use Drupal\views\Tests\ViewTestData; + /** * Basic test for pluggable access. * @@ -35,6 +37,8 @@ class AccessTest extends PluginTestBase { $this->enableViewsTestModule(); + ViewTestData::importTestViews(get_class($this), array('views_test_data')); + $this->admin_user = $this->drupalCreateUser(array('access all views')); $this->web_user = $this->drupalCreateUser(); $this->web_role = current($this->web_user->roles); @@ -42,6 +46,7 @@ class AccessTest extends PluginTestBase { $this->normal_role = $this->drupalCreateRole(array()); $this->normal_user = $this->drupalCreateUser(array('views_test_data test permission')); $this->normal_user->roles[$this->normal_role] = $this->normal_role; + // @todo when all the plugin information is cached make a reset function and // call it here. } @@ -74,57 +79,19 @@ class AccessTest extends PluginTestBase { $access_plugin = $view->display_handler->getPlugin('access'); $this->assertFalse($access_plugin->access($this->normal_user)); + $this->drupalGet('test_access_static'); + $this->assertResponse(403); + $display = &$view->storage->getDisplay('default'); + $display['display_options']['access']['options']['access'] = TRUE; $access_plugin->options['access'] = TRUE; + $view->save(); + $this->container->get('router.builder')->rebuild(); + $this->assertTrue($access_plugin->access($this->normal_user)); - // FALSE comes from hook_menu caching. - $expected_hook_menu = array( - 'views_test_data_test_static_access_callback', array(FALSE) - ); - $hook_menu = $view->executeHookMenu('page_1'); - $this->assertEqual($expected_hook_menu, $hook_menu['test_access_static']['access arguments'][0]); - - $expected_hook_menu = array( - 'views_test_data_test_static_access_callback', array(TRUE) - ); - $this->assertTrue(views_access($expected_hook_menu)); - } - - /** - * Tests dynamic access plugin. - * - * @see Drupal\views_test\Plugin\views\access\DyamicTest - */ - function testDynamicAccessPlugin() { - $view = views_get_view('test_access_dynamic'); - $view->setDisplay(); - $argument1 = $this->randomName(); - $argument2 = $this->randomName(); - state()->set('test_dynamic_access_argument1', $argument1); - state()->set('test_dynamic_access_argument2', $argument2); - - $access_plugin = $view->display_handler->getPlugin('access'); - - $this->assertFalse($access_plugin->access($this->normal_user)); - - $access_plugin->options['access'] = TRUE; - $this->assertFalse($access_plugin->access($this->normal_user)); - - $view->setArguments(array($argument1, $argument2)); - $this->assertTrue($access_plugin->access($this->normal_user)); - - // FALSE comes from hook_menu caching. - $expected_hook_menu = array( - 'views_test_data_test_dynamic_access_callback', array(FALSE, 1, 2) - ); - $hook_menu = $view->executeHookMenu('page_1'); - $this->assertEqual($expected_hook_menu, $hook_menu['test_access_dynamic']['access arguments'][0]); - - $expected_hook_menu = array( - 'views_test_data_test_dynamic_access_callback', array(TRUE, 1, 2) - ); - $this->assertTrue(views_access($expected_hook_menu, $argument1, $argument2)); + $this->drupalGet('test_access_static'); + $this->assertResponse(200); } } diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php index 49ed01cdeb9..2b85c9368c1 100644 --- a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageTest.php @@ -2,26 +2,45 @@ /** * @file - * Definition of Drupal\views\Tests\Plugin\DisplayPageTest. + * Contains \Drupal\views\Tests\Plugin\DisplayPageTest. */ namespace Drupal\views\Tests\Plugin; -use Drupal\views\Tests\Plugin\PluginTestBase; +use Drupal\Core\Routing\RouteBuildEvent; +use Drupal\views\EventSubscriber\RouteSubscriber; +use Drupal\views\Tests\ViewUnitTestBase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\Routing\RouteCollection; /** * Tests the page display plugin. * * @see Drupal\views\Plugin\display\Page */ -class DisplayPageTest extends PluginTestBase { +class DisplayPageTest extends ViewUnitTestBase { /** * Views used by this test. * * @var array */ - public static $testViews = array('test_page_display'); + public static $testViews = array('test_page_display', 'test_page_display_route'); + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = array('system', 'user'); + + /** + * The router dumper to get all routes. + * + * @var \Drupal\Core\Routing\MatcherDumper + */ + protected $routerDumper; public static function getInfo() { return array( @@ -31,21 +50,82 @@ class DisplayPageTest extends PluginTestBase { ); } + /** + * {@inheritdoc} + */ protected function setUp() { parent::setUp(); - $this->enableViewsTestModule(); + // Setup the needed tables in order to make the drupal router working. + $this->installSchema('system', 'router'); + $this->installSchema('system', 'url_alias'); + $this->installSchema('system', 'menu_router'); + $this->installSchema('user', 'role_permission'); } /** * Checks the behavior of the page for access denied/not found behaviours. */ public function testPageResponses() { - $view = views_get_view('test_page_display'); - $this->drupalGet('test_page_display_403'); - $this->assertResponse(403); - $this->drupalGet('test_page_display_404'); - $this->assertResponse(404); + // @todo Importing a route should fire a container rebuild. + $this->container->get('router.builder')->rebuild(); + + $subrequest = Request::create('/test_page_display_403', 'GET'); + $response = $this->container->get('http_kernel')->handle($subrequest, HttpKernelInterface::SUB_REQUEST); + $this->assertEqual($response->getStatusCode(), 403); + + $subrequest = Request::create('/test_page_display_404', 'GET'); + $response = $this->container->get('http_kernel')->handle($subrequest, HttpKernelInterface::SUB_REQUEST); + $this->assertEqual($response->getStatusCode(), 404); + + $subrequest = Request::create('/test_page_display_200', 'GET'); + $response = $this->container->get('http_kernel')->handle($subrequest, HttpKernelInterface::SUB_REQUEST); + $this->assertEqual($response->getStatusCode(), 200); + } + + /** + * Checks that the router items are properly registered + */ + public function testPageRouterItems() { + $subscriber = new RouteSubscriber(); + $collection = new RouteCollection(); + $subscriber->dynamicRoutes(new RouteBuildEvent($collection, 'dynamic_routes')); + + // Check the controller defaults. + foreach ($collection as $id => $route) { + if (strpos($id, 'test_page_display_route') === 0) { + $this->assertEqual($route->getDefault('_controller'), 'Drupal\views\Routing\ViewPageController::handle'); + $this->assertEqual($route->getDefault('view_id'), 'test_page_display_route'); + $this->assertEqual($route->getDefault('display_id'), str_replace('test_page_display_route.', '', $id)); + } + } + + // Check the generated patterns and default values. + $route = $collection->get('view.test_page_display_route.page_1'); + $this->assertEqual($route->getPath(), '/test_route_without_arguments'); + + $route = $collection->get('view.test_page_display_route.page_2'); + $this->assertEqual($route->getPath(), '/test_route_with_argument/{arg_id}'); + $this->assertTrue($route->hasDefault('arg_id'), 'A default value is set for the optional argument id.'); + + $route = $collection->get('view.test_page_display_route.page_3'); + $this->assertEqual($route->getPath(), '/test_route_with_argument/{arg_id}/suffix'); + $this->assertFalse($route->hasDefault('arg_id'), 'No default value is set for the required argument id.'); + + $route = $collection->get('view.test_page_display_route.page_4'); + $this->assertEqual($route->getPath(), '/test_route_with_argument/{arg_id}/suffix/{arg_id_2}'); + $this->assertFalse($route->hasDefault('arg_id'), 'No default value is set for the required argument id.'); + $this->assertTrue($route->hasDefault('arg_id_2'), 'A default value is set for the optional argument id_2.'); + + $route = $collection->get('view.test_page_display_route.page_5'); + $this->assertEqual($route->getPath(), '/test_route_with_argument/{arg_id}/{arg_id_2}'); + $this->assertTrue($route->hasDefault('arg_id'), 'A default value is set for the optional argument id.'); + $this->assertTrue($route->hasDefault('arg_id_2'), 'A default value is set for the optional argument id_2.'); + + $route = $collection->get('view.test_page_display_route.page_6'); + $this->assertEqual($route->getPath(), '/test_route_with_argument/{arg_id}/{arg_id_2}'); + $this->assertFalse($route->hasDefault('arg_id'), 'No default value is set for the required argument id.'); + $this->assertFalse($route->hasDefault('arg_id_2'), 'No default value is set for the required argument id_2.'); } } diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageWebTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageWebTest.php new file mode 100644 index 00000000000..174cb7aef48 --- /dev/null +++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/DisplayPageWebTest.php @@ -0,0 +1,72 @@ + 'Display: Page plugin (web)', + 'description' => 'Tests the page display plugin (web).', + 'group' => 'Views Plugins', + ); + } + + protected function setUp() { + parent::setUp(); + + $this->enableViewsTestModule(); + } + + /** + * Tests arguments. + */ + public function testArguments() { + $this->drupalGet('test_route_without_arguments'); + $this->assertResponse(200); + $result = $this->xpath('//span[@class="field-content"]'); + $this->assertEqual(count($result), 5, 'All entries was returned'); + + $this->drupalGet('test_route_without_arguments/1'); + $this->assertResponse(404); + + $this->drupalGet('test_route_with_argument/1'); + $this->assertResponse(200); + $result = $this->xpath('//span[@class="field-content"]'); + $this->assertEqual(count($result), 1, 'Ensure that just the filtered entry was returned.'); + $this->assertEqual((string) $result[0], 1, 'The passed ID was returned.'); + + $this->drupalGet('test_route_with_suffix/1/suffix'); + $this->assertResponse(200); + $result = $this->xpath('//span[@class="field-content"]'); + $this->assertEqual(count($result), 1, 'Ensure that just the filtered entry was returned.'); + $this->assertEqual((string) $result[0], 1, 'The passed ID was returned.'); + + $this->drupalGet('test_route_with_suffix_and_argument/1/suffix/2'); + $this->assertResponse(200); + $result = $this->xpath('//span[@class="field-content"]'); + $this->assertEqual(count($result), 0, 'No result was returned.'); + + $this->drupalGet('test_route_with_suffix_and_argument/1/suffix/1'); + $this->assertResponse(200); + $result = $this->xpath('//span[@class="field-content"]'); + $this->assertEqual(count($result), 1, 'Ensure that just the filtered entry was returned.'); + $this->assertEqual((string) $result[0], 1, 'The passed ID was returned.'); + } + +} diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewPageControllerTest.php b/core/modules/views/lib/Drupal/views/Tests/ViewPageControllerTest.php new file mode 100644 index 00000000000..d937aea64c2 --- /dev/null +++ b/core/modules/views/lib/Drupal/views/Tests/ViewPageControllerTest.php @@ -0,0 +1,95 @@ + 'View page controller test', + 'description' => 'Tests views page controller.', + 'group' => 'Views' + ); + } + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->installSchema('system', 'menu_router'); + $this->installSchema('user', 'role_permission'); + + $this->pageController = new ViewPageController($this->container->get('plugin.manager.entity')->getStorageController('view'), new ViewExecutableFactory()); + } + + /** + * Tests the page controller. + */ + public function testPageController() { + $this->assertTrue($this->pageController instanceof ViewPageController, 'Ensure the right class is stored in the container'); + + // Pass in a non existent view. + $random_view_id = $this->randomName(); + + $request = new Request(); + $request->attributes->set('view_id', $random_view_id); + $request->attributes->set('display_id', 'default'); + try { + $this->pageController->handle($request); + $this->fail('No exception thrown on non-existing view.'); + } + + catch (NotFoundHttpException $e) { + $this->pass('Exception thrown when view was not found'); + } + + $request->attributes->set('view_id', 'test_page_view'); + $output = $this->pageController->handle($request); + $this->assertTrue(is_array($output)); + $this->assertEqual($output['#view']->storage->id, 'test_page_view', 'The right view was executed.'); + + $request->attributes->set('display_id', 'page_1'); + $output = $this->pageController->handle($request); + $this->assertTrue($output instanceof Response, 'Ensure the page display returns a response object.'); + } + +} diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewTestBase.php b/core/modules/views/lib/Drupal/views/Tests/ViewTestBase.php index 93685aa1acb..51a0c515ff7 100644 --- a/core/modules/views/lib/Drupal/views/Tests/ViewTestBase.php +++ b/core/modules/views/lib/Drupal/views/Tests/ViewTestBase.php @@ -8,6 +8,7 @@ namespace Drupal\views\Tests; use Drupal\simpletest\WebTestBase; +use Drupal\views\ViewExecutable; /** * Defines a base class for Views testing in the full web test environment. @@ -31,6 +32,10 @@ abstract class ViewTestBase extends WebTestBase { protected function setUp() { parent::setUp(); + // Ensure that the plugin definitions are cleared. + foreach (ViewExecutable::getPluginTypes() as $plugin_type) { + $this->container->get("plugin.manager.views.$plugin_type")->clearCachedDefinitions(); + } ViewTestData::importTestViews(get_class($this), array('views_test_config')); } @@ -47,6 +52,8 @@ abstract class ViewTestBase extends WebTestBase { module_enable(array('views_test_data')); $this->resetAll(); + $this->rebuildContainer(); + $this->container->get('module_handler')->reload(); // Load the test dataset. $data_set = $this->dataSet(); diff --git a/core/modules/views/lib/Drupal/views/ViewsAccessCheck.php b/core/modules/views/lib/Drupal/views/ViewsAccessCheck.php new file mode 100644 index 00000000000..b5242bfee78 --- /dev/null +++ b/core/modules/views/lib/Drupal/views/ViewsAccessCheck.php @@ -0,0 +1,37 @@ +getDefaults()); + } + + /** + * Implements AccessCheckInterface::applies(). + */ + public function access(Route $route, Request $request) { + $access = user_access('access all views'); + + return $access ?: NULL; + } + +} diff --git a/core/modules/views/tests/views_test_config/test_views/views.view.test_access_dynamic.yml b/core/modules/views/tests/views_test_config/test_views/views.view.test_access_dynamic.yml deleted file mode 100644 index 5af9c8d051c..00000000000 --- a/core/modules/views/tests/views_test_config/test_views/views.view.test_access_dynamic.yml +++ /dev/null @@ -1,33 +0,0 @@ -base_table: node -core: '8' -description: '' -status: '1' -display: - default: - display_options: - access: - type: test_dynamic - cache: - type: none - exposed_form: - type: basic - pager: - type: full - style: - type: default - row: - type: fields - display_plugin: default - display_title: Master - id: default - position: '0' - page_1: - display_options: - path: test_access_dynamic - display_plugin: page - display_title: Page - id: page_1 - position: '0' -label: '' -id: test_access_dynamic -tag: '' diff --git a/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display.yml b/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display.yml index 01f50ffc9cc..a293826d4d8 100644 --- a/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display.yml +++ b/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display.yml @@ -1,14 +1,22 @@ -base_table: node +base_table: views_test_data core: '8' description: '' status: '1' display: default: display_options: - access: - type: none - cache: - type: none + defaults: + fields: '0' + pager: '0' + pager_options: '0' + sorts: '0' + fields: + age: + field: age + id: age + relationship: none + table: views_test_data + plugin_id: numeric display_plugin: default display_title: Master id: default @@ -19,14 +27,21 @@ display: display_plugin: page display_title: Page id: page_1 - position: '0' + position: '1' page_2: display_options: path: test_page_display_404 display_plugin: page display_title: Page id: page_2 - position: '0' + position: '2' + page_3: + display_options: + path: test_page_display_200 + display_plugin: page + display_title: Page + id: page_3 + position: '3' label: '' id: test_page_display tag: '' diff --git a/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display_arguments.yml b/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display_arguments.yml new file mode 100644 index 00000000000..2ece46ed99a --- /dev/null +++ b/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display_arguments.yml @@ -0,0 +1,87 @@ +base_table: views_test_data +base_field: id +core: '8' +description: '' +status: '1' +display: + default: + display_options: + defaults: + fields: '0' + pager: '0' + pager_options: '0' + sorts: '0' + fields: + id: + id: id + field: id + table: views_test_data + plugin_id: numeric + display_plugin: default + display_title: Master + id: default + position: '0' + page_1: + display_options: + path: test_route_without_arguments + display_plugin: page + display_title: Page + id: page_1 + position: '0' + page_2: + display_options: + defaults: + arguments: '0' + arguments: + id: + field: id + id: id + relationship: none + table: views_test_data + plugin_id: numeric + path: test_route_with_argument + display_plugin: page + display_title: Page + id: page_2 + position: '0' + page_3: + display_options: + defaults: + arguments: '0' + arguments: + id: + field: id + id: id + relationship: none + table: views_test_data + plugin_id: numeric + path: test_route_with_suffix/%/suffix + display_plugin: page + display_title: Page + id: page_3 + position: '0' + page_4: + display_options: + defaults: + arguments: '0' + arguments: + id: + field: id + id: id + relationship: none + table: views_test_data + plugin_id: numeric + id_2: + field: id + id: id_2 + relationship: none + table: views_test_data + plugin_id: numeric + path: test_route_with_suffix_and_argument/%/suffix + display_plugin: page + display_title: Page + id: page_4 + position: '0' +human_name: '' +id: test_page_display_arguments +tag: '' diff --git a/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display_route.yml b/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display_route.yml new file mode 100644 index 00000000000..cdaebd2ac5b --- /dev/null +++ b/core/modules/views/tests/views_test_config/test_views/views.view.test_page_display_route.yml @@ -0,0 +1,142 @@ +base_table: views_test_data +base_field: id +core: '8' +description: '' +status: '1' +display: + default: + display_options: + defaults: + fields: '0' + pager: '0' + pager_options: '0' + sorts: '0' + fields: + id: + id: id + table: views_test_data + field: id + plugin_id: numeric + display_plugin: default + display_title: Master + id: default + position: '0' + page_1: + display_options: + path: test_route_without_arguments + display_plugin: page + display_title: Page + id: page_1 + position: '0' + page_2: + display_options: + defaults: + arguments: '0' + arguments: + id: + field: id + id: id + relationship: none + table: views_test_data + plugin_id: numeric + path: test_route_with_argument + display_plugin: page + display_title: Page + id: page_2 + position: '0' + page_3: + display_options: + defaults: + arguments: '0' + arguments: + id: + field: id + id: id + relationship: none + table: views_test_data + plugin_id: numeric + path: test_route_with_argument/%/suffix + display_plugin: page + display_title: Page + id: page_3 + position: '0' + page_4: + display_options: + defaults: + arguments: '0' + arguments: + id: + field: id + id: id + relationship: none + table: views_test_data + plugin_id: numeric + id_2: + field: id + id: id_2 + relationship: none + table: views_test_data + plugin_id: numeric + path: test_route_with_argument/%/suffix + display_plugin: page + display_title: Page + id: page_4 + position: '0' + page_5: + display_options: + defaults: + arguments: '0' + arguments: + id: + field: id + id: id + relationship: none + table: views_test_data + plugin_id: numeric + id_2: + field: id + id: id_2 + relationship: none + table: views_test_data + plugin_id: numeric + path: test_route_with_argument + display_plugin: page + display_title: Page + id: page_5 + position: '0' + page_6: + display_options: + defaults: + arguments: '0' + arguments: + id: + field: id + id: id + relationship: none + table: views_test_data + plugin_id: numeric + id_2: + field: id + id: id_2 + relationship: none + table: views_test_data + plugin_id: numeric + path: test_route_with_argument/%/% + display_plugin: page + display_title: Page + id: page_6 + position: '0' + page_7: + display_options: + defaults: + access: '0' + access: + type: test_static + path: test_route_arguments_access + display_plugin: page + display_title: Page + id: page_7 + position: '0' +human_name: '' +id: test_page_display_route +tag: '' diff --git a/core/modules/views/tests/views_test_config/test_views/views.view.test_page_view.yml b/core/modules/views/tests/views_test_config/test_views/views.view.test_page_view.yml new file mode 100644 index 00000000000..41d09e5fdf0 --- /dev/null +++ b/core/modules/views/tests/views_test_config/test_views/views.view.test_page_view.yml @@ -0,0 +1,30 @@ +base_table: views_test_data +core: '8' +description: '' +disabled: '0' +display: + default: + display_options: + defaults: + fields: '0' + pager: '0' + pager_options: '0' + sorts: '0' + fields: + age: + field: age + id: age + relationship: none + table: views_test_data + plugin_id: numeric + display_plugin: default + display_title: Master + id: default + position: '0' + page_1: + display_plugin: page + display_title: Test page view + id: page_1 +human_name: '' +id: test_page_view +tag: '' diff --git a/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/DynamicTest.php b/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/DynamicTest.php deleted file mode 100644 index b153c93be1a..00000000000 --- a/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/DynamicTest.php +++ /dev/null @@ -1,40 +0,0 @@ - FALSE, 'bool' => TRUE); - - return $options; - } - - public function access($account) { - return !empty($this->options['access']) && isset($this->view->args[0]) && $this->view->args[0] == state()->get('test_dynamic_access_argument1') && isset($this->view->args[1]) && $this->view->args[1] == state()->get('test_dynamic_access_argument2'); - } - - function get_access_callback() { - return array('views_test_data_test_dynamic_access_callback', array(!empty($options['access']), 1, 2)); - } - -} diff --git a/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/StaticTest.php b/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/StaticTest.php index 398e8d7cf7b..fe620977e4c 100644 --- a/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/StaticTest.php +++ b/core/modules/views/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/access/StaticTest.php @@ -10,6 +10,7 @@ namespace Drupal\views_test_data\Plugin\views\access; use Drupal\Component\Annotation\Plugin; use Drupal\Core\Annotation\Translation; use Drupal\views\Plugin\views\access\AccessPluginBase; +use Symfony\Component\Routing\Route; /** * Tests a static access plugin. @@ -33,8 +34,13 @@ class StaticTest extends AccessPluginBase { return !empty($this->options['access']); } - function get_access_callback() { - return array('views_test_data_test_static_access_callback', array(!empty($options['access']))); + /** + * {@inheritdoc} + */ + public function alterRouteDefinition(Route $route) { + if (!empty($this->options['access'])) { + $route->setRequirement('_access', 'TRUE'); + } } } diff --git a/core/modules/views/tests/views_test_config/test_views/views.view.test_access_static.yml b/core/modules/views/tests/views_test_data/test_views/views.view.test_access_static.yml similarity index 100% rename from core/modules/views/tests/views_test_config/test_views/views.view.test_access_static.yml rename to core/modules/views/tests/views_test_data/test_views/views.view.test_access_static.yml diff --git a/core/modules/views/tests/views_test_data/views_test_data.module b/core/modules/views/tests/views_test_data/views_test_data.module index 9dc515930e3..4dd4386f16b 100644 --- a/core/modules/views/tests/views_test_data/views_test_data.module +++ b/core/modules/views/tests/views_test_data/views_test_data.module @@ -19,14 +19,6 @@ function views_test_data_permission() { ); } -function views_test_data_test_static_access_callback($access) { - return $access; -} - -function views_test_data_test_dynamic_access_callback($access, $argument1, $argument2) { - return $access && $argument1 == state()->get('test_dynamic_access_argument1') && $argument2 == state()->get('test_dynamic_access_argument2'); -} - /** * Access callback for the generic handler test. * diff --git a/core/modules/views/views.module b/core/modules/views/views.module index 09d8c6eaaa3..99b29c02507 100644 --- a/core/modules/views/views.module +++ b/core/modules/views/views.module @@ -354,16 +354,6 @@ function views_menu_alter(&$callbacks) { // overriding) one that we removed above. $callbacks[$path] = $item; } - else { - // This item already exists, so it must be one that we added. - // We change the various callback arguments to pass an array - // of possible display IDs instead of a single ID. - $callbacks[$path]['page arguments'][1] = (array)$callbacks[$path]['page arguments'][1]; - $callbacks[$path]['page arguments'][1][] = $display_id; - $callbacks[$path]['access arguments'][] = $item['access arguments'][0]; - $callbacks[$path]['load arguments'][1] = (array)$callbacks[$path]['load arguments'][1]; - $callbacks[$path]['load arguments'][1][] = $display_id; - } $our_paths[$path] = TRUE; } } @@ -654,7 +644,6 @@ function views_field_create_instance($instance) { cache('views_info')->deleteAll(); cache('views_results')->deleteAll(); } - /** * Implements hook_field_update_instance. */ @@ -686,6 +675,13 @@ function views_invalidate_cache() { $module_handler = Drupal::moduleHandler(); + // Set the router to be rebuild. + // @todo Figure out why the cache rebuild is trigged but the route table + // does not exist yet. + if (db_table_exists('router')) { + Drupal::service('router.builder')->rebuild(); + } + // Invalidate the block cache to update views block derivatives. if ($module_handler->moduleExists('block')) { Drupal::service('plugin.manager.block')->clearCachedDefinitions(); @@ -695,68 +691,6 @@ function views_invalidate_cache() { $module_handler->invokeAll('views_invalidate_cache'); } -/** - * Determine if the logged in user has access to a view. - * - * This function should only be called from a menu hook or some other - * embedded source. Each argument is the result of a call to - * views_plugin_access::get_access_callback() which is then used - * to determine if that display is accessible. If *any* argument - * is accessible, then the view is accessible. - */ -function views_access() { - $args = func_get_args(); - foreach ($args as $arg) { - if ($arg === TRUE) { - return TRUE; - } - - if (!is_array($arg)) { - continue; - } - - list($callback, $arguments) = $arg; - $arguments = $arguments ? $arguments : array(); - // Bring dynamic arguments to the access callback. - foreach ($arguments as $key => $value) { - if (is_int($value) && isset($args[$value])) { - $arguments[$key] = $args[$value]; - } - } - if (function_exists($callback) && call_user_func_array($callback, $arguments)) { - return TRUE; - } - } - - return FALSE; -} - -/** - * Access callback for the views_plugin_access_perm access plugin. - * - * Determine if the specified user has access to a view on the basis of - * permissions. If the $account argument is omitted, the current user - * is used. - */ -function views_check_perm($perm, $account = NULL) { - return user_access($perm, $account) || user_access('access all views', $account); -} - -/** - * Access callback for the views_plugin_access_role access plugin. - - * Determine if the specified user has access to a view on the basis of any of - * the requested roles. If the $account argument is omitted, the current user - * is used. - */ -function views_check_roles($rids, $account = NULL) { - global $user; - $account = isset($account) ? $account : $user; - $roles = array_keys($account->roles); - $roles[] = $account->uid ? DRUPAL_AUTHENTICATED_RID : DRUPAL_ANONYMOUS_RID; - return user_access('access all views', $account) || array_intersect(array_filter($rids), $roles); -} - /** * Set the current 'page view' that is being displayed so that it is easy * for other modules or the theme to identify. diff --git a/core/modules/views/views.services.yml b/core/modules/views/views.services.yml index 0f4b0d2daac..1629da5e9a7 100644 --- a/core/modules/views/views.services.yml +++ b/core/modules/views/views.services.yml @@ -78,3 +78,12 @@ services: factory_method: get factory_service: cache_factory arguments: [views_results] + views.route_subscriber: + class: Drupal\views\EventSubscriber\RouteSubscriber + arguments: ['@config.factory'] + tags: + - { name: 'event_subscriber' } + views.route_access_check: + class: Drupal\views\ViewsAccessCheck + tags: + - { name: 'access_check' }