Commit 82141437 authored by catch's avatar catch

Issue #2497017 by damiankloip, jmolivas: Views::getApplicableViews()...

Issue #2497017 by damiankloip, jmolivas: Views::getApplicableViews() initializes displays during route rebuilding etc
parent 1daf8de1
......@@ -101,9 +101,8 @@ protected function getViewsDisplayIDsWithRoute() {
// @todo Convert this method to some service.
$views = $this->getApplicableViews();
foreach ($views as $data) {
list($view, $display_id) = $data;
$id = $view->storage->id();
$this->viewsDisplayPairs[] = $id . '.' . $display_id;
list($view_id, $display_id) = $data;
$this->viewsDisplayPairs[] = $view_id . '.' . $display_id;
}
$this->viewsDisplayPairs = array_combine($this->viewsDisplayPairs, $this->viewsDisplayPairs);
}
......
......@@ -7,10 +7,12 @@
namespace Drupal\views\Plugin\Derivative;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\views\ViewEntityInterface;
use Drupal\views\Views;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -33,6 +35,13 @@ class ViewsLocalTask extends DeriverBase implements ContainerDeriverInterface {
*/
protected $state;
/**
* The view storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $viewStorage;
/**
* Constructs a \Drupal\views\Plugin\Derivative\ViewsLocalTask instance.
*
......@@ -40,10 +49,13 @@ class ViewsLocalTask extends DeriverBase implements ContainerDeriverInterface {
* The route provider.
* @param \Drupal\Core\State\StateInterface $state
* The state key value store.
* @param \Drupal\Core\Entity\EntityStorageInterface $view_storage
* The view storage.
*/
public function __construct(RouteProviderInterface $route_provider, StateInterface $state) {
public function __construct(RouteProviderInterface $route_provider, StateInterface $state, EntityStorageInterface $view_storage) {
$this->routeProvider = $route_provider;
$this->state = $state;
$this->viewStorage = $view_storage;
}
/**
......@@ -52,7 +64,8 @@ public function __construct(RouteProviderInterface $route_provider, StateInterfa
public static function create(ContainerInterface $container, $base_plugin_id) {
return new static(
$container->get('router.route_provider'),
$container->get('state')
$container->get('state'),
$container->get('entity.manager')->getStorage('view')
);
}
......@@ -65,7 +78,8 @@ public function getDerivativeDefinitions($base_plugin_definition) {
$view_route_names = $this->state->get('views.view_route_names');
foreach ($this->getApplicableMenuViews() as $pair) {
/** @var $executable \Drupal\views\ViewExecutable */
list($executable, $display_id) = $pair;
list($view_id, $display_id) = $pair;
$executable = $this->viewStorage->load($view_id)->getExecutable();
$executable->setDisplay($display_id);
$menu = $executable->display_handler->getOption('menu');
......@@ -101,8 +115,9 @@ public function alterLocalTasks(&$local_tasks) {
$view_route_names = $this->state->get('views.view_route_names');
foreach ($this->getApplicableMenuViews() as $pair) {
list($view_id, $display_id) = $pair;
/** @var $executable \Drupal\views\ViewExecutable */
list($executable, $display_id) = $pair;
$executable = $this->viewStorage->load($view_id)->getExecutable();
$executable->setDisplay($display_id);
$menu = $executable->display_handler->getOption('menu');
......
......@@ -8,14 +8,43 @@
namespace Drupal\views\Plugin\Derivative;
use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Drupal\views\Views;
use Drupal\Core\Entity\EntityStorageInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides menu links for Views.
*
* @see \Drupal\views\Plugin\Menu\ViewsMenuLink
*/
class ViewsMenuLink extends DeriverBase {
class ViewsMenuLink extends DeriverBase implements ContainerDeriverInterface {
/**
* The view storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $viewStorage;
/**
* Constructs a \Drupal\views\Plugin\Derivative\ViewsLocalTask instance.
*
* @param \Drupal\Core\Entity\EntityStorageInterface $view_storage
* The view storage.
*/
public function __construct(EntityStorageInterface $view_storage) {
$this->viewStorage = $view_storage;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, $base_plugin_id) {
return new static(
$container->get('entity.manager')->getStorage('view')
);
}
/**
* {@inheritdoc}
......@@ -23,10 +52,13 @@ class ViewsMenuLink extends DeriverBase {
public function getDerivativeDefinitions($base_plugin_definition) {
$links = array();
$views = Views::getApplicableViews('uses_menu_links');
foreach ($views as $data) {
/** @var \Drupal\views\ViewExecutable $view */
list($view, $display_id) = $data;
if ($result = $view->getMenuLinks($display_id)) {
list($view_id, $display_id) = $data;
/** @var \Drupal\views\ViewExecutable $executable */
$executable = $this->viewStorage->load($view_id)->getExecutable();
if ($result = $executable->getMenuLinks($display_id)) {
foreach ($result as $link_id => $link) {
$links[$link_id] = $link + $base_plugin_definition;
}
......
......@@ -107,13 +107,15 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
// Filter views that list the entity type we want, and group the separate
// displays by view.
$entity_type = $this->entityManager->getDefinition($this->configuration['target_type']);
$view_storage = $this->entityManager->getStorage('view');
$options = array();
foreach ($displays as $data) {
list($view, $display_id) = $data;
if (in_array($view->storage->get('base_table'), [$entity_type->getBaseTable(), $entity_type->getDataTable()])) {
$name = $view->storage->get('id');
$display = $view->storage->get('display');
$options[$name . ':' . $display_id] = $name . ' - ' . $display[$display_id]['display_title'];
list($view_id, $display_id) = $data;
$view = $view_storage->load($view_id);
if (in_array($view->get('base_table'), [$entity_type->getBaseTable(), $entity_type->getDataTable()])) {
$display = $view->get('display');
$options[$view_id . ':' . $display_id] = $view_id . ' - ' . $display[$display_id]['display_title'];
}
}
......
......@@ -194,44 +194,47 @@ public static function getEnabledDisplayExtenders() {
}
/**
* Return a list of all views and display IDs that have a particular
* Return a list of all view IDs and display IDs that have a particular
* setting in their display's plugin settings.
*
* @param string $type
* A flag from the display plugin definitions (e.g, 'uses_menu_links').
*
* @return array
* A list of arrays containing the $view and $display_id.
* A list of arrays containing the $view_id and $display_id.
* @code
* array(
* array($view, $display_id),
* array($view, $display_id),
* array($view_id, $display_id),
* array($view_id, $display_id),
* );
* @endcode
*/
public static function getApplicableViews($type) {
// Get all display plugins which provides the type.
$display_plugins = static::pluginManager('display')->getDefinitions();
$ids = array();
$plugin_ids = [];
foreach ($display_plugins as $id => $definition) {
if (!empty($definition[$type])) {
$ids[$id] = $id;
$plugin_ids[$id] = $id;
}
}
$entity_ids = \Drupal::service('entity.query')->get('view')
->condition('status', TRUE)
->condition("display.*.display_plugin", $ids, 'IN')
->condition("display.*.display_plugin", $plugin_ids, 'IN')
->execute();
$result = array();
foreach (\Drupal::entityManager()->getStorage('view')->loadMultiple($entity_ids) as $view) {
// Check each display to see if it meets the criteria and is enabled.
$executable = $view->getExecutable();
$executable->initDisplay();
foreach ($executable->displayHandlers as $id => $handler) {
if (!empty($handler->definition[$type]) && $handler->isEnabled()) {
$result[] = array($executable, $id);
foreach ($view->get('display') as $id => $display) {
// If the key doesn't exist, enabled is assumed.
$enabled = !empty($display['display_options']['enabled']) || !array_key_exists('enabled', $display['display_options']);
if ($enabled && in_array($display['display_plugin'], $plugin_ids)) {
$result[] = [$view->id(), $id];
}
}
}
......
......@@ -186,9 +186,9 @@ protected function setupMocks() {
$executable->displayHandlers = $display_collection;
$this->routeSubscriber->applicableViews = array();
$this->routeSubscriber->applicableViews[] = array($executable, 'page_1');
$this->routeSubscriber->applicableViews[] = array($executable, 'page_2');
$this->routeSubscriber->applicableViews[] = array($executable, 'page_3');
$this->routeSubscriber->applicableViews[] = array('test_id', 'page_1');
$this->routeSubscriber->applicableViews[] = array('test_id', 'page_2');
$this->routeSubscriber->applicableViews[] = array('test_id', 'page_3');
return array($executable, $view, $display_1, $display_2);
}
......
......@@ -32,6 +32,11 @@ class ViewsLocalTaskTest extends UnitTestCase {
*/
protected $state;
/**
* @var \Drupal\Core\Entity\EntityStorageInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $viewStorage;
protected $baseDefinition = array(
'class' => '\Drupal\views\Plugin\Menu\LocalTask\ViewsLocalTask',
'deriver' => '\Drupal\views\Plugin\Derivative\ViewsLocalTask'
......@@ -47,8 +52,9 @@ class ViewsLocalTaskTest extends UnitTestCase {
protected function setUp() {
$this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface');
$this->state = $this->getMock('Drupal\Core\State\StateInterface');
$this->viewStorage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
$this->localTaskDerivative = new TestViewsLocalTask($this->routeProvider, $this->state);
$this->localTaskDerivative = new TestViewsLocalTask($this->routeProvider, $this->state, $this->viewStorage);
}
/**
......@@ -81,7 +87,22 @@ public function testGetDerivativeDefinitionsWithoutLocalTask() {
->will($this->returnValue(array('type' => 'normal')));
$executable->display_handler = $display_plugin;
$result = array(array($executable, 'page_1'));
$storage = $this->getMockBuilder('Drupal\views\Entity\View')
->disableOriginalConstructor()
->getMock();
$storage->expects($this->any())
->method('id')
->will($this->returnValue('example_view'));
$storage->expects($this->any())
->method('getExecutable')
->willReturn($executable);
$this->viewStorage->expects($this->any())
->method('load')
->with('example_view')
->willReturn($storage);
$result = [['example_view', 'page_1']];
$this->localTaskDerivative->setApplicableMenuViews($result);
$definitions = $this->localTaskDerivative->getDerivativeDefinitions($this->baseDefinition);
......@@ -101,8 +122,16 @@ public function testGetDerivativeDefinitionsWithLocalTask() {
$storage->expects($this->any())
->method('id')
->will($this->returnValue('example_view'));
$storage->expects($this->any())
->method('getExecutable')
->willReturn($executable);
$executable->storage = $storage;
$this->viewStorage->expects($this->any())
->method('load')
->with('example_view')
->willReturn($storage);
$display_plugin = $this->getMockBuilder('Drupal\views\Plugin\views\display\PathPluginBase')
->setMethods(array('getOption'))
->disableOriginalConstructor()
......@@ -113,7 +142,7 @@ public function testGetDerivativeDefinitionsWithLocalTask() {
->will($this->returnValue(array('type' => 'tab', 'weight' => 12, 'title' => 'Example title')));
$executable->display_handler = $display_plugin;
$result = array(array($executable, 'page_1'));
$result = [['example_view', 'page_1']];
$this->localTaskDerivative->setApplicableMenuViews($result);
// Mock the view route names state.
......@@ -146,8 +175,16 @@ public function testGetDerivativeDefinitionsWithOverrideRoute() {
$storage->expects($this->any())
->method('id')
->will($this->returnValue('example_view'));
$storage->expects($this->any())
->method('getExecutable')
->willReturn($executable);
$executable->storage = $storage;
$this->viewStorage->expects($this->any())
->method('load')
->with('example_view')
->willReturn($storage);
$display_plugin = $this->getMockBuilder('Drupal\views\Plugin\views\display\PathPluginBase')
->setMethods(array('getOption'))
->disableOriginalConstructor()
......@@ -158,7 +195,7 @@ public function testGetDerivativeDefinitionsWithOverrideRoute() {
->will($this->returnValue(array('type' => 'tab', 'weight' => 12)));
$executable->display_handler = $display_plugin;
$result = array(array($executable, 'page_1'));
$result = [['example_view', 'page_1']];
$this->localTaskDerivative->setApplicableMenuViews($result);
// Mock the view route names state.
......@@ -187,8 +224,16 @@ public function testGetDerivativeDefinitionsWithDefaultLocalTask() {
$storage->expects($this->any())
->method('id')
->will($this->returnValue('example_view'));
$storage->expects($this->any())
->method('getExecutable')
->willReturn($executable);
$executable->storage = $storage;
$this->viewStorage->expects($this->any())
->method('load')
->with('example_view')
->willReturn($storage);
$display_plugin = $this->getMockBuilder('Drupal\views\Plugin\views\display\PathPluginBase')
->setMethods(array('getOption'))
->disableOriginalConstructor()
......@@ -199,7 +244,7 @@ public function testGetDerivativeDefinitionsWithDefaultLocalTask() {
->will($this->returnValue(array('type' => 'default tab', 'weight' => 12, 'title' => 'Example title')));
$executable->display_handler = $display_plugin;
$result = array(array($executable, 'page_1'));
$result = [['example_view', 'page_1']];
$this->localTaskDerivative->setApplicableMenuViews($result);
// Mock the view route names state.
......@@ -248,8 +293,16 @@ public function testGetDerivativeDefinitionsWithExistingLocalTask() {
$storage->expects($this->any())
->method('id')
->will($this->returnValue('example_view'));
$storage->expects($this->any())
->method('getExecutable')
->willReturn($executable);
$executable->storage = $storage;
$this->viewStorage->expects($this->any())
->method('load')
->with('example_view')
->willReturn($storage);
$display_plugin = $this->getMockBuilder('Drupal\views\Plugin\views\display\PathPluginBase')
->setMethods(array('getOption', 'getPath'))
->disableOriginalConstructor()
......@@ -263,7 +316,7 @@ public function testGetDerivativeDefinitionsWithExistingLocalTask() {
->will($this->returnValue('path/example'));
$executable->display_handler = $display_plugin;
$result = array(array($executable, 'page_1'));
$result = [['example_view', 'page_1']];
$this->localTaskDerivative->setApplicableMenuViews($result);
// Mock the view route names state.
......
......@@ -7,6 +7,7 @@
namespace Drupal\Tests\views\Unit;
use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Tests\UnitTestCase;
use Drupal\views\Views;
use Drupal\views\Entity\View;
......@@ -21,13 +22,20 @@
*/
class ViewsTest extends UnitTestCase {
/**
* The test container.
*
* @var \Drupal\Core\DependencyInjection\ContainerBuilder
*/
protected $container;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$container = new ContainerBuilder();
$this->container = new ContainerBuilder();
$user = $this->getMock('Drupal\Core\Session\AccountInterface');
$request_stack = new RequestStack();
$request_stack->push(new Request());
......@@ -35,9 +43,18 @@ protected function setUp() {
->disableOriginalConstructor()
->getMock();
$route_provider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface');
$container->set('views.executable', new ViewExecutableFactory($user, $request_stack, $views_data, $route_provider));
$this->container->set('views.executable', new ViewExecutableFactory($user, $request_stack, $views_data, $route_provider));
$this->view = new View(array('id' => 'test_view'), 'view');
\Drupal::setContainer($this->container);
}
/**
* Tests the getView() method.
*
* @covers ::getView
*/
public function testGetView() {
$view = new View(['id' => 'test_view'], 'view');
$view_storage = $this->getMockBuilder('Drupal\Core\Config\Entity\ConfigEntityStorage')
->disableOriginalConstructor()
......@@ -45,28 +62,145 @@ protected function setUp() {
$view_storage->expects($this->once())
->method('load')
->with('test_view')
->will($this->returnValue($this->view));
->will($this->returnValue($view));
$entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
$entity_manager->expects($this->once())
->method('getStorage')
->with('view')
->will($this->returnValue($view_storage));
$container->set('entity.manager', $entity_manager);
$this->container->set('entity.manager', $entity_manager);
\Drupal::setContainer($container);
$executable = Views::getView('test_view');
$this->assertInstanceOf('Drupal\views\ViewExecutable', $executable);
$this->assertEquals($view->id(), $executable->storage->id());
$this->assertEquals(spl_object_hash($view), spl_object_hash($executable->storage));
}
/**
* Tests the getView() method.
* @covers ::getApplicableViews
*
* @covers ::getView
* @dataProvider providerTestGetApplicableViews
*/
public function testGetView() {
$executable = Views::getView('test_view');
$this->assertInstanceOf('Drupal\views\ViewExecutable', $executable);
$this->assertEquals($this->view->id(), $executable->storage->id());
$this->assertEquals(spl_object_hash($this->view), spl_object_hash($executable->storage));
public function testGetApplicableViews($applicable_type, $expected) {
$view_1 = new View([
'id' => 'test_view_1',
'display' => [
'default' => [
'display_plugin' => 'default',
'display_options' => [],
],
'type_a' => [
'display_plugin' => 'type_a',
'display_options' => [],
],
],
], 'view');
$view_2 = new View([
'id' => 'test_view_2',
'display' => [
'default' => [
'display_plugin' => 'default',
'display_options' => [],
],
'type_b' => [
'display_plugin' => 'type_b',
'display_options' => [
'enabled' => TRUE,
],
],
'type_b_2' => [
'display_plugin' => 'type_b',
'display_options' => [
'enabled' => FALSE,
],
],
],
], 'view');
$view_3 = new View([
'id' => 'test_view_3',
'display' => [
'default' => [
'display_plugin' => 'default',
'display_options' => [],
],
// Test with Type A but a disabled display.
'type_a' => [
'display_plugin' => 'type_a',
'display_options' => [
'enabled' => FALSE
],
],
// Type D intentionally doesn't exist.
'type_d' => [
'display_plugin' => 'type_d',
'display_options' => [],
],
],
], 'view');
$query = $this->getMock('Drupal\Core\Entity\Query\QueryInterface');
$query->expects($this->exactly(2))
->method('condition')
->willReturnSelf();
$query->expects($this->once())
->method('execute')
->willReturn(['test_view_1', 'test_view_2', 'test_view_3']);
$view_storage = $this->getMockBuilder('Drupal\Core\Config\Entity\ConfigEntityStorage')
->disableOriginalConstructor()
->getMock();
$view_storage->expects($this->once())
->method('getQuery')
->willReturn($query);
$view_storage->expects($this->once())
->method('loadMultiple')
->with(['test_view_1', 'test_view_2', 'test_view_3'])
->will($this->returnValue(['test_view_1' => $view_1, 'test_view_2' => $view_2, 'test_view_3' => $view_3]));
$entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
$entity_manager->expects($this->exactly(2))
->method('getStorage')
->with('view')
->will($this->returnValue($view_storage));
$this->container->set('entity.manager', $entity_manager);
$definitions = [
'type_a' => [
'type_a' => TRUE,
'type_b' => FALSE,
],
'type_b' => [
'type_a' => FALSE,
'type_b' => TRUE,
],
];
$display_manager = $this->getMock('Drupal\Component\Plugin\PluginManagerInterface');
$display_manager->expects($this->once())
->method('getDefinitions')
->willReturn($definitions);
$this->container->set('plugin.manager.views.display', $display_manager);
$entity_query = new QueryFactory($entity_manager);
$this->container->set('entity.query', $entity_query);
$result = Views::getApplicableViews($applicable_type);
$this->assertEquals($expected, $result);
}
/**
* Data provider for testGetApplicableViews.
*
* @return array
*/
public function providerTestGetApplicableViews() {
return [
['type_a', [['test_view_1', 'type_a']]],
['type_b', [['test_view_2', 'type_b']]],
['type_c', []],
];
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment