ThemeData model now busts the [front-end] combiner cache
Separation of concerns, move the combiner asset variable injection logic to the cms module Tweak readme
This commit is contained in:
parent
cd5a579c04
commit
744d5654b3
16
README.md
16
README.md
|
|
@ -21,14 +21,6 @@ Instructions on how to install October can be found at the [installation guide](
|
|||
|
||||
October was created by [Alexey Bobkov](http://ca.linkedin.com/pub/aleksey-bobkov/2b/ba0/232) and [Samuel Georges](http://au.linkedin.com/pub/sam-georges/31/641/a9), who both continue to develop the platform.
|
||||
|
||||
### Coding standards
|
||||
|
||||
Please follow the following guides and code standards:
|
||||
|
||||
* [PSR 4 Coding Standards](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md)
|
||||
* [PSR 2 Coding Style Guide](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
|
||||
* [PSR 1 Coding Standards](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md)
|
||||
|
||||
### Foundation library
|
||||
|
||||
The CMS uses [Laravel](http://laravel.com) as a foundation PHP framework.
|
||||
|
|
@ -48,3 +40,11 @@ The OctoberCMS platform is open-sourced software licensed under the [MIT license
|
|||
### Contributing
|
||||
|
||||
Before sending a Pull Request, be sure to review the [Contributing Guidelines](CONTRIBUTING.md) first.
|
||||
|
||||
### Coding standards
|
||||
|
||||
Please follow the following guides and code standards:
|
||||
|
||||
* [PSR 4 Coding Standards](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md)
|
||||
* [PSR 2 Coding Style Guide](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
|
||||
* [PSR 1 Coding Standards](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use System\Classes\SettingsManager;
|
|||
use System\Classes\CombineAssets;
|
||||
use Cms\Classes\ComponentManager;
|
||||
use Cms\Classes\Page as CmsPage;
|
||||
use Cms\Classes\Theme as CmsTheme;
|
||||
use Cms\Models\ThemeData;
|
||||
|
||||
class ServiceProvider extends ModuleServiceProvider
|
||||
{
|
||||
|
|
@ -27,6 +27,7 @@ class ServiceProvider extends ModuleServiceProvider
|
|||
|
||||
$this->registerComponents();
|
||||
$this->registerAssetBundles();
|
||||
$this->registerCombinerEvents();
|
||||
|
||||
/*
|
||||
* Backend specific
|
||||
|
|
@ -77,6 +78,25 @@ class ServiceProvider extends ModuleServiceProvider
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers events for the asset combiner.
|
||||
*/
|
||||
protected function registerCombinerEvents()
|
||||
{
|
||||
if (App::runningInBackend() || App::runningInConsole()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Event::listen('cms.combiner.beforePrepare', function ($combiner, $assets) {
|
||||
$filters = array_flatten($combiner->getFilters());
|
||||
ThemeData::applyAssetVariablesToCombinerFilters($filters);
|
||||
});
|
||||
|
||||
Event::listen('cms.combiner.getCacheKey', function ($combiner, $holder) {
|
||||
$holder->key = $holder->key . ThemeData::getCombinerCacheKey();
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Register navigation
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -64,7 +64,10 @@ class ThemeData extends Model
|
|||
|
||||
public function afterSave()
|
||||
{
|
||||
CombineAssets::resetCache();
|
||||
try {
|
||||
CombineAssets::resetCache();
|
||||
}
|
||||
catch (Exception $ex) {}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -85,6 +88,8 @@ class ThemeData extends Model
|
|||
|
||||
public function afterFetch()
|
||||
{
|
||||
$data = (array) $this->data + $this->getDefaultValues();
|
||||
|
||||
/*
|
||||
* Repeater form fields store arrays and must be jsonable.
|
||||
*/
|
||||
|
|
@ -98,13 +103,14 @@ class ThemeData extends Model
|
|||
}
|
||||
elseif ($field['type'] == 'fileupload') {
|
||||
$this->attachOne[$id] = 'System\Models\File';
|
||||
unset($data[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill this model with the jsonable attributes kept in 'data'.
|
||||
*/
|
||||
$this->setRawAttributes((array) $this->getAttributes() + (array) $this->data, true);
|
||||
$this->setRawAttributes((array) $this->getAttributes() + $data, true);
|
||||
}
|
||||
|
||||
public function beforeValidate()
|
||||
|
|
@ -127,13 +133,27 @@ class ThemeData extends Model
|
|||
*/
|
||||
public function setDefaultValues()
|
||||
{
|
||||
foreach ($this->getDefaultValues() as $attribute => $field) {
|
||||
$this->{$attribute} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets default values for this model based on form field definitions.
|
||||
*/
|
||||
public function getDefaultValues()
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($this->getFormFields() as $attribute => $field) {
|
||||
if (!$value = array_get($field, 'default')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->{$attribute} = $value;
|
||||
$result[$attribute] = $value;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -145,9 +165,11 @@ class ThemeData extends Model
|
|||
if (!$theme = CmsTheme::load($this->theme))
|
||||
throw new Exception(Lang::get('Unable to find theme with name :name', $this->theme));
|
||||
|
||||
return $theme->getConfigValue('form.fields', []) +
|
||||
$theme->getConfigValue('form.tabs.fields', []) +
|
||||
$theme->getConfigValue('form.secondaryTabs.fields', []);
|
||||
$config = $theme->getConfigArray('form');
|
||||
|
||||
return array_get($config, 'fields', []) +
|
||||
array_get($config, 'tabs.fields', []) +
|
||||
array_get($config, 'secondaryTabs.fields', []);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -168,4 +190,40 @@ class ThemeData extends Model
|
|||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies asset variables to the combiner filters that support it.
|
||||
* @return void
|
||||
*/
|
||||
public static function applyAssetVariablesToCombinerFilters($filters)
|
||||
{
|
||||
$theme = CmsTheme::getActiveTheme();
|
||||
if (!$theme->hasCustomData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$assetVars = $theme->getCustomData()->getAssetVariables();
|
||||
|
||||
foreach ($filters as $filter) {
|
||||
if (method_exists($filter, 'setPresets')) {
|
||||
$filter->setPresets($assetVars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a cache key for the combiner, this allows variables to bust the cache.
|
||||
* @return string
|
||||
*/
|
||||
public static function getCombinerCacheKey()
|
||||
{
|
||||
$theme = CmsTheme::getActiveTheme();
|
||||
if (!$theme->hasCustomData()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$customData = $theme->getCustomData();
|
||||
|
||||
return (string) $customData->updated_at ?: '';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ use App;
|
|||
use Url;
|
||||
use File;
|
||||
use Lang;
|
||||
use Event;
|
||||
use Cache;
|
||||
use Route;
|
||||
use Config;
|
||||
use Request;
|
||||
use Response;
|
||||
use Cms\Classes\Theme;
|
||||
use Assetic\Asset\FileAsset;
|
||||
use Assetic\Asset\GlobAsset;
|
||||
use Assetic\Asset\AssetCache;
|
||||
|
|
@ -165,11 +165,11 @@ class CombineAssets
|
|||
* Returns the combined contents from a prepared cache identifier.
|
||||
* @return string Combined file contents.
|
||||
*/
|
||||
public function getContents($cacheId)
|
||||
public function getContents($cacheKey)
|
||||
{
|
||||
$cacheInfo = $this->getCache($cacheId);
|
||||
$cacheInfo = $this->getCache($cacheKey);
|
||||
if (!$cacheInfo) {
|
||||
throw new ApplicationException(Lang::get('system::lang.combiner.not_found', ['name'=>$cacheId]));
|
||||
throw new ApplicationException(Lang::get('system::lang.combiner.not_found', ['name'=>$cacheKey]));
|
||||
}
|
||||
|
||||
$this->localPath = $cacheInfo['path'];
|
||||
|
|
@ -287,23 +287,23 @@ class CombineAssets
|
|||
/*
|
||||
* Cache and process
|
||||
*/
|
||||
$cacheId = $this->makeCacheId($assets);
|
||||
$cacheInfo = $this->useCache ? $this->getCache($cacheId) : false;
|
||||
$cacheKey = $this->getCacheKey($assets);
|
||||
$cacheInfo = $this->useCache ? $this->getCache($cacheKey) : false;
|
||||
|
||||
if (!$cacheInfo) {
|
||||
$combiner = $this->prepareCombiner($assets);
|
||||
$lastMod = $combiner->getLastModified();
|
||||
|
||||
$cacheInfo = [
|
||||
'version' => $cacheId.'-'.$lastMod,
|
||||
'etag' => $cacheId,
|
||||
'version' => $cacheKey.'-'.$lastMod,
|
||||
'etag' => $cacheKey,
|
||||
'lastMod' => $lastMod,
|
||||
'files' => $assets,
|
||||
'path' => $this->localPath,
|
||||
'extension' => $extension
|
||||
];
|
||||
|
||||
$this->putCache($cacheId, $cacheInfo);
|
||||
$this->putCache($cacheKey, $cacheInfo);
|
||||
}
|
||||
|
||||
return $this->getCombinedUrl($cacheInfo['version']);
|
||||
|
|
@ -315,11 +315,15 @@ class CombineAssets
|
|||
*/
|
||||
protected function prepareCombiner(array $assets, $rewritePath = null)
|
||||
{
|
||||
/*
|
||||
* Extensibility
|
||||
*/
|
||||
Event::fire('cms.combiner.beforePrepare', [$this, $assets]);
|
||||
|
||||
$files = [];
|
||||
$filesSalt = null;
|
||||
foreach ($assets as $asset) {
|
||||
$filters = $this->getFilters(File::extension($asset)) ?: [];
|
||||
$filters = $this->processFilters($filters);
|
||||
$path = File::symbolizePath($asset, null) ?: $this->localPath . $asset;
|
||||
$files[] = new FileAsset($path, $filters, public_path());
|
||||
$filesSalt .= $this->localPath . $asset;
|
||||
|
|
@ -468,29 +472,6 @@ class CombineAssets
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocess filters to use standard configuration provided by the system.
|
||||
* @param array $filters
|
||||
* @return array
|
||||
*/
|
||||
protected function processFilters($filters)
|
||||
{
|
||||
$theme = Theme::getActiveTheme();
|
||||
if (!$theme->hasCustomData()) {
|
||||
return $filters;
|
||||
}
|
||||
|
||||
$assetVars = $theme->getCustomData()->getAssetVariables();
|
||||
|
||||
foreach ($filters as $filter) {
|
||||
if (method_exists($filter, 'setPresets')) {
|
||||
$filter->setPresets($assetVars);
|
||||
}
|
||||
}
|
||||
|
||||
return $filters;
|
||||
}
|
||||
|
||||
//
|
||||
// Bundles
|
||||
//
|
||||
|
|
@ -632,16 +613,16 @@ class CombineAssets
|
|||
* @var array List of asset files.
|
||||
* @return bool Successful
|
||||
*/
|
||||
protected function putCache($cacheId, array $cacheInfo)
|
||||
protected function putCache($cacheKey, array $cacheInfo)
|
||||
{
|
||||
$cacheId = 'combiner.'.$cacheId;
|
||||
$cacheKey = 'combiner.'.$cacheKey;
|
||||
|
||||
if (Cache::has($cacheId)) {
|
||||
if (Cache::has($cacheKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->putCacheIndex($cacheId);
|
||||
Cache::forever($cacheId, base64_encode(serialize($cacheInfo)));
|
||||
$this->putCacheIndex($cacheKey);
|
||||
Cache::forever($cacheKey, base64_encode(serialize($cacheInfo)));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -650,15 +631,15 @@ class CombineAssets
|
|||
* @var string Cache identifier
|
||||
* @return array Cache information
|
||||
*/
|
||||
protected function getCache($cacheId)
|
||||
protected function getCache($cacheKey)
|
||||
{
|
||||
$cacheId = 'combiner.'.$cacheId;
|
||||
$cacheKey = 'combiner.'.$cacheKey;
|
||||
|
||||
if (!Cache::has($cacheId)) {
|
||||
if (!Cache::has($cacheKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return @unserialize(@base64_decode(Cache::get($cacheId)));
|
||||
return @unserialize(@base64_decode(Cache::get($cacheKey)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -666,9 +647,18 @@ class CombineAssets
|
|||
* @var array Asset files
|
||||
* @return string Unique identifier
|
||||
*/
|
||||
protected function makeCacheId(array $assets)
|
||||
protected function getCacheKey(array $assets)
|
||||
{
|
||||
return md5($this->localPath . implode('|', $assets));
|
||||
$cacheKey = $this->localPath . implode('|', $assets);
|
||||
|
||||
/*
|
||||
* Extensibility
|
||||
*/
|
||||
$dataHolder = (object) ['key' => $cacheKey];
|
||||
Event::fire('cms.combiner.getCacheKey', [$this, $dataHolder]);
|
||||
$cacheKey = $dataHolder->key;
|
||||
|
||||
return md5($cacheKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -680,8 +670,8 @@ class CombineAssets
|
|||
if (Cache::has('combiner.index')) {
|
||||
$index = (array) @unserialize(@base64_decode(Cache::get('combiner.index'))) ?: [];
|
||||
|
||||
foreach ($index as $cacheId) {
|
||||
Cache::forget($cacheId);
|
||||
foreach ($index as $cacheKey) {
|
||||
Cache::forget($cacheKey);
|
||||
}
|
||||
|
||||
Cache::forget('combiner.index');
|
||||
|
|
@ -696,7 +686,7 @@ class CombineAssets
|
|||
* @var string Cache identifier
|
||||
* @return bool Returns false if identifier is already in store
|
||||
*/
|
||||
protected function putCacheIndex($cacheId)
|
||||
protected function putCacheIndex($cacheKey)
|
||||
{
|
||||
$index = [];
|
||||
|
||||
|
|
@ -704,11 +694,11 @@ class CombineAssets
|
|||
$index = (array) @unserialize(@base64_decode(Cache::get('combiner.index'))) ?: [];
|
||||
}
|
||||
|
||||
if (in_array($cacheId, $index)) {
|
||||
if (in_array($cacheKey, $index)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$index[] = $cacheId;
|
||||
$index[] = $cacheKey;
|
||||
|
||||
Cache::forever('combiner.index', base64_encode(serialize($index)));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue