Completed
Pull Request — master (#15)
by Robbert
02:28
created

Store::set()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2.0055

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 13
ccs 8
cts 9
cp 0.8889
rs 9.4286
cc 2
eloc 9
nc 2
nop 3
crap 2.0055
1
<?php
2
3
/*
4
 * This file is part of the Ariadne Component Library.
5
 *
6
 * (c) Muze <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace arc\cache;
13
14
/**
15
 * This class implements a generic cache store based on the \arc\cache\StoreInterface.
16
 * It requires an instance of a storage class, e.g. \arc\cache\FileStore.
17
 * You can create a default cache store through the \arc\cache::create factory method.
18
 */
19
class Store implements StoreInterface
20
{
21
    private $timeout = 7200;
22
    private $storage = null;
23
    private $currentPath = null;
24
25
    /**
26
     * @param object     $storage     An object implementing the methods in \arc\cache\FileStore
27
     * @param int|string $timeout     Default cache timeout in seconds or a string parseable by strtotime
28
     * @param null       $currentPath The current path in the cache store.
29
     */
30 4
    public function __construct($storage, $timeout = 7200, $currentPath = null)
31
    {
32 4
        $this->timeout = $this->getTimeout( $timeout );
33 4
        $this->currentPath = $currentPath ?: '/';
34 4
        $this->storage = $storage->cd( $this->currentPath );
35 4
    }
36
37
    /* \arc\KeyValueStoreInterface */
38
39
    /**
40
     *	Part of the KeyValueStoreInterface, this function will return the value for the given name
41
     *  but only if it is still fresh. Identical to getIfFresh().
42
     *  @param string $name
43
     *  @return mixed value
44
     */
45
    public function getVar($name)
46
    {
47
        return $this->getIfFresh( $name );
48
    }
49
50
    /**
51
     *	Part of the KeyValueStoreInterface, this function will set a value for the given name
52
     *  Identical to set(). It will use the default timeout set when the cache store was constructed.
53
     *  @param string $name
54
     *  @param string $value
55
     *  @return mixed value
56
     */
57 1
    public function putVar($name, $value)
58
    {
59 1
        $this->set( $name, $value, $this->timeout );
60 1
    }
61
62
    /* PathTreeInterface */
63
64
    /**
65
     *	Part of the PathTreeInterface, this function will return a new cache store with the new path.
66
     *  @param string $path
67
     *  @return \arc\cache\Store
68
     */
69 2
    public function cd($path)
70
    {
71 2
        $path = \arc\path::collapse( $path, $this->currentPath );
72
73 2
        return new Store( $this->storage, $this->timeout, $path);
74
    }
75
76
    /**
77
     *	Part of the PathTreeInterface, this function will return a list of items in the cache store.
78
     *  @return array
79
     */
80
    public function ls()
81
    {
82
        return $this->storage->ls();
83
    }
84
85
    /* StoreInterface */
86
87
    /**
88
     *	This method will return the cached image with the given name, if it is still fresh, or
89
     *  if not call the callable method to generate a new value, store it and return that.
90
     *  @param string $name
91
     *  @param callable $calculateCallback
92
     *  @return mixed
93
     */
94 1
    public function cache($name, $calculateCallback)
95
    {
96 1
        if ($this->isFresh( $name )) {
97
            return $this->getVar( $name );
98
        } else {
99 1
            $result = call_user_func( $calculateCallback );
100 1
            $this->putVar( $name, $result );
101
102 1
            return $result;
103
        }
104
    }
105
106
    /**
107
     * This method returns a new cache store with the given timeout. In all other respects
108
     * the new store is a copy of the current one.
109
     * @param mixed $timeout Either a timestamp (int) or a string parseable by strtotime.
110
     * @return \arc\cache\Store
111
     */
112
    public function timeout($timeout)
113
    {
114
        return new Store( $this->storage, $timeout, $this->currentPath );
115
    }
116
117
    /**
118
     *	This method returns the value stored for the given name - even if no longer fresh -
119
     *  or null if there is no value stored.
120
     *  @param string $name
121
     *  @return mixed
122
     */
123 3
    public function get($name)
124
    {
125 3
        $content = $this->storage->getVar( $name );
126 3
        if ($content) {
127 3
            return unserialize( $content );
128
        } else {
129 1
            return null;
130
        }
131
    }
132
133
    /**
134
     *	This method stores a name - value pair, with either a given timeout or the default
135
     *  timeout for this Store.
136
     *  @param string $name
137
     *  @param mixed $value
138
     *  @param mixed $timeout Either a timestamp (int) or a string parseable by strtotime.
139
     *  @return bool true for successfull storage, false for failure.
140
     */
141 5
    public function set($name, $value, $timeout = null)
142
    {
143 5
        $timeout = $this->getTimeout( $timeout );
144 5
        $value = serialize( $value );
145 5
        if ($this->storage->putVar( $name, $value )) {
146 5
            $result = $this->storage->setInfo( $name, array( 'mtime' => $timeout ) );
147 5
        } else {
148
            $result = false;
149
        }
150 5
        $this->unlock( $name );
151
152 5
        return $result;
153
    }
154
155
    /**
156
     *	This method returns metadata for the given name.
157
     *  @param string $name
158
     *  @return array
159
     */
160 3
    public function getInfo($name)
161
    {
162 3
        return $this->storage->getInfo( $name );
163
    }
164
165
    /**
166
     *	This method checks if the value for the given name is fresh for at least the time
167
     *  passed as the freshness param.
168
     *  @param string $name
169
     *  @param mixed $freshness either a unix timestamp or a string parseable by strtotime
170
     *  @return bool
171
     */
172 3
    public function isFresh($name, $freshness = 0)
173
    {
174 3
        $freshness = $this->getTimeout( $freshness );
175 3
        $info = $this->getInfo( $name );
176 3
        if ($info && $info['mtime'] >= $freshness) {
177 1
            return true;
178
        } else {
179 3
            return false;
180
        }
181
    }
182
183
    /**
184
     *  This method returns the value associated with the given name if it is still fresh,
185
     *  otherwise it will return null. You can set a minimum freshness time.
186
     *  @param string $name
187
     *  @param mixed $freshness either a unix timestamp or a string parseable by strtotime
188
     *  @return mixed
189
     */
190 2
    public function getIfFresh($name, $freshness = 0)
191
    {
192 2
        if ($this->isFresh($name, $freshness)){
193 1
            return $this->get( $name );
194
        } else {
195 2
            return null;
196
        }
197
    }
198
199
    /**
200
     *  This method locks the store for the given name. If blocking is set to true, other
201
     *  processes are blocked from reading any current value. Returns true if the lock
202
     *  succeeded.
203
     *  @param string $name
204
     *  @param bool $blocking
205
     *  @return bool
206
     */
207 2
    public function lock($name, $blocking = false)
208
    {
209 2
        return $this->storage->lock( $name, $blocking );
210
    }
211
212
    /**
213
     *  This method waits for the store to be unlocked for the given name.
214
     *  @param string $name
215
     */
216
    public function wait($name)
217
    {
218
        if ($this->lock( $name, true)) {
219
            return $this->unlock($name);
220
        } else {
221
            return false;
222
        }
223
    }
224
225
    /**
226
     *  This method unlocks the store for the given name. Returns true on succes,
227
     *  false on failure.
228
     *  @param string $name
229
     *  @return bool
230
     */
231 5
    public function unlock($name)
232
    {
233 5
        return $this->storage->unlock( $name );
234
    }
235
236
    /**
237
     *  This method removes any value for a given name from the store.
238
     *  @param string $name
239
     *  @return bool
240
     */
241 1
    public function remove($name)
242
    {
243 1
        return $this->storage->remove( $name );
244
    }
245
246
    /**
247
     *  This method removes any value for a given name from the store. If the name
248
     *  is a path, it will also remove any values for any child paths.
249
     *  @param string $name
250
     *  @return bool
251
     */
252 2
    public function purge($name = null)
253
    {
254 2
        return $this->storage->purge( $name );
255
    }
256
257 5
    private function getTimeout($timeout)
258
    {
259 5
        if (!isset( $timeout )) {
260 2
            $timeout = time();
261 5
        } elseif (is_string( $timeout )) {
262
            $timeout = strtotime( $timeout );
263
        } else {
264 5
            $timeout = time() + $timeout;
265
        }
266
267 5
        return $timeout;
268
    }
269
}
270