[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/horde/framework/Horde/Imap/Client/Cache/Backend/ -> Mongo.php (source)

   1  <?php
   2  /**
   3   * Copyright 2013-2014 Horde LLC (http://www.horde.org/)
   4   *
   5   * See the enclosed file COPYING for license information (LGPL). If you
   6   * did not receive this file, see http://www.horde.org/licenses/lgpl21.
   7   *
   8   * @category  Horde
   9   * @copyright 2013-2014 Horde LLC
  10   * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
  11   * @package   Imap_Client
  12   */
  13  
  14  /**
  15   * A MongoDB database implementation for caching IMAP/POP data.
  16   * Requires the Horde_Mongo class.
  17   *
  18   * @author    Michael Slusarz <slusarz@horde.org>
  19   * @category  Horde
  20   * @copyright 2013-2014 Horde LLC
  21   * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
  22   * @package   Imap_Client
  23   */
  24  class Horde_Imap_Client_Cache_Backend_Mongo extends Horde_Imap_Client_Cache_Backend implements Horde_Mongo_Collection_Index
  25  {
  26      /** Mongo collection names. */
  27      const BASE = 'horde_imap_client_cache_data';
  28      const MD = 'horde_imap_client_cache_metadata';
  29      const MSG = 'horde_imap_client_cache_message';
  30  
  31      /** Mongo field names: BASE collection. */
  32      const BASE_HOSTSPEC = 'hostspec';
  33      const BASE_MAILBOX = 'mailbox';
  34      const BASE_MODIFIED = 'modified';
  35      const BASE_PORT = 'port';
  36      const BASE_UID = 'data';
  37      const BASE_USERNAME = 'username';
  38  
  39      /** Mongo field names: MD collection. */
  40      const MD_DATA = 'data';
  41      const MD_FIELD = 'field';
  42      const MD_UID = 'uid';
  43  
  44      /** Mongo field names: MSG collection. */
  45      const MSG_DATA = 'data';
  46      const MSG_MSGUID = 'msguid';
  47      const MSG_UID = 'uid';
  48  
  49      /**
  50       * The MongoDB object for the cache data.
  51       *
  52       * @var MongoDB
  53       */
  54      protected $_db;
  55  
  56      /**
  57       * The list of indices.
  58       *
  59       * @var array
  60       */
  61      protected $_indices = array(
  62          self::BASE => array(
  63              'base_index_1' => array(
  64                  self::BASE_HOSTSPEC => 1,
  65                  self::BASE_MAILBOX => 1,
  66                  self::BASE_PORT => 1,
  67                  self::BASE_USERNAME => 1,
  68              )
  69          ),
  70          self::MSG => array(
  71              'msg_index_1' => array(
  72                  self::MSG_MSGUID => 1,
  73                  self::MSG_UID => 1
  74              )
  75          )
  76      );
  77  
  78      /**
  79       * Constructor.
  80       *
  81       * @param array $params  Configuration parameters:
  82       * <pre>
  83       *   - REQUIRED parameters:
  84       *     - mongo_db: (Horde_Mongo_Client) A MongoDB client object.
  85       * </pre>
  86       */
  87      public function __construct(array $params = array())
  88      {
  89          if (!isset($params['mongo_db'])) {
  90              throw new InvalidArgumentException('Missing mongo_db parameter.');
  91          }
  92  
  93          parent::__construct($params);
  94      }
  95  
  96      /**
  97       */
  98      protected function _initOb()
  99      {
 100          $this->_db = $this->_params['mongo_db']->selectDB(null);
 101      }
 102  
 103      /**
 104       */
 105      public function get($mailbox, $uids, $fields, $uidvalid)
 106      {
 107          $this->getMetaData($mailbox, $uidvalid, array('uidvalid'));
 108  
 109          if (!($uid = $this->_getUid($mailbox))) {
 110              return array();
 111          }
 112  
 113          $out = array();
 114          $query = array(
 115              self::MSG_MSGUID => array('$in' => array_map('strval', $uids)),
 116              self::MSG_UID => $uid
 117          );
 118  
 119          try {
 120              $cursor = $this->_db->selectCollection(self::MSG)->find(
 121                  $query,
 122                  array(
 123                      self::MSG_DATA => true,
 124                      self::MSG_MSGUID => true
 125                  )
 126              );
 127              foreach ($cursor as $val) {
 128                  $out[$val[self::MSG_MSGUID]] = $this->_value($val[self::MSG_DATA]);
 129              }
 130          } catch (MongoException $e) {}
 131  
 132          return $out;
 133      }
 134  
 135      /**
 136       */
 137      public function getCachedUids($mailbox, $uidvalid)
 138      {
 139          $this->getMetaData($mailbox, $uidvalid, array('uidvalid'));
 140  
 141          if (!($uid = $this->_getUid($mailbox))) {
 142              return array();
 143          }
 144  
 145          $out = array();
 146          $query = array(
 147              self::MSG_UID => $uid
 148          );
 149  
 150          try {
 151              $cursor = $this->_db->selectCollection(self::MSG)->find(
 152                  $query,
 153                  array(
 154                      self::MSG_MSGUID => true
 155                  )
 156              );
 157              foreach ($cursor as $val) {
 158                  $out[] = $val[self::MSG_MSGUID];
 159              }
 160          } catch (MongoException $e) {}
 161  
 162          return $out;
 163      }
 164  
 165      /**
 166       */
 167      public function set($mailbox, $data, $uidvalid)
 168      {
 169          if ($uid = $this->_getUid($mailbox)) {
 170              $res = $this->get($mailbox, array_keys($data), array(), $uidvalid);
 171          } else {
 172              $res = array();
 173              $uid = $this->_createUid($mailbox);
 174          }
 175  
 176          $coll = $this->_db->selectCollection(self::MSG);
 177  
 178          foreach ($data as $key => $val) {
 179              try {
 180                  if (isset($res[$key])) {
 181                      $coll->update(array(
 182                          self::MSG_MSGUID => strval($key),
 183                          self::MSG_UID => $uid
 184                      ), array(
 185                          self::MSG_DATA => $this->_value(array_merge($res[$key], $val)),
 186                          self::MSG_MSGUID => strval($key),
 187                          self::MSG_UID => $uid
 188                      ));
 189                  } else {
 190                      $coll->insert(array(
 191                          self::MSG_DATA => $this->_value($val),
 192                          self::MSG_MSGUID => strval($key),
 193                          self::MSG_UID => $uid
 194                      ));
 195                  }
 196              } catch (MongoException $e) {}
 197          }
 198  
 199          /* Update modified time. */
 200          try {
 201              $this->_db->selectCollection(self::BASE)->update(
 202                  array(self::BASE_UID => $uid),
 203                  array(self::BASE_MODIFIED => time())
 204              );
 205          } catch (MongoException $e) {}
 206  
 207          /* Update uidvalidity. */
 208          $this->setMetaData($mailbox, array('uidvalid' => $uidvalid));
 209      }
 210  
 211      /**
 212       */
 213      public function getMetaData($mailbox, $uidvalid, $entries)
 214      {
 215          if (!($uid = $this->_getUid($mailbox))) {
 216              return array();
 217          }
 218  
 219          $out = array();
 220          $query = array(
 221              self::MD_UID => $uid
 222          );
 223  
 224          if (!empty($entries)) {
 225              $entries[] = 'uidvalid';
 226              $query[self::MD_FIELD] = array(
 227                  '$in' => array_unique($entries)
 228              );
 229          }
 230  
 231          try {
 232              $cursor = $this->_db->selectCollection(self::MD)->find(
 233                  $query,
 234                  array(
 235                      self::MD_DATA => true,
 236                      self::MD_FIELD => true
 237                  )
 238              );
 239              foreach ($cursor as $val) {
 240                  $out[$val[self::MD_FIELD]] = $this->_value($val[self::MD_DATA]);
 241              }
 242  
 243              if (is_null($uidvalid) ||
 244                  !isset($out['uidvalid']) ||
 245                  ($out['uidvalid'] == $uidvalid)) {
 246                  return $out;
 247              }
 248  
 249              $this->deleteMailbox($mailbox);
 250          } catch (MongoException $e) {}
 251  
 252          return array();
 253      }
 254  
 255      /**
 256       */
 257      public function setMetaData($mailbox, $data)
 258      {
 259          if (!($uid = $this->_getUid($mailbox))) {
 260              $uid = $this->_createUid($mailbox);
 261          }
 262  
 263          $coll = $this->_db->selectCollection(self::MD);
 264  
 265          foreach ($data as $key => $val) {
 266              try {
 267                  $coll->update(
 268                      array(
 269                          self::MD_FIELD => $key,
 270                          self::MD_UID => $uid
 271                      ),
 272                      array(
 273                          self::MD_DATA => $this->_value($val),
 274                          self::MD_FIELD => $key,
 275                          self::MD_UID => $uid
 276                      ),
 277                      array('upsert' => true)
 278                  );
 279              } catch (MongoException $e) {}
 280          }
 281      }
 282  
 283      /**
 284       */
 285      public function deleteMsgs($mailbox, $uids)
 286      {
 287          if (!empty($uids) && ($uid = $this->_getUid($mailbox))) {
 288              try {
 289                  $this->_db->selectCollection(self::MSG)->remove(array(
 290                      self::MSG_MSGUID => array('$in' => array_map('strval', $uids)),
 291                      self::MSG_UID => $uid
 292                  ));
 293              } catch (MongoException $e) {}
 294          }
 295      }
 296  
 297      /**
 298       */
 299      public function deleteMailbox($mailbox)
 300      {
 301          if (!($uid = $this->_getUid($mailbox))) {
 302              return;
 303          }
 304  
 305          foreach (array(self::BASE, self::MD, self::MSG) as $val) {
 306              try {
 307                  $this->_db->selectCollection($val)->remove(array(
 308                      'uid' => $uid
 309                  ));
 310              } catch (MongoException $e) {}
 311          }
 312      }
 313  
 314      /**
 315       */
 316      public function clear($lifetime)
 317      {
 318          if (is_null($lifetime)) {
 319              foreach (array(self::BASE, self::MD, self::MSG) as $val) {
 320                  $this->_db->selectCollection($val)->drop();
 321              }
 322              return;
 323          }
 324  
 325          $query = array(
 326              self::BASE_MODIFIED => array('$lt' => (time() - $lifetime))
 327          );
 328          $uids = array();
 329  
 330          try {
 331              $cursor = $this->_db->selectCollection(self::BASE)->find($query);
 332              foreach ($cursor as $val) {
 333                  $uids[] = strval($val['_id']);
 334              }
 335          } catch (MongoException $e) {}
 336  
 337          if (empty($uids)) {
 338              return;
 339          }
 340  
 341          foreach (array(self::BASE, self::MD, self::MSG) as $val) {
 342              try {
 343                  $this->_db->selectCollection($val)->remove(array(
 344                      'uid' => array('$in' => $uids)
 345                  ));
 346              } catch (MongoException $e) {}
 347          }
 348      }
 349  
 350      /**
 351       * Return the UID for a mailbox/user/server combo.
 352       *
 353       * @param string $mailbox  Mailbox name.
 354       *
 355       * @return string  UID from base table.
 356       */
 357      protected function _getUid($mailbox)
 358      {
 359          $query = array(
 360              self::BASE_HOSTSPEC => $this->_params['hostspec'],
 361              self::BASE_MAILBOX => $mailbox,
 362              self::BASE_PORT => $this->_params['port'],
 363              self::BASE_USERNAME => $this->_params['username']
 364          );
 365  
 366          try {
 367              if ($result = $this->_db->selectCollection(self::BASE)->findOne($query)) {
 368                  return strval($result['_id']);
 369              }
 370          } catch (MongoException $e) {}
 371  
 372          return null;
 373      }
 374  
 375      /**
 376       * Create and return the UID for a mailbox/user/server combo.
 377       *
 378       * @param string $mailbox  Mailbox name.
 379       *
 380       * @return string  UID from base table.
 381       */
 382      protected function _createUid($mailbox)
 383      {
 384          $this->_db->selectCollection(self::BASE)->insert(array(
 385              self::BASE_HOSTSPEC => $this->_params['hostspec'],
 386              self::BASE_MAILBOX => $mailbox,
 387              self::BASE_PORT => $this->_params['port'],
 388              self::BASE_USERNAME => $this->_params['username']
 389          ));
 390  
 391          return $this->_getUid($mailbox);
 392      }
 393  
 394      /**
 395       * Convert data from/to storage format.
 396       *
 397       * @param mixed|MongoBinData $data  The data object.
 398       *
 399       * @return mixed|MongoBinData  The converted data.
 400       */
 401      protected function _value($data)
 402      {
 403          static $compress;
 404  
 405          if (!isset($compress)) {
 406              $compress = new Horde_Compress_Fast();
 407          }
 408  
 409          return ($data instanceof MongoBinData)
 410              ? @unserialize($compress->decompress($data->bin))
 411              : new MongoBinData($compress->compress(serialize($data)), MongoBinData::BYTE_ARRAY);
 412      }
 413  
 414      /* Horde_Mongo_Collection_Index methods. */
 415  
 416      /**
 417       */
 418      public function checkMongoIndices()
 419      {
 420          foreach ($this->_indices as $key => $val) {
 421              if (!$this->_params['mongo_db']->checkIndices($key, $val)) {
 422                  return false;
 423              }
 424          }
 425  
 426          return true;
 427      }
 428  
 429      /**
 430       */
 431      public function createMongoIndices()
 432      {
 433          foreach ($this->_indices as $key => $val) {
 434              $this->_params['mongo_db']->createIndices($key, $val);
 435          }
 436      }
 437  
 438  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1