You are here

function _drush_features_component_filter in Features 7.2

Same name and namespace in other branches
  1. 8.4 drush/features.drush8.inc \_drush_features_component_filter()
  2. 8.3 drush/features.drush8.inc \_drush_features_component_filter()
  3. 7 features.drush.inc \_drush_features_component_filter()

Filters components by patterns.

Parameters

string[][] $all_components: Format: $[$component][$name] = $title.

string[] $patterns: Format: $[] = $pattern.

bool[] $options: Options to control what is returned, and which components are included. Exported items (defined in at least one enabled are included if $options['exported'] is TRUE(-ish) or not provided. Non-exported items If $options['exported'] is TRUE(-ish) or not provided, "exported" features are Possible array keys: 'exported', 'not exported', 'provided by'.

Return value

array[]|false Format: Contains two sub-arrays: $['components'][$component][$name] = $title $['sources'][$component . ':' . $name] = implode(', ', $providing_modules)

2 calls to _drush_features_component_filter()
drush_features_components in ./features.drush.inc
Drush command callback for 'features-components'.
drush_features_export in ./features.drush.inc
Drush command callback for 'features-export'.

File

./features.drush.inc, line 373
Features module drush integration.

Code

function _drush_features_component_filter($all_components, $patterns = array(), $options = array()) {
  $options += array(
    'exported' => TRUE,
    'not exported' => TRUE,
    'provided by' => FALSE,
  );
  $pool = array();

  // Maps exported components to feature modules.
  $components_map = features_get_component_map();

  // First filter on exported state.
  foreach ($all_components as $source => $components) {
    foreach ($components as $name => $title) {
      $exported = !empty($components_map[$source][$name]);
      if ($exported) {
        if ($options['exported']) {
          $pool[$source][$name] = $title;
        }
      }
      else {
        if ($options['not exported']) {
          $pool[$source][$name] = $title;
        }
      }
    }
  }
  $state_string = '';
  if (!$options['exported']) {
    $state_string = 'unexported';
  }
  elseif (!$options['not exported']) {
    $state_string = 'exported';
  }
  $selected = array();
  foreach ($patterns as $pattern) {

    // Rewrite * to %. Let users use both as wildcard.
    $pattern = strtr($pattern, array(
      '*' => '%',
    ));
    $sources = array();
    if (strpos($pattern, ':') !== FALSE) {
      list($source_pattern, $component_pattern) = explode(':', $pattern, 2);
    }
    else {
      $source_pattern = $pattern;
      $component_pattern = '';
    }

    // If source is empty, use a pattern.
    if ($source_pattern == '') {
      $source_pattern = '%';
    }
    if ($component_pattern == '') {
      $component_pattern = '%';
    }
    $preg_source_pattern = strtr(preg_quote($source_pattern, '/'), array(
      '%' => '.*',
    ));
    $preg_component_pattern = strtr(preg_quote($component_pattern, '/'), array(
      '%' => '.*',
    ));

    // If it isn't a pattern, but a simple string, we don't anchor the pattern,
    // this allows for abbreviating. Else, we do, as this seems more natural for
    // patterns.
    if (strpos($source_pattern, '%') !== FALSE) {
      $preg_source_pattern = '^' . $preg_source_pattern . '$';
    }
    if (strpos($component_pattern, '%') !== FALSE) {
      $preg_component_pattern = '^' . $preg_component_pattern . '$';
    }
    $matches = array();

    // Find the sources.
    $all_sources = array_keys($pool);
    $matches = preg_grep('/' . $preg_source_pattern . '/', $all_sources);
    if (sizeof($matches) > 0) {

      // If we have multiple matches and the source string wasn't a
      // pattern, check if one of the matches is equal to the pattern, and
      // use that, or error out.
      if (sizeof($matches) > 1 and $preg_source_pattern[0] != '^') {
        if (in_array($source_pattern, $matches)) {
          $matches = array(
            $source_pattern,
          );
        }
        else {
          return drush_set_error('', dt('Ambiguous source "!source", matches !matches', array(
            '!source' => $source_pattern,
            '!matches' => join(', ', $matches),
          )));
        }
      }

      // Loose the indexes preg_grep preserved.
      $sources = array_values($matches);
    }
    else {
      return drush_set_error('', dt('No !state sources match "!source"', array(
        '!state' => $state_string,
        '!source' => $source_pattern,
      )));
    }

    // Now find the components.
    foreach ($sources as $source) {

      // Find the components.
      $all_components = array_keys($pool[$source]);

      // See if there's any matches.
      $matches = preg_grep('/' . $preg_component_pattern . '/', $all_components);
      if (sizeof($matches) > 0) {

        // If we have multiple matches and the components string wasn't a
        // pattern, check if one of the matches is equal to the pattern, and
        // use that, or error out.
        if (sizeof($matches) > 1 and $preg_component_pattern[0] != '^') {
          if (in_array($component_pattern, $matches)) {
            $matches = array(
              $component_pattern,
            );
          }
          else {
            return drush_set_error('', dt('Ambiguous component "!component", matches !matches', array(
              '!component' => $component_pattern,
              '!matches' => join(', ', $matches),
            )));
          }
        }
        if (empty($selected[$source])) {
          $selected[$source] = array();
        }
        $selected[$source] += array_intersect_key($pool[$source], array_flip($matches));
      }
      else {

        // No matches. If the source was a pattern, just carry on, else
        // error out. Allows for patterns like :*field*.
        if ($preg_source_pattern[0] != '^') {
          return drush_set_error('', dt('No !state !source components match "!component"', array(
            '!state' => $state_string,
            '!component' => $component_pattern,
            '!source' => $source,
          )));
        }
      }
    }
  }

  // Lastly, provide feature module information on the selected components, if
  // requested.
  $provided_by = array();
  if ($options['provided by'] && $options['exported']) {
    foreach ($selected as $source => $components) {
      foreach ($components as $name => $title) {
        $exported = !empty($components_map[$source][$name]);
        if ($exported) {
          $provided_by[$source . ':' . $name] = join(', ', $components_map[$source][$name]);
        }
      }
    }
  }
  return array(
    'components' => $selected,
    'sources' => $provided_by,
  );
}