Issue #2341357 by xjm, dawehner, larowlan, Wim Leers: Views entity area config is not deployable and missing dependencies
parent
0fb9bb5474
commit
9a5eb867cd
|
@ -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}
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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']);
|
||||
}
|
||||
|
||||
}
|
|
@ -1151,6 +1151,13 @@ class ViewUI implements ViewEntityInterface {
|
|||
return $this->storage->getConfigDependencyName();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfigTarget() {
|
||||
return $this->storage->getConfigTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue