CachedCallable::getTtlAndKey()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 1
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\Utility;
16
17
use Phossa2\Cache\CachePool;
18
use Phossa2\Cache\CacheItem;
19
use Phossa2\Shared\Extension\ExtensionAbstract;
20
21
/**
22
 * CachedCallable
23
 *
24
 * Cache result of a callable
25
 *
26
 * ```php
27
 * $cachePool->addUtility(new CachedCallable());
28
 *
29
 * // get result of callable [$object, 'method'] with parameters ...
30
 * // cache the result for 3600 sec.
31
 * $res = $cachePool->callableCache(3600, [$object, 'method'], $param1);
32
 * ```
33
 *
34
 * @package Phossa2\Cache
35
 * @author  Hong Zhang <[email protected]>
36
 * @see     ExtensionAbstract
37
 * @see     CacheItem
38
 * @see     CachePool
39
 * @version 2.0.0
40
 * @since   2.0.0 added
41
 */
42
class CachedCallable extends ExtensionAbstract
43
{
44
    /**
45
     * default ttl for the cached callable result
46
     *
47
     * @var    int
48
     * @access protected
49
     */
50
    protected $ttl = 86400;
51
52
    /**
53
     * {@inheritDoc}
54
     */
55
    public function methodsAvailable()/*# : array */
56
    {
57
        return ['callableCache'];
58
    }
59
60
    /**
61
     * Complete cycle of get cached result of a callable
62
     *
63
     * 1. if first argument is int, it is a TTL
64
     * 2. otherwise the first argument is a callable
65
     * 3. the remaining are the arguments for the callable
66
     *
67
     * @return mixed
68
     * @throws \Exception except from callable execution
69
     * @access public
70
     * @api
71
     */
72
    public function callableCache()
73
    {
74
        // get method arguments
75
        $args = func_get_args();
76
77
        // get ttl and uniq key
78
        list($ttl, $key) = $this->getTtlAndKey($args);
79
80
        /* @var $cache CachePool */
81
        $cache = $this->server;
82
83
        /* @var $item CacheItem */
84
        $item = $cache->getItem($key);
85
86
        if ($item->isHit()) {
87
            return $item->get();
88
        } else {
89
            $func = array_shift($args);
90
            $val  = call_user_func_array($func, $args);
91
            $cache->save($item->set($val)->expiresAfter($ttl));
92
            return $val;
93
        }
94
    }
95
96
    /**
97
     * The real boot method
98
     *
99
     * @access protected
100
     */
101
    protected function bootExtension()
102
    {
103
    }
104
105
    /**
106
     * Get TTL and unique key
107
     *
108
     * @param  array &$args
109
     * @return array
110
     * @access protected
111
     */
112
    protected function getTtlAndKey(array &$args)/*# : array */
113
    {
114
        if (is_numeric($args[0])) {
115
            $ttl = (int) array_shift($args);
116
            $key = $this->generateKey($args);
117
        } else {
118
            $key = $this->generateKey($args);
119
            $ttl = $this->ttl;
120
        }
121
        return [$ttl, $key];
122
    }
123
124
    /**
125
     * Generate key base on input
126
     *
127
     * @param  mixed $reference reference data
128
     * @return string
129
     * @access protected
130
     */
131
    protected function generateKey($reference)/*# : string */
132
    {
133
        if (is_array($reference)) {
134
            $reference = $this->flatReference($reference);
135
        }
136
        $md5 = md5(serialize($reference));
137
        return sprintf("/%s/%s/%s", $md5[0], $md5[1], $md5);
138
    }
139
140
    /**
141
     * flat the reference array to make it easy for serialize
142
     *
143
     * @param  array $reference reference data
144
     * @return array flattered array
145
     * @access protected
146
     */
147
    protected function flatReference(array $reference)/*# : array */
148
    {
149
        reset($reference);
150
        foreach ($reference as $key => $value) {
151
            if (is_object($value)) {
152
                $reference[$key] = get_class($value);
153
            } elseif (is_array($value)) {
154
                $reference[$key] = $this->flatReference($value);
155
            }
156
        }
157
        ksort($reference);
158
        return $reference;
159
    }
160
}
161