Completed
Push — master ( 0feaa6...f4afa6 )
by Jean-Christophe
01:33
created

CacheManager::setExpired()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 3
nc 1
nop 2
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
16
class CacheManager {
17
	public static $cache;
18
	private static $routes=[ ];
0 ignored issues
show
Unused Code introduced by
The property $routes is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
19
	private static $cacheDirectory;
20
	private static $expiredRoutes=[ ];
21
22
	public static function start(&$config) {
23
		self::$cacheDirectory=self::initialGetCacheDirectory($config);
24
		$cacheDirectory=ROOT . DS . self::$cacheDirectory;
25
		Annotations::$config['cache']=new AnnotationCache($cacheDirectory . '/annotations');
26
		self::register(Annotations::getManager());
27
		self::$cache=new ArrayCache($cacheDirectory, ".cache");
28
	}
29
30
	public static function startProd(&$config) {
31
		self::$cacheDirectory=self::initialGetCacheDirectory($config);
32
		$cacheDirectory=ROOT . DS . self::$cacheDirectory;
33
		self::$cache=new ArrayCache($cacheDirectory, ".cache");
34
	}
35
36
	public static function getControllerCache($isRest=false) {
37
		$key=($isRest)?"rest":"default";
38
		if (self::$cache->exists("controllers/routes.".$key))
39
			return self::$cache->fetch("controllers/routes.".$key);
40
		return [ ];
41
	}
42
43
	public static function getRestCache() {
44
		if (self::$cache->exists("controllers/rest"))
45
			return self::$cache->fetch("controllers/rest");
46
		return [ ];
47
	}
48
49
	public static function getRouteCache($routePath, $duration) {
50
		$key=self::getRouteKey($routePath);
51
52
		if (self::$cache->exists("controllers/" . $key) && !self::expired($key, $duration)) {
53
			$response=self::$cache->file_get_contents("controllers/" . $key);
54
			return $response;
55
		} else {
56
			$response=Startup::runAsString($routePath);
57
			return self::storeRouteResponse($key, $response);
58
		}
59
	}
60
61
	public static function expired($key, $duration) {
62
		return self::$cache->expired("controllers/" . $key, $duration) === true || \array_key_exists($key, self::$expiredRoutes);
63
	}
64
65
	public static function isExpired($path,$duration){
66
		$route=Router::getRoute($path,false);
67
		if($route!==false && \is_array($route)){
68
			return self::expired(self::getRouteKey($route), $duration);
69
		}
70
		return true;
71
	}
72
73
	public static function setExpired($routePath, $expired=true) {
74
		$key=self::getRouteKey($routePath);
75
		self::setKeyExpired($key, $expired);
76
	}
77
78
	private static function setKeyExpired($key, $expired=true) {
79
		if ($expired) {
80
			self::$expiredRoutes[$key]=true;
81
		} else {
82
			unset(self::$expiredRoutes[$key]);
83
		}
84
	}
85
86
	public static function setRouteCache($routePath) {
87
		$key=self::getRouteKey($routePath);
88
		$response=Startup::runAsString($routePath);
89
		return self::storeRouteResponse($key, $response);
90
	}
91
92
	private static function storeRouteResponse($key, $response) {
93
		self::setKeyExpired($key, false);
94
		self::$cache->store("controllers/" . $key, $response, false);
95
		return $response;
96
	}
97
98
	private static function getRouteKey($routePath) {
99
		return "path" . \md5(\implode("", $routePath));
100
	}
101
102
	private static function initialGetCacheDirectory(&$config) {
103
		$cacheDirectory=@$config["cacheDirectory"];
104
		if (!isset($cacheDirectory)) {
105
			$config["cacheDirectory"]="cache/";
106
			$cacheDirectory=$config["cacheDirectory"];
107
		}
108
		return $cacheDirectory;
109
	}
110
111
	public static function getCacheDirectory() {
112
		return self::$cacheDirectory;
113
	}
114
115
	public static function createOrmModelCache($classname) {
116
		$key=self::getModelCacheKey($classname);
117
		if(isset(self::$cache)){
118
			if (!self::$cache->exists($key)) {
119
				$p=new ModelParser();
120
				$p->parse($classname);
121
				self::$cache->store($key, $p->__toString());
122
			}
123
			return self::$cache->fetch($key);
124
		}
125
	}
126
127
	public static function getModelCacheKey($classname){
128
		return \str_replace("\\", DIRECTORY_SEPARATOR, $classname);
129
	}
130
131
	public static function modelCacheExists($classname){
132
		$key=self::getModelCacheKey($classname);
133
		if(isset(self::$cache))
134
			return self::$cache->exists($key);
135
		return false;
136
	}
137
138
	private static function addControllerCache($classname) {
139
		$parser=new ControllerParser();
140
		try {
141
			$parser->parse($classname);
142
			return $parser->asArray();
143
		} catch ( \Exception $e ) {
144
			// Nothing to do
145
		}
146
		return [];
147
	}
148
149
	public static function checkCache(&$config,$silent=false) {
150
		$dirs=self::getCacheDirectories($config,$silent);
151
		foreach ($dirs as $dir){
152
			self::safeMkdir($dir);
153
		}
154
		return $dirs;
155
	}
156
157
	public static function getCacheDirectories(&$config,$silent=false){
158
		$cacheDirectory=self::initialGetCacheDirectory($config);
159
		if(!$silent){
160
			echo "cache directory is " . FsUtils::cleanPathname(ROOT . DS . $cacheDirectory) . "\n";
161
		}
162
		$modelsDir=str_replace("\\", DS, $config["mvcNS"]["models"]);
163
		$controllersDir=str_replace("\\", DS, $config["mvcNS"]["controllers"]);
164
		$annotationCacheDir=ROOT . DS . $cacheDirectory . DS . "annotations";
165
		$modelsCacheDir=ROOT . DS . $cacheDirectory . DS . $modelsDir;
166
		$queriesCacheDir=ROOT . DS . $cacheDirectory . DS . "queries";
167
		$controllersCacheDir=ROOT . DS . $cacheDirectory . DS . $controllersDir;
168
		$viewsCacheDir=ROOT . DS . $cacheDirectory . DS . "views";
169
		return [ "annotations" => $annotationCacheDir,"models" => $modelsCacheDir,"controllers" => $controllersCacheDir,"queries" => $queriesCacheDir ,"views"=>$viewsCacheDir];
170
	}
171
172
	private static function safeMkdir($dir) {
173
		if (!is_dir($dir))
174
			return mkdir($dir, 0777, true);
175
	}
176
177
	public static function clearCache(&$config, $type="all") {
178
		$cacheDirectories=self::checkCache($config);
179
		$cacheDirs=["annotations","controllers","models","queries","views"];
180
		foreach ($cacheDirs as $typeRef){
181
			self::_clearCache($cacheDirectories, $type, $typeRef);
182
		}
183
	}
184
185
	private static function _clearCache($cacheDirectories,$type,$typeRef){
186
		if ($type === "all" || $type === $typeRef)
187
			FsUtils::deleteAllFilesFromFolder($cacheDirectories[$typeRef]);
188
	}
189
190
	public static function initCache(&$config, $type="all") {
191
		self::checkCache($config,$type);
0 ignored issues
show
Documentation introduced by
$type is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
192
		self::start($config);
193
		if ($type === "all" || $type === "models")
194
			self::initModelsCache($config);
195
		if ($type === "all" || $type === "controllers")
196
			self::initRouterCache($config);
197
		if ($type === "all" || $type === "rest")
198
			self::initRestCache($config);
199
	}
200
201
	public static function initModelsCache(&$config,$forChecking=false,$silent=false) {
202
		$files=self::getModelsFiles($config, "models",$silent);
0 ignored issues
show
Documentation introduced by
'models' is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Unused Code introduced by
The call to CacheManager::getModelsFiles() has too many arguments starting with $silent.

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 @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
203
		foreach ( $files as $file ) {
204
			if (is_file($file)) {
205
				$model=ClassUtils::getClassFullNameFromFile($file);
206
				if(!$forChecking){
207
					new $model();
208
				}
209
			}
210
		}
211
	}
212
213
	public static function getModelsFiles(&$config,$silent=false){
214
		return self::_getFiles($config, "models",$silent);
215
	}
216
217
	public static function getControllersFiles(&$config,$silent=false){
218
		return self::_getFiles($config, "controllers",$silent);
219
	}
220
221
	private static function _getFiles(&$config,$type,$silent=false){
222
		$typeNS=$config["mvcNS"][$type];
223
		$typeDir=ROOT . DS . str_replace("\\", DS, $typeNS);
224
		if(!$silent)
225
			echo \ucfirst($type)." directory is " . ROOT . $typeNS . "\n";
226
		return FsUtils::glob_recursive($typeDir . DS . '*');
227
	}
228
229
	private static function initRouterCache(&$config) {
230
		$routes=["rest"=>[],"default"=>[]];
231
		$files=self::getControllersFiles($config);
232
		foreach ( $files as $file ) {
233
			if (is_file($file)) {
234
				$controller=ClassUtils::getClassFullNameFromFile($file);
235
				$parser=new ControllerParser();
236
				try {
237
					$parser->parse($controller);
238
					$ret= $parser->asArray();
239
					$key=($parser->isRest())?"rest":"default";
240
					$routes[$key]=\array_merge($routes[$key], $ret);
241
				} catch ( \Exception $e ) {
242
					// Nothing to do
243
				}
244
245
			}
246
		}
247
		self::$cache->store("controllers/routes.default", "return " . JArray::asPhpArray($routes["default"], "array") . ";");
248
		self::$cache->store("controllers/routes.rest", "return " . JArray::asPhpArray($routes["rest"], "array") . ";");
249
	}
250
251
	private static function initRestCache(&$config) {
252
		$restCache=[];
253
		$files=self::getControllersFiles($config);
254
		foreach ( $files as $file ) {
255
			if (is_file($file)) {
256
				$controller=ClassUtils::getClassFullNameFromFile($file);
257
				$parser=new RestControllerParser();
258
				$parser->parse($controller,$config);
259
				if($parser->isRest())
260
					$restCache=\array_merge($restCache,$parser->asArray());
261
			}
262
		}
263
		self::$cache->store("controllers/rest", "return " . JArray::asPhpArray($restCache, "array") . ";");
264
	}
265
266
	private static function register(AnnotationManager $annotationManager) {
267
		$annotationManager->registry=array_merge($annotationManager->registry, [
268
				'id' => 'micro\annotations\IdAnnotation',
269
				'manyToOne' => 'micro\annotations\ManyToOneAnnotation',
270
				'oneToMany' => 'micro\annotations\OneToManyAnnotation',
271
				'manyToMany' => 'micro\annotations\ManyToManyAnnotation',
272
				'joinColumn' => 'micro\annotations\JoinColumnAnnotation',
273
				'table' => 'micro\annotations\TableAnnotation',
274
				'transient' => 'micro\annotations\TransientAnnotation',
275
				'column' => 'micro\annotations\ColumnAnnotation',
276
				'joinTable' => 'micro\annotations\JoinTableAnnotation',
277
				'route' => 'micro\annotations\router\RouteAnnotation',
278
				'var' => 'mindplay\annotations\standard\VarAnnotation',
279
				'yuml' => 'micro\annotations\YumlAnnotation',
280
				'rest' => 'micro\annotations\rest\RestAnnotation',
281
				'authorization' => 'micro\annotations\rest\AuthorizationAnnotation'
282
		]);
283
	}
284
285
	public static function addAdminRoutes() {
286
		self::addControllerCache("micro\controllers\Admin");
287
	}
288
289
	public static function getRoutes() {
290
		$result=self::getControllerCache();
291
		return $result;
292
	}
293
294
	public static function getRestRoutes() {
295
		$result=[];
296
		$restCache=self::getRestCache();
297
		foreach ($restCache as $controllerClass=>$restAttributes){
298
			if(isset($restCache[$controllerClass])){
299
				$result[$controllerClass]=["restAttributes"=>$restAttributes,"routes"=>self::getControllerRoutes($controllerClass,true)];
300
			}
301
		}
302
		return $result;
303
	}
304
305
	public static function getControllerRoutes($controllerClass,$isRest=false){
306
		$result=[];
307
		$ctrlCache=self::getControllerCache($isRest);
308
		foreach ($ctrlCache as $path=>$routeAttributes){
309
			if(isset($routeAttributes["controller"])){
310
				if($routeAttributes["controller"]===$controllerClass){
311
					$result[$path]=$routeAttributes;
312
				}
313
			}else{
314
				$firstValue=reset($routeAttributes);
315
				if(isset($firstValue)&&isset($firstValue["controller"])){
316
					if($firstValue["controller"]===$controllerClass){
317
						$result[$path]=$routeAttributes;
318
					}
319
				}
320
			}
321
		}
322
		return $result;
323
	}
324
325 View Code Duplication
	public static function getRestResource($controllerClass){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
326
		$cache=self::getRestCache();
327
		if(isset($cache[$controllerClass])){
328
			return $cache[$controllerClass]["resource"];
329
		}
330
		return null;
331
	}
332
333 View Code Duplication
	public static function getRestCacheController($controllerClass){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
334
		$cache=self::getRestCache();
335
		if(isset($cache[$controllerClass])){
336
			return $cache[$controllerClass];
337
		}
338
		return null;
339
	}
340
341
342
	public static function addRoute($path, $controller, $action="index", $methods=null, $name="") {
343
		$controllerCache=self::getControllerCache();
344
		Router::addRouteToRoutes($controllerCache, $path, $controller, $action, $methods, $name);
345
		self::$cache->store("controllers/routes", "return " . JArray::asPhpArray($controllerCache, "array") . ";");
346
	}
347
}
348