Passed
Pull Request — master (#251)
by Gabriel
10:21
created

LegacyMongoDBCache::doDelete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 9.4285
c 0
b 0
f 0
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
            return false;
59
        }
60
61 65
        return unserialize($document[MongoDBCache::DATA_FIELD]->bin);
62
    }
63
64
    /**
65
     * {@inheritdoc}
66
     */
67 73
    protected function doContains($id)
68
    {
69 73
        $document = $this->collection->findOne(['_id' => $id], [MongoDBCache::EXPIRATION_FIELD]);
70
71 73
        if ($document === null) {
72 52
            return false;
73
        }
74
75 69
        if ($this->isExpired($document)) {
76 1
            $this->createExpirationIndex();
77 1
            $this->doDelete($id);
78 1
            return false;
79
        }
80
81 69
        return true;
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87 75
    protected function doSave($id, $data, $lifeTime = 0)
88
    {
89
        try {
90 75
            $result = $this->collection->update(
91 75
                ['_id' => $id],
92
                [
93 75
                    '$set' => [
94 75
                        MongoDBCache::EXPIRATION_FIELD => ($lifeTime > 0 ? new MongoDate(time() + $lifeTime) : null),
95 75
                        MongoDBCache::DATA_FIELD => new MongoBinData(serialize($data), MongoBinData::BYTE_ARRAY),
96
                    ],
97
                ],
98 75
                ['upsert' => true, 'multiple' => false]
99
            );
100 1
        } catch (MongoCursorException $e) {
101 1
            return false;
102
        }
103
104 74
        return ($result['ok'] ?? 1) == 1;
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110 46
    protected function doDelete($id)
111
    {
112 46
        $result = $this->collection->remove(['_id' => $id]);
113
114 46
        return ($result['ok'] ?? 1) == 1;
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120 2
    protected function doFlush()
121
    {
122
        // Use remove() in lieu of drop() to maintain any collection indexes
123 2
        $result = $this->collection->remove();
124
125 2
        return ($result['ok'] ?? 1) == 1;
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131 1
    protected function doGetStats()
132
    {
133 1
        $serverStatus = $this->collection->db->command([
134 1
            'serverStatus' => 1,
135
            'locks' => 0,
136
            'metrics' => 0,
137
            'recordStats' => 0,
138
            'repl' => 0,
139
        ]);
140
141 1
        $collStats = $this->collection->db->command(['collStats' => 1]);
142
143
        return [
144 1
            Cache::STATS_HITS => null,
145
            Cache::STATS_MISSES => null,
146 1
            Cache::STATS_UPTIME => $serverStatus['uptime'] ?? null,
147 1
            Cache::STATS_MEMORY_USAGE => $collStats['size'] ?? null,
148
            Cache::STATS_MEMORY_AVAILABLE  => null,
149
        ];
150
    }
151
152
    /**
153
     * Check if the document is expired.
154
     *
155
     * @param array $document
156
     */
157 70
    private function isExpired(array $document) : bool
158
    {
159 70
        return isset($document[MongoDBCache::EXPIRATION_FIELD]) &&
160 70
            $document[MongoDBCache::EXPIRATION_FIELD] instanceof MongoDate &&
161 70
            $document[MongoDBCache::EXPIRATION_FIELD]->sec < time();
162
    }
163
164
165 1
    private function createExpirationIndex() : void
166
    {
167 1
        if ($this->expirationIndexCreated) {
168
            return;
169
        }
170
171 1
        $this->expirationIndexCreated = true;
172 1
        $this->collection->createIndex([MongoDBCache::EXPIRATION_FIELD => 1], ['background' => true, 'expireAfterSeconds' => 0]);
173 1
    }
174
}
175