Skip to content

Commit 11e3401

Browse files
authored
Merge pull request #246 from tmishutin/master
Merging into a development branch while I work through the code.
2 parents 17add5b + 62fdd9b commit 11e3401

File tree

8 files changed

+362
-37
lines changed

8 files changed

+362
-37
lines changed

src/CacheBelongsToMany.php

Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
<?php
2+
namespace GeneaLabs\LaravelModelCaching;
3+
4+
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
5+
use GeneaLabs\LaravelModelCaching\Traits\BuilderCaching;
6+
use GeneaLabs\LaravelModelCaching\Traits\Caching;
7+
use Fico7489\Laravel\Pivot\Traits\FiresPivotEventsTrait;
8+
9+
class CacheBelongsToMany extends BelongsToMany
10+
{
11+
use BuilderCaching,
12+
Caching,
13+
FiresPivotEventsTrait;
14+
15+
protected function makeCacheKey(
16+
array $columns = ['*'],
17+
$idColumn = null,
18+
string $keyDifferentiator = ''
19+
) : string {
20+
$eagerLoad = $this->eagerLoad ?? [];
21+
$model = $this->model ?? $this;
22+
$query = $this->query->getQuery() ?? app('db')->query();
23+
24+
return (new CacheKey($eagerLoad, $model, $query))
25+
->make($columns, $idColumn, $keyDifferentiator);
26+
}
27+
28+
public function avg($column)
29+
{
30+
if (! $this->isCachable()) {
31+
return parent::avg($column);
32+
}
33+
34+
$cacheKey = $this->makeCacheKey(["*"], null, "-avg_{$column}");
35+
36+
return $this->cachedValue(func_get_args(), $cacheKey);
37+
}
38+
39+
public function count($columns = "*")
40+
{
41+
if (! $this->isCachable()) {
42+
return parent::count($columns);
43+
}
44+
45+
$cacheKey = $this->makeCacheKey([$columns], null, "-count");
46+
47+
return $this->cachedValue(func_get_args(), $cacheKey);
48+
}
49+
50+
public function decrement($column, $amount = 1, array $extra = [])
51+
{
52+
$this->cache($this->makeCacheTags())
53+
->flush();
54+
55+
return parent::decrement($column, $amount, $extra);
56+
}
57+
58+
public function delete()
59+
{
60+
$this->cache($this->makeCacheTags())
61+
->flush();
62+
63+
return parent::delete();
64+
}
65+
66+
/**
67+
* @SuppressWarnings(PHPMD.ShortVariable)
68+
*/
69+
public function find($id, $columns = ["*"])
70+
{
71+
if (! $this->isCachable()) {
72+
return parent::find($id, $columns);
73+
}
74+
75+
$idKey = collect($id)
76+
->implode('_');
77+
$preStr = is_array($id)
78+
? 'find_list'
79+
: 'find';
80+
$cacheKey = $this->makeCacheKey($columns, null, "-{$preStr}_{$idKey}");
81+
82+
return $this->cachedValue(func_get_args(), $cacheKey);
83+
}
84+
85+
public function first($columns = ["*"])
86+
{
87+
if (! $this->isCachable()) {
88+
return parent::first($columns);
89+
}
90+
91+
if (! is_array($columns)) {
92+
$columns = [$columns];
93+
}
94+
95+
$cacheKey = $this->makeCacheKey($columns, null, "-first");
96+
97+
return $this->cachedValue(func_get_args(), $cacheKey);
98+
}
99+
100+
public function forceDelete()
101+
{
102+
$this->cache($this->makeCacheTags())
103+
->flush();
104+
105+
return parent::forceDelete();
106+
}
107+
108+
public function get($columns = ["*"])
109+
{
110+
if (! $this->isCachable()) {
111+
return parent::get($columns);
112+
}
113+
114+
$cacheKey = $this->makeCacheKey($columns);
115+
116+
return $this->cachedValue(func_get_args(), $cacheKey);
117+
}
118+
119+
public function increment($column, $amount = 1, array $extra = [])
120+
{
121+
$this->cache($this->makeCacheTags())
122+
->flush();
123+
124+
return parent::increment($column, $amount, $extra);
125+
}
126+
127+
public function inRandomOrder($seed = '')
128+
{
129+
$this->isCachable = false;
130+
131+
return parent::inRandomOrder($seed);
132+
}
133+
134+
public function insert(array $values)
135+
{
136+
$this->checkCooldownAndFlushAfterPersisting($this->model);
137+
138+
return parent::insert($values);
139+
}
140+
141+
public function max($column)
142+
{
143+
if (! $this->isCachable()) {
144+
return parent::max($column);
145+
}
146+
147+
$cacheKey = $this->makeCacheKey(["*"], null, "-max_{$column}");
148+
149+
return $this->cachedValue(func_get_args(), $cacheKey);
150+
}
151+
152+
public function min($column)
153+
{
154+
if (! $this->isCachable()) {
155+
return parent::min($column);
156+
}
157+
158+
$cacheKey = $this->makeCacheKey(["*"], null, "-min_{$column}");
159+
160+
return $this->cachedValue(func_get_args(), $cacheKey);
161+
}
162+
163+
public function paginate(
164+
$perPage = null,
165+
$columns = ["*"],
166+
$pageName = "page",
167+
$page = null
168+
) {
169+
if (! $this->isCachable()) {
170+
return parent::paginate($perPage, $columns, $pageName, $page);
171+
}
172+
173+
$page = app('request')->input($pageName)
174+
?: $page
175+
?: 1;
176+
177+
if (is_array($page)) {
178+
$page = $this->recursiveImplodeWithKey($page);
179+
}
180+
$cacheKey = $this->makeCacheKey($columns, null, "-paginate_by_{$perPage}_{$pageName}_{$page}");
181+
182+
return $this->cachedValue(func_get_args(), $cacheKey);
183+
}
184+
185+
public function getRelation($name)
186+
{
187+
$relation = parent::getRelation($name);
188+
189+
if (! $this->isCachable()
190+
&& is_a($relation->getQuery(), self::class)
191+
) {
192+
$relation->getQuery()->disableModelCaching();
193+
}
194+
195+
return $relation;
196+
}
197+
198+
protected function recursiveImplodeWithKey(array $items, string $glue = "_") : string
199+
{
200+
$result = "";
201+
202+
foreach ($items as $key => $value) {
203+
if (is_array($value)) {
204+
$result .= $key . $glue . $this->recursiveImplodeWithKey($value, $glue);
205+
206+
continue;
207+
}
208+
209+
$result .= $glue . $key . $glue . $value;
210+
}
211+
212+
return $result;
213+
}
214+
215+
public function pluck($column, $key = null)
216+
{
217+
if (! $this->isCachable()) {
218+
return parent::pluck($column, $key);
219+
}
220+
221+
$keyDifferentiator = "-pluck_{$column}" . ($key ? "_{$key}" : "");
222+
$cacheKey = $this->makeCacheKey([$column], null, $keyDifferentiator);
223+
224+
return $this->cachedValue(func_get_args(), $cacheKey);
225+
}
226+
227+
public function sum($column)
228+
{
229+
if (! $this->isCachable()) {
230+
return parent::sum($column);
231+
}
232+
233+
$cacheKey = $this->makeCacheKey(["*"], null, "-sum_{$column}");
234+
235+
return $this->cachedValue(func_get_args(), $cacheKey);
236+
}
237+
238+
public function update(array $values)
239+
{
240+
$this->checkCooldownAndFlushAfterPersisting($this->model);
241+
242+
return parent::update($values);
243+
}
244+
245+
public function value($column)
246+
{
247+
if (! $this->isCachable()) {
248+
return parent::value($column);
249+
}
250+
251+
$cacheKey = $this->makeCacheKey(["*"], null, "-value_{$column}");
252+
253+
return $this->cachedValue(func_get_args(), $cacheKey);
254+
}
255+
256+
public function cachedValue(array $arguments, string $cacheKey)
257+
{
258+
$method = debug_backtrace()[1]['function'];
259+
$cacheTags = $this->makeCacheTags();
260+
$hashedCacheKey = sha1($cacheKey);
261+
$result = $this->retrieveCachedValue(
262+
$arguments,
263+
$cacheKey,
264+
$cacheTags,
265+
$hashedCacheKey,
266+
$method
267+
);
268+
269+
return $this->preventHashCollision(
270+
$result,
271+
$arguments,
272+
$cacheKey,
273+
$cacheTags,
274+
$hashedCacheKey,
275+
$method
276+
);
277+
}
278+
279+
protected function preventHashCollision(
280+
array $result,
281+
array $arguments,
282+
string $cacheKey,
283+
array $cacheTags,
284+
string $hashedCacheKey,
285+
string $method
286+
) {
287+
if ($result["key"] === $cacheKey) {
288+
return $result["value"];
289+
}
290+
291+
$this->cache()
292+
->tags($cacheTags)
293+
->forget($hashedCacheKey);
294+
295+
return $this->retrieveCachedValue(
296+
$arguments,
297+
$cacheKey,
298+
$cacheTags,
299+
$hashedCacheKey,
300+
$method
301+
);
302+
}
303+
304+
protected function retrieveCachedValue(
305+
array $arguments,
306+
string $cacheKey,
307+
array $cacheTags,
308+
string $hashedCacheKey,
309+
string $method
310+
) {
311+
$this->checkCooldownAndRemoveIfExpired($this->getModel());
312+
313+
return $this->cache($cacheTags)
314+
->rememberForever(
315+
$hashedCacheKey,
316+
function () use ($arguments, $cacheKey, $method) {
317+
return [
318+
"key" => $cacheKey,
319+
"value" => parent::{$method}(...$arguments),
320+
];
321+
}
322+
);
323+
}
324+
}

