View source
<?php
namespace Drupal\features_ui\Form;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Xss;
use Drupal\features\FeaturesAssignerInterface;
use Drupal\features\FeaturesGeneratorInterface;
use Drupal\features\FeaturesManagerInterface;
use Drupal\features\ConfigurationItem;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\config_update\ConfigRevertInterface;
class FeaturesEditForm extends FormBase {
protected $featuresManager;
protected $assigner;
protected $generator;
protected $package;
protected $bundle;
protected $oldBundle;
protected $excluded;
protected $required;
protected $conflicts;
protected $allowConflicts;
protected $missing;
protected $configRevert;
public function __construct(FeaturesManagerInterface $features_manager, FeaturesAssignerInterface $assigner, FeaturesGeneratorInterface $generator, ConfigRevertInterface $config_revert) {
$this->featuresManager = $features_manager;
$this->assigner = $assigner;
$this->generator = $generator;
$this->configRevert = $config_revert;
$this->excluded = [];
$this->required = [];
$this->conflicts = [];
$this->missing = [];
}
public static function create(ContainerInterface $container) {
return new static($container
->get('features.manager'), $container
->get('features_assigner'), $container
->get('features_generator'), $container
->get('features.config_update'));
}
public function getFormId() {
return 'features_edit_form';
}
public function buildForm(array $form, FormStateInterface $form_state, $featurename = '') {
$session = $this
->getRequest()
->getSession();
$trigger = $form_state
->getTriggeringElement();
if (isset($trigger['#name']) && $trigger['#name'] == 'package') {
$this->oldBundle = $this->bundle;
}
elseif (isset($trigger['#name']) && $trigger['#name'] == 'conflicts') {
if (isset($session)) {
$session
->set('features_allow_conflicts', $form_state
->getValue('conflicts'));
}
}
if (!$form_state
->isValueEmpty('package')) {
$bundle_name = $form_state
->getValue('package');
$bundle = $this->assigner
->getBundle($bundle_name);
}
else {
$bundle = $this->assigner
->loadBundle();
}
$this->bundle = $bundle
->getMachineName();
$this->allowConflicts = FALSE;
if (isset($session)) {
$this->allowConflicts = $session
->get('features_allow_conflicts', FALSE);
}
$this->assigner
->assignConfigPackages(TRUE);
$packages = $this->featuresManager
->getPackages();
if (empty($packages[$featurename])) {
$featurename = str_replace([
'-',
' ',
], '_', $featurename);
$this->package = $this->featuresManager
->initPackage($featurename, NULL, '', 'module', $bundle);
}
else {
$this->package = $packages[$featurename];
}
if (!empty($packages[$featurename]) && $this->package
->getBundle() !== $this->bundle && $form_state
->isValueEmpty('package')) {
$bundle = $this->assigner
->getBundle($this->package
->getBundle());
if (empty($bundle)) {
$bundle = $this->assigner
->createBundleFromDefault($this->package
->getBundle());
}
$this->bundle = $bundle
->getMachineName();
$this->assigner
->reset();
$this->assigner
->assignConfigPackages(TRUE);
$packages = $this->featuresManager
->getPackages();
$this->package = $packages[$featurename];
}
$form = [
'#show_operations' => FALSE,
'#prefix' => '<div id="features-edit-wrapper" class="features-edit-wrapper clearfix">',
'#suffix' => '</div>',
];
$form['info'] = [
'#type' => 'fieldset',
'#title' => $this
->t('General Information'),
'#tree' => FALSE,
'#weight' => 2,
'#prefix' => '<div id="features-export-info" class="features-export-info">',
'#suffix' => '</div>',
];
$form['info']['name'] = [
'#title' => $this
->t('Name'),
'#description' => $this
->t('Example: Image gallery') . ' (' . $this
->t('Do not begin name with numbers.') . ')',
'#type' => 'textfield',
'#default_value' => $this->package
->getName(),
];
if (!$bundle
->isDefault()) {
$form['info']['name']['#description'] .= '<br/>' . $this
->t('The namespace "@name_" will be prepended to the machine name', [
'@name' => $bundle
->getMachineName(),
]);
}
$form['info']['machine_name'] = [
'#type' => 'machine_name',
'#title' => $this
->t('Machine-readable name'),
'#description' => $this
->t('Example: image_gallery') . ' ' . $this
->t('May only contain lowercase letters, numbers and underscores.'),
'#required' => TRUE,
'#default_value' => $bundle
->getShortName($this->package
->getMachineName()),
'#machine_name' => [
'source' => [
'info',
'name',
],
'exists' => [
$this,
'featureExists',
],
],
];
if (!$bundle
->isDefault()) {
$form['info']['machine_name']['#description'] .= '<br/>' . $this
->t('NOTE: Do NOT include the namespace prefix "@name_"; it will be added automatically.', [
'@name' => $bundle
->getMachineName(),
]);
}
$form['info']['description'] = [
'#title' => $this
->t('Description'),
'#description' => $this
->t('Provide a short description of what users should expect when they install your feature.'),
'#type' => 'textarea',
'#rows' => 3,
'#default_value' => $this->package
->getDescription(),
];
$form['info']['package'] = [
'#title' => $this
->t('Bundle'),
'#type' => 'select',
'#options' => $this->assigner
->getBundleOptions(),
'#default_value' => $bundle
->getMachineName(),
'#ajax' => [
'callback' => '::updateBundle',
'wrapper' => 'features-export-info',
],
];
$form['info']['version'] = [
'#title' => $this
->t('Version'),
'#description' => $this
->t('Examples: 8.x-1.0, 3.1.4'),
'#type' => 'textfield',
'#required' => FALSE,
'#default_value' => $this->package
->getVersion(),
'#size' => 30,
];
[
$full_name,
$path,
] = $this->featuresManager
->getExportInfo($this->package, $bundle);
$form['info']['directory'] = [
'#title' => $this
->t('Path'),
'#description' => $this
->t('Path to export package using Write action, relative to root directory.'),
'#type' => 'textfield',
'#required' => FALSE,
'#default_value' => $path,
'#size' => 30,
];
$require_all = $this->package
->getRequiredAll();
$form['info']['require_all'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Mark all config as required'),
'#default_value' => $this->package
->getRequiredAll(),
'#description' => $this
->t('Required config will be assigned to this feature regardless of other assignment plugins.'),
];
$form['conflicts'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Allow conflicts'),
'#default_value' => $this->allowConflicts,
'#description' => $this
->t('Allow configuration to be exported to more than one feature.'),
'#weight' => 8,
'#ajax' => [
'callback' => '::updateForm',
'wrapper' => 'features-edit-wrapper',
],
'#wrapper_attributes' => [
'class' => [
'features-ui-conflicts',
],
],
];
$generation_info = [];
if (\Drupal::currentUser()
->hasPermission('export configuration')) {
$generation_info = $this->generator
->getGenerationMethods();
uasort($generation_info, '\\Drupal\\Component\\Utility\\SortArray::sortByWeightElement');
}
$form['actions'] = [
'#type' => 'actions',
'#tree' => TRUE,
];
foreach ($generation_info as $method_id => $method) {
$form['actions'][$method_id] = [
'#type' => 'submit',
'#name' => $method_id,
'#value' => $this
->t('@name', [
'@name' => $method['name'],
]),
'#attributes' => [
'title' => Html::escape($method['description']),
],
];
}
$form['export'] = $this
->buildComponentList($form_state);
if (!empty($this->missing)) {
if ($this->allowConflicts) {
$form['actions']['#prefix'] = '<strong>' . $this
->t('WARNING: Package contains configuration missing from site.') . '<br>' . $this
->t('This configuration will be removed if you export it.') . '</strong>';
}
else {
foreach ($generation_info as $method_id => $method) {
unset($form['actions'][$method_id]);
}
$form['actions']['#prefix'] = '<strong>' . $this
->t('Package contains configuration missing from site.') . '<br>' . $this
->t('Import the feature to create the missing config before you can export it.') . '<br>' . $this
->t('Or, enable the Allow Conflicts option above.') . '</strong>';
}
$form['actions']['import_missing'] = [
'#type' => 'submit',
'#name' => 'import_missing',
'#value' => $this
->t('Import Missing'),
'#attributes' => [
'title' => $this
->t('Import only the missing configuration items.'),
],
];
}
$form['#attached'] = [
'library' => [
'features_ui/drupal.features_ui.admin',
],
'drupalSettings' => [
'features' => [
'excluded' => $this->excluded,
'required' => $this->required,
'conflicts' => $this->conflicts,
'autodetect' => TRUE,
],
],
];
return $form;
}
public function updateForm($form, FormStateInterface $form_state) {
return $form;
}
public function updateBundle($form, FormStateInterface $form_state) {
$old_bundle = $this->assigner
->getBundle($this->oldBundle);
$bundle_name = $form_state
->getValue('package');
$bundle = $this->assigner
->getBundle($bundle_name);
if (isset($bundle) && isset($old_bundle)) {
$short_name = $old_bundle
->getShortName($this->package
->getMachineName());
if ($bundle
->isDefault()) {
$short_name = $old_bundle
->getFullName($short_name);
}
$this->package
->setMachineName($bundle
->getFullName($short_name));
$form['info']['machine_name']['#value'] = $bundle
->getShortName($this->package
->getMachineName());
}
return $form['info'];
}
public function featureExists($value, $element, $form_state) {
$bundle = $this->assigner
->getBundle($this->bundle);
$value = $bundle
->getFullName($value);
$packages = $this->featuresManager
->getPackages();
return isset($packages[$value]) && $packages[$value]
->getState() !== FeaturesManagerInterface::STATUS_NO_EXPORT || \Drupal::moduleHandler()
->moduleExists($value);
}
protected function buildComponentList(FormStateInterface $form_state) {
$element = [
'#type' => 'fieldset',
'#title' => $this
->t('Components'),
'#description' => $this
->t('Expand each component section and select which items should be included in this feature export.'),
'#tree' => FALSE,
'#prefix' => '<div id="features-export-wrapper" class="features-export-wrapper js-features-export-wrapper">',
'#suffix' => '</div>',
'#weight' => 1,
];
$element['features_filter_wrapper'] = [
'#type' => 'fieldgroup',
'#title' => $this
->t('Filters'),
'#title_display' => 'invisible',
'#tree' => FALSE,
'#prefix' => '<div id="features-filter" class="features-filter js-features-filter visually-hidden">',
'#suffix' => '</div>',
'#weight' => -10,
'#attributes' => [
'class' => [
'features-filter__fieldset',
'container-inline',
],
],
];
$element['features_filter_wrapper']['features_filter'] = [
'#type' => 'textfield',
'#title' => $this
->t('Search'),
'#hidden' => TRUE,
'#default_value' => '',
'#attributes' => [
'class' => [
'js-features-filter-input',
],
],
'#suffix' => "<span class='features-filter-clear js-features-filter-clear'>" . $this
->t('Clear') . "</span>",
];
$element['features_filter_wrapper']['checkall'] = [
'#type' => 'checkbox',
'#default_value' => FALSE,
'#hidden' => TRUE,
'#title' => $this
->t('Select all'),
'#attributes' => [
'class' => [
'features-checkall',
'js-features-checkall',
'features-filter',
'js-features-filter',
],
],
'#label_attributes' => [
'title' => $this
->t('Select all currently expanded configurations'),
],
];
$element['features_filter_wrapper']['toggle-components'] = [
'#type' => 'html_tag',
'#tag' => 'a',
'#value' => $this
->t('Expand all'),
'#attributes' => [
'href' => '#',
'title' => $this
->t('Expand/collapse components in order to "Select all".'),
'class' => [
'features-toggle-components',
'features-filter',
'js-features-filter',
],
],
];
$element['features_filter_wrapper']['hide-components'] = [
'#type' => 'select',
'#title' => $this
->t('Hide'),
'#options' => [
'included' => $this
->t('Normal'),
'included+groups' => $this
->t('Normal (and empty groups)'),
'added' => $this
->t('Added'),
'detected' => $this
->t('Auto detected'),
'conflict' => $this
->t('Conflict'),
],
'#empty_option' => $this
->t('- None -'),
'#default_value' => '',
'#attributes' => [
'class' => [
'features-hide-component',
'features-filter',
'js-features-filter',
],
'title' => $this
->t('Hide specific Features components'),
],
];
$element['features_filter_wrapper']['features_legend'] = [
'#type' => 'fieldset',
'#title' => $this
->t('Legend'),
'#tree' => FALSE,
'#prefix' => '<div id="features-legend">',
'#suffix' => '</div>',
];
$element['features_filter_wrapper']['features_legend']['legend'] = [
'#markup' => implode('', [
"<span class='features-legend-component features-legend-component--included'>" . $this
->t('Normal') . '</span> ',
"<span class='features-legend-component features-legend-component--added'>" . $this
->t('Added') . '</span> ',
"<span class='features-legend-component features-legend-component--detected'>" . $this
->t('Auto detected') . '</span> ',
"<span class='features-legend-component features-legend-component--conflict'>" . $this
->t('Conflict') . '</span> ',
]),
];
$sections = [
'included',
'detected',
'added',
];
$config_types = $this->featuresManager
->listConfigTypes();
$export = $this
->getComponentList($form_state);
foreach ($export['components'] as $component => $component_info) {
$component_items_count = count($component_info['_features_options']['sources']);
$label = new FormattableMarkup('@component (<span class="component-count js-component-count">@count</span>)', [
'@component' => $config_types[$component],
'@count' => $component_items_count,
]);
$count = 0;
foreach ($sections as $section) {
$count += count($component_info['_features_options'][$section]);
}
$extra_class = $count == 0 ? 'features-export-empty' : '';
$component_name = str_replace('_', '-', Html::escape($component));
if ($count + $component_items_count > 0) {
$element[$component] = [
'#markup' => '',
'#tree' => TRUE,
];
$element[$component]['sources'] = [
'#type' => 'details',
'#title' => $label,
'#tree' => TRUE,
'#open' => FALSE,
'#attributes' => [
'class' => [
'features-export-component',
'js-features-export-component',
],
],
'#prefix' => "<div class='features-export-parent js-features-export-parent js-component--name-{$component}'>",
];
$element[$component]['sources']['selected'] = [
'#type' => 'checkboxes',
'#id' => "edit-sources-{$component_name}",
'#options' => $this
->domDecodeOptions($component_info['_features_options']['sources']),
'#default_value' => $this
->domDecodeOptions($component_info['_features_selected']['sources'], FALSE),
'#attributes' => [
'class' => [
'component-select',
],
],
'#prefix' => "<span class='components-select js-components-select'>",
'#suffix' => '</span>',
];
$element[$component]['before-list'] = [
'#markup' => "<div class='component-list js-component-list features-export-list js-features-export-list {$extra_class}'>",
];
foreach ($sections as $section) {
$element[$component][$section] = [
'#type' => 'checkboxes',
'#options' => !empty($component_info['_features_options'][$section]) ? $this
->domDecodeOptions($component_info['_features_options'][$section]) : [],
'#default_value' => !empty($component_info['_features_selected'][$section]) ? $this
->domDecodeOptions($component_info['_features_selected'][$section], FALSE) : [],
'#attributes' => [
'class' => [
'component-' . $section,
'js-component-' . $section,
],
],
'#prefix' => "<span class='components-{$section} js-components-{$section}'>",
'#suffix' => '</span>',
];
}
$element[$component]['after-list'] = [
'#markup' => "</div></div>",
];
}
}
$element['features_missing'] = [
'#theme' => 'item_list',
'#wrapper_attributes' => [
'class' => [
'features-missing-items',
],
],
'#items' => $export['missing'],
'#title' => $this
->t('Configuration missing from active site:'),
'#suffix' => '<div class="description">' . $this
->t('Import the feature to create the missing config listed above.') . '</div>',
'#access' => !empty($export['missing']),
];
return $element;
}
protected function getComponentList(FormStateInterface $form_state) {
$config = $this->featuresManager
->getConfigCollection();
$package_name = $this->package
->getMachineName();
$package_config = $this->package
->getConfig();
if (!empty($this->package
->getConfigOrig())) {
$package_config = array_unique(array_merge($package_config, $this->package
->getConfigOrig()));
}
if (!empty($package_config)) {
$this->featuresManager
->assignConfigDependents($package_config, $package_name);
}
$packages = $this->featuresManager
->getPackages();
$this->package = $packages[$package_name];
$components = [];
$this->conflicts = [];
foreach ($config as $item_name => $item) {
if ($item
->getPackage() != $package_name && !empty($packages[$item
->getPackage()]) && $packages[$item
->getPackage()]
->getStatus() != FeaturesManagerInterface::STATUS_NO_EXPORT) {
$this->conflicts[$item
->getType()][$item
->getShortName()] = $item
->getLabel();
}
if ($this->allowConflicts || !isset($this->conflicts[$item
->getType()][$item
->getShortName()]) || $this->package
->getConfigOrig() && in_array($item_name, $this->package
->getConfigOrig())) {
$components[$item
->getType()][$item
->getShortName()] = $item
->getLabel();
}
}
$this->missing = [];
$exported_features_info = [];
foreach ($this->package
->getConfigOrig() as $item_name) {
if (isset($config[$item_name])) {
$item = $config[$item_name];
$exported_features_info[$item
->getType()][$item
->getShortName()] = $item
->getLabel();
}
else {
$this->missing[] = $item_name;
}
}
$exported_features_info['dependencies'] = $this->package
->getDependencyInfo();
foreach ([
'excluded',
'required',
] as $constraint) {
$this->{$constraint} = [];
$info = !empty($this->package
->{'get' . $constraint}()) ? $this->package
->{'get' . $constraint}() : [];
if (is_array($info)) {
foreach ($info as $item_name) {
if (!isset($config[$item_name])) {
continue;
}
$item = $config[$item_name];
$this->{$constraint}[$item
->getType()][$item
->getShortName()] = $item
->getLabel();
}
}
}
$new_features_info = [];
foreach ($this->package
->getConfig() as $item_name) {
$item = $config[$item_name];
$new_features_info[$item
->getType()][$item
->getShortName()] = $item
->getLabel();
}
$new_features_info['dependencies'] = $this->package
->getDependencies();
$config_new = [];
$sections = [
'sources',
'included',
'detected',
'added',
];
$config_count = [];
foreach ($components as $component => $component_info) {
$config_new[$component] = [];
$config_count[$component] = 0;
if (!$form_state
->isValueEmpty([
$component,
'sources',
'selected',
])) {
$config_new[$component] = $config_new[$component] + $this
->domDecodeOptions(array_filter($form_state
->getValue([
$component,
'sources',
'selected',
])));
$config_count[$component]++;
}
foreach ([
'included',
'added',
'detected',
] as $section) {
if (!$form_state
->isValueEmpty([
$component,
$section,
])) {
$config_new[$component] = $config_new[$component] + $this
->domDecodeOptions(array_filter($form_state
->getValue([
$component,
$section,
])));
$config_count[$component]++;
}
}
if ($component == 'dependencies') {
if ($config_count[$component] == 0 && !empty($exported_features_info['dependencies'])) {
$config_new[$component] = array_combine($exported_features_info['dependencies'], $exported_features_info['dependencies']);
}
}
elseif ($config_count[$component] == 0 && !empty($exported_features_info[$component])) {
$config_names = array_keys($exported_features_info[$component]);
$config_new[$component] = array_combine($config_names, $config_names);
}
}
$export['package'] = $this->package;
$export['config_new'] = $config_new;
foreach ($components as $component => $component_info) {
$component_export = $component_info;
foreach ($sections as $section) {
$component_export['_features_options'][$section] = [];
$component_export['_features_selected'][$section] = [];
}
if (!empty($component_info)) {
$exported_components = !empty($exported_features_info[$component]) ? $exported_features_info[$component] : [];
$new_components = !empty($new_features_info[$component]) ? $new_features_info[$component] : [];
foreach ($component_info as $key => $label) {
$config_name = $this->featuresManager
->getFullName($component, $key);
if (!$form_state
->isValueEmpty([
$component,
'sources',
'selected',
$key,
])) {
$form_state
->setValue([
$component,
'sources',
'selected',
$key,
], FALSE);
$form_state
->setValue([
$component,
'added',
$key,
], 1);
$component_export['_features_options']['added'][$key] = $this
->configLabel($component, $key, $label);
$component_export['_features_selected']['added'][$key] = $key;
if (isset($this->excluded[$component][$key])) {
unset($this->excluded[$component][$key]);
}
else {
$this->required[$component][$key] = $key;
}
}
elseif (isset($new_components[$key]) || isset($config_new[$component][$key])) {
if (isset($exported_components[$key])) {
$section = 'included';
$default_value = $key;
if ($form_state
->isSubmitted() && ($form_state
->hasValue([
$component,
'included',
$key,
]) || $form_state
->isValueEmpty([
$component,
'detected',
$key,
])) && empty($config_new[$component][$key])) {
$section = 'detected';
$default_value = FALSE;
}
elseif ($form_state
->isSubmitted() && $form_state
->isValueEmpty([
$component,
'added',
$key,
]) && $form_state
->isValueEmpty([
$component,
'detected',
$key,
]) && $form_state
->isValueEmpty([
$component,
'included',
$key,
])) {
$section = 'added';
$default_value = FALSE;
}
}
else {
$section = 'detected';
$default_value = NULL;
if (isset($this->excluded[$component][$key]) && !$form_state
->isSubmitted()) {
$default_value = FALSE;
}
else {
$default_value = $key;
}
if ($form_state
->isSubmitted() && (!$form_state
->isValueEmpty([
$component,
'added',
$key,
]) || !$form_state
->isValueEmpty([
$component,
'sources',
'selected',
$key,
]))) {
$section = 'added';
$default_value = $key;
}
elseif ($form_state
->isSubmitted() && $form_state
->isValueEmpty([
$component,
'sources',
'selected',
$key,
]) && $form_state
->isValueEmpty([
$component,
'detected',
$key,
]) && !$form_state
->hasValue([
$component,
'added',
$key,
])) {
$section = 'detected';
$default_value = FALSE;
}
}
$component_export['_features_options'][$section][$key] = $this
->configLabel($component, $key, $label);
$component_export['_features_selected'][$section][$key] = $default_value;
if ($section == 'detected' && $default_value === FALSE) {
if (!isset($this->required[$component][$key]) || $this->package
->getRequired() === TRUE) {
$this->excluded[$component][$key] = $key;
}
unset($this->required[$component][$key]);
if ($component == 'dependencies') {
$export['package']
->removeDependency($key);
}
else {
$export['package']
->removeConfig($config_name);
}
}
else {
unset($this->excluded[$component][$key]);
}
if ($form_state
->isSubmitted()) {
if (!$default_value) {
$form_state
->setValue([
$component,
$section,
$key,
], FALSE);
}
else {
$form_state
->setValue([
$component,
$section,
$key,
], 1);
}
}
}
elseif (!$form_state
->isSubmitted() && isset($exported_components[$key])) {
$component_export['_features_options']['added'][$key] = $this
->configLabel($component, $key, $label);
$component_export['_features_selected']['added'][$key] = $key;
}
else {
$added = FALSE;
foreach ([
'included',
'added',
] as $section) {
if (!$form_state
->isValueEmpty([
$component,
$section,
$key,
])) {
$component_export['_features_options'][$section][$key] = $this
->configLabel($component, $key, $label);
$component_export['_features_selected'][$section][$key] = $key;
$added = TRUE;
}
}
if (!$added) {
$component_export['_features_options']['sources'][$key] = $this
->configLabel($component, $key, $label);
$component_export['_features_selected']['sources'][$key] = FALSE;
}
}
}
}
$export['components'][$component] = $component_export;
}
$export['features_exclude'] = $this->excluded;
$export['features_require'] = $this->required;
$export['conflicts'] = $this->conflicts;
$export['missing'] = $this->missing;
return $export;
}
protected function configLabel($type, $key, $label) {
$value = Html::escape($label);
if ($key != $label) {
$value .= ' <span class="config-name">(' . Html::escape($key) . ')</span>';
}
if (isset($this->conflicts[$type][$key])) {
$config = $this->featuresManager
->getConfigCollection();
$config_name = $this->featuresManager
->getFullName($type, $key);
$package_name = isset($config[$config_name]) ? $config[$config_name]
->getPackage() : '';
$packages = $this->featuresManager
->getPackages();
if (isset($packages[$package_name])) {
$package_name = $packages[$package_name]
->getMachineName();
}
$value .= ' <span class="config-name">[' . $this
->t('in') . ' ' . Html::escape($package_name) . ']</span>';
}
return Xss::filterAdmin($value);
}
public function submitForm(array &$form, FormStateInterface $form_state) {
$bundle = $this->assigner
->getBundle($this->bundle);
$this->assigner
->assignConfigPackages();
$this->package
->setName($form_state
->getValue('name'));
$this->package
->setMachineName($form_state
->getValue('machine_name'));
$this->package
->setDescription($form_state
->getValue('description'));
$this->package
->setVersion($form_state
->getValue('version'));
$this->package
->setDirectory($form_state
->getValue('directory'));
$this->package
->setBundle($bundle
->getMachineName());
$this->featuresManager
->setPackage($this->package);
$config = $this
->updatePackageConfig($form_state);
$this->featuresManager
->assignConfigPackage($this->package
->getMachineName(), $config, TRUE);
$this->package
->setExcluded($this
->updateExcluded());
if ($form_state
->getValue('require_all')) {
$this->package
->setRequired(TRUE);
}
else {
$required = $this
->updateRequired();
$this->package
->setRequired($required);
}
$this->featuresManager
->setPackage($this->package);
$method_id = NULL;
$trigger = $form_state
->getTriggeringElement();
$op = $form_state
->getValue('op');
if (!empty($trigger) && empty($op)) {
$method_id = $trigger['#name'];
}
$form_state
->setRedirect('features.edit', [
'featurename' => $this->package
->getMachineName(),
]);
if ($method_id == 'import_missing') {
$this
->importMissing();
}
elseif (!empty($method_id)) {
$packages = [
$this->package
->getMachineName(),
];
$this->generator
->generatePackages($method_id, $bundle, $packages);
$this->generator
->applyExportFormSubmit($method_id, $form, $form_state);
}
$this->assigner
->setCurrent($bundle);
}
protected function updatePackageConfig(FormStateInterface $form_state) {
$config = [];
$components = $this
->getComponentList($form_state);
foreach ($components['config_new'] as $config_type => $items) {
foreach ($items as $name) {
$config[] = $this->featuresManager
->getFullName($config_type, $name);
}
}
return $config;
}
protected function importMissing() {
$config = $this->featuresManager
->getConfigCollection();
$missing = $this->featuresManager
->reorderMissing($this->missing);
foreach ($missing as $config_name) {
if (!isset($config[$config_name])) {
$item = $this->featuresManager
->getConfigType($config_name);
$type = ConfigurationItem::fromConfigStringToConfigType($item['type']);
try {
$this->configRevert
->import($type, $item['name_short']);
$this
->messenger()
->addStatus($this
->t('Imported @name', [
'@name' => $config_name,
]));
} catch (\Exception $e) {
$this
->messenger()
->addError($this
->t('Error importing @name : @message', [
'@name' => $config_name,
'@message' => $e
->getMessage(),
]));
}
}
}
}
protected function updateExcluded() {
return $this
->updateConstrained('excluded');
}
protected function updateRequired() {
return $this
->updateConstrained('required');
}
protected function updateConstrained($constraint) {
$constrained = [];
foreach ($this->{$constraint} as $type => $item) {
foreach ($item as $name => $value) {
$constrained[] = $this->featuresManager
->getFullName($type, $name);
}
}
return $constrained;
}
protected function domEncode($key) {
$replacements = $this
->domEncodeMap();
return strtr($key, $replacements);
}
protected function domDecode($key) {
$replacements = array_flip($this
->domEncodeMap());
return strtr($key, $replacements);
}
protected function domDecodeOptions(array $options, $keys_only = FALSE) {
$replacements = array_flip($this
->domEncodeMap());
$encoded = [];
foreach ($options as $key => $value) {
$encoded[strtr($key, $replacements)] = $keys_only ? $value : strtr($value, $replacements);
}
return $encoded;
}
protected function domEncodeMap() {
return [
':' => '__' . ord(':') . '__',
'/' => '__' . ord('/') . '__',
',' => '__' . ord(',') . '__',
'.' => '__' . ord('.') . '__',
'<' => '__' . ord('<') . '__',
'>' => '__' . ord('>') . '__',
'%' => '__' . ord('%') . '__',
')' => '__' . ord(')') . '__',
'(' => '__' . ord('(') . '__',
];
}
}