devel_wizard-2.x-dev/src/Plugin/DevelWizard/Spell/ConfigEntityMigrationSpellBase.php

src/Plugin/DevelWizard/Spell/ConfigEntityMigrationSpellBase.php
<?php

declare(strict_types=1);

namespace Drupal\devel_wizard\Plugin\DevelWizard\Spell;

use Drupal\Component\Serialization\Yaml;
use Drupal\Component\Utility\Random;
use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleExtensionList;
use Drupal\Core\Extension\ModuleInstallerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Template\TwigEnvironment;
use Drupal\devel_wizard\ShellProcessFactoryInterface;
use Drupal\devel_wizard\Spell\SpellManagerInterface;
use Drupal\devel_wizard\Spell\SpellTraitPackageManager;
use Drupal\devel_wizard\Utils;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Path;

abstract class ConfigEntityMigrationSpellBase extends ConfigEntitySpellBase {

  use SpellTraitPackageManager;

  protected SpellManagerInterface $spellManager;

  protected TwigEnvironment $twig;

  protected UuidInterface $uuid;

  protected string $sitePath;

  protected Random $random;

  protected Filesystem $fs;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('messenger'),
      $container->get('logger.channel.devel_wizard_spell'),
      $container->get('string_translation'),
      $container->get('devel_wizard.utils'),
      $container->get('entity_type.manager'),
      $container->get('config.factory'),
      $container->get('plugin.manager.devel_wizard.spell'),
      $container->get('devel_wizard.shell_process_factory'),
      $container->get('extension.list.module'),
      $container->get('module_installer'),
      $container->get('twig'),
      $container->get('uuid'),
      $container->getParameter('site.path'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    MessengerInterface $messenger,
    LoggerInterface $logger,
    TranslationInterface $stringTranslation,
    Utils $utils,
    EntityTypeManagerInterface $entityTypeManager,
    ConfigFactoryInterface $configFactory,
    SpellManagerInterface $spellManager,
    ShellProcessFactoryInterface $shellProcessFactory,
    ModuleExtensionList $moduleList,
    ModuleInstallerInterface $moduleInstaller,
    TwigEnvironment $twig,
    UuidInterface $uuid,
    string $sitePath,
    ?Filesystem $fs = NULL,
    ?Random $random = NULL
  ) {
    $this->entityTypeManager = $entityTypeManager;
    $this->spellManager = $spellManager;
    $this->shellProcessFactory = $shellProcessFactory;
    $this->moduleList = $moduleList;
    $this->moduleInstaller = $moduleInstaller;
    $this->twig = $twig;
    $this->uuid = $uuid;
    $this->sitePath = $sitePath;
    $this->fs = $fs ?: new Filesystem();
    $this->random = $random ?: new Random();

    parent::__construct(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $messenger,
      $logger,
      $stringTranslation,
      $utils,
      $configFactory,
    );
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return [
      'machine_name' => '',
      'migration_module' => 'app_dc',
      'migration_group' => 'app_dummy',
    ];
  }

  protected function populateCalculatedConfigurationValues(): static {
    parent::populateCalculatedConfigurationValues();

    if (empty($this->configuration['machine_name'])) {
      throw new \InvalidArgumentException('machine_name is required');
    }

    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $configuration = $this->getConfiguration();
    $configEntityType = $this->getConfigEntityType();

    $form['machine_name'] = [
      '#type' => 'textfield',
      '#required' => TRUE,
      '#title' => $configEntityType?->getLabel() ?: $this->t('Bundle'),
      '#description' => $this->t(
        'The machine-name of the @entity_type.label to create the migration for.',
        [
          '@entity_type.label' => $configEntityType?->getLabel() ?: $this->t('Config Entity'),
        ],
      ),
      '#default_value' => $configuration['machine_name'],
      '#autocomplete_route_name' => 'devel_wizard.autocomplete.config_entity_instance',
      '#autocomplete_route_parameters' => [
        'entityTypeId' => $this->configEntityTypeId,
      ],
    ];

    $form['migration_module'] = [
      '#title' => $this->t('Migration module'),
      '#type' => 'textfield',
      '#required' => TRUE,
      '#default_value' => $configuration['migration_module'],
      '#description' => $this->t('A custom module machine-name where migration definition YAML files will be placed, under {machine-name}/config/install folder.'),
      '#autocomplete_route_name' => 'devel_wizard.autocomplete.module',
    ];

    $form['migration_group'] = [
      '#title' => $this->t('Migration group'),
      '#type' => 'textfield',
      '#required' => TRUE,
      '#default_value' => $configuration['migration_group'],
      '#description' => $this->t('A name for the migration group eg: app_dummy, app_default.'),
      '#autocomplete_route_name' => 'devel_wizard.autocomplete.config_entity_instance',
      '#autocomplete_route_parameters' => ['entityTypeId' => 'migration_group'],
    ];

    return $form;
  }

  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
    // @todo Implement validateConfigurationForm() method.
  }

  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValue($form['#parents'], []);
    $this->setConfiguration($values);
  }

  /**
   * @throws \Twig\Error\Error
   */
  protected function doIt(): static {
    if (!isset($this->batchContext['sandbox']['current_step'])) {
      $this->batchContext['sandbox']['current_step'] = 'composer_packages_require';
    }

    switch ($this->batchContext['sandbox']['current_step']) {
      case 'composer_packages_require':
        $this->doItComposerRequire();
        drupal_flush_all_caches();

        $this->batchContext['message'] = $this->t('Create migration related modules');
        $this->batchContext['sandbox']['current_step'] = 'module_create';
        $this->batchContext['sandbox']['finished'] = 0.4;
        break;

      case 'module_create':
        $this->doItModuleCreate();
        drupal_flush_all_caches();

        $this->batchContext['message'] = $this->t('Enable migration related modules');
        $this->batchContext['sandbox']['current_step'] = 'module_install';
        $this->batchContext['sandbox']['finished'] = 0.5;

        break;

      case 'module_install':
        $this->doItModuleInstall();
        drupal_flush_all_caches();

        $this->batchContext['message'] = $this->t('Create migration definitions and dummy data sources.');
        $this->batchContext['sandbox']['current_step'] = 'migration_create';
        $this->batchContext['sandbox']['finished'] = 0.8;
        break;

      case 'migration_create':
        $this->doItMigrationCreate();
        drupal_flush_all_caches();

        $this->batchContext['sandbox']['current_step'] = '_finished';
        $this->batchContext['sandbox']['finished'] = 1.0;
        break;

      case '_finished':
        $this->batchContext['sandbox']['finished'] = 1.0;
        break;
    }

    return $this;
  }

  protected function doItComposerRequire(): static {
    $this->installComposerPackages('prod', $this->getRequiredPackagesProd());
    $this->installComposerPackages('dev', $this->getRequiredPackagesDev());

    return $this;
  }

  protected function doItModuleCreate(): static {
    // @todo Implement this step as "sub_spell".
    $configuration = $this->getConfiguration();
    $machineName = $configuration['migration_module'];
    if ($this->moduleList->exists($machineName)) {
      return $this;
    }

    /* @noinspection PhpUnhandledExceptionInspection */
    $moduleSpell = $this->spellManager->createInstance(
      'devel_wizard_module',
      [
        'type' => 'custom',
        'machine_name' => $configuration['migration_module'],
        'name' => 'App - Default and Dummy migrations',
        'description' => 'Provides content migrations',
        'package' => 'App',
        'info.yml' => [
          'dependencies' => [
            'migrate_dc:migrate_dc',
          ],
        ],
      ],
    );
    $subBatchContext = [];
    $moduleSpell->prepare();
    $moduleSpell->abracadabra($subBatchContext);

    return $this;
  }

  protected function doItModuleInstall(): static {
    $configuration = $this->getConfiguration();
    $machineName = $configuration['migration_module'];

    $this->ensureModuleInstalled('migrate_tools');
    $this->ensureModuleInstalled('migrate_plus');
    $this->ensureModuleInstalled('migrate_dc');
    $this->ensureModuleInstalled($machineName);

    return $this;
  }

  /**
   * @throws \Twig\Error\Error
   */
  protected function doItMigrationCreate(): static {
    $this
      ->doItMigrationCreateGroup()
      ->doItMigrationCreateDefinitions()
      ->doItMigrationCreateSource();

    return $this;
  }

  /**
   * @throws \Twig\Error\Error
   */
  protected function doItMigrationCreateGroup(): static {
    $configuration = $this->getConfiguration();
    $moduleName = $configuration['migration_module'];
    $modulePath = $this->getModulePath($moduleName);
    $migrationGroup = $configuration['migration_group'];

    $filePath = Path::join(
      $modulePath,
      'config',
      'install',
      "migrate_plus.migration_group.{$migrationGroup}.yml",
    );

    $values = [
      'migration_group' => $migrationGroup,
      'migration_module' => $moduleName,
      'site_path' => $this->sitePath,
    ];

    $templatePath = '@devel_wizard/migration/devel_wizard.migration_group.yml.twig';
    $rendered = $this->twig->render($templatePath, $values);

    $this->fs->mkdir(Path::getDirectory($filePath));
    $this->fs->dumpFile($filePath, $rendered);
    $this->messageFilesystemEntryCreate($filePath);

    return $this;
  }

  /**
   * @throws \Twig\Error\Error
   */
  protected function doItMigrationCreateDefinitions(): static {
    $configuration = $this->getConfiguration();

    $bundleId = $configuration['machine_name'];
    $moduleName = $configuration['migration_module'];
    $modulePath = $this->getModulePath($moduleName);
    $migrationGroup = $configuration['migration_group'];
    $migrationId = "{$migrationGroup}__{$this->contentEntityTypeId}__{$bundleId}";

    // @todo Make it configurable "plugin" vs "config".
    $filePath = Path::join(
      $modulePath,
      'config',
      'install',
      "migrate_plus.migration.{$migrationId}.yml",
    );

    $tplPath = "@devel_wizard/migration/devel_wizard.migration_definition.{$this->contentEntityTypeId}.yml.twig";
    $tplValues = [
      'entity_type' => $this->contentEntityTypeId,
      'migration_id' => $migrationId,
      'bundle' => $bundleId,
      'migration_group' => $migrationGroup,
    ];

    $this->fs->mkdir(Path::getDirectory($filePath));
    $this->fs->dumpFile($filePath, $this->twig->render($tplPath, $tplValues));
    $this->messageFilesystemEntryCreate($filePath);

    return $this;
  }

  protected function doItMigrationCreateSource(): static {
    $configuration = $this->getConfiguration();
    $nodeTypeId = $configuration['machine_name'];
    $migrationGroup = $configuration['migration_group'];

    $filePath = Path::join(
      '..',
      $this->sitePath,
      'content',
      $migrationGroup,
      $this->contentEntityTypeId,
      "{$nodeTypeId}.yml",
    );

    $sourceData = $this->getMigrationSourceData();
    $this->fs->mkdir(Path::getDirectory($filePath));
    $this->fs->dumpFile($filePath, Yaml::encode($sourceData));
    $this->messageFilesystemEntryCreate($filePath);

    return $this;
  }

  abstract protected function getMigrationSourceData(): array;

  public function getRequiredPackagesProd(): array {
    return [];
  }

  public function getRequiredPackagesDev(): array {
    return [
      'drupal/migrate_tools' => '^6.0',
      'drupal/migrate_plus' => '^6.0',
      'drupal/migrate_dc' => '2.x-dev',
    ];
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc