class ConfigSingleImportForm

Same name and namespace in other branches
  1. 11.x core/modules/config/src/Form/ConfigSingleImportForm.php \Drupal\config\Form\ConfigSingleImportForm
  2. 10 core/modules/config/src/Form/ConfigSingleImportForm.php \Drupal\config\Form\ConfigSingleImportForm
  3. 9 core/modules/config/src/Form/ConfigSingleImportForm.php \Drupal\config\Form\ConfigSingleImportForm
  4. 8.9.x core/modules/config/src/Form/ConfigSingleImportForm.php \Drupal\config\Form\ConfigSingleImportForm

Provides a form for importing a single configuration file.

@internal

Hierarchy

Expanded class hierarchy of ConfigSingleImportForm

1 string reference to 'ConfigSingleImportForm'
config.routing.yml in core/modules/config/config.routing.yml
core/modules/config/config.routing.yml

File

core/modules/config/src/Form/ConfigSingleImportForm.php, line 27

Namespace

Drupal\config\Form
View source
class ConfigSingleImportForm extends ConfirmFormBase {
  
  /**
   * If the config exists, this is that object. Otherwise, FALSE.
   *
   * @var \Drupal\Core\Config\Config|\Drupal\Core\Config\Entity\ConfigEntityInterface|bool
   */
  protected $configExists = FALSE;
  
  /**
   * The submitted data needing to be confirmed.
   *
   * @var array
   */
  protected $data = [];
  
