Issue #2476563 by Gábor Hojtsy, penyaskito, amateescu: Entity operations links tied to original entity language, ignore everything else
parent
400baf1609
commit
1ae0ed8796
|
@ -386,6 +386,8 @@ abstract class ConfigEntityBase extends Entity implements ConfigEntityInterface
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function urlInfo($rel = 'edit-form', array $options = []) {
|
public function urlInfo($rel = 'edit-form', array $options = []) {
|
||||||
|
// Unless language was already provided, avoid setting an explicit language.
|
||||||
|
$options += ['language' => NULL];
|
||||||
return parent::urlInfo($rel, $options);
|
return parent::urlInfo($rel, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Definition of Drupal\config\Tests\ConfigEntityListMultilingualTest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Drupal\config\Tests;
|
||||||
|
|
||||||
|
use Drupal\simpletest\WebTestBase;
|
||||||
|
use Drupal\language\Entity\ConfigurableLanguage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the listing of configuration entities in a multilingual scenario.
|
||||||
|
*
|
||||||
|
* @group config
|
||||||
|
*/
|
||||||
|
class ConfigEntityListMultilingualTest extends WebTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modules to enable.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public static $modules = array('config_test', 'language', 'block');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
// Delete the override config_test entity. It is not required by this test.
|
||||||
|
\Drupal::entityManager()->getStorage('config_test')->load('override')->delete();
|
||||||
|
ConfigurableLanguage::createFromLangcode('hu')->save();
|
||||||
|
|
||||||
|
$this->drupalPlaceBlock('local_actions_block');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the listing UI with different language scenarios.
|
||||||
|
*/
|
||||||
|
function testListUI() {
|
||||||
|
// Log in as an administrative user to access the full menu trail.
|
||||||
|
$this->drupalLogin($this->drupalCreateUser(array('access administration pages', 'administer site configuration')));
|
||||||
|
|
||||||
|
// Get the list page.
|
||||||
|
$this->drupalGet('admin/structure/config_test');
|
||||||
|
$this->assertLinkByHref('admin/structure/config_test/manage/dotted.default');
|
||||||
|
|
||||||
|
// Add a new entity using the action link.
|
||||||
|
$this->clickLink('Add test configuration');
|
||||||
|
$edit = array(
|
||||||
|
'label' => 'Antilop',
|
||||||
|
'id' => 'antilop',
|
||||||
|
'langcode' => 'hu',
|
||||||
|
);
|
||||||
|
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||||
|
// Ensure that operations for editing the Hungarian entity appear in English.
|
||||||
|
$this->assertLinkByHref('admin/structure/config_test/manage/antilop');
|
||||||
|
|
||||||
|
// Get the list page in Hungarian and assert Hungarian admin links
|
||||||
|
// regardless of language of config entities.
|
||||||
|
$this->drupalGet('hu/admin/structure/config_test');
|
||||||
|
$this->assertLinkByHref('hu/admin/structure/config_test/manage/dotted.default');
|
||||||
|
$this->assertLinkByHref('hu/admin/structure/config_test/manage/antilop');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ namespace Drupal\config_test;
|
||||||
use Drupal\Core\Entity\EntityForm;
|
use Drupal\Core\Entity\EntityForm;
|
||||||
use Drupal\Core\Entity\Query\QueryFactory;
|
use Drupal\Core\Entity\Query\QueryFactory;
|
||||||
use Drupal\Core\Form\FormStateInterface;
|
use Drupal\Core\Form\FormStateInterface;
|
||||||
|
use Drupal\Core\Language\LanguageInterface;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,6 +127,13 @@ class ConfigTestForm extends EntityForm {
|
||||||
'#access' => !empty($size),
|
'#access' => !empty($size),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$form['langcode'] = array(
|
||||||
|
'#type' => 'language_select',
|
||||||
|
'#title' => t('Language'),
|
||||||
|
'#languages' => LanguageInterface::STATE_ALL,
|
||||||
|
'#default_value' => $entity->language()->getId(),
|
||||||
|
);
|
||||||
|
|
||||||
$form['actions'] = array('#type' => 'actions');
|
$form['actions'] = array('#type' => 'actions');
|
||||||
$form['actions']['submit'] = array(
|
$form['actions']['submit'] = array(
|
||||||
'#type' => 'submit',
|
'#type' => 'submit',
|
||||||
|
|
|
@ -9,7 +9,9 @@ namespace Drupal\views\Plugin\views\field;
|
||||||
|
|
||||||
use Drupal\Core\Entity\EntityManagerInterface;
|
use Drupal\Core\Entity\EntityManagerInterface;
|
||||||
use Drupal\Core\Form\FormStateInterface;
|
use Drupal\Core\Form\FormStateInterface;
|
||||||
|
use Drupal\Core\Language\LanguageManagerInterface;
|
||||||
use Drupal\Core\Routing\RedirectDestinationTrait;
|
use Drupal\Core\Routing\RedirectDestinationTrait;
|
||||||
|
use Drupal\views\Entity\Render\EntityTranslationRenderTrait;
|
||||||
use Drupal\views\ResultRow;
|
use Drupal\views\ResultRow;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
|
@ -22,6 +24,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
*/
|
*/
|
||||||
class EntityOperations extends FieldPluginBase {
|
class EntityOperations extends FieldPluginBase {
|
||||||
|
|
||||||
|
use EntityTranslationRenderTrait;
|
||||||
use RedirectDestinationTrait;
|
use RedirectDestinationTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,6 +34,13 @@ class EntityOperations extends FieldPluginBase {
|
||||||
*/
|
*/
|
||||||
protected $entityManager;
|
protected $entityManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The language manager.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||||
|
*/
|
||||||
|
protected $languageManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
|
@ -42,10 +52,14 @@ class EntityOperations extends FieldPluginBase {
|
||||||
* The plugin implementation definition.
|
* The plugin implementation definition.
|
||||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||||
* The entity manager.
|
* The entity manager.
|
||||||
|
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||||
|
* The language manager.
|
||||||
*/
|
*/
|
||||||
public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityManagerInterface $entity_manager) {
|
public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager) {
|
||||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||||
|
|
||||||
$this->entityManager = $entity_manager;
|
$this->entityManager = $entity_manager;
|
||||||
|
$this->languageManager = $language_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,7 +70,8 @@ class EntityOperations extends FieldPluginBase {
|
||||||
$configuration,
|
$configuration,
|
||||||
$plugin_id,
|
$plugin_id,
|
||||||
$plugin_definition,
|
$plugin_definition,
|
||||||
$container->get('entity.manager')
|
$container->get('entity.manager'),
|
||||||
|
$container->get('language_manager')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +113,7 @@ class EntityOperations extends FieldPluginBase {
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function render(ResultRow $values) {
|
public function render(ResultRow $values) {
|
||||||
$entity = $this->getEntity($values);
|
$entity = $this->getEntityTranslation($this->getEntity($values), $values);
|
||||||
$operations = $this->entityManager->getListBuilder($entity->getEntityTypeId())->getOperations($entity);
|
$operations = $this->entityManager->getListBuilder($entity->getEntityTypeId())->getOperations($entity);
|
||||||
if ($this->options['destination']) {
|
if ($this->options['destination']) {
|
||||||
foreach ($operations as &$operation) {
|
foreach ($operations as &$operation) {
|
||||||
|
@ -120,8 +135,39 @@ class EntityOperations extends FieldPluginBase {
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function query() {
|
public function query() {
|
||||||
// There is nothing to ensure or add for this handler, so we purposefully do
|
// We purposefully do not call parent::query() because we do not want the
|
||||||
// nothing here and do not call parent::query() either.
|
// default query behavior for Views fields. Instead, let the entity
|
||||||
|
// translation renderer provide the correct query behavior.
|
||||||
|
if ($this->languageManager->isMultilingual()) {
|
||||||
|
$this->getEntityTranslationRenderer()->query($this->query, $this->relationship);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getEntityTypeId() {
|
||||||
|
return $this->getEntityType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getEntityManager() {
|
||||||
|
return $this->entityManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getLanguageManager() {
|
||||||
|
return $this->languageManager;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getView() {
|
||||||
|
return $this->view;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ namespace Drupal\views\Tests\Handler;
|
||||||
|
|
||||||
use Drupal\Core\Url;
|
use Drupal\Core\Url;
|
||||||
use Drupal\entity_test\Entity\EntityTest;
|
use Drupal\entity_test\Entity\EntityTest;
|
||||||
|
use Drupal\language\Entity\ConfigurableLanguage;
|
||||||
|
use Drupal\node\Entity\Node;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the core Drupal\views\Plugin\views\field\EntityOperations handler.
|
* Tests the core Drupal\views\Plugin\views\field\EntityOperations handler.
|
||||||
|
@ -29,30 +31,62 @@ class FieldEntityOperationsTest extends HandlerTestBase {
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public static $modules = array('entity_test');
|
public static $modules = array('node', 'language');
|
||||||
|
|
||||||
|
function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
// Create Article content type.
|
||||||
|
$this->drupalCreateContentType(['type' => 'article', 'name' => 'Article']);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests entity operations field.
|
* Tests entity operations field.
|
||||||
*/
|
*/
|
||||||
public function testEntityOperations() {
|
public function testEntityOperations() {
|
||||||
// Create some test entities.
|
// Add languages and refresh the container so the entity manager will have
|
||||||
|
// fresh data.
|
||||||
|
ConfigurableLanguage::createFromLangcode('hu')->save();
|
||||||
|
ConfigurableLanguage::createFromLangcode('es')->save();
|
||||||
|
$this->rebuildContainer();
|
||||||
|
|
||||||
|
// Create some test entities. Every other entity is Hungarian while all
|
||||||
|
// have a Spanish translation.
|
||||||
|
$entities = array();
|
||||||
for ($i = 0; $i < 5; $i++) {
|
for ($i = 0; $i < 5; $i++) {
|
||||||
EntityTest::create(array(
|
$entity = Node::create([
|
||||||
'name' => $this->randomString(),
|
'title' => $this->randomString(),
|
||||||
))->save();
|
'type' => 'article',
|
||||||
|
'langcode' => $i % 2 === 0 ? 'hu' : 'en',
|
||||||
|
]);
|
||||||
|
$entity->save();
|
||||||
|
$translation = $entity->addTranslation('es');
|
||||||
|
$translation->set('title', $entity->getTitle() . ' in Spanish');
|
||||||
|
$translation->save();
|
||||||
|
$entities[$i] = $entity;
|
||||||
}
|
}
|
||||||
$entities = EntityTest::loadMultiple();
|
|
||||||
|
|
||||||
$admin_user = $this->drupalCreateUser(array('access administration pages', 'administer entity_test content'));
|
$admin_user = $this->drupalCreateUser(array('access administration pages', 'administer nodes', 'bypass node access'));
|
||||||
$this->drupalLogin($admin_user);
|
$this->drupalLogin($this->rootUser);
|
||||||
$this->drupalGet('test-entity-operations');
|
$this->drupalGet('test-entity-operations');
|
||||||
|
/** @var $entity \Drupal\entity_test\Entity\EntityTest */
|
||||||
foreach ($entities as $entity) {
|
foreach ($entities as $entity) {
|
||||||
$operations = \Drupal::entityManager()->getListBuilder('entity_test')->getOperations($entity);
|
/** @var \Drupal\Core\Language\LanguageInterface $language */
|
||||||
foreach ($operations as $operation) {
|
foreach ($entity->getTranslationLanguages() as $language) {
|
||||||
$expected_destination = Url::fromUri('internal:/test-entity-operations')->toString();
|
$entity = $entity->getTranslation($language->getId());
|
||||||
$result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[contains(@href, :path) and text()=:title]', array(':path' => $operation['url']->toString() . '?destination=' . $expected_destination, ':title' => $operation['title']));
|
$operations = \Drupal::entityManager()->getListBuilder('node')->getOperations($entity);
|
||||||
$this->assertEqual(count($result), 1, t('Found entity @operation link with destination parameter.', array('@operation' => $operation['title'])));
|
$this->assertTrue(count($operations) > 0, 'There are operations.');
|
||||||
|
foreach ($operations as $operation) {
|
||||||
|
$expected_destination = Url::fromUri('internal:/test-entity-operations')->toString();
|
||||||
|
$result = $this->xpath('//ul[contains(@class, dropbutton)]/li/a[@href=:path and text()=:title]', array(':path' => $operation['url']->toString() . '?destination=' . $expected_destination, ':title' => $operation['title']));
|
||||||
|
$this->assertEqual(count($result), 1, t('Found entity @operation link with destination parameter.', array('@operation' => $operation['title'])));
|
||||||
|
// Entities which were created in Hungarian should link to the Hungarian
|
||||||
|
// edit form, others to the English one (which has no path prefix here).
|
||||||
|
$base_path = \Drupal::request()->getBasePath();
|
||||||
|
$parts = explode('/', str_replace($base_path, '', $operation['url']->toString()));
|
||||||
|
$expected_prefix = ($language->getId() != 'en' ? $language->getId() : 'node');
|
||||||
|
$this->assertEqual($parts[1], $expected_prefix, 'Entity operation links to the correct language for the entity.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,13 @@ langcode: en
|
||||||
status: true
|
status: true
|
||||||
dependencies:
|
dependencies:
|
||||||
module:
|
module:
|
||||||
- entity_test
|
- node
|
||||||
id: test_entity_operations
|
id: test_entity_operations
|
||||||
label: test_entity_operations
|
label: test_entity_operations
|
||||||
module: views
|
module: views
|
||||||
description: ''
|
description: ''
|
||||||
tag: ''
|
tag: ''
|
||||||
base_table: entity_test
|
base_table: node_field_data
|
||||||
base_field: id
|
base_field: id
|
||||||
core: 8.x
|
core: 8.x
|
||||||
display:
|
display:
|
||||||
|
@ -35,60 +35,29 @@ display:
|
||||||
row:
|
row:
|
||||||
type: fields
|
type: fields
|
||||||
fields:
|
fields:
|
||||||
name:
|
title:
|
||||||
id: name
|
id: title
|
||||||
table: entity_test
|
table: node_field_data
|
||||||
field: name
|
field: title
|
||||||
relationship: none
|
label: Title
|
||||||
group_type: group
|
|
||||||
admin_label: ''
|
|
||||||
label: ''
|
|
||||||
exclude: false
|
exclude: false
|
||||||
alter:
|
alter:
|
||||||
alter_text: false
|
alter_text: false
|
||||||
text: ''
|
|
||||||
make_link: false
|
|
||||||
path: ''
|
|
||||||
absolute: false
|
|
||||||
external: false
|
|
||||||
replace_spaces: false
|
|
||||||
path_case: none
|
|
||||||
trim_whitespace: false
|
|
||||||
alt: ''
|
|
||||||
rel: ''
|
|
||||||
link_class: ''
|
|
||||||
prefix: ''
|
|
||||||
suffix: ''
|
|
||||||
target: ''
|
|
||||||
nl2br: false
|
|
||||||
max_length: 0
|
|
||||||
word_boundary: true
|
|
||||||
ellipsis: true
|
|
||||||
more_link: false
|
|
||||||
more_link_text: ''
|
|
||||||
more_link_path: ''
|
|
||||||
strip_tags: false
|
|
||||||
trim: false
|
|
||||||
preserve_tags: ''
|
|
||||||
html: false
|
|
||||||
element_type: ''
|
|
||||||
element_class: ''
|
element_class: ''
|
||||||
element_label_type: ''
|
|
||||||
element_label_class: ''
|
|
||||||
element_label_colon: false
|
|
||||||
element_wrapper_type: ''
|
|
||||||
element_wrapper_class: ''
|
|
||||||
element_default_classes: true
|
element_default_classes: true
|
||||||
empty: ''
|
empty: ''
|
||||||
hide_empty: false
|
hide_empty: false
|
||||||
empty_zero: false
|
empty_zero: false
|
||||||
hide_alter_empty: true
|
hide_alter_empty: true
|
||||||
entity_type: entity_test
|
entity_type: node
|
||||||
entity_field: name
|
entity_field: title
|
||||||
|
type: string
|
||||||
|
settings:
|
||||||
|
link_to_entity: true
|
||||||
plugin_id: field
|
plugin_id: field
|
||||||
operations:
|
operations:
|
||||||
id: operations
|
id: operations
|
||||||
table: entity_test
|
table: node
|
||||||
field: operations
|
field: operations
|
||||||
relationship: none
|
relationship: none
|
||||||
group_type: group
|
group_type: group
|
||||||
|
|
|
@ -24,6 +24,13 @@ class EntityOperationsUnitTest extends UnitTestCase {
|
||||||
*/
|
*/
|
||||||
protected $entityManager;
|
protected $entityManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The language manager.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||||
|
*/
|
||||||
|
protected $languageManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The plugin under test.
|
* The plugin under test.
|
||||||
*
|
*
|
||||||
|
@ -38,13 +45,14 @@ class EntityOperationsUnitTest extends UnitTestCase {
|
||||||
*/
|
*/
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
$this->entityManager = $this->getMock('\Drupal\Core\Entity\EntityManagerInterface');
|
$this->entityManager = $this->getMock('\Drupal\Core\Entity\EntityManagerInterface');
|
||||||
|
$this->languageManager = $this->getMock('\Drupal\Core\Language\LanguageManagerInterface');
|
||||||
|
|
||||||
$configuration = array();
|
$configuration = array();
|
||||||
$plugin_id = $this->randomMachineName();
|
$plugin_id = $this->randomMachineName();
|
||||||
$plugin_definition = array(
|
$plugin_definition = array(
|
||||||
'title' => $this->randomMachineName(),
|
'title' => $this->randomMachineName(),
|
||||||
);
|
);
|
||||||
$this->plugin = new EntityOperations($configuration, $plugin_id, $plugin_definition, $this->entityManager);
|
$this->plugin = new EntityOperations($configuration, $plugin_id, $plugin_definition, $this->entityManager, $this->languageManager);
|
||||||
|
|
||||||
$redirect_service = $this->getMock('Drupal\Core\Routing\RedirectDestinationInterface');
|
$redirect_service = $this->getMock('Drupal\Core\Routing\RedirectDestinationInterface');
|
||||||
$redirect_service->expects($this->any())
|
$redirect_service->expects($this->any())
|
||||||
|
|
|
@ -66,10 +66,13 @@ class EntityUrlTest extends UnitTestCase {
|
||||||
$this->assertEquals($langcode, $uri->getOption('language')->getId());
|
$this->assertEquals($langcode, $uri->getOption('language')->getId());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// The expected langcode for a config entity is 'en', because it sets the
|
if ($entity instanceof ConfigEntityInterface) {
|
||||||
// value as default property.
|
// Config entities do not provide a language with their URIs.
|
||||||
$expected_langcode = $entity instanceof ConfigEntityInterface ? 'en' : LanguageInterface::LANGCODE_NOT_SPECIFIED;
|
$this->assertEquals(NULL, $uri->getOption('language'));
|
||||||
$this->assertEquals($expected_langcode, $uri->getOption('language')->getId());
|
}
|
||||||
|
else {
|
||||||
|
$this->assertEquals(LanguageInterface::LANGCODE_NOT_SPECIFIED, $uri->getOption('language')->getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue