/**
  * Reads and merges in existing files for a given package or profile.
  */
 protected function preparePackage(Package $package, array $existing_packages, FeaturesBundleInterface $bundle = NULL)
 {
     if (isset($existing_packages[$package->getMachineName()])) {
         $existing_directory = $existing_packages[$package->getMachineName()];
         // Scan for all files.
         $files = file_scan_directory($existing_directory, '/.*/');
         foreach ($files as $file) {
             // Skip files in the any existing configuration directory, as these
             // will be replaced.
             foreach (array_keys($this->featuresManager->getExtensionStorages()->getExtensionStorages()) as $directory) {
                 if (strpos($file->uri, $directory) !== FALSE) {
                     continue 2;
                 }
             }
             // Merge in the info file.
             if ($file->name == $package->getMachineName() . '.info') {
                 $files = $package->getFiles();
                 $files['info']['string'] = $this->mergeInfoFile($package->getFiles()['info']['string'], $file->uri);
                 $package->setFiles($files);
             } else {
                 // Determine if the file is within a subdirectory of the
                 // extension's directory.
                 $file_directory = dirname($file->uri);
                 if ($file_directory !== $existing_directory) {
                     $subdirectory = substr($file_directory, strlen($existing_directory) + 1);
                 } else {
                     $subdirectory = NULL;
                 }
                 $package->appendFile(['filename' => $file->filename, 'subdirectory' => $subdirectory, 'string' => file_get_contents($file->uri)]);
             }
         }
     }
 }
 /**
  * {@inheritdoc}
  */
 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->setBundle($bundle->getMachineName());
     // Save it first just to create it in case it's a new package.
     $this->featuresManager->setPackage($this->package);
     $this->package->setConfig($this->updatePackageConfig($form_state));
     $this->package->setExcluded($this->updateExcluded());
     $this->package->setRequired($this->updateRequired());
     // Now save it with the selected config data.
     $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'];
     }
     // Set default redirect, but allow generators to change it later.
     $form_state->setRedirect('features.edit', array('featurename' => $this->package->getMachineName()));
     if (!empty($method_id)) {
         $packages = array($this->package->getMachineName());
         $this->generator->generatePackages($method_id, $packages, $bundle);
         $this->generator->applyExportFormSubmit($method_id, $form, $form_state);
     }
     $this->assigner->setCurrent($bundle);
 }
 /**
  * Reads and merges in existing files for a given package or profile.
  *
  * @param \Drupal\features\Package &$package
  *   The package.
  * @param array $existing_packages
  *   An array of existing packages.
  * @param \Drupal\features\FeaturesBundleInterface $bundle
  *   The bundle the package belongs to.
  */
 protected function preparePackage(Package $package, array $existing_packages, FeaturesBundleInterface $bundle = NULL)
 {
     // If this package is already present, prepare files.
     if (isset($existing_packages[$package->getMachineName()])) {
         $existing_directory = $existing_packages[$package->getMachineName()];
         $package->setDirectory($existing_directory);
         // Merge in the info file.
         $info_file_uri = $this->root . '/' . $existing_directory . '/' . $package->getMachineName() . '.info.yml';
         if (file_exists($info_file_uri)) {
             $files = $package->getFiles();
             $files['info']['string'] = $this->mergeInfoFile($package->getFiles()['info']['string'], $info_file_uri);
             $package->setFiles($files);
         }
         // Remove the config directories, as they will be replaced.
         foreach (array_keys($this->featuresManager->getExtensionStorages()->getExtensionStorages()) as $directory) {
             $config_directory = $this->root . '/' . $existing_directory . '/' . $directory;
             if (is_dir($config_directory)) {
                 file_unmanaged_delete_recursive($config_directory);
             }
         }
     }
 }
