View source
<?php
namespace Drupal\config\Form;
use Drupal\Component\Serialization\Yaml;
use Drupal\config\StorageReplaceDataWrapper;
use Drupal\Core\Config\ConfigImporter;
use Drupal\Core\Config\ConfigImporterException;
use Drupal\Core\Config\ConfigManagerInterface;
use Drupal\Core\Config\StorageComparer;
use Drupal\Core\Config\StorageInterface;
use Drupal\Core\Config\TypedConfigManagerInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Extension\ModuleInstallerInterface;
use Drupal\Core\Extension\ThemeHandlerInterface;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Lock\LockBackendInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class ConfigSingleImportForm extends ConfirmFormBase {
protected $entityManager;
protected $configStorage;
protected $renderer;
protected $eventDispatcher;
protected $configManager;
protected $lock;
protected $typedConfigManager;
protected $moduleHandler;
protected $themeHandler;
protected $moduleInstaller;
protected $configExists = FALSE;
protected $data = array();
public function __construct(EntityManagerInterface $entity_manager, StorageInterface $config_storage, RendererInterface $renderer, EventDispatcherInterface $event_dispatcher, ConfigManagerInterface $config_manager, LockBackendInterface $lock, TypedConfigManagerInterface $typed_config, ModuleHandlerInterface $module_handler, ModuleInstallerInterface $module_installer, ThemeHandlerInterface $theme_handler) {
$this->entityManager = $entity_manager;
$this->configStorage = $config_storage;
$this->renderer = $renderer;
$this->eventDispatcher = $event_dispatcher;
$this->configManager = $config_manager;
$this->lock = $lock;
$this->typedConfigManager = $typed_config;
$this->moduleHandler = $module_handler;
$this->moduleInstaller = $module_installer;
$this->themeHandler = $theme_handler;
}
public static function create(ContainerInterface $container) {
return new static($container
->get('entity.manager'), $container
->get('config.storage'), $container
->get('renderer'), $container
->get('event_dispatcher'), $container
->get('config.manager'), $container
->get('lock.persistent'), $container
->get('config.typed'), $container
->get('module_handler'), $container
->get('module_installer'), $container
->get('theme_handler'));
}
public function getFormId() {
return 'config_single_import_form';
}
public function getCancelUrl() {
return new Url('config.import_single');
}
public function getQuestion() {
if ($this->data['config_type'] === 'system.simple') {
$name = $this->data['config_name'];
$type = $this
->t('simple configuration');
}
else {
$definition = $this->entityManager
->getDefinition($this->data['config_type']);
$name = $this->data['import'][$definition
->getKey('id')];
$type = $definition
->getLowercaseLabel();
}
$args = array(
'%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;
}
public function buildForm(array $form, FormStateInterface $form_state) {
if ($this->data) {
return parent::buildForm($form, $form_state);
}
$entity_types = array();
foreach ($this->entityManager
->getDefinitions() as $entity_type => $definition) {
if ($definition
->isSubclassOf('Drupal\\Core\\Config\\Entity\\ConfigEntityInterface')) {
$entity_types[$entity_type] = $definition
->getLabel();
}
}
uasort($entity_types, 'strnatcasecmp');
$config_types = array(
'system.simple' => $this
->t('Simple configuration'),
) + $entity_types;
$form['config_type'] = array(
'#title' => $this
->t('Configuration type'),
'#type' => 'select',
'#options' => $config_types,
'#required' => TRUE,
);
$form['config_name'] = array(
'#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' => array(
'required' => array(
':input[name="config_type"]' => array(
'value' => 'system.simple',
),
),
'visible' => array(
':input[name="config_type"]' => array(
'value' => 'system.simple',
),
),
),
);
$form['import'] = array(
'#title' => $this
->t('Paste your configuration here'),
'#type' => 'textarea',
'#rows' => 24,
'#required' => TRUE,
);
$form['advanced'] = array(
'#type' => 'details',
'#title' => $this
->t('Advanced'),
);
$form['advanced']['custom_entity_id'] = array(
'#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'] = array(
'#type' => 'actions',
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this
->t('Import'),
'#button_type' => 'primary',
);
return $form;
}
public function validateForm(array &$form, FormStateInterface $form_state) {
if ($this->data) {
return;
}
$data = Yaml::decode($form_state
->getValue('import'));
if ($form_state
->getValue('config_type') !== 'system.simple') {
$definition = $this->entityManager
->getDefinition($form_state
->getValue('config_type'));
$id_key = $definition
->getKey('id');
if (!$form_state
->isValueEmpty('custom_entity_id')) {
$data[$id_key] = $form_state
->getValue('custom_entity_id');
}
$entity_storage = $this->entityManager
->getStorage($form_state
->getValue('config_type'));
if (!isset($data[$id_key])) {
$form_state
->setErrorByName('import', $this
->t('Missing ID key "@id_key" for this @entity_type import.', array(
'@id_key' => $id_key,
'@entity_type' => $definition
->getLabel(),
)));
return;
}
$config_name = $definition
->getConfigPrefix() . '.' . $data[$id_key];
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(array(
'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;
}
if (!$form_state
->getErrors()) {
$source_storage = new StorageReplaceDataWrapper($this->configStorage);
$source_storage
->replaceData($config_name, $data);
$storage_comparer = new StorageComparer($source_storage, $this->configStorage, $this->configManager);
if (!$storage_comparer
->createChangelist()
->hasChanges()) {
$form_state
->setErrorByName('import', $this
->t('There are no changes to import.'));
}
else {
$config_importer = new ConfigImporter($storage_comparer, $this->eventDispatcher, $this->configManager, $this->lock, $this->typedConfigManager, $this->moduleHandler, $this->moduleInstaller, $this->themeHandler, $this
->getStringTranslation());
try {
$config_importer
->validate();
$form_state
->set('config_importer', $config_importer);
} catch (ConfigImporterException $e) {
$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));
}
}
}
$form_state
->setValueForElement($form['import'], $data);
}
public function submitForm(array &$form, FormStateInterface $form_state) {
if (!$this->data) {
$form_state
->setRebuild();
$this->data = $form_state
->getValues();
return;
}
$config_importer = $form_state
->get('config_importer');
if ($config_importer
->alreadyImporting()) {
drupal_set_message($this
->t('Another request may be importing configuration already.'), 'error');
}
else {
try {
$sync_steps = $config_importer
->initialize();
$batch = [
'operations' => [],
'finished' => [
ConfigSync::class,
'finishBatch',
],
'title' => $this
->t('Importing configuration'),
'init_message' => $this
->t('Starting configuration import.'),
'progress_message' => $this
->t('Completed @current step of @total.'),
'error_message' => $this
->t('Configuration import has encountered an error.'),
];
foreach ($sync_steps as $sync_step) {
$batch['operations'][] = [
[
ConfigSync::class,
'processBatch',
],
[
$config_importer,
$sync_step,
],
];
}
batch_set($batch);
} catch (ConfigImporterException $e) {
drupal_set_message($this
->t('The configuration import failed for the following reasons:'), 'error');
foreach ($config_importer
->getErrors() as $message) {
drupal_set_message($message, 'error');
}
}
}
}
}