diff --git a/core/modules/views/lib/Drupal/views/Controller/ViewAjaxController.php b/core/modules/views/lib/Drupal/views/Controller/ViewAjaxController.php index 859c904..64abab3 100644 --- a/core/modules/views/lib/Drupal/views/Controller/ViewAjaxController.php +++ b/core/modules/views/lib/Drupal/views/Controller/ViewAjaxController.php @@ -17,6 +17,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * Defines a controller to load a view via AJAX. @@ -94,11 +95,11 @@ public function ajaxView(Request $request) { } // Load the view. - $result = $this->storageController->load(array($name)); - if (!$entity = reset($result)) { + if (!$entity = $this->storageController->load($name)) { throw new NotFoundHttpException(); } $view = $this->executableFactory->get($entity); + $response->setView($view); if ($view && $view->access($display_id)) { // Fix the current path for paging. if (!empty($path)) { @@ -131,8 +132,11 @@ public function ajaxView(Request $request) { $preview = $view->preview($display_id, $args); $response->addCommand(new ReplaceCommand(".view-dom-id-$dom_id", drupal_render($preview))); + return $response; + } + else { + throw new AccessDeniedHttpException(); } - return $response; } else { throw new NotFoundHttpException(); diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewAjaxTest.php b/core/modules/views/lib/Drupal/views/Tests/ViewAjaxTest.php new file mode 100644 index 0000000..68fdaae --- /dev/null +++ b/core/modules/views/lib/Drupal/views/Tests/ViewAjaxTest.php @@ -0,0 +1,68 @@ + 'View: Ajax', + 'description' => 'Tests the ajax view functionality.', + 'group' => 'Views' + ); + } + + protected function setUp() { + parent::setUp(); + + $this->enableViewsTestModule(); + } + + /** + * Tests an ajax view. + */ + public function testAjaxView() { + $this->drupalGet('test_ajax_view'); + + $data = array(); + $data['view_name'] = 'test_ajax_view'; + $data['view_display_id'] = 'test_ajax_view'; + + $post = 'view_name=test_ajax_view&view_display_id=page_1'; + $response = $this->curlExec(array( + CURLOPT_URL => url('views/ajax', array('absolute' => TRUE)), + CURLOPT_POST => TRUE, + CURLOPT_POSTFIELDS => $post, + CURLOPT_HTTPHEADER => array( + 'Accept: application/json', + 'Content-Type: application/x-www-form-urlencoded', + ), + )); + $data = Json::decode($response); + + // Ensure that the view insert command is part of the result. + $this->assertEqual($data[1]['command'], 'insert'); + $this->assertTrue(strpos($data[1]['selector'], '.view-dom-id-') === 0); + + $this->drupalSetContent($data[1]['data']); + $result = $this->xpath('//div[contains(@class, "views-row")]'); + $this->assertEqual(count($result), 2, 'Ensure that two items are renderd in the HTML.'); + } + +} diff --git a/core/modules/views/tests/Drupal/views/Tests/Controller/ViewAjaxControllerTest.php b/core/modules/views/tests/Drupal/views/Tests/Controller/ViewAjaxControllerTest.php new file mode 100644 index 0000000..eb6fd3c --- /dev/null +++ b/core/modules/views/tests/Drupal/views/Tests/Controller/ViewAjaxControllerTest.php @@ -0,0 +1,197 @@ + 'View: Ajax controller', + 'description' => 'Tests the views ajax controller.', + 'group' => 'Views' + ); + } + + protected function setUp() { + $this->viewStorage = $this->getMock('Drupal\Core\Entity\EntityStorageControllerInterface'); + $this->executableFactory = $this->getMockBuilder('Drupal\views\ViewExecutableFactory') + ->disableOriginalConstructor() + ->getMock(); + + $this->viewAjaxController = new ViewAjaxController($this->viewStorage, $this->executableFactory); + } + + /** + * Tests missing view_name and view_display_id + * + * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + */ + public function testMissingViewName() { + $request = new Request(); + $this->viewAjaxController->ajaxView($request); + } + + /** + * Tests with view_name and view_display_id but not existing view. + * + * @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + */ + public function testMissingView() { + $request = new Request(); + $request->request->set('view_name', 'test_view'); + $request->request->set('view_display_id', 'page_1'); + + $this->viewStorage->expects($this->once()) + ->method('load') + ->with('test_view') + ->will($this->returnValue(FALSE)); + + $this->viewAjaxController->ajaxView($request); + } + + /** + * Tests a view without having access to it. + * + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + public function testAccessDeniedView() { + $request = new Request(); + $request->request->set('view_name', 'test_view'); + $request->request->set('view_display_id', 'page_1'); + + $view = $this->getMockBuilder('Drupal\views\Entity\View') + ->disableOriginalConstructor() + ->getMock(); + + $this->viewStorage->expects($this->once()) + ->method('load') + ->with('test_view') + ->will($this->returnValue($view)); + + $executable = $this->getMockBuilder('Drupal\views\ViewExecutable') + ->disableOriginalConstructor() + ->getMock(); + $executable->expects($this->once()) + ->method('access') + ->will($this->returnValue(FALSE)); + + $this->executableFactory->staticExpects($this->once()) + ->method('get') + ->with($view) + ->will($this->returnValue($executable)); + + $this->viewAjaxController->ajaxView($request); + } + + /** + * Tests a valid view without arguments pagers etc. + */ + public function testAjaxView() { + $request = new Request(); + $request->request->set('view_name', 'test_view'); + $request->request->set('view_display_id', 'page_1'); + + list($view, $executable) = $this->setupValidMocks(); + + $response = $this->viewAjaxController->ajaxView($request); + $this->assertTrue($response instanceof ViewAjaxResponse); + + $this->assertSame($response->getView(), $executable); + } + + /** + * Sets up a bunch of valid mocks like the view entity and executable. + */ + protected function setupValidMocks() { + $view = $this->getMockBuilder('Drupal\views\Entity\View') + ->disableOriginalConstructor() + ->getMock(); + + $this->viewStorage->expects($this->once()) + ->method('load') + ->with('test_view') + ->will($this->returnValue($view)); + + $executable = $this->getMockBuilder('Drupal\views\ViewExecutable') + ->disableOriginalConstructor() + ->getMock(); + $executable->expects($this->once()) + ->method('access') + ->will($this->returnValue(TRUE)); + $executable->expects($this->once()) + ->method('preview') + ->will($this->returnValue(array('#markup' => 'View result'))); + + $this->executableFactory->staticExpects($this->once()) + ->method('get') + ->with($view) + ->will($this->returnValue($executable)); + + return array($view, $executable); + } + +} + +} + +namespace { + // @todo Remove once drupal_render got converted to autoloadable code. + if (!function_exists('drupal_static')) { + function drupal_static($key) { + return $key; + } + } + + // @todo Remove once drupal_render got converted to autoloadable code. + if (!function_exists('drupal_render')) { + function drupal_render($array) { + return isset($array['#markup']) ? $array['#markup'] : (string) $array; + } + } + +} diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_ajax_view.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_ajax_view.yml new file mode 100644 index 0000000..0bc6418 --- /dev/null +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_ajax_view.yml @@ -0,0 +1,64 @@ +base_table: views_test_data +core: '8' +description: '' +status: '1' +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 + provider: views_test_data + id: + field: id + id: id + relationship: none + table: views_test_data + plugin_id: numeric + provider: views_test_data + name: + field: name + id: name + relationship: none + table: views_test_data + plugin_id: string + provider: views_test_data + pager: + options: + offset: '0' + items_per_page: 2 + type: mini + pager_options: { } + sorts: + id: + field: id + id: id + order: ASC + relationship: none + table: views_test_data + plugin_id: numeric + provider: views_test_data + use_ajax: 1 + display_plugin: default + display_title: Master + id: default + position: '0' + page_1: + display_options: + path: test_ajax_view + display_plugin: page + display_title: Page + id: page_1 + position: '1' +label: 'Test ajax view' +id: test_ajax_view +tag: ''