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

Cache   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 218
Duplicated Lines 3.67 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 85.44%

Importance

Changes 0
Metric Value
dl 8
loc 218
ccs 88
cts 103
cp 0.8544
rs 8.3999
c 0
b 0
f 0
wmc 46
lcom 1
cbo 6

12 Methods

Rating   Name   Duplication   Size   Complexity  
A canUseMemcache() 0 4 3
A saveTextToFile() 8 8 2
A hasExpiredCache() 0 6 2
A init() 0 6 2
B getDataFromFile() 0 11 5
B extractDataWithFormat() 0 20 8
B transformData() 0 21 7
A storeData() 0 10 3
A readFromCache() 0 13 4
A checkAdminSite() 0 10 2
B needCache() 0 11 5
A getRequestCacheHash() 0 9 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Cache often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Cache, and based on these observations, apply Extract Interface, too.

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