|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* @author Jared King <[email protected]> |
|
5
|
|
|
* |
|
6
|
|
|
* @link http://jaredtking.com |
|
7
|
|
|
* |
|
8
|
|
|
* @copyright 2015 Jared King |
|
9
|
|
|
* @license MIT |
|
10
|
|
|
*/ |
|
11
|
|
|
namespace Pulsar; |
|
12
|
|
|
|
|
13
|
|
|
use Stash\Item; |
|
14
|
|
|
|
|
15
|
|
|
trait Cacheable |
|
16
|
|
|
{ |
|
17
|
|
|
/** |
|
18
|
|
|
* @staticvar \Stash\Pool |
|
19
|
|
|
*/ |
|
20
|
|
|
private static $cachePool; |
|
21
|
|
|
|
|
22
|
|
|
/** |
|
23
|
|
|
* @staticvar array |
|
24
|
|
|
*/ |
|
25
|
|
|
private static $cachePrefix = []; |
|
26
|
|
|
|
|
27
|
|
|
/** |
|
28
|
|
|
* @var \Stash\Item |
|
29
|
|
|
*/ |
|
30
|
|
|
private $_cacheItem; |
|
31
|
|
|
|
|
32
|
|
|
public static function find($id) |
|
33
|
|
|
{ |
|
34
|
|
|
if (self::$cachePool) { |
|
35
|
|
|
// Attempt to load the model from the caching layer first. |
|
36
|
|
|
// If that fails, then fall through to the data layer. |
|
37
|
|
|
$model = static::buildFromIds($id); |
|
38
|
|
|
$item = $model->getCacheItem(); |
|
39
|
|
|
$values = $item->get(); |
|
40
|
|
|
|
|
41
|
|
|
if (!$item->isMiss()) { |
|
42
|
|
|
// load the values directly instead of using |
|
43
|
|
|
// refreshWith() to prevent triggering another |
|
44
|
|
|
// cache call |
|
45
|
|
|
$model->_exists = true; |
|
46
|
|
|
$model->_values = $values; |
|
47
|
|
|
|
|
48
|
|
|
return $model; |
|
49
|
|
|
} |
|
50
|
|
|
|
|
51
|
|
|
// If the cache was a miss, then lock down the |
|
52
|
|
|
// cache item, attempt to load the model from |
|
53
|
|
|
// the database, and then update the cache. |
|
54
|
|
|
// Stash calls this Stampede Protection. |
|
55
|
|
|
|
|
56
|
|
|
// NOTE Currently disabling Stampede Protection |
|
57
|
|
|
// because there is no way to unlock the item |
|
58
|
|
|
// if we fail to load the model, whether |
|
59
|
|
|
// due to a DB failure or non-existent record. |
|
60
|
|
|
// This is problematic with the Redis driver |
|
61
|
|
|
// because it will attempt to unlock the cache |
|
62
|
|
|
// item once the script shuts down and the |
|
63
|
|
|
// redis connection has closed. |
|
64
|
|
|
// $item->lock(); |
|
|
|
|
|
|
65
|
|
|
} |
|
66
|
|
|
|
|
67
|
|
|
return parent::find($id); |
|
68
|
|
|
} |
|
69
|
|
|
|
|
70
|
|
|
public function refreshWith(array $values) |
|
71
|
|
|
{ |
|
72
|
|
|
return parent::refreshWith($values)->cache(); |
|
73
|
|
|
} |
|
74
|
|
|
|
|
75
|
|
|
public function clearCache() |
|
76
|
|
|
{ |
|
77
|
|
|
if (self::$cachePool) { |
|
78
|
|
|
$this->getCacheItem()->clear(); |
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
|
|
return parent::clearCache(); |
|
82
|
|
|
} |
|
83
|
|
|
|
|
84
|
|
|
/** |
|
85
|
|
|
* Sets the default cache instance used by new models. |
|
86
|
|
|
* |
|
87
|
|
|
* @param \Stash\Pool $pool |
|
88
|
|
|
*/ |
|
89
|
|
|
public static function setCachePool($pool) |
|
90
|
|
|
{ |
|
91
|
|
|
self::$cachePool = $pool; |
|
92
|
|
|
} |
|
93
|
|
|
|
|
94
|
|
|
/** |
|
95
|
|
|
* Returns the cache instance. |
|
96
|
|
|
* |
|
97
|
|
|
* @return \Stash\Pool|false |
|
98
|
|
|
*/ |
|
99
|
|
|
public function getCachePool() |
|
100
|
|
|
{ |
|
101
|
|
|
return self::$cachePool; |
|
102
|
|
|
} |
|
103
|
|
|
|
|
104
|
|
|
/** |
|
105
|
|
|
* Returns the cache TTL. |
|
106
|
|
|
* |
|
107
|
|
|
* @return int|null |
|
108
|
|
|
*/ |
|
109
|
|
|
public function getCacheTTL() |
|
110
|
|
|
{ |
|
111
|
|
|
return (property_exists($this, 'cacheTTL')) ? static::$cacheTTL : 86400; // default = 1 day |
|
112
|
|
|
} |
|
113
|
|
|
|
|
114
|
|
|
/** |
|
115
|
|
|
* Returns the cache key for this model. |
|
116
|
|
|
* |
|
117
|
|
|
* @return string |
|
118
|
|
|
*/ |
|
119
|
|
|
public function getCacheKey() |
|
120
|
|
|
{ |
|
121
|
|
|
$k = get_called_class(); |
|
122
|
|
|
if (!isset(self::$cachePrefix[$k])) { |
|
123
|
|
|
self::$cachePrefix[$k] = 'models/'.strtolower(static::modelName()); |
|
124
|
|
|
} |
|
125
|
|
|
|
|
126
|
|
|
return self::$cachePrefix[$k].'/'.$this->id(); |
|
|
|
|
|
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
/** |
|
130
|
|
|
* Returns the cache item for this model. |
|
131
|
|
|
* |
|
132
|
|
|
* @return \Stash\Item|null |
|
133
|
|
|
*/ |
|
134
|
|
|
public function getCacheItem() |
|
135
|
|
|
{ |
|
136
|
|
|
if (!self::$cachePool) { |
|
137
|
|
|
return; |
|
138
|
|
|
} |
|
139
|
|
|
|
|
140
|
|
|
if (!$this->_cacheItem) { |
|
141
|
|
|
$this->_cacheItem = self::$cachePool->getItem($this->getCacheKey()); |
|
142
|
|
|
} |
|
143
|
|
|
|
|
144
|
|
|
return $this->_cacheItem; |
|
145
|
|
|
} |
|
146
|
|
|
|
|
147
|
|
|
/** |
|
148
|
|
|
* Caches the entire model. |
|
149
|
|
|
* |
|
150
|
|
|
* @return self |
|
151
|
|
|
*/ |
|
152
|
|
|
public function cache() |
|
153
|
|
|
{ |
|
154
|
|
|
if (!self::$cachePool || count($this->_values) == 0) { |
|
|
|
|
|
|
155
|
|
|
return $this; |
|
156
|
|
|
} |
|
157
|
|
|
|
|
158
|
|
|
// cache the local properties |
|
159
|
|
|
$this->getCacheItem() |
|
160
|
|
|
->set($this->_values, $this->getCacheTTL()); |
|
161
|
|
|
|
|
162
|
|
|
return $this; |
|
163
|
|
|
} |
|
164
|
|
|
} |
|
165
|
|
|
|
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.