/**
   * {@inheritdoc}
   */
  public function generate(array $packages = array(), FeaturesBundleInterface $bundle = NULL) {
    // If no packages were specified, get all packages.
    if (empty($packages)) {
      $packages = $this->featuresManager->getPackages();
    }

    $return = [];

    // Add profile files.
    if (isset($bundle) && $bundle->isProfile()) {
      $profile_package = $this->featuresManager->getPackage($bundle->getProfileName());
      if (!empty($profile_package)) {
        $this->generatePackage($return, $profile_package);
      }
    }

    // Add package files.
    // We need to update the system.module.files state because it's cached.
    // Cannot just call system_rebuild_module_data() because $listing->scan() has
    // it's own internal static cache that we cannot clear at this point.
    $files = \Drupal::state()->get('system.module.files');
    foreach ($packages as $package) {
      $this->generatePackage($return, $package);
      if (!isset($files[$package['machine_name']]) && isset($package['files']['info'])) {
        $files[$package['machine_name']] = $package['directory'] . '/' . $package['files']['info']['filename'];
      }
    }

    // Rebuild system module cache
    \Drupal::state()->set('system.module.files', $files);

    return $return;
  }
 /**
  * {@inheritdoc}
  */
 public function generate(array $packages = array(), FeaturesBundleInterface $bundle = NULL)
 {
     // If no packages were specified, get all packages.
     if (empty($packages)) {
         $packages = $this->featuresManager->getPackages();
     }
     // Determine the best name for the tar archive.
     // Single package export, so name by package name.
     if (count($packages) == 1) {
         $filename = current($packages)['machine_name'];
     } elseif (isset($bundle) && $bundle->isProfile()) {
         $filename = $bundle->getProfileName();
     } elseif (isset($bundle) && !$bundle->isDefault()) {
         $filename = $bundle->getMachineName();
     } else {
         $filename = 'generated_features';
     }
     $return = [];
     $this->archiveName = $filename . '.tar.gz';
     $archive_name = file_directory_temp() . '/' . $this->archiveName;
     if (file_exists($archive_name)) {
         file_unmanaged_delete($archive_name);
     }
     $archiver = new ArchiveTar($archive_name);
     // Add package files.
     foreach ($packages as $package) {
         if (count($packages) == 1) {
             // Single module export, so don't generate entire modules dir structure.
             $package['directory'] = $package['machine_name'];
         }
         $this->generatePackage($return, $package, $archiver);
     }
     return $return;
 }
  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $settings = array(
      'types' => array_filter($form_state->getValue('types')),
    );
    $this->currentBundle->setAssignmentSettings(self::METHOD_ID, $settings)->save();
    $this->setRedirect($form_state);

    drupal_set_message($this->t('Package assignment configuration saved.'));
  }
 /**
  * Enables a specified assignment method.
  *
  * @param string $method_id
  *   The ID of an assignment method.
  * @param bool $exclusive
  *   (optional) Whether to set the method as the only enabled method.
  *   Defaults to TRUE.
  */
 protected function enableAssignmentMethod($method_id, $exclusive = TRUE)
 {
     if ($exclusive) {
         $this->bundle->setEnabledAssignments([$method_id]);
     } else {
         $enabled = array_keys($this->bundle->getEnabledAssignments());
         $enabled[] = $method_id;
         $this->bundle->setEnabledAssignments($enabled);
     }
 }
 /**
  * {@inheritdoc}
  */
 public function renameBundle($old_machine, $new_machine) {
   $is_current = (isset($this->currentBundle) && ($old_machine == $this->currentBundle->getMachineName()));
   $bundle = $this->getBundle($old_machine);
   if ($bundle->getMachineName() != '') {
     // Remove old bundle from the list if it's not the Default bundle.
     unset($this->bundles[$old_machine]);
   }
   $bundle->setMachineName($new_machine);
   $this->setBundle($bundle);
   // Put the bundle into the list with the correct name.
   $this->bundles[$bundle->getMachineName()] = $bundle;
   if ($is_current) {
     $this->setCurrent($bundle);
   }
   return $bundle;
 }
 /**
  * Adds the optional bundle prefix to package machine names.
  *
  * @param string[] &$package_names
  *   Array of package names, passed by reference.
  * @param \Drupal\features\FeaturesBundleInterface $bundle
  *   The optional bundle used for the generation.  Used to generate profiles.
  */
 protected function setPackageBundleNames(array &$package_names, FeaturesBundleInterface $bundle = NULL)
 {
     if ($bundle && !$bundle->isDefault()) {
         $new_package_names = [];
         // Assign the selected bundle to the exports.
         $packages = $this->featuresManager->getPackages();
         foreach ($package_names as $package_name) {
             // Rename package to use bundle prefix.
             $package = $packages[$package_name];
             // The install profile doesn't need renaming.
             if ($package['type'] != 'profile') {
                 unset($packages[$package_name]);
                 $package['machine_name'] = $bundle->getFullName($package['machine_name']);
                 $packages[$package['machine_name']] = $package;
             }
             // Set the bundle machine name.
             $packages[$package['machine_name']]['bundle'] = $bundle->getMachineName();
             $new_package_names[] = $package['machine_name'];
         }
         $this->featuresManager->setPackages($packages);
         $package_names = $new_package_names;
     }
 }
 /**
  * {@inheritdoc}
  */
 public function setCurrent(FeaturesBundleInterface $bundle)
 {
     $this->currentBundle = $bundle;
     $session = \Drupal::request()->getSession();
     if (isset($session)) {
         $session->set('features_current_bundle', $bundle->getMachineName());
     }
     return $bundle;
 }
 /**
  * {@inheritdoc}
  */
 public function getExportInfo($package, FeaturesBundleInterface $bundle = NULL)
 {
     $full_name = $package['machine_name'];
     $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['machine_name'])) {
         $path .= empty($path) ? 'modules' : '/modules';
         $export_settings = $this->getExportSettings();
         if (!empty($export_settings['folder'])) {
             $path .= '/' . $export_settings['folder'];
         }
     }
     return array($full_name, $path);
 }
 /**
  * Redirects back to the Bundle config form.
  *
  * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The form state.
  */
 protected function setRedirect(FormStateInterface $form_state)
 {
     $form_state->setRedirect('features.assignment', array('bundle_name' => $this->currentBundle->getMachineName()));
 }
