Passed
Push — master ( 5c1ad9...58f408 )
by Marco
05:40
created

LegacyMongoDBCache::doDelete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
crap 1
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\Common\Cache;
21
22
use MongoBinData;
23
use MongoCollection;
24
use MongoCursorException;
25
use MongoDate;
26
27
/**
28
 * MongoDB cache provider.
29
 *
30
 * @author Jeremy Mikola <[email protected]>
31
 * @internal Do not use - will be removed in 2.0. Use MongoDBCache instead
32
 */
33
class LegacyMongoDBCache extends CacheProvider
34
{
35
    /**
36
     * @var MongoCollection
37
     */
38
    private $collection;
39
40
    /**
41
     * @var bool
42
     */
43
    private $expirationIndexCreated = false;
44
45
    /**
46
     * Constructor.
47
     *
48
     * This provider will default to the write concern and read preference
49
     * options set on the MongoCollection instance (or inherited from MongoDB or
50
     * MongoClient). Using an unacknowledged write concern (< 1) may make the
51
     * return values of delete() and save() unreliable. Reading from secondaries
52
     * may make contain() and fetch() unreliable.
53
     *
54
     * @see http://www.php.net/manual/en/mongo.readpreferences.php
55
     * @see http://www.php.net/manual/en/mongo.writeconcerns.php
56
     * @param MongoCollection $collection
57
     */
58 78
    public function __construct(MongoCollection $collection)
59
    {
60 78
        @trigger_error('Using the legacy MongoDB cache provider is deprecated and will be removed in 2.0', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
61 78
        $this->collection = $collection;
62 78
    }
63
64
    /**
65
     * {@inheritdoc}
66
     */
67 76
    protected function doFetch($id)
68
    {
69 76
        $document = $this->collection->findOne(['_id' => $id], [MongoDBCache::DATA_FIELD, MongoDBCache::EXPIRATION_FIELD]);
70
71 76
        if ($document === null) {
72 76
            return false;
73
        }
74
75 64
        if ($this->isExpired($document)) {
76
            $this->createExpirationIndex();
77
            $this->doDelete($id);
78
            return false;
79
        }
80
81 64
        return unserialize($document[MongoDBCache::DATA_FIELD]->bin);
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87 72
    protected function doContains($id)
88
    {
89 72
        $document = $this->collection->findOne(['_id' => $id], [MongoDBCache::EXPIRATION_FIELD]);
90
91 72
        if ($document === null) {
92 52
            return false;
93
        }
94
95 68
        if ($this->isExpired($document)) {
96 1
            $this->createExpirationIndex();
97 1
            $this->doDelete($id);
98 1
            return false;
99
        }
100
101 68
        return true;
102
    }
103
104
    /**
105
     * {@inheritdoc}
106
     */
107 74
    protected function doSave($id, $data, $lifeTime = 0)
108
    {
109
        try {
110 74
            $result = $this->collection->update(
111 74
                ['_id' => $id],
112 74
                ['$set' => [
113 74
                    MongoDBCache::EXPIRATION_FIELD => ($lifeTime > 0 ? new MongoDate(time() + $lifeTime) : null),
114 74
                    MongoDBCache::DATA_FIELD => new MongoBinData(serialize($data), MongoBinData::BYTE_ARRAY),
115
                ]],
116 74
                ['upsert' => true, 'multiple' => false]
117
            );
118 1
        } catch (MongoCursorException $e) {
119 1
            return false;
120
        }
121
122 73
        return ($result['ok'] ?? 1) == 1;
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128 46
    protected function doDelete($id)
129
    {
130 46
        $result = $this->collection->remove(['_id' => $id]);
131
132 46
        return ($result['ok'] ?? 1) == 1;
133
    }
134
135
    /**
136
     * {@inheritdoc}
137
     */
138 2
    protected function doFlush()
139
    {
140
        // Use remove() in lieu of drop() to maintain any collection indexes
141 2
        $result = $this->collection->remove();
142
143 2
        return ($result['ok'] ?? 1) == 1;
144
    }
145
146
    /**
147
     * {@inheritdoc}
148
     */
149 1
    protected function doGetStats()
150
    {
151 1
        $serverStatus = $this->collection->db->command([
152 1
            'serverStatus' => 1,
153
            'locks' => 0,
154
            'metrics' => 0,
155
            'recordStats' => 0,
156
            'repl' => 0,
157
        ]);
158
159 1
        $collStats = $this->collection->db->command(['collStats' => 1]);
160
161
        return [
162 1
            Cache::STATS_HITS => null,
163 1
            Cache::STATS_MISSES => null,
164 1
            Cache::STATS_UPTIME => $serverStatus['uptime'] ?? null,
165 1
            Cache::STATS_MEMORY_USAGE => $collStats['size'] ?? null,
166 1
            Cache::STATS_MEMORY_AVAILABLE  => null,
167
        ];
168
    }
169
170
    /**
171
     * Check if the document is expired.
172
     *
173
     * @param array $document
174
     *
175
     * @return bool
176
     */
177 69
    private function isExpired(array $document) : bool
178
    {
179 69
        return isset($document[MongoDBCache::EXPIRATION_FIELD]) &&
180 2
            $document[MongoDBCache::EXPIRATION_FIELD] instanceof MongoDate &&
181 69
            $document[MongoDBCache::EXPIRATION_FIELD]->sec < time();
182
    }
183
184
185 1
    private function createExpirationIndex(): void
186
    {
187 1
        if ($this->expirationIndexCreated) {
188
            return;
189
        }
190
191 1
        $this->expirationIndexCreated = true;
192 1
        $this->collection->createIndex([MongoDBCache::EXPIRATION_FIELD => 1], ['background' => true, 'expireAfterSeconds' => 0]);
193 1
    }
194
}
195