diff --git a/core/core.services.yml b/core/core.services.yml index 6ff5dd54fa3bc507994f7e262101c229650fcb91..8527b2773abd0096fef71b46260a68fae25d0cb8 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -254,7 +254,7 @@ services: arguments: ['%container.modules%', '@cache.bootstrap'] theme_handler: class: Drupal\Core\Extension\ThemeHandler - arguments: ['@config.factory', '@module_handler', '@state', '@info_parser', '@config.installer', '@router.builder'] + arguments: ['@config.factory', '@module_handler', '@state', '@info_parser', '@asset.css.collection_optimizer', '@config.installer', '@router.builder'] entity.manager: class: Drupal\Core\Entity\EntityManager arguments: ['@container.namespaces', '@module_handler', '@cache.discovery', '@language_manager', '@string_translation', '@class_resolver', '@typed_data_manager'] diff --git a/core/includes/common.inc b/core/includes/common.inc index 8b241ab37006f5f72a0ef60d450063c714a89600..6c6c4a3a88af884027d6b5c41b3f6bef22103872 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -1328,24 +1328,12 @@ function drupal_pre_render_styles($elements) { /** * Deletes old cached CSS files. - */ -function drupal_clear_css_cache() { - \Drupal::state()->delete('drupal_css_cache_files'); - file_scan_directory('public://css', '/.*/', array('callback' => 'drupal_delete_file_if_stale')); -} - -/** - * Deletes files modified more than a set time ago. * - * Callback for file_scan_directory() within: - * - drupal_clear_css_cache() - * - drupal_clear_js_cache() + * @deprecated in Drupal 8.x, will be removed before Drupal 9.0. + * Use \Drupal\Core\Asset\AssetCollectionOptimizerInterface::deleteAll(). */ -function drupal_delete_file_if_stale($uri) { - // Default stale file threshold is 30 days. - if (REQUEST_TIME - filemtime($uri) > \Drupal::config('system.performance')->get('stale_file_threshold')) { - file_unmanaged_delete($uri); - } +function drupal_clear_css_cache() { + \Drupal::service('asset.css.collection_optimizer')->deleteAll(); } /** @@ -2463,11 +2451,12 @@ function drupal_attach_tabledrag(&$element, array $options) { /** * Deletes old cached JavaScript files and variables. + * + * @deprecated in Drupal 8.x, will be removed before Drupal 9.0. + * Use \Drupal\Core\Asset\AssetCollectionOptimizerInterface::deleteAll(). */ function drupal_clear_js_cache() { - \Drupal::state()->delete('system.javascript_parsed'); - \Drupal::state()->delete('system.js_cache_files'); - file_scan_directory('public://js', '/.*/', array('callback' => 'drupal_delete_file_if_stale')); + \Drupal::service('asset.js.collection_optimizer')->deleteAll(); } /** @@ -3956,8 +3945,8 @@ function drupal_flush_all_caches() { } // Flush asset file caches. - drupal_clear_css_cache(); - drupal_clear_js_cache(); + \Drupal::service('asset.css.collection_optimizer')->deleteAll(); + \Drupal::service('asset.js.collection_optimizer')->deleteAll(); _drupal_flush_css_js(); // Reset all static caches. diff --git a/core/lib/Drupal/Core/Asset/AssetCollectionOptimizerInterface.php b/core/lib/Drupal/Core/Asset/AssetCollectionOptimizerInterface.php index f7102d244bbdfd1fdad8ecdc593a46bbf246ff5b..4963c82879a678701e72d0a87316a021471f6c67 100644 --- a/core/lib/Drupal/Core/Asset/AssetCollectionOptimizerInterface.php +++ b/core/lib/Drupal/Core/Asset/AssetCollectionOptimizerInterface.php @@ -22,4 +22,17 @@ interface AssetCollectionOptimizerInterface { */ public function optimize(array $assets); + /** + * Returns all optimized asset collections assets. + * + * @return string[] + * URIs for all optimized asset collection assets. + */ + public function getAll(); + + /** + * Deletes all optimized asset collections assets. + */ + public function deleteAll(); + } diff --git a/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php b/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php index 3da9d9104239fe036567f2ce273492ed9f19309b..b02bb46b9bf1fb262beec1492eb369563bd62ccf 100644 --- a/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php +++ b/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php @@ -71,8 +71,8 @@ public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptim * variable is emptied to force a rebuild of the cache. Second, the cache file * is generated if it is missing on disk. Old cache files are not deleted * immediately when the lookup variable is emptied, but are deleted after a - * set period by drupal_delete_file_if_stale(). This ensures that files - * referenced by a cached page will still be available. + * configurable period (@code system.performance.stale_file_threshold @endcode) + * to ensure that files referenced by a cached page will still be available. */ public function optimize(array $css_assets) { // Group the assets. @@ -175,4 +175,27 @@ protected function generateHash(array $css_group) { } return hash('sha256', serialize($css_data)); } + + /** + * {@inheritdoc} + */ + public function getAll() { + return $this->state->get('drupal_css_cache_files'); + } + + /** + * {@inheritdoc} + */ + public function deleteAll() { + $this->state->delete('drupal_css_cache_files'); + + $delete_stale = function($uri) { + // Default stale file threshold is 30 days. + if (REQUEST_TIME - filemtime($uri) > \Drupal::config('system.performance')->get('stale_file_threshold')) { + file_unmanaged_delete($uri); + } + }; + file_scan_directory('public://css', '/.*/', array('callback' => $delete_stale)); + } + } diff --git a/core/lib/Drupal/Core/Asset/JsCollectionOptimizer.php b/core/lib/Drupal/Core/Asset/JsCollectionOptimizer.php index 4126e57e4b010e2f2b8488c2ee5cf56101f56e38..23564797760ffb34f1399a3fb316a3b0b009c78b 100644 --- a/core/lib/Drupal/Core/Asset/JsCollectionOptimizer.php +++ b/core/lib/Drupal/Core/Asset/JsCollectionOptimizer.php @@ -72,8 +72,8 @@ public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptim * variable is emptied to force a rebuild of the cache. Second, the cache file * is generated if it is missing on disk. Old cache files are not deleted * immediately when the lookup variable is emptied, but are deleted after a - * set period by drupal_delete_file_if_stale(). This ensures that files - * referenced by a cached page will still be available. + * configurable period (@code system.performance.stale_file_threshold @endcode) + * to ensure that files referenced by a cached page will still be available. */ public function optimize(array $js_assets) { // Group the assets. @@ -163,4 +163,26 @@ protected function generateHash(array $js_group) { } return hash('sha256', serialize($js_data)); } + + /** + * {@inheritdoc} + */ + public function getAll() { + return $this->state->get('system.js_cache_files'); + } + + /** + * {@inheritdoc} + */ + public function deleteAll() { + $this->state->delete('system.js_cache_files'); + $delete_stale = function($uri) { + // Default stale file threshold is 30 days. + if (REQUEST_TIME - filemtime($uri) > \Drupal::config('system.performance')->get('stale_file_threshold')) { + file_unmanaged_delete($uri); + } + }; + file_scan_directory('public://js', '/.*/', array('callback' => $delete_stale)); + } + } diff --git a/core/lib/Drupal/Core/DependencyInjection/UpdateServiceProvider.php b/core/lib/Drupal/Core/DependencyInjection/UpdateServiceProvider.php index 32ad9b768252c24cec3ed75a43d6f9aa4705e4e7..ec30db020ef9a17edab2ac1e3c03182c1bbf91c1 100644 --- a/core/lib/Drupal/Core/DependencyInjection/UpdateServiceProvider.php +++ b/core/lib/Drupal/Core/DependencyInjection/UpdateServiceProvider.php @@ -42,7 +42,8 @@ public function register(ContainerBuilder $container) { ->addArgument(new Reference('config.factory')) ->addArgument(new Reference('module_handler')) ->addArgument(new Reference('state')) - ->addArgument(new Reference('info_parser')); + ->addArgument(new Reference('info_parser')) + ->addArgument(new Reference('asset.css.collection_optimizer')); } } diff --git a/core/lib/Drupal/Core/Extension/ThemeHandler.php b/core/lib/Drupal/Core/Extension/ThemeHandler.php index dbe2c78dca90af28a477d6008f394748f071b642..e1b8cbfdcbf2ba61fdb42067f5fca3646e9c5bff 100644 --- a/core/lib/Drupal/Core/Extension/ThemeHandler.php +++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Extension; use Drupal\Component\Utility\String; +use Drupal\Core\Asset\AssetCollectionOptimizerInterface; use Drupal\Core\Cache\Cache; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\ConfigInstallerInterface; @@ -92,6 +93,13 @@ class ThemeHandler implements ThemeHandlerInterface { */ protected $extensionDiscovery; + /** + * The CSS asset collection optimizer service. + * + * @var \Drupal\Core\Asset\AssetCollectionOptimizerInterface + */ + protected $cssCollectionOptimizer; + /** * Constructs a new ThemeHandler. * @@ -103,6 +111,8 @@ class ThemeHandler implements ThemeHandlerInterface { * The state store. * @param \Drupal\Core\Extension\InfoParserInterface $info_parser * The info parser to parse the theme.info.yml files. + * @param \Drupal\Core\Asset\AssetCollectionOptimizerInterface $css_collection_optimizer + * The CSS asset collection optimizer service. * @param \Drupal\Core\Config\ConfigInstallerInterface $config_installer * (optional) The config installer to install configuration. This optional * to allow the theme handler to work before Drupal is installed and has a @@ -112,11 +122,12 @@ class ThemeHandler implements ThemeHandlerInterface { * @param \Drupal\Core\Extension\ExtensionDiscovery $extension_discovery * (optional) A extension discovery instance (for unit tests). */ - public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, StateInterface $state, InfoParserInterface $info_parser, ConfigInstallerInterface $config_installer = NULL, RouteBuilder $route_builder = NULL, ExtensionDiscovery $extension_discovery = NULL) { + public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, StateInterface $state, InfoParserInterface $info_parser, AssetCollectionOptimizerInterface $css_collection_optimizer = NULL, ConfigInstallerInterface $config_installer = NULL, RouteBuilder $route_builder = NULL, ExtensionDiscovery $extension_discovery = NULL) { $this->configFactory = $config_factory; $this->moduleHandler = $module_handler; $this->state = $state; $this->infoParser = $info_parser; + $this->cssCollectionOptimizer = $css_collection_optimizer; $this->configInstaller = $config_installer; $this->routeBuilder = $route_builder; $this->extensionDiscovery = $extension_discovery; @@ -260,7 +271,7 @@ public function enable(array $theme_list, $enable_dependencies = TRUE) { watchdog('system', '%theme theme enabled.', array('%theme' => $key), WATCHDOG_INFO); } - $this->clearCssCache(); + $this->cssCollectionOptimizer->deleteAll(); $this->resetSystem(); // Invoke hook_themes_enabled() after the themes have been enabled. @@ -297,7 +308,7 @@ public function disable(array $theme_list) { } } - $this->clearCssCache(); + $this->cssCollectionOptimizer->deleteAll(); $extension_config = $this->configFactory->get('core.extension'); $current_theme_data = $this->state->get('system.theme.data', array()); @@ -636,13 +647,6 @@ protected function systemListReset() { system_list_reset(); } - /** - * Wraps drupal_clear_css_cache(). - */ - protected function clearCssCache() { - drupal_clear_css_cache(); - } - /** * Wraps drupal_theme_rebuild(). */ diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module index b44d1a1d0a379682cdb646dd161823569a9e7252..c8803709879ea40cc9d21ddb58379a1fd7836821 100644 --- a/core/modules/locale/locale.module +++ b/core/modules/locale/locale.module @@ -541,6 +541,13 @@ function locale_system_remove($components) { } } +/** + * Implements hook_cache_flush(). + */ +function locale_cache_flush() { + \Drupal::state()->delete('system.javascript_parsed'); +} + /** * Implements hook_js_alter(). */ @@ -1397,4 +1404,3 @@ function locale_translation_language_table($form_element) { } return $form_element; } - diff --git a/core/modules/system/src/Form/PerformanceForm.php b/core/modules/system/src/Form/PerformanceForm.php index 85d2415408161519f7821dcb26ac3c6aa1b9c720..98b0b8288eec4c6ac77dd3f8fb1f2c46b2f88fc5 100644 --- a/core/modules/system/src/Form/PerformanceForm.php +++ b/core/modules/system/src/Form/PerformanceForm.php @@ -7,6 +7,7 @@ namespace Drupal\system\Form; +use Drupal\Core\Asset\AssetCollectionOptimizerInterface; use Drupal\Core\Form\ConfigFormBase; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Cache\CacheBackendInterface; @@ -20,7 +21,7 @@ class PerformanceForm extends ConfigFormBase { /** - * The render cache object. + * The render cache bin. * * @var \Drupal\Core\Cache\CacheBackendInterface */ @@ -33,6 +34,20 @@ class PerformanceForm extends ConfigFormBase { */ protected $dateFormatter; + /** + * The CSS asset collection optimizer service. + * + * @var \Drupal\Core\Asset\AssetCollectionOptimizerInterface + */ + protected $cssCollectionOptimizer; + + /** + * The JavaScript asset collection optimizer service. + * + * @var \Drupal\Core\Asset\AssetCollectionOptimizerInterface + */ + protected $jsCollectionOptimizer; + /** * Constructs a PerformanceForm object. * @@ -41,12 +56,18 @@ class PerformanceForm extends ConfigFormBase { * @param \Drupal\Core\Cache\CacheBackendInterface $render_cache * @param \Drupal\Core\Datetime\DateFormatter $date_formater * The date formatter service. + * @param \Drupal\Core\Asset\AssetCollectionOptimizerInterface $css_collection_optimizer + * The CSS asset collection optimizer service. + * @param \Drupal\Core\Asset\AssetCollectionOptimizerInterface $js_collection_optimizer + * The JavaScript asset collection optimizer service. */ - public function __construct(ConfigFactoryInterface $config_factory, CacheBackendInterface $render_cache, DateFormatter $date_formater) { + public function __construct(ConfigFactoryInterface $config_factory, CacheBackendInterface $render_cache, DateFormatter $date_formater, AssetCollectionOptimizerInterface $css_collection_optimizer, AssetCollectionOptimizerInterface $js_collection_optimizer) { parent::__construct($config_factory); $this->renderCache = $render_cache; $this->dateFormatter = $date_formater; + $this->cssCollectionOptimizer = $css_collection_optimizer; + $this->jsCollectionOptimizer = $js_collection_optimizer; } /** @@ -56,7 +77,9 @@ public static function create(ContainerInterface $container) { return new static( $container->get('config.factory'), $container->get('cache.render'), - $container->get('date.formatter') + $container->get('date.formatter'), + $container->get('asset.css.collection_optimizer'), + $container->get('asset.js.collection_optimizer') ); } @@ -157,8 +180,8 @@ public function buildForm(array $form, FormStateInterface $form_state) { * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { - drupal_clear_css_cache(); - drupal_clear_js_cache(); + $this->cssCollectionOptimizer->deleteAll(); + $this->jsCollectionOptimizer->deleteAll(); // This form allows page compression settings to be changed, which can // invalidate cached pages in the render cache, so it needs to be cleared on // form submit. diff --git a/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php b/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php index 675d04ede3cf02ddd0150338a013ca10e71ae766..5daac3f9c915db39f098de0f575ac9f12b53b38f 100644 --- a/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php +++ b/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php @@ -70,6 +70,13 @@ class ThemeHandlerTest extends UnitTestCase { */ protected $extensionDiscovery; + /** + * The CSS asset collection optimizer service. + * + * @var \Drupal\Core\Asset\AssetCollectionOptimizerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $cssCollectionOptimizer; + /** * The tested theme handler. * @@ -100,7 +107,10 @@ protected function setUp() { $this->extensionDiscovery = $this->getMockBuilder('Drupal\Core\Extension\ExtensionDiscovery') ->disableOriginalConstructor() ->getMock(); - $this->themeHandler = new TestThemeHandler($this->configFactory, $this->moduleHandler, $this->state, $this->infoParser, $this->configInstaller, $this->routeBuilder, $this->extensionDiscovery); + $this->cssCollectionOptimizer = $this->getMockBuilder('\Drupal\Core\Asset\CssCollectionOptimizer') //\Drupal\Core\Asset\AssetCollectionOptimizerInterface'); + ->disableOriginalConstructor() + ->getMock(); + $this->themeHandler = new TestThemeHandler($this->configFactory, $this->moduleHandler, $this->state, $this->infoParser, $this->cssCollectionOptimizer, $this->configInstaller, $this->routeBuilder, $this->extensionDiscovery); $cache_backend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface'); $this->getContainerWithCacheBins($cache_backend);