Completed
Push — 2.0 ( aed067...b26523 )
by Marco
04:31
created

Apc::get()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 43
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6.0087

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 43
ccs 15
cts 16
cp 0.9375
rs 8.439
cc 6
eloc 16
nc 7
nop 1
crap 6.0087
1
<?php namespace Comodojo\Cache\Providers;
2
3
use \Comodojo\Cache\Providers\AbstractProvider;
4
use \Psr\Log\LoggerInterface;
5
use \Comodojo\Exception\CacheException;
6
use \Exception;
7
8
/**
9
 * Apc/Apcu cache class
10
 *
11
 * @package     Comodojo Spare Parts
12
 * @author      Marco Giovinazzi <[email protected]>
13
 * @license     MIT
14
 *
15
 * LICENSE:
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
 * THE SOFTWARE.
24
 */
25
26
class Apc extends AbstractProvider {
27
28
    private static $is_apcu = false;
29
30
    /**
31
     * Class constructor
32
     *
33
     * @throws \Comodojo\Exception\CacheException
34
     */
35 18
    public function __construct(LoggerInterface $logger = null) {
36
37 18
        parent::__construct($logger);
38
39 18
        if ( self::getApcStatus() === false ) {
40
41
            $this->logger->error("Apc extension not available, disabling ApcProvider administratively");
42
43
            $this->disable();
44
45
        } else {
46
47
            // In cli, apcu SHOULD NOT use the request time for cache retrieve/invalidation.
48
            // This is because in cli the request time is allways the same.
49 18
            if ( php_sapi_name() === 'cli' ) {
50 18
                ini_set('apc.use_request_time',0);
51 18
            }
52
53
        }
54
55 18
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60 32
    public function set($name, $data, $ttl = null) {
61
62 32
        if ( empty($name) ) throw new CacheException("Name of object cannot be empty");
63
64 32
        if ( is_null($data) ) throw new CacheException("Object content cannot be null");
65
66
        // simply return false if cache is disabled
67 32
        if ( !$this->isEnabled() ) return false;
68
69
        // reset error state, just in case
70 32
        $this->resetErrorState();
71
72
        try {
73
74 32
            $this->setTtl($ttl);
75
76 32
            $namespace = $this->getNamespaceKey();
77
78 32
            if ( $namespace === false ) $namespace = $this->setNamespaceKey();
79
80
            // if namespace is still false, raise an error and exit gracefully
81 32
            if ( $namespace === false ) {
82
83
                $this->logger->error("Error writing cache (APC), exiting gracefully");
84
85
                $this->setErrorState("Error writing cache (APC)");
86
87
                return false;
88
89
            }
90
91 32
            $shadowName = $namespace."-".md5($name);
92
93 32
            $shadowTtl = $this->ttl;
94
95 32
            if ( self::$is_apcu ) {
96
97 32
                $return = apcu_store($shadowName, $data, $shadowTtl);
98
99 32
            } else {
100
101
                $return = apc_store($shadowName, $data, $shadowTtl);
102
103
            }
104
105 32
            if ( $return === false ) {
106
107
                $this->logger->error("Error writing cache (APC), exiting gracefully");
108
109
                $this->setErrorState("Error writing cache (APC)");
110
111
            }
112
113 32
        } catch (CacheException $ce) {
114
115
            throw $ce;
116
117
        }
118
119 32
        return $return;
120
121
    }
122
123
    /**
124
     * {@inheritdoc}
125
     */
126 26
    public function get($name) {
127
128 26
        if ( empty($name) ) throw new CacheException("Name of object cannot be empty");
129
130 26
        if ( !$this->isEnabled() ) return null;
131
132 26
        $this->resetErrorState();
133
134 26
        $namespace = $this->getNamespaceKey();
135
136 26
        if ( $namespace === false ) {
137
138 9
            return null;
139
140
        }
141
142 21
        $shadowName = $namespace."-".md5($name);
143
144 21
        $success = null;
145
146 21
        if ( self::$is_apcu ) {
147
148 21
            $return = apcu_fetch($shadowName, $success);
149
150 21
        } else {
151
152
            $return = apc_fetch($shadowName, $success);
153
154
        }
155
156 21
        if ( $return === false ) {
157
158
            // This is actually not an error, just KNF flag
159
            // $this->logger->error("Error reading cache (APC), exiting gracefully");
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% 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...
160
            // $this->setErrorState();
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...
161
162 7
            return null;
163
164
        }
165
166 14
        return $return;
167
168
    }
169
170
    /**
171
     * {@inheritdoc}
172
     */
173 11
    public function delete($name = null) {
174
175 11
        if ( !$this->isEnabled() ) return false;
176
177 11
        $this->resetErrorState();
178
179 11
        $namespace = $this->getNamespaceKey();
180
181 11
        if ( $namespace === false ) return true;
182
183 11
        $to_delete = empty($name) ? $this->getNamespace() : $namespace."-".md5($name);
184
185 11
        if ( self::$is_apcu ) {
186
187 11
            $delete = apcu_delete($to_delete);
188
189 11
        } else {
190
191
            $delete = apc_delete($to_delete);
192
193
        }
194
195
        // if ( $delete === false ) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% 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...
196
197
            // This is actually not an error, just KNF flag
198
            // $this->logger->error("Error deleting cache (APC), exiting gracefully");
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% 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...
199
            // $this->setErrorState();
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...
200
201
        // }
202
203 11
        return $delete;
204
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     */
210 7
    public function flush() {
211
212 7
        if ( !$this->isEnabled() ) return false;
213
214 7
        $result = self::$is_apcu ? apcu_clear_cache() : apc_clear_cache("user");
215
216 7
        return $result;
217
218
    }
219
220
    /**
221
     * {@inheritdoc}
222
     */
223 7
    public function status() {
224
225 7 View Code Duplication
        if ( !$this->isEnabled() ) return array(
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
226
            "provider"  => "apc",
227
            "enabled"   => false,
228
            "objects"   => null,
229
            "options"   => array()
230
        );
231
232 7
        $stats = self::$is_apcu ? apcu_cache_info(true) : apc_cache_info("user", true);
233
234 7
        if ( isset($stats["num_entries"]) ) {
235
236 7
            $objects = $stats["num_entries"];
237
238 7
        } else {
239
240
            //  in some APC versions the "num_entries" field is not available; let's try to calculate it
241
            $stats_2 = self::$is_apcu ? apcu_cache_info() : apc_cache_info("user");
242
243
            $objects = sizeof($stats_2["cache_list"]);
244
245
        }
246
247
        return array(
248 7
            "provider"  => self::$is_apcu ? "apcu" : "apc",
249 7
            "enabled"   => $this->isEnabled(),
250 7
            "objects"   => intval($objects),
251
            "options"   => $stats
252 7
        );
253
254
    }
255
256
    /**
257
     * Set namespace key
258
     *
259
     * @return  mixed
260
     */
261 14
    private function setNamespaceKey() {
262
263 14
        $uId = self::getUniqueId();
264
265 14
        $return = self::$is_apcu ? apcu_store($this->getNamespace(), $uId, 0) : apc_store($this->getNamespace(), $uId, 0);
266
267 14
        return $return === false ? false : $uId;
268
269
    }
270
271
    /**
272
     * Get namespace key
273
     *
274
     * @return  string
275
     */
276 48
    private function getNamespaceKey() {
277
278 48
        return self::$is_apcu ? apcu_fetch($this->getNamespace()) : apc_fetch($this->getNamespace());
279
280
    }
281
282
    /**
283
     * Check APC availability
284
     *
285
     * @return  bool
286
     */
287 18
    private static function getApcStatus() {
288
289 18
        $apc = extension_loaded('apc');
290
291 18
        $apcu = extension_loaded('apcu');
292
293 18
        if ( $apcu ) self::$is_apcu = true;
294
295 18
        return ( ( $apc || $apcu ) && ini_get('apc.enabled') );
296
297
    }
298
299
}
300