Skip to content

Instantly share code, notes, and snippets.

@godismyjudge95
Last active January 28, 2026 20:01
Show Gist options
  • Select an option

  • Save godismyjudge95/0b257f870f27d34078567a962a964f6e to your computer and use it in GitHub Desktop.

Select an option

Save godismyjudge95/0b257f870f27d34078567a962a964f6e to your computer and use it in GitHub Desktop.
Flush glide cache command
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
use League\Glide\Server;
use Statamic\Contracts\Assets\Asset;
use Statamic\Facades\AssetContainer;
use Statamic\Facades\Glide as GlideManager;
class FlushGlideCache extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'glide:flush {path : Asset path or URL} {--container=assets : Asset container handle when not present in input}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Flush Glide cache for a specific asset path or URL';
/**
* Execute the console command.
*/
public function handle(): int
{
$input = (string) $this->argument('path');
$defaultContainer = (string) $this->option('container');
[$container, $assetPath] = $this->normalizeInput($input, $defaultContainer);
if ($assetPath === '') {
$this->error('Unable to determine asset path from input.');
return self::FAILURE;
}
$cacheDiskName = (string) config('statamic.assets.image_manipulation.cache');
if ($cacheDiskName === '') {
$this->error('Glide cache disk is not configured.');
return self::FAILURE;
}
$cachePath = trim((string) config('statamic.assets.image_manipulation.cache_path', '/'), '/');
$prefix = $this->buildCachePrefix($cachePath, $container, $assetPath);
$disk = Storage::disk($cacheDiskName);
$files = $disk->allFiles($prefix);
if (empty($files)) {
$this->warn('No cached files found for: '.$container.'/'.$assetPath);
return self::SUCCESS;
}
$presetHashes = $this->buildPresetHashMap($container, $assetPath);
$rows = [];
foreach ($files as $file) {
$hash = $this->extractHashFromCachePath($file);
$preset = $presetHashes[$hash] ?? '';
$rows[] = [
$file,
$hash,
is_array($preset) ? implode(', ', $preset) : $preset,
];
}
$this->table(['Cache File', 'Hash', 'Preset'], $rows);
if (! $this->confirm('Delete these cached files?')) {
$this->warn('Aborted. No files deleted.');
return self::SUCCESS;
}
$disk->delete($files);
$disk->deleteDirectory($prefix);
$this->info('Deleted '.count($files).' cached file(s) for: '.$container.'/'.$assetPath);
return self::SUCCESS;
}
/**
* Normalize the user input into a container handle and asset path.
*
* @return array{0: string, 1: string}
*/
protected function normalizeInput(string $input, string $defaultContainer): array
{
$input = trim($input);
$path = $input;
if (str_contains($input, '://')) {
$parsedPath = parse_url($input, PHP_URL_PATH);
if (is_string($parsedPath)) {
$path = $parsedPath;
}
}
$path = rawurldecode($path);
$path = ltrim($path, '/');
if (str_contains($path, 'containers/')) {
$segments = explode('/', $path);
$containerIndex = array_search('containers', $segments, true);
if ($containerIndex !== false && isset($segments[$containerIndex + 1])) {
$container = $segments[$containerIndex + 1];
$remaining = array_slice($segments, $containerIndex + 2);
$assetPath = $this->stripGlideHash($remaining);
return [$container, $assetPath];
}
}
if (str_starts_with($path, 'assets/')) {
$path = substr($path, strlen('assets/'));
}
return [$defaultContainer, ltrim($path, '/')];
}
/**
* Remove the Glide hash segment from a path segment list.
*/
protected function stripGlideHash(array $segments): string
{
$hashIndex = null;
foreach ($segments as $index => $segment) {
if (preg_match('/^[a-f0-9]{32}$/i', $segment) === 1) {
$hashIndex = $index;
break;
}
}
if ($hashIndex !== null) {
$segments = array_slice($segments, 0, $hashIndex);
}
return implode('/', $segments);
}
/**
* Build the cache prefix for the Glide cache disk.
*/
protected function buildCachePrefix(string $cachePath, string $container, string $assetPath): string
{
$cachePath = trim($cachePath, '/');
$prefix = $cachePath === '' ? '' : $cachePath.'/';
return $prefix.'containers/'.$container.'/'.trim($assetPath, '/');
}
/**
* Build a map of cache hashes to preset names.
*
* @return array<string, array<int, string>>
*/
protected function buildPresetHashMap(string $container, string $assetPath): array
{
$presets = (array) config('statamic.assets.image_manipulation.presets', []);
if ($presets === []) {
return [];
}
$asset = $this->resolveAsset($container, $assetPath);
$server = GlideManager::server();
$basename = basename($assetPath);
$folder = trim(dirname($assetPath), '.');
if ($asset) {
$server->setSource($asset->disk()->filesystem()->getDriver());
$server->setSourcePathPrefix($asset->folder());
$server->setCachePathPrefix('containers/'.$asset->container()->id().'/'.$asset->folder());
} else {
$server->setSourcePathPrefix($folder === '.' ? '' : $folder);
$server->setCachePathPrefix('containers/'.$container.($folder !== '' && $folder !== '.' ? '/'.$folder : ''));
}
$this->applyDefaultManipulations($server, $asset);
$hashes = [];
foreach (array_keys($presets) as $preset) {
$cachePath = $server->getCachePath($basename, ['p' => $preset]);
$hash = $this->extractHashFromCachePath($cachePath);
if ($hash !== '') {
$hashes[$hash][] = $preset;
}
}
return $hashes;
}
/**
* Resolve an asset from the container and path.
*/
protected function resolveAsset(string $container, string $assetPath): ?Asset
{
$assetContainer = AssetContainer::find($container);
if (! $assetContainer) {
return null;
}
return $assetContainer->makeAsset($assetPath);
}
/**
* Apply Statamic's default manipulations to the Glide server.
*/
protected function applyDefaultManipulations(Server $server, ?Asset $asset): void
{
$defaults = GlideManager::normalizeParameters(
(array) config('statamic.assets.image_manipulation.defaults', [])
);
if ((bool) config('statamic.assets.auto_crop') && $asset) {
$defaults['fit'] = 'crop-'.$asset->get('focus', '50-50');
}
$server->setDefaults($defaults);
}
/**
* Extract the hash segment from a cache path.
*/
protected function extractHashFromCachePath(string $cachePath): string
{
$segments = array_values(array_filter(explode('/', trim($cachePath, '/'))));
$count = count($segments);
if ($count < 2) {
return '';
}
return $segments[$count - 2] ?? '';
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment