You are here

function advagg_bundler_merge in Advanced CSS/JS Aggregation 6

Same name and namespace in other branches
  1. 7.2 advagg_bundler/advagg_bundler.advagg.inc \advagg_bundler_merge()
  2. 7 advagg_bundler/advagg_bundler.module \advagg_bundler_merge()

Merge bundles together if too many where created.

This preserves the order.

Parameters

$groupings: array of requested groups

$max: max number of grouping

1 call to advagg_bundler_merge()
advagg_bundler_advagg_filenames_alter in advagg_bundler/advagg_bundler.module
Implement hook_advagg_filenames_alter.

File

advagg_bundler/advagg_bundler.module, line 259
Advanced aggregation bundler module.

Code

function advagg_bundler_merge(&$groupings, $max, $filetype) {
  $group_count = count($groupings);
  if (!empty($max)) {

    // Keep going till array has been merged to the desired size.
    while ($group_count > $max) {

      // Get array sizes.
      // Counts the number of files that are placed into each bundle.
      $counts = array();
      foreach ($groupings as $key => $values) {
        $counts[$key] = count($values);
      }

      // Create mapping.
      // Calculates the file count of potential merges. It only merges with
      // neighbors in order to preserve execution order.
      $map = array();
      $prev_key = '';
      foreach ($counts as $key => $val) {

        // First run of the foreach loop; populate prev key/values and continue.
        // We can't merge with the previous group in this case.
        if (empty($prev_key)) {
          $prev_key = $key;
          $prev_val = $val;
          continue;
        }

        // Array key ($prev_val + $val) is the file count of this new group if
        // these 2 groups ($prev_key, $key) where to be merged together.
        $map[] = array(
          $prev_val + $val => array(
            $prev_key,
            $key,
          ),
        );
        $prev_key = $key;
        $prev_val = $val;
      }

      // Get best merge candidate.
      // We are looking for the smallest file count. $min is populated with a
      // large number (15 bits) so it won't be selected in this process.
      $min = 32767;
      foreach ($map as $v) {
        foreach ($v as $key => $values) {
          $min = min($min, $key);

          // If the min value (number of files in the proposed merged bundle) is
          // the same as the key, then get the 2 bundle keys that generated this
          // new min value.
          if ($min == $key) {
            list($first, $last) = $values;
          }
        }
      }

      // Create the new merged set.
      $a = $groupings[$first];
      $b = $groupings[$last];
      $new_set = array_merge($a, $b);

      // Rebuild the array with the new set in the correct place.
      $new_groupings = array();
      foreach ($groupings as $key => $files) {
        if ($key == $first) {
          $new_groupings[$first . ' ' . $last] = $new_set;
        }
        elseif ($key != $last) {
          $new_groupings[$key] = $files;
        }
      }
      $groupings = $new_groupings;
      $group_count--;
    }
  }

  // Make sure there isn't a group that has all files that don't exist or empty.
  $bad_groups = array();
  $counts = array();
  foreach ($groupings as $key => $group) {
    $missing_counter = 0;
    $counts[$key] = count($group);
    foreach ($group as $i => $file) {
      advagg_clearstatcache(TRUE, $file);
      if (!file_exists($file) || filesize($file) == 0) {
        $missing_counter++;
      }
    }

    // If all files are missing/empty in this group then it is a bad set.
    if ($missing_counter == count($group)) {
      $bad_groups[$key] = TRUE;
    }
  }

  // Add the bad groups to the smallest grouping in this set.
  if (!empty($bad_groups)) {
    $merge_candidate_key = '';
    $merge_candidate_count = 32767;
    $bad_group = array();
    foreach ($groupings as $key => $group) {
      if (isset($bad_groups[$key])) {

        // Merge all bad groups into one.
        $bad_group = array_merge($bad_group, $group);

        // Delete the bad group from the master set.
        unset($groupings[$key]);
        continue;
      }

      // Find the smallest good grouping.
      $min = min($merge_candidate_count, count($group));
      if ($min < $merge_candidate_count) {
        $merge_candidate_key = $key;
        $merge_candidate_count = $min;
      }
    }

    // Move the bad files into the smallest good group.
    $new_set = $groupings[$merge_candidate_key];
    $new_set = array_merge($new_set, $bad_group);
    $groupings[$merge_candidate_key] = $new_set;
  }

  // Prevent CSS selectors exceeding 4095 due to limits with IE9 and below.
  if ($filetype == 'css') {

    // Check each group to see if it exceeds the selector limit.
    do {
      $groupings_edited = FALSE;
      foreach ($groupings as $key => $group) {

        // Restart the selector limit check if the grouping was edited.
        if ($groupings_edited) {
          break;
        }
        $group_selector_counter = 0;
        $selector_counts = advagg_bundler_get_css_selector_count($group);
        for ($i = 0; $i < count($group) && !$groupings_edited; $i++) {
          $selector_count = isset($selector_counts[$group[$i]]) ? $selector_counts[$group[$i]] : 0;
          if ($group_selector_counter + $selector_count > SELECTOR_SPLIT_VALUE) {
            $groupings_edited = TRUE;

            // Divide the group.
            $first_group = array_splice($group, 0, $i);
            $second_group = array_splice($group, 0);

            // Rebuild the array with the new set in the correct place.
            $new_groupings = array();
            foreach ($groupings as $k => $files) {
              if ($k == $key) {
                $new_groupings[$k . '_1'] = $first_group;
                $new_groupings[$k . '_2'] = $second_group;
              }
              else {
                $new_groupings[$k] = $files;
              }
            }
            $groupings = $new_groupings;
          }
          else {
            $group_selector_counter += $selector_count;
          }
        }
      }
    } while ($groupings_edited);
  }
}