/** * {@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())); }
/** * 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; }
/** * {@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); }