Completed
Push — refactorCachePSR2 ( 42c00b...43ff10 )
by Michael
03:15
created

Cache::addDependencies()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace dokuwiki\Cache;
4
5
/**
6
 * Generic handling of caching
7
 */
8
class Cache
9
{
10
    public $key = '';          // primary identifier for this item
11
    public $ext = '';          // file ext for cache data, secondary identifier for this item
12
    public $cache = '';        // cache file name
13
    public $depends = array(); // array containing cache dependency information,
14
    //   used by makeDefaultCacheDecision to determine cache validity
15
16
    public $_event = '';       // event to be triggered during useCache
17
    public $_time;
18
    public $_nocache = false;  // if set to true, cache will not be used or stored
19
20
    /**
21
     * @param string $key primary identifier
22
     * @param string $ext file extension
23
     */
24
    public function __construct($key, $ext)
25
    {
26
        $this->key = $key;
27
        $this->ext = $ext;
28
        $this->cache = getCacheName($key, $ext);
29
    }
30
31
    /**
32
     * public method to determine whether the cache can be used
33
     *
34
     * to assist in centralisation of event triggering and calculation of cache statistics,
35
     * don't override this function override makeDefaultCacheDecision()
36
     *
37
     * @param  array $depends array of cache dependencies, support dependecies:
38
     *                            'age'   => max age of the cache in seconds
39
     *                            'files' => cache must be younger than mtime of each file
40
     *                                       (nb. dependency passes if file doesn't exist)
41
     *
42
     * @return bool    true if cache can be used, false otherwise
43
     */
44
    public function useCache($depends = array())
45
    {
46
        $this->depends = $depends;
47
        $this->addDependencies();
48
49
        if ($this->_event) {
50
            return $this->stats(trigger_event($this->_event, $this, array($this, 'makeDefaultCacheDecision')));
51
        } else {
52
            return $this->stats($this->makeDefaultCacheDecision());
53
        }
54
    }
55
56
    /**
57
     * internal method containing cache use decision logic
58
     *
59
     * this function processes the following keys in the depends array
60
     *   purge - force a purge on any non empty value
61
     *   age   - expire cache if older than age (seconds)
62
     *   files - expire cache if any file in this array was updated more recently than the cache
63
     *
64
     * Note that this function needs to be public as it is used as callback for the event handler
65
     *
66
     * can be overridden
67
     *
68
     * @internal This method may only be called by the event handler! Call \dokuwiki\Cache\Cache::useCache instead!
69
     *
70
     * @return bool               see useCache()
71
     */
72
    public function makeDefaultCacheDecision()
73
    {
74
75
        if ($this->_nocache) {
76
            return false;
77
        }                              // caching turned off
78
        if (!empty($this->depends['purge'])) {
79
            return false;
80
        }              // purge requested?
81
        if (!($this->_time = @filemtime($this->cache))) {
82
            return false;
83
        }   // cache exists?
84
85
        // cache too old?
86
        if (!empty($this->depends['age']) && ((time() - $this->_time) > $this->depends['age'])) {
87
            return false;
88
        }
89
90
        if (!empty($this->depends['files'])) {
91
            foreach ($this->depends['files'] as $file) {
92
                if ($this->_time <= @filemtime($file)) {
93
                    return false;
94
                }         // cache older than files it depends on?
95
            }
96
        }
97
98
        return true;
99
    }
100
101
    /**
102
     * add dependencies to the depends array
103
     *
104
     * this method should only add dependencies,
105
     * it should not remove any existing dependencies and
106
     * it should only overwrite a dependency when the new value is more stringent than the old
107
     */
108
    protected function addDependencies()
109
    {
110
        global $INPUT;
111
        if ($INPUT->has('purge')) {
112
            $this->depends['purge'] = true;
113
        }   // purge requested
114
    }
115
116
    /**
117
     * retrieve the cached data
118
     *
119
     * @param   bool $clean true to clean line endings, false to leave line endings alone
120
     * @return  string          cache contents
121
     */
122
    public function retrieveCache($clean = true)
123
    {
124
        return io_readFile($this->cache, $clean);
125
    }
126
127
    /**
128
     * cache $data
129
     *
130
     * @param   string $data the data to be cached
131
     * @return  bool           true on success, false otherwise
132
     */
133
    public function storeCache($data)
134
    {
135
        if ($this->_nocache) {
136
            return false;
137
        }
138
139
        return io_savefile($this->cache, $data);
140
    }
141
142
    /**
143
     * remove any cached data associated with this cache instance
144
     */
145
    public function removeCache()
146
    {
147
        @unlink($this->cache);
148
    }
149
150
    /**
151
     * Record cache hits statistics.
152
     * (Only when debugging allowed, to reduce overhead.)
153
     *
154
     * @param    bool $success result of this cache use attempt
155
     * @return   bool              pass-thru $success value
156
     */
157
    protected function stats($success)
158
    {
159
        global $conf;
160
        static $stats = null;
161
        static $file;
162
163
        if (!$conf['allowdebug']) {
164
            return $success;
165
        }
166
167
        if (is_null($stats)) {
168
            $file = $conf['cachedir'] . '/cache_stats.txt';
169
            $lines = explode("\n", io_readFile($file));
170
171
            foreach ($lines as $line) {
172
                $i = strpos($line, ',');
173
                $stats[substr($line, 0, $i)] = $line;
174
            }
175
        }
176
177
        if (isset($stats[$this->ext])) {
178
            list($ext, $count, $hits) = explode(',', $stats[$this->ext]);
179
        } else {
180
            $ext = $this->ext;
181
            $count = 0;
182
            $hits = 0;
183
        }
184
185
        $count++;
186
        if ($success) {
187
            $hits++;
188
        }
189
        $stats[$this->ext] = "$ext,$count,$hits";
190
191
        io_saveFile($file, join("\n", $stats));
192
193
        return $success;
194
    }
195
}
196