Exemple #4
0
 /**
  * Builds the details of a package.
  *
  * @param \Drupal\features\Package $package
  *   The package.
  *
  * @return array
  *   A render array of a form element.
  */
 protected function buildPackageDetail(Package $package)
 {
     $config_collection = $this->featuresManager->getConfigCollection();
     $url = Url::fromRoute('features.edit', array('featurename' => $package->getMachineName()));
     $element['name'] = array('data' => \Drupal::l($package->getName(), $url), 'class' => array('feature-name'));
     $machine_name = $package->getMachineName();
     // Except for the 'unpackaged' pseudo-package, display the full name, since
     // that's what will be generated.
     if ($machine_name !== 'unpackaged') {
         $machine_name = $this->assigner->getBundle($package->getBundle())->getFullName($machine_name);
     }
     $element['machine_name'] = $machine_name;
     $element['status'] = array('data' => $this->featuresManager->statusLabel($package->getStatus()), 'class' => array('column-nowrap'));
     // Use 'data' instead of plain string value so a blank version doesn't
     // remove column from table.
     $element['version'] = array('data' => SafeMarkup::checkPlain($package->getVersion()), 'class' => array('column-nowrap'));
     $overrides = $this->featuresManager->detectOverrides($package);
     $new_config = $this->featuresManager->detectNew($package);
     $conflicts = array();
     $missing = array();
     if ($package->getStatus() == FeaturesManagerInterface::STATUS_NO_EXPORT) {
         $overrides = array();
         $new_config = array();
     }
     // Bundle package configuration by type.
     $package_config = array();
     foreach ($package->getConfig() as $item_name) {
         $item = $config_collection[$item_name];
         $package_config[$item->getType()][] = array('name' => SafeMarkup::checkPlain($item_name), 'label' => SafeMarkup::checkPlain($item->getLabel()), 'class' => in_array($item_name, $overrides) ? 'features-override' : (in_array($item_name, $new_config) ? 'features-detected' : ''));
     }
     // Conflict config from other modules.
     foreach ($package->getConfigOrig() as $item_name) {
         if (!isset($config_collection[$item_name])) {
             $missing[] = $item_name;
             $package_config['missing'][] = array('name' => SafeMarkup::checkPlain($item_name), 'label' => SafeMarkup::checkPlain($item_name), 'class' => 'features-conflict');
         } elseif (!in_array($item_name, $package->getConfig())) {
             $item = $config_collection[$item_name];
             $conflicts[] = $item_name;
             $package_config[$item->getType()][] = array('name' => SafeMarkup::checkPlain($item_name), 'label' => SafeMarkup::checkPlain($item->getLabel()), 'class' => 'features-conflict');
         }
     }
     // Add dependencies.
     $package_config['dependencies'] = array();
     foreach ($package->getDependencies() as $dependency) {
         $package_config['dependencies'][] = array('name' => $dependency, 'label' => $this->moduleHandler->getName($dependency), 'class' => '');
     }
     $class = '';
     $label = '';
     if (!empty($conflicts)) {
         $url = Url::fromRoute('features.edit', array('featurename' => $package->getMachineName()));
         $class = 'features-conflict';
         $label = $this->t('Conflicts');
     } elseif (!empty($overrides)) {
         $url = Url::fromRoute('features.diff', array('featurename' => $package->getMachineName()));
         $class = 'features-override';
         $label = $this->featuresManager->stateLabel(FeaturesManagerInterface::STATE_OVERRIDDEN);
     } elseif (!empty($new_config)) {
         $url = Url::fromRoute('features.diff', array('featurename' => $package->getMachineName()));
         $class = 'features-detected';
         $label = $this->t('New detected');
     } elseif (!empty($missing)) {
         $url = Url::fromRoute('features.edit', array('featurename' => $package->getMachineName()));
         $class = 'features-conflict';
         $label = $this->t('Missing');
     }
     if (!empty($class)) {
         $element['state'] = array('data' => \Drupal::l($label, $url), 'class' => array($class, 'column-nowrap'));
     } else {
         $element['state'] = '';
     }
     $config_types = $this->featuresManager->listConfigTypes();
     // Add dependencies.
     $config_types['dependencies'] = $this->t('Dependencies');
     $config_types['missing'] = $this->t('Missing');
     uasort($config_types, 'strnatcasecmp');
     $rows = array();
     // Use sorted array for order.
     foreach ($config_types as $type => $label) {
         // For each component type, offer alternating rows.
         $row = array();
         if (isset($package_config[$type])) {
             $row[] = array('data' => array('#type' => 'html_tag', '#tag' => 'span', '#value' => SafeMarkup::checkPlain($label), '#attributes' => array('title' => SafeMarkup::checkPlain($type), 'class' => 'features-item-label')));
             $row[] = array('data' => array('#theme' => 'features_items', '#items' => $package_config[$type], '#value' => SafeMarkup::checkPlain($label), '#title' => SafeMarkup::checkPlain($type)), 'class' => 'item');
             $rows[] = $row;
         }
     }
     $element['table'] = array('#type' => 'table', '#rows' => $rows);
     $details = array();
     $details['description'] = array('#markup' => Xss::filterAdmin($package->getDescription()));
     $details['table'] = array('#type' => 'details', '#title' => array('#markup' => $this->t('Included configuration')), '#description' => array('data' => $element['table']));
     $element['details'] = array('class' => array('description', 'expand'), 'data' => $details);
     return $element;
 }
 /**
  * {@inheritdoc}
  */
 public function getExportInfo(Package $package, FeaturesBundleInterface $bundle = NULL)
 {
     $full_name = isset($bundle) ? $bundle->getFullName($package->getMachineName()) : $package->getMachineName();
     $path = '';
     // Adjust export directory to be in profile.
     if (isset($bundle) && $bundle->isProfile()) {
         $path .= 'profiles/' . $bundle->getProfileName();
     }
     // If this is not the profile package, nest the directory.
     if (!isset($bundle) || !$bundle->isProfilePackage($package->getMachineName())) {
         $path .= empty($path) ? 'modules' : '/modules';
         $export_settings = $this->getExportSettings();
         if (!empty($export_settings['folder'])) {
             $path .= '/' . $export_settings['folder'];
         }
     }
     return array($full_name, $path);
 }
 /**
  * Returns a form element for the given overrides.
  *
  * @param \Drupal\features\Package $package
  *   A package.
  * @param array $overrides
  *   An array of overrides.
  * @param array $missing
  *   An array of missing config.
  *
  * @return array
  *   A form element.
  */
 protected function diffOutput(Package $package, $overrides, $missing = array())
 {
     $element = array();
     $config = $this->featuresManager->getConfigCollection();
     $components = array_merge($missing, $overrides);
     $header = array(array('data' => '', 'class' => 'diff-marker'), array('data' => $this->t('Active site config'), 'class' => 'diff-context'), array('data' => '', 'class' => 'diff-marker'), array('data' => $this->t('Feature code config'), 'class' => 'diff-context'));
     foreach ($components as $name) {
         $rows[] = array(array('data' => $name, 'colspan' => 4, 'header' => TRUE));
         if (!isset($config[$name])) {
             $details = array('#markup' => $this->t('Component in feature missing from active config.'));
         } else {
             $active = $this->featuresManager->getActiveStorage()->read($name);
             $extension = $this->featuresManager->getExtensionStorages()->read($name);
             if (empty($extension)) {
                 $details = array('#markup' => $this->t('Dependency detected in active config but not exported to the feature.'));
             } else {
                 $diff = $this->configDiff->diff($active, $extension);
                 $details = array('#type' => 'table', '#header' => $header, '#rows' => $this->diffFormatter->format($diff), '#attributes' => array('class' => array('diff', 'features-diff')));
             }
         }
         $element[$name] = array('row' => array('data' => array('#type' => 'details', '#title' => Html::escape($name), '#open' => TRUE, '#description' => array('data' => $details))), '#attributes' => array('class' => 'diff-' . $package->getMachineName()));
     }
     return $element;
 }