Completed
Push — master ( 91f666...3f0f06 )
by Jared
01:52
created

Cacheable::getCacheTTL()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
/**
4
 * @author Jared King <[email protected]>
5
 *
6
 * @see http://jaredtking.com
7
 *
8
 * @copyright 2015 Jared King
9
 * @license MIT
10
 */
11
12
namespace Pulsar\Traits;
13
14
use Psr\Cache\CacheItemInterface;
15
use Psr\Cache\CacheItemPoolInterface;
16
17
/**
18
 * Adds a caching layer to a model that is queried before refresh() is called.
19
 */
20
trait Cacheable
21
{
22
    /**
23
     * @var CacheItemPoolInterface
24
     */
25
    private static $cachePool;
26
27
    /**
28
     * @var array
29
     */
30
    private static $cachePrefix = [];
31
32
    /**
33
     * @var CacheItemInterface
34
     */
35
    private $cacheItem;
36
37
    /**
38
     * Sets the default cache instance used by new models.
39
     */
40
    public static function setCachePool(CacheItemPoolInterface $pool): void
41
    {
42
        self::$cachePool = $pool;
43
    }
44
45
    /**
46
     * Clears the default cache instance for all models.
47
     */
48
    public static function clearCachePool(): void
49
    {
50
        self::$cachePool = null;
51
    }
52
53
    /**
54
     * Returns the cache instance.
55
     */
56
    public function getCachePool(): ?CacheItemPoolInterface
57
    {
58
        return self::$cachePool;
59
    }
60
61
    /**
62
     * Returns the cache TTL.
63
     */
64
    public function getCacheTTL(): ?int
65
    {
66
        return (property_exists($this, 'cacheTTL')) ? static::$cacheTTL : 86400; // default = 1 day
67
    }
68
69
    /**
70
     * Returns the cache key for this model.
71
     */
72
    public function getCacheKey(): string
73
    {
74
        $k = get_called_class();
75
        if (!isset(self::$cachePrefix[$k])) {
76
            self::$cachePrefix[$k] = 'models.'.strtolower(static::modelName());
77
        }
78
79
        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...
80
    }
81
82
    /**
83
     * Returns the cache item for this model.
84
     */
85
    public function getCacheItem(): ?CacheItemInterface
86
    {
87
        if (!self::$cachePool) {
88
            return null;
89
        }
90
91
        if (!$this->cacheItem) {
92
            $k = $this->getCacheKey();
93
            $this->cacheItem = self::$cachePool->getItem($k);
94
        }
95
96
        return $this->cacheItem;
97
    }
98
99
    public function refresh()
100
    {
101
        if (!$this->hasId()) {
0 ignored issues
show
Bug introduced by
It seems like hasId() 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...
102
            return $this;
103
        }
104
105
        if (self::$cachePool) {
106
            // Attempt to load the model from the caching layer first.
107
            // If that fails, then fall through to the data layer.
108
            $item = $this->getCacheItem();
109
110
            if ($item->isHit()) {
111
                // load the values directly instead of using
112
                // refreshWith() to prevent triggering another
113
                // cache call
114
                $this->_persisted = true;
0 ignored issues
show
Bug introduced by
The property _persisted 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...
115
                $this->_values = $item->get();
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...
116
117
                // clear any relationships
118
                $this->_relationships = [];
0 ignored issues
show
Bug introduced by
The property _relationships 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...
119
120
                return $this;
121
            }
122
        }
123
124
        return parent::refresh();
125
    }
126
127
    public function refreshWith(array $values)
128
    {
129
        return parent::refreshWith($values)->cache();
130
    }
131
132
    /**
133
     * Caches the entire model.
134
     *
135
     * @return $this
136
     */
137
    public function cache()
138
    {
139
        if (!self::$cachePool || 0 == count($this->_values)) {
140
            return $this;
141
        }
142
143
        // cache the local properties
144
        $item = $this->getCacheItem();
145
        $item->set($this->_values)
146
            ->expiresAfter($this->getCacheTTL());
147
148
        self::$cachePool->save($item);
149
150
        return $this;
151
    }
152
153
    public function clearCache()
154
    {
155
        if (self::$cachePool) {
156
            $k = $this->getCacheKey();
157
            self::$cachePool->deleteItem($k);
158
        }
159
160
        return parent::clearCache();
161
    }
162
}
163