summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDries2013-11-17 20:28:59 (GMT)
committerDries2013-11-17 20:28:59 (GMT)
commit821d3bb00bc1716d8de9b100b697fbd7bf1db9f6 (patch)
tree86e8dd01b25be1212273c517e25c6597ee99da19
parent503284a99ad016039b9f7f208cc0a11ed579add7 (diff)
Issue #2110845 by dawehner: Allow overriding views to override paths with parameters.
-rw-r--r--core/modules/views/lib/Drupal/views/Plugin/views/display/PathPluginBase.php20
-rw-r--r--core/modules/views/lib/Drupal/views/Routing/ViewPageController.php27
-rw-r--r--core/modules/views/lib/Drupal/views/Tests/ViewPageControllerTest.php94
-rw-r--r--core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php40
-rw-r--r--core/modules/views/tests/Drupal/views/Tests/Routing/ViewPageControllerTest.php265
5 files changed, 348 insertions, 98 deletions
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 ac3cb9e..51c8308 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
@@ -214,6 +214,8 @@ abstract class PathPluginBase extends DisplayPluginBase implements DisplayRouter
// Ensure that we don't override a route which is already controlled by
// views.
if (!$route->hasDefault('view_id') && ('/' . $view_path == $route_path)) {
+ $parameters = $route->compile()->getPathVariables();
+
// @todo Figure out whether we need to merge some settings (like
// requirements).
@@ -223,6 +225,24 @@ abstract class PathPluginBase extends DisplayPluginBase implements DisplayRouter
$view_id = $this->view->storage->id();
$display_id = $this->display['id'];
$route = $this->getRoute($view_id, $display_id);
+
+ $path = $route->getPath();
+ // Load the argument IDs from the view executable.
+ $view_arguments = (array) $this->view->argument;
+ $argument_ids = array_keys($view_arguments);
+
+ // Replace the path with the original parameter names and add a mapping.
+ $argument_map = array();
+ // We assume that the numeric ids of the parameters match the one from
+ // the view argument handlers.
+ foreach ($parameters as $position => $parameter_name) {
+ $path = str_replace('arg_' . $argument_ids[$position], $parameter_name, $path);
+ $argument_map['arg_' . $argument_ids[$position]] = $parameter_name;
+ }
+ // Set the corrected path and the mapping to the route object.
+ $route->setDefault('_view_argument_map', $argument_map);
+ $route->setPath($path);
+
$collection->add($name, $route);
$view_route_names[$view_id . '.' . $display_id] = $name;
}
diff --git a/core/modules/views/lib/Drupal/views/Routing/ViewPageController.php b/core/modules/views/lib/Drupal/views/Routing/ViewPageController.php
index 8da43f0..6fb4a7c 100644
--- a/core/modules/views/lib/Drupal/views/Routing/ViewPageController.php
+++ b/core/modules/views/lib/Drupal/views/Routing/ViewPageController.php
@@ -7,6 +7,7 @@
namespace Drupal\views\Routing;
+use Drupal\Component\Utility\String;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityStorageControllerInterface;
use Drupal\views\ViewExecutableFactory;
@@ -65,15 +66,37 @@ class ViewPageController implements ContainerInjectionInterface {
$entity = $this->storageController->load($view_id);
if (empty($entity)) {
- throw new NotFoundHttpException(format_string('Page controller for view %id requested, but view was not found.', array('%id' => $view_id)));
+ throw new NotFoundHttpException(String::format('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();
+ $map = $request->attributes->get('_view_argument_map', array());
foreach (array_keys((array) $view->argument) as $argument_id) {
- $arg = $request->attributes->get('arg_' . $argument_id);
+
+ // Allow parameters be pulled from the request.
+ // The map stores the actual name of the parameter in the request. Views
+ // which override existing controller, use for example 'node' instead of
+ // arg_nid as name.
+ $attribute = 'arg_' . $argument_id;
+ if (isset($map[$attribute])) {
+ $attribute = $map[$attribute];
+
+ // First try to get from the original values then on the not converted
+ // ones.
+ if ($request->attributes->has('_raw_variables')) {
+ $arg = $request->attributes->get('_raw_variables')->get($attribute);
+ }
+ else {
+ $arg = $request->attributes->get($attribute);
+ }
+ }
+ else {
+ $arg = $request->attributes->get($attribute);
+ }
+
if (isset($arg)) {
$args[] = $arg;
}
diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewPageControllerTest.php b/core/modules/views/lib/Drupal/views/Tests/ViewPageControllerTest.php
deleted file mode 100644
index d4806f0..0000000
--- a/core/modules/views/lib/Drupal/views/Tests/ViewPageControllerTest.php
+++ /dev/null
@@ -1,94 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\views\Tests\ViewPageControllerTest.
- */
-
-namespace Drupal\views\Tests;
-
-use Drupal\views\Routing\ViewPageController;
-use Drupal\views\ViewExecutableFactory;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
-
-/**
- * Tests the page controller but not the actualy execution/rendering of a view.
- *
- * @see \Drupal\views\Routing\ViewPageController
- */
-class ViewPageControllerTest extends ViewUnitTestBase {
-
- /**
- * Modules to enable.
- *
- * @var array
- */
- public static $modules = array('user');
-
- /**
- * Views used by this test.
- *
- * @var array
- */
- public static $testViews = array('test_page_view');
-
- /**
- * The page controller of views.
- *
- * @var \Drupal\views\Routing\ViewPageController
- */
- public $pageController;
-
- public static function getInfo() {
- return array(
- 'name' => 'View page controller test',
- 'description' => 'Tests views page controller.',
- 'group' => 'Views'
- );
- }
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
-
- $this->installSchema('system', array('router', 'menu_router'));
-
- $this->pageController = new ViewPageController($this->container->get('entity.manager')->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/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php b/core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php
index e7f15a8..2e2395e 100644
--- a/core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php
+++ b/core/modules/views/tests/Drupal/views/Tests/Plugin/display/PathPluginBaseTest.php
@@ -114,8 +114,8 @@ class PathPluginBaseTest extends UnitTestCase {
*/
public function testAlterRoute() {
$collection = new RouteCollection();
- $collection->add('test_route', new Route('test_route', array('_controller' => 'Drupal\Tests\Core\Controller\TestController')));
- $route_2 = new Route('test_route/example', array('_controller' => 'Drupal\Tests\Core\Controller\TestController'));
+ $collection->add('test_route', new Route('test_route', array('_controller' => 'Drupal\Tests\Core\Controller\TestController::content')));
+ $route_2 = new Route('test_route/example', array('_controller' => 'Drupal\Tests\Core\Controller\TestController::content'));
$collection->add('test_route_2', $route_2);
list($view) = $this->setupViewExecutableAccessPlugin();
@@ -146,6 +146,42 @@ class PathPluginBaseTest extends UnitTestCase {
}
/**
+ * Tests alter routes with parameters in the overriding route.
+ */
+ public function testAlterRoutesWithParameters() {
+ $collection = new RouteCollection();
+ $collection->add('test_route', new Route('test_route/{parameter}', array('_controller' => 'Drupal\Tests\Core\Controller\TestController::content')));
+
+ list($view) = $this->setupViewExecutableAccessPlugin();
+
+ // Manually setup an argument handler.
+ $argument = $this->getMockBuilder('Drupal\views\Plugin\views\argument\ArgumentPluginBase')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $view->argument['test_id'] = $argument;
+
+ $display = array();
+ $display['display_plugin'] = 'page';
+ $display['id'] = 'page_1';
+ $display['display_options'] = array(
+ 'path' => 'test_route/%',
+ );
+ $this->pathPlugin->initDisplay($view, $display);
+
+ $view_route_names = $this->pathPlugin->alterRoutes($collection);
+ $this->assertEquals(array('test_id.page_1' => 'test_route'), $view_route_names);
+
+ // Ensure that the test_route is overridden.
+ $route = $collection->get('test_route');
+ $this->assertInstanceOf('\Symfony\Component\Routing\Route', $route);
+ $this->assertEquals('test_id', $route->getDefault('view_id'));
+ $this->assertEquals('page_1', $route->getDefault('display_id'));
+ // Ensure that the path did not changed and placeholders are respected.
+ $this->assertEquals('/test_route/{parameter}', $route->getPath());
+ $this->assertEquals(array('arg_test_id' => 'parameter'), $route->getDefault('_view_argument_map'));
+ }
+
+ /**
* Returns some mocked view entity, view executable, and access plugin.
*/
protected function setupViewExecutableAccessPlugin() {
diff --git a/core/modules/views/tests/Drupal/views/Tests/Routing/ViewPageControllerTest.php b/core/modules/views/tests/Drupal/views/Tests/Routing/ViewPageControllerTest.php
new file mode 100644
index 0000000..5bcf07a
--- /dev/null
+++ b/core/modules/views/tests/Drupal/views/Tests/Routing/ViewPageControllerTest.php
@@ -0,0 +1,265 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Tests\Routing\ViewPageControllerTest.
+ */
+
+namespace Drupal\views\Tests\Routing;
+
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Routing\ViewPageController;
+use Symfony\Component\HttpFoundation\ParameterBag;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
+
+/**
+ * Tests the page controller but not the actual execution/rendering of a view.
+ *
+ * @group Drupal
+ * @group Views
+ *
+ * @see \Drupal\views\Routing\ViewPageController
+ */
+class ViewPageControllerTest extends UnitTestCase {
+
+ /**
+ * The page controller of views.
+ *
+ * @var \Drupal\views\Routing\ViewPageController
+ */
+ public $pageController;
+
+ /**
+ * The mocked view storage controller.
+ *
+ * @var \Drupal\views\ViewStorageController|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $storageController;
+
+ /**
+ * The mocked view executable factory.
+ *
+ * @var \Drupal\views\ViewExecutableFactory|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $executableFactory;
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'View page controller test',
+ 'description' => 'Tests views page controller.',
+ 'group' => 'Views'
+ );
+ }
+
+ protected function setUp() {
+ $this->storageController = $this->getMockBuilder('Drupal\views\ViewStorageController')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->executableFactory = $this->getMockBuilder('Drupal\views\ViewExecutableFactory')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->pageController = new ViewPageController($this->storageController, $this->executableFactory);
+ }
+
+ /**
+ * Tests the page controller.
+ */
+ public function testPageController() {
+ $view = $this->getMock('Drupal\views\ViewStorageInterface');
+
+ $this->storageController->expects($this->once())
+ ->method('load')
+ ->with('test_page_view')
+ ->will($this->returnValue($view));
+
+ $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $executable->expects($this->once())
+ ->method('setDisplay')
+ ->with('default');
+ $executable->expects($this->once())
+ ->method('initHandlers');
+ $executable->expects($this->once())
+ ->method('executeDisplay')
+ ->with('default', array())
+ ->will($this->returnValue(array('#markup' => 'example output')));
+
+ $this->executableFactory->staticExpects($this->any())
+ ->method('get')
+ ->with($view)
+ ->will($this->returnValue($executable));
+
+ $request = new Request();
+ $request->attributes->set('view_id', 'test_page_view');
+ $request->attributes->set('display_id', 'default');
+
+ $output = $this->pageController->handle($request);
+ $this->assertInternalType('array', $output);
+ $this->assertEquals(array('#markup' => 'example output'), $output);
+ }
+
+ /**
+ * Tests the page controller with arguments on a non overridden page view.
+ */
+ public function testHandleWithArgumentsWithoutOverridden() {
+ $view = $this->getMock('Drupal\views\ViewStorageInterface');
+
+ $this->storageController->expects($this->once())
+ ->method('load')
+ ->with('test_page_view')
+ ->will($this->returnValue($view));
+
+ $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $executable->expects($this->once())
+ ->method('setDisplay')
+ ->with('page_1');
+ $executable->expects($this->once())
+ ->method('initHandlers');
+
+ // Manually setup a argument handler.
+ $argument = $this->getMockBuilder('Drupal\views\Plugin\views\argument\ArgumentPluginBase')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $executable->argument['test_id'] = $argument;
+
+ $executable->expects($this->once())
+ ->method('executeDisplay')
+ ->with('page_1', array('test-argument'));
+
+ $this->executableFactory->staticExpects($this->any())
+ ->method('get')
+ ->with($view)
+ ->will($this->returnValue($executable));
+
+ $request = new Request();
+ $request->attributes->set('view_id', 'test_page_view');
+ $request->attributes->set('display_id', 'page_1');
+ // Add the argument to the request.
+ $request->attributes->set('arg_test_id', 'test-argument');
+
+ $this->pageController->handle($request);
+ }
+
+ /**
+ * Tests the page controller with arguments of a overridden page view.
+ *
+ * Note: This test does not care about upcasting for now.
+ */
+ public function testHandleWithArgumentsOnOveriddenRoute() {
+ $view = $this->getMock('Drupal\views\ViewStorageInterface');
+
+ $this->storageController->expects($this->once())
+ ->method('load')
+ ->with('test_page_view')
+ ->will($this->returnValue($view));
+
+ $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $executable->expects($this->once())
+ ->method('setDisplay')
+ ->with('page_1');
+ $executable->expects($this->once())
+ ->method('initHandlers');
+
+ // Manually setup a argument handler.
+ $argument = $this->getMockBuilder('Drupal\views\Plugin\views\argument\ArgumentPluginBase')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $executable->argument['test_id'] = $argument;
+
+ $executable->expects($this->once())
+ ->method('executeDisplay')
+ ->with('page_1', array('test-argument'));
+
+ $this->executableFactory->staticExpects($this->any())
+ ->method('get')
+ ->with($view)
+ ->will($this->returnValue($executable));
+
+ $request = new Request();
+ $request->attributes->set('view_id', 'test_page_view');
+ $request->attributes->set('display_id', 'page_1');
+ // Add the argument to the request.
+ $request->attributes->set('parameter', 'test-argument');
+ $request->attributes->set('_view_argument_map', array(
+ 'arg_test_id' => 'parameter',
+ ));
+
+ $this->pageController->handle($request);
+ }
+
+ /**
+ * Tests the page controller with arguments of a overridden page view.
+ *
+ * This test care about upcasted values and ensures that the raw variables
+ * are pulled in.
+ */
+ public function testHandleWithArgumentsOnOveriddenRouteWithUpcasting() {
+ $view = $this->getMock('Drupal\views\ViewStorageInterface');
+
+ $this->storageController->expects($this->once())
+ ->method('load')
+ ->with('test_page_view')
+ ->will($this->returnValue($view));
+
+ $executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $executable->expects($this->once())
+ ->method('setDisplay')
+ ->with('page_1');
+ $executable->expects($this->once())
+ ->method('initHandlers');
+
+ // Manually setup a argument handler.
+ $argument = $this->getMockBuilder('Drupal\views\Plugin\views\argument\ArgumentPluginBase')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $executable->argument['test_id'] = $argument;
+
+ $executable->expects($this->once())
+ ->method('executeDisplay')
+ ->with('page_1', array('example_id'));
+
+ $this->executableFactory->staticExpects($this->any())
+ ->method('get')
+ ->with($view)
+ ->will($this->returnValue($executable));
+
+ $request = new Request();
+ $request->attributes->set('view_id', 'test_page_view');
+ $request->attributes->set('display_id', 'page_1');
+ // Add the argument to the request.
+ $request->attributes->set('test_entity', $this->getMock('Drupal\Core\Entity\EntityInterface'));
+ $raw_variables = new ParameterBag(array('test_entity' => 'example_id'));
+ $request->attributes->set('_raw_variables', $raw_variables);
+
+ $request->attributes->set('_view_argument_map', array(
+ 'arg_test_id' => 'test_entity',
+ ));
+
+ $this->pageController->handle($request);
+ }
+
+ /**
+ * Tests handle with a non existing view.
+ *
+ * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
+ */
+ public function testHandleWithNotExistingView() {
+ // 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');
+ $this->pageController->handle($request);
+ }
+
+}