Completed
Pull Request — 2.8.x (#7984)
by Niko
62:21
created

DefaultCacheFactory::getRegion()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 38
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 8.1039

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 22
c 1
b 0
f 1
dl 0
loc 38
ccs 15
cts 17
cp 0.8824
rs 8.4444
cc 8
nc 8
nop 1
crap 8.1039
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\DefaultMultiGetRegion;
34
use Doctrine\ORM\Cache\Region\DefaultRegion;
35
use Doctrine\ORM\Cache\Region\FileLockRegion;
36
use Doctrine\ORM\Cache\Region\UpdateTimestampCache;
37
use Doctrine\ORM\EntityManagerInterface;
38
use Doctrine\ORM\Mapping\ClassMetadata;
39
use Doctrine\ORM\Persisters\Collection\CollectionPersister;
40
use Doctrine\ORM\Persisters\Entity\EntityPersister;
41
42
/**
43
 * @since   2.5
44
 * @author  Fabio B. Silva <[email protected]>
45
 */
46
class DefaultCacheFactory implements CacheFactory
47
{
48
    /**
49
     * @var CacheAdapter
50
     */
51
    private $cache;
52
53
    /**
54
     * @var \Doctrine\ORM\Cache\RegionsConfiguration
55
     */
56
    private $regionsConfig;
57
58
    /**
59
     * @var \Doctrine\ORM\Cache\TimestampRegion|null
60
     */
61
    private $timestampRegion;
62
63
    /**
64
     * @var \Doctrine\ORM\Cache\Region[]
65
     */
66
    private $regions = [];
67
68
    /**
69
     * @var string|null
70
     */
71
    private $fileLockRegionDirectory;
72
73
    /**
74
     * @param RegionsConfiguration $cacheConfig
75
     * @param CacheAdapter         $cache
76
     */
77 288
    public function __construct(RegionsConfiguration $cacheConfig, CacheAdapter $cache)
78
    {
79 288
        $this->cache         = $cache;
80 288
        $this->regionsConfig = $cacheConfig;
81 288
    }
82
83
    /**
84
     * @param string $fileLockRegionDirectory
85
     */
86 1
    public function setFileLockRegionDirectory($fileLockRegionDirectory)
87
    {
88 1
        $this->fileLockRegionDirectory = (string) $fileLockRegionDirectory;
89 1
    }
90
91
    /**
92
     * @return string
93
     */
94
    public function getFileLockRegionDirectory()
95
    {
96
        return $this->fileLockRegionDirectory;
97
    }
98
99
    /**
100
     * @param \Doctrine\ORM\Cache\Region $region
101
     */
102
    public function setRegion(Region $region)
103
    {
104
        $this->regions[$region->getName()] = $region;
105
    }
106
107
    /**
108
     * @param \Doctrine\ORM\Cache\TimestampRegion $region
109
     */
110
    public function setTimestampRegion(TimestampRegion $region)
111
    {
112
        $this->timestampRegion = $region;
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118 134
    public function buildCachedEntityPersister(EntityManagerInterface $em, EntityPersister $persister, ClassMetadata $metadata)
119
    {
120 134
        $region     = $this->getRegion($metadata->cache);
121 134
        $usage      = $metadata->cache['usage'];
122
123 134
        if ($usage === ClassMetadata::CACHE_USAGE_READ_ONLY) {
124 122
            return new ReadOnlyCachedEntityPersister($persister, $region, $em, $metadata);
125
        }
126
127 95
        if ($usage === ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE) {
128 93
            return new NonStrictReadWriteCachedEntityPersister($persister, $region, $em, $metadata);
129
        }
130
131 2
        if ($usage === ClassMetadata::CACHE_USAGE_READ_WRITE) {
132 1
            return new ReadWriteCachedEntityPersister($persister, $region, $em, $metadata);
133
        }
134
135 1
        throw new \InvalidArgumentException(sprintf("Unrecognized access strategy type [%s]", $usage));
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141 81
    public function buildCachedCollectionPersister(EntityManagerInterface $em, CollectionPersister $persister, array $mapping)
142
    {
143 81
        $usage      = $mapping['cache']['usage'];
144 81
        $region     = $this->getRegion($mapping['cache']);
145
146 81
        if ($usage === ClassMetadata::CACHE_USAGE_READ_ONLY) {
147 59
            return new ReadOnlyCachedCollectionPersister($persister, $region, $em, $mapping);
148
        }
149
150 80
        if ($usage === ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE) {
151 78
            return new NonStrictReadWriteCachedCollectionPersister($persister, $region, $em, $mapping);
152
        }
153
154 2
        if ($usage === ClassMetadata::CACHE_USAGE_READ_WRITE) {
155 1
            return new ReadWriteCachedCollectionPersister($persister, $region, $em, $mapping);
156
        }
157
158 1
        throw new \InvalidArgumentException(sprintf("Unrecognized access strategy type [%s]", $usage));
159
    }
160
161
    /**
162
     * {@inheritdoc}
163
     */
164 64
    public function buildQueryCache(EntityManagerInterface $em, $regionName = null)
165
    {
166 64
        return new DefaultQueryCache(
167 64
            $em,
168 64
            $this->getRegion(
169
                [
170 64
                    'region' => $regionName ?: Cache::DEFAULT_QUERY_REGION_NAME,
171 64
                    'usage'  => ClassMetadata::CACHE_USAGE_NONSTRICT_READ_WRITE
172
                ]
173
            )
174
        );
175
    }
176
177
    /**
178
     * {@inheritdoc}
179
     */
180 117
    public function buildCollectionHydrator(EntityManagerInterface $em, array $mapping)
181
    {
182 117
        return new DefaultCollectionHydrator($em);
183
    }
184
185
    /**
186
     * {@inheritdoc}
187
     */
188 211
    public function buildEntityHydrator(EntityManagerInterface $em, ClassMetadata $metadata)
189
    {
190 211
        return new DefaultEntityHydrator($em);
191
    }
192
193
    /**
194
     * {@inheritdoc}
195
     */
196 136
    public function getRegion(array $cache)
197
    {
198 136
        if (isset($this->regions[$cache['region']])) {
199 26
            $region = $this->regions[$cache['region']];
200
            if ($cache['usage'] === ClassMetadata::CACHE_USAGE_READ_WRITE &&
201
                !($region instanceof ConcurrentRegion)
202 136
            ) {
203 136
                throw new \LogicException('If you want to use a "READ_WRITE" cache an implementation of "Doctrine\ORM\Cache\ConcurrentRegion" is required');
204 136
            }
205
206 136
            return $region;
207 135
        }
208 136
209
        $name         = $cache['region'];
210 136
        $cacheAdapter = $this->createRegionCache($name);
211
        $lifetime     = $this->regionsConfig->getLifetime($cache['region']);
212
213 2
        $region = ($cacheAdapter instanceof MultiGetCache)
214 2
            ? new DefaultMultiGetRegion($name, $cacheAdapter, $lifetime)
215
            : new DefaultRegion($name, $cacheAdapter, $lifetime);
216 2
217
        if ($cache['usage'] === ClassMetadata::CACHE_USAGE_READ_WRITE) {
218 2
219
            if (
220
                '' === $this->fileLockRegionDirectory ||
221
                null === $this->fileLockRegionDirectory
222
            ) {
223
                throw new \LogicException(
224
                    'If you want to use a "READ_WRITE" cache an implementation of "Doctrine\ORM\Cache\ConcurrentRegion" is required, ' .
225
                    '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(). '
226 134
                );
227
            }
228
229
            $directory = $this->fileLockRegionDirectory . DIRECTORY_SEPARATOR . $cache['region'];
230
            $region    = new FileLockRegion($region, $directory, $this->regionsConfig->getLockLifetime($cache['region']));
231
        }
232
233
        return $this->regions[$cache['region']] = $region;
234 136
    }
235
236 136
    /**
237
     * @param string $name
238 136
     *
239 1
     * @return CacheAdapter
240
     */
241
    private function createRegionCache($name)
242 135
    {
243
        $cacheAdapter = clone $this->cache;
244 135
245 1
        if (!$cacheAdapter instanceof CacheProvider) {
246
            return $cacheAdapter;
247
        }
248 135
249
        $namespace = $cacheAdapter->getNamespace();
250 135
251
        if ('' !== $namespace) {
252
            $namespace .= ':';
253
        }
254
255
        $cacheAdapter->setNamespace($namespace . $name);
256 225
257
        return $cacheAdapter;
258 225
    }
259 225
260 225
    /**
261
     * {@inheritdoc}
262 225
     */
263
    public function getTimestampRegion()
264
    {
265 225
        if ($this->timestampRegion === null) {
266
            $name     = Cache::DEFAULT_TIMESTAMP_REGION_NAME;
267
            $lifetime = $this->regionsConfig->getLifetime($name);
268
269
            $this->timestampRegion = new UpdateTimestampCache($name, clone $this->cache, $lifetime);
270
        }
271 288
272
        return $this->timestampRegion;
273 288
    }
274
275
    /**
276
     * {@inheritdoc}
277
     */
278
    public function createCache(EntityManagerInterface $em)
279
    {
280
        return new DefaultCache($em);
281
    }
282
}
283