|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace micro\cache; |
|
4
|
|
|
|
|
5
|
|
|
use mindplay\annotations\Annotations; |
|
6
|
|
|
use mindplay\annotations\AnnotationCache; |
|
7
|
|
|
use mindplay\annotations\AnnotationManager; |
|
8
|
|
|
use micro\orm\parser\ModelParser; |
|
9
|
|
|
use micro\utils\JArray; |
|
10
|
|
|
use micro\controllers\Router; |
|
11
|
|
|
use micro\controllers\Startup; |
|
12
|
|
|
|
|
13
|
|
|
class CacheManager { |
|
14
|
|
|
public static $cache; |
|
15
|
|
|
private static $routes=[ ]; |
|
16
|
|
|
private static $cacheDirectory; |
|
17
|
|
|
private static $expiredRoutes=[ ]; |
|
18
|
|
|
|
|
19
|
|
|
public static function start(&$config) { |
|
20
|
|
|
self::$cacheDirectory=self::initialGetCacheDirectory($config); |
|
21
|
|
|
$cacheDirectory=ROOT . DS . self::$cacheDirectory; |
|
22
|
|
|
Annotations::$config['cache']=new AnnotationCache($cacheDirectory . '/annotations'); |
|
23
|
|
|
self::register(Annotations::getManager()); |
|
24
|
|
|
self::$cache=new ArrayCache($cacheDirectory, ".cache"); |
|
25
|
|
|
} |
|
26
|
|
|
|
|
27
|
|
|
public static function startProd(&$config) { |
|
28
|
|
|
self::$cacheDirectory=self::initialGetCacheDirectory($config); |
|
29
|
|
|
$cacheDirectory=ROOT . DS . self::$cacheDirectory; |
|
30
|
|
|
self::$cache=new ArrayCache($cacheDirectory, ".cache"); |
|
31
|
|
|
} |
|
32
|
|
|
|
|
33
|
|
|
public static function getControllerCache() { |
|
34
|
|
|
if (self::$cache->exists("controllers/routes")) |
|
35
|
|
|
return self::$cache->fetch("controllers/routes"); |
|
36
|
|
|
return [ ]; |
|
37
|
|
|
} |
|
38
|
|
|
|
|
39
|
|
|
public static function getRouteCache($routePath, $duration) { |
|
40
|
|
|
$key=self::getRouteKey($routePath); |
|
41
|
|
|
|
|
42
|
|
|
if (self::$cache->exists("controllers/" . $key) && !self::expired($key, $duration)) { |
|
43
|
|
|
$response=self::$cache->file_get_contents("controllers/" . $key); |
|
44
|
|
|
return $response; |
|
45
|
|
|
} else { |
|
46
|
|
|
$response=Startup::runAsString($routePath); |
|
47
|
|
|
return self::storeRouteResponse($key, $response); |
|
48
|
|
|
} |
|
49
|
|
|
} |
|
50
|
|
|
|
|
51
|
|
|
public static function expired($key, $duration) { |
|
52
|
|
|
return self::$cache->expired("controllers/" . $key, $duration) === true || \array_key_exists($key, self::$expiredRoutes); |
|
53
|
|
|
} |
|
54
|
|
|
|
|
55
|
|
|
public static function isExpired($path,$duration){ |
|
56
|
|
|
$route=Router::getRoute($path,false); |
|
|
|
|
|
|
57
|
|
|
if($route!==false && \is_array($route)){ |
|
58
|
|
|
return self::expired(self::getRouteKey($route), $duration); |
|
59
|
|
|
} |
|
60
|
|
|
return true; |
|
61
|
|
|
} |
|
62
|
|
|
|
|
63
|
|
|
public static function setExpired($routePath, $expired=true) { |
|
64
|
|
|
$key=self::getRouteKey($routePath); |
|
65
|
|
|
self::setKeyExpired($key, $expired); |
|
66
|
|
|
} |
|
67
|
|
|
|
|
68
|
|
|
private static function setKeyExpired($key, $expired=true) { |
|
69
|
|
|
if ($expired) { |
|
70
|
|
|
self::$expiredRoutes[$key]=true; |
|
71
|
|
|
} else { |
|
72
|
|
|
unset(self::$expiredRoutes[$key]); |
|
73
|
|
|
} |
|
74
|
|
|
} |
|
75
|
|
|
|
|
76
|
|
|
public static function setRouteCache($routePath) { |
|
77
|
|
|
$key=self::getRouteKey($routePath); |
|
78
|
|
|
$response=Startup::runAsString($routePath); |
|
79
|
|
|
return self::storeRouteResponse($key, $response); |
|
80
|
|
|
} |
|
81
|
|
|
|
|
82
|
|
|
private static function storeRouteResponse($key, $response) { |
|
83
|
|
|
self::setKeyExpired($key, false); |
|
84
|
|
|
self::$cache->store("controllers/" . $key, $response, false); |
|
85
|
|
|
return $response; |
|
86
|
|
|
} |
|
87
|
|
|
|
|
88
|
|
|
private static function getRouteKey($routePath) { |
|
89
|
|
|
return "path" . \md5(\implode("", $routePath)); |
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
|
|
private static function initialGetCacheDirectory(&$config) { |
|
93
|
|
|
$cacheDirectory=@$config["cacheDirectory"]; |
|
94
|
|
|
if (!isset($cacheDirectory)) { |
|
95
|
|
|
$config["cacheDirectory"]="cache/"; |
|
96
|
|
|
$cacheDirectory=$config["cacheDirectory"]; |
|
97
|
|
|
} |
|
98
|
|
|
return $cacheDirectory; |
|
99
|
|
|
} |
|
100
|
|
|
|
|
101
|
|
|
public static function getCacheDirectory() { |
|
102
|
|
|
return self::$cacheDirectory; |
|
103
|
|
|
} |
|
104
|
|
|
|
|
105
|
|
|
public static function createOrmModelCache($className) { |
|
106
|
|
|
$key=\str_replace("\\", DIRECTORY_SEPARATOR, $className); |
|
107
|
|
|
if (!self::$cache->exists($key)) { |
|
108
|
|
|
$p=new ModelParser(); |
|
109
|
|
|
$p->parse($className); |
|
110
|
|
|
self::$cache->store($key, $p->__toString()); |
|
111
|
|
|
} |
|
112
|
|
|
return self::$cache->fetch($key); |
|
113
|
|
|
} |
|
114
|
|
|
|
|
115
|
|
|
private static function addControllerCache($classname) { |
|
116
|
|
|
$parser=new ControllerParser(); |
|
117
|
|
|
try { |
|
118
|
|
|
$parser->parse($classname); |
|
119
|
|
|
self::$routes=\array_merge($parser->asArray(), self::$routes); |
|
120
|
|
|
} catch ( \Exception $e ) { |
|
121
|
|
|
// Nothing to do |
|
122
|
|
|
} |
|
123
|
|
|
} |
|
124
|
|
|
|
|
125
|
|
|
public static function checkCache(&$config) { |
|
126
|
|
|
$cacheDirectory=self::initialGetCacheDirectory($config); |
|
127
|
|
|
$modelsDir=str_replace("\\", DS, $config["mvcNS"]["models"]); |
|
128
|
|
|
$controllersDir=str_replace("\\", DS, $config["mvcNS"]["controllers"]); |
|
129
|
|
|
echo "cache directory is " . ROOT . DS . $cacheDirectory . "\n"; |
|
130
|
|
|
$annotationCacheDir=ROOT . DS . $cacheDirectory . DS . "annotations"; |
|
131
|
|
|
$modelsCacheDir=ROOT . DS . $cacheDirectory . DS . $modelsDir; |
|
132
|
|
|
$queriesCacheDir=ROOT . DS . $cacheDirectory . DS . "queries"; |
|
133
|
|
|
$controllersCacheDir=ROOT . DS . $cacheDirectory . DS . $controllersDir; |
|
134
|
|
|
self::safeMkdir($annotationCacheDir); |
|
135
|
|
|
self::safeMkdir($modelsCacheDir); |
|
136
|
|
|
self::safeMkdir($controllersCacheDir); |
|
137
|
|
|
self::safeMkdir($queriesCacheDir); |
|
138
|
|
|
return [ "annotations" => $annotationCacheDir,"models" => $modelsCacheDir,"controllers" => $controllersCacheDir,"queries" => $queriesCacheDir ]; |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
private static function safeMkdir($dir) { |
|
142
|
|
|
if (!is_dir($dir)) |
|
143
|
|
|
return mkdir($dir, 0777, true); |
|
144
|
|
|
} |
|
145
|
|
|
|
|
146
|
|
|
private static function deleteAllFilesFromFolder($folder) { |
|
147
|
|
|
$files=glob($folder . '/*'); |
|
148
|
|
|
foreach ( $files as $file ) { |
|
149
|
|
|
if (is_file($file)) |
|
150
|
|
|
unlink($file); |
|
151
|
|
|
} |
|
152
|
|
|
} |
|
153
|
|
|
|
|
154
|
|
|
public static function clearCache(&$config, $type="all") { |
|
155
|
|
|
$cacheDirectories=self::checkCache($config); |
|
156
|
|
|
if ($type === "all") { |
|
157
|
|
|
self::deleteAllFilesFromFolder($cacheDirectories["annotations"]); |
|
158
|
|
|
} |
|
159
|
|
|
if ($type === "all" || $type === "controllers") |
|
160
|
|
|
self::deleteAllFilesFromFolder($cacheDirectories["controllers"]); |
|
161
|
|
|
if ($type === "all" || $type === "models") |
|
162
|
|
|
self::deleteAllFilesFromFolder($cacheDirectories["models"]); |
|
163
|
|
|
if ($type === "all" || $type === "queries") |
|
164
|
|
|
self::deleteAllFilesFromFolder($cacheDirectories["queries"]); |
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
public static function initCache(&$config, $type="all") { |
|
168
|
|
|
self::checkCache($config); |
|
169
|
|
|
self::start($config); |
|
170
|
|
|
if ($type === "all" || $type === "models") |
|
171
|
|
|
self::initModelsCache($config); |
|
172
|
|
|
if ($type === "all" || $type === "controllers") |
|
173
|
|
|
self::initControllersCache($config); |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
|
|
private static function initModelsCache(&$config) { |
|
177
|
|
|
$modelsNS=$config["mvcNS"]["models"]; |
|
178
|
|
|
$modelsDir=ROOT . DS . str_replace("\\", DS, $modelsNS); |
|
179
|
|
|
echo "Models directory is " . ROOT . $modelsNS . "\n"; |
|
180
|
|
|
$files=self::glob_recursive($modelsDir . DS . '*'); |
|
181
|
|
|
foreach ( $files as $file ) { |
|
182
|
|
|
if (is_file($file)) { |
|
183
|
|
|
$model=ClassUtils::getClassFullNameFromFile($file); |
|
184
|
|
|
new $model(); |
|
185
|
|
|
} |
|
186
|
|
|
} |
|
187
|
|
|
} |
|
188
|
|
|
|
|
189
|
|
|
public static function getControllerFiles(&$config,$silent=false){ |
|
190
|
|
|
$controllersNS=$config["mvcNS"]["controllers"]; |
|
191
|
|
|
$controllersDir=ROOT . DS . str_replace("\\", DS, $controllersNS); |
|
192
|
|
|
if(!$silent) |
|
193
|
|
|
echo "Controllers directory is " . ROOT . $controllersNS . "\n"; |
|
194
|
|
|
return self::glob_recursive($controllersDir . DS . '*'); |
|
195
|
|
|
} |
|
196
|
|
|
|
|
197
|
|
|
private static function initControllersCache(&$config) { |
|
198
|
|
|
$files=self::getControllerFiles($config); |
|
199
|
|
|
foreach ( $files as $file ) { |
|
200
|
|
|
if (is_file($file)) { |
|
201
|
|
|
$controller=ClassUtils::getClassFullNameFromFile($file); |
|
202
|
|
|
self::addControllerCache($controller); |
|
203
|
|
|
} |
|
204
|
|
|
} |
|
205
|
|
|
if ($config["debug"]) |
|
206
|
|
|
self::addAdminRoutes(); |
|
207
|
|
|
self::$cache->store("controllers/routes", "return " . JArray::asPhpArray(self::$routes, "array") . ";"); |
|
208
|
|
|
} |
|
209
|
|
|
|
|
210
|
|
|
public static function glob_recursive($pattern, $flags=0) { |
|
211
|
|
|
$files=glob($pattern, $flags); |
|
212
|
|
|
foreach ( glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir ) { |
|
213
|
|
|
$files=array_merge($files, self::glob_recursive($dir . '/' . basename($pattern), $flags)); |
|
214
|
|
|
} |
|
215
|
|
|
return $files; |
|
216
|
|
|
} |
|
217
|
|
|
|
|
218
|
|
|
private static function register(AnnotationManager $annotationManager) { |
|
219
|
|
|
$annotationManager->registry=array_merge($annotationManager->registry, [ |
|
220
|
|
|
'id' => 'micro\annotations\IdAnnotation', |
|
221
|
|
|
'manyToOne' => 'micro\annotations\ManyToOneAnnotation', |
|
222
|
|
|
'oneToMany' => 'micro\annotations\OneToManyAnnotation', |
|
223
|
|
|
'manyToMany' => 'micro\annotations\ManyToManyAnnotation', |
|
224
|
|
|
'joinColumn' => 'micro\annotations\JoinColumnAnnotation', |
|
225
|
|
|
'table' => 'micro\annotations\TableAnnotation', |
|
226
|
|
|
'transient' => 'micro\annotations\TransientAnnotation', |
|
227
|
|
|
'column' => 'micro\annotations\ColumnAnnotation', |
|
228
|
|
|
'joinTable' => 'micro\annotations\JoinTableAnnotation', |
|
229
|
|
|
'route' => 'micro\annotations\router\RouteAnnotation', |
|
230
|
|
|
'var' => 'mindplay\annotations\standard\VarAnnotation' |
|
231
|
|
|
]); |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
public static function addAdminRoutes() { |
|
235
|
|
|
self::addControllerCache("micro\controllers\Admin"); |
|
236
|
|
|
} |
|
237
|
|
|
|
|
238
|
|
|
public static function getRoutes() { |
|
239
|
|
|
$result=self::getControllerCache(); |
|
240
|
|
|
return $result; |
|
241
|
|
|
} |
|
242
|
|
|
|
|
243
|
|
|
public static function addRoute($path, $controller, $action="index", $methods=null, $name="") { |
|
244
|
|
|
$controllerCache=self::getControllerCache(); |
|
245
|
|
|
Router::addRouteToRoutes($controllerCache, $path, $controller, $action, $methods, $name); |
|
246
|
|
|
self::$cache->store("controllers/routes", "return " . JArray::asPhpArray($controllerCache, "array") . ";"); |
|
247
|
|
|
} |
|
248
|
|
|
} |
|
249
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignorePhpDoc annotation to the duplicate definition and it will be ignored.