core_library.bypass.inc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <?php
  2. /**
  3. * @file
  4. * Core Library bypass mode specific functions.
  5. */
  6. /**
  7. * Rebuild files for the given CSS group.
  8. *
  9. * This function is mainly a proxy to drupal_build_css_cache() which does its
  10. * job quite well.
  11. *
  12. * Because this function will name files using an ugly hash and does heavy I/O,
  13. * ours will call it only if really necessary, and will use non-randomized file
  14. * names for HTML inclusion, therefore will proceed to a file copy right after
  15. * each aggregated file has been created.
  16. *
  17. * @param array $map
  18. * Mapped filename.
  19. * @param array $medias
  20. * Key value pairs, keys are CSS media property, values are Drupal core CSS
  21. * description array, weight ordered, suitable for building the aggregated
  22. * file.
  23. *
  24. * @return mixed
  25. * Suitable value for stored status array. If there was any during aggregated
  26. * file creation or copy, this will break any remaining files to aggregate
  27. * return NULL, this will force a new attempt on next page hits.
  28. *
  29. * @see core_library_element_style_pre_render()
  30. * @see drupal_build_css_cache()
  31. */
  32. function _core_library_element_style_rebuild_group($map, $css) {
  33. // Best case scenario, we have no files.
  34. if (empty($css)) {
  35. return -1;
  36. }
  37. // Build the file using core function.
  38. if ($file_uri = drupal_build_css_cache($css)) {
  39. if (file_unmanaged_copy($file_uri, 'public://static/' . $map . '.css', FILE_EXISTS_REPLACE)) {
  40. // Mark the file as built.
  41. watchdog('core_library', "CSS file for mapping " . $map . " has been sucessfully built", NULL, WATCHDOG_NOTICE);
  42. return TRUE;
  43. }
  44. else {
  45. watchdog('core_library', "CSS file for mapping " . $map . " could not be copied after being built", NULL, WATCHDOG_ERROR);
  46. return NULL;
  47. }
  48. }
  49. else {
  50. // Built has failed, therefore we cannot continue.
  51. watchdog('core_library', "CSS file for mapping " . $map . " could not be built", NULL, WATCHDOG_ERROR);
  52. return NULL;
  53. }
  54. }
  55. /**
  56. * drupal_pre_render_styles() replacement.
  57. *
  58. * This function pass through multiple steps:
  59. * 1. Fetch the current aggregated files status in the $status array.
  60. * 2. Fetch the user set groups configuration in the $groups array.
  61. * 3. Check we have files matching in the status array for each group, mark
  62. * each missing file for rebuild in the $rebuild array.
  63. * 4. Iterate over the $rebuild array, and rebuild missing files (if they are
  64. * files matching the group).
  65. * 5. If any modification has been done to $status, save it for next hits.
  66. * 6. Build the drupal_render() final result using the current $status array
  67. * which has been modified or not.
  68. * 7. Remove items we consumed from the final list, and let external files
  69. * being processed by core.
  70. *
  71. * During the whole process, we use a $mapping array. This array contain, for
  72. * each group, an alphanumerical filename prefix for future aggregated files.
  73. *
  74. * Filenames are being built using this mapping array and this convention:
  75. * - <group_prefix>-<media>.css
  76. *
  77. * This function aggregates all theme files in their own group, whatever is the
  78. * user configuration, to ensure no theme conflicts if the site as more than
  79. * one themes (most sites will have at least two, frontend and backend themes).
  80. *
  81. * Ideal case is, all files have already been built, therefore $status and
  82. * $groups array matches each other. In this particular case, no I/O at all is
  83. * being done and only the drupal_render() array is built pragmatically using
  84. * the $status array content.
  85. */
  86. function core_library_element_style_pre_render($elements) {
  87. global $theme_key;
  88. // Status array contains filename as keys, and numeric keys as values which
  89. // can be any of those:
  90. // - -1 : No files, no need to rebuild.
  91. // - TRUE : File already built.
  92. // - empty : Nothing done, or built failed, need rebuild.
  93. $status = variable_get('core_library_css_status');
  94. // Group to filename mapping. Each group can have one or more medias, we will
  95. // distinguish this later in the algorithm.
  96. $mapping = array(
  97. CSS_SYSTEM => 'system',
  98. CSS_THEME => 'theme-' . str_replace('_', '-', $theme_key),
  99. CSS_DEFAULT => 'default',
  100. );
  101. // What do we need to rebuild, this array will contain groups as keys, and
  102. // $css sub-array for each of those groups.
  103. $rebuild = array();
  104. // Determine how to build groups. This depends on the user configuration.
  105. // User configuration has been taken into account by hook_library_css_alter()
  106. // earlier during the normal execution flow. We only have to regroup those
  107. // using the core grouping algorithm to ensure we have different groups for
  108. // browser specific files.
  109. foreach (drupal_group_css($elements['#items']) as $core_group) {
  110. $map = NULL;
  111. // Scan for external file, we won't handle ourselves.
  112. if ($core_group['type'] == 'external') {
  113. // FIXME: Do something!
  114. }
  115. // Scan for browser specific rules. Remember that
  116. else if (!$core_group['browsers']['!IE']) {
  117. $map = $mapping[$core_group['group']] . '-' . str_replace(' ', '', $core_group['browsers']['IE']) . '-' . $core_group['media'];
  118. }
  119. // Normal processing (all browsers).
  120. else {
  121. $map = $mapping[$core_group['group']] . '-' . $core_group['media'];
  122. }
  123. if ($map) {
  124. // Populate our group array, using core given groups. Those groups reflect
  125. // what we aggregated before at hook_library_css_alter() time, adding
  126. // browser information we omitted or let live with defaults.
  127. $groups[$map] = $core_group;
  128. // Also mark the current for rebuild if needed.
  129. if (!isset($status[$map]) || !$status[$map]) {
  130. $rebuild[] = $map;
  131. }
  132. }
  133. }
  134. // Rebuild files we have to.
  135. if (!empty($rebuild)) {
  136. // Iterate over files, and rebuild the one we need.
  137. foreach ($rebuild as $map) {
  138. $status[$map] = _core_library_element_style_rebuild_group($map, $groups[$map]['items']);
  139. }
  140. // Save our status (do not rebuild CSS later).
  141. variable_set('core_library_css_status', $status);
  142. }
  143. // Build the final result for drupal_render().
  144. foreach ($groups as $map => $data) {
  145. // Do not include empty or non existing files. All files should be empty
  146. // or built when we get in this part of the algorithm.
  147. if ($status[$map] == TRUE) {
  148. // Compute the real filename using the same convention than the
  149. // _core_library_element_style_rebuild_group() function.
  150. $file = $map . '.css';
  151. // Add the real element for drupal_render() function to include the tag.
  152. $elements[] = array(
  153. '#type' => 'html_tag',
  154. '#tag' => 'link',
  155. '#attributes' => array(
  156. 'type' => 'text/css',
  157. 'rel' => 'stylesheet',
  158. 'href' => file_create_url('public://static/' . $file),
  159. 'media' => $data['media'],
  160. ),
  161. '#browsers' => $data['browsers'],
  162. );
  163. }
  164. }
  165. // All ok.
  166. return $elements;
  167. }