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:
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']
......
......@@ -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.
......
......@@ -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();
}
......@@ -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));
}
}
......@@ -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));
}
}
......@@ -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'));
}
}
......
......@@ -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().
*/
......
......@@ -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;
}
......@@ -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.
......
......@@ -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);
......
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