Passed
Push — master ( 0991d4...ef4a94 )
by Fran
04:27
created

Cache::storeData()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 5
dl 0
loc 7
ccs 6
cts 6
cp 1
crap 2
rs 9.4285
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\helpers\FileHelper;
8
use PSFS\base\types\traits\SingletonTrait;
9
10
/**
11
 * Class Cache
12
 * @package PSFS\base
13
 * Gestión de los ficheros de cache
14
 */
15
class Cache
16
{
17
    /**
18
     * @var \Memcache
19
     */
20
    protected $memcache = null;
21
22
    const JSON = 1;
23
    const TEXT = 2;
24
    const GZIP = 3;
25
    const JSONGZ = 4;
26
    const MEMCACHE = 5;
27
28
    use SingletonTrait;
29
30 2
    public function __construct()
31
    {
32 2
        $this->setLoaded(true);
33 2
    }
34
35
    /**
36
     * @return bool
37
     */
38 2
    public static function canUseMemcache()
39
    {
40 2
        return Config::getParam('psfs.memcache', false) && !Config::getParam('debug') && class_exists('Memcached');
41
    }
42
43
    /**
44
     * Método que guarda un text en un fichero
45
     * @param string $data
46
     * @param string $path
47
     * @throws ConfigException
48
     */
49 4 View Code Duplication
    private function saveTextToFile($data, $path)
50
    {
51 4
        GeneratorHelper::createDir(dirname($path));
52 4
        if (false === FileHelper::writeFile($path, $data)) {
53
            throw new ConfigException(_('No se tienen los permisos suficientes para escribir en el fichero ') . $path);
54
        }
55 4
    }
56
57
    /**
58
     * Método que extrae el texto de un fichero
59
     * @param string $path
60
     * @param int $transform
61
     * @param boolean $absolute
62
     * @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...
63
     */
64 6
    public function getDataFromFile($path, $transform = Cache::TEXT, $absolute = false)
65
    {
66 6
        Logger::log('Gathering data from cache', LOG_DEBUG, ['path' => $path]);
67 6
        $data = null;
68 6
        $absolutePath = ($absolute) ? $path : CACHE_DIR . DIRECTORY_SEPARATOR . $path;
69 6
        if (file_exists($absolutePath)) {
70 3
            $data = FileHelper::readFile($absolutePath);
71
        }
72 6
        return Cache::extractDataWithFormat($data, $transform);
73
    }
74
75
    /**
76
     * Método que verifica si un fichero tiene la cache expirada
77
     * @param string $path
78
     * @param int $expires
79
     * @param boolean $absolute
80
     * @return bool
81
     */
82 1
    private function hasExpiredCache($path, $expires = 300, $absolute = false)
83
    {
84 1
        Logger::log('Checking expiration', LOG_DEBUG, ['path' => $path]);
85 1
        $absolutePath = ($absolute) ? $path : CACHE_DIR . DIRECTORY_SEPARATOR . $path;
86 1
        $lasModificationDate = filemtime($absolutePath);
87 1
        return ($lasModificationDate + $expires <= time());
88
    }
89
90
    /**
91
     * Método que transforma los datos de salida
92
     * @param string $data
93
     * @param int $transform
94
     * @return array|string|null
95
     */
96 6 View Code Duplication
    public static function extractDataWithFormat($data, $transform = Cache::TEXT)
97
    {
98 6
        Logger::log('Extracting data from cache', LOG_DEBUG);
99
        switch ($transform) {
100 6
            case Cache::JSON:
101 6
                $data = json_decode($data, true);
102 6
                break;
103 4
            case Cache::JSONGZ:
104 4
                $data = Cache::extractDataWithFormat($data, Cache::GZIP);
105 4
                $data = Cache::extractDataWithFormat($data, Cache::JSON);
0 ignored issues
show
Bug introduced by
It seems like $data defined by \PSFS\base\Cache::extrac...\PSFS\base\Cache::JSON) on line 105 can also be of type array 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...
106 4
                break;
107 4
            case Cache::GZIP:
108 4
                if (function_exists('gzuncompress') && !empty($data)) {
109 2
                    $data = @gzuncompress($data ?: '');
110
                }
111 4
                break;
112
        }
113 6
        return $data;
114
    }
115
116
    /**
117
     * Método que transforma los datos de entrada del fichero
118
     * @param string $data
119
     * @param int $transform
120
     * @return string
121
     */
122 4 View Code Duplication
    public static function transformData($data, $transform = Cache::TEXT)
123
    {
124 4
        Logger::log('Transform data in cache', LOG_DEBUG);
125
        switch ($transform) {
126 4
            case Cache::JSON:
127 4
                $data = json_encode($data, JSON_PRETTY_PRINT);
128 4
                break;
129 3
            case Cache::JSONGZ:
130 2
                $data = Cache::transformData($data, Cache::JSON);
131 2
                $data = Cache::transformData($data, Cache::GZIP);
132 2
                break;
133 3
            case Cache::GZIP:
134 2
                if (function_exists('gzcompress')) {
135 2
                    $data = gzcompress($data ?: '');
136
                }
137 2
                break;
138
        }
139 4
        return $data;
140
    }
141
142
    /**
143
     * Método que guarda en fichero los datos pasados
144
     * @param $path
145
     * @param $data
146
     * @param int $transform
147
     * @param boolean $absolute
148
     * @param integer $expires
149
     */
150 4
    public function storeData($path, $data, $transform = Cache::TEXT, $absolute = false, $expires = 600)
0 ignored issues
show
Unused Code introduced by
The parameter $expires is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
151
    {
152 4
        Logger::log('Store data in cache', LOG_DEBUG, ['path' => $path]);
153 4
        $data = Cache::transformData($data, $transform);
154 4
        $absolutePath = ($absolute) ? $path : CACHE_DIR . DIRECTORY_SEPARATOR . $path;
155 4
        $this->saveTextToFile($data, $absolutePath);
156 4
    }
157
158
    /**
159
     * Método que verifica si tiene que leer o no un fichero de cache
160
     * @param string $path
161
     * @param int $expires
162
     * @param callable $function
0 ignored issues
show
Documentation introduced by
Should the type for parameter $function not be callable|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
163
     * @param int $transform
164
     * @return mixed
165
     */
166 1
    public function readFromCache($path, $expires = 300, $function = null, $transform = Cache::TEXT)
167
    {
168 1
        $data = null;
169 1
        Logger::log('Reading data from cache', LOG_DEBUG, ['path' => $path]);
170 1
        if (file_exists(CACHE_DIR . DIRECTORY_SEPARATOR . $path)) {
171 1
            if (is_callable($function) && $this->hasExpiredCache($path, $expires)) {
172 1
                $data = call_user_func($function);
173 1
                $this->storeData($path, $data, $transform, false, $expires);
174
            } else {
175 1
                $data = $this->getDataFromFile($path, $transform);
176
            }
177
        }
178 1
        return $data;
179
    }
180
181
    /**
182
     * @return bool
183
     */
184 1
    private static function checkAdminSite()
185
    {
186 1
        return Security::getInstance()->canAccessRestrictedAdmin();
187
    }
188
189
    /**
190
     * Método estático que revisa si se necesita cachear la respuesta de un servicio o no
191
     * @return integer|boolean
192
     */
193 1
    public static function needCache()
194
    {
195 1
        $needCache = false;
196 1
        Logger::log('Checking cache requirements', LOG_DEBUG);
197 1
        if (!self::checkAdminSite() && !Config::getParam('debug')) {
198 1
            $action = Security::getInstance()->getSessionKey("__CACHE__");
199 1
            Logger::log('Gathering cache params from Session', LOG_DEBUG, $action);
200 1
            if (null !== $action && array_key_exists("cache", $action) && $action["cache"] > 0) {
201 1
                $needCache = $action["cache"];
202
            }
203
        }
204 1
        return $needCache;
205
    }
206
207
    /**
208
     * Método que construye un hash para almacenar la cache
209
     * @return array
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...
210
     */
211 1
    public function getRequestCacheHash()
212
    {
213 1
        $hashPath = null;
214 1
        $filename = null;
215 1
        $action = Security::getInstance()->getSessionKey("__CACHE__");
216 1
        Logger::log('Gathering cache hash for request', LOG_DEBUG, $action);
217 1
        if (null !== $action && $action["cache"] > 0) {
218 1
            $query = $action['params'];
219 1
            $query['X-API-LANG'] = Request::header('X-API-LANG', 'es');
220 1
            $filename = FileHelper::generateHashFilename($action["http"], $action["slug"], $query);
221 1
            $hashPath = FileHelper::generateCachePath($action, $query);
222 1
            Logger::log('Cache file calculated', LOG_DEBUG, ['file' => $filename, 'hash' => $hashPath]);
223
        }
224 1
        return [$hashPath, $filename];
225
    }
226
227
    /**
228
     * Flush cache when save a registry
229
     */
230
    public function flushCache() {
231
        Logger::log('Flushing cache', LOG_DEBUG);
232
        $action = Security::getInstance()->getSessionKey("__CACHE__");
233
        $hashPath = FileHelper::generateCachePath($action, $action['params']) . '..' . DIRECTORY_SEPARATOR . ' .. ' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR;
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 167 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...
234
        FileHelper::deleteDir($hashPath);
235
    }
236
}
237