Passed
Push — master ( 02345f...0e807a )
by Fran
05:53 queued 14s
created

Cache::getDataFromFile()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 5.0342

Importance

Changes 0
Metric Value
cc 5
eloc 8
nc 6
nop 3
dl 0
loc 11
ccs 8
cts 9
cp 0.8889
crap 5.0342
rs 8.8571
c 0
b 0
f 0
1
<?php
2
namespace PSFS\base;
3
4
use PSFS\base\config\Config;
5
use PSFS\base\exception\ConfigException;
6
use PSFS\base\types\helpers\GeneratorHelper;
7
use PSFS\base\types\SingletonTrait;
8
9
/**
10
 * Class Cache
11
 * @package PSFS\base
12
 * Gestión de los ficheros de cache
13
 */
14
class Cache
15
{
16
    /**
17
     * @var \Memcache
18
     */
19
    protected $memcache = null;
20
21
    const JSON = 1;
22
    const TEXT = 2;
23
    const GZIP = 3;
24
    const JSONGZ = 4;
25
    const MEMCACHE = 5;
26
27
    use SingletonTrait;
28
29 1
    public function init() {
30 1
        if(Cache::canUseMemcache()) {
31
            $this->memcache = new \Memcached();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Memcached() of type object<Memcached> is incompatible with the declared type object<Memcache> of property $memcache.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
32
            $this->memcache->connect(Config::getParam('memcache.host', '127.0.0.1'), Config::getParam('memcache.port', 11211));
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 127 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
33
        }
34 1
    }
35
36
    /**
37
     * @return bool
38
     */
39 6
    public static function canUseMemcache()
40
    {
41 6
        return Config::getParam('psfs.memcache', false) && !Config::getParam('debug') && class_exists('Memcached');
42
    }
43
44
    /**
45
     * Método que guarda un text en un fichero
46
     * @param string $data
47
     * @param string $path
48
     * @throws ConfigException
49
     */
50 5 View Code Duplication
    private function saveTextToFile($data, $path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
51
    {
52 5
        GeneratorHelper::createDir(dirname($path));
53 5
        if (false === file_put_contents($path, $data)) {
54
            throw new ConfigException(_('No se tienen los permisos suficientes para escribir en el fichero ')
55
                . $path);
56
        }
57 5
    }
58
59
    /**
60
     * Método que extrae el texto de un fichero
61
     * @param string $path
62
     * @param int $transform
63
     * @param boolean $absolute
64
     * @return mixed
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array|string|null.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
65
     */
66 6
    public function getDataFromFile($path, $transform = Cache::TEXT, $absolute = false)
67
    {
68 6
        $data = null;
69 6
        $absolutePath = ($absolute) ? $path : CACHE_DIR . DIRECTORY_SEPARATOR . $path;
70 6
        if(Cache::MEMCACHE && Cache::canUseMemcache()) {
71
            $data = $this->memcache->get(sha1($absolutePath));
72 6
        } elseif (file_exists($absolutePath)) {
73 4
            $data = file_get_contents($absolutePath);
74 4
        }
75 6
        return Cache::extractDataWithFormat($data, $transform);
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type array<integer,string> or null; however, PSFS\base\Cache::extractDataWithFormat() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
76
    }
77
78
    /**
79
     * Método que verifica si un fichero tiene la cache expirada
80
     * @param string $path
81
     * @param int $expires
82
     * @param boolean $absolute
83
     * @return bool
84
     */
85 1
    private function hasExpiredCache($path, $expires = 300, $absolute = false)
86
    {
87 1
        $absolutePath = ($absolute) ? $path : CACHE_DIR . DIRECTORY_SEPARATOR . $path;
88 1
        $lasModificationDate = filemtime($absolutePath);
89 1
        return ($lasModificationDate + $expires <= time());
90
    }
91
92
    /**
93
     * Método que transforma los datos de salida
94
     * @param string $data
95
     * @param int $transform
96
     * @return array|string|null
97
     */
98 6
    public static function extractDataWithFormat($data, $transform = Cache::TEXT)
99
    {
100
        switch ($transform) {
101 6
            case Cache::JSON:
102 6
                $data = json_decode($data, true);
103 6
                break;
104 4
            case Cache::JSONGZ:
105 4
                $data = Cache::extractDataWithFormat($data, Cache::GZIP);
106 4
                $data = Cache::extractDataWithFormat($data, Cache::JSON);
107 4
                break;
108 4
            case Cache::GZIP:
109 4
                if (function_exists('gzuncompress') && !empty($data)) {
110 2
                    $data = @gzuncompress($data ?: '');
111 2
                }
112 4
                break;
113 1
            case Cache::MEMCACHE:
114
                $data = unserialize($data);
115
        }
116 6
        return $data;
117
    }
118
119
    /**
120
     * Método que transforma los datos de entrada del fichero
121
     * @param string $data
122
     * @param int $transform
123
     * @return string
124
     */
125 5
    public static function transformData($data, $transform = Cache::TEXT)
126
    {
127
        switch ($transform) {
128 5
            case Cache::JSON:
129 5
                $data = json_encode($data, JSON_PRETTY_PRINT);
130 5
                break;
131 3
            case Cache::JSONGZ:
132 2
                $data = Cache::transformData($data, Cache::JSON);
133 2
                $data = Cache::transformData($data, Cache::GZIP);
134 2
                break;
135 3
            case Cache::GZIP:
136 2
                if (function_exists('gzcompress')) {
137 2
                    $data = gzcompress($data ?: '');
138 2
                }
139 2
                break;
140 2
            case Cache::MEMCACHE:
141
                $data = serialize($data);
142
                break;
143
        }
144 5
        return $data;
145
    }
146
147
    /**
148
     * Método que guarda en fichero los datos pasados
149
     * @param $path
150
     * @param $data
151
     * @param int $transform
152
     * @param boolean $absolute
153
     * @param integer $expires
154
     */
155 5
    public function storeData($path, $data, $transform = Cache::TEXT, $absolute = false, $expires = 600)
156
    {
157 5
        $data = Cache::transformData($data, $transform);
158 5
        $absolutePath = ($absolute) ? $path : CACHE_DIR . DIRECTORY_SEPARATOR . $path;
159 5
        if(Cache::MEMCACHE == $transform) {
160
            $this->memcache->set(sha1($absolutePath), $data, $expires);
161
        } else {
162 5
            $this->saveTextToFile($data, $absolutePath);
163
        }
164 5
    }
165
166
    /**
167
     * Método que verifica si tiene que leer o no un fichero de cache
168
     * @param string $path
169
     * @param int $expires
170
     * @param callable $function
171
     * @param int $transform
172
     * @return mixed
173
     */
174 1
    public function readFromCache($path, $expires = 300, callable $function, $transform = Cache::TEXT)
175
    {
176 1
        $data = null;
177 1
        if (file_exists(CACHE_DIR . DIRECTORY_SEPARATOR . $path)) {
178 1
            if (null !== $function && $this->hasExpiredCache($path, $expires)) {
179 1
                $data = call_user_func($function);
180 1
                $this->storeData($path, $data, $transform, false, $expires);
181 1
            } else {
182 1
                $data = $this->getDataFromFile($path, $transform);
183
            }
184 1
        }
185 1
        return $data;
186
    }
187
188
    /**
189
     * @return bool
190
     */
191 1
    private static function checkAdminSite()
192
    {
193 1
        $isAdminRequest = false;
194 1
        $lastRequest = Security::getInstance()->getSessionKey("lastRequest");
195 1
        if (null !== $lastRequest) {
196
            $url = str_replace(Request::getInstance()->getRootUrl(true), '', $lastRequest['url']);
197
            $isAdminRequest = preg_match('/^\/admin\//i', $url);
198
        }
199 1
        return (bool)$isAdminRequest;
200
    }
201
202
    /**
203
     * Método estático que revisa si se necesita cachear la respuesta de un servicio o no
204
     * @return integer|boolean
205
     */
206 1
    public static function needCache()
207
    {
208 1
        $needCache = false;
209 1
        if (!self::checkAdminSite()) {
210 1
            $action = Security::getInstance()->getSessionKey("__CACHE__");
211 1
            if (null !== $action && array_key_exists("cache", $action) && $action["cache"] > 0) {
212 1
                $needCache = $action["cache"];
213 1
            }
214 1
        }
215 1
        return $needCache;
216
    }
217
218
    /**
219
     * Método que construye un hash para almacenar la cache
220
     * @return string
221
     */
222 1
    public function getRequestCacheHash()
223
    {
224 1
        $hash = "";
225 1
        $action = Security::getInstance()->getSessionKey("__CACHE__");
226 1
        if (null !== $action && $action["cache"] > 0) {
227 1
            $hash = $action["http"] . " " . $action["slug"];
228 1
        }
229 1
        return sha1($hash);
230
    }
231
}
232