-
Notifications
You must be signed in to change notification settings - Fork 0
/
CacheControlTools.module
213 lines (198 loc) · 6.89 KB
/
CacheControlTools.module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
<?php
namespace ProcessWire;
class CacheControlTools extends Wire implements Module
{
/** @var string The cache namespace for storing asset versions in the database */
public const ASSET_CACHE_NAMESPACE = 'cache-control-assets';
/** @var string The default asset type / category if none is specified */
public const ASSET_CACHE_DEFAULT_KEY = 'default';
/** @var string The name of the system log for this module */
public const LOG_NAME = 'cache-control';
public static function getModuleInfo()
{
return [
'title' => __('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;
}
}