LegacyMongoDBCache   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Test Coverage

Coverage 92.59%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 54
c 1
b 0
f 0
dl 0
loc 154
ccs 50
cts 54
cp 0.9259
rs 10
wmc 18

9 Methods

Rating   Name   Duplication   Size   Complexity  
A isExpired() 0 5 3
A doFlush() 0 6 1
A doContains() 0 16 3
A doGetStats() 0 18 1
A doFetch() 0 16 3
A __construct() 0 4 1
A createExpirationIndex() 0 8 2
A doSave() 0 18 3
A doDelete() 0 5 1
1
<?php
2
3
namespace Doctrine\Common\Cache;
4
5
use MongoBinData;
6
use MongoCollection;
7
use MongoCursorException;
8
use MongoDate;
9
use const E_USER_DEPRECATED;
10
use function serialize;
11
use function time;
12
use function trigger_error;
13
use function unserialize;
14
15
/**
16
 * MongoDB cache provider.
17
 *
18
 * @internal Do not use - will be removed in 2.0. Use MongoDBCache instead
19
 */
20
class LegacyMongoDBCache extends CacheProvider
21
{
22
    /** @var MongoCollection */
23
    private $collection;
24
25
    /** @var bool */
26
    private $expirationIndexCreated = false;
27
28
    /**
29
     * This provider will default to the write concern and read preference
30
     * options set on the MongoCollection instance (or inherited from MongoDB or
31
     * MongoClient). Using an unacknowledged write concern (< 1) may make the
32
     * return values of delete() and save() unreliable. Reading from secondaries
33
     * may make contain() and fetch() unreliable.
34
     *
35
     * @see http://www.php.net/manual/en/mongo.readpreferences.php
36
     * @see http://www.php.net/manual/en/mongo.writeconcerns.php
37
     */
38 79
    public function __construct(MongoCollection $collection)
39
    {
40 79
        @trigger_error('Using the legacy MongoDB cache provider is deprecated and will be removed in 2.0', E_USER_DEPRECATED);
41 79
        $this->collection = $collection;
42 79
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47 77
    protected function doFetch($id)
48
    {
49 77
        $document = $this->collection->findOne(['_id' => $id], [MongoDBCache::DATA_FIELD, MongoDBCache::EXPIRATION_FIELD]);
50
51 77
        if ($document === null) {
52 77
            return false;
53
        }
54
55 65
        if ($this->isExpired($document)) {
56
            $this->createExpirationIndex();
57
            $this->doDelete($id);
58
59
            return false;
60
        }
61
62 65
        return unserialize($document[MongoDBCache::DATA_FIELD]->bin);
63
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68 73
    protected function doContains($id)
69
    {
70 73
        $document = $this->collection->findOne(['_id' => $id], [MongoDBCache::EXPIRATION_FIELD]);
71
72 73
        if ($document === null) {
73 52
            return false;
74
        }
75
76 69
        if ($this->isExpired($document)) {
77 1
            $this->createExpirationIndex();
78 1
            $this->doDelete($id);
79
80 1
            return false;
81
        }
82
83 69
        return true;
84
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89 75
    protected function doSave($id, $data, $lifeTime = 0)
90
    {
91
        try {
92 75
            $result = $this->collection->update(
93 75
                ['_id' => $id],
94
                [
95 75
                    '$set' => [
96 75
                        MongoDBCache::EXPIRATION_FIELD => ($lifeTime > 0 ? new MongoDate(time() + $lifeTime) : null),
97 75
                        MongoDBCache::DATA_FIELD => new MongoBinData(serialize($data), MongoBinData::BYTE_ARRAY),
98
                    ],
99
                ],
100 75
                ['upsert' => true, 'multiple' => false]
101
            );
102 1
        } catch (MongoCursorException $e) {
103 1
            return false;
104
        }
105
106 74
        return ($result['ok'] ?? 1) == 1;
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112 46
    protected function doDelete($id)
113
    {
114 46
        $result = $this->collection->remove(['_id' => $id]);
115
116 46
        return ($result['ok'] ?? 1) == 1;
117
    }
118
119
    /**
120
     * {@inheritdoc}
121
     */
122 2
    protected function doFlush()
123
    {
124
        // Use remove() in lieu of drop() to maintain any collection indexes
125 2
        $result = $this->collection->remove();
126
127 2
        return ($result['ok'] ?? 1) == 1;
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133 1
    protected function doGetStats()
134
    {
135 1
        $serverStatus = $this->collection->db->command([
136 1
            'serverStatus' => 1,
137
            'locks' => 0,
138
            'metrics' => 0,
139
            'recordStats' => 0,
140
            'repl' => 0,
141
        ]);
142
143 1
        $collStats = $this->collection->db->command(['collStats' => 1]);
144
145
        return [
146 1
            Cache::STATS_HITS => null,
147
            Cache::STATS_MISSES => null,
148 1
            Cache::STATS_UPTIME => $serverStatus['uptime'] ?? null,
149 1
            Cache::STATS_MEMORY_USAGE => $collStats['size'] ?? null,
150
            Cache::STATS_MEMORY_AVAILABLE  => null,
151
        ];
152
    }
153
154
    /**
155
     * Check if the document is expired.
156
     *
157
     * @param array $document
158
     */
159 70
    private function isExpired(array $document) : bool
160
    {
161 70
        return isset($document[MongoDBCache::EXPIRATION_FIELD]) &&
162 70
            $document[MongoDBCache::EXPIRATION_FIELD] instanceof MongoDate &&
163 70
            $document[MongoDBCache::EXPIRATION_FIELD]->sec < time();
164
    }
165
166 1
    private function createExpirationIndex() : void
167
    {
168 1
        if ($this->expirationIndexCreated) {
169
            return;
170
        }
171
172 1
        $this->expirationIndexCreated = true;
173 1
        $this->collection->createIndex([MongoDBCache::EXPIRATION_FIELD => 1], ['background' => true, 'expireAfterSeconds' => 0]);
174 1
    }
175
}
176