Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 8 |
CRAP | |
0.00% |
0 / 212 |
ConfigSingleImportForm | |
0.00% |
0 / 1 |
|
0.00% |
0 / 8 |
992 | |
0.00% |
0 / 212 |
__construct | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 11 |
|||
create | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 13 |
|||
getFormId | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getCancelUrl | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getQuestion | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 21 |
|||
buildForm | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 55 |
|||
validateForm | |
0.00% |
0 / 1 |
210 | |
0.00% |
0 / 75 |
|||
submitForm | |
0.00% |
0 / 1 |
42 | |
0.00% |
0 / 33 |
<?php | |
/** | |
* @file | |
* Contains \Drupal\config\Form\ConfigSingleImportForm. | |
*/ | |
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; | |
/** | |
* Provides a form for importing a single configuration file. | |
*/ | |
class ConfigSingleImportForm extends ConfirmFormBase { | |
/** | |
* The entity manager. | |
* | |
* @var \Drupal\Core\Entity\EntityManagerInterface | |
*/ | |
protected $entityManager; | |
/** | |
* The config storage. | |
* | |
* @var \Drupal\Core\Config\StorageInterface | |
*/ | |
protected $configStorage; | |
/** | |
* The renderer service. | |
* | |
* @var \Drupal\Core\Render\RendererInterface | |
*/ | |
protected $renderer; | |
/** | |
* The event dispatcher. | |
* | |
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface | |
*/ | |
protected $eventDispatcher; | |
/** | |
* The configuration manager. | |
* | |
* @var \Drupal\Core\Config\ConfigManagerInterface; | |
*/ | |
protected $configManager; | |
/** | |
* The database lock object. | |
* | |
* @var \Drupal\Core\Lock\LockBackendInterface | |
*/ | |
protected $lock; | |
/** | |
* The typed config manager. | |
* | |
* @var \Drupal\Core\Config\TypedConfigManagerInterface | |
*/ | |
protected $typedConfigManager; | |
/** | |
* The module handler. | |
* | |
* @var \Drupal\Core\Extension\ModuleHandlerInterface | |
*/ | |
protected $moduleHandler; | |
/** | |
* The theme handler. | |
* | |
* @var \Drupal\Core\Extension\ThemeHandlerInterface | |
*/ | |
protected $themeHandler; | |
/** | |
* The module installer. | |
* | |
* @var \Drupal\Core\Extension\ModuleInstallerInterface | |
*/ | |
protected $moduleInstaller; | |
/** | |
* 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 = array(); | |
/** | |
* Constructs a new ConfigSingleImportForm. | |
* | |
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager | |
* The entity manager. | |
* @param \Drupal\Core\Config\StorageInterface $config_storage | |
* The config storage. | |
* @param \Drupal\Core\Render\RendererInterface $renderer | |
* The renderer service. | |
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher | |
* The event dispatcher used to notify subscribers of config import events. | |
* @param \Drupal\Core\Config\ConfigManagerInterface $config_manager | |
* The configuration manager. | |
* @param \Drupal\Core\Lock\LockBackendInterface $lock | |
* The lock backend to ensure multiple imports do not occur at the same time. | |
* @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config | |
* The typed configuration manager. | |
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler | |
* The module handler. | |
* @param \Drupal\Core\Extension\ModuleInstallerInterface $module_installer | |
* The module installer. | |
* @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler | |
* The theme handler. | |
*/ | |
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; | |
// Services necessary for \Drupal\Core\Config\ConfigImporter. | |
$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; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
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') | |
); | |
} | |
/** | |
* {@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->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; | |
} | |
/** | |
* {@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 = array(); | |
foreach ($this->entityManager->getDefinitions() as $entity_type => $definition) { | |
if ($definition->isSubclassOf('Drupal\Core\Config\Entity\ConfigEntityInterface')) { | |
$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 = 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; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function validateForm(array &$form, FormStateInterface $form_state) { | |
// The confirmation step needs no additional validation. | |
if ($this->data) { | |
return; | |
} | |
// Decode the submitted import. | |
$data = Yaml::decode($form_state->getValue('import')); | |
// Validate for config entities. | |
if ($form_state->getValue('config_type') !== 'system.simple') { | |
$definition = $this->entityManager->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->entityManager->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.', array('@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; | |
} | |
} | |
// If there is no entity with a matching ID, check for a UUID match. | |
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; | |
} | |
// 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, | |
$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) { | |
// 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()) { | |
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) { | |
// There are validation errors. | |
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'); | |
} | |
} | |
} | |
} | |
} |