Unverified Commit 74f8df5f authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3522779 by mglaman, phenaproxima, alexpott: Dispatch an event for...

Issue #3522779 by mglaman, phenaproxima, alexpott: Dispatch an event for manipulating entity data during content import

(cherry picked from commit 44799b51)
parent 43005e81
Loading
Loading
Loading
Loading
Loading
+5 −0
Changes for core/lib/Drupal/Core/DefaultContent/Importer.php: 5 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -215,6 +215,11 @@ private function toEntity(array $data): ContentEntityInterface {
      throw new ImportException('The uuid metadata must be specified.');
    }

    // Allow third-party code to modify the entity data before the entity is
    // created.
    $event = new PreEntityImportEvent($data);
    $data = ['_meta' => $event->metadata] + $this->eventDispatcher->dispatch($event)->data;

    $is_root = FALSE;
    // @see ::loadEntityDependency()
    if ($this->dependencies === NULL && !empty($data['_meta']['depends'])) {
+30 −0
Changes for core/lib/Drupal/Core/DefaultContent/PreEntityImportEvent.php: 30 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Core\DefaultContent;

use Symfony\Contracts\EventDispatcher\Event;

/**
 * Event dispatched before an entity is created during default content import.
 *
 * This event is dispatched for each entity before it is created from the
 * decoded data. Subscribers can modify the entity data (default and
 * translations) but not the metadata.
 */
final class PreEntityImportEvent extends Event {

  /**
   * The entity metadata.
   *
   * @var array<string, mixed>
   */
  public readonly array $metadata;

  public function __construct(public array $data) {
    $this->metadata = $data['_meta'];
    unset($this->data['_meta']);
  }

}
+86 −0
Changes for core/tests/Drupal/KernelTests/Core/DefaultContent/ImporterTest.php: 86 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\KernelTests\Core\DefaultContent;

use Drupal\Core\DefaultContent\Finder;
use Drupal\Core\DefaultContent\Importer;
use Drupal\Core\DefaultContent\PreEntityImportEvent;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\user\Traits\UserCreationTrait;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

/**
 * Tests the Default Content Importer.
 */
#[Group('DefaultContent')]
#[CoversClass(Importer::class)]
#[RunTestsInSeparateProcesses]
class ImporterTest extends KernelTestBase implements EventSubscriberInterface {

  use UserCreationTrait;

  /**
   * {@inheritdoc}
   */
  protected static $modules = ['system', 'user', 'entity_test'];

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();
    $this->installEntitySchema('entity_test');

    $this->container->get(EventDispatcherInterface::class)
      ->addSubscriber($this);
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents(): array {
    return [
      PreEntityImportEvent::class => 'onPreEntityImport',
    ];
  }

  /**
   * Modify entity data before it is imported.
   *
   * @param \Drupal\Core\DefaultContent\PreEntityImportEvent $event
   *   The event being handled.
   */
  public function onPreEntityImport(PreEntityImportEvent $event): void {
    self::assertSame('entity_test', $event->metadata['entity_type']);

    if ($event->metadata['uuid'] === '01234567-89ab-cdef-0123-456789abcdef') {
      $event->data['default']['name'] = [
        ['value' => 'Changed name'],
      ];
    }
    // Anything we put in `_meta` should be discarded.
    $event->data['_meta']['entity_type'] = 'This will be ignored.';
  }

  /**
   * Tests changing entity data upon import.
   */
  public function testChangeDataOnImport(): void {
    $this->setUpCurrentUser(admin: TRUE);

    $finder = new Finder($this->getDrupalRoot() . '/core/tests/fixtures/pre_entity_import_default_content');
    $this->container->get(Importer::class)->importContent($finder);

    $entity = $this->container->get(EntityRepositoryInterface::class)
      ->loadEntityByUuid('entity_test', '01234567-89ab-cdef-0123-456789abcdef');
    self::assertSame('Changed name', $entity?->label());
  }

}
+19 −0
Changes for core/tests/fixtures/pre_entity_import_default_content/entity_test/01234567-89ab-cdef-0123-456789abcdef.yml: 19 added lines, 0 removed lines.
Original line number Diff line number Diff line
_meta:
  version: '1.0'
  entity_type: entity_test
  uuid: 01234567-89ab-cdef-0123-456789abcdef
  bundle: entity_test
  default_langcode: en
default:
  name:
    -
      value: 'Test Entity One'
  created:
    -
      value: 1711638565
  user_id:
    -
      target_id: 1
  langcode:
    -
      value: en
+19 −0
Changes for core/tests/fixtures/pre_entity_import_default_content/entity_test/12345678-9abc-def0-1234-56789abcdef0.yml: 19 added lines, 0 removed lines.
Original line number Diff line number Diff line
_meta:
  version: '1.0'
  entity_type: entity_test
  uuid: 12345678-9abc-def0-1234-56789abcdef0
  bundle: entity_test
  default_langcode: en
default:
  name:
    -
      value: 'Simple Test Entity'
  created:
    -
      value: 1609459200
  user_id:
    -
      target_id: 1
  langcode:
    -
      value: en
Loading