Completed
Pull Request — master (#562)
by Richard
09:55
created

CacheManager   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 210
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 12.66%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 210
ccs 10
cts 79
cp 0.1266
rs 10
wmc 27
lcom 1
cbo 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 3
A getDefaults() 0 15 1
A createDefaultConfig() 0 19 4
A getCache() 0 16 4
C startPoolAccess() 0 31 7
B getDriver() 0 11 5
A getDefaultPool() 0 15 3
1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
*/
11
12
namespace Xoops\Core\Cache;
13
14
use Stash\Pool;
15
use Stash\Interfaces\DriverInterface;
16
use Xmf\Yaml;
17
use Xoops\Core\Cache\DriverList;
18
use Xoops\Core\Cache\Access;
19
20
/**
21
 * Provides a standardized cache access
22
 *
23
 * @category  Xoops\Core\Cache
24
 * @package   CacheManager
25
 * @author    Richard Griffith <[email protected]>
26
 * @copyright 2015 The XOOPS Project https://github.com/XOOPS
27
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
28
 * @link      http://xoops.org
29
 */
30
class CacheManager
31
{
32
    /**
33
     * Cache Access objects for pools
34
     *
35
     * @var Access[]
36
     */
37
    protected $pools = [];
38
39
    /**
40
     * Pool definitions
41
     *
42
     * @var array
43
     */
44
    protected $poolDefs = [];
45
46
    /**
47
     * Xoops instance
48
     *
49
     * @var \Xoops
50
     */
51
    protected $xoops;
52
53
    /**
54
     * __construct
55
     */
56
    public function __construct()
57
    {
58
        $this->xoops = \Xoops::getInstance();
59
        $defaults = $this->getDefaults();
60
		$xoops_var_path = \XoopsBaseConfig::get('var-path');
61
		$cache_file = $xoops_var_path . '/configs/cache.php';
62
        $poolDefs = Yaml::readWrapped($cache_file);
63
        if (empty($poolDefs)) {
64
            Yaml::saveWrapped($defaults, $cache_file);
65
        }
66
        $poolDefs = is_array($poolDefs) ? $poolDefs : array();
67
        $this->poolDefs = array_merge($defaults, $poolDefs);
68
    }
69
70
    /**
71
     * getDefaults get default cache configuration used if there is no config file
72
     *
73
     * @return array cache configuration
74
     */
75
    private static function getDefaults()
76
    {
77
78
        $defaults = [
79
            'default' => [
80
                'driver' => 'Sqlite',
81
                'options' => ['path' => \XoopsBaseConfig::get('var-path') . '/stash/'],
82
                ],
83
            'temp' => [
84
                'driver' => 'Ephemeral',
85
                'options' => [],
86
                ],
87
            ];
88
        return $defaults;
89
    }
90
91
    /**
92
     * Create a default configuration file, used in installation
93
     *
94
     * SQLite is the recommended driver, and will be used by default if available.
95
     *
96
     * We will fall back to FileSystem if SQLite is not available.
97
     *
98
     * Note: some versions of the Stash FileSystem driver appear susceptible to
99
     * race conditions which may cause random failures.
100
     *
101
     * Note for Windows users:
102
     *
103
     * When using Windows NTFS, PHP has a maximum path length of 260 bytes. Each key level in a
104
     * Stash hierarchical key corresponds to a directory, and is normalized as an md5 hash. Also,
105
     * Stash uses 2 levels for its own integrity and locking mechanisms. The full key length used
106
     * in XoopCore can reach 202 characters.
107
     *
108
     * Installing the pdo_sqlite3 extension is highly recommended to avoid problems.
109
     *
110
     * @return void
111
     */
112
    public static function createDefaultConfig()
113
    {
114
        $configFile = \XoopsBaseConfig::get('var-path') . '/configs/cache.php';
115
        if (file_exists($configFile)) {
116
            return;
117
        }
118
        $defaults = self::getDefaults();
119
        if (!array_key_exists("SQLite", \Stash\DriverList::getAvailableDrivers())) {
120
            $defaults['default']['driver'] = 'FileSystem';
121
            $defaults['default']['options'] = [
122
                'dirSplit' => 1,
123
                'path' => \XoopsBaseConfig::get('var-path') . '/stash/'
124
            ];
125
            if (false !== stripos(PHP_OS, 'WIN')) {
126
                trigger_error("SQLite is strongly recommended on windows due to 260 character file path restrictions.");
127
            }
128
        }
129
        Yaml::saveWrapped($defaults, $configFile);
130
    }
131
132
    /**
133
     * Get a cache corresponding to the specified name
134
     *
135
     * @param string $name Name of cache definition
136
     *
137
     * @return Access object
138
     */
139 29
    public function getCache($name)
140
    {
141 29
        $pool = false;
142 29
        if (array_key_exists($name, $this->pools)) {
143 28
            $pool =  $this->pools[$name];
144 1
        } elseif (array_key_exists($name, $this->poolDefs)) {
145 1
            $pool =  $this->startPoolAccess($name);
146
        }
147 29
        if ($pool === false) {
148 1
            $pool = $this->getDefaultPool($name);
149
        }
150
151 29
        $this->pools[$name] = $pool;
152
153 29
        return $pool;
154
    }
155
156
    /**
157
     * Instantiate an Access object from named configuration, including
158
     * instantiating pool and driver
159
     *
160
     * @param string $name name of pool configuration to start
161
     *
162
     * @return Access|false pool or false if a pool cannot be created
163
     */
164
    protected function startPoolAccess($name)
165
    {
166
        $pool = false;
167
        $options = false;
168
        if (isset($this->poolDefs[$name]['options'])) {
169
            $options = $this->poolDefs[$name]['options'];
170
        }
171
        $driverName = $this->poolDefs[$name]['driver'];
172
        if (0 === strcasecmp($driverName, 'Composite')) {
173
            $drivers = array();
174
            foreach ($this->poolDefs[$name]['options']['drivers'] as $subDriver) {
175
                $drivers[] = $this->getDriver($subDriver['driver'], $subDriver['options']);
176
            }
177
            $options['drivers'] = $drivers;
178
        }
179
180
        $driver = $this->getDriver($driverName, $options);
181
        if ($driver!==false) {
182
            $pool = new Pool($driver);
183
            if (is_object($pool)) {
184
                $pool->setLogger($this->xoops->logger());
185
                $pool->setNamespace($this->xoops->db()->prefix());
186
            }
187
        }
188
        if (!$pool) {
189
            $this->xoops->logger()->warn('Could not create cache pool '.$name);
0 ignored issues
show
Documentation Bug introduced by
The method warn does not exist on object<Xoops\Core\Logger>? 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...
190
            return $pool;
191
        }
192
193
        return new Access($pool);
194
    }
195
196
    /**
197
     * getDriver
198
     *
199
     * @param string $driverName short name of the driver
200
     * @param array  $options    array of options for the driver
201
     *
202
     * @return DriverInterface|false driver object or false if it could not be instantiated
203
     */
204
    protected function getDriver($driverName, $options)
205
    {
206
        $driver = false;
207
        $driverClass = DriverList::getDriverClass($driverName);
208
209
        if ($driverClass!==false && $driverClass::isAvailable()) {
210
            $options = is_array($options) ? $options : array();
211
            $driver = new $driverClass($options);
212
        }
213
        return ($driver instanceof DriverInterface) ? $driver : false;
214
    }
215
216
    /**
217
     * Get an Access object based on the default pool. If it isn't set, create it.
218
     * If no definition exists for default, use Stash default (Ephimeral.)
219
     *
220
     * @param string $originalName originally requested pool configuration name
221
     *
222
     * @return Access object
223
     */
224
    protected function getDefaultPool($originalName)
225
    {
226
        $this->xoops->events()->triggerEvent('debug.log', 'Substituting default cache pool for '.$originalName);
227
        $name = 'default';
228
        if (array_key_exists($name, $this->pools)) {
229
            return $this->pools[$name];
230
        }
231
        $pool = $this->startPoolAccess($name);
232
        if ($pool===false) {
233
            $this->xoops->logger()->error('Could not create default cache pool');
234
            $pool = new Access(new \Stash\Pool());
235
        }
236
        $this->pools[$name] = $pool;
237
        return $pool;
238
    }
239
}
240