Given a file info array it will split the file up.

Paramètres

array $file_info: File info array.

Return value

array Array with file and split data.

1 call to Files::splitCssFile()
Files::scanFile dans src/State/Files.php
Given a filename calculate various hashes and gather meta data.

Fichier

src/State/Files.php, line 316

Classe

Files
Provides AdvAgg with a file status state system using a key value store.

Namespace

Drupal\advagg\State

Code

private function splitCssFile(array &$file_info) {
    // Get the CSS file and break up by media queries.
    if (!isset($file_info['contents'])) {
        $file_info['contents'] = file_get_contents($file_info['data']);
    }
    $media_blocks = $this->parseMediaBlocks($file_info['contents']);
    // Get 98% of the css.ie.selector_limit; usually 4013.
    $selector_split_value = (int) max(floor($this->config
        ->get('css.ie.selector_limit') * 0.98), 100);
    $part_selector_count = 0;
    $major_chunks = [];
    $counter = 0;
    // Group media queries together.
    foreach ($media_blocks as $media_block) {
        // Get the number of selectors.
        // http://stackoverflow.com/a/12567381/125684
        $selector_count = preg_match_all('/\\{.+?\\}|,/s', $media_block);
        $part_selector_count += $selector_count;
        if ($part_selector_count > $selector_split_value) {
            if (isset($major_chunks[$counter])) {
                ++$counter;
                $major_chunks[$counter] = $media_block;
            }
            else {
                $major_chunks[$counter] = $media_block;
            }
            ++$counter;
            $part_selector_count = 0;
        }
        else {
            if (isset($major_chunks[$counter])) {
                $major_chunks[$counter] .= "\n" . $media_block;
            }
            else {
                $major_chunks[$counter] = $media_block;
            }
        }
    }
    $file_info['parts'] = [];
    $overall_split = 0;
    $split_at = $selector_split_value;
    $chunk_split_value = (int) $this->config
        ->get('css.ie.selector_limit') - $selector_split_value - 1;
    foreach ($major_chunks as $chunks) {
        // Get the number of selectors.
        $selector_count = preg_match_all('/\\{.+?\\}|,/s', $chunks);
        // Pass through if selector count is low.
        if ($selector_count < $selector_split_value) {
            $overall_split += $selector_count;
            $subfile = $this->createSubfile($chunks, $overall_split, $file_info);
            if (!$subfile) {
                // Somthing broke; do not create a subfile.
                \Drupal::logger('advagg')->notice('Spliting up a CSS file failed. File info: <code>@info</code>', [
                    '@info' => var_export($file_info, TRUE),
                ]);
                return [];
            }
            $file_info['parts'][] = [
                'path' => $subfile,
                'selectors' => $selector_count,
            ];
            continue;
        }
        $media_query = '';
        if (strpos($chunks, '@media') !== FALSE) {
            $media_query_pos = strpos($chunks, '{');
            $media_query = substr($chunks, 0, $media_query_pos);
            $chunks = substr($chunks, $media_query_pos + 1);
        }
        // Split CSS into selector chunks.
        $split = preg_split('/(\\{.+?\\}|,)/si', $chunks, -1, PREG_SPLIT_DELIM_CAPTURE);
        // Setup and handle media queries.
        $new_css_chunk = [
            0 => '',
        ];
        $selector_chunk_counter = 0;
        $counter = 0;
        if (!empty($media_query)) {
            $new_css_chunk[0] = $media_query . '{';
            $new_css_chunk[1] = '';
            ++$selector_chunk_counter;
            ++$counter;
        }
        // Have the key value be the running selector count and put split array
        // semi back together.
        foreach ($split as $value) {
            $new_css_chunk[$counter] .= $value;
            if (strpos($value, '}') === FALSE) {
                ++$selector_chunk_counter;
            }
            else {
                if ($counter + 1 < $selector_chunk_counter) {
                    $selector_chunk_counter += ($counter - $selector_chunk_counter + 1) / 2;
                }
                $counter = $selector_chunk_counter;
                if (!isset($new_css_chunk[$counter])) {
                    $new_css_chunk[$counter] = '';
                }
            }
        }
        // Group selectors.
        while (!empty($new_css_chunk)) {
            // Find where to split the array.
            $string_to_write = '';
            while (array_key_exists($split_at, $new_css_chunk) === FALSE) {
                --$split_at;
            }
            // Combine parts of the css so that it can be saved to disk.
            foreach ($new_css_chunk as $key => $value) {
                if ($key !== $split_at) {
                    // Move this css row to the $string_to_write variable.
                    $string_to_write .= $value;
                    unset($new_css_chunk[$key]);
                }
                else {
                    // Get the number of selectors in this chunk.
                    $chunk_selector_count = preg_match_all('/\\{.+?\\}|,/s', $new_css_chunk[$key]);
                    if ($chunk_selector_count < $chunk_split_value) {
                        // The number of selectors at this point is below the threshold;
                        // move this chunk to the write var and break out of the loop.
                        $string_to_write .= $value;
                        unset($new_css_chunk[$key]);
                        $overall_split = $split_at;
                        $split_at += $selector_split_value;
                    }
                    else {
                        // The number of selectors with this chunk included is over the
                        // threshold; do not move it. Change split position so the next
                        // iteration of the while loop ends at the correct spot. Because
                        // we skip unset here, this chunk will start the next part file.
                        $overall_split = $split_at;
                        $split_at += $selector_split_value - $chunk_selector_count;
                    }
                    break;
                }
            }
            // Handle media queries.
            if (!empty($media_query)) {
                // See if brackets need a new line.
                if (strpos($string_to_write, "\n") === 0) {
                    $open_bracket = '{';
                }
                else {
                    $open_bracket = "{\n";
                }
                if (strrpos($string_to_write, "\n") === strlen($string_to_write)) {
                    $close_bracket = '}';
                }
                else {
                    $close_bracket = "\n}";
                }
                // Fix syntax around media queries.
                if ($first) {
                    $string_to_write .= $close_bracket;
                }
                elseif (empty($new_css_chunk)) {
                    $string_to_write = $media_query . $open_bracket . $string_to_write;
                }
                else {
                    $string_to_write = $media_query . $open_bracket . $string_to_write . $close_bracket;
                }
            }
            // Write the data.
            $subfile = $this->createSubfile($string_to_write, $overall_split, $file_info);
            if (!$subfile) {
                // Somthing broke; did not create a subfile.
                \Drupal::logger('advagg')->notice('Spliting up a CSS file failed. File info: <code>@info</code>', [
                    '@info' => var_export($file_info, TRUE),
                ]);
                return [];
            }
            $sub_selector_count = preg_match_all('/\\{.+?\\}|,/s', $string_to_write, $matches);
            $file_info['parts'][] = [
                'path' => $subfile,
                'selectors' => $sub_selector_count,
            ];
        }
    }
}