3 +---------------------------------------------------------------------------------+
4 | Copyright (c) 2010 ActiveMongo |
5 +---------------------------------------------------------------------------------+
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met: |
8 | 1. Redistributions of source code must retain the above copyright |
9 | notice, this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
15 | 3. All advertising materials mentioning features or use of this software |
16 | must display the following acknowledgement: |
17 | This product includes software developed by César D. Rodas. |
19 | 4. Neither the name of the César D. Rodas nor the |
20 | names of its contributors may be used to endorse or promote products |
21 | derived from this software without specific prior written permission. |
23 | THIS SOFTWARE IS PROVIDED BY CÉSAR D. RODAS ''AS IS'' AND ANY |
24 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
25 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
26 | DISCLAIMED. IN NO EVENT SHALL CÉSAR D. RODAS BE LIABLE FOR ANY |
27 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
28 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
30 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE |
33 +---------------------------------------------------------------------------------+
34 | Authors: César Rodas <crodas@php.net> |
35 +---------------------------------------------------------------------------------+
39 * Cursor used for cached items
41 class CacheCursor
Extends MongoCursor
47 function __construct()
51 function setResultArray(Array $array)
53 $this->var = array_values($array);
54 $this->size
= count($array);
65 return (string)$this->var[$this->pos
]['_id'];
70 if (!$this->valid()) {
73 return $this->var[$this->pos
];
83 return isset($this->var[$this->pos
]);
95 return $this->var[$this->pos
];
100 return count($this->var);
109 abstract class CacheDriver
114 * serialize -- by default with BSON
116 * @param object $object
120 function serialize($object)
122 return bson_encode($object);
126 * deserialize -- by default with BSON
128 * @param string $string
132 function deserialize($string)
134 return bson_decode($string);
138 abstract function get($key, &$object);
140 abstract function set($key, $document, $ttl);
142 function getMulti(Array $keys, Array &$object)
144 foreach ($keys as $key) {
145 if ($this->get($key, $object[$key]) === FALSE) {
146 $object[$key] = FALSE;
151 function setMulti(Array $objects, Array $ttl)
153 foreach ($objects as $id => $value) {
154 if (!isset($ttl[$id])) {
157 $this->set($id, $value, $ttl[$id]);
161 abstract function delete(Array $key);
164 final class ActiveMongo_Cache
166 private static $instance;
170 private function __construct()
172 ActiveMongo
::addEvent('before_query', array($this, 'QueryRead'));
173 ActiveMongo
::addEvent('after_query', array($this, 'QuerySave'));
174 ActiveMongo
::addEvent('after_create', array($this, 'UpdateHook'));
175 ActiveMongo
::addEvent('after_update', array($this, 'UpdateHook'));
178 public static function Init()
180 if (self
::$instance) {
183 self
::$instance = new ActiveMongo_Cache
;
186 public static function setDriver(CacheDriver
$driver)
189 self
::$instance->driver
= $driver;
192 public static function enable()
195 self
::$instance->enabled
= TRUE;
198 public static function disable()
201 self
::$instance->enabled
= FALSE;
204 final protected function hasCache($class)
206 if (!$this->driver
InstanceOf CacheDriver
) {
209 $enable = isset($class::$cacheable) ?
$class::$cacheable : $this->enabled
;
213 final protected function getQueryID($query_document)
215 /* TODO: Peform some sort of sorting */
216 /* to treat queries with same parameters but */
217 /* different order equal */
219 $id = $this->driver
->serialize($query_document);
227 function QueryRead($class, $query_document, &$resultset)
229 if (!$this->hasCache($class)) {
233 $query_id = $this->getQueryID($query_document);
235 if ($this->driver
->get($query_id, $query_result) === FALSE) {
239 if (!is_array($query_result) ||
count($query_result) == 0) {
246 $cache_ids = array_combine(array_keys($query_result), array_keys($query_result));
247 $this->driver
->getMulti($cache_ids, $result);
249 foreach ($result as $id => $doc) {
250 if (!is_array($doc)) {
255 if (count($toquery) > 0) {
257 $db->where('_id IN', array_values($toquery));
258 foreach ($db as $doc) {
259 foreach ($toquery as $id) {
260 if ($id == $doc['_id']) {
268 $resultset = new CacheCursor
;
269 $resultset->setResultArray($result);
271 /* Return FALSE to prevent the execution of
272 * any hook similar hook
281 function QuerySave($class, $query_document, $cursor)
283 if (!$this->hasCache($class)) {
287 $query_id = $this->getQueryID($query_document);
292 foreach ($cursor as $id=>$document) {
293 $ids[$id] = $document['_id'];
294 $docs[$id] = $document;
298 $this->driver
->setMulti($docs, $ttl);
299 $this->driver
->set($query_id, $ids, 3600);
302 // UpdateHook($class, $document, $obj) {{{
306 * Save or Replace an object (document)
309 * @param string $class Class name
310 * @param object $document Document sent to mongodb
311 * @param object $obj ActiveMongo Object
315 function UpdateHook($class, $document, $obj)
317 if (!$this->hasCache($class)) {
321 if (!isset($obj['_id'])) {
322 if (!isset($document['_id'])) {
323 return; /* Weird condition */
325 $obj['_id'] = $document['_id'];
328 $this->driver
->set((string)$obj['_id'], $obj, 3600);
334 ActiveMongo_Cache
::Init();
341 * vim600: sw=4 ts=4 fdm=marker