Item::overrideIsHit()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace MatthiasMullie\Scrapbook\Psr6;
4
5
use DateTime;
6
use DateTimeInterface;
7
use Psr\Cache\CacheItemInterface;
8
9
/**
10
 * Representation of a cache item, both existing & non-existing (to be created).
11
 *
12
 * @author Matthias Mullie <[email protected]>
13
 * @copyright Copyright (c) 2014, Matthias Mullie. All rights reserved
14
 * @license LICENSE MIT
15
 */
16
class Item implements CacheItemInterface
17
{
18
    /**
19
     * @var string
20
     */
21
    protected $hash;
22
23
    /**
24
     * @var string
25
     */
26
    protected $key;
27
28
    /**
29
     * @var Repository
30
     */
31
    protected $repository;
32
33
    /**
34
     * @var mixed
35
     */
36
    protected $value;
37
38
    /**
39
     * @var int
40
     */
41
    protected $expire = 0;
42
43
    /**
44
     * @var bool
45
     */
46
    protected $isHit = null;
47
48
    /**
49
     * @var bool
50
     */
51
    protected $changed = false;
52
53
    /**
54
     * @param string $key
55
     */
56
    public function __construct($key, Repository $repository)
57
    {
58
        $this->key = $key;
59
60
        /*
61
         * Register this key (tied to this particular object) to the value
62
         * repository.
63
         *
64
         * If 1 key is requested multiple times, the value could be an object
65
         * that could be altered (by reference) and if all objects-for-same-key
66
         * reference that same value, all would've been changed (because all
67
         * would be that exact same value.)
68
         *
69
         * I'm using spl_object_hash to get a unique identifier linking $key to
70
         * this particular object, without using this object itself (I could use
71
         * SplObjectStorage.) If I stored this object, it wouldn't be destructed
72
         * when it's no longer needed, and I want it to destruct so I can free
73
         * up this value in the repository when it's no longer needed.
74
         */
75
        $this->repository = $repository;
76
        $this->hash = spl_object_hash($this);
77
        $this->repository->add($this->hash, $this->key);
78
    }
79
80
    /**
81
     * When this item is being killed, we should no longer keep its value around
82
     * in the repository. Free up some memory!
83
     */
84
    public function __destruct()
85
    {
86
        $this->repository->remove($this->hash);
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92
    public function getKey()
93
    {
94
        return $this->key;
95
    }
96
97
    /**
98
     * {@inheritdoc}
99
     */
100
    public function get()
101
    {
102
        // value was already set on this object, return that one!
103
        if (null !== $this->value) {
104
            return $this->value;
105
        }
106
107
        // sanity check
108
        if (!$this->isHit()) {
109
            return;
110
        }
111
112
        return $this->repository->get($this->hash);
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118
    public function set($value)
119
    {
120
        $this->value = $value;
121
        $this->changed = true;
122
123
        return $this;
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129
    public function isHit()
130
    {
131
        if (null !== $this->isHit) {
132
            return $this->isHit;
133
        }
134
135
        return $this->repository->exists($this->hash);
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141
    public function expiresAt($expiration)
142
    {
143
        // DateTimeInterface only exists since PHP>=5.5, also accept DateTime
144
        if ($expiration instanceof \DateTimeInterface || $expiration instanceof \DateTime) {
145
            // convert datetime to unix timestamp
146
            $this->expire = (int) $expiration->format('U');
147
            $this->changed = true;
148
        } elseif (null === $expiration) {
149
            $this->expire = 0;
150
            $this->changed = true;
151
        } else {
152
            $class = get_class($this);
153
            $type = gettype($expiration);
154
            $error = "Argument 1 passed to $class::expiresAt()  must be an ".
155
                "instance of DateTime or DateTimeImmutable, $type given";
156
157
            if (class_exists('\TypeError')) {
158
                throw new \TypeError($error);
159
            }
160
            trigger_error($error, E_USER_ERROR);
161
        }
162
163
        return $this;
164
    }
165
166
    /**
167
     * {@inheritdoc}
168
     */
169
    public function expiresAfter($time)
170
    {
171
        if ($time instanceof \DateInterval) {
172
            $expire = new \DateTime();
173
            $expire->add($time);
174
            // convert datetime to unix timestamp
175
            $this->expire = (int) $expire->format('U');
176
        } elseif (is_int($time)) {
177
            $this->expire = time() + $time;
178
        } elseif (is_null($time)) {
179
            // this is allowed, but just defaults to infinite
180
            $this->expire = 0;
181
        } else {
182
            throw new InvalidArgumentException('Invalid time: '.serialize($time).'. Must be integer or instance of DateInterval.');
183
        }
184
        $this->changed = true;
185
186
        return $this;
187
    }
188
189
    /**
190
     * Returns the set expiration time in integer form (as it's what
191
     * KeyValueStore expects).
192
     *
193
     * @return int
194
     */
195
    public function getExpiration()
196
    {
197
        return $this->expire;
198
    }
199
200
    /**
201
     * Returns true if the item is already expired, false otherwise.
202
     *
203
     * @return bool
204
     */
205
    public function isExpired()
206
    {
207
        $expire = $this->getExpiration();
208
209
        return 0 !== $expire && $expire < time();
210
    }
211
212
    /**
213
     * We'll want to know if this Item was altered (value or expiration date)
214
     * once we'll want to store it.
215
     *
216
     * @return bool
217
     */
218
    public function hasChanged()
219
    {
220
        return $this->changed;
221
    }
222
223
    /**
224
     * Allow isHit to be override, in case it's a value that is returned from
225
     * memory, when a value is being saved deferred.
226
     *
227
     * @param bool $isHit
228
     */
229
    public function overrideIsHit($isHit)
230
    {
231
        $this->isHit = $isHit;
232
    }
233
}
234