Ajde_Cache::__construct()   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
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
class Ajde_Cache extends Ajde_Object_Singleton
4
{
5
    protected $_hashContext;
6
    protected $_hashFinal;
7
    protected $_lastModified = [];
8
    protected $_contents;
9
10
    protected $_enabled = true;
11
12
    /**
13
     * @staticvar Ajde_Cache $instance
14
     *
15
     * @return Ajde_Cache
16
     */
17
    public static function getInstance()
18
    {
19
        static $instance;
20
21
        return $instance === null ? $instance = new self() : $instance;
22
    }
23
24
    protected function __construct()
25
    {
26
        $this->_enabled = config('layout.cache.enabled');
27
    }
28
29
    public function isEnabled()
30
    {
31
        return $this->_enabled;
32
    }
33
34
    public function enable()
35
    {
36
        $this->_enabled = true;
37
    }
38
39
    public function disable()
40
    {
41
        $this->_enabled = false;
42
    }
43
44
    public function getHashContext()
45
    {
46
        if (!isset($this->_hashContext)) {
47
            $this->_hashContext = hash_init('md5');
48
        }
49
50
        return $this->_hashContext;
51
    }
52
53
    public function updateHash($data)
54
    {
55
        if (!isset($this->_hashFinal)) {
56
            hash_update($this->getHashContext(), $data);
57
        }
58
    }
59
60
    public function addFile($filename)
61
    {
62
        if (!isset($this->_hashFinal)) {
63
            if (is_file(LOCAL_ROOT.$filename)) {
64
                hash_update_file($this->getHashContext(), LOCAL_ROOT.$filename);
65
                $this->addLastModified(filemtime(LOCAL_ROOT.$filename));
66
            }
67
        }
68
    }
69
70
    public function getHash()
71
    {
72
        if (!isset($this->_hashFinal)) {
73
            $this->_hashFinal = hash_final($this->getHashContext());
74
        }
75
76
        return $this->_hashFinal;
77
    }
78
79
    public function addLastModified($timestamp)
80
    {
81
        $this->_lastModified[] = $timestamp;
82
    }
83
84
    public function getLastModified()
85
    {
86
        if (empty($this->_lastModified)) {
87
            return time();
88
        }
89
90
        return max($this->_lastModified);
91
    }
92
93
    public function ETagMatch($serverETag = null)
94
    {
95
        if (empty($serverETag) && isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
96
            $serverETag = $_SERVER['HTTP_IF_NONE_MATCH'];
97
        }
98
99
        return $serverETag == $this->getHash();
100
    }
101
102
    public function modifiedSince()
103
    {
104
        if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
105
            return $this->getLastModified() > strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
106
        }
107
108
        return false;
109
    }
110
111
    public function setContents($contents)
112
    {
113
        $this->set('contents', $contents);
114
    }
115
116
    public function getContents()
117
    {
118
        return $this->get('contents');
119
    }
120
121
    public function saveResponse()
122
    {
123
        $response = Ajde::app()->getResponse();
124
        $document = Ajde::app()->getDocument();
125
126
        // Expires and Cache-Control
127
        if ($document->getCacheControl() == Ajde_Document::CACHE_CONTROL_NOCACHE || $this->isEnabled() == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
128
            $response->addHeader('Expires', gmdate('D, d M Y H:i:s \G\M\T', time()));
129
            $response->addHeader('Cache-Control', Ajde_Document::CACHE_CONTROL_NOCACHE.', max-age=0');
130
        } else {
131
            $response->addHeader('Expires', gmdate('D, d M Y H:i:s \G\M\T', time() + $document->getMaxAge()));
132
            $response->addHeader('Cache-Control', $document->getCacheControl().', max-age='.$document->getMaxAge());
133
        }
134
135
        // Content
136
        if (($this->ETagMatch() && !$this->modifiedSince()) && $this->isEnabled()) {
137
            $response->setResponseType(Ajde_Http_Response::RESPONSE_TYPE_NOT_MODIFIED);
138
            $response->setData(false);
139
        } else {
140
            $response->addHeader('Last-Modified', gmdate('D, d M Y H:i:s', $this->getLastModified()).' GMT');
141
            $response->addHeader('Etag', $this->getHash());
142
            $response->addHeader('Content-Type', $document->getContentType());
143
            $response->setData($this->hasContents() ? $this->getContents() : false);
0 ignored issues
show
Documentation Bug introduced by
The method hasContents does not exist on object<Ajde_Cache>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
144
        }
145
    }
146
147
    /**
148
     * Remember a cached value in the cache directory as a file.
149
     *
150
     * @param string   $key
151
     * @param callable $callback
152
     * @param int      $ttl      in seconds, defaults to 3600 (one hour)
153
     *
154
     * @return mixed
155
     */
156
    public static function remember($key, Closure $callback, $ttl = 3600)
157
    {
158
        $safeKey = substr(preg_replace('/[^a-zA-Z0-9_-]/', '-', $key), 0, 100);
159
        $cacheFilename = CACHE_DIR.'STATIC_CACHE_'.$safeKey;
160
161
        if (file_exists(LOCAL_ROOT.$cacheFilename) && filemtime(LOCAL_ROOT.$cacheFilename) > (time() - $ttl)) {
162
            return json_decode(file_get_contents(LOCAL_ROOT.$cacheFilename));
163
        } else {
164
            $result = $callback->__invoke();
165
            file_put_contents(LOCAL_ROOT.$cacheFilename, json_encode($result));
166
167
            return $result;
168
        }
169
    }
170
}
171