__('Cache Control Tools'), 'summary' => __('Utility module installed alongside ProcessCacheControl to provide helper methods.'), 'author' => "Moritz L'Hoest", 'href' => 'https://github.com/MoritzLost/ProcessCacheControl', 'version' => '1.1.1', 'icon' => 'floppy-o', 'requires' => [ 'ProcessCacheControl', 'ProcessWire>=3.0.130', 'PHP>=7.1', ], ]; } /** @var bool If this is true, all helper methods will not write any log messages */ protected $silent = false; /** * Turn off all logging done by the helper methods of this module. You can * still call logMessage to log messages manually. * * @return self */ public function silent(): self { $this->silent = true; return $this; } /** * Turn the logging done by helper methods back on. * * @return self */ public function verbose(): self { $this->silent = false; return $this; } /** * Get the stored asset version string to append to asset source URLs. Generates * a new version string if none exists. * * @param string $type Optional asset class / category. * @return string */ public function getAssetVersion(string $type = self::ASSET_CACHE_DEFAULT_KEY): string { $assetVersion = $this->wire('cache')->getFor( self::ASSET_CACHE_NAMESPACE, $type ); return $assetVersion ?: $this->refreshAssetVersion($type); } /** * Refresh the stored asset version string and return it. * * @param string $type Optional asset class / category to refresh the version for. * @param string|null $version The new version to store. Defaults to the curernt timestamp. * @return string */ public function refreshAssetVersion(string $type = self::ASSET_CACHE_DEFAULT_KEY, ?string $version = null): string { $version = $version ?? time(); $this->wire('cache')->saveFor( self::ASSET_CACHE_NAMESPACE, $type, $version, WireCache::expireNever ); $this->logMessageIfNotSilent(sprintf( $this->_('Updated the asset version for type %1$s to: %2$s'), $type, $version )); return $version; } /** * Clear out all stored asset versions. New version strings will be * automatically generated the next time they are requested. * * @return self */ public function clearAllAssetVersions(): self { $this->wire('cache')->deleteFor(self::ASSET_CACHE_NAMESPACE); $this->logMessageIfNotSilent($this->_('Cleared all stored asset versions.')); return $this; } /** * Clear all files and directories in the specified folder inside the site's * cache directory. Includes a safety check to never delete anything outside * the cache directory. * * @param string $directory The name of the folder to clear, without a leading slash. * @return self */ public function clearCacheDirectoryContent(string $directory): self { $dirPath = $this->wire('config')->paths->cache . $directory; $dirPathFromRoot = $this->wire('config')->urls->cache . $directory; // check if the directory exists, and exit early if it doesn't if (!is_dir($dirPath)) { $this->logMessageIfNotSilent(sprintf( $this->_('Skipped request to delete missing folder: %s'), $dirPathFromRoot )); return $this; } // iterate over all contents of the directory and remove them recursively $dirIterator = new \DirectoryIterator($dirPath); $cacheLimitPath = $this->wire('config')->paths->cache; foreach ($dirIterator as $fileinfo) { if ($fileinfo->isDot()) continue; if ($fileinfo->isDir()) { $this->wire('files')->rmdir( $fileinfo->getPathname(), true, ['limitPath' => $cacheLimitPath] ); } if ($fileinfo->isFile() || $fileinfo->isLink()) { $this->wire('files')->unlink( $fileinfo->getPathname(), $cacheLimitPath ); } } // log the result if ($directory === PageRender::cacheDirName) { // special case: the "Page" directory contains the template render cache $this->logMessageIfNotSilent($this->_('Cleared the template render cache.')); } else { $this->logMessageIfNotSilent(sprintf( $this->_('Removed all files from the following cache directory: %s'), $dirPathFromRoot )); } return $this; } /** * Clears out all cache entries for the specified namespaces using * ProcessWire's cache API ($cache / WireCache). * * @param array $namespaces An array of cache namespaces to clear. * @return self */ public function clearWireCacheByNamespaces(array $namespaces): self { foreach ($namespaces as $namespace) { $this->wire('cache')->deleteFor($namespace); } $this->logMessageIfNotSilent(sprintf( $this->_('Deleted WireCache entries for the following namespaces: %s'), implode(', ', $namespaces) )); return $this; } /** * Log a message in the dedicated log file for this module. Newly added * cache actions should use this method to log messages about what they are * doing. The module page will automatically display all messages during * this page view. * * @param string $message The message to log. * @return self */ public function logMessage(string $message): self { $this->wire('log')->save( self::LOG_NAME, $message ); return $this; } /** * Log a message only if this instance is not currently set to silent. * * @see self::logMessage */ public function logMessageIfNotSilent(string $message): self { if (!$this->isSilent) { $this->logMessage($message); } return $this; } }