  /**
   * Constructs a new ConfigSingleImportForm.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   The entity type manager.
   * @param \Drupal\Core\Config\StorageInterface $configStorage
   *   The config storage.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer service.
   * @param \Drupal\Core\Config\ConfigImporterFactory $configImporterFactory
   *   The config importer factory.
   */
  public function __construct(protected EntityTypeManagerInterface $entityTypeManager, protected StorageInterface $configStorage, protected RendererInterface $renderer, protected ConfigImporterFactory $configImporterFactory) {
  }
  
  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container->get('entity_type.manager'), $container->get('config.storage'), $container->get('renderer'), $container->get(ConfigImporterFactory::class));
  }
  
  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'config_single_import_form';
  }
  
  /**
   * {@inheritdoc}
   */
  public function getCancelUrl() {
    return new Url('config.import_single');
  }
  
  /**
   * {@inheritdoc}
   */
  public function getQuestion() {
    if ($this->data['config_type'] === 'system.simple') {
      $name = $this->data['config_name'];
      $type = $this->t('simple configuration');
    }
    else {
      $definition = $this->entityTypeManager
        ->getDefinition($this->data['config_type']);
      $name = $this->data['import'][$definition->getKey('id')];
      $type = $definition->getSingularLabel();
    }
    $args = [
      '%name' => $name,
      '@type' => strtolower($type),
    ];
    if ($this->configExists) {
      $question = $this->t('Are you sure you want to update the %name @type?', $args);
    }
    else {
      $question = $this->t('Are you sure you want to create a new %name @type?', $args);
    }
    return $question;
  }
  
  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    // When this is the confirmation step fall through to the confirmation form.
    if ($this->data) {
      return parent::buildForm($form, $form_state);
    }
    $entity_types = [];
    foreach ($this->entityTypeManager
      ->getDefinitions() as $entity_type => $definition) {
      if ($definition->entityClassImplements(ConfigEntityInterface::class)) {
        $entity_types[$entity_type] = $definition->getLabel();
      }
    }
    // Sort the entity types by label, then add the simple config to the top.
    uasort($entity_types, 'strnatcasecmp');
    $config_types = [
      'system.simple' => $this->t('Simple configuration'),
    ] + $entity_types;
    $form['config_type'] = [
      '#title' => $this->t('Configuration type'),
      '#type' => 'select',
      '#options' => $config_types,
      '#required' => TRUE,
    ];
    $form['config_name'] = [
      '#title' => $this->t('Configuration name'),
      '#description' => $this->t('Enter the name of the configuration file without the <em>.yml</em> extension. (e.g. <em>system.site</em>)'),
      '#type' => 'textfield',
      '#states' => [
        'required' => [
          ':input[name="config_type"]' => [
            'value' => 'system.simple',
          ],
        ],
        'visible' => [
          ':input[name="config_type"]' => [
            'value' => 'system.simple',
          ],
        ],
      ],
    ];
    $form['import'] = [
      '#title' => $this->t('Paste your configuration here'),
      '#type' => 'textarea',
      '#rows' => 24,
      '#required' => TRUE,
    ];
    $form['advanced'] = [
      '#type' => 'details',
      '#title' => $this->t('Advanced'),
    ];
    $form['advanced']['custom_entity_id'] = [
      '#title' => $this->t('Custom Entity ID'),
      '#type' => 'textfield',
      '#description' => $this->t('Specify a custom entity ID. This will override the entity ID in the configuration above.'),
    ];
    $form['actions'] = [
      '#type' => 'actions',
    ];
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Import'),
      '#button_type' => 'primary',
    ];
    return $form;
  }
  
  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    // The confirmation step needs no additional validation.
    if ($this->data) {
      return;
    }
    try {
      // Decode the submitted import.
      $data = Yaml::decode($form_state->getValue('import'));
    } catch (InvalidDataTypeException $e) {
      $form_state->setErrorByName('import', $this->t('The import failed with the following message: %message', [
        '%message' => $e->getMessage(),
      ]));
    }
    // Validate for config entities.
    if ($form_state->getValue('config_type') && $form_state->getValue('config_type') !== 'system.simple') {
      $definition = $this->entityTypeManager
        ->getDefinition($form_state->getValue('config_type'));
      $id_key = $definition->getKey('id');
      // If a custom entity ID is specified, override the value in the
      // configuration data being imported.
      if (!$form_state->isValueEmpty('custom_entity_id')) {
        $data[$id_key] = $form_state->getValue('custom_entity_id');
      }
      $entity_storage = $this->entityTypeManager
        ->getStorage($form_state->getValue('config_type'));
      // If an entity ID was not specified, set an error.
      if (!isset($data[$id_key])) {
        $form_state->setErrorByName('import', $this->t('Missing ID key "@id_key" for this @entity_type import.', [
          '@id_key' => $id_key,
          '@entity_type' => $definition->getLabel(),
        ]));
        return;
      }
      $config_name = $definition->getConfigPrefix() . '.' . $data[$id_key];
      // If there is an existing entity, ensure matching ID and UUID.
      if ($entity = $entity_storage->load($data[$id_key])) {
        $this->configExists = $entity;
        if (!isset($data['uuid'])) {
          $form_state->setErrorByName('import', $this->t('An entity with this machine name already exists but the import did not specify a UUID.'));
          return;
        }
        if ($data['uuid'] !== $entity->uuid()) {
          $form_state->setErrorByName('import', $this->t('An entity with this machine name already exists but the UUID does not match.'));
          return;
        }
      }
      elseif (isset($data['uuid']) && $entity_storage->loadByProperties([
        'uuid' => $data['uuid'],
      ])) {
        $form_state->setErrorByName('import', $this->t('An entity with this UUID already exists but the machine name does not match.'));
      }
    }
    else {
      $config_name = $form_state->getValue('config_name');
      $config = $this->config($config_name);
      $this->configExists = !$config->isNew() ? $config : FALSE;
    }
    // Use ConfigImporter validation.
    if (!$form_state->getErrors()) {
      $source_storage = new StorageReplaceDataWrapper($this->configStorage);
      $source_storage->replaceData($config_name, $data);
      $storage_comparer = new StorageComparer($source_storage, $this->configStorage);
      $storage_comparer->createChangelist();
      if (!$storage_comparer->hasChanges()) {
        $form_state->setErrorByName('import', $this->t('There are no changes to import.'));
      }
      else {
        $config_importer = $this->configImporterFactory
          ->get($storage_comparer);
        try {
          $config_importer->validate();
          $form_state->set('config_importer', $config_importer);
        } catch (ConfigImporterException) {
          // There are validation errors.
          $item_list = [
            '#theme' => 'item_list',
            '#items' => $config_importer->getErrors(),
            '#title' => $this->t('The configuration cannot be imported because it failed validation for the following reasons:'),
          ];
          $form_state->setErrorByName('import', $this->renderer
            ->render($item_list));
        }
      }
    }
    // Store the decoded version of the submitted import.
    $form_state->setValueForElement($form['import'], $data);
  }
  
  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    // If this form has not yet been confirmed, store the values and rebuild.
    if (!$this->data) {
      $form_state->setRebuild();
      $this->data = $form_state->getValues();
      return;
    }
    /** @var \Drupal\Core\Config\ConfigImporter $config_importer */
    $config_importer = $form_state->get('config_importer');
    if ($config_importer->alreadyImporting()) {
      $this->messenger()
        ->addError($this->t('Another request may be importing configuration already.'));
    }
    else {
      try {
        $sync_steps = $config_importer->initialize();
        $batch_builder = (new BatchBuilder())->setTitle($this->t('Importing configuration'))
          ->setFinishCallback([
          ConfigImporterBatch::class,
          'finish',
        ])
          ->setInitMessage($this->t('Starting configuration import.'))
          ->setProgressMessage($this->t('Completed @current step of @total.'))
          ->setErrorMessage($this->t('Configuration import has encountered an error.'));
        foreach ($sync_steps as $sync_step) {
          $batch_builder->addOperation([
            ConfigImporterBatch::class,
            'process',
          ], [
            $config_importer,
            $sync_step,
          ]);
        }
        batch_set($batch_builder->toArray());
      } catch (ConfigImporterException) {
        // There are validation errors.
        $this->messenger()
          ->addError($this->t('The configuration import failed for the following reasons:'));
        foreach ($config_importer->getErrors() as $message) {
          $this->messenger()
            ->addError($message);
        }
      }
    }
  }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title Overrides
