Completed
Push — master ( f96361...9355d7 )
by Jared
02:34
created

Cacheable::refresh()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 39
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 39
rs 8.5806
cc 4
eloc 13
nc 4
nop 0
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();
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

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.

Loading history...
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();
0 ignored issues
show
Bug introduced by
It seems like id() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
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) {
0 ignored issues
show
Bug introduced by
The property _values 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;
Loading history...
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