Commit d7d58725 authored by alexpott's avatar alexpott

Issue #2307419 by Wim Leers: AssetCollectionOptimizerInterface should allow...

Issue #2307419 by Wim Leers: AssetCollectionOptimizerInterface should allow listing and deleting all aggregates (optimized collection assets).
parent 8196034a
...@@ -254,7 +254,7 @@ services: ...@@ -254,7 +254,7 @@ services:
arguments: ['%container.modules%', '@cache.bootstrap'] arguments: ['%container.modules%', '@cache.bootstrap']
theme_handler: theme_handler:
class: Drupal\Core\Extension\ThemeHandler 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: entity.manager:
class: Drupal\Core\Entity\EntityManager class: Drupal\Core\Entity\EntityManager
arguments: ['@container.namespaces', '@module_handler', '@cache.discovery', '@language_manager', '@string_translation', '@class_resolver', '@typed_data_manager'] arguments: ['@container.namespaces', '@module_handler', '@cache.discovery', '@language_manager', '@string_translation', '@class_resolver', '@typed_data_manager']
......
...@@ -1328,24 +1328,12 @@ function drupal_pre_render_styles($elements) { ...@@ -1328,24 +1328,12 @@ function drupal_pre_render_styles($elements) {
/** /**
* Deletes old cached CSS files. * 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: * @deprecated in Drupal 8.x, will be removed before Drupal 9.0.
* - drupal_clear_css_cache() * Use \Drupal\Core\Asset\AssetCollectionOptimizerInterface::deleteAll().
* - drupal_clear_js_cache()
*/ */
function drupal_delete_file_if_stale($uri) { function drupal_clear_css_cache() {
// Default stale file threshold is 30 days. \Drupal::service('asset.css.collection_optimizer')->deleteAll();
if (REQUEST_TIME - filemtime($uri) > \Drupal::config('system.performance')->get('stale_file_threshold')) {
file_unmanaged_delete($uri);
}
} }
/** /**
...@@ -2463,11 +2451,12 @@ function drupal_attach_tabledrag(&$element, array $options) { ...@@ -2463,11 +2451,12 @@ function drupal_attach_tabledrag(&$element, array $options) {
/** /**
* Deletes old cached JavaScript files and variables. * 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() { function drupal_clear_js_cache() {
\Drupal::state()->delete('system.javascript_parsed'); \Drupal::service('asset.js.collection_optimizer')->deleteAll();
\Drupal::state()->delete('system.js_cache_files');
file_scan_directory('public://js', '/.*/', array('callback' => 'drupal_delete_file_if_stale'));
} }
/** /**
...@@ -3956,8 +3945,8 @@ function drupal_flush_all_caches() { ...@@ -3956,8 +3945,8 @@ function drupal_flush_all_caches() {
} }
// Flush asset file caches. // Flush asset file caches.
drupal_clear_css_cache(); \Drupal::service('asset.css.collection_optimizer')->deleteAll();
drupal_clear_js_cache(); \Drupal::service('asset.js.collection_optimizer')->deleteAll();
_drupal_flush_css_js(); _drupal_flush_css_js();
// Reset all static caches. // Reset all static caches.
......
...@@ -22,4 +22,17 @@ interface AssetCollectionOptimizerInterface { ...@@ -22,4 +22,17 @@ interface AssetCollectionOptimizerInterface {
*/ */
public function optimize(array $assets); 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();
} }
...@@ -71,8 +71,8 @@ public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptim ...@@ -71,8 +71,8 @@ public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptim
* variable is emptied to force a rebuild of the cache. Second, the cache file * 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 * 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 * immediately when the lookup variable is emptied, but are deleted after a
* set period by drupal_delete_file_if_stale(). This ensures that files * configurable period (@code system.performance.stale_file_threshold @endcode)
* referenced by a cached page will still be available. * to ensure that files referenced by a cached page will still be available.
*/ */
public function optimize(array $css_assets) { public function optimize(array $css_assets) {
// Group the assets. // Group the assets.
...@@ -175,4 +175,27 @@ protected function generateHash(array $css_group) { ...@@ -175,4 +175,27 @@ protected function generateHash(array $css_group) {
} }
return hash('sha256', serialize($css_data)); 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));
}
} }
...@@ -72,8 +72,8 @@ public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptim ...@@ -72,8 +72,8 @@ public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptim
* variable is emptied to force a rebuild of the cache. Second, the cache file * 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 * 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 * immediately when the lookup variable is emptied, but are deleted after a
* set period by drupal_delete_file_if_stale(). This ensures that files * configurable period (@code system.performance.stale_file_threshold @endcode)
* referenced by a cached page will still be available. * to ensure that files referenced by a cached page will still be available.
*/ */
public function optimize(array $js_assets) { public function optimize(array $js_assets) {
// Group the assets. // Group the assets.
...@@ -163,4 +163,26 @@ protected function generateHash(array $js_group) { ...@@ -163,4 +163,26 @@ protected function generateHash(array $js_group) {
} }
return hash('sha256', serialize($js_data)); 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));
}
} }
...@@ -42,7 +42,8 @@ public function register(ContainerBuilder $container) { ...@@ -42,7 +42,8 @@ public function register(ContainerBuilder $container) {
->addArgument(new Reference('config.factory')) ->addArgument(new Reference('config.factory'))
->addArgument(new Reference('module_handler')) ->addArgument(new Reference('module_handler'))
->addArgument(new Reference('state')) ->addArgument(new Reference('state'))
->addArgument(new Reference('info_parser')); ->addArgument(new Reference('info_parser'))
->addArgument(new Reference('asset.css.collection_optimizer'));
} }
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
namespace Drupal\Core\Extension; namespace Drupal\Core\Extension;
use Drupal\Component\Utility\String; use Drupal\Component\Utility\String;
use Drupal\Core\Asset\AssetCollectionOptimizerInterface;
use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\Cache;
use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ConfigInstallerInterface; use Drupal\Core\Config\ConfigInstallerInterface;
...@@ -92,6 +93,13 @@ class ThemeHandler implements ThemeHandlerInterface { ...@@ -92,6 +93,13 @@ class ThemeHandler implements ThemeHandlerInterface {
*/ */
protected $extensionDiscovery; protected $extensionDiscovery;
/**
* The CSS asset collection optimizer service.
*
* @var \Drupal\Core\Asset\AssetCollectionOptimizerInterface
*/
protected $cssCollectionOptimizer;
/** /**
* Constructs a new ThemeHandler. * Constructs a new ThemeHandler.
* *
...@@ -103,6 +111,8 @@ class ThemeHandler implements ThemeHandlerInterface { ...@@ -103,6 +111,8 @@ class ThemeHandler implements ThemeHandlerInterface {
* The state store. * The state store.
* @param \Drupal\Core\Extension\InfoParserInterface $info_parser * @param \Drupal\Core\Extension\InfoParserInterface $info_parser
* The info parser to parse the theme.info.yml files. * 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 * @param \Drupal\Core\Config\ConfigInstallerInterface $config_installer
* (optional) The config installer to install configuration. This optional * (optional) The config installer to install configuration. This optional
* to allow the theme handler to work before Drupal is installed and has a * to allow the theme handler to work before Drupal is installed and has a
...@@ -112,11 +122,12 @@ class ThemeHandler implements ThemeHandlerInterface { ...@@ -112,11 +122,12 @@ class ThemeHandler implements ThemeHandlerInterface {
* @param \Drupal\Core\Extension\ExtensionDiscovery $extension_discovery * @param \Drupal\Core\Extension\ExtensionDiscovery $extension_discovery
* (optional) A extension discovery instance (for unit tests). * (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->configFactory = $config_factory;
$this->moduleHandler = $module_handler; $this->moduleHandler = $module_handler;
$this->state = $state; $this->state = $state;
$this->infoParser = $info_parser; $this->infoParser = $info_parser;
$this->cssCollectionOptimizer = $css_collection_optimizer;
$this->configInstaller = $config_installer; $this->configInstaller = $config_installer;
$this->routeBuilder = $route_builder; $this->routeBuilder = $route_builder;
$this->extensionDiscovery = $extension_discovery; $this->extensionDiscovery = $extension_discovery;
...@@ -260,7 +271,7 @@ public function enable(array $theme_list, $enable_dependencies = TRUE) { ...@@ -260,7 +271,7 @@ public function enable(array $theme_list, $enable_dependencies = TRUE) {
watchdog('system', '%theme theme enabled.', array('%theme' => $key), WATCHDOG_INFO); watchdog('system', '%theme theme enabled.', array('%theme' => $key), WATCHDOG_INFO);
} }
$this->clearCssCache(); $this->cssCollectionOptimizer->deleteAll();
$this->resetSystem(); $this->resetSystem();
// Invoke hook_themes_enabled() after the themes have been enabled. // Invoke hook_themes_enabled() after the themes have been enabled.
...@@ -297,7 +308,7 @@ public function disable(array $theme_list) { ...@@ -297,7 +308,7 @@ public function disable(array $theme_list) {
} }
} }
$this->clearCssCache(); $this->cssCollectionOptimizer->deleteAll();
$extension_config = $this->configFactory->get('core.extension'); $extension_config = $this->configFactory->get('core.extension');
$current_theme_data = $this->state->get('system.theme.data', array()); $current_theme_data = $this->state->get('system.theme.data', array());
...@@ -636,13 +647,6 @@ protected function systemListReset() { ...@@ -636,13 +647,6 @@ protected function systemListReset() {
system_list_reset(); system_list_reset();
} }
/**
* Wraps drupal_clear_css_cache().
*/
protected function clearCssCache() {
drupal_clear_css_cache();
}
/** /**
* Wraps drupal_theme_rebuild(). * Wraps drupal_theme_rebuild().
*/ */
......
...@@ -541,6 +541,13 @@ function locale_system_remove($components) { ...@@ -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(). * Implements hook_js_alter().
*/ */
...@@ -1397,4 +1404,3 @@ function locale_translation_language_table($form_element) { ...@@ -1397,4 +1404,3 @@ function locale_translation_language_table($form_element) {
} }
return $form_element; return $form_element;
} }
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
namespace Drupal\system\Form; namespace Drupal\system\Form;
use Drupal\Core\Asset\AssetCollectionOptimizerInterface;
use Drupal\Core\Form\ConfigFormBase; use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Cache\CacheBackendInterface;
...@@ -20,7 +21,7 @@ ...@@ -20,7 +21,7 @@
class PerformanceForm extends ConfigFormBase { class PerformanceForm extends ConfigFormBase {
/** /**
* The render cache object. * The render cache bin.
* *
* @var \Drupal\Core\Cache\CacheBackendInterface * @var \Drupal\Core\Cache\CacheBackendInterface
*/ */
...@@ -33,6 +34,20 @@ class PerformanceForm extends ConfigFormBase { ...@@ -33,6 +34,20 @@ class PerformanceForm extends ConfigFormBase {
*/ */
protected $dateFormatter; 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. * Constructs a PerformanceForm object.
* *
...@@ -41,12 +56,18 @@ class PerformanceForm extends ConfigFormBase { ...@@ -41,12 +56,18 @@ class PerformanceForm extends ConfigFormBase {
* @param \Drupal\Core\Cache\CacheBackendInterface $render_cache * @param \Drupal\Core\Cache\CacheBackendInterface $render_cache
* @param \Drupal\Core\Datetime\DateFormatter $date_formater * @param \Drupal\Core\Datetime\DateFormatter $date_formater
* The date formatter service. * 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); parent::__construct($config_factory);
$this->renderCache = $render_cache; $this->renderCache = $render_cache;
$this->dateFormatter = $date_formater; $this->dateFormatter = $date_formater;
$this->cssCollectionOptimizer = $css_collection_optimizer;
$this->jsCollectionOptimizer = $js_collection_optimizer;
} }
/** /**
...@@ -56,7 +77,9 @@ public static function create(ContainerInterface $container) { ...@@ -56,7 +77,9 @@ public static function create(ContainerInterface $container) {
return new static( return new static(
$container->get('config.factory'), $container->get('config.factory'),
$container->get('cache.render'), $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) { ...@@ -157,8 +180,8 @@ public function buildForm(array $form, FormStateInterface $form_state) {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function submitForm(array &$form, FormStateInterface $form_state) { public function submitForm(array &$form, FormStateInterface $form_state) {
drupal_clear_css_cache(); $this->cssCollectionOptimizer->deleteAll();
drupal_clear_js_cache(); $this->jsCollectionOptimizer->deleteAll();
// This form allows page compression settings to be changed, which can // 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 // invalidate cached pages in the render cache, so it needs to be cleared on
// form submit. // form submit.
......
...@@ -70,6 +70,13 @@ class ThemeHandlerTest extends UnitTestCase { ...@@ -70,6 +70,13 @@ class ThemeHandlerTest extends UnitTestCase {
*/ */
protected $extensionDiscovery; protected $extensionDiscovery;
/**
* The CSS asset collection optimizer service.
*
* @var \Drupal\Core\Asset\AssetCollectionOptimizerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $cssCollectionOptimizer;
/** /**
* The tested theme handler. * The tested theme handler.
* *
...@@ -100,7 +107,10 @@ protected function setUp() { ...@@ -100,7 +107,10 @@ protected function setUp() {
$this->extensionDiscovery = $this->getMockBuilder('Drupal\Core\Extension\ExtensionDiscovery') $this->extensionDiscovery = $this->getMockBuilder('Drupal\Core\Extension\ExtensionDiscovery')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->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'); $cache_backend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
$this->getContainerWithCacheBins($cache_backend); $this->getContainerWithCacheBins($cache_backend);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment