75fe0ca113049f8b1278559f0e89f6d58c6c1d3d
[yaffs-website] / vendor / doctrine / cache / lib / Doctrine / Common / Cache / MongoDBCache.php
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  * @since  1.1
31  * @author Jeremy Mikola <jmikola@gmail.com>
32  */
33 class MongoDBCache extends CacheProvider
34 {
35     /**
36      * The data field will store the serialized PHP value.
37      */
38     const DATA_FIELD = 'd';
39
40     /**
41      * The expiration field will store a MongoDate value indicating when the
42      * cache entry should expire.
43      *
44      * With MongoDB 2.2+, entries can be automatically deleted by MongoDB by
45      * indexing this field with the "expireAfterSeconds" option equal to zero.
46      * This will direct MongoDB to regularly query for and delete any entries
47      * whose date is older than the current time. Entries without a date value
48      * in this field will be ignored.
49      *
50      * The cache provider will also check dates on its own, in case expired
51      * entries are fetched before MongoDB's TTLMonitor pass can expire them.
52      *
53      * @see http://docs.mongodb.org/manual/tutorial/expire-data/
54      */
55     const EXPIRATION_FIELD = 'e';
56
57     /**
58      * @var MongoCollection
59      */
60     private $collection;
61
62     /**
63      * Constructor.
64      *
65      * This provider will default to the write concern and read preference
66      * options set on the MongoCollection instance (or inherited from MongoDB or
67      * MongoClient). Using an unacknowledged write concern (< 1) may make the
68      * return values of delete() and save() unreliable. Reading from secondaries
69      * may make contain() and fetch() unreliable.
70      *
71      * @see http://www.php.net/manual/en/mongo.readpreferences.php
72      * @see http://www.php.net/manual/en/mongo.writeconcerns.php
73      * @param MongoCollection $collection
74      */
75     public function __construct(MongoCollection $collection)
76     {
77         $this->collection = $collection;
78     }
79
80     /**
81      * {@inheritdoc}
82      */
83     protected function doFetch($id)
84     {
85         $document = $this->collection->findOne(array('_id' => $id), array(self::DATA_FIELD, self::EXPIRATION_FIELD));
86
87         if ($document === null) {
88             return false;
89         }
90
91         if ($this->isExpired($document)) {
92             $this->doDelete($id);
93             return false;
94         }
95
96         return unserialize($document[self::DATA_FIELD]->bin);
97     }
98
99     /**
100      * {@inheritdoc}
101      */
102     protected function doContains($id)
103     {
104         $document = $this->collection->findOne(array('_id' => $id), array(self::EXPIRATION_FIELD));
105
106         if ($document === null) {
107             return false;
108         }
109
110         if ($this->isExpired($document)) {
111             $this->doDelete($id);
112             return false;
113         }
114
115         return true;
116     }
117
118     /**
119      * {@inheritdoc}
120      */
121     protected function doSave($id, $data, $lifeTime = 0)
122     {
123         try {
124             $result = $this->collection->update(
125                 array('_id' => $id),
126                 array('$set' => array(
127                     self::EXPIRATION_FIELD => ($lifeTime > 0 ? new MongoDate(time() + $lifeTime) : null),
128                     self::DATA_FIELD => new MongoBinData(serialize($data), MongoBinData::BYTE_ARRAY),
129                 )),
130                 array('upsert' => true, 'multiple' => false)
131             );
132         } catch (MongoCursorException $e) {
133             return false;
134         }
135
136         return isset($result['ok']) ? $result['ok'] == 1 : true;
137     }
138
139     /**
140      * {@inheritdoc}
141      */
142     protected function doDelete($id)
143     {
144         $result = $this->collection->remove(array('_id' => $id));
145
146         return isset($result['ok']) ? $result['ok'] == 1 : true;
147     }
148
149     /**
150      * {@inheritdoc}
151      */
152     protected function doFlush()
153     {
154         // Use remove() in lieu of drop() to maintain any collection indexes
155         $result = $this->collection->remove();
156
157         return isset($result['ok']) ? $result['ok'] == 1 : true;
158     }
159
160     /**
161      * {@inheritdoc}
162      */
163     protected function doGetStats()
164     {
165         $serverStatus = $this->collection->db->command(array(
166             'serverStatus' => 1,
167             'locks' => 0,
168             'metrics' => 0,
169             'recordStats' => 0,
170             'repl' => 0,
171         ));
172
173         $collStats = $this->collection->db->command(array('collStats' => 1));
174
175         return array(
176             Cache::STATS_HITS => null,
177             Cache::STATS_MISSES => null,
178             Cache::STATS_UPTIME => (isset($serverStatus['uptime']) ? (int) $serverStatus['uptime'] : null),
179             Cache::STATS_MEMORY_USAGE => (isset($collStats['size']) ? (int) $collStats['size'] : null),
180             Cache::STATS_MEMORY_AVAILABLE  => null,
181         );
182     }
183
184     /**
185      * Check if the document is expired.
186      *
187      * @param array $document
188      *
189      * @return bool
190      */
191     private function isExpired(array $document)
192     {
193         return isset($document[self::EXPIRATION_FIELD]) &&
194             $document[self::EXPIRATION_FIELD] instanceof MongoDate &&
195             $document[self::EXPIRATION_FIELD]->sec < time();
196     }
197 }