Unverified Commit 175d099d authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3540305 by phenaproxima, thejimbirch: The addComponentToLayout config...

Issue #3540305 by phenaproxima, thejimbirch: The addComponentToLayout config action should support adding multiple components

(cherry picked from commit a8c4e56c)
parent 2ffb26b0
Loading
Loading
Loading
Loading
Loading
+31 −8
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@
 */
#[ConfigAction(
  id: 'add_layout_component',
  admin_label: new TranslatableMarkup('Add component to layout'),
  admin_label: new TranslatableMarkup('Add component(s) to layout'),
  deriver: AddComponentDeriver::class,
)]
final class AddComponent implements ConfigActionPluginInterface, ContainerFactoryPluginInterface {
@@ -67,6 +67,7 @@ public function __construct(
    private readonly ConfigManagerInterface $configManager,
    private readonly UuidInterface $uuidGenerator,
    private readonly string $pluginId,
    private readonly bool $multiple,
  ) {}

  /**
@@ -78,24 +79,47 @@ public static function create(ContainerInterface $container, array $configuratio
      $container->get(ConfigManagerInterface::class),
      $container->get(UuidInterface::class),
      $plugin_id,
      $plugin_definition['multiple'],
    );
  }

  /**
   * {@inheritdoc}
   */
  public function apply(string $configName, mixed $value): void {
    assert(is_array($value));
    $section_delta = $value['section'];
    $position = $value['position'];
  public function apply(string $configName, mixed $values): void {
    assert(is_array($values));

    assert(is_int($section_delta));
    assert(is_int($position));
    if ($this->multiple) {
      assert(array_is_list($values));
    }
    else {
      $values = [$values];
    }

    $entity = $this->configManager->loadConfigEntityByName($configName);
    if (!$entity instanceof SectionListInterface) {
      throw new ConfigActionException("No entity found for applying the addComponentToLayout action.");
    }
    foreach ($values as $value) {
      $this->applySingle($entity, $value);
    }
    $entity->save();
  }

  /**
   * Adds a single component to the layout.
   *
   * @param \Drupal\layout_builder\SectionListInterface $entity
   *   The entity with a layout.
   * @param array $value
   *   The data for the config action.
   */
  private function applySingle(SectionListInterface $entity, array $value): void {
    $section_delta = $value['section'];
    $position = $value['position'];

    assert(is_int($section_delta));
    assert(is_int($position));

    $section = $entity->getSection($section_delta);
    $component = $value['component'];
@@ -127,7 +151,6 @@ public function apply(string $configName, mixed $value): void {
    $position = min($position, count($section->getComponentsByRegion($region)));
    $section->insertComponent($position, $component);
    $entity->setSection($section_delta, $section);
    $entity->save();
  }

}
+6 −1
Original line number Diff line number Diff line
@@ -41,7 +41,12 @@ public function getDerivativeDefinitions($base_plugin_definition): array {
      }
    }
    $base_plugin_definition['entity_types'] = $entity_types;
    $this->derivatives['addComponentToLayout'] = $base_plugin_definition;
    $this->derivatives['addComponentToLayout'] = $base_plugin_definition + [
      'multiple' => FALSE,
    ];
    $this->derivatives['addComponentsToLayout'] = $base_plugin_definition + [
      'multiple' => TRUE,
    ];
    return $this->derivatives;
  }

+76 −3
Original line number Diff line number Diff line
@@ -6,19 +6,25 @@

use Drupal\Core\Config\Action\ConfigActionException;
use Drupal\Core\Config\Action\ConfigActionManager;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\entity_test\EntityTestHelper;
use Drupal\KernelTests\KernelTestBase;
use Drupal\layout_builder\Plugin\ConfigAction\AddComponent;
use Drupal\layout_builder\Plugin\ConfigAction\Deriver\AddComponentDeriver;
use Drupal\layout_builder\Plugin\SectionStorage\DefaultsSectionStorage;
use Drupal\layout_builder\Section;
use Drupal\layout_builder\SectionListInterface;
use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;

/**
 * @coversDefaultClass \Drupal\layout_builder\Plugin\ConfigAction\AddComponent
 *
 * @group layout_builder
 * Tests that `addComponentToLayout` config action.
 */
#[Group('layout_builder')]
#[CoversClass(AddComponent::class)]
#[CoversClass(AddComponentDeriver::class)]
class AddComponentTest extends KernelTestBase {

  /**
@@ -398,4 +404,71 @@ public function testActionFailsIfEntityNotFound(): void {
      ]);
  }

  /**
   * Tests that the deriver produces the expected derivatives.
   */
  public function testDerivativeDefinitions(): void {
    $singular = $this->configActionManager->getDefinition('add_layout_component:addComponentToLayout');
    $plural = $this->configActionManager->getDefinition('add_layout_component:addComponentsToLayout');
    // These actions should be limited to entity types that carry section lists.
    $this->assertSame(['entity_view_display'], $singular['entity_types']);
    // The `multiple` flag should differ.
    $this->assertFalse($singular['multiple']);
    $this->assertTrue($plural['multiple']);

    // There should only be two derivatives (the singular and the plural).
    $definitions = array_filter(
      array_keys($this->configActionManager->getDefinitions()),
      fn (string $id): bool => str_starts_with($id, 'add_layout_component:'),
    );
    $this->assertCount(2, $definitions);
  }

  /**
   * Tests adding multiple components at once.
   */
  public function testAddMultipleComponents(): void {
    $uuid1 = '955493d5-f4c0-4fd1-a8aa-6bcf92d455e6';
    $uuid2 = 'b6e2f3d1-a496-426c-b0e5-eff1d14fc461';

    $this->configActionManager->applyAction(
      'addComponentsToLayout',
      'core.entity_view_display.entity_test.bundle_with_extra_fields.default',
      [
        [
          'section' => 0,
          'position' => 0,
          'component' => [
            'region' => [
              'layout_twocol_section' => 'first',
            ],
            'default_region' => 'content',
            'configuration' => [
              'id' => 'my_plugin_id',
            ],
            'uuid' => $uuid1,
          ],
        ],
        [
          'section' => 0,
          'position' => 1,
          'component' => [
            'region' => [
              'layout_twocol_section' => 'first',
            ],
            'default_region' => 'content',
            'configuration' => [
              'id' => 'my_plugin_id',
            ],
            'uuid' => $uuid2,
          ],
        ],
      ],
    );
    $display = EntityViewDisplay::load('entity_test.bundle_with_extra_fields.default');
    $components = $display?->getSection(0)->getComponents();
    $this->assertArrayHasKey($uuid1, $components);
    $this->assertArrayHasKey($uuid2, $components);
  }

}