Completed
Push — master ( e099bf...2f0857 )
by Lars
04:09
created

Cache::getItem()   C

Complexity

Conditions 12
Paths 21

Size

Total Lines 58
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 12.2563

Importance

Changes 0
Metric Value
dl 0
loc 58
ccs 29
cts 33
cp 0.8788
rs 6.5331
c 0
b 0
f 0
cc 12
eloc 30
nc 21
nop 2
crap 12.2563

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace voku\cache;
4
5
/**
6
 * Cache: global-cache class
7
 *
8
 * can use different cache-adapter:
9
 * - Redis
10
 * - Memcache / Memcached
11
 * - APC / APCu
12
 * - Xcache
13
 * - Array
14
 * - File
15
 *
16
 * @package   voku\cache
17
 */
18
class Cache implements iCache
19
{
20
21
  /**
22
   * @var iAdapter
23
   */
24
  private $adapter;
25
26
  /**
27
   * @var iSerializer
28
   */
29
  private $serializer;
30
31
  /**
32
   * @var string
33
   */
34
  private $prefix = '';
35
36
  /**
37
   * @var bool
38
   */
39
  private $isReady = false;
40
41
  /**
42
   * @var bool
43
   */
44
  private $isActive = true;
45
46
  /**
47
   * @var mixed no cache, if admin-session is set
48
   */
49
  private $isAdminSession = false;
50
51
  /**
52
   * @var array
53
   */
54
  private static $STATIC_CACHE = array();
55
56
  /**
57
   * @var array
58
   */
59
  private static $STATIC_CACHE_EXPIRE = array();
60
61
  /**
62
   * @var array
63
   */
64
  private static $STATIC_CACHE_COUNTER = array();
65
66
  /**
67
   * @var int
68
   */
69
  private $staticCacheHitCounter = 10;
70
71
  /**
72
   * __construct
73
   *
74
   * @param null|iAdapter    $adapter
75
   * @param null|iSerializer $serializer
76
   * @param boolean          $checkForUser   check for dev-ip or if cms-user is logged-in
77
   * @param boolean          $cacheEnabled   false will disable the cache (use it e.g. for global settings)
78
   * @param string|boolean   $isAdminSession set a user-id, if the user is a admin (so we can disable cache for this
79
   *                                         user)
80
   */
81 50
  public function __construct($adapter = null, $serializer = null, $checkForUser = true, $cacheEnabled = true, $isAdminSession = false)
82
  {
83 50
    $this->isAdminSession = $isAdminSession;
84
85
    // First check if the cache is active at all.
86 50
    $this->setActive($cacheEnabled);
87
    if (
88 50
        $this->isActive === true
89 50
        &&
90
        $checkForUser === true
91 50
    ) {
92
      $this->setActive($this->isCacheActiveForTheCurrentUser());
93
    }
94
95
    // If the cache is active, then try to auto-connect to the best possible cache-system.
96 50
    if ($this->isActive === true) {
97
98 50
      $this->setPrefix($this->getTheDefaultPrefix());
99
100
      if (
101
          $adapter === null
102 50
          ||
103 50
          !is_object($adapter)
104 50
          ||
105
          !$adapter instanceof iAdapter
106 50
      ) {
107
        $adapter = $this->autoConnectToAvailableCacheSystem();
108
      }
109
110
      // INFO: Memcache(d) has his own "serializer", so don't use it twice
111 50
      if (!is_object($serializer) && $serializer === null) {
112
        if (
113 1
            $adapter instanceof AdapterMemcached
114
            ||
115
            $adapter instanceof AdapterMemcache
116
        ) {
117
          $serializer = new SerializerNo();
118
        } else {
119
          // set default serializer
120
          $serializer = new SerializerIgbinary();
121
        }
122
      }
123 50
    }
124
125
    // Final checks ...
126
    if (
127
        $serializer instanceof iSerializer
128 50
        &&
129
        $adapter instanceof iAdapter
130 50
    ) {
131 50
      $this->setCacheIsReady(true);
132
133 50
      $this->adapter = $adapter;
134 50
      $this->serializer = $serializer;
135 50
    }
136 50
  }
137
138
  /**
139
   * enable / disable the cache
140
   *
141
   * @param boolean $isActive
142
   */
143 50
  public function setActive($isActive)
144
  {
145 50
    $this->isActive = (boolean)$isActive;
146 50
  }
147
148
  /**
149
   * check if the current use is a admin || dev || server == client
150
   *
151
   * @return bool
152
   */
153
  public function isCacheActiveForTheCurrentUser()
0 ignored issues
show
Coding Style introduced by
isCacheActiveForTheCurrentUser uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
isCacheActiveForTheCurrentUser uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
154
  {
155
    $active = true;
156
157
    // test the cache, with this GET-parameter
158
    $testCache = isset($_GET['testCache']) ? (int)$_GET['testCache'] : 0;
159
160
    if ($testCache != 1) {
161
      if (
162
          // admin is logged-in
163
          $this->isAdminSession
164
          ||
165
          // server == client
166
          (
167
              isset($_SERVER['SERVER_ADDR'])
168
              &&
169
              $_SERVER['SERVER_ADDR'] == $this->getClientIp()
170
          )
171
          ||
172
          // user is a dev
173
          $this->checkForDev() === true
174
      ) {
175
        $active = false;
176
      }
177
    }
178
179
    return $active;
180
  }
181
182
  /**
183
   * returns the IP address of the client
184
   *
185
   * @param   bool $trust_proxy_headers   Whether or not to trust the
186
   *                                      proxy headers HTTP_CLIENT_IP
187
   *                                      and HTTP_X_FORWARDED_FOR. ONLY
188
   *                                      use if your $_SERVER is behind a
189
   *                                      proxy that sets these values
190
   *
191
   * @return  string
192
   */
193
  private function getClientIp($trust_proxy_headers = false)
0 ignored issues
show
Coding Style introduced by
getClientIp uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
194
  {
195
    $remoteAddr = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'NO_REMOTE_ADDR';
196
197
    if ($trust_proxy_headers) {
198
      return $remoteAddr;
199
    }
200
201
    if (isset($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP']) {
202
      $ip = $_SERVER['HTTP_CLIENT_IP'];
203
    } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR']) {
204
      $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
205
    } else {
206
      $ip = $remoteAddr;
207
    }
208
209
    return $ip;
210
  }
211
212
  /**
213
   * Check for local developer.
214
   *
215
   * @return bool
216
   */
217
  private function checkForDev()
0 ignored issues
show
Coding Style introduced by
checkForDev uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
checkForDev uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
218
  {
219
    $return = false;
220
221
    if (function_exists('checkForDev')) {
222
      $return = checkForDev();
223
    } else {
224
225
      // for testing with dev-address
226
      $noDev = isset($_GET['noDev']) ? (int)$_GET['noDev'] : 0;
227
      $remoteAddr = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'NO_REMOTE_ADDR';
228
229
      if (
230
          $noDev != 1
231
          &&
232
          (
233
              $remoteAddr === '127.0.0.1'
234
              ||
235
              $remoteAddr === '::1'
236
              ||
237
              PHP_SAPI === 'cli'
238
          )
239
      ) {
240
        $return = true;
241
      }
242
    }
243
244
    return $return;
245
  }
246
247
  /**
248
   * Set the default-prefix via "SERVER"-var + "SESSION"-language.
249
   */
250 50
  protected function getTheDefaultPrefix()
0 ignored issues
show
Coding Style introduced by
getTheDefaultPrefix uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
getTheDefaultPrefix uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
251
  {
252 50
    return (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '') . '_' .
253 50
           (isset($_SERVER['THEME']) ? $_SERVER['THEME'] : '') . '_' .
254 50
           (isset($_SERVER['STAGE']) ? $_SERVER['STAGE'] : '') . '_' .
255 50
           (isset($_SESSION['language']) ? $_SESSION['language'] : '') . '_' .
256 50
           (isset($_SESSION['language_extra']) ? $_SESSION['language_extra'] : '');
257
  }
258
259
  /**
260
   * Auto-connect to the available cache-system on the server.
261
   *
262
   * @return iAdapter
263
   */
264
  protected function autoConnectToAvailableCacheSystem()
265
  {
266
    static $adapterCache;
267
268
    if (is_object($adapterCache) && $adapterCache instanceof iAdapter) {
269
      return $adapterCache;
270
    }
271
272
    $memcached = null;
273
    $isMemcachedAvailable = false;
274
    if (extension_loaded('memcached')) {
275
      $memcached = new \Memcached();
276
      /** @noinspection PhpUsageOfSilenceOperatorInspection */
277
      $isMemcachedAvailable = @$memcached->addServer('127.0.0.1', 11211);
278
    }
279
280
    if ($isMemcachedAvailable === false) {
281
      $memcached = null;
282
    }
283
284
    $adapterMemcached = new AdapterMemcached($memcached);
285
    if ($adapterMemcached->installed() === true) {
286
287
      // -------------------------------------------------------------
288
      // "Memcached"
289
      // -------------------------------------------------------------
290
      $adapter = $adapterMemcached;
291
292
    } else {
293
294
      $memcache = null;
295
      $isMemcacheAvailable = false;
296
      if (class_exists('\Memcache')) {
297
        $memcache = new \Memcache;
298
        /** @noinspection PhpUsageOfSilenceOperatorInspection */
299
        $isMemcacheAvailable = @$memcache->connect('127.0.0.1', 11211);
300
      }
301
302
      if ($isMemcacheAvailable === false) {
303
        $memcache = null;
304
      }
305
306
      $adapterMemcache = new AdapterMemcache($memcache);
307
      if ($adapterMemcache->installed() === true) {
308
309
        // -------------------------------------------------------------
310
        // "Memcache"
311
        // -------------------------------------------------------------
312
        $adapter = $adapterMemcache;
313
314
      } else {
315
316
        $redis = null;
317
        $isRedisAvailable = false;
318
        if (
319
            extension_loaded('redis')
320
            &&
321
            class_exists('\Predis\Client')
322
        ) {
323
          /** @noinspection PhpUndefinedNamespaceInspection */
324
          /** @noinspection PhpUndefinedClassInspection */
325
          $redis = new \Predis\Client(
326
              array(
327
                  'scheme'  => 'tcp',
328
                  'host'    => '127.0.0.1',
329
                  'port'    => 6379,
330
                  'timeout' => '2.0',
331
              )
332
          );
333
          try {
334
            $redis->connect();
335
            $isRedisAvailable = $redis->getConnection()->isConnected();
336
          } catch (\Exception $e) {
337
            // nothing
338
          }
339
        }
340
341
        if ($isRedisAvailable === false) {
342
          $redis = null;
343
        }
344
345
        $adapterRedis = new AdapterPredis($redis);
346
        if ($adapterRedis->installed() === true) {
347
348
          // -------------------------------------------------------------
349
          // Redis
350
          // -------------------------------------------------------------
351
          $adapter = $adapterRedis;
352
353
        } else {
354
355
          $adapterXcache = new AdapterXcache();
356
          if ($adapterXcache->installed() === true) {
357
358
            // -------------------------------------------------------------
359
            // "Xcache"
360
            // -------------------------------------------------------------
361
            $adapter = $adapterXcache;
362
363
          } else {
364
365
            $adapterApc = new AdapterApc();
366
            if ($adapterApc->installed() === true) {
367
368
              // -------------------------------------------------------------
369
              // "APC"
370
              // -------------------------------------------------------------
371
              $adapter = $adapterApc;
372
373
            } else {
374
375
              $adapterApcu = new AdapterApcu();
376
              if ($adapterApcu->installed() === true) {
377
378
                // -------------------------------------------------------------
379
                // "APCu"
380
                // -------------------------------------------------------------
381
                $adapter = $adapterApcu;
382
383
              } else {
384
385
                $adapterFile = new AdapterFile();
386
                if ($adapterFile->installed() === true) {
387
388
                  // -------------------------------------------------------------
389
                  // File-Cache
390
                  // -------------------------------------------------------------
391
                  $adapter = $adapterFile;
392
393
                } else {
394
395
                  // -------------------------------------------------------------
396
                  // Static-PHP-Cache
397
                  // -------------------------------------------------------------
398
                  $adapter = new AdapterArray();
399
                }
400
              }
401
            }
402
          }
403
        }
404
      }
405
    }
406
407
    // save to static cache
408
    $adapterCache = $adapter;
409
410
    return $adapter;
411
  }
412
413
  /**
414
   * Set "isReady" state.
415
   *
416
   * @param boolean $isReady
417
   */
418 50
  private function setCacheIsReady($isReady)
419
  {
420 50
    $this->isReady = (boolean)$isReady;
421 50
  }
422
423
  /**
424
   * Get the "isReady" state.
425
   *
426
   * @return boolean
427
   */
428 5
  public function getCacheIsReady()
429
  {
430 5
    return $this->isReady;
431
  }
432
433
  /**
434
   * Get cached-item by key.
435
   *
436
   * @param string $key
437
   * @param int    $forceStaticCacheHitCounter
438
   *
439
   * @return mixed
440
   */
441 24
  public function getItem($key, $forceStaticCacheHitCounter = 0)
442
  {
443
    // init
444 24
    $forceStaticCacheHitCounter = (int)$forceStaticCacheHitCounter;
445
446 24
    if (!$this->adapter instanceof iAdapter) {
447
      return null;
448
    }
449
450 24
    $storeKey = $this->calculateStoreKey($key);
451
452
    // check if we already using static-cache
453 24
    $useStaticCache = true;
454 24
    if ($this->adapter instanceof AdapterArray) {
455 5
      $useStaticCache = false;
456 5
    }
457
458 24
    if (!isset(self::$STATIC_CACHE_COUNTER[$storeKey])) {
459 13
      self::$STATIC_CACHE_COUNTER[$storeKey] = 0;
460 13
    }
461
462
    // get from static-cache
463
    if (
464
        $useStaticCache === true
465 24
        &&
466 19
        $this->checkForStaticCache($storeKey) === true
467 24
    ) {
468 4
      return self::$STATIC_CACHE[$storeKey];
469
    }
470
471 22
    $serialized = $this->adapter->get($storeKey);
472 22
    $value = $serialized ? $this->serializer->unserialize($serialized) : null;
473
474 22
    self::$STATIC_CACHE_COUNTER[$storeKey]++;
475
476
    // save into static-cache if needed
477
    if (
478
        $useStaticCache === true
479 22
        &&
480
        (
481
          (
482
            $forceStaticCacheHitCounter !== 0
483 17
            &&
484
            self::$STATIC_CACHE_COUNTER[$storeKey] >= $forceStaticCacheHitCounter
485
          )
486
          ||
487
          (
488 17
            $this->staticCacheHitCounter !== 0
489 17
            &&
490 17
            self::$STATIC_CACHE_COUNTER[$storeKey] >= $this->staticCacheHitCounter
491 17
          )
492 17
        )
493 22
    ) {
494 3
      self::$STATIC_CACHE[$storeKey] = $value;
495 3
    }
496
497 22
    return $value;
498
  }
499
500
  /**
501
   * Calculate store-key (prefix + $rawKey).
502
   *
503
   * @param string $rawKey
504
   *
505
   * @return string
506
   */
507 40
  private function calculateStoreKey($rawKey)
508
  {
509 40
    $str = $this->getPrefix() . $rawKey;
510
511 40
    if ($this->adapter instanceof AdapterFile) {
512 8
      $str = $this->cleanStoreKey($str);
513 8
    }
514
515 40
    return $str;
516
  }
517
518
  /**
519
   * Clean store-key (required e.g. for the "File"-Adapter).
520
   *
521
   * @param string $str
522
   *
523
   * @return string
524
   */
525 8
  private function cleanStoreKey($str)
526
  {
527 8
    $str = preg_replace("/[\r\n\t ]+/", ' ', $str);
528 8
    $str = str_replace(
529 8
        array('"', '*', ':', '<', '>', '?', "'", '|'),
530
        array(
531 8
            '-+-',
532 8
            '-+-+-',
533 8
            '-+-+-+-',
534 8
            '-+-+-+-+-',
535 8
            '-+-+-+-+-+-',
536 8
            '-+-+-+-+-+-+-',
537 8
            '-+-+-+-+-+-+-+-',
538 8
            '-+-+-+-+-+-+-+-+-',
539 8
        ),
540
        $str
541 8
    );
542 8
    $str = html_entity_decode($str, ENT_QUOTES, 'UTF-8');
543 8
    $str = htmlentities($str, ENT_QUOTES, 'UTF-8');
544 8
    $str = preg_replace('/(&)([a-z])([a-z]+;)/i', '$2', $str);
545 8
    $str = str_replace(' ', '-', $str);
546 8
    $str = rawurlencode($str);
547 8
    $str = str_replace('%', '-', $str);
548
549 8
    return $str;
550
  }
551
552
  /**
553
   * Get the prefix.
554
   *
555
   * @return string
556
   */
557 40
  public function getPrefix()
558
  {
559 40
    return $this->prefix;
560
  }
561
562
  /**
563
   * !!! Set the prefix. !!!
564
   *
565
   * WARNING: Do not use if you don't know what you do. Because this will overwrite the default prefix.
566
   *
567
   * @param string $prefix
568
   */
569 50
  public function setPrefix($prefix)
570
  {
571 50
    $this->prefix = (string)$prefix;
572 50
  }
573
574
  /**
575
   * Get the current value, when the static cache is used.
576
   *
577
   * @return int
578
   */
579
  public function getStaticCacheHitCounter()
580
  {
581
    return $this->staticCacheHitCounter;
582
  }
583
584
  /**
585
   * Set the static-hit-counter: Who often do we hit the cache, before we use static cache?
586
   *
587
   * @param int $staticCacheHitCounter
588
   */
589
  public function setStaticCacheHitCounter($staticCacheHitCounter)
590
  {
591
    $this->staticCacheHitCounter = (int)$staticCacheHitCounter;
592
  }
593
594
  /**
595
   * Set cache-item by key => value + date.
596
   *
597
   * @param string    $key
598
   * @param mixed     $value
599
   * @param \DateTime $date <p>If the date is in the past, we will remove the existing cache-item.</p>
600
   *
601
   * @return boolean
602
   * @throws \Exception
603
   */
604 9
  public function setItemToDate($key, $value, \DateTime $date)
605
  {
606 9
    $ttl = $date->getTimestamp() - time();
607
608 9
    if ($ttl <= 0) {
609 1
      throw new \Exception('Date in the past.');
610
    }
611
612 8
    $storeKey = $this->calculateStoreKey($key);
613
614 8
    return $this->setItem($storeKey, $value, $ttl);
615
  }
616
617
  /**
618
   * Set cache-item by key => value + ttl.
619
   *
620
   * @param string $key
621
   * @param mixed  $value
622
   * @param int    $ttl
623
   *
624
   * @return bool
625
   */
626 23
  public function setItem($key, $value, $ttl = 0)
627
  {
628
    if (
629 23
        !$this->adapter instanceof iAdapter
630 23
        ||
631 23
        !$this->serializer instanceof iSerializer
632 23
    ) {
633
      return false;
634
    }
635
636 23
    $storeKey = $this->calculateStoreKey($key);
637 23
    $serialized = $this->serializer->serialize($value);
638
639
    // update static-cache, if it's exists
640 23
    if (array_key_exists($storeKey, self::$STATIC_CACHE) === true) {
641 3
      self::$STATIC_CACHE[$storeKey] = $value;
642 3
    }
643
644 23
    if ($ttl) {
645
      // always cache the TTL time, maybe we need this later ...
646 10
      self::$STATIC_CACHE_EXPIRE[$storeKey] = ($ttl ? (int)$ttl + time() : 0);
647
648 10
      return $this->adapter->setExpired($storeKey, $serialized, $ttl);
649
    }
650
651 13
    return $this->adapter->set($storeKey, $serialized);
652
  }
653
654
  /**
655
   * Remove a cached-item.
656
   *
657
   * @param string $key
658
   *
659
   * @return bool
660
   */
661 2
  public function removeItem($key)
662
  {
663 2
    if (!$this->adapter instanceof iAdapter) {
664
      return false;
665
    }
666
667 2
    $storeKey = $this->calculateStoreKey($key);
668
669
    // remove static-cache
670
    if (
671 2
        !empty(self::$STATIC_CACHE)
672 2
        &&
673 1
        array_key_exists($storeKey, self::$STATIC_CACHE) === true
674 2
    ) {
675
      unset(
676
          self::$STATIC_CACHE[$storeKey],
677
          self::$STATIC_CACHE_COUNTER[$storeKey],
678
          self::$STATIC_CACHE_EXPIRE[$storeKey]
679
      );
680
    }
681
682 2
    return $this->adapter->remove($storeKey);
683
  }
684
685
  /**
686
   * Remove all cached-items.
687
   *
688
   * @return bool
689
   */
690 1
  public function removeAll()
691
  {
692 1
    if (!$this->adapter instanceof iAdapter) {
693
      return false;
694
    }
695
696
    // remove static-cache
697 1
    if (!empty(self::$STATIC_CACHE)) {
698 1
      self::$STATIC_CACHE = array();
699 1
      self::$STATIC_CACHE_COUNTER = array();
700 1
      self::$STATIC_CACHE_EXPIRE = array();
701 1
    }
702
703 1
    return $this->adapter->removeAll();
704
  }
705
706
  /**
707
   * Check if cached-item exists.
708
   *
709
   * @param string $key
710
   *
711
   * @return boolean
712
   */
713 7
  public function existsItem($key)
714
  {
715 7
    if (!$this->adapter instanceof iAdapter) {
716
      return false;
717
    }
718
719 7
    $storeKey = $this->calculateStoreKey($key);
720
721
    // check static-cache
722 7
    if ($this->checkForStaticCache($storeKey) === true) {
723
      return true;
724
    }
725
726 7
    return $this->adapter->exists($storeKey);
727
  }
728
729
  /**
730
   * @param string $storeKey
731
   *
732
   * @return bool
733
   */
734 26
  private function checkForStaticCache($storeKey)
735
  {
736
    if (
737 26
        !empty(self::$STATIC_CACHE)
738 26
        &&
739 17
        array_key_exists($storeKey, self::$STATIC_CACHE) === true
740 26
        &&
741 6
        array_key_exists($storeKey, self::$STATIC_CACHE_EXPIRE) === true
742 26
        &&
743 4
        time() <= self::$STATIC_CACHE_EXPIRE[$storeKey]
744 26
    ) {
745 4
      return true;
746
    }
747
748 24
    return false;
749
  }
750
751
  /**
752
   * Get the current adapter class-name.
753
   *
754
   * @return string
755
   */
756 2
  public function getUsedAdapterClassName()
757
  {
758 2
    return get_class($this->adapter);
759
  }
760
761
  /**
762
   * Get the current serializer class-name.
763
   *
764
   * @return string
765
   */
766 2
  public function getUsedSerializerClassName()
767
  {
768 2
    return get_class($this->serializer);
769
  }
770
}
771