StampedeProtection::methodsAvailable()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * Phossa Project
4
 *
5
 * PHP version 5.4
6
 *
7
 * @category  Library
8
 * @package   Phossa2\Cache
9
 * @copyright Copyright (c) 2016 phossa.com
10
 * @license   http://mit-license.org/ MIT License
11
 * @link      http://www.phossa.com/
12
 */
13
/*# declare(strict_types=1); */
14
15
namespace Phossa2\Cache\Extension;
16
17
use Phossa2\Cache\CacheItem;
18
use Phossa2\Cache\CachePool;
19
use Phossa2\Cache\Message\Message;
20
use Phossa2\Event\Interfaces\EventInterface;
21
use Phossa2\Event\EventableExtensionAbstract;
22
use Phossa2\Cache\Interfaces\CacheItemExtendedInterface;
23
24
/**
25
 * Stampede protection for the cache
26
 *
27
 * If item expires in 600 seconds (configurable), and by 5% (configurable)
28
 * chance, this extension will mark the $item as a miss to force regenerating
29
 * the item before it is truly expired.
30
 *
31
 * ```php
32
 * $stampede = new StampedeProtection([
33
 *     'probability' => 60, // probability 60/1000
34
 *     'time_left'   => 300 // change time left in seconds
35
 * ]);
36
 * $cachePool->addExtension($stampede);
37
 * ```
38
 *
39
 * @package Phossa2\Cache
40
 * @author  Hong Zhang <[email protected]>
41
 * @see     EventableExtensionAbstract
42
 * @see     CacheItem
43
 * @version 2.0.1
44
 * @since   2.0.0 added
45
 * @since   2.0.1 moved to EventableExtensionAbstract
46
 */
47
class StampedeProtection extends EventableExtensionAbstract
48
{
49
    /**
50
     * Probability, usually 1 - 100
51
     *
52
     * @var    int
53
     * @access protected
54
     */
55
    protected $probability = 50;
56
57
    /**
58
     * time left in seconds
59
     *
60
     * @var    int
61
     * @access protected
62
     */
63
    protected $time_left = 600;
64
65
    /**
66
     * {@inheritDoc}
67
     */
68
    public function methodsAvailable()/*# : array */
69
    {
70
        return ['stampedeProtect'];
71
    }
72
73
    /**
74
     * {@inheritDoc}
75
     */
76
    protected function extensionHandles()/*# : array */
77
    {
78
        // change hit status
79
        return [
80
            [
81
                'event'   => CachePool::EVENT_HAS_AFTER,
82
                'handler' => ['stampedeProtect', 80]
83
            ]
84
        ];
85
    }
86
87
    /**
88
     * Change hit status if ...
89
     *
90
     * @param  EventInterface $event
91
     * @return bool
92
     * @access public
93
     */
94
    public function stampedeProtect(EventInterface $event)/*# : bool */
95
    {
96
        /* @var CachePool $pool */
97
        $pool = $event->getTarget();
98
        /* @var CacheItem $item */
99
        $item = $event->getParam('item');
100
101
        if ($item instanceof CacheItemExtendedInterface) {
102
            $left = $item->getExpiration()->getTimestamp() - time();
103
            if ($left < $this->time_left && rand(1, 1000) <= $this->probability) {
104
                return $pool->setError(
105
                    Message::get(Message::CACHE_EXT_STAMPEDE, $item->getKey()),
106
                    Message::CACHE_EXT_STAMPEDE
107
                );
108
            }
109
        }
110
111
        return true;
112
    }
113
}
114