Completed
Push — master ( 4e5730...4e304d )
by Marco
17s
created

DefaultCacheFactory   B

Complexity

Total Complexity 28

Size/Duplication

Total Lines 227
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 18

Test Coverage

Coverage 83.12%

Importance

Changes 0
Metric Value
wmc 28
lcom 1
cbo 18
dl 0
loc 227
ccs 64
cts 77
cp 0.8312
rs 7.3333
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A setFileLockRegionDirectory() 0 4 1
A getFileLockRegionDirectory() 0 4 1
A setRegion() 0 4 1
A setTimestampRegion() 0 4 1
A buildCachedEntityPersister() 0 19 4
A buildCachedCollectionPersister() 0 19 4
A buildCollectionHydrator() 0 4 1
A buildEntityHydrator() 0 4 1
A buildQueryCache() 0 12 2
B getRegion() 0 29 5
A createRegionCache() 0 18 3
A getTimestampRegion() 0 11 2
A createCache() 0 4 1
1
<?php
2
3
/*
4
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
 *
16
 * This software consists of voluntary contributions made by many individuals
17
 * and is licensed under the MIT license. For more information, see
18
 * <http://www.doctrine-project.org>.
19
 */
20
21
namespace Doctrine\ORM\Cache;
22
23
use Doctrine\Common\Cache\Cache as CacheAdapter;
24
use Doctrine\Common\Cache\CacheProvider;
25
use Doctrine\Common\Cache\MultiGetCache;
26
use Doctrine\ORM\Cache;
27
use Doctrine\ORM\Cache\Persister\Collection\NonStrictReadWriteCachedCollectionPersister;
28
use Doctrine\ORM\Cache\Persister\Collection\ReadOnlyCachedCollectionPersister;
29
use Doctrine\ORM\Cache\Persister\Collection\ReadWriteCachedCollectionPersister;
30
use Doctrine\ORM\Cache\Persister\Entity\NonStrictReadWriteCachedEntityPersister;
31
use Doctrine\ORM\Cache\Persister\Entity\ReadOnlyCachedEntityPersister;
32
use Doctrine\ORM\Cache\Persister\Entity\ReadWriteCachedEntityPersister;
33
use Doctrine\ORM\Cache\Region;
34
use Doctrine\ORM\Cache\Region\DefaultMultiGetRegion;
35
use Doctrine\ORM\Cache\Region\DefaultRegion;
36
use Doctrine\ORM\Cache\Region\FileLockRegion;
37
use Doctrine\ORM\Cache\Region\UpdateTimestampCache;
38
use Doctrine\ORM\EntityManagerInterface;
39
use Doctrine\ORM\Mapping\ClassMetadata;
40
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
41
use Doctrine\ORM\Persisters\Entity\EntityPersister;
42
43
/**
44
 * @since   2.5
45
 * @author  Fabio B. Silva <[email protected]>
46
 */
