|
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
|
|
|
use micro\utils\FsUtils; |
|
13
|
|
|
use micro\cache\parser\ControllerParser; |
|
14
|
|
|
use micro\cache\parser\RestControllerParser; |
|
15
|
|
|
use micro\exceptions\RestException; |
|
16
|
|
|
use micro\exceptions\RouterException; |
|
17
|
|
|
|
|
18
|
|
|
class CacheManager { |
|
19
|
|
|
public static $cache; |
|
20
|
|
|
private static $cacheDirectory; |
|
21
|
|
|
private static $expiredRoutes=[ ]; |
|
22
|
|
|
|
|
23
|
|
|
public static function start(&$config) { |
|
24
|
|
|
self::$cacheDirectory=self::initialGetCacheDirectory($config); |
|
25
|
|
|
$cacheDirectory=ROOT . DS . self::$cacheDirectory; |
|
26
|
|
|
Annotations::$config['cache']=new AnnotationCache($cacheDirectory . '/annotations'); |
|
27
|
|
|
self::register(Annotations::getManager()); |
|
28
|
|
|
self::getCacheInstance($config, $cacheDirectory, ".cache"); |
|
29
|
|
|
//self::$cache=new ArrayCache($cacheDirectory, ".cache"); |
|
|
|
|
|
|
30
|
|
|
} |
|
31
|
|
|
|
|
32
|
|
|
public static function startProd(&$config) { |
|
33
|
|
|
self::$cacheDirectory=self::initialGetCacheDirectory($config); |
|
34
|
|
|
$cacheDirectory=ROOT . DS . self::$cacheDirectory; |
|
35
|
|
|
self::getCacheInstance($config,$cacheDirectory, ".cache"); |
|
36
|
|
|
} |
|
37
|
|
|
|
|
38
|
|
|
protected static function getCacheInstance(&$config,$cacheDirectory,$postfix){ |
|
39
|
|
|
$cacheSystem='micro\cache\ArrayCache'; |
|
40
|
|
|
if(!isset(self::$cache)){ |
|
41
|
|
|
if(isset($config["cache"]["system"])){ |
|
42
|
|
|
$cacheSystem=$config["cache"]["system"]; |
|
43
|
|
|
} |
|
44
|
|
|
self::$cache=new $cacheSystem($cacheDirectory,$postfix); |
|
45
|
|
|
} |
|
46
|
|
|
return self::$cache; |
|
47
|
|
|
} |
|
48
|
|
|
|
|
49
|
|
|
public static function getControllerCache($isRest=false) { |
|
50
|
|
|
$key=($isRest)?"rest":"default"; |
|
51
|
|
|
if (self::$cache->exists("controllers/routes.".$key)) |
|
52
|
|
|
return self::$cache->fetch("controllers/routes.".$key); |
|
53
|
|
|
return []; |
|
54
|
|
|
//throw new RouterException( $key." cache does not exist : the file `".FsUtils::cleanPathname(ROOT.DS.self::getCacheDirectory()."controllers/routes.").$key.".cache.php` is missing.\nTry to Re-init cache."); |
|
|
|
|
|
|
55
|
|
|
} |
|
56
|
|
|
|
|
57
|
|
|
public static function getRestCache() { |
|
58
|
|
|
if (self::$cache->exists("controllers/rest")) |
|
59
|
|
|
return self::$cache->fetch("controllers/rest"); |
|
60
|
|
|
throw new RestException("Rest cache does not exist : the file `".FsUtils::cleanPathname(ROOT.DS.self::getCacheDirectory()."controllers/")."rest.cache.php` is missing.\nTry to Re-init Rest cache."); |
|
61
|
|
|
} |
|
62
|
|
|
|
|
63
|
|
|
public static function getRouteCache($routePath, $duration) { |
|
64
|
|
|
$key=self::getRouteKey($routePath); |
|
65
|
|
|
|
|
66
|
|
|
if (self::$cache->exists("controllers/" . $key) && !self::expired($key, $duration)) { |
|
67
|
|
|
$response=self::$cache->file_get_contents("controllers/" . $key); |
|
68
|
|
|
return $response; |
|
69
|
|
|
} else { |
|
70
|
|
|
$response=Startup::runAsString($routePath); |
|
71
|
|
|
return self::storeRouteResponse($key, $response); |
|
72
|
|
|
} |
|
73
|
|
|
} |
|
74
|
|
|
|
|
75
|
|
|
public static function expired($key, $duration) { |
|
76
|
|
|
return self::$cache->expired("controllers/" . $key, $duration) === true || \array_key_exists($key, self::$expiredRoutes); |
|
77
|
|
|
} |
|
78
|
|
|
|
|
79
|
|
|
public static function isExpired($path,$duration){ |
|
80
|
|
|
$route=Router::getRoute($path,false); |
|
81
|
|
|
if($route!==false && \is_array($route)){ |
|
82
|
|
|
return self::expired(self::getRouteKey($route), $duration); |
|
83
|
|
|
} |
|
84
|
|
|
return true; |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
public static function setExpired($routePath, $expired=true) { |
|
88
|
|
|
$key=self::getRouteKey($routePath); |
|
89
|
|
|
self::setKeyExpired($key, $expired); |
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
|
|
private static function setKeyExpired($key, $expired=true) { |
|
93
|
|
|
if ($expired) { |
|
94
|
|
|
self::$expiredRoutes[$key]=true; |
|
95
|
|
|
} else { |
|
96
|
|
|
unset(self::$expiredRoutes[$key]); |
|
97
|
|
|
} |
|
98
|
|
|
} |
|
99
|
|
|
|
|
100
|
|
|
public static function setRouteCache($routePath) { |
|
101
|
|
|
$key=self::getRouteKey($routePath); |
|
102
|
|
|
$response=Startup::runAsString($routePath); |
|
103
|
|
|
return self::storeRouteResponse($key, $response); |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
private static function storeRouteResponse($key, $response) { |
|
107
|
|
|
self::setKeyExpired($key, false); |
|
108
|
|
|
self::$cache->store("controllers/" . $key, $response, false); |
|
109
|
|
|
return $response; |
|
110
|
|
|
} |
|
111
|
|
|
|
|
112
|
|
|
private static function getRouteKey($routePath) { |
|
113
|
|
|
return "path" . \md5(\implode("", $routePath)); |
|
114
|
|
|
} |
|
115
|
|
|
|
|
116
|
|
|
private static function initialGetCacheDirectory(&$config) { |
|
117
|
|
|
$cacheDirectory=@$config["cache"]["directory"]; |
|
118
|
|
|
if (!isset($cacheDirectory)) { |
|
119
|
|
|
$config["cache"]["directory"]="cache/"; |
|
120
|
|
|
$cacheDirectory=$config["cache"]["directory"]; |
|
121
|
|
|
} |
|
122
|
|
|
return $cacheDirectory; |
|
123
|
|
|
} |
|
124
|
|
|
|
|
125
|
|
|
public static function getCacheDirectory() { |
|
126
|
|
|
return self::$cacheDirectory; |
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
public static function createOrmModelCache($classname) { |
|
130
|
|
|
$key=self::getModelCacheKey($classname); |
|
131
|
|
|
if(isset(self::$cache)){ |
|
132
|
|
|
if (!self::$cache->exists($key)) { |
|
133
|
|
|
$p=new ModelParser(); |
|
134
|
|
|
$p->parse($classname); |
|
135
|
|
|
self::$cache->store($key, $p->__toString()); |
|
136
|
|
|
} |
|
137
|
|
|
return self::$cache->fetch($key); |
|
138
|
|
|
} |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
public static function getOrmModelCache($classname) { |
|
142
|
|
|
return self::$cache->fetch(self::getModelCacheKey($classname)); |
|
143
|
|
|
} |
|
144
|
|
|
|
|
145
|
|
|
public static function getModelCacheKey($classname){ |
|
146
|
|
|
return \str_replace("\\", DIRECTORY_SEPARATOR, $classname); |
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
public static function modelCacheExists($classname){ |
|
150
|
|
|
$key=self::getModelCacheKey($classname); |
|
151
|
|
|
if(isset(self::$cache)) |
|
152
|
|
|
return self::$cache->exists($key); |
|
153
|
|
|
return false; |
|
154
|
|
|
} |
|
155
|
|
|
|
|
156
|
|
|
private static function addControllerCache($classname) { |
|
157
|
|
|
$parser=new ControllerParser(); |
|
158
|
|
|
try { |
|
159
|
|
|
$parser->parse($classname); |
|
160
|
|
|
return $parser->asArray(); |
|
161
|
|
|
} catch ( \Exception $e ) { |
|
162
|
|
|
// Nothing to do |
|
163
|
|
|
} |
|
164
|
|
|
return []; |
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
public static function checkCache(&$config,$silent=false) { |
|
168
|
|
|
$dirs=self::getCacheDirectories($config,$silent); |
|
169
|
|
|
foreach ($dirs as $dir){ |
|
170
|
|
|
self::safeMkdir($dir); |
|
171
|
|
|
} |
|
172
|
|
|
return $dirs; |
|
173
|
|
|
} |
|
174
|
|
|
|
|
175
|
|
|
public static function getCacheDirectories(&$config,$silent=false){ |
|
176
|
|
|
$cacheDirectory=self::initialGetCacheDirectory($config); |
|
177
|
|
|
if(!$silent){ |
|
178
|
|
|
echo "cache directory is " . FsUtils::cleanPathname(ROOT . DS . $cacheDirectory) . "\n"; |
|
179
|
|
|
} |
|
180
|
|
|
$modelsDir=str_replace("\\", DS, $config["mvcNS"]["models"]); |
|
181
|
|
|
$controllersDir=str_replace("\\", DS, $config["mvcNS"]["controllers"]); |
|
182
|
|
|
$annotationCacheDir=ROOT . DS . $cacheDirectory . DS . "annotations"; |
|
183
|
|
|
$modelsCacheDir=ROOT . DS . $cacheDirectory . DS . $modelsDir; |
|
184
|
|
|
$queriesCacheDir=ROOT . DS . $cacheDirectory . DS . "queries"; |
|
185
|
|
|
$controllersCacheDir=ROOT . DS . $cacheDirectory . DS . $controllersDir; |
|
186
|
|
|
$viewsCacheDir=ROOT . DS . $cacheDirectory . DS . "views"; |
|
187
|
|
|
return [ "annotations" => $annotationCacheDir,"models" => $modelsCacheDir,"controllers" => $controllersCacheDir,"queries" => $queriesCacheDir ,"views"=>$viewsCacheDir]; |
|
188
|
|
|
} |
|
189
|
|
|
|
|
190
|
|
|
private static function safeMkdir($dir) { |
|
191
|
|
|
if (!is_dir($dir)) |
|
192
|
|
|
return mkdir($dir, 0777, true); |
|
193
|
|
|
} |
|
194
|
|
|
|
|
195
|
|
|
public static function clearCache(&$config, $type="all") { |
|
196
|
|
|
$cacheDirectories=self::checkCache($config); |
|
197
|
|
|
$cacheDirs=["annotations","controllers","models","queries","views"]; |
|
198
|
|
|
foreach ($cacheDirs as $typeRef){ |
|
199
|
|
|
self::_clearCache($cacheDirectories, $type, $typeRef); |
|
200
|
|
|
} |
|
201
|
|
|
} |
|
202
|
|
|
|
|
203
|
|
|
private static function _clearCache($cacheDirectories,$type,$typeRef){ |
|
204
|
|
|
if ($type === "all" || $type === $typeRef) |
|
205
|
|
|
FsUtils::deleteAllFilesFromFolder($cacheDirectories[$typeRef]); |
|
206
|
|
|
} |
|
207
|
|
|
|
|
208
|
|
|
public static function initCache(&$config, $type="all",$silent=false) { |
|
209
|
|
|
self::checkCache($config,$silent); |
|
210
|
|
|
self::start($config); |
|
211
|
|
|
if ($type === "all" || $type === "models") |
|
212
|
|
|
self::initModelsCache($config,false,$silent); |
|
213
|
|
|
if ($type === "all" || $type === "controllers") |
|
214
|
|
|
self::initRouterCache($config,$silent); |
|
215
|
|
|
if ($type === "all" || $type === "rest") |
|
216
|
|
|
self::initRestCache($config,$silent); |
|
217
|
|
|
} |
|
218
|
|
|
|
|
219
|
|
|
public static function initModelsCache(&$config,$forChecking=false,$silent=false) { |
|
220
|
|
|
$files=self::getModelsFiles($config,$silent); |
|
221
|
|
|
foreach ( $files as $file ) { |
|
222
|
|
|
if (is_file($file)) { |
|
223
|
|
|
$model=ClassUtils::getClassFullNameFromFile($file); |
|
224
|
|
|
if(!$forChecking){ |
|
225
|
|
|
self::createOrmModelCache($model); |
|
226
|
|
|
} |
|
227
|
|
|
} |
|
228
|
|
|
} |
|
229
|
|
|
if(!$silent){ |
|
230
|
|
|
echo "Models cache reset\n"; |
|
231
|
|
|
} |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
public static function getModelsFiles(&$config,$silent=false){ |
|
235
|
|
|
return self::_getFiles($config, "models",$silent); |
|
236
|
|
|
} |
|
237
|
|
|
|
|
238
|
|
|
public static function getModels(&$config,$silent=false){ |
|
239
|
|
|
$result=[]; |
|
240
|
|
|
$files=self::getModelsFiles($config,$silent); |
|
241
|
|
|
foreach ($files as $file){ |
|
242
|
|
|
$result[]=ClassUtils::getClassFullNameFromFile($file); |
|
243
|
|
|
} |
|
244
|
|
|
return $result; |
|
245
|
|
|
} |
|
246
|
|
|
|
|
247
|
|
|
public static function getControllersFiles(&$config,$silent=false){ |
|
248
|
|
|
return self::_getFiles($config, "controllers",$silent); |
|
249
|
|
|
} |
|
250
|
|
|
|
|
251
|
|
|
private static function _getFiles(&$config,$type,$silent=false){ |
|
252
|
|
|
$typeNS=$config["mvcNS"][$type]; |
|
253
|
|
|
$typeDir=ROOT . DS . str_replace("\\", DS, $typeNS); |
|
254
|
|
|
if(!$silent) |
|
255
|
|
|
echo \ucfirst($type)." directory is " . ROOT . $typeNS . "\n"; |
|
256
|
|
|
return FsUtils::glob_recursive($typeDir . DS . '*'); |
|
257
|
|
|
} |
|
258
|
|
|
|
|
259
|
|
|
private static function initRouterCache(&$config,$silent=false) { |
|
260
|
|
|
$routes=["rest"=>[],"default"=>[]]; |
|
261
|
|
|
$files=self::getControllersFiles($config); |
|
262
|
|
|
foreach ( $files as $file ) { |
|
263
|
|
|
if (is_file($file)) { |
|
264
|
|
|
$controller=ClassUtils::getClassFullNameFromFile($file); |
|
265
|
|
|
$parser=new ControllerParser(); |
|
266
|
|
|
try { |
|
267
|
|
|
$parser->parse($controller); |
|
268
|
|
|
$ret= $parser->asArray(); |
|
269
|
|
|
$key=($parser->isRest())?"rest":"default"; |
|
270
|
|
|
$routes[$key]=\array_merge($routes[$key], $ret); |
|
271
|
|
|
} catch ( \Exception $e ) { |
|
272
|
|
|
// Nothing to do |
|
273
|
|
|
} |
|
274
|
|
|
|
|
275
|
|
|
} |
|
276
|
|
|
} |
|
277
|
|
|
self::$cache->store("controllers/routes.default", "return " . JArray::asPhpArray($routes["default"], "array") . ";"); |
|
278
|
|
|
self::$cache->store("controllers/routes.rest", "return " . JArray::asPhpArray($routes["rest"], "array") . ";"); |
|
279
|
|
|
if(!$silent){ |
|
280
|
|
|
echo "Router cache reset\n"; |
|
281
|
|
|
} |
|
282
|
|
|
} |
|
283
|
|
|
|
|
284
|
|
|
private static function initRestCache(&$config,$silent=false) { |
|
285
|
|
|
$restCache=[]; |
|
286
|
|
|
$files=self::getControllersFiles($config); |
|
287
|
|
|
foreach ( $files as $file ) { |
|
288
|
|
|
if (is_file($file)) { |
|
289
|
|
|
$controller=ClassUtils::getClassFullNameFromFile($file); |
|
290
|
|
|
$parser=new RestControllerParser(); |
|
291
|
|
|
$parser->parse($controller,$config); |
|
292
|
|
|
if($parser->isRest()) |
|
293
|
|
|
$restCache=\array_merge($restCache,$parser->asArray()); |
|
294
|
|
|
} |
|
295
|
|
|
} |
|
296
|
|
|
self::$cache->store("controllers/rest", "return " . JArray::asPhpArray($restCache, "array") . ";"); |
|
297
|
|
|
if(!$silent){ |
|
298
|
|
|
echo "Rest cache reset\n"; |
|
299
|
|
|
} |
|
300
|
|
|
} |
|
301
|
|
|
|
|
302
|
|
|
private static function register(AnnotationManager $annotationManager) { |
|
303
|
|
|
$annotationManager->registry=array_merge($annotationManager->registry, [ |
|
304
|
|
|
'id' => 'micro\annotations\IdAnnotation', |
|
305
|
|
|
'manyToOne' => 'micro\annotations\ManyToOneAnnotation', |
|
306
|
|
|
'oneToMany' => 'micro\annotations\OneToManyAnnotation', |
|
307
|
|
|
'manyToMany' => 'micro\annotations\ManyToManyAnnotation', |
|
308
|
|
|
'joinColumn' => 'micro\annotations\JoinColumnAnnotation', |
|
309
|
|
|
'table' => 'micro\annotations\TableAnnotation', |
|
310
|
|
|
'transient' => 'micro\annotations\TransientAnnotation', |
|
311
|
|
|
'column' => 'micro\annotations\ColumnAnnotation', |
|
312
|
|
|
'joinTable' => 'micro\annotations\JoinTableAnnotation', |
|
313
|
|
|
'route' => 'micro\annotations\router\RouteAnnotation', |
|
314
|
|
|
'var' => 'mindplay\annotations\standard\VarAnnotation', |
|
315
|
|
|
'yuml' => 'micro\annotations\YumlAnnotation', |
|
316
|
|
|
'rest' => 'micro\annotations\rest\RestAnnotation', |
|
317
|
|
|
'authorization' => 'micro\annotations\rest\AuthorizationAnnotation' |
|
318
|
|
|
]); |
|
319
|
|
|
} |
|
320
|
|
|
|
|
321
|
|
|
public static function addAdminRoutes() { |
|
322
|
|
|
self::addControllerCache("micro\controllers\Admin"); |
|
323
|
|
|
} |
|
324
|
|
|
|
|
325
|
|
|
public static function getRoutes() { |
|
326
|
|
|
$result=self::getControllerCache(); |
|
327
|
|
|
return $result; |
|
328
|
|
|
} |
|
329
|
|
|
|
|
330
|
|
|
public static function getRestRoutes() { |
|
331
|
|
|
$result=[]; |
|
332
|
|
|
$restCache=self::getRestCache(); |
|
333
|
|
|
foreach ($restCache as $controllerClass=>$restAttributes){ |
|
334
|
|
|
if(isset($restCache[$controllerClass])){ |
|
335
|
|
|
$result[$controllerClass]=["restAttributes"=>$restAttributes,"routes"=>self::getControllerRoutes($controllerClass,true)]; |
|
336
|
|
|
} |
|
337
|
|
|
} |
|
338
|
|
|
return $result; |
|
339
|
|
|
} |
|
340
|
|
|
|
|
341
|
|
|
public static function getControllerRoutes($controllerClass,$isRest=false){ |
|
342
|
|
|
$result=[]; |
|
343
|
|
|
$ctrlCache=self::getControllerCache($isRest); |
|
344
|
|
|
foreach ($ctrlCache as $path=>$routeAttributes){ |
|
345
|
|
|
if(isset($routeAttributes["controller"])){ |
|
346
|
|
|
if($routeAttributes["controller"]===$controllerClass){ |
|
347
|
|
|
$result[$path]=$routeAttributes; |
|
348
|
|
|
} |
|
349
|
|
|
}else{ |
|
350
|
|
|
$firstValue=reset($routeAttributes); |
|
351
|
|
|
if(isset($firstValue)&&isset($firstValue["controller"])){ |
|
352
|
|
|
if($firstValue["controller"]===$controllerClass){ |
|
353
|
|
|
$result[$path]=$routeAttributes; |
|
354
|
|
|
} |
|
355
|
|
|
} |
|
356
|
|
|
} |
|
357
|
|
|
} |
|
358
|
|
|
return $result; |
|
359
|
|
|
} |
|
360
|
|
|
|
|
361
|
|
|
public static function getRestResource($controllerClass){ |
|
362
|
|
|
$cacheControllerClass=self::getRestCacheController($controllerClass); |
|
363
|
|
|
if(isset($cacheControllerClass)) |
|
364
|
|
|
return $cacheControllerClass["resource"]; |
|
365
|
|
|
return null; |
|
366
|
|
|
} |
|
367
|
|
|
|
|
368
|
|
|
public static function getRestCacheController($controllerClass){ |
|
369
|
|
|
$cache=self::getRestCache(); |
|
370
|
|
|
if(isset($cache[$controllerClass])){ |
|
371
|
|
|
return $cache[$controllerClass]; |
|
372
|
|
|
} |
|
373
|
|
|
return null; |
|
374
|
|
|
} |
|
375
|
|
|
|
|
376
|
|
|
|
|
377
|
|
|
public static function addRoute($path, $controller, $action="index", $methods=null, $name="") { |
|
378
|
|
|
$controllerCache=self::getControllerCache(); |
|
379
|
|
|
Router::addRouteToRoutes($controllerCache, $path, $controller, $action, $methods, $name); |
|
380
|
|
|
self::$cache->store("controllers/routes", "return " . JArray::asPhpArray($controllerCache, "array") . ";"); |
|
381
|
|
|
} |
|
382
|
|
|
} |
|
383
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.