Drupal 8.0.0 beta 12. More info: https://www.drupal.org/node/2514176
This commit is contained in:
commit
9921556621
13277 changed files with 1459781 additions and 0 deletions
46
core/modules/config/src/Form/ConfigExportForm.php
Normal file
46
core/modules/config/src/Form/ConfigExportForm.php
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\config\Form\ConfigExportForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\config\Form;
|
||||
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Defines the configuration export form.
|
||||
*/
|
||||
class ConfigExportForm extends FormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'config_export_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$form['description'] = array(
|
||||
'#markup' => '<p>' . $this->t('Use the export button below to download your site configuration.') . '</p>',
|
||||
);
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Export'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$form_state->setRedirect('config.export_download');
|
||||
}
|
||||
|
||||
}
|
||||
108
core/modules/config/src/Form/ConfigImportForm.php
Normal file
108
core/modules/config/src/Form/ConfigImportForm.php
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\config\Form\ConfigImportForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\config\Form;
|
||||
|
||||
use Drupal\Core\Archiver\ArchiveTar;
|
||||
use Drupal\Core\Config\StorageInterface;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Defines the configuration import form.
|
||||
*/
|
||||
class ConfigImportForm extends FormBase {
|
||||
|
||||
/**
|
||||
* The configuration storage.
|
||||
*
|
||||
* @var \Drupal\Core\Config\StorageInterface
|
||||
*/
|
||||
protected $configStorage;
|
||||
|
||||
/**
|
||||
* Constructs a new ConfigImportForm.
|
||||
*
|
||||
* @param \Drupal\Core\Config\StorageInterface $config_storage
|
||||
* The configuration storage.
|
||||
*/
|
||||
public function __construct(StorageInterface $config_storage) {
|
||||
$this->configStorage = $config_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.storage.staging')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'config_import_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$form['import_tarball'] = array(
|
||||
'#type' => 'file',
|
||||
'#title' => $this->t('Configuration archive'),
|
||||
'#description' => $this->t('Allowed types: @extensions.', array('@extensions' => 'tar.gz tgz tar.bz2')),
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Upload'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
$file_upload = $this->getRequest()->files->get('files[import_tarball]', NULL, TRUE);
|
||||
if ($file_upload && $file_upload->isValid()) {
|
||||
$form_state->setValue('import_tarball', $file_upload->getRealPath());
|
||||
}
|
||||
else {
|
||||
$form_state->setErrorByName('import_tarball', $this->t('The file could not be uploaded.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
if ($path = $form_state->getValue('import_tarball')) {
|
||||
$this->configStorage->deleteAll();
|
||||
try {
|
||||
$archiver = new ArchiveTar($path, 'gz');
|
||||
$files = array();
|
||||
foreach ($archiver->listContent() as $file) {
|
||||
$files[] = $file['filename'];
|
||||
}
|
||||
$archiver->extractList($files, config_get_config_directory(CONFIG_STAGING_DIRECTORY));
|
||||
drupal_set_message($this->t('Your configuration files were successfully uploaded and are ready for import.'));
|
||||
$form_state->setRedirect('config.sync');
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
drupal_set_message($this->t('Could not extract the contents of the tar file. The error message is <em>@message</em>', array('@message' => $e->getMessage())), 'error');
|
||||
}
|
||||
drupal_unlink($path);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
206
core/modules/config/src/Form/ConfigSingleExportForm.php
Normal file
206
core/modules/config/src/Form/ConfigSingleExportForm.php
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\config\Form\ConfigSingleExportForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\config\Form;
|
||||
|
||||
use Drupal\Component\Serialization\Yaml;
|
||||
use Drupal\Core\Config\StorageInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a form for exporting a single configuration file.
|
||||
*/
|
||||
class ConfigSingleExportForm extends FormBase {
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The config storage.
|
||||
*
|
||||
* @var \Drupal\Core\Config\StorageInterface
|
||||
*/
|
||||
protected $configStorage;
|
||||
|
||||
/**
|
||||
* Tracks the valid config entity type definitions.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface[]
|
||||
*/
|
||||
protected $definitions = 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.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager, StorageInterface $config_storage) {
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->configStorage = $config_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.manager'),
|
||||
$container->get('config.storage')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'config_single_export_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $config_type = NULL, $config_name = NULL) {
|
||||
foreach ($this->entityManager->getDefinitions() as $entity_type => $definition) {
|
||||
if ($definition->isSubclassOf('Drupal\Core\Config\Entity\ConfigEntityInterface')) {
|
||||
$this->definitions[$entity_type] = $definition;
|
||||
}
|
||||
}
|
||||
$entity_types = array_map(function (EntityTypeInterface $definition) {
|
||||
return $definition->getLabel();
|
||||
}, $this->definitions);
|
||||
// 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,
|
||||
'#default_value' => $config_type,
|
||||
'#ajax' => array(
|
||||
'callback' => '::updateConfigurationType',
|
||||
'wrapper' => 'edit-config-type-wrapper',
|
||||
),
|
||||
);
|
||||
$default_type = $form_state->getValue('config_type', $config_type);
|
||||
$form['config_name'] = array(
|
||||
'#title' => $this->t('Configuration name'),
|
||||
'#type' => 'select',
|
||||
'#options' => $this->findConfiguration($default_type),
|
||||
'#default_value' => $config_name,
|
||||
'#required' => TRUE,
|
||||
'#prefix' => '<div id="edit-config-type-wrapper">',
|
||||
'#suffix' => '</div>',
|
||||
'#ajax' => array(
|
||||
'callback' => '::updateExport',
|
||||
'wrapper' => 'edit-export-wrapper',
|
||||
),
|
||||
);
|
||||
|
||||
$form['export'] = array(
|
||||
'#title' => $this->t('Here is your configuration:'),
|
||||
'#type' => 'textarea',
|
||||
'#rows' => 24,
|
||||
'#required' => TRUE,
|
||||
'#prefix' => '<div id="edit-export-wrapper">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
if ($config_type && $config_name) {
|
||||
$fake_form_state = (new FormState())->setValues([
|
||||
'config_type' => $config_type,
|
||||
'config_name' => $config_name,
|
||||
]);
|
||||
$form['export'] = $this->updateExport($form, $fake_form_state);
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles switching the configuration type selector.
|
||||
*/
|
||||
public function updateConfigurationType($form, FormStateInterface $form_state) {
|
||||
$form['config_name']['#options'] = $this->findConfiguration($form_state->getValue('config_type'));
|
||||
return $form['config_name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles switching the export textarea.
|
||||
*/
|
||||
public function updateExport($form, FormStateInterface $form_state) {
|
||||
// Determine the full config name for the selected config entity.
|
||||
if ($form_state->getValue('config_type') !== 'system.simple') {
|
||||
$definition = $this->entityManager->getDefinition($form_state->getValue('config_type'));
|
||||
$name = $definition->getConfigPrefix() . '.' . $form_state->getValue('config_name');
|
||||
}
|
||||
// The config name is used directly for simple configuration.
|
||||
else {
|
||||
$name = $form_state->getValue('config_name');
|
||||
}
|
||||
// Read the raw data for this config name, encode it, and display it.
|
||||
$form['export']['#value'] = Yaml::encode($this->configStorage->read($name));
|
||||
$form['export']['#description'] = $this->t('Filename: %name', array('%name' => $name . '.yml'));
|
||||
return $form['export'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles switching the configuration type selector.
|
||||
*/
|
||||
protected function findConfiguration($config_type) {
|
||||
$names = array(
|
||||
'' => $this->t('- Select -'),
|
||||
);
|
||||
// For a given entity type, load all entities.
|
||||
if ($config_type && $config_type !== 'system.simple') {
|
||||
$entity_storage = $this->entityManager->getStorage($config_type);
|
||||
foreach ($entity_storage->loadMultiple() as $entity) {
|
||||
$entity_id = $entity->id();
|
||||
$label = $entity->label() ?: $entity_id;
|
||||
$names[$entity_id] = $label;
|
||||
}
|
||||
}
|
||||
// Handle simple configuration.
|
||||
else {
|
||||
// Gather the config entity prefixes.
|
||||
$config_prefixes = array_map(function (EntityTypeInterface $definition) {
|
||||
return $definition->getConfigPrefix() . '.';
|
||||
}, $this->definitions);
|
||||
|
||||
// Find all config, and then filter our anything matching a config prefix.
|
||||
$names = $this->configStorage->listAll();
|
||||
$names = array_combine($names, $names);
|
||||
foreach ($names as $config_name) {
|
||||
foreach ($config_prefixes as $config_prefix) {
|
||||
if (strpos($config_name, $config_prefix) === 0) {
|
||||
unset($names[$config_name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $names;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
// Nothing to submit.
|
||||
}
|
||||
|
||||
}
|
||||
268
core/modules/config/src/Form/ConfigSingleImportForm.php
Normal file
268
core/modules/config/src/Form/ConfigSingleImportForm.php
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\config\Form\ConfigSingleImportForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\config\Form;
|
||||
|
||||
use Drupal\Component\Serialization\Yaml;
|
||||
use Drupal\Core\Config\StorageInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager, StorageInterface $config_storage) {
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->configStorage = $config_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.manager'),
|
||||
$container->get('config.storage')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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;
|
||||
}
|
||||
// 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 = $this->config($form_state->getValue('config_name'));
|
||||
$this->configExists = !$config->isNew() ? $config : FALSE;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// If a simple configuration file was added, set the data and save.
|
||||
if ($this->data['config_type'] === 'system.simple') {
|
||||
$this->configFactory()->getEditable($this->data['config_name'])->setData($this->data['import'])->save();
|
||||
drupal_set_message($this->t('The %name configuration was imported.', array('%name' => $this->data['config_name'])));
|
||||
}
|
||||
// For a config entity, create an entity and save it.
|
||||
else {
|
||||
try {
|
||||
$entity_storage = $this->entityManager->getStorage($this->data['config_type']);
|
||||
if ($this->configExists) {
|
||||
$entity = $entity_storage->updateFromStorageRecord($this->configExists, $this->data['import']);
|
||||
}
|
||||
else {
|
||||
$entity = $entity_storage->createFromStorageRecord($this->data['import']);
|
||||
}
|
||||
$entity->save();
|
||||
drupal_set_message($this->t('The @entity_type %label was imported.', array('@entity_type' => $entity->getEntityTypeId(), '%label' => $entity->label())));
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
drupal_set_message($e->getMessage(), 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
418
core/modules/config/src/Form/ConfigSync.php
Normal file
418
core/modules/config/src/Form/ConfigSync.php
Normal file
|
|
@ -0,0 +1,418 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\config\Form\ConfigSync.
|
||||
*/
|
||||
|
||||
namespace Drupal\config\Form;
|
||||
|
||||
use Drupal\Component\Uuid\UuidInterface;
|
||||
use Drupal\Core\Config\ConfigImporterException;
|
||||
use Drupal\Core\Config\ConfigImporter;
|
||||
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\Config\ConfigManagerInterface;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Config\StorageInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Lock\LockBackendInterface;
|
||||
use Drupal\Core\Config\StorageComparer;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Construct the storage changes in a configuration synchronization form.
|
||||
*/
|
||||
class ConfigSync extends FormBase {
|
||||
|
||||
/**
|
||||
* The database lock object.
|
||||
*
|
||||
* @var \Drupal\Core\Lock\LockBackendInterface
|
||||
*/
|
||||
protected $lock;
|
||||
|
||||
/**
|
||||
* The staging configuration object.
|
||||
*
|
||||
* @var \Drupal\Core\Config\StorageInterface
|
||||
*/
|
||||
protected $stagingStorage;
|
||||
|
||||
/**
|
||||
* The active configuration object.
|
||||
*
|
||||
* @var \Drupal\Core\Config\StorageInterface
|
||||
*/
|
||||
protected $activeStorage;
|
||||
|
||||
/**
|
||||
* The snapshot configuration object.
|
||||
*
|
||||
* @var \Drupal\Core\Config\StorageInterface
|
||||
*/
|
||||
protected $snapshotStorage;
|
||||
|
||||
/**
|
||||
* Event dispatcher.
|
||||
*
|
||||
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
|
||||
*/
|
||||
protected $eventDispatcher;
|
||||
|
||||
/**
|
||||
* The configuration manager.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigManagerInterface;
|
||||
*/
|
||||
protected $configManager;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The renderer.
|
||||
*
|
||||
* @var \Drupal\Core\Render\RendererInterface
|
||||
*/
|
||||
protected $renderer;
|
||||
|
||||
/**
|
||||
* Constructs the object.
|
||||
*
|
||||
* @param \Drupal\Core\Config\StorageInterface $staging_storage
|
||||
* The source storage.
|
||||
* @param \Drupal\Core\Config\StorageInterface $active_storage
|
||||
* The target storage.
|
||||
* @param \Drupal\Core\Config\StorageInterface $snapshot_storage
|
||||
* The snapshot storage.
|
||||
* @param \Drupal\Core\Lock\LockBackendInterface $lock
|
||||
* The lock object.
|
||||
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
|
||||
* Event dispatcher.
|
||||
* @param \Drupal\Core\Config\ConfigManagerInterface $config_manager
|
||||
* Configuration manager.
|
||||
* @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.
|
||||
* @param \Drupal\Core\Render\RendererInterface
|
||||
* The renderer.
|
||||
*/
|
||||
public function __construct(StorageInterface $staging_storage, StorageInterface $active_storage, StorageInterface $snapshot_storage, LockBackendInterface $lock, EventDispatcherInterface $event_dispatcher, ConfigManagerInterface $config_manager, TypedConfigManagerInterface $typed_config, ModuleHandlerInterface $module_handler, ModuleInstallerInterface $module_installer, ThemeHandlerInterface $theme_handler, RendererInterface $renderer) {
|
||||
$this->stagingStorage = $staging_storage;
|
||||
$this->activeStorage = $active_storage;
|
||||
$this->snapshotStorage = $snapshot_storage;
|
||||
$this->lock = $lock;
|
||||
$this->eventDispatcher = $event_dispatcher;
|
||||
$this->configManager = $config_manager;
|
||||
$this->typedConfigManager = $typed_config;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->moduleInstaller = $module_installer;
|
||||
$this->themeHandler = $theme_handler;
|
||||
$this->renderer = $renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.storage.staging'),
|
||||
$container->get('config.storage'),
|
||||
$container->get('config.storage.snapshot'),
|
||||
$container->get('lock.persistent'),
|
||||
$container->get('event_dispatcher'),
|
||||
$container->get('config.manager'),
|
||||
$container->get('config.typed'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('module_installer'),
|
||||
$container->get('theme_handler'),
|
||||
$container->get('renderer')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'config_admin_import_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Import all'),
|
||||
);
|
||||
$source_list = $this->stagingStorage->listAll();
|
||||
$storage_comparer = new StorageComparer($this->stagingStorage, $this->activeStorage, $this->configManager);
|
||||
if (empty($source_list) || !$storage_comparer->createChangelist()->hasChanges()) {
|
||||
$form['no_changes'] = array(
|
||||
'#type' => 'table',
|
||||
'#header' => array('Name', 'Operations'),
|
||||
'#rows' => array(),
|
||||
'#empty' => $this->t('There are no configuration changes to import.'),
|
||||
);
|
||||
$form['actions']['#access'] = FALSE;
|
||||
return $form;
|
||||
}
|
||||
elseif (!$storage_comparer->validateSiteUuid()) {
|
||||
drupal_set_message($this->t('The staged configuration cannot be imported, because it originates from a different site than this site. You can only synchronize configuration between cloned instances of this site.'), 'error');
|
||||
$form['actions']['#access'] = FALSE;
|
||||
return $form;
|
||||
}
|
||||
// A list of changes will be displayed, so check if the user should be
|
||||
// warned of potential losses to configuration.
|
||||
if ($this->snapshotStorage->exists('core.extension')) {
|
||||
$snapshot_comparer = new StorageComparer($this->activeStorage, $this->snapshotStorage, $this->configManager);
|
||||
if (!$form_state->getUserInput() && $snapshot_comparer->createChangelist()->hasChanges()) {
|
||||
$change_list = array();
|
||||
foreach ($snapshot_comparer->getAllCollectionNames() as $collection) {
|
||||
foreach ($snapshot_comparer->getChangelist(NULL, $collection) as $config_names) {
|
||||
if (empty($config_names)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($config_names as $config_name) {
|
||||
$change_list[] = $config_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
sort($change_list);
|
||||
$change_list_render = array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $change_list,
|
||||
);
|
||||
$change_list_html = $this->renderer->renderPlain($change_list_render);
|
||||
drupal_set_message($this->t('The following items in your active configuration have changes since the last import that may be lost on the next import. !changes', array('!changes' => $change_list_html)), 'warning');
|
||||
}
|
||||
}
|
||||
|
||||
// Store the comparer for use in the submit.
|
||||
$form_state->set('storage_comparer', $storage_comparer);
|
||||
|
||||
// Add the AJAX library to the form for dialog support.
|
||||
$form['#attached']['library'][] = 'core/drupal.ajax';
|
||||
|
||||
foreach ($storage_comparer->getAllCollectionNames() as $collection) {
|
||||
if ($collection != StorageInterface::DEFAULT_COLLECTION) {
|
||||
$form[$collection]['collection_heading'] = array(
|
||||
'#type' => 'html_tag',
|
||||
'#tag' => 'h2',
|
||||
'#value' => $this->t('!collection configuration collection', array('!collection' => $collection)),
|
||||
);
|
||||
}
|
||||
foreach ($storage_comparer->getChangelist(NULL, $collection) as $config_change_type => $config_names) {
|
||||
if (empty($config_names)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// @todo A table caption would be more appropriate, but does not have the
|
||||
// visual importance of a heading.
|
||||
$form[$collection][$config_change_type]['heading'] = array(
|
||||
'#type' => 'html_tag',
|
||||
'#tag' => 'h3',
|
||||
);
|
||||
switch ($config_change_type) {
|
||||
case 'create':
|
||||
$form[$collection][$config_change_type]['heading']['#value'] = $this->formatPlural(count($config_names), '@count new', '@count new');
|
||||
break;
|
||||
|
||||
case 'update':
|
||||
$form[$collection][$config_change_type]['heading']['#value'] = $this->formatPlural(count($config_names), '@count changed', '@count changed');
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
$form[$collection][$config_change_type]['heading']['#value'] = $this->formatPlural(count($config_names), '@count removed', '@count removed');
|
||||
break;
|
||||
|
||||
case 'rename':
|
||||
$form[$collection][$config_change_type]['heading']['#value'] = $this->formatPlural(count($config_names), '@count renamed', '@count renamed');
|
||||
break;
|
||||
}
|
||||
$form[$collection][$config_change_type]['list'] = array(
|
||||
'#type' => 'table',
|
||||
'#header' => array('Name', 'Operations'),
|
||||
);
|
||||
|
||||
foreach ($config_names as $config_name) {
|
||||
if ($config_change_type == 'rename') {
|
||||
$names = $storage_comparer->extractRenameNames($config_name);
|
||||
$route_options = array('source_name' => $names['old_name'], 'target_name' => $names['new_name']);
|
||||
$config_name = $this->t('!source_name to !target_name', array('!source_name' => $names['old_name'], '!target_name' => $names['new_name']));
|
||||
}
|
||||
else {
|
||||
$route_options = array('source_name' => $config_name);
|
||||
}
|
||||
if ($collection != StorageInterface::DEFAULT_COLLECTION) {
|
||||
$route_name = 'config.diff_collection';
|
||||
$route_options['collection'] = $collection;
|
||||
}
|
||||
else {
|
||||
$route_name = 'config.diff';
|
||||
}
|
||||
$links['view_diff'] = array(
|
||||
'title' => $this->t('View differences'),
|
||||
'url' => Url::fromRoute($route_name, $route_options),
|
||||
'attributes' => array(
|
||||
'class' => array('use-ajax'),
|
||||
'data-dialog-type' => 'modal',
|
||||
'data-dialog-options' => json_encode(array(
|
||||
'width' => 700
|
||||
)),
|
||||
),
|
||||
);
|
||||
$form[$collection][$config_change_type]['list']['#rows'][] = array(
|
||||
'name' => $config_name,
|
||||
'operations' => array(
|
||||
'data' => array(
|
||||
'#type' => 'operations',
|
||||
'#links' => $links,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$config_importer = new ConfigImporter(
|
||||
$form_state->get('storage_comparer'),
|
||||
$this->eventDispatcher,
|
||||
$this->configManager,
|
||||
$this->lock,
|
||||
$this->typedConfigManager,
|
||||
$this->moduleHandler,
|
||||
$this->moduleInstaller,
|
||||
$this->themeHandler,
|
||||
$this->getStringTranslation()
|
||||
);
|
||||
if ($config_importer->alreadyImporting()) {
|
||||
drupal_set_message($this->t('Another request may be synchronizing configuration already.'));
|
||||
}
|
||||
else{
|
||||
try {
|
||||
$sync_steps = $config_importer->initialize();
|
||||
$batch = array(
|
||||
'operations' => array(),
|
||||
'finished' => array(get_class($this), 'finishBatch'),
|
||||
'title' => t('Synchronizing configuration'),
|
||||
'init_message' => t('Starting configuration synchronization.'),
|
||||
'progress_message' => t('Completed @current step of @total.'),
|
||||
'error_message' => t('Configuration synchronization has encountered an error.'),
|
||||
'file' => drupal_get_path('module', 'config') . '/config.admin.inc',
|
||||
);
|
||||
foreach ($sync_steps as $sync_step) {
|
||||
$batch['operations'][] = array(array(get_class($this), 'processBatch'), array($config_importer, $sync_step));
|
||||
}
|
||||
|
||||
batch_set($batch);
|
||||
}
|
||||
catch (ConfigImporterException $e) {
|
||||
// There are validation errors.
|
||||
drupal_set_message($this->t('The configuration cannot be imported because it failed validation for the following reasons:'), 'error');
|
||||
foreach ($config_importer->getErrors() as $message) {
|
||||
drupal_set_message($message, 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the config import batch and persists the importer.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigImporter $config_importer
|
||||
* The batch config importer object to persist.
|
||||
* @param string $sync_step
|
||||
* The synchronization step to do.
|
||||
* @param array $context
|
||||
* The batch context.
|
||||
*/
|
||||
public static function processBatch(ConfigImporter $config_importer, $sync_step, &$context) {
|
||||
if (!isset($context['sandbox']['config_importer'])) {
|
||||
$context['sandbox']['config_importer'] = $config_importer;
|
||||
}
|
||||
|
||||
$config_importer = $context['sandbox']['config_importer'];
|
||||
$config_importer->doSyncStep($sync_step, $context);
|
||||
if ($errors = $config_importer->getErrors()) {
|
||||
if (!isset($context['results']['errors'])) {
|
||||
$context['results']['errors'] = array();
|
||||
}
|
||||
$context['results']['errors'] += $errors;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish batch.
|
||||
*
|
||||
* This function is a static function to avoid serializing the ConfigSync
|
||||
* object unnecessarily.
|
||||
*/
|
||||
public static function finishBatch($success, $results, $operations) {
|
||||
if ($success) {
|
||||
if (!empty($results['errors'])) {
|
||||
foreach ($results['errors'] as $error) {
|
||||
drupal_set_message($error, 'error');
|
||||
\Drupal::logger('config_sync')->error($error);
|
||||
}
|
||||
drupal_set_message(\Drupal::translation()->translate('The configuration was imported with errors.'), 'warning');
|
||||
}
|
||||
else {
|
||||
drupal_set_message(\Drupal::translation()->translate('The configuration was imported successfully.'));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// An error occurred.
|
||||
// $operations contains the operations that remained unprocessed.
|
||||
$error_operation = reset($operations);
|
||||
$message = \Drupal::translation()->translate('An error occurred while processing %error_operation with arguments: @arguments', array('%error_operation' => $error_operation[0], '@arguments' => print_r($error_operation[1], TRUE)));
|
||||
drupal_set_message($message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in a new issue