47
class DefaultCacheFactory implements CacheFactory
48
{
49
    /**
50
     * @var CacheAdapter
51
     */
52
    private $cache;
53
54
    /**
55
     * @var \Doctrine\ORM\Cache\RegionsConfiguration
56
     */
57
    private $regionsConfig;
58
59
    /**
60
     * @var \Doctrine\ORM\Cache\TimestampRegion|null
61
     */
62
    private $timestampRegion;
63
64
    /**
65
     * @var \Doctrine\ORM\Cache\Region[]
66
     */
67
    private $regions = [];
68
69
    /**
70
     * @var string|null
71
     */
72
    private $fileLockRegionDirectory;
73
74
    /**
75
     * @param RegionsConfiguration $cacheConfig
76
     * @param CacheAdapter         $cache
77
     */
78 281
    public function __construct(RegionsConfiguration $cacheConfig, CacheAdapter $cache)
79
    {
80 281
        $this->cache         = $cache;
81 281
        $this->regionsConfig = $cacheConfig;
82 281
    }
83
84
    /**
85
     * @param string $fileLockRegionDirectory
86
     */
87
    public function setFileLockRegionDirectory($fileLockRegionDirectory)
88
    {
89
        $this->fileLockRegionDirectory = (string) $fileLockRegionDirectory;
90
    }
91
92
    /**
93
     * @return string
94
     */
95
    public function getFileLockRegionDirectory()
96
    {
97
        return $this->fileLockRegionDirectory;
98
    }
99
100
    /**
101
     * @param \Doctrine\ORM\Cache\Region $region
102
     */
103
    public function setRegion(Region $region)
104
    {
105
        $this->regions[$region->getName()] = $region;
106
    }
107
108
    /**
109
     * @param \Doctrine\ORM\Cache\TimestampRegion $region
110
     */
111
    public function setTimestampRegion(TimestampRegion $region)
112
    {
113
        $this->timestampRegion = $region;
114
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119 128
    public function buildCachedEntityPersister(EntityManagerInterface $em, EntityPersister $persister, ClassMetadata $metadata)
120
    {
121 128
        $region     = $this->getRegion($metadata->cache);
122 128
        $usage      = $metadata->cache['usage'];
123
124 128
        if ($usage === ClassMetadata::CACHE_USAGE_READ_ONLY) {
125 119
            return new ReadOnlyCachedEntityPersister($persister, $region, $em, $metadata);
126
        }
127
128 92
        if ($usage === ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE) {
129 90
            return new NonStrictReadWriteCachedEntityPersister($persister, $region, $em, $metadata);
130
        }
131
132 2
        if ($usage === ClassMetadata::CACHE_USAGE_READ_WRITE) {
133 1
            return new ReadWriteCachedEntityPersister($persister, $region, $em, $metadata);
0 ignored issues
show
Compatibility introduced by
$region of type object<Doctrine\ORM\Cache\Region> is not a sub-type of object<Doctrine\ORM\Cache\ConcurrentRegion>. It seems like you assume a child interface of the interface Doctrine\ORM\Cache\Region to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
134
        }
135
136 1
        throw new \InvalidArgumentException(sprintf("Unrecognized access strategy type [%s]", $usage));
137
    }
138
139
    /**
140
     * {@inheritdoc}
141
     */
142 81
    public function buildCachedCollectionPersister(EntityManagerInterface $em, CollectionPersister $persister, array $mapping)
143
    {
144 81
        $usage      = $mapping['cache']['usage'];
145 81
        $region     = $this->getRegion($mapping['cache']);
146
147 81
        if ($usage === ClassMetadata::CACHE_USAGE_READ_ONLY) {
148 59
            return new ReadOnlyCachedCollectionPersister($persister, $region, $em, $mapping);
149
        }
150
151 80
        if ($usage === ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE) {
152 78
            return new NonStrictReadWriteCachedCollectionPersister($persister, $region, $em, $mapping);
153
        }
154
155 2
        if ($usage === ClassMetadata::CACHE_USAGE_READ_WRITE) {
156 1
            return new ReadWriteCachedCollectionPersister($persister, $region, $em, $mapping);
0 ignored issues
show
Compatibility introduced by
$region of type object<Doctrine\ORM\Cache\Region> is not a sub-type of object<Doctrine\ORM\Cache\ConcurrentRegion>. It seems like you assume a child interface of the interface Doctrine\ORM\Cache\Region to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
157
        }
158
159 1
        throw new \InvalidArgumentException(sprintf("Unrecognized access strategy type [%s]", $usage));
160
    }
161
162
    /**
163
     * {@inheritdoc}
164
     */
165 63
    public function buildQueryCache(EntityManagerInterface $em, $regionName = null)
166
    {
167 63
        return new DefaultQueryCache(
168
            $em,
169 63
            $this->getRegion(
170
                [
171 63
                    'region' => $regionName ?: Cache::DEFAULT_QUERY_REGION_NAME,
172 63
                    'usage'  => ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE
173
                ]
174
            )
175
        );
176
    }
177
178
    /**
179
     * {@inheritdoc}
180
     */
181 117
    public function buildCollectionHydrator(EntityManagerInterface $em, array $mapping)
182
    {
183 117
        return new DefaultCollectionHydrator($em);
184
    }
185
186
    /**
187
     * {@inheritdoc}
188
     */
189 205
    public function buildEntityHydrator(EntityManagerInterface $em, ClassMetadata $metadata)
190
    {
191 205
        return new DefaultEntityHydrator($em);
192
    }
193
194
    /**
195
     * {@inheritdoc}
196
     */
197 131
    public function getRegion(array $cache)
198
    {
199 131
        if (isset($this->regions[$cache['region']])) {
200 25
            return $this->regions[$cache['region']];
201
        }
202
203 131
        $name         = $cache['region'];
204 131
        $cacheAdapter = $this->createRegionCache($name);
205 131
        $lifetime     = $this->regionsConfig->getLifetime($cache['region']);
206
207 131
        $region = ($cacheAdapter instanceof MultiGetCache)
208 130
            ? new DefaultMultiGetRegion($name, $cacheAdapter, $lifetime)
209 131
            : new DefaultRegion($name, $cacheAdapter, $lifetime);
210
211 131
        if ($cache['usage'] === ClassMetadata::CACHE_USAGE_READ_WRITE) {
212
213 1
            if ( ! $this->fileLockRegionDirectory) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fileLockRegionDirectory of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
214 1
                throw new \LogicException(
215
                    'If you want to use a "READ_WRITE" cache an implementation of "Doctrine\ORM\Cache\ConcurrentRegion" is required, ' .
216 1
                    'The default implementation provided by doctrine is "Doctrine\ORM\Cache\Region\FileLockRegion" if you want to use it please provide a valid directory, DefaultCacheFactory#setFileLockRegionDirectory(). '
217
                );
218
            }
219
220
            $directory = $this->fileLockRegionDirectory . DIRECTORY_SEPARATOR . $cache['region'];
221
            $region    = new FileLockRegion($region, $directory, $this->regionsConfig->getLockLifetime($cache['region']));
222
        }
223
224 130
        return $this->regions[$cache['region']] = $region;
225
    }
226
227
    /**
228
     * @param string $name
229
     *
230
     * @return CacheAdapter
231
     */
232 131
    private function createRegionCache($name)
233
    {
234 131
        $cacheAdapter = clone $this->cache;
235
236 131
        if (!$cacheAdapter instanceof CacheProvider) {
237 1
            return $cacheAdapter;
238
        }
239
240 130
        $namespace = $cacheAdapter->getNamespace();
241
242 130
        if ('' !== $namespace) {
243 1
            $namespace .= ':';
244
        }
245
246 130
        $cacheAdapter->setNamespace($namespace . $name);
247
248 130
        return $cacheAdapter;
249
    }
250
251
    /**
252
     * {@inheritdoc}
253
     */
254 219
    public function getTimestampRegion()
255
    {
256 219
        if ($this->timestampRegion === null) {
257 219
            $name     = Cache::DEFAULT_TIMESTAMP_REGION_NAME;
258 219
            $lifetime = $this->regionsConfig->getLifetime($name);
259
260 219
            $this->timestampRegion = new UpdateTimestampCache($name, clone $this->cache, $lifetime);
261
        }
262
263 219
        return $this->timestampRegion;
264
    }
265
266
    /**
267
     * {@inheritdoc}
268
     */
269 281
    public function createCache(EntityManagerInterface $em)
270
    {
271 281
        return new DefaultCache($em);
272
    }
273
}
274