Example #10
0
 /**
  * Builds the details of a package.
  *
  * @param \Drupal\features\Package $package
  *   The package.
  * @param \Drupal\features\FeaturesBundleInterface
  *   The current bundle.
  *
  * @return array
  *   A render array of a form element.
  */
 protected function buildPackageDetail(Package $package, FeaturesBundleInterface $bundle)
 {
     $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 = $bundle->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' => Html::escape($package->getVersion()), 'class' => array('column-nowrap'));
     $overrides = $this->featuresManager->detectOverrides($package);
     $new_config = $this->featuresManager->detectNew($package);
     $conflicts = array();
     $missing = array();
     $moved = 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) {
         if (isset($config_collection[$item_name])) {
             $item = $config_collection[$item_name];
             $package_config[$item->getType()][] = array('name' => Html::escape($item_name), 'label' => Html::escape($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' => Html::escape($item_name), 'label' => Html::escape($item_name), 'class' => 'features-missing');
         } elseif (!in_array($item_name, $package->getConfig())) {
             $item = $config_collection[$item_name];
             if (empty($item->getProvider())) {
                 $conflicts[] = $item_name;
                 $package_name = !empty($item->getPackage()) ? $item->getPackage() : $this->t('PACKAGE NOT ASSIGNED');
                 $package_config[$item->getType()][] = array('name' => Html::escape($package_name), 'label' => Html::escape($item->getLabel()), 'class' => 'features-conflict');
             } else {
                 $moved[] = $item_name;
                 $package_name = !empty($item->getPackage()) ? $item->getPackage() : $this->t('PACKAGE NOT ASSIGNED');
                 $package_config[$item->getType()][] = array('name' => $this->t('Moved to @package', array('@package' => $package_name)), 'label' => Html::escape($item->getLabel()), 'class' => 'features-moved');
             }
         }
     }
     // Add dependencies.
     $package_config['dependencies'] = array();
     foreach ($package->getDependencies() as $dependency) {
         $package_config['dependencies'][] = array('name' => $dependency, 'label' => $this->moduleHandler->getName($dependency), 'class' => '');
     }
     $class = '';
     $state_links = [];
     if (!empty($conflicts)) {
         $state_links[] = array('#type' => 'link', '#title' => $this->t('Conflicts'), '#url' => Url::fromRoute('features.edit', array('featurename' => $package->getMachineName())), '#attributes' => array('class' => array('features-conflict')));
     }
     if (!empty($overrides)) {
         $state_links[] = array('#type' => 'link', '#title' => $this->featuresManager->stateLabel(FeaturesManagerInterface::STATE_OVERRIDDEN), '#url' => Url::fromRoute('features.diff', array('featurename' => $package->getMachineName())), '#attributes' => array('class' => array('features-override')));
     }
     if (!empty($new_config)) {
         $state_links[] = array('#type' => 'link', '#title' => $this->t('New detected'), '#url' => Url::fromRoute('features.diff', array('featurename' => $package->getMachineName())), '#attributes' => array('class' => array('features-detected')));
     }
     if (!empty($missing) && $package->getStatus() == FeaturesManagerInterface::STATUS_INSTALLED) {
         $state_links[] = array('#type' => 'link', '#title' => $this->t('Missing'), '#url' => Url::fromRoute('features.edit', array('featurename' => $package->getMachineName())), '#attributes' => array('class' => array('features-missing')));
     }
     if (!empty($moved)) {
         $state_links[] = array('#type' => 'link', '#title' => $this->t('Moved'), '#url' => Url::fromRoute('features.edit', array('featurename' => $package->getMachineName())), '#attributes' => array('class' => array('features-moved')));
     }
     if (!empty($state_links)) {
         $element['state'] = array('data' => $state_links, 'class' => array('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' => Html::escape($label), '#attributes' => array('title' => Html::escape($type), 'class' => 'features-item-label')));
             $row[] = array('data' => array('#theme' => 'features_items', '#items' => $package_config[$type], '#value' => Html::escape($label), '#title' => Html::escape($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;
 }
Example #11
0
 /**
  * {@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'];
         }
     }
     // Use the same path of a package to override it.
     if ($extension = $package->getExtension()) {
         $extension_path = $extension->getPath();
         $path = dirname($extension_path);
     }
     return array($full_name, $path);
 }
  /**
   * {@inheritdoc}
   */
  public function getExportInfo($package, FeaturesBundleInterface $bundle = NULL) {

    $full_name = $package['machine_name'];

    if (isset($bundle) && $bundle->isProfile()) {
      // Adjust export directory to be in profile.
      $path = 'profiles/' . $bundle->getProfileName() . '/modules';
    }
    else {
      $path = 'modules';
    }

    $export_settings = $this->getExportSettings();
    if (!empty($export_settings['folder'])) {
      $path .= '/' . $export_settings['folder'];
    }

    return array($full_name, $path);
  }