ConfigSingleImportForm::$configExists protected property If the config exists, this is that object. Otherwise, FALSE.
ConfigSingleImportForm::$data protected property The submitted data needing to be confirmed.
ConfigSingleImportForm::buildForm public function Form constructor. Overrides ConfirmFormBase::buildForm
ConfigSingleImportForm::create public static function Instantiates a new instance of this class. Overrides FormBase::create
ConfigSingleImportForm::getCancelUrl public function Returns the route to go to if the user cancels the action. Overrides ConfirmFormInterface::getCancelUrl
ConfigSingleImportForm::getFormId public function Returns a unique string identifying the form. Overrides FormInterface::getFormId
ConfigSingleImportForm::getQuestion public function Returns the question to ask the user. Overrides ConfirmFormInterface::getQuestion
ConfigSingleImportForm::submitForm public function Form submission handler. Overrides FormInterface::submitForm
ConfigSingleImportForm::validateForm public function Form validation handler. Overrides FormBase::validateForm
ConfigSingleImportForm::__construct public function Constructs a new ConfigSingleImportForm.
ConfirmFormBase::getCancelText public function Returns a caption for the link which cancels the action. Overrides ConfirmFormInterface::getCancelText 2
ConfirmFormBase::getConfirmText public function Returns a caption for the button that confirms the action. Overrides ConfirmFormInterface::getConfirmText 23
ConfirmFormBase::getDescription public function Returns additional text to display as a description. Overrides ConfirmFormInterface::getDescription 19
ConfirmFormBase::getFormName public function Returns the internal name used to refer to the confirmation item. Overrides ConfirmFormInterface::getFormName
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 2
DependencySerializationTrait::__wakeup public function 2
FormBase::$configFactory protected property The config factory. 2
FormBase::$requestStack protected property The request stack. 1
FormBase::$routeMatch protected property The route match.
FormBase::config protected function Retrieves a configuration object.
FormBase::configFactory protected function Gets the config factory for this form. 2
FormBase::container private function Returns the service container.
FormBase::currentUser protected function Gets the current user. 2
FormBase::getRequest protected function Gets the request object. Overrides HtmxRequestInfoTrait::getRequest
FormBase::getRouteMatch protected function Gets the route match.
FormBase::logger protected function Gets the logger for a specific channel.
FormBase::redirect protected function Returns a redirect response object for the specified route.
FormBase::resetConfigFactory public function Resets the configuration factory.
FormBase::setConfigFactory public function Sets the config factory for this form.
FormBase::setRequestStack public function Sets the request stack object to use.
HtmxRequestInfoTrait::getHtmxCurrentUrl protected function Retrieves the URL of the requesting page from an HTMX request header.
HtmxRequestInfoTrait::getHtmxPrompt protected function Retrieves the prompt from an HTMX request header.
HtmxRequestInfoTrait::getHtmxTarget protected function Retrieves the target identifier from an HTMX request header.
HtmxRequestInfoTrait::getHtmxTrigger protected function Retrieves the trigger identifier from an HTMX request header.
HtmxRequestInfoTrait::getHtmxTriggerName protected function Retrieves the trigger name from an HTMX request header.
HtmxRequestInfoTrait::isHtmxBoosted protected function Determines if the request is boosted by HTMX.
HtmxRequestInfoTrait::isHtmxHistoryRestoration protected function Determines if if the request is for history restoration.
HtmxRequestInfoTrait::isHtmxRequest protected function Determines if the request is sent by HTMX.
LoggerChannelTrait::$loggerFactory protected property The logger channel factory service.
LoggerChannelTrait::getLogger protected function Gets the logger for a specific channel.
LoggerChannelTrait::setLoggerFactory public function Injects the logger channel factory.
MessengerTrait::$messenger protected property The messenger. 25
MessengerTrait::messenger public function Gets the messenger. 25
MessengerTrait::setMessenger public function Sets the messenger.
RedirectDestinationTrait::$redirectDestination protected property The redirect destination service. 2
RedirectDestinationTrait::getDestinationArray protected function Prepares a &#039;destination&#039; URL query parameter for use with \Drupal\Core\Url.
RedirectDestinationTrait::getRedirectDestination protected function Returns the redirect destination service.
RedirectDestinationTrait::setRedirectDestination public function Sets the redirect destination service.
StringTranslationTrait::$stringTranslation protected property The string translation service. 3
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language. 1

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.