PageRenderTime 71ms CodeModel.GetById 38ms RepoModel.GetById 1ms app.codeStats 0ms

/src/library/Lexsign/Queue/Adapter/Mongo.php

https://github.com/akentner/mediathek
PHP | 475 lines | 229 code | 68 blank | 178 comment | 28 complexity | 7de4120e334c27f95f6e5c775595d52e MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Queue
  17. * @subpackage Adapter
  18. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: Db.php 23775 2011-03-01 17:25:24Z ralph $
  21. */
  22. /**
  23. * @see Zend_Queue_Adapter_AdapterAbstract
  24. */
  25. require_once 'Zend/Queue/Adapter/AdapterAbstract.php';
  26. /**
  27. * @see Zend_Queue_Adapter_Db_Message
  28. */
  29. require_once 'Lexsign/Queue/Adapter/Mongo/Message.php';
  30. /**
  31. * @see Zend_Queue_Adapter_Db_Message
  32. */
  33. require_once 'Shanty/Mongo/Document.php';
  34. /**
  35. * Class for using connecting to a Zend_Db-based queuing system
  36. *
  37. * @category Zend
  38. * @package Zend_Queue
  39. * @subpackage Adapter
  40. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  41. * @license http://framework.zend.com/license/new-bsd New BSD License
  42. */
  43. class Lexsign_Queue_Adapter_Mongo extends Zend_Queue_Adapter_AdapterAbstract {
  44. /**
  45. * @var Zend_Queue_Adapter_Db_Queue
  46. */
  47. protected $_queueTable = null;
  48. /**
  49. * @var Zend_Queue_Adapter_Db_Message
  50. */
  51. protected $_messageTable = null;
  52. /**
  53. * @var Zend_Db_Table_Row_Abstract
  54. */
  55. protected $_messageRow = null;
  56. /**
  57. * Constructor
  58. *
  59. * @param array|Zend_Config $options
  60. * @param Zend_Queue|null $queue
  61. * @return void
  62. */
  63. public function __construct($options, Zend_Queue $queue = null) {
  64. parent::__construct($options, $queue);
  65. $this->_initMongoAdapter();
  66. }
  67. /**
  68. * Initialize Db adapter using 'driverOptions' section of the _options array
  69. *
  70. * Throws an exception if the adapter cannot connect to DB.
  71. *
  72. * @return Zend_Db_Adapter_Abstract
  73. * @throws Zend_Queue_Exception
  74. */
  75. protected function _initMongoAdapter() {
  76. $options = &$this->_options['driverOptions'];
  77. if (!array_key_exists('host', $options)) {
  78. require_once 'Zend/Queue/Exception.php';
  79. throw new Zend_Queue_Exception("Configuration array must have a key for 'host' for the host to use");
  80. }
  81. if (!array_key_exists('db', $options)) {
  82. require_once 'Zend/Queue/Exception.php';
  83. throw new Zend_Queue_Exception("Configuration array must have a key for 'db' for the password to use");
  84. }
  85. try {
  86. $mongo = new Lexsign_Queue_Adapter_Mongo_Message();
  87. } catch (Zend_Db_Exception $e) {
  88. require_once 'Zend/Queue/Exception.php';
  89. throw new Zend_Queue_Exception('Error connecting to database: ' . $e->getMessage(), $e->getCode(), $e);
  90. }
  91. // return $mongo;
  92. }
  93. /* * ******************************************************************
  94. * Queue management functions
  95. * ******************************************************************* */
  96. /**
  97. * Does a queue already exist?
  98. *
  99. * Throws an exception if the adapter cannot determine if a queue exists.
  100. * use isSupported('isExists') to determine if an adapter can test for
  101. * queue existance.
  102. *
  103. * @param string $name
  104. * @return boolean
  105. * @throws Zend_Queue_Exception
  106. */
  107. public function isExists($name) {
  108. $id = 0;
  109. try {
  110. $id = $this->getQueueId($name);
  111. } catch (Zend_Queue_Exception $e) {
  112. return false;
  113. }
  114. return ($id > 0);
  115. }
  116. /**
  117. * Create a new queue
  118. *
  119. * Visibility timeout is how long a message is left in the queue "invisible"
  120. * to other readers. If the message is acknowleged (deleted) before the
  121. * timeout, then the message is deleted. However, if the timeout expires
  122. * then the message will be made available to other queue readers.
  123. *
  124. * @param string $name queue name
  125. * @param integer $timeout default visibility timeout
  126. * @return boolean
  127. * @throws Zend_Queue_Exception - database error
  128. */
  129. public function create($name, $timeout = null) {
  130. if ($this->isExists($name)) {
  131. return false;
  132. }
  133. $queue = $this->_queueTable->createRow();
  134. $queue->queue_name = $name;
  135. $queue->timeout = ($timeout === null) ? self::CREATE_TIMEOUT_DEFAULT : (int) $timeout;
  136. try {
  137. if ($queue->save()) {
  138. return true;
  139. }
  140. } catch (Exception $e) {
  141. require_once 'Zend/Queue/Exception.php';
  142. throw new Zend_Queue_Exception($e->getMessage(), $e->getCode(), $e);
  143. }
  144. return false;
  145. }
  146. /**
  147. * Delete a queue and all of it's messages
  148. *
  149. * Returns false if the queue is not found, true if the queue exists
  150. *
  151. * @param string $name queue name
  152. * @return boolean
  153. * @throws Zend_Queue_Exception - database error
  154. */
  155. public function delete($name) {
  156. $id = $this->getQueueId($name); // get primary key
  157. // if the queue does not exist then it must already be deleted.
  158. $list = $this->_queueTable->find($id);
  159. if (count($list) === 0) {
  160. return false;
  161. }
  162. $queue = $list->current();
  163. if ($queue instanceof Zend_Db_Table_Row_Abstract) {
  164. try {
  165. $queue->delete();
  166. } catch (Exception $e) {
  167. require_once 'Zend/Queue/Exception.php';
  168. throw new Zend_Queue_Exception($e->getMessage(), $e->getCode(), $e);
  169. }
  170. }
  171. if (array_key_exists($name, $this->_queues)) {
  172. unset($this->_queues[$name]);
  173. }
  174. return true;
  175. }
  176. /*
  177. * Get an array of all available queues
  178. *
  179. * Not all adapters support getQueues(), use isSupported('getQueues')
  180. * to determine if the adapter supports this feature.
  181. *
  182. * @return array
  183. * @throws Zend_Queue_Exception - database error
  184. */
  185. public function getQueues() {
  186. $query = $this->_queueTable->select();
  187. $query->from($this->_queueTable, array('queue_id', 'queue_name'));
  188. $this->_queues = array();
  189. foreach ($this->_queueTable->fetchAll($query) as $queue) {
  190. $this->_queues[$queue->queue_name] = (int) $queue->queue_id;
  191. }
  192. $list = array_keys($this->_queues);
  193. return $list;
  194. }
  195. /**
  196. * Return the approximate number of messages in the queue
  197. *
  198. * @param Zend_Queue $queue
  199. * @return integer
  200. * @throws Zend_Queue_Exception
  201. */
  202. public function count(Zend_Queue $queue = null) {
  203. if ($queue === null) {
  204. $queue = $this->_queue;
  205. }
  206. $info = $this->_messageTable->info();
  207. $db = $this->_messageTable->getAdapter();
  208. $query = $db->select();
  209. $query->from($info['name'], array(new Zend_Db_Expr('COUNT(1)')))
  210. ->where('queue_id=?', $this->getQueueId($queue->getName()));
  211. // return count results
  212. return (int) $db->fetchOne($query);
  213. }
  214. /* * ******************************************************************
  215. * Messsage management functions
  216. * ******************************************************************* */
  217. /**
  218. * Send a message to the queue
  219. *
  220. * @param string $message Message to send to the active queue
  221. * @param Zend_Queue $queue
  222. * @return Zend_Queue_Message
  223. * @throws Zend_Queue_Exception - database error
  224. */
  225. public function send($message, Zend_Queue $queue = null) {
  226. if ($this->_messageRow === null) {
  227. $this->_messageRow = $this->_messageTable->createRow();
  228. }
  229. if ($queue === null) {
  230. $queue = $this->_queue;
  231. }
  232. if (is_scalar($message)) {
  233. $message = (string) $message;
  234. }
  235. if (is_string($message)) {
  236. $message = trim($message);
  237. }
  238. if (!$this->isExists($queue->getName())) {
  239. require_once 'Zend/Queue/Exception.php';
  240. throw new Zend_Queue_Exception('Queue does not exist:' . $queue->getName());
  241. }
  242. $msg = clone $this->_messageRow;
  243. $msg->queue_id = $this->getQueueId($queue->getName());
  244. $msg->created = time();
  245. $msg->body = $message;
  246. $msg->md5 = md5($message);
  247. // $msg->timeout = ??? @TODO
  248. try {
  249. $msg->save();
  250. } catch (Exception $e) {
  251. require_once 'Zend/Queue/Exception.php';
  252. throw new Zend_Queue_Exception($e->getMessage(), $e->getCode(), $e);
  253. }
  254. $options = array(
  255. 'queue' => $queue,
  256. 'data' => $msg->toArray(),
  257. );
  258. $classname = $queue->getMessageClass();
  259. if (!class_exists($classname)) {
  260. require_once 'Zend/Loader.php';
  261. Zend_Loader::loadClass($classname);
  262. }
  263. return new $classname($options);
  264. }
  265. /**
  266. * Get messages in the queue
  267. *
  268. * @param integer $maxMessages Maximum number of messages to return
  269. * @param integer $timeout Visibility timeout for these messages
  270. * @param Zend_Queue $queue
  271. * @return Zend_Queue_Message_Iterator
  272. * @throws Zend_Queue_Exception - database error
  273. */
  274. public function receive($maxMessages = null, $timeout = null, Zend_Queue $queue = null) {
  275. if ($maxMessages === null) {
  276. $maxMessages = 1;
  277. }
  278. if ($timeout === null) {
  279. $timeout = self::RECEIVE_TIMEOUT_DEFAULT;
  280. }
  281. if ($queue === null) {
  282. $queue = $this->_queue;
  283. }
  284. $msgs = array();
  285. $info = $this->_messageTable->info();
  286. $microtime = microtime(true); // cache microtime
  287. $db = $this->_messageTable->getAdapter();
  288. // start transaction handling
  289. try {
  290. if ($maxMessages > 0) { // ZF-7666 LIMIT 0 clause not included.
  291. $db->beginTransaction();
  292. $query = $db->select();
  293. if ($this->_options['options'][Zend_Db_Select::FOR_UPDATE]) {
  294. // turn on forUpdate
  295. $query->forUpdate();
  296. }
  297. $query->from($info['name'], array('*'))
  298. ->where('queue_id=?', $this->getQueueId($queue->getName()))
  299. ->where('handle IS NULL OR timeout+' . (int) $timeout . ' < ' . (int) $microtime)
  300. ->limit($maxMessages);
  301. foreach ($db->fetchAll($query) as $data) {
  302. // setup our changes to the message
  303. $data['handle'] = md5(uniqid(rand(), true));
  304. $update = array(
  305. 'handle' => $data['handle'],
  306. 'timeout' => $microtime,
  307. );
  308. // update the database
  309. $where = array();
  310. $where[] = $db->quoteInto('message_id=?', $data['message_id']);
  311. $where[] = 'handle IS NULL OR timeout+' . (int) $timeout . ' < ' . (int) $microtime;
  312. $count = $db->update($info['name'], $update, $where);
  313. // we check count to make sure no other thread has gotten
  314. // the rows after our select, but before our update.
  315. if ($count > 0) {
  316. $msgs[] = $data;
  317. }
  318. }
  319. $db->commit();
  320. }
  321. } catch (Exception $e) {
  322. $db->rollBack();
  323. require_once 'Zend/Queue/Exception.php';
  324. throw new Zend_Queue_Exception($e->getMessage(), $e->getCode(), $e);
  325. }
  326. $options = array(
  327. 'queue' => $queue,
  328. 'data' => $msgs,
  329. 'messageClass' => $queue->getMessageClass(),
  330. );
  331. $classname = $queue->getMessageSetClass();
  332. if (!class_exists($classname)) {
  333. require_once 'Zend/Loader.php';
  334. Zend_Loader::loadClass($classname);
  335. }
  336. return new $classname($options);
  337. }
  338. /**
  339. * Delete a message from the queue
  340. *
  341. * Returns true if the message is deleted, false if the deletion is
  342. * unsuccessful.
  343. *
  344. * @param Zend_Queue_Message $message
  345. * @return boolean
  346. * @throws Zend_Queue_Exception - database error
  347. */
  348. public function deleteMessage(Zend_Queue_Message $message) {
  349. $db = $this->_messageTable->getAdapter();
  350. $where = $db->quoteInto('handle=?', $message->handle);
  351. if ($this->_messageTable->delete($where)) {
  352. return true;
  353. }
  354. return false;
  355. }
  356. /* * ******************************************************************
  357. * Supporting functions
  358. * ******************************************************************* */
  359. /**
  360. * Return a list of queue capabilities functions
  361. *
  362. * $array['function name'] = true or false
  363. * true is supported, false is not supported.
  364. *
  365. * @param string $name
  366. * @return array
  367. */
  368. public function getCapabilities() {
  369. return array(
  370. 'create' => true,
  371. 'delete' => true,
  372. 'send' => true,
  373. 'receive' => true,
  374. 'deleteMessage' => true,
  375. 'getQueues' => true,
  376. 'count' => true,
  377. 'isExists' => true,
  378. );
  379. }
  380. /* * ******************************************************************
  381. * Functions that are not part of the Zend_Queue_Adapter_Abstract
  382. * ******************************************************************* */
  383. /**
  384. * Get the queue ID
  385. *
  386. * Returns the queue's row identifier.
  387. *
  388. * @param string $name
  389. * @return integer|null
  390. * @throws Zend_Queue_Exception
  391. */
  392. protected function getQueueId($name) {
  393. if (array_key_exists($name, $this->_queues)) {
  394. return $this->_queues[$name];
  395. }
  396. $query = $this->_queueTable->select();
  397. $query->from($this->_queueTable, array('queue_id'))
  398. ->where('queue_name=?', $name);
  399. $queue = $this->_queueTable->fetchRow($query);
  400. if ($queue === null) {
  401. require_once 'Zend/Queue/Exception.php';
  402. throw new Zend_Queue_Exception('Queue does not exist: ' . $name);
  403. }
  404. $this->_queues[$name] = (int) $queue->queue_id;
  405. return $this->_queues[$name];
  406. }
  407. }