1 | <?php |
||||
2 | /** |
||||
3 | * Created by PhpStorm. |
||||
4 | * User: arthur |
||||
5 | * Date: 11.10.18 |
||||
6 | * Time: 14:11. |
||||
7 | */ |
||||
8 | |||||
9 | namespace Foundation\Cache; |
||||
10 | |||||
11 | use Cache; |
||||
12 | use Foundation\Exceptions\Exception; |
||||
13 | use Illuminate\Support\Facades\Redis; |
||||
14 | |||||
15 | class ModelCache |
||||
16 | { |
||||
17 | protected $model; |
||||
18 | |||||
19 | protected $cacheTime; |
||||
20 | |||||
21 | /* Unique secondary indexes */ |
||||
22 | protected $secondaryIndexes; |
||||
23 | |||||
24 | /** |
||||
25 | * ModelCache constructor. |
||||
26 | */ |
||||
27 | 1 | public function __construct(string $model, array $indexes = [], $cacheTime = null) |
|||
28 | { |
||||
29 | 1 | $this->model = $model; |
|||
30 | 1 | $this->secondaryIndexes = $indexes; |
|||
31 | 1 | $this->cacheTime = $cacheTime; |
|||
32 | 1 | } |
|||
33 | |||||
34 | /** |
||||
35 | * @param $id |
||||
36 | * @param string $modelClass |
||||
37 | * |
||||
38 | * @return \Eloquent |
||||
39 | */ |
||||
40 | public function find($id, $eagerLoad = true) |
||||
41 | { |
||||
42 | $model = Cache::get(self::getCacheName($id)); |
||||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||||
43 | |||||
44 | if ($eagerLoad) { |
||||
45 | return $this->eagerLoadRelations($model); |
||||
46 | } |
||||
47 | |||||
48 | return $model; |
||||
49 | } |
||||
50 | |||||
51 | public function findBy(string $index, $key, $eagerLoad = true) |
||||
52 | { |
||||
53 | if (! in_array($index, $this->secondaryIndexes)) { |
||||
54 | throw new Exception('provided index does not exist as secondary index on the cache model'); |
||||
55 | } |
||||
56 | $modelId = $this->findSecondaryIndex($index, $key); |
||||
57 | |||||
58 | if ($modelId === null) { |
||||
59 | $model = ($this->model)::where($index, $key)->first(); |
||||
60 | if ($model !== null) { |
||||
61 | $this->store($model); |
||||
62 | } |
||||
63 | |||||
64 | return $model; |
||||
65 | } |
||||
66 | |||||
67 | return $this->find($modelId, $eagerLoad); |
||||
68 | } |
||||
69 | |||||
70 | protected function eagerLoadRelations($model) |
||||
71 | { |
||||
72 | if ($model !== null) { |
||||
73 | return $model::eagerLoadRelations([$model])[0]; |
||||
74 | } |
||||
75 | } |
||||
76 | |||||
77 | protected function findSecondaryIndex(string $index, $key) |
||||
78 | { |
||||
79 | return Cache::get($this->getCacheName($key, $index)); |
||||
80 | } |
||||
81 | |||||
82 | /** |
||||
83 | * @param string |
||||
84 | */ |
||||
85 | 1 | public function getCacheName($id, string $index = 'id') |
|||
86 | { |
||||
87 | 1 | return config('model.cache_prefix').':'.strtolower(get_short_class_name($this->model)).':'.$index.':'.$id; |
|||
88 | } |
||||
89 | |||||
90 | /** |
||||
91 | * @return \Illuminate\Config\Repository|mixed |
||||
92 | */ |
||||
93 | 1 | public function getCacheTime() |
|||
94 | { |
||||
95 | 1 | return $this->cacheTime ?? config('model.cache_time'); |
|||
96 | } |
||||
97 | |||||
98 | /** |
||||
99 | * @param \Eloquent $model |
||||
100 | */ |
||||
101 | 1 | public function store($model) |
|||
102 | { |
||||
103 | 1 | Cache::put($this->getCacheName($model->getKey()), $model->newFromBuilder($model->getAttributes()), $this->getCacheTime()); |
|||
0 ignored issues
–
show
It seems like
$this->getCacheTime() can also be of type Illuminate\Config\Repository ; however, parameter $ttl of Illuminate\Support\Facades\Cache::put() does only seem to accept DateInterval|DateTimeInterface|integer , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
104 | 1 | $this->storeSecondaryIndexReferences($model); |
|||
105 | 1 | } |
|||
106 | |||||
107 | /** |
||||
108 | * @param string $index |
||||
109 | * @param \Eloquent $model |
||||
110 | */ |
||||
111 | 1 | protected function storeSecondaryIndexReferences($model) |
|||
112 | { |
||||
113 | 1 | foreach ($this->secondaryIndexes as $index) { |
|||
114 | 1 | $indexValue = $model->$index; |
|||
115 | 1 | if ($indexValue !== null) { |
|||
116 | 1 | Cache::put($this->getCacheName($indexValue, $index), $model->getKey(), $this->getCacheTime()); |
|||
0 ignored issues
–
show
It seems like
$this->getCacheTime() can also be of type Illuminate\Config\Repository ; however, parameter $ttl of Illuminate\Support\Facades\Cache::put() does only seem to accept DateInterval|DateTimeInterface|integer , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
117 | } |
||||
118 | } |
||||
119 | 1 | } |
|||
120 | |||||
121 | /** |
||||
122 | * @param $id |
||||
123 | * @param string $modelClass |
||||
124 | * |
||||
125 | * @return bool |
||||
126 | */ |
||||
127 | public function remove($id) |
||||
128 | { |
||||
129 | return Cache::forget($this->getCacheName($id)); |
||||
130 | } |
||||
131 | |||||
132 | public static function clearAll() |
||||
133 | { |
||||
134 | $pattern = config('model.cache_prefix'); |
||||
135 | self::deleteWithPrefix($pattern); |
||||
136 | } |
||||
137 | |||||
138 | /** |
||||
139 | * @param $prefix |
||||
140 | * |
||||
141 | * @throws Exception |
||||
142 | */ |
||||
143 | private static function deleteWithPrefix($prefix) |
||||
144 | { |
||||
145 | $redis = self::getCacheConnection(); |
||||
146 | $keyPattern = Cache::getPrefix().$prefix.'*'; |
||||
0 ignored issues
–
show
The call to
Illuminate\Cache\CacheManager::getPrefix() has too few arguments starting with config .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has less 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. Please note the @ignore annotation hint above. ![]() |
|||||
147 | $keys = $redis->keys($keyPattern); |
||||
148 | $redis->delete($keys); |
||||
149 | } |
||||
150 | |||||
151 | /** |
||||
152 | * @throws Exception |
||||
153 | * |
||||
154 | * @return \Illuminate\Redis\Connections\Connection |
||||
155 | */ |
||||
156 | private static function getCacheConnection() |
||||
157 | { |
||||
158 | if (config('cache.default') === 'redis') { |
||||
159 | return Redis::connection('cache'); |
||||
160 | } |
||||
161 | |||||
162 | throw new Exception('This action is only possible with redis as cache driver'); |
||||
163 | } |
||||
164 | |||||
165 | /** |
||||
166 | * @param $modelClass |
||||
167 | * |
||||
168 | * @throws Exception |
||||
169 | */ |
||||
170 | public function clearModelCache() |
||||
171 | { |
||||
172 | $pattern = config('model.cache_prefix').':'.strtolower(get_short_class_name($this->model)); |
||||
173 | self::deleteWithPrefix($pattern); |
||||
174 | } |
||||
175 | |||||
176 | public function enabled(): bool |
||||
177 | { |
||||
178 | return (bool) config('model.caching'); |
||||
179 | } |
||||
180 | } |
||||
181 |