This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Rinvex\Cacheable; |
||
6 | |||
7 | use Closure; |
||
8 | use Illuminate\Database\Eloquent\Model; |
||
9 | use Illuminate\Database\Eloquent\Builder; |
||
10 | |||
11 | trait CacheableEloquent |
||
12 | { |
||
13 | /** |
||
14 | * Register an updated model event with the dispatcher. |
||
15 | * |
||
16 | * @param \Closure|string $callback |
||
17 | * |
||
18 | * @return void |
||
19 | */ |
||
20 | abstract public static function updated($callback); |
||
21 | |||
22 | /** |
||
23 | * Register a created model event with the dispatcher. |
||
24 | * |
||
25 | * @param \Closure|string $callback |
||
26 | * |
||
27 | * @return void |
||
28 | */ |
||
29 | abstract public static function created($callback); |
||
30 | |||
31 | /** |
||
32 | * Register a deleted model event with the dispatcher. |
||
33 | * |
||
34 | * @param \Closure|string $callback |
||
35 | * |
||
36 | * @return void |
||
37 | */ |
||
38 | abstract public static function deleted($callback); |
||
39 | |||
40 | /** |
||
41 | * Boot the cacheable eloquent trait for a model. |
||
42 | * |
||
43 | * @return void |
||
44 | */ |
||
45 | public static function bootCacheableEloquent(): void |
||
46 | { |
||
47 | static::updated(function (Model $cachedModel) { |
||
48 | ! $cachedModel->isCacheClearEnabled() || $cachedModel::forgetCache(); |
||
49 | }); |
||
50 | |||
51 | static::created(function (Model $cachedModel) { |
||
52 | ! $cachedModel->isCacheClearEnabled() || $cachedModel::forgetCache(); |
||
53 | }); |
||
54 | |||
55 | static::deleted(function (Model $cachedModel) { |
||
56 | ! $cachedModel->isCacheClearEnabled() || $cachedModel::forgetCache(); |
||
57 | }); |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * Store the given cache key for the given model by mimicking cache tags. |
||
62 | * |
||
63 | * @param string $modelName |
||
64 | * @param string $cacheKey |
||
65 | * |
||
66 | * @return void |
||
67 | */ |
||
68 | protected static function storeCacheKey(string $modelName, string $cacheKey): void |
||
69 | { |
||
70 | $keysFile = storage_path('framework/cache/data/rinvex.cacheable.json'); |
||
71 | $cacheKeys = static::getCacheKeys($keysFile); |
||
72 | |||
73 | if (! isset($cacheKeys[$modelName]) || ! in_array($cacheKey, $cacheKeys[$modelName])) { |
||
74 | $cacheKeys[$modelName][] = $cacheKey; |
||
75 | file_put_contents($keysFile, json_encode($cacheKeys)); |
||
76 | } |
||
77 | } |
||
78 | |||
79 | /** |
||
80 | * Get cache keys from the given file. |
||
81 | * |
||
82 | * @param string $file |
||
83 | * |
||
84 | * @return array |
||
85 | */ |
||
86 | protected static function getCacheKeys($file): array |
||
87 | { |
||
88 | if (! file_exists($file)) { |
||
89 | $dir = dirname($file); |
||
90 | is_dir($dir) || mkdir($dir); |
||
91 | file_put_contents($file, null); |
||
92 | } |
||
93 | |||
94 | return json_decode(file_get_contents($file), true) ?: []; |
||
95 | } |
||
96 | |||
97 | /** |
||
98 | * Flush cache keys of the given model by mimicking cache tags. |
||
99 | * |
||
100 | * @param string $modelName |
||
101 | * |
||
102 | * @return array |
||
103 | */ |
||
104 | protected static function flushCacheKeys(string $modelName): array |
||
105 | { |
||
106 | $flushedKeys = []; |
||
107 | $keysFile = storage_path('framework/cache/data/rinvex.cacheable.json'); |
||
108 | $cacheKeys = static::getCacheKeys($keysFile); |
||
109 | |||
110 | if (isset($cacheKeys[$modelName])) { |
||
111 | $flushedKeys = $cacheKeys[$modelName]; |
||
112 | |||
113 | unset($cacheKeys[$modelName]); |
||
114 | |||
115 | file_put_contents($keysFile, json_encode($cacheKeys)); |
||
116 | } |
||
117 | |||
118 | return $flushedKeys; |
||
119 | } |
||
120 | |||
121 | /** |
||
122 | * Set the model cache lifetime. |
||
123 | * |
||
124 | * @param int $cacheLifetime |
||
125 | * |
||
126 | * @return $this |
||
127 | */ |
||
128 | public function setCacheLifetime(int $cacheLifetime) |
||
129 | { |
||
130 | $this->cacheLifetime = $cacheLifetime; |
||
0 ignored issues
–
show
|
|||
131 | |||
132 | return $this; |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * Get the model cache lifetime. |
||
137 | * |
||
138 | * @return int |
||
139 | */ |
||
140 | public function getCacheLifetime(): int |
||
141 | { |
||
142 | return $this->cacheLifetime ?? -1; |
||
143 | } |
||
144 | |||
145 | /** |
||
146 | * Set the model cache driver. |
||
147 | * |
||
148 | * @param string $cacheDriver |
||
149 | * |
||
150 | * @return $this |
||
151 | */ |
||
152 | public function setCacheDriver($cacheDriver) |
||
153 | { |
||
154 | $this->cacheDriver = $cacheDriver; |
||
0 ignored issues
–
show
The property
cacheDriver does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
![]() |
|||
155 | |||
156 | return $this; |
||
157 | } |
||
158 | |||
159 | /** |
||
160 | * Get the model cache driver. |
||
161 | * |
||
162 | * @return string|null |
||
163 | */ |
||
164 | public function getCacheDriver(): ?string |
||
165 | { |
||
166 | return $this->cacheDriver ?? null; |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * Determine if model cache clear is enabled. |
||
171 | * |
||
172 | * @return bool |
||
173 | */ |
||
174 | public function isCacheClearEnabled(): bool |
||
175 | { |
||
176 | return $this->cacheClearEnabled ?? true; |
||
0 ignored issues
–
show
The property
cacheClearEnabled does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
![]() |
|||
177 | } |
||
178 | |||
179 | /** |
||
180 | * Forget the model cache. |
||
181 | * |
||
182 | * @return void |
||
183 | */ |
||
184 | public static function forgetCache() |
||
185 | { |
||
186 | static::fireCacheFlushEvent('cache.flushing'); |
||
187 | |||
188 | // Flush cache tags |
||
189 | if (method_exists(app('cache')->getStore(), 'tags')) { |
||
190 | app('cache')->tags(static::class)->flush(); |
||
191 | } else { |
||
192 | // Flush cache keys, then forget actual cache |
||
193 | foreach (static::flushCacheKeys(static::class) as $cacheKey) { |
||
194 | app('cache')->forget($cacheKey); |
||
195 | } |
||
196 | } |
||
197 | |||
198 | static::fireCacheFlushEvent('cache.flushed', false); |
||
199 | } |
||
200 | |||
201 | /** |
||
202 | * Fire the given event for the model. |
||
203 | * |
||
204 | * @param string $event |
||
205 | * @param bool $halt |
||
206 | * |
||
207 | * @return mixed |
||
208 | */ |
||
209 | protected static function fireCacheFlushEvent($event, $halt = true) |
||
210 | { |
||
211 | if (! isset(static::$dispatcher)) { |
||
212 | return true; |
||
213 | } |
||
214 | |||
215 | // We will append the names of the class to the event to distinguish it from |
||
216 | // other model events that are fired, allowing us to listen on each model |
||
217 | // event set individually instead of catching event for all the models. |
||
218 | $event = "eloquent.{$event}: ".static::class; |
||
219 | |||
220 | $method = $halt ? 'until' : 'dispatch'; |
||
221 | |||
222 | return static::$dispatcher->{$method}($event, static::class); |
||
223 | } |
||
224 | |||
225 | /** |
||
226 | * Reset cached model to its defaults. |
||
227 | * |
||
228 | * @return $this |
||
229 | */ |
||
230 | public function resetCacheConfig() |
||
231 | { |
||
232 | ! $this->cacheDriver || $this->cacheDriver = null; |
||
233 | ! $this->cacheLifetime || $this->cacheLifetime = -1; |
||
234 | |||
235 | return $this; |
||
236 | } |
||
237 | |||
238 | /** |
||
239 | * Generate unique cache key. |
||
240 | * |
||
241 | * @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder $builder |
||
242 | * @param array $columns |
||
243 | * |
||
244 | * @return string |
||
245 | */ |
||
246 | protected function generateCacheKey($builder, array $columns): string |
||
247 | { |
||
248 | $query = $builder instanceof Builder ? $builder->getQuery() : $builder; |
||
249 | $vars = [ |
||
250 | 'aggregate' => $query->aggregate, |
||
251 | 'columns' => $query->columns, |
||
252 | 'distinct' => $query->distinct, |
||
253 | 'from' => $query->from, |
||
254 | 'joins' => $query->joins, |
||
255 | 'wheres' => $query->wheres, |
||
256 | 'groups' => $query->groups, |
||
257 | 'havings' => $query->havings, |
||
258 | 'orders' => $query->orders, |
||
259 | 'limit' => $query->limit, |
||
260 | 'offset' => $query->offset, |
||
261 | 'unions' => $query->unions, |
||
262 | 'unionLimit' => $query->unionLimit, |
||
263 | 'unionOffset' => $query->unionOffset, |
||
264 | 'unionOrders' => $query->unionOrders, |
||
265 | 'lock' => $query->lock, |
||
266 | ]; |
||
267 | |||
268 | return md5(json_encode([ |
||
269 | $vars, |
||
270 | $columns, |
||
271 | static::class, |
||
272 | $this->getCacheDriver(), |
||
273 | $this->getCacheLifetime(), |
||
274 | $builder instanceof Builder ? $builder->getEagerLoads() : null, |
||
275 | $builder->getBindings(), |
||
0 ignored issues
–
show
The method
getBindings does only exist in Illuminate\Database\Query\Builder , but not in Illuminate\Database\Eloquent\Builder .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
276 | $builder->toSql(), |
||
0 ignored issues
–
show
The method
toSql does only exist in Illuminate\Database\Query\Builder , but not in Illuminate\Database\Eloquent\Builder .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
277 | ])); |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * Cache given callback. |
||
282 | * |
||
283 | * @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder $builder |
||
284 | * @param array $columns |
||
285 | * @param \Closure $closure |
||
286 | * |
||
287 | * @return mixed |
||
288 | */ |
||
289 | public function cacheQuery($builder, array $columns, Closure $closure) |
||
290 | { |
||
291 | $modelName = $this->getMorphClass(); |
||
292 | $lifetime = $this->getCacheLifetime(); |
||
293 | $cacheKey = $this->generateCacheKey($builder, $columns); |
||
294 | |||
295 | // Switch cache driver on runtime |
||
296 | if ($driver = $this->getCacheDriver()) { |
||
297 | app('cache')->setDefaultDriver($driver); |
||
298 | } |
||
299 | |||
300 | // We need cache tags, check if default driver supports it |
||
301 | if (method_exists(app('cache')->getStore(), 'tags')) { |
||
302 | $result = $lifetime === -1 ? app('cache')->tags($modelName)->rememberForever($cacheKey, $closure) : app('cache')->tags($modelName)->remember($cacheKey, $lifetime, $closure); |
||
303 | |||
304 | return $result; |
||
305 | } |
||
306 | |||
307 | $result = $lifetime === -1 ? app('cache')->rememberForever($cacheKey, $closure) : app('cache')->remember($cacheKey, $lifetime, $closure); |
||
308 | |||
309 | // Default cache driver doesn't support tags, let's do it manually |
||
310 | static::storeCacheKey($modelName, $cacheKey); |
||
311 | |||
312 | // We're done, let's clean up! |
||
313 | $this->resetCacheConfig(); |
||
314 | |||
315 | return $result; |
||
316 | } |
||
317 | |||
318 | /** |
||
319 | * Create a new Eloquent query builder for the model. |
||
320 | * |
||
321 | * @param \Illuminate\Database\Query\Builder $query |
||
322 | * |
||
323 | * @return \Illuminate\Database\Eloquent\Builder|static |
||
324 | */ |
||
325 | public function newEloquentBuilder($query) |
||
326 | { |
||
327 | return new EloquentBuilder($query); |
||
328 | } |
||
329 | } |
||
330 |
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: