You are here

class FeaturesUIController in Features 8.4

Same name and namespace in other branches
  1. 8.3 modules/features_ui/src/Controller/FeaturesUIController.php \Drupal\features_ui\Controller\FeaturesUIController

Returns ajax responses for the Features UI.

Hierarchy

Expanded class hierarchy of FeaturesUIController

File

modules/features_ui/src/Controller/FeaturesUIController.php, line 14

Namespace

Drupal\features_ui\Controller
View source
class FeaturesUIController implements ContainerInjectionInterface {

  /**
   * The features manager.
   *
   * @var \Drupal\features\FeaturesManagerInterface
   */
  protected $featuresManager;

  /**
   * The package assigner.
   *
   * @var array
   */
  protected $assigner;

  /**
   * Constructs a new FeaturesUIController object.
   *
   * @param \Drupal\features\FeaturesManagerInterface $features_manager
   *   The features manager.
   * @param \Drupal\features\FeaturesAssignerInterface $assigner
   *   The feature assigner.
   */
  public function __construct(FeaturesManagerInterface $features_manager, FeaturesAssignerInterface $assigner) {
    $this->featuresManager = $features_manager;
    $this->assigner = $assigner;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('features.manager'), $container
      ->get('features_assigner'));
  }

  /**
   * Returns a list of auto-detected config items for a feature.
   *
   * @param string $name
   *   Short machine name of feature to process.
   *
   * @return array
   *   List of auto-detected config items, keyed by type and short name.
   */
  public function detect($name) {
    $detected = [];
    $this->assigner
      ->assignConfigPackages();
    $config_collection = $this->featuresManager
      ->getConfigCollection();
    $items = $_POST['items'];
    if (!empty($items)) {
      $excluded = !empty($_POST['excluded']) ? $_POST['excluded'] : [];
      $selected = [];
      foreach ($items as $key) {
        preg_match('/^([^\\[]+)(\\[.+\\])?\\[(.+)\\]\\[(.+)\\]$/', $key, $matches);
        if (!empty($matches[1]) && !empty($matches[4])) {
          $component = $matches[1];
          $item = $this
            ->domDecode($matches[4]);
          if (!isset($excluded[$component][$item])) {
            $selected[] = $this->featuresManager
              ->getFullName($component, $item);
          }
        }
      }
      $detected = !empty($selected) ? $this
        ->getConfigDependents($selected, $name) : [];
      $detected = array_merge($detected, $selected);
    }
    $result = [];
    foreach ($detected as $config_name) {
      $item = $config_collection[$config_name];
      $result[$item
        ->getType()][$item
        ->getShortName()] = $item
        ->getName();
    }
    return new JsonResponse($result);
  }

  /**
   * Returns the configuration dependent on given items.
   *
   * @param array $item_names
   *   An array of item names.
   * @param string $package_name
   *   Short machine name of feature to process.
   *
   * @return array
   *   An array of config items.
   */
  protected function getConfigDependents(array $item_names, $package_name) {
    $result = [];
    $config_collection = $this->featuresManager
      ->getConfigCollection();
    $packages = $this->featuresManager
      ->getPackages();
    $settings = $this->featuresManager
      ->getSettings();
    $allow_conflicts = $settings
      ->get('conflicts');
    if (empty($item_names)) {
      $item_names = array_keys($config_collection);
    }

    // Add any existing auto-detected items already in the package config.
    $this->package = $packages[$package_name];
    $package_config = isset($this->package) ? $this->package
      ->getConfig() : [];
    $package_config = !empty($package_config) ? array_unique(array_merge($package_config, $item_names)) : $item_names;
    foreach ($package_config as $config_name) {
      if (!$config_collection[$config_name]
        ->getPackageExcluded()) {
        $result[] = $config_name;
      }
    }

    // Now add dependents of the items selected.
    foreach ($item_names as $item_name) {
      if ($config_collection[$item_name]
        ->getPackage()) {
        foreach ($config_collection[$item_name]
          ->getDependents() as $dependent_item_name) {
          if (isset($config_collection[$dependent_item_name])) {
            $allow = TRUE;
            if (!$allow_conflicts && $config_collection[$dependent_item_name]
              ->getPackage()) {
              if ($packages[$config_collection[$dependent_item_name]
                ->getPackage()]) {
                $allow = $packages[$config_collection[$dependent_item_name]
                  ->getPackage()]
                  ->getStatus() == FeaturesManagerInterface::STATUS_NO_EXPORT || $config_collection[$item_name]
                  ->getPackage() == $config_collection[$dependent_item_name]
                  ->getPackage();
              }
            }
            if ($allow) {
              $result[] = $dependent_item_name;
            }
          }
        }
      }
    }
    return $result;
  }

  /**
   * Encodes a given key.
   *
   * @param string $key
   *   The key to encode.
   *
   * @return string
   *   The encoded key.
   */
  protected function domEncode($key) {
    $replacements = $this
      ->domEncodeMap();
    return strtr($key, $replacements);
  }

  /**
   * Decodes a given key.
   *
   * @param string $key
   *   The key to decode.
   *
   * @return string
   *   The decoded key.
   */
  protected function domDecode($key) {
    $replacements = array_flip($this
      ->domEncodeMap());
    return strtr($key, $replacements);
  }

  /**
   * Returns encoding map for decode and encode options.
   *
   * @return array
   *   An encoding map.
   */
  protected function domEncodeMap() {
    return [
      ':' => '__' . ord(':') . '__',
      '/' => '__' . ord('/') . '__',
      ',' => '__' . ord(',') . '__',
      '.' => '__' . ord('.') . '__',
      '<' => '__' . ord('<') . '__',
      '>' => '__' . ord('>') . '__',
      '%' => '__' . ord('%') . '__',
      ')' => '__' . ord(')') . '__',
      '(' => '__' . ord('(') . '__',
    ];
  }

}

Members

Namesort descending Modifiers Type Description Overrides
FeaturesUIController::$assigner protected property The package assigner.
FeaturesUIController::$featuresManager protected property The features manager.
FeaturesUIController::create public static function Instantiates a new instance of this class. Overrides ContainerInjectionInterface::create
FeaturesUIController::detect public function Returns a list of auto-detected config items for a feature.
FeaturesUIController::domDecode protected function Decodes a given key.
FeaturesUIController::domEncode protected function Encodes a given key.
FeaturesUIController::domEncodeMap protected function Returns encoding map for decode and encode options.
FeaturesUIController::getConfigDependents protected function Returns the configuration dependent on given items.
FeaturesUIController::__construct public function Constructs a new FeaturesUIController object.