Issue #2341357 by xjm, dawehner, larowlan, Wim Leers: Views entity area config is not deployable and missing dependencies

8.0.x
Alex Pott 2015-01-30 10:37:56 +00:00
parent 0fb9bb5474
commit 9a5eb867cd
16 changed files with 723 additions and 31 deletions

View File

@ -415,6 +415,17 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
return $this->getEntityType()->getConfigPrefix() . '.' . $this->id();
}
/**
* {@inheritdoc}
*/
public function getConfigTarget() {
// For configuration entities, use the config ID for the config target
// identifier. This ensures that default configuration (which does not yet
// have UUIDs) can be provided and installed with references to the target,
// and also makes config dependencies more readable.
return $this->id();
}
/**
* {@inheritdoc}
*/

View File

@ -569,4 +569,13 @@ abstract class Entity implements EntityInterface {
return $this->getEntityTypeId() . ':' . $this->bundle() . ':' . $this->uuid();
}
/**
* {@inheritdoc}
*/
public function getConfigTarget() {
// For content entities, use the UUID for the config target identifier.
// This ensures that references to the target can be deployed reliably.
return $this->uuid();
}
}

View File

@ -429,4 +429,15 @@ interface EntityInterface extends AccessibleInterface {
*/
public function getConfigDependencyName();
/**
* Gets the configuration target identifier for the entity.
*
* Used to supply the correct format for storing a reference targeting this
* entity in configuration.
*
* @return string
* The configuration target identifier.
*/
public function getConfigTarget();
}

View File

@ -12,6 +12,7 @@ use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Component\Utility\String;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\Entity\ConfigEntityType;
use Drupal\Core\DependencyInjection\ClassResolverInterface;
use Drupal\Core\Entity\Exception\AmbiguousEntityClassException;
use Drupal\Core\Entity\Exception\NoCorrespondingEntityClassException;
@ -978,6 +979,28 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
return reset($entities);
}
/**
* {@inheritdoc}
*/
public function loadEntityByConfigTarget($entity_type_id, $target) {
$entity_type = $this->getDefinition($entity_type_id);
// For configuration entities, the config target is given by the entity ID.
// @todo Consider adding a method to allow entity types to indicate the
// target identifier key rather than hard-coding this check. Issue:
// https://www.drupal.org/node/2412983.
if ($entity_type instanceof ConfigEntityType) {
$entity = $this->getStorage($entity_type_id)->load($target);
}
// For content entities, the config target is given by the UUID.
else {
$entity = $this->loadEntityByUuid($entity_type_id, $target);
}
return $entity;
}
/**
* {@inheritdoc}
*/

View File

@ -469,6 +469,26 @@ interface EntityManagerInterface extends PluginManagerInterface, EntityTypeListe
*/
public function loadEntityByUuid($entity_type_id, $uuid);
/**
* Loads an entity by the config target identifier.
*
* @param string $entity_type_id
* The entity type ID to load from.
* @param string $target
* The configuration target to load, as returned from
* \Drupal\Core\Entity\EntityInterface::getConfigTarget().
*
* @return \Drupal\Core\Entity\EntityInterface|FALSE
* The entity object, or FALSE if there is no entity with the given UUID.
*
* @throws \Drupal\Core\Entity\EntityStorageException
* Thrown if the target identifier is a UUID but the entity type does not
* support UUIDs.
*
* @see \Drupal\Core\Entity\EntityInterface::getConfigTarget()
*/
public function loadEntityByConfigTarget($entity_type_id, $target);
/**
* Returns the entity type ID based on the class that is called on.
*

View File

@ -104,7 +104,7 @@ interface EntityStorageInterface {
* An associative array where the keys are the property names and the
* values are the values those properties must have.
*
* @return array
* @return \Drupal\Core\Entity\EntityInterface[]
* An array of entity objects indexed by their ids.
*/
public function loadByProperties(array $values = array());

View File

@ -227,7 +227,7 @@ display:
admin_label: ''
empty: true
tokenize: true
entity_id: '!1'
target: '!1'
view_mode: full
bypass_access: false
plugin_id: entity

View File

@ -8,9 +8,9 @@ views.area.entity:
type: views_area
label: 'Entity'
mapping:
entity_id:
target:
type: string
label: 'ID'
label: 'The target entity'
view_mode:
type: string
label: 'View mode'

View File