src/CacheKey.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ class CacheKey
1919

2020
public function __construct(
2121
array $eagerLoad,
22-
Model $model,
23-
Builder $query
22+
$model,
23+
$query
2424
) {
2525
$this->eagerLoad = $eagerLoad;
2626
$this->model = $model;

src/CacheTags.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ class CacheTags
1616

1717
public function __construct(
1818
array $eagerLoad,
19-
Model $model,
20-
Builder $query
19+
$model,
20+
$query
2121
) {
2222
$this->eagerLoad = $eagerLoad;
2323
$this->model = $model;

src/Traits/Cachable.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
trait Cachable
66
{
7-
use PivotEventTrait;
8-
use Caching;
9-
use ModelCaching;
7+
use Caching,
8+
ModelCaching,
9+
PivotEventTrait {
10+
ModelCaching::newBelongsToMany insteadof PivotEventTrait;
11+
}
1012
}

src/Traits/CachePrefixing.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ protected function getCachePrefix() : string
1414

1515
protected function getDatabaseName() : string
1616
{
17-
return $this->model->getConnection()->getDatabaseName();
17+
return $this->query->getConnection()->getDatabaseName();
1818
}
1919

2020
protected function getConnectionName() : string

src/Traits/Caching.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ protected function makeCacheKey(
7979
protected function makeCacheTags() : array
8080
{
8181
$eagerLoad = $this->eagerLoad ?? [];
82-
$model = $this->model instanceof Model
83-
? $this->model
82+
$model = $this->getModel() instanceof Model
83+
? $this->getModel()
8484
: $this;
8585
$query = $this->query instanceof Builder
8686
? $this->query

0 commit comments

Comments
 (0)