Loading core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/EntityClone.php 0 → 100644 +61 −0 Changes for core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/EntityClone.php: 61 added lines, 0 removed lines. Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\Core\Config\Action\Plugin\ConfigAction; use Drupal\Core\Config\Action\Attribute\ConfigAction; use Drupal\Core\Config\Action\ConfigActionException; use Drupal\Core\Config\Action\ConfigActionManager; use Drupal\Core\Config\Action\ConfigActionPluginInterface; use Drupal\Core\Config\ConfigManagerInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\StringTranslation\TranslatableMarkup; use Symfony\Component\DependencyInjection\ContainerInterface; /** * @internal * This API is experimental. */ #[ConfigAction( id: 'cloneAs', admin_label: new TranslatableMarkup('Clone entity with a new ID'), entity_types: ['*'], )] final class EntityClone implements ConfigActionPluginInterface, ContainerFactoryPluginInterface { public function __construct( private readonly ConfigManagerInterface $configManager, private readonly ConfigActionManager $configActionManager, ) {} /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static { return new static( $container->get(ConfigManagerInterface::class), $container->get('plugin.manager.config_action'), ); } /** * {@inheritdoc} */ public function apply(string $configName, mixed $duplicate_id): void { assert(is_string($duplicate_id)); // If the original doesn't exist, there's nothing to clone. $original = $this->configManager->loadConfigEntityByName($configName); if (empty($original)) { throw new ConfigActionException("Cannot clone '$configName' because it does not exist."); } $clone = $original->createDuplicate(); $clone->set($original->getEntityType()->getKey('id'), $duplicate_id); // Use the config action manager to invoke the `entity_create` action on // the clone, so that it will be validated. $this->configActionManager->applyAction('entity_create:createIfNotExists', $clone->getConfigDependencyName(), $clone->toArray()); } } core/tests/Drupal/KernelTests/Core/Recipe/EntityCloneConfigActionTest.php 0 → 100644 +72 −0 Changes for core/tests/Drupal/KernelTests/Core/Recipe/EntityCloneConfigActionTest.php: 72 added lines, 0 removed lines. Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\KernelTests\Core\Recipe; use Drupal\Core\Config\Action\ConfigActionException; use Drupal\KernelTests\KernelTestBase; use Drupal\Tests\user\Traits\UserCreationTrait; use Drupal\user\Entity\Role; /** * @covers \Drupal\Core\Config\Action\Plugin\ConfigAction\EntityClone * @group Recipe */ class EntityCloneConfigActionTest extends KernelTestBase { use UserCreationTrait; /** * {@inheritdoc} */ protected static $modules = ['system', 'user']; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->installConfig('user'); $this->createRole(['access user profiles'], 'test'); } /** * Tests error if original entity does not exist. */ public function testErrorIfOriginalDoesNotExist(): void { $this->expectException(ConfigActionException::class); $this->expectExceptionMessage("Cannot clone 'user.role.nope' because it does not exist."); $this->container->get('plugin.manager.config_action') ->applyAction('cloneAs', 'user.role.nope', 'user.role.yep'); } /** * Tests successful clone. */ public function testSuccessfulClone(): void { $this->container->get('plugin.manager.config_action') ->applyAction('cloneAs', 'user.role.test', 'cloned'); $clone = Role::load('cloned'); $this->assertInstanceOf(Role::class, $clone); $this->assertTrue($clone->hasPermission('access user profiles')); } /** * Tests no error is thrown when an entity with the same ID already exists. */ public function testNoErrorWithExistingEntity(): void { $this->createRole(['administer site configuration'], 'cloned'); $this->container->get('plugin.manager.config_action') ->applyAction('cloneAs', 'user.role.test', 'cloned'); $clone = Role::load('cloned'); $this->assertInstanceOf(Role::class, $clone); $this->assertTrue($clone->hasPermission('administer site configuration')); $this->assertFalse($clone->hasPermission('access user profiles')); } } Loading
core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/EntityClone.php 0 → 100644 +61 −0 Changes for core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/EntityClone.php: 61 added lines, 0 removed lines. Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\Core\Config\Action\Plugin\ConfigAction; use Drupal\Core\Config\Action\Attribute\ConfigAction; use Drupal\Core\Config\Action\ConfigActionException; use Drupal\Core\Config\Action\ConfigActionManager; use Drupal\Core\Config\Action\ConfigActionPluginInterface; use Drupal\Core\Config\ConfigManagerInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\StringTranslation\TranslatableMarkup; use Symfony\Component\DependencyInjection\ContainerInterface; /** * @internal * This API is experimental. */ #[ConfigAction( id: 'cloneAs', admin_label: new TranslatableMarkup('Clone entity with a new ID'), entity_types: ['*'], )] final class EntityClone implements ConfigActionPluginInterface, ContainerFactoryPluginInterface { public function __construct( private readonly ConfigManagerInterface $configManager, private readonly ConfigActionManager $configActionManager, ) {} /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static { return new static( $container->get(ConfigManagerInterface::class), $container->get('plugin.manager.config_action'), ); } /** * {@inheritdoc} */ public function apply(string $configName, mixed $duplicate_id): void { assert(is_string($duplicate_id)); // If the original doesn't exist, there's nothing to clone. $original = $this->configManager->loadConfigEntityByName($configName); if (empty($original)) { throw new ConfigActionException("Cannot clone '$configName' because it does not exist."); } $clone = $original->createDuplicate(); $clone->set($original->getEntityType()->getKey('id'), $duplicate_id); // Use the config action manager to invoke the `entity_create` action on // the clone, so that it will be validated. $this->configActionManager->applyAction('entity_create:createIfNotExists', $clone->getConfigDependencyName(), $clone->toArray()); } }
core/tests/Drupal/KernelTests/Core/Recipe/EntityCloneConfigActionTest.php 0 → 100644 +72 −0 Changes for core/tests/Drupal/KernelTests/Core/Recipe/EntityCloneConfigActionTest.php: 72 added lines, 0 removed lines. Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\KernelTests\Core\Recipe; use Drupal\Core\Config\Action\ConfigActionException; use Drupal\KernelTests\KernelTestBase; use Drupal\Tests\user\Traits\UserCreationTrait; use Drupal\user\Entity\Role; /** * @covers \Drupal\Core\Config\Action\Plugin\ConfigAction\EntityClone * @group Recipe */ class EntityCloneConfigActionTest extends KernelTestBase { use UserCreationTrait; /** * {@inheritdoc} */ protected static $modules = ['system', 'user']; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->installConfig('user'); $this->createRole(['access user profiles'], 'test'); } /** * Tests error if original entity does not exist. */ public function testErrorIfOriginalDoesNotExist(): void { $this->expectException(ConfigActionException::class); $this->expectExceptionMessage("Cannot clone 'user.role.nope' because it does not exist."); $this->container->get('plugin.manager.config_action') ->applyAction('cloneAs', 'user.role.nope', 'user.role.yep'); } /** * Tests successful clone. */ public function testSuccessfulClone(): void { $this->container->get('plugin.manager.config_action') ->applyAction('cloneAs', 'user.role.test', 'cloned'); $clone = Role::load('cloned'); $this->assertInstanceOf(Role::class, $clone); $this->assertTrue($clone->hasPermission('access user profiles')); } /** * Tests no error is thrown when an entity with the same ID already exists. */ public function testNoErrorWithExistingEntity(): void { $this->createRole(['administer site configuration'], 'cloned'); $this->container->get('plugin.manager.config_action') ->applyAction('cloneAs', 'user.role.test', 'cloned'); $clone = Role::load('cloned'); $this->assertInstanceOf(Role::class, $clone); $this->assertTrue($clone->hasPermission('administer site configuration')); $this->assertFalse($clone->hasPermission('access user profiles')); } }