@ -266,6 +266,7 @@ class View extends ConfigEntityBase implements ViewEntityInterface {
$executable = $this->getExecutable();
$executable->initDisplay();
$executable->initStyle();
$handler_types = array_keys(Views::getHandlerTypes());
foreach ($executable->displayHandlers as $display) {

View File

@ -7,9 +7,12 @@
namespace Drupal\views\Plugin\views\area;
use Drupal\Component\Uuid\Uuid;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\ViewExecutable;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides an area handler which renders an entity in a certain view mode.
@ -27,6 +30,43 @@ class Entity extends TokenizeAreaPluginBase {
*/
protected $entityType;
/**
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
*/
protected $entityManager;
/**
* Constructs a new Entity instance.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->entityManager = $entity_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity.manager')
);
}
/**
* Overrides \Drupal\views\Plugin\views\area\AreaPluginBase::init().
*/
@ -45,9 +85,10 @@ class Entity extends TokenizeAreaPluginBase {
// this handler.
$options['tokenize']['default'] = TRUE;
$options['entity_id'] = array('default' => '');
$options['view_mode'] = array('default' => 'default');
$options['bypass_access'] = array('default' => FALSE);
// Contains the config target identifier for the entity.
$options['target'] = ['default' => ''];
$options['view_mode'] = ['default' => 'default'];
$options['bypass_access'] = ['default' => FALSE];
return $options;
}
@ -60,16 +101,31 @@ class Entity extends TokenizeAreaPluginBase {
$form['view_mode'] = array(
'#type' => 'select',
'#options' => \Drupal::entityManager()->getViewModeOptions($this->entityType),
'#options' => $this->entityManager->getViewModeOptions($this->entityType),
'#title' => $this->t('View mode'),
'#default_value' => $this->options['view_mode'],
);
$form['entity_id'] = array(
'#title' => $this->t('ID'),
$label = $this->entityManager->getDefinition($this->entityType)->getLabel();
$target = $this->options['target'];
// If the target does not contain tokens, try to load the entity and
// display the entity ID to the admin form user.
// @todo Use a method to check for tokens in
// https://www.drupal.org/node/2396607.
if (strpos($this->options['target'], '{{') === FALSE && strpos($this->options['target'], '!') === FALSE && strpos($this->options['target'], '%') === FALSE && strpos($this->options['target'], '[') === FALSE) {
// @todo If the entity does not exist, this will will show the config
// target identifier. Decide if this is the correct behavior in
// https://www.drupal.org/node/2415391.
if ($target_entity = $this->entityManager->loadEntityByConfigTarget($this->entityType, $this->options['target'])) {
$target = $target_entity->id();
}
}
$form['target'] = [
'#title' => $this->t('@entity_type_label ID', ['@entity_type_label' => $label]),
'#type' => 'textfield',
'#default_value' => $this->options['entity_id'],
);
'#default_value' => $target,
];
$form['bypass_access'] = array(
'#type' => 'checkbox',
@ -79,19 +135,67 @@ class Entity extends TokenizeAreaPluginBase {
);
}
/**
* {@inheritdoc}
*/
public function submitOptionsForm(&$form, FormStateInterface $form_state) {
parent::submitOptionsForm($form, $form_state);
// Load the referenced entity and store its config target identifier if
// the target does not contains tokens.
// @todo Use a method to check for tokens in
// https://www.drupal.org/node/2396607.
$options = $form_state->getValue('options');
if (strpos($options['target'], '{{') === FALSE && strpos($options['target'], '!') === FALSE && strpos($options['target'], '%') === FALSE && strpos($options['target'], '[') === FALSE) {
if ($entity = $this->entityManager->getStorage($this->entityType)->load($options['target'])) {
$options['target'] = $entity->getConfigTarget();
}
$form_state->setValue('options', $options);
}
}
/**
* {@inheritdoc}
*/
public function render($empty = FALSE) {
if (!$empty || !empty($this->options['empty'])) {
$entity_id = $this->tokenizeValue($this->options['entity_id']);
$entity = entity_load($this->entityType, $entity_id);
if ($entity && (!empty($this->options['bypass_access']) || $entity->access('view'))) {
return entity_view($entity, $this->options['view_mode']);
// @todo Use a method to check for tokens in
// https://www.drupal.org/node/2396607.
if (strpos($this->options['target'], '{{') !== FALSE || strpos($this->options['target'], '!') !== FALSE || strpos($this->options['target'], '%') !== FALSE || strpos($this->options['target'], '[') !== FALSE) {
$target_id = $this->tokenizeValue($this->options['target']);
if ($entity = $this->entityManager->getStorage($this->entityType)->load($target_id)) {
$target_entity = $entity;
}
}
else {
if ($entity = $this->entityManager->loadEntityByConfigTarget($this->entityType, $this->options['target'])) {
$target_entity = $entity;
}
}
if (isset($target_entity) && (!empty($this->options['bypass_access']) || $target_entity->access('view'))) {
$view_builder = $this->entityManager->getViewBuilder($this->entityType);
return $view_builder->view($target_entity, $this->options['view_mode']);
}
}
return array();
return [];
}
/**
* {@inheritdoc}
*/
public function calculateDependencies() {
$dependencies = parent::calculateDependencies();
// Ensure that we don't add dependencies for placeholders.
// @todo Use a method to check for tokens in
// https://www.drupal.org/node/2396607.
if (strpos($this->options['target'], '{{') === FALSE && strpos($this->options['target'], '!') === FALSE && strpos($this->options['target'], '%') === FALSE && strpos($this->options['target'], '[') === FALSE) {
if ($entity = $this->entityManager->loadEntityByConfigTarget($this->entityType, $this->options['target'])) {
$dependencies[$this->entityManager->getDefinition($this->entityType)->getConfigDependencyKey()][] = $entity->getConfigDependencyName();
}
}
return $dependencies;
}
}

View File

@ -106,7 +106,7 @@ abstract class TokenizeAreaPluginBase extends AreaPluginBase {
*/
public function tokenizeValue($value) {
if ($this->options['tokenize']) {
$value = $this->view->style_plugin->tokenizeValue($value, 0);
$value = $this->view->getStyle()->tokenizeValue($value, 0);
}
// As we add the globalTokenForm() we also should replace the token here.
return $this->globalTokenReplace($value);

View File

@ -7,9 +7,11 @@
namespace Drupal\views\Tests\Handler;
use Drupal\block\Entity\Block;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormState;
use Drupal\views\Tests\ViewTestBase;
use Drupal\views\Entity\View;
use Drupal\views\Tests\ViewUnitTestBase;
use Drupal\views\Views;
/**
@ -18,14 +20,14 @@ use Drupal\views\Views;
* @group views
* @see \Drupal\views\Plugin\views\area\Entity
*/
class AreaEntityTest extends ViewTestBase {
class AreaEntityTest extends ViewUnitTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('entity_test');
public static $modules = ['entity_test', 'user', 'block'];
/**
* Views used by this test.
@ -34,10 +36,27 @@ class AreaEntityTest extends ViewTestBase {
*/
public static $testViews = array('test_entity_area');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
}
$this->enableViewsTestModule();
/**
* {@inheritdoc}
*/
protected function setUpFixtures() {
$this->installEntitySchema('user');
$this->installEntitySchema('entity_test');
$this->installConfig(['entity_test']);
Block::create([
'id' => 'test_block',
'plugin' => 'system_main_block',
])->save();
parent::setUpFixtures();
}
/**
@ -72,20 +91,51 @@ class AreaEntityTest extends ViewTestBase {
* Tests the area handler.
*/
public function testEntityArea() {
/** @var \Drupal\Core\Entity\EntityInterface[] $entities */
$entities = array();
for ($i = 0; $i < 3; $i++) {
$random_label = $this->randomMachineName();
$data = array('bundle' => 'entity_test', 'name' => $random_label);
$entity_test = $this->container->get('entity.manager')->getStorage('entity_test')->create($data);
$entity_test = $this->container->get('entity.manager')
->getStorage('entity_test')
->create($data);
$uuid_map[0] = 'aa0c61cb-b7bb-4795-972a-493dabcf529c';
$uuid_map[1] = '62cef0ff-6f30-4f7a-b9d6-a8ed5a3a6bf3';
$uuid_map[2] = '3161d6e9-3326-4719-b513-8fa68a731ba2';
$entity_test->uuid->value = $uuid_map[$i];
$entity_test->save();
$entities[] = $entity_test;
\Drupal::state()->set('entity_test_entity_access.view.' . $entity_test->id(), $i != 2);
\Drupal::state()
->set('entity_test_entity_access.view.' . $entity_test->id(), $i != 2);
}
$this->doTestCalculateDependencies();
$this->doTestRender($entities);
}
/**
* Tests rendering the entity area handler.
*
* @param \Drupal\Core\Entity\EntityInterface[] $entities
* The entities.
*/
public function doTestRender($entities) {
$view = Views::getView('test_entity_area');
$preview = $view->preview('default', [$entities[1]->id()]);
$this->setRawContent(\Drupal::service('renderer')->render($preview));
$result = $this->xpath('//div[@class = "view-header"]');
$this->assertTrue(strpos(trim((string) $result[0]), $entities[0]->label()) !== FALSE, 'The rendered entity appears in the header of the view.');
$this->assertTrue(strpos(trim((string) $result[0]), 'full') !== FALSE, 'The rendered entity appeared in the right view mode.');
$result = $this->xpath('//div[@class = "view-footer"]');
$this->assertTrue(strpos(trim((string) $result[0]), $entities[1]->label()) !== FALSE, 'The rendered entity appears in the footer of the view.');
$this->assertTrue(strpos(trim((string) $result[0]), 'full') !== FALSE, 'The rendered entity appeared in the right view mode.');
$preview = $view->preview('default', array($entities[1]->id()));
$this->drupalSetContent(drupal_render($preview));
$this->setRawContent(drupal_render($preview));
$result = $this->xpath('//div[@class = "view-header"]');
$this->assertTrue(strpos(trim((string) $result[0]), $entities[0]->label()) !== FALSE, 'The rendered entity appears in the header of the view.');
@ -107,7 +157,7 @@ class AreaEntityTest extends ViewTestBase {
$view->setHandler('default', 'header', 'entity_entity_test', $item);
$preview = $view->preview('default', array($entities[1]->id()));
$this->drupalSetContent(drupal_render($preview));
$this->setRawContent(drupal_render($preview));
$result = $this->xpath('//div[@class = "view-header"]');
$this->assertTrue(strpos(trim((string) $result[0]), $entities[0]->label()) !== FALSE, 'The rendered entity appears in the header of the view.');
@ -116,7 +166,7 @@ class AreaEntityTest extends ViewTestBase {
// Test entity access.
$view = Views::getView('test_entity_area');
$preview = $view->preview('default', array($entities[2]->id()));
$this->drupalSetContent(drupal_render($preview));
$this->setRawContent(drupal_render($preview));
$result = $this->xpath('//div[@class = "view-footer"]');
$this->assertTrue(strpos($result[0], $entities[2]->label()) === FALSE, 'The rendered entity does not appear in the footer of the view.');
@ -129,4 +179,18 @@ class AreaEntityTest extends ViewTestBase {
$this->assertTrue(isset($form['view_mode']['#options']['default']), 'Ensure that the default view mode is available.');
}
/**
* Tests the calculation of the rendered dependencies.
*/
public function doTestCalculateDependencies() {
$view = View::load('test_entity_area');
$dependencies = $view->calculateDependencies();
// Ensure that both config and content entity dependencies are calculated.
$this->assertEqual([
'config' => ['block.block.test_block'],
'content' => ['entity_test:entity_test:aa0c61cb-b7bb-4795-972a-493dabcf529c'],
], $dependencies);
}
}

View File

@ -1,6 +1,8 @@
langcode: und
status: true
dependencies: { }
dependencies:
content:
- entity_test:entity_test:aa0c61cb-b7bb-4795-972a-493dabcf529c
id: test_entity_area
label: ''
module: views
@ -21,7 +23,7 @@ display:
field: entity_entity_test
id: entity_entity_test
table: views
entity_id: '1'
target: 'aa0c61cb-b7bb-4795-972a-493dabcf529c'
view_mode: full
plugin_id: entity
footer:
@ -29,7 +31,14 @@ display:
field: entity_entity_test
id: entity_entity_test
table: views
entity_id: '!1'
target: '!1'
view_mode: full
plugin_id: entity
entity_block:
field: entity_block
id: entity_block
table: views
target: 'test_block'
view_mode: full
plugin_id: entity
fields:

View File

@ -0,0 +1,327 @@
<?php
/**
* @file
* Contains \Drupal\Tests\views\Unit\Plugin\area\EntityTest.
*/
namespace Drupal\Tests\views\Unit\Plugin\area;
use Drupal\Tests\UnitTestCase;
use Drupal\views\Plugin\views\area\Entity;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* @coversDefaultClass \Drupal\views\Plugin\views\area\Entity
* @group Entity
*/
class EntityTest extends UnitTestCase {
/**
* The tested entity area handler.
*
* @var \Drupal\views\Plugin\views\area\Entity
*/
protected $entityHandler;
/**
* The mocked entity manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $entityManager;
/**
* The mocked entity storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $entityStorage;
/**
* The mocked entity view builder.
*
* @var \Drupal\Core\Entity\EntityViewBuilderInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $entityViewBuilder;
/**
* The mocked view executable.
*
* @var \Drupal\views\ViewExecutable|\PHPUnit_Framework_MockObject_MockObject
*/
protected $executable;
/**
* The mocked display.
*
* @var \Drupal\views\Plugin\views\display\DisplayPluginBase|\PHPUnit_Framework_MockObject_MockObject
*/
protected $display;
/**
* The mocked style plugin.
*
* @var \Drupal\views\Plugin\views\style\StylePluginBase|\PHPUnit_Framework_MockObject_MockObject
*/
protected $stylePlugin;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
$this->entityStorage = $this->getMock('Drupal\Core\Entity\EntityStorageInterface');
$this->entityViewBuilder = $this->getMock('Drupal\Core\Entity\EntityViewBuilderInterface');
$this->executable = $this->getMockBuilder('Drupal\views\ViewExecutable')
->disableOriginalConstructor()
->getMock();
$this->display = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase')
->disableOriginalConstructor()
->getMock();
$this->stylePlugin = $this->getMockBuilder('Drupal\views\Plugin\views\style\StylePluginBase')
->disableOriginalConstructor()
->getMock();
$this->executable->style_plugin = $this->stylePlugin;
$this->entityHandler = new Entity(array(), 'entity', array('entity_type' => 'entity_test'), $this->entityManager);
$this->display->expects($this->any())
->method('getPlugin')
->with('style')
->willReturn($this->stylePlugin);
$this->executable->expects($this->any())
->method('getStyle')
->willReturn($this->stylePlugin);
$token = $this->getMockBuilder('Drupal\Core\Utility\Token')
->disableOriginalConstructor()
->getMock();
$token->expects($this->any())
->method('replace')
->willReturnArgument(0);
$container = new ContainerBuilder();
$container->set('token', $token);
\Drupal::setContainer($container);
}
/**
* Ensures that the entity manager returns an entity storage.
*/
protected function setupEntityManager() {
$this->entityManager->expects($this->any())
->method('getStorage')
->with('entity_test')
->willReturn($this->entityStorage);
$this->entityManager->expects($this->any())
->method('getViewBuilder')
->with('entity_test')
->willReturn($this->entityViewBuilder);
}
/**
* Data provider for testing different types of tokens.
*
* @return array
*/
public function providerTestTokens() {
return [
['!1', 5],
['%2', 6],
['{{ test_render_token }}', 7],
['[test:global_token]', 8],
];
}
/**
* @covers ::render
* @covers ::defineOptions
* @covers ::init
*/
public function testRenderWithId() {
$this->setupEntityManager();
$options = [
'target' => 1,
'tokenize' => FALSE,
];
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = $this->getMock('Drupal\Core\Entity\EntityInterface');
$entity->expects($this->once())
->method('access')
->willReturn(TRUE);
$this->entityStorage->expects($this->never())
->method('loadByProperties');
$this->entityManager->expects($this->any())
->method('loadEntityByConfigTarget')
->willReturn($entity);
$this->entityViewBuilder->expects($this->once())
->method('view')
->with($entity, 'default')
->willReturn(['#markup' => 'hallo']);
$this->entityHandler->init($this->executable, $this->display, $options);
$result = $this->entityHandler->render();
$this->assertEquals(['#markup' => 'hallo'], $result);
}
/**
* @covers ::render
* @covers ::defineOptions
* @covers ::init
*
* @dataProvider providerTestTokens
*/
public function testRenderWithIdAndToken($token, $id) {
$this->setupEntityManager();
$options = [
'target' => $token,
'tokenize' => TRUE,
];
$entity = $this->getMock('Drupal\Core\Entity\EntityInterface');
$entity->expects($this->once())
->method('access')
->willReturn(TRUE);
$this->stylePlugin->expects($this->once())
->method('tokenizeValue')
->with($token, 0)
->willReturn($id);
$this->entityStorage->expects($this->never())
->method('loadByProperties');
$this->entityStorage->expects($this->once())
->method('load')
->with($id)
->willReturn($entity);
$this->entityViewBuilder->expects($this->once())
->method('view')
->with($entity, 'default')
->willReturn(['#markup' => 'hallo']);
$this->entityHandler->init($this->executable, $this->display, $options);
$result = $this->entityHandler->render();
$this->assertEquals(['#markup' => 'hallo'], $result);
}
/**
* @covers ::render
* @covers ::defineOptions
* @covers ::init
*/
public function testRenderWithUuid() {
$this->setupEntityManager();
$uuid = '1d52762e-b9d8-4177-908f-572d1a5845a4';
$options = [
'target' => $uuid,
'tokenize' => FALSE,
];
$entity = $this->getMock('Drupal\Core\Entity\EntityInterface');
$entity->expects($this->once())
->method('access')
->willReturn(TRUE);
$this->entityStorage->expects($this->never())
->method('load');
$this->entityManager->expects($this->once())
->method('loadEntityByConfigTarget')
->willReturn($entity);
$this->entityViewBuilder->expects($this->once())
->method('view')
->with($entity, 'default')
->willReturn(['#markup' => 'hallo']);
$this->entityHandler->init($this->executable, $this->display, $options);
$result = $this->entityHandler->render();
$this->assertEquals(['#markup' => 'hallo'], $result);
}
/**
* @covers ::calculateDependencies
*
* @dataProvider providerTestTokens
*/
public function testCalculateDependenciesWithPlaceholder($token, $id) {
$this->setupEntityManager();
$options = [
'target' => $token,
];
$this->entityHandler->init($this->executable, $this->display, $options);
$this->assertEquals([], $this->entityHandler->calculateDependencies());
}
/**
* @covers ::calculateDependencies
*/
public function testCalculateDependenciesWithUuid() {
$this->setupEntityManager();
$uuid = '1d52762e-b9d8-4177-908f-572d1a5845a4';
$entity = $this->getMock('Drupal\Core\Entity\EntityInterface');
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
$entity->expects($this->once())
->method('getConfigDependencyName')
->willReturn('entity_test:test-bundle:1d52762e-b9d8-4177-908f-572d1a5845a4');
$this->entityStorage->expects($this->never())
->method('load');
$this->entityManager->expects($this->once())
->method('loadEntityByConfigTarget')
->willReturn($entity);
$entity_type->expects($this->once())
->method('getConfigDependencyKey')
->willReturn('content');
$this->entityManager->expects($this->once())
->method('getDefinition')
->willReturn($entity_type);
$options = [
'target' => $uuid,
];
$this->entityHandler->init($this->executable, $this->display, $options);
$this->assertEquals(['content' => ['entity_test:test-bundle:1d52762e-b9d8-4177-908f-572d1a5845a4']], $this->entityHandler->calculateDependencies());
}
/**
* @covers ::calculateDependencies
*/
public function testCalculateDependenciesWithEntityId() {
$this->setupEntityManager();
$entity = $this->getMock('Drupal\Core\Entity\EntityInterface');
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
$entity->expects($this->once())
->method('getConfigDependencyName')
->willReturn('entity_test:test-bundle:1d52762e-b9d8-4177-908f-572d1a5845a4');
$this->entityManager->expects($this->once())
->method('loadEntityByConfigTarget')
->willReturn($entity);
$this->entityStorage->expects($this->never())
->method('loadByProperties');
$entity_type->expects($this->once())
->method('getConfigDependencyKey')
->willReturn('content');
$this->entityManager->expects($this->once())
->method('getDefinition')
->willReturn($entity_type);
$options = [
'target' => 1,
];
$this->entityHandler->init($this->executable, $this->display, $options);
$this->assertEquals(['content' => ['entity_test:test-bundle:1d52762e-b9d8-4177-908f-572d1a5845a4']], $this->entityHandler->calculateDependencies());
}
}

View File

@ -0,0 +1,106 @@
<?php
/**
* @file
* Contains Drupal\views_ui\Tests\AreaEntityUITest.
*/
namespace Drupal\views_ui\Tests;
use Drupal\block\Entity\Block;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\views\Entity\View;
/**
* Tests the entity area UI test.
*
* @see \Drupal\views\Plugin\views\area\Entity
* @group views_ui
*/
class AreaEntityUITest extends UITestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['entity_test'];
public function testUI() {
// Set up a block and a entity_test entity.
$block = Block::create(['id' => 'test_id', 'plugin' => 'system_main_block']);
$block->save();
$entity_test = EntityTest::create(['bundle' => 'entity_test']);
$entity_test->save();
$default = $this->randomView([]);
$id = $default['id'];
$view = View::load($id);
$this->drupalGet($view->urlInfo('edit-form'));
// Add a global NULL argument to the view for testing argument placeholders.
$this->drupalPostForm("admin/structure/views/nojs/add-handler/$id/page_1/argument", ['name[views.null]' => 1], 'Add and configure contextual filters');
$this->drupalPostForm(NULL, [], 'Apply');
// Configure both the entity_test area header and the block header to
// reference the given entities.
$this->drupalPostForm("admin/structure/views/nojs/add-handler/$id/page_1/header", ['name[views.entity_block]' => 1], 'Add and configure header');
$this->drupalPostForm(NULL, ['options[target]' => $block->id()], 'Apply');
$this->drupalPostForm("admin/structure/views/nojs/add-handler/$id/page_1/header", ['name[views.entity_entity_test]' => 1], 'Add and configure header');
$this->drupalPostForm(NULL, ['options[target]' => $entity_test->id()], 'Apply');
$this->drupalPostForm(NULL, [], 'Save');
// Confirm the correct target identifiers were saved for both entities.
$view = View::load($id);
$header = $view->getDisplay('default')['display_options']['header'];
$this->assertEqual(['entity_block', 'entity_entity_test'], array_keys($header));
$this->assertEqual($block->id(), $header['entity_block']['target']);
$this->assertEqual($entity_test->uuid(), $header['entity_entity_test']['target']);
// Confirm that the correct serial ID (for the entity_test) and config ID
// (for the block) are displayed in the form.
$this->drupalGet("admin/structure/views/nojs/handler/$id/page_1/header/entity_block");
$this->assertFieldByName('options[target]', $block->id());
$this->drupalGet("admin/structure/views/nojs/handler/$id/page_1/header/entity_entity_test");
$this->assertFieldByName('options[target]', $entity_test->id());
// Replace the header target entities with argument placeholders.
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_block", ['options[target]' => '!1'], 'Apply');
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_entity_test", ['options[target]' => '!1'], 'Apply');
$this->drupalPostForm(NULL, [], 'Save');
// Confirm that the argument placeholders are saved.
$view = View::load($id);
$header = $view->getDisplay('default')['display_options']['header'];
$this->assertEqual(['entity_block', 'entity_entity_test'], array_keys($header));
$this->assertEqual('!1', $header['entity_block']['target']);
$this->assertEqual('!1', $header['entity_entity_test']['target']);
// Confirm that the argument placeholders are still displayed in the form.
$this->drupalGet("admin/structure/views/nojs/handler/$id/page_1/header/entity_block");
$this->assertFieldByName('options[target]', '!1');
$this->drupalGet("admin/structure/views/nojs/handler/$id/page_1/header/entity_entity_test");
$this->assertFieldByName('options[target]', '!1');
// Change the targets for both headers back to the entities.
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_block", ['options[target]' => $block->id()], 'Apply');
$this->drupalPostForm("admin/structure/views/nojs/handler/$id/page_1/header/entity_entity_test", ['options[target]' => $entity_test->id()], 'Apply');
$this->drupalPostForm(NULL, [], 'Save');
// Confirm the targets were again saved correctly and not skipped based on
// the previous form value.
$view = View::load($id);
$header = $view->getDisplay('default')['display_options']['header'];
$this->assertEqual(['entity_block', 'entity_entity_test'], array_keys($header));
$this->assertEqual($block->id(), $header['entity_block']['target']);
$this->assertEqual($entity_test->uuid(), $header['entity_entity_test']['target']);
}
}

View File

@ -1151,6 +1151,13 @@ class ViewUI implements ViewEntityInterface {
return $this->storage->getConfigDependencyName();
}
/**
* {@inheritdoc}
*/
public function getConfigTarget() {
return $this->storage->getConfigTarget();
}
/**
* {@inheritdoc}
*/