Completed
Push — fix-2494 ( 3153ee )
by Sam
07:19
created

DefaultCacheFactory   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 101
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 0
loc 101
rs 10
c 0
b 0
f 0
wmc 17
lcom 1
cbo 3

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
D create() 0 29 9
A isAPCUSupported() 0 8 2
A isPHPFilesSupported() 0 8 2
A createCache() 0 12 3
1
<?php
2
3
namespace SilverStripe\Core\Cache;
4
5
use Psr\Log\LoggerAwareInterface;
6
use Psr\Log\LoggerInterface;
7
use Psr\SimpleCache\CacheInterface;
8
use SilverStripe\Core\Injector\Injector;
9
use Symfony\Component\Cache\Simple\FilesystemCache;
10
use Symfony\Component\Cache\Simple\ApcuCache;
11
use Symfony\Component\Cache\Simple\ChainCache;
12
use Symfony\Component\Cache\Simple\PhpFilesCache;
13
use Symfony\Component\Cache\Adapter\ApcuAdapter;
14
use Symfony\Component\Cache\Adapter\PhpFilesAdapter;
15
16
/**
17
 * Returns the most performant combination of caches available on the system:
18
 * - `PhpFilesCache` (PHP 7 with opcache enabled)
19
 * - `ApcuCache` (requires APC) with a `FilesystemCache` fallback (for larger cache volumes)
20
 * - `FilesystemCache` if none of the above is available
21
 *
22
 * Modelled after `Symfony\Component\Cache\Adapter\AbstractAdapter::createSystemCache()`
23
 */
24
class DefaultCacheFactory implements CacheFactory
25
{
26
    /**
27
     * @var string Absolute directory path
28
     */
29
    protected $args = [];
30
31
    /**
32
     * @var LoggerInterface
33
     */
34
    protected $logger;
35
36
    /**
37
     * @param array $args List of global options to merge with args during create()
38
     * @param LoggerInterface $logger Logger instance to assign
39
     */
40
    public function __construct($args = [], LoggerInterface $logger = null)
41
    {
42
        $this->args = $args;
0 ignored issues
show
Documentation Bug introduced by
It seems like $args of type array is incompatible with the declared type string of property $args.

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...
43
        $this->logger = $logger;
44
    }
45
46
    /**
47
     * @inheritdoc
48
     */
49
    public function create($service, array $args = array())
50
    {
51
        // merge args with default
52
        $args = array_merge($this->args, $args);
53
        $namespace = isset($args['namespace']) ? $args['namespace'] : '';
54
        $defaultLifetime = isset($args['defaultLifetime']) ? $args['defaultLifetime'] : 0;
55
        $directory = isset($args['directory']) ? $args['directory'] : null;
56
        $version = isset($args['version']) ? $args['version'] : null;
57
58
        // Check support
59
        $apcuSupported = $this->isAPCUSupported();
60
        $phpFilesSupported = $this->isPHPFilesSupported();
61
62
        // If apcu isn't supported, phpfiles is the next best preference
63
        if (!$apcuSupported && $phpFilesSupported) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $apcuSupported of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
64
            return $this->createCache(PhpFilesCache::class, [$namespace, $defaultLifetime, $directory]);
65
        }
66
67
        // Create filessytem cache
68
        $fs = $this->createCache(FilesystemCache::class, [$namespace, $defaultLifetime, $directory]);
69
        if (!$apcuSupported) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $apcuSupported of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
70
            return $fs;
71
        }
72
73
        // Chain this cache with ApcuCache
74
        $apcuNamespace = $namespace . ($namespace ? '_' : '') . md5(BASE_PATH);
75
        $apcu = $this->createCache(ApcuCache::class, [$apcuNamespace, (int) $defaultLifetime / 5, $version]);
76
        return $this->createCache(ChainCache::class, [[$apcu, $fs]]);
77
    }
78
79
    /**
80
     * Determine if apcu is supported
81
     *
82
     * @return bool
83
     */
84
    protected function isAPCUSupported()
85
    {
86
        static $apcuSupported = null;
87
        if (null === $apcuSupported) {
88
            $apcuSupported = ApcuAdapter::isSupported();
89
        }
90
        return $apcuSupported;
91
    }
92
93
    /**
94
     * Determine if PHP files is supported
95
     *
96
     * @return bool
97
     */
98
    protected function isPHPFilesSupported()
99
    {
100
        static $phpFilesSupported = null;
101
        if (null === $phpFilesSupported) {
102
            $phpFilesSupported = PhpFilesAdapter::isSupported();
103
        }
104
        return $phpFilesSupported;
105
    }
106
107
    /**
108
     * @param string $class
109
     * @param array $args
110
     * @return CacheInterface
111
     */
112
    protected function createCache($class, $args)
113
    {
114
        /** @var CacheInterface $cache */
115
        $cache = Injector::inst()->createWithArgs($class, $args);
116
117
        // Assign cache logger
118
        if ($this->logger && $cache instanceof LoggerAwareInterface) {
119
            $cache->setLogger($this->logger);
120
        }
121
122
        return $cache;
123
    }
124
}
125