Issue #3481695 by phenaproxima, a.dmitriiev, thejimbirch, b_sharpe, alexpott: Entity displays cloning requires special config action
(cherry picked from commit a1b47eafdb
)
merge-requests/9925/head
parent
25ad53d3df
commit
9b7d24a6fa
|
@ -138,12 +138,14 @@ final class EntityMethod implements ConfigActionPluginInterface, ContainerFactor
|
|||
if ($this->numberOfRequiredParams !== 1 && $this->numberOfParams !== 1) {
|
||||
throw new EntityMethodException(sprintf('Entity method config action \'%s\' requires an array value. The number of parameters or required parameters for %s::%s() is not 1', $this->pluginId, $entity->getEntityType()->getClass(), $this->method));
|
||||
}
|
||||
$entity->{$this->method}($value);
|
||||
$result = $entity->{$this->method}($value);
|
||||
}
|
||||
else {
|
||||
$entity->{$this->method}(...$value);
|
||||
$result = $entity->{$this->method}(...$value);
|
||||
}
|
||||
return $entity;
|
||||
// If an instance of the entity (either itself, or a clone) was returned
|
||||
// by the method, return that.
|
||||
return is_a($result, get_class($entity)) ? $result : $entity;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -324,6 +324,7 @@ abstract class EntityDisplayBase extends ConfigEntityBase implements EntityDispl
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
#[ActionMethod(adminLabel: new TranslatableMarkup('Copy to another mode'), pluralize: FALSE)]
|
||||
public function createCopy($mode) {
|
||||
$display = $this->createDuplicate();
|
||||
$display->mode = $display->originalMode = $mode;
|
||||
|
@ -588,4 +589,20 @@ abstract class EntityDisplayBase extends ConfigEntityBase implements EntityDispl
|
|||
return \Drupal::logger('system');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($property_name, $value): static {
|
||||
// If changing the entity ID, also update the target entity type, bundle,
|
||||
// and view mode.
|
||||
if ($this->isNew() && $property_name === $this->getEntityType()->getKey('id')) {
|
||||
if (substr_count($value, '.') !== 2) {
|
||||
throw new \InvalidArgumentException("'$value' is not a valid entity display ID.");
|
||||
}
|
||||
[$this->targetEntityType, $this->bundle, $this->mode] = explode('.', $value);
|
||||
}
|
||||
parent::set($property_name, $value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ class LayoutBuilderEntityViewDisplayValidationTest extends ConfigEntityValidatio
|
|||
*/
|
||||
public function testImmutableProperties(array $valid_values = []): void {
|
||||
parent::testImmutableProperties([
|
||||
'id' => 'entity_test_with_bundle.two.full',
|
||||
'targetEntityType' => 'entity_test_with_bundle',
|
||||
'bundle' => 'two',
|
||||
]);
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Drupal\KernelTests\Core\Entity;
|
|||
|
||||
use Drupal\comment\Entity\CommentType;
|
||||
use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
||||
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
@ -170,4 +171,22 @@ class EntityDisplayBaseTest extends KernelTestBase {
|
|||
$this->assertSame($expected_dependencies, $entity_display->getDependencies());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that changing the entity ID updates related properties.
|
||||
*/
|
||||
public function testChangeId(): void {
|
||||
/** @var \Drupal\Core\Entity\Display\EntityDisplayInterface $display */
|
||||
$display = $this->container->get(EntityDisplayRepositoryInterface::class)
|
||||
->getViewDisplay('entity_test', 'entity_test');
|
||||
$this->assertSame('entity_test.entity_test.default', $display->id());
|
||||
$display->set('id', 'node.page.rss');
|
||||
$this->assertSame('node', $display->getTargetEntityTypeId());
|
||||
$this->assertSame('page', $display->getTargetBundle());
|
||||
$this->assertSame('rss', $display->getMode());
|
||||
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage("'a.b' is not a valid entity display ID.");
|
||||
$display->set('id', 'a.b');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -113,6 +113,7 @@ class EntityFormDisplayValidationTest extends ConfigEntityValidationTestBase {
|
|||
*/
|
||||
public function testImmutableProperties(array $valid_values = []): void {
|
||||
parent::testImmutableProperties([
|
||||
'id' => 'entity_test_with_bundle.two.default',
|
||||
'targetEntityType' => 'entity_test_with_bundle',
|
||||
'bundle' => 'two',
|
||||
]);
|
||||
|
|
|
@ -92,6 +92,7 @@ class EntityViewDisplayValidationTest extends ConfigEntityValidationTestBase {
|
|||
*/
|
||||
public function testImmutableProperties(array $valid_values = []): void {
|
||||
parent::testImmutableProperties([
|
||||
'id' => 'entity_test_with_bundle.two.full',
|
||||
'targetEntityType' => 'entity_test_with_bundle',
|
||||
'bundle' => 'two',
|
||||
]);
|
||||
|
|
|
@ -5,7 +5,10 @@ declare(strict_types=1);
|
|||
namespace Drupal\KernelTests\Core\Recipe;
|
||||
|
||||
use Drupal\Core\Config\Action\ConfigActionException;
|
||||
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
|
||||
use Drupal\Core\Extension\ModuleInstallerInterface;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
|
||||
use Drupal\Tests\user\Traits\UserCreationTrait;
|
||||
use Drupal\user\Entity\Role;
|
||||
|
||||
|
@ -15,6 +18,7 @@ use Drupal\user\Entity\Role;
|
|||
*/
|
||||
class EntityCloneConfigActionTest extends KernelTestBase {
|
||||
|
||||
use ContentTypeCreationTrait;
|
||||
use UserCreationTrait;
|
||||
|
||||
/**
|
||||
|
@ -69,4 +73,37 @@ class EntityCloneConfigActionTest extends KernelTestBase {
|
|||
$this->assertFalse($clone->hasPermission('access user profiles'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests cloning entity displays, which have specialized logic for that.
|
||||
*/
|
||||
public function testCloneEntityDisplay(): void {
|
||||
$this->container->get(ModuleInstallerInterface::class)->install(['node']);
|
||||
$this->createContentType(['type' => 'alpha']);
|
||||
$this->createContentType(['type' => 'beta']);
|
||||
|
||||
/** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
|
||||
$display_repository = $this->container->get(EntityDisplayRepositoryInterface::class);
|
||||
// Create the default view displays for each node type.
|
||||
$display_repository->getViewDisplay('node', 'alpha')->save();
|
||||
$display_repository->getViewDisplay('node', 'beta')->save();
|
||||
|
||||
// Ensure the `rss` displays don't exist yet.
|
||||
$this->assertTrue($display_repository->getViewDisplay('node', 'alpha', 'rss')->isNew());
|
||||
$this->assertTrue($display_repository->getViewDisplay('node', 'beta', 'rss')->isNew());
|
||||
// Use the action to clone the default view displays to the `rss` view mode.
|
||||
/** @var \Drupal\Core\Config\Action\ConfigActionManager $manager */
|
||||
$manager = $this->container->get('plugin.manager.config_action');
|
||||
$manager->applyAction('cloneAs', 'core.entity_view_display.node.alpha.default', 'node.alpha.rss');
|
||||
$manager->applyAction('entity_method:core.entity_view_display:createCopy', 'core.entity_view_display.node.beta.default', 'rss');
|
||||
$this->assertFalse($display_repository->getViewDisplay('node', 'alpha', 'rss')->isNew());
|
||||
$this->assertFalse($display_repository->getViewDisplay('node', 'beta', 'rss')->isNew());
|
||||
|
||||
// Ensure that this also works with wildcards.
|
||||
$this->assertTrue($display_repository->getViewDisplay('node', 'alpha', 'search_result')->isNew());
|
||||
$this->assertTrue($display_repository->getViewDisplay('node', 'beta', 'search_result')->isNew());
|
||||
$manager->applyAction('entity_method:core.entity_view_display:createCopy', 'core.entity_view_display.node.*.default', 'search_result');
|
||||
$this->assertFalse($display_repository->getViewDisplay('node', 'alpha', 'search_result')->isNew());
|
||||
$this->assertFalse($display_repository->getViewDisplay('node', 'beta', 'search_result')->isNew());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace Drupal\Tests\Core\Config\Entity;
|
||||
|
||||
use Drupal\Core\Entity\EntityDisplayBase;
|
||||
use Drupal\Core\Entity\EntityType;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
|
@ -25,6 +26,7 @@ class EntityDisplayBaseTest extends UnitTestCase {
|
|||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->entityDisplay = $this->getMockBuilder(EntityDisplayBaseMockableClass::class)
|
||||
->disableOriginalConstructor()
|
||||
->onlyMethods([])
|
||||
|
@ -91,4 +93,13 @@ class EntityDisplayBaseMockableClass extends EntityDisplayBase {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
public function getEntityType() {
|
||||
return new EntityType([
|
||||
'id' => 'entity_view_display',
|
||||
'entity_keys' => [
|
||||
'id' => 'id',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue