You are here

magic.inc in Magic 7

A file to contain functions for the magic module to abuse.

File

includes/magic.inc
View source
<?php

/**
 * @file
 * A file to contain functions for the magic module to abuse.
 */

/**
 * Helper function to change magic keywords into the exclude array.
 *
 * This helper function will remove kewords such as :contrib or :base-theme and
 * change them into the paths that they represent.
 *
 * @param $exclude
 *   An array of paths to remove.
 *
 * @return array
 *   An array with 'exclude' and 'include' as the keys. Exclude contains a set
 *   of files to remove, while 'include' has the files to keep.
 */
function magic_generate_exclude_full($array) {
  global $base_theme_info, $theme_info;
  $return = array(
    'exclude' => array(),
    'include' => array(),
  );
  foreach ($array as $item) {
    $invert = substr($item, 0, 1) == '~' ? TRUE : FALSE;
    if ($invert) {
      $item = substr($item, 1);
    }
    $items = array();

    // We now check the string against a set of standard variables.
    if ($item == ':all') {
      $items[] = '*';
    }
    elseif ($item == ':core') {

      // This is unique as there are several areas where core files might be.
      $items = array(
        'misc/*',
        'modules/*',
        'themes/*',
      );
    }
    elseif ($item == ':contrib') {
      $items[] = 'sites/all/modules/*';
    }
    elseif ($item == ':base-theme') {
      if (empty($base_theme_info)) {

        // We do not actually have a base theme.
        continue;
      }
      $items[] = drupal_get_path('theme', $base_theme_info[0]->name) . '/*';
    }
    elseif ($item == ':current-theme') {
      $items[] = drupal_get_path('theme', $theme_info->name) . '/*';
    }
    else {
      $items[] = $item;
    }
    if ($invert) {
      $return['include'] = array_merge($return['include'], $items);
    }
    else {
      $return['exclude'] = array_merge($return['exclude'], $items);
    }
  }
  return $return;
}

/**
 * Helper function for generating a regex from a list of paths.
 *
 * Generates a single regex from a list of file paths that can be used to match
 * JS or CSS files using preg_grep() for example in hook_css_alter() or
 * hook_js_alter(). The '*' (asterisk) character can be used as a wild-card.
 *
 * @param $paths
 *   An array of file paths.
 *
 * @return string
 *   The generated regex.
 *
 * @see hook_js_alter()
 * @see hook_css_alter()
 */
function magic_generate_path_regex($paths) {
  foreach ($paths as &$item) {

    // The first segment (everything before the first slash) is the namespace.
    // This rule only applies to local files... So if the namespace can not be
    // mapped to a module, profile or theme engine we assume that the we are
    // trying to target an external file.
    list($namespace) = explode('/', $item);

    // Check if the namespace refers to a file residing in the 'misc' folder.
    if ($namespace != '*') {

      // Otherwise, check if it refers to a theme, module, profile or theme
      // engine.
      foreach (array(
        'theme',
        'module',
        'profile',
        'theme_engine',
      ) as $type) {

        // We can't use drupal_get_path() directly because that uses dirname()
        // internally which returns '.' if no filename was found.
        if ($filename = drupal_get_filename($type, $namespace)) {
          $prefix = dirname($filename);
          $item = substr_replace($item, $prefix, 0, strlen($namespace));
          break;
        }
      }
    }

    // Escape any regex characters and turn asterisk wildcards into actual regex
    // wildcards.
    $item = preg_quote($item, '/');
    $item = str_replace('\\*', '(.*)', $item);
  }
  return empty($paths) ? FALSE : '/^(' . implode('|', $paths) . ')$/';
}

/**
 * Helper function for eliminating elements from an array using a simplified
 * regex pattern.
 *
 * @param $elements
 *   The array of elements that should have some of its items removed.
 * @param $regex
 *   A regex as generated by omega_generate_path_regex().
 */
function magic_exclude_assets(&$elements, $exclude, $include) {
  $mapping = magic_generate_asset_mapping($elements);

  // We first check to see if we have an include array. If not, we don't need to
  // check it as well.
  if ($include) {

    // We do a grep on each the exclude list, and include list and return the keys
    // of the exclude list minus those that are specifically included.
    $full_exclude = array_diff_key(preg_grep($exclude, $mapping), preg_grep($include, $mapping));

    // Finally, implode the array of items to exclude into a proper regex and
    // invoke in on the array of files to be excluded.
    $elements = array_diff_key($elements, $full_exclude);
  }
  else {

    // We only have an exclude array, so we only have to do a preg_grep for it.
    $elements = array_diff_key($elements, preg_grep($exclude, $mapping));
  }
}

/**
 * Helper function for generating a map of assets based on the data attribute.
 *
 * We can not rely on the array keys of the JS and CSS file arrays in Drupal
 * because in case of inline JS or CSS (which uses numerical array keys) and due
 * to potential overrides of the 'data' attribute which holds the actual,
 * reliable path of the file. This function returns a single-level array of
 * reliable JS/CSS file paths using the original array keys as keys. Elements of
 * type 'inline' or 'setting' are ignored.
 *
 * @param $elements
 *   An array of JS or CSS files as given in hook_css_alter() or
 *   hook_js_alter().
 *
 * @return array
 *   A map of file paths generated from $elements.
 *
 * @see hook_js_alter()
 * @see hook_css_alter()
 */
function magic_generate_asset_mapping($elements) {
  $mapping = array();
  foreach ($elements as $key => $item) {
    if ($item['type'] == 'inline') {

      // Naturally, in-line CSS is not supported.
      continue;
    }

    // We can also remove the settings array, if we want to. This can only be
    // removed by specifying "settings" in the exclude file.
    if ($item['type'] == 'setting') {
      $mapping[$key] = ':settings';
      continue;
    }

    // We need to build an array containing just the 'data' attribute because
    // that's the actual path of the file. The array key of the elements can
    // be something else if someone is sneaky enough to use drupal_add_js() or
    // drupal_add_css() with a bogus first argument (normally, that is the
    // path to the file) and then specify the actual path through the 'data'
    // attribute in the $options array.
    $mapping[$key] = $item['data'];
  }
  return $mapping;
}

Functions

Namesort descending Description
magic_exclude_assets Helper function for eliminating elements from an array using a simplified regex pattern.
magic_generate_asset_mapping Helper function for generating a map of assets based on the data attribute.
magic_generate_exclude_full Helper function to change magic keywords into the exclude array.
magic_generate_path_regex Helper function for generating a regex from a list of paths.