diff --git a/system/blueprints/config/backups.yaml b/system/blueprints/config/backups.yaml
index fd584352a..2d054d049 100644
--- a/system/blueprints/config/backups.yaml
+++ b/system/blueprints/config/backups.yaml
@@ -119,7 +119,7 @@ form:
.schedule_at:
type: cron
label: Run Scheduled Job
- default: '* * * * *'
+ default: '* 3 * * *'
validate:
required: true
diff --git a/system/blueprints/config/system.yaml b/system/blueprints/config/system.yaml
index 5bc2e4970..6e5316027 100644
--- a/system/blueprints/config/system.yaml
+++ b/system/blueprints/config/system.yaml
@@ -514,6 +514,12 @@ form:
help: PLUGIN_ADMIN.CACHE_PREFIX_HELP
placeholder: PLUGIN_ADMIN.CACHE_PREFIX_PLACEHOLDER
+ cache.purge_at:
+ type: cron
+ label: PLUGIN_ADMIN.CACHE_PURGE_JOB
+ help: PLUGIN_ADMIN.CACHE_PURGE_JOB_HELP
+ default: '* 3 * * *'
+
cache.clear_images_by_default:
type: toggle
label: PLUGIN_ADMIN.CLEAR_IMAGES_BY_DEFAULT
diff --git a/system/config/system.yaml b/system/config/system.yaml
index 065e059f2..fad5a1c20 100644
--- a/system/config/system.yaml
+++ b/system/config/system.yaml
@@ -76,6 +76,7 @@ cache:
method: file # Method to check for updates in pages: file|folder|hash|none
driver: auto # One of: auto|file|apc|xcache|memcache|wincache
prefix: 'g' # Cache prefix string (prevents cache conflicts)
+ purge_at: '0 4 * * *' # How often to purge old cache (using new scheduler)
clear_images_by_default: true # By default grav will include processed images in cache clear, this can be disabled
cli_compatibility: false # Ensures only non-volatile drivers are used (file, redis, memcache, etc.)
lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite)
diff --git a/system/src/Grav/Common/Cache.php b/system/src/Grav/Common/Cache.php
index 71eb29ff7..f458c9ca6 100644
--- a/system/src/Grav/Common/Cache.php
+++ b/system/src/Grav/Common/Cache.php
@@ -117,27 +117,45 @@ class Cache extends Getters
$this->config = $grav['config'];
$this->now = time();
- $this->cache_dir = $grav['locator']->findResource('cache://doctrine', true, true);
+ if (is_null($this->enabled)) {
+ $this->enabled = (bool)$this->config->get('system.cache.enabled');
+ }
/** @var Uri $uri */
$uri = $grav['uri'];
$prefix = $this->config->get('system.cache.prefix');
-
- if (is_null($this->enabled)) {
- $this->enabled = (bool)$this->config->get('system.cache.enabled');
- }
+ $uniqueness = substr(md5($uri->rootUrl(true) . $this->config->key() . GRAV_VERSION), 2, 8);
// Cache key allows us to invalidate all cache on configuration changes.
- $this->key = ($prefix ? $prefix : 'g') . '-' . substr(md5($uri->rootUrl(true) . $this->config->key() . GRAV_VERSION),
- 2, 8);
-
+ $this->key = ($prefix ? $prefix : 'g') . '-' . $uniqueness;
+ $this->cache_dir = $grav['locator']->findResource('cache://doctrine/' . $uniqueness, true, true);
$this->driver_setting = $this->config->get('system.cache.driver');
-
$this->driver = $this->getCacheDriver();
-
- // Set the cache namespace to our unique key
$this->driver->setNamespace($this->key);
+
+ /** @var EventDispatcher $dispatcher */
+ $dispatcher = Grav::instance()['events'];
+ $dispatcher->addListener('onSchedulerInitialized', [$this, 'onSchedulerInitialized']);
+ }
+
+ public function purgeOldCache()
+ {
+ $cache_dir = dirname($this->cache_dir);
+ $current = basename($this->cache_dir);
+ $count = 0;
+
+ foreach (new \DirectoryIterator($cache_dir) as $file) {
+ $dir = $file->getBasename();
+ if ($file->isDot() || $file->isFile() || $dir === $current) {
+ continue;
+ }
+
+ Folder::delete($file->getPathname());
+ $count++;
+ }
+
+ return $count;
}
/**
@@ -507,4 +525,29 @@ class Cache extends Getters
return false;
}
}
+
+ public static function purgeJob()
+ {
+ $cache = Grav::instance()['cache'];
+ $deleted_folders = $cache->purgeOldCache();
+ echo 'Deleted ' . $deleted_folders . ' folders...';
+ }
+
+ public function onSchedulerInitialized(Event $event)
+ {
+ /** @var Scheduler $scheduler */
+ $scheduler = $event['scheduler'];
+ $config = Grav::instance()['config'];
+
+ $at = $config->get('system.cache.purge_at');
+ $name = 'cache-purge';
+ $logs = 'logs/' . $name . '.out';
+
+ $job = $scheduler->addFunction('Grav\Common\Cache::purgeJob', null, $name );
+ $job->at($at);
+ $job->output($logs);
+
+ }
+
+
}
diff --git a/system/src/Grav/Console/Cli/ClearCacheCommand.php b/system/src/Grav/Console/Cli/ClearCacheCommand.php
index cb5ffe84f..294142d32 100644
--- a/system/src/Grav/Console/Cli/ClearCacheCommand.php
+++ b/system/src/Grav/Console/Cli/ClearCacheCommand.php
@@ -9,6 +9,7 @@
namespace Grav\Console\Cli;
use Grav\Common\Cache;
+use Grav\Common\Grav;
use Grav\Console\ConsoleCommand;
use Symfony\Component\Console\Input\InputOption;
@@ -23,11 +24,14 @@ class ClearCacheCommand extends ConsoleCommand
->setName('clear-cache')
->setAliases(['clearcache'])
->setDescription('Clears Grav cache')
+ ->addOption('purge', null, InputOption::VALUE_NONE, 'If set purge old caches')
->addOption('all', null, InputOption::VALUE_NONE, 'If set will remove all including compiled, twig, doctrine caches')
->addOption('assets-only', null, InputOption::VALUE_NONE, 'If set will remove only assets/*')
->addOption('images-only', null, InputOption::VALUE_NONE, 'If set will remove only images/*')
->addOption('cache-only', null, InputOption::VALUE_NONE, 'If set will remove only cache/*')
->addOption('tmp-only', null, InputOption::VALUE_NONE, 'If set will remove only tmp/*')
+ ->addOption('tmp-only', null, InputOption::VALUE_NONE, 'If set will remove only tmp/*')
+
->setHelp('The clear-cache deletes all cache files');
}
@@ -45,25 +49,35 @@ class ClearCacheCommand extends ConsoleCommand
private function cleanPaths()
{
$this->output->writeln('');
- $this->output->writeln('Clearing cache');
- $this->output->writeln('');
- if ($this->input->getOption('all')) {
- $remove = 'all';
- } elseif ($this->input->getOption('assets-only')) {
- $remove = 'assets-only';
- } elseif ($this->input->getOption('images-only')) {
- $remove = 'images-only';
- } elseif ($this->input->getOption('cache-only')) {
- $remove = 'cache-only';
- } elseif ($this->input->getOption('tmp-only')) {
- $remove = 'tmp-only';
+
+ if ($this->input->getOption('purge')) {
+ $this->output->writeln('Purging old cache');
+ $this->output->writeln('');
+
+ $cache = Grav::instance()['cache'];
+ $cache->purgeOldCache();
} else {
- $remove = 'standard';
- }
+ $this->output->writeln('Clearing cache');
+ $this->output->writeln('');
- foreach (Cache::clearCache($remove) as $result) {
- $this->output->writeln($result);
+ if ($this->input->getOption('all')) {
+ $remove = 'all';
+ } elseif ($this->input->getOption('assets-only')) {
+ $remove = 'assets-only';
+ } elseif ($this->input->getOption('images-only')) {
+ $remove = 'images-only';
+ } elseif ($this->input->getOption('cache-only')) {
+ $remove = 'cache-only';
+ } elseif ($this->input->getOption('tmp-only')) {
+ $remove = 'tmp-only';
+ } else {
+ $remove = 'standard';
+ }
+
+ foreach (Cache::clearCache($remove) as $result) {
+ $this->output->writeln($result);
+ }
}
}
}