|
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 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
18 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
19 * @version $Id: Queue.php 20096 2010-01-06 02:05:09Z bkarwin $ |
|
20 */ |
|
21 |
|
22 /** |
|
23 * Class for connecting to queues performing common operations. |
|
24 * |
|
25 * @category Zend |
|
26 * @package Zend_Queue |
|
27 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
28 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
29 */ |
|
30 class Zend_Queue implements Countable |
|
31 { |
|
32 /** |
|
33 * Use the TIMEOUT constant in the config of a Zend_Queue |
|
34 */ |
|
35 const TIMEOUT = 'timeout'; |
|
36 |
|
37 /** |
|
38 * Default visibility passed to count |
|
39 */ |
|
40 const VISIBILITY_TIMEOUT = 30; |
|
41 |
|
42 /** |
|
43 * Use the NAME constant in the config of Zend_Queue |
|
44 */ |
|
45 const NAME = 'name'; |
|
46 |
|
47 /** |
|
48 * @var Zend_Queue_Adapter_AdapterInterface |
|
49 */ |
|
50 protected $_adapter = null; |
|
51 |
|
52 /** |
|
53 * User-provided configuration |
|
54 * |
|
55 * @var array |
|
56 */ |
|
57 protected $_options = array(); |
|
58 |
|
59 /** |
|
60 * Zend_Queue_Message class |
|
61 * |
|
62 * @var string |
|
63 */ |
|
64 protected $_messageClass = 'Zend_Queue_Message'; |
|
65 |
|
66 /** |
|
67 * Zend_Queue_Message_Iterator class |
|
68 * |
|
69 * @var string |
|
70 */ |
|
71 protected $_messageSetClass = 'Zend_Queue_Message_Iterator'; |
|
72 |
|
73 /** |
|
74 * @var Zend_Log |
|
75 */ |
|
76 protected $_logger = null; |
|
77 |
|
78 /** |
|
79 * Constructor |
|
80 * |
|
81 * Can be called as |
|
82 * $queue = new Zend_Queue($config); |
|
83 * - or - |
|
84 * $queue = new Zend_Queue('array', $config); |
|
85 * - or - |
|
86 * $queue = new Zend_Queue(null, $config); // Zend_Queue->createQueue(); |
|
87 * |
|
88 * @param string|Zend_Queue_Adapter|array|Zend_Config|null String or adapter instance, or options array or Zend_Config instance |
|
89 * @param Zend_Config|array $options Zend_Config or a configuration array |
|
90 * @return void |
|
91 */ |
|
92 public function __construct($spec, $options = array()) |
|
93 { |
|
94 $adapter = null; |
|
95 if ($spec instanceof Zend_Queue_Adapter_AdapterInterface) { |
|
96 $adapter = $spec; |
|
97 } elseif (is_string($spec)) { |
|
98 $adapter = $spec; |
|
99 } elseif ($spec instanceof Zend_Config) { |
|
100 $options = $spec->toArray(); |
|
101 } elseif (is_array($spec)) { |
|
102 $options = $spec; |
|
103 } |
|
104 |
|
105 // last minute error checking |
|
106 if ((null === $adapter) |
|
107 && (!is_array($options) && (!$options instanceof Zend_Config)) |
|
108 ) { |
|
109 require_once 'Zend/Queue/Exception.php'; |
|
110 throw new Zend_Queue_Exception('No valid params passed to constructor'); |
|
111 } |
|
112 |
|
113 // Now continue as we would if we were a normal constructor |
|
114 if ($options instanceof Zend_Config) { |
|
115 $options = $options->toArray(); |
|
116 } elseif (!is_array($options)) { |
|
117 $options = array(); |
|
118 } |
|
119 |
|
120 // Make sure we have some defaults to work with |
|
121 if (!isset($options[self::TIMEOUT])) { |
|
122 $options[self::TIMEOUT] = self::VISIBILITY_TIMEOUT; |
|
123 } |
|
124 |
|
125 // Make sure all defaults are appropriately set. |
|
126 if (!array_key_exists('timeout', $options)) { |
|
127 $options[self::TIMEOUT] = self::VISIBILITY_TIMEOUT; |
|
128 } |
|
129 if (array_key_exists('messageClass', $options)) { |
|
130 $this->setMessageClass($options['messageClass']); |
|
131 } |
|
132 if (array_key_exists('messageSetClass', $options)) { |
|
133 $this->setMessageSetClass($options['messageSetClass']); |
|
134 } |
|
135 |
|
136 $this->setOptions($options); |
|
137 |
|
138 // if we were passed an adapter we either build the $adapter or use it |
|
139 if (null !== $adapter) { |
|
140 $this->setAdapter($adapter); |
|
141 } |
|
142 } |
|
143 |
|
144 /** |
|
145 * Set queue options |
|
146 * |
|
147 * @param array $options |
|
148 * @return Zend_Queue |
|
149 */ |
|
150 public function setOptions(array $options) |
|
151 { |
|
152 $this->_options = array_merge($this->_options, $options); |
|
153 return $this; |
|
154 } |
|
155 |
|
156 /** |
|
157 * Set an individual configuration option |
|
158 * |
|
159 * @param string $name |
|
160 * @param mixed $value |
|
161 * @return Zend_Queue |
|
162 */ |
|
163 public function setOption($name, $value) |
|
164 { |
|
165 $this->_options[(string) $name] = $value; |
|
166 return $this; |
|
167 } |
|
168 |
|
169 /** |
|
170 * Returns the configuration options for the queue |
|
171 * |
|
172 * @return array |
|
173 */ |
|
174 public function getOptions() |
|
175 { |
|
176 return $this->_options; |
|
177 } |
|
178 |
|
179 /** |
|
180 * Determine if a requested option has been defined |
|
181 * |
|
182 * @param string $name |
|
183 * @return bool |
|
184 */ |
|
185 public function hasOption($name) |
|
186 { |
|
187 return array_key_exists($name, $this->_options); |
|
188 } |
|
189 |
|
190 /** |
|
191 * Retrieve a single option |
|
192 * |
|
193 * @param string $name |
|
194 * @return null|mixed Returns null if option does not exist; option value otherwise |
|
195 */ |
|
196 public function getOption($name) |
|
197 { |
|
198 if ($this->hasOption($name)) { |
|
199 return $this->_options[$name]; |
|
200 } |
|
201 return null; |
|
202 } |
|
203 |
|
204 /** |
|
205 * Set the adapter for this queue |
|
206 * |
|
207 * @param string|Zend_Queue_Adapter_AdapterInterface $adapter |
|
208 * @return Zend_Queue Provides a fluent interface |
|
209 */ |
|
210 public function setAdapter($adapter) |
|
211 { |
|
212 if (is_string($adapter)) { |
|
213 if (null === ($adapterNamespace = $this->getOption('adapterNamespace'))) { |
|
214 $adapterNamespace = 'Zend_Queue_Adapter'; |
|
215 } |
|
216 |
|
217 $adapterName = str_replace( |
|
218 ' ', |
|
219 '_', |
|
220 ucwords( |
|
221 str_replace( |
|
222 '_', |
|
223 ' ', |
|
224 strtolower($adapterNamespace . '_' . $adapter) |
|
225 ) |
|
226 ) |
|
227 ); |
|
228 |
|
229 if (!class_exists($adapterName)) { |
|
230 require_once 'Zend/Loader.php'; |
|
231 Zend_Loader::loadClass($adapterName); |
|
232 } |
|
233 |
|
234 /* |
|
235 * Create an instance of the adapter class. |
|
236 * Pass the configuration to the adapter class constructor. |
|
237 */ |
|
238 $adapter = new $adapterName($this->getOptions(), $this); |
|
239 } |
|
240 |
|
241 if (!$adapter instanceof Zend_Queue_Adapter_AdapterInterface) { |
|
242 require_once 'Zend/Queue/Exception.php'; |
|
243 throw new Zend_Queue_Exception("Adapter class '" . get_class($adapterName) . "' does not implement Zend_Queue_Adapter_AdapterInterface"); |
|
244 } |
|
245 |
|
246 $this->_adapter = $adapter; |
|
247 |
|
248 $this->_adapter->setQueue($this); |
|
249 |
|
250 if (null !== ($name = $this->getOption(self::NAME))) { |
|
251 $this->_setName($name); |
|
252 } |
|
253 |
|
254 return $this; |
|
255 } |
|
256 |
|
257 /** |
|
258 * Get the adapter for this queue |
|
259 * |
|
260 * @return Zend_Queue_Adapter_AdapterInterface |
|
261 */ |
|
262 public function getAdapter() |
|
263 { |
|
264 return $this->_adapter; |
|
265 } |
|
266 |
|
267 /** |
|
268 * @param string $className |
|
269 * @return Zend_Queue Provides a fluent interface |
|
270 */ |
|
271 public function setMessageClass($className) |
|
272 { |
|
273 $this->_messageClass = (string) $className; |
|
274 return $this; |
|
275 } |
|
276 |
|
277 /** |
|
278 * @return string |
|
279 */ |
|
280 public function getMessageClass() |
|
281 { |
|
282 return $this->_messageClass; |
|
283 } |
|
284 |
|
285 /** |
|
286 * @param string $className |
|
287 * @return Zend_Queue Provides a fluent interface |
|
288 */ |
|
289 public function setMessageSetClass($className) |
|
290 { |
|
291 $this->_messageSetClass = (string) $className; |
|
292 return $this; |
|
293 } |
|
294 |
|
295 /** |
|
296 * @return string |
|
297 */ |
|
298 public function getMessageSetClass() |
|
299 { |
|
300 return $this->_messageSetClass; |
|
301 } |
|
302 |
|
303 /** |
|
304 * Get the name of the queue |
|
305 * |
|
306 * Note: _setName() used to exist, but it caused confusion with createQueue |
|
307 * Will evaluate later to see if we should add it back in. |
|
308 * |
|
309 * @return string |
|
310 */ |
|
311 public function getName() |
|
312 { |
|
313 return $this->getOption(self::NAME); |
|
314 } |
|
315 |
|
316 /** |
|
317 * Create a new queue |
|
318 * |
|
319 * @param string $name queue name |
|
320 * @param integer $timeout default visibility timeout |
|
321 * @return Zend_Queue|false |
|
322 * @throws Zend_Queue_Exception |
|
323 */ |
|
324 public function createQueue($name, $timeout = null) |
|
325 { |
|
326 if (!is_string($name)) { |
|
327 require_once 'Zend/Queue/Exception.php'; |
|
328 throw new Zend_Queue_Exception('$name is not a string'); |
|
329 } |
|
330 |
|
331 if ((null !== $timeout) && !is_integer($timeout)) { |
|
332 require_once 'Zend/Queue/Exception.php'; |
|
333 throw new Zend_Queue_Exception('$timeout must be an integer'); |
|
334 } |
|
335 |
|
336 // Default to standard timeout |
|
337 if (null === $timeout) { |
|
338 $timeout = $this->getOption(self::TIMEOUT); |
|
339 } |
|
340 |
|
341 // Some queues allow you to create on the fly, but cannot return |
|
342 // a list of queues. Stomp protocol for example. |
|
343 if ($this->isSupported('create')) { |
|
344 if ($this->getAdapter()->isExists($name)) { |
|
345 return false; |
|
346 } |
|
347 |
|
348 if (!$this->getAdapter()->create($name, $timeout)) { |
|
349 return false; |
|
350 } |
|
351 } |
|
352 |
|
353 $options = array( |
|
354 self::NAME => $name, |
|
355 'timeout' => $timeout |
|
356 ); |
|
357 |
|
358 return new self($this->getAdapter(), $options); |
|
359 } |
|
360 |
|
361 /** |
|
362 * Delete the queue this object is working on. |
|
363 * |
|
364 * This queue is disabled, regardless of the outcome of the deletion |
|
365 * of the queue, because the programmers intent is to disable this queue. |
|
366 * |
|
367 * @return boolean |
|
368 */ |
|
369 public function deleteQueue() |
|
370 { |
|
371 if ($this->isSupported('delete')) { |
|
372 $deleted = $this->getAdapter()->delete($this->getName()); |
|
373 } |
|
374 else { |
|
375 $deleted = true; |
|
376 } |
|
377 |
|
378 /** |
|
379 * @see Zend_Queue_Adapter_Null |
|
380 */ |
|
381 require_once('Zend/Queue/Adapter/Null.php'); |
|
382 $this->setAdapter(new Zend_Queue_Adapter_Null($this->getOptions())); |
|
383 |
|
384 return $deleted; |
|
385 } |
|
386 |
|
387 /** |
|
388 * Delete a message from the queue |
|
389 * |
|
390 * Returns true if the message is deleted, false if the deletion is |
|
391 * unsuccessful. |
|
392 * |
|
393 * Returns true if the adapter doesn't support message deletion. |
|
394 * |
|
395 * @param Zend_Queue_Message $message |
|
396 * @return boolean |
|
397 * @throws Zend_Queue_Exception |
|
398 */ |
|
399 public function deleteMessage(Zend_Queue_Message $message) |
|
400 { |
|
401 if ($this->getAdapter()->isSupported('deleteMessage')) { |
|
402 return $this->getAdapter()->deleteMessage($message); |
|
403 } |
|
404 return true; |
|
405 } |
|
406 |
|
407 /** |
|
408 * Send a message to the queue |
|
409 * |
|
410 * @param mixed $message message |
|
411 * @return Zend_Queue_Message |
|
412 * @throws Zend_Queue_Exception |
|
413 */ |
|
414 public function send($message) |
|
415 { |
|
416 return $this->getAdapter()->send($message); |
|
417 } |
|
418 |
|
419 /** |
|
420 * Returns the approximate number of messages in the queue |
|
421 * |
|
422 * @return integer |
|
423 */ |
|
424 public function count() |
|
425 { |
|
426 if ($this->getAdapter()->isSupported('count')) { |
|
427 return $this->getAdapter()->count(); |
|
428 } |
|
429 return 0; |
|
430 } |
|
431 |
|
432 /** |
|
433 * Return the first element in the queue |
|
434 * |
|
435 * @param integer $maxMessages |
|
436 * @param integer $timeout |
|
437 * @return Zend_Queue_Message_Iterator |
|
438 */ |
|
439 public function receive($maxMessages=null, $timeout=null) |
|
440 { |
|
441 if (($maxMessages !== null) && !is_integer($maxMessages)) { |
|
442 require_once 'Zend/Queue/Exception.php'; |
|
443 throw new Zend_Queue_Exception('$maxMessages must be an integer or null'); |
|
444 } |
|
445 |
|
446 if (($timeout !== null) && !is_integer($timeout)) { |
|
447 require_once 'Zend/Queue/Exception.php'; |
|
448 throw new Zend_Queue_Exception('$timeout must be an integer or null'); |
|
449 } |
|
450 |
|
451 // Default to returning only one message |
|
452 if ($maxMessages === null) { |
|
453 $maxMessages = 1; |
|
454 } |
|
455 |
|
456 // Default to standard timeout |
|
457 if ($timeout === null) { |
|
458 $timeout = $this->getOption(self::TIMEOUT); |
|
459 } |
|
460 |
|
461 return $this->getAdapter()->receive($maxMessages, $timeout); |
|
462 } |
|
463 |
|
464 /** |
|
465 * Return a list of queue capabilities functions |
|
466 * |
|
467 * $array['function name'] = true or false |
|
468 * true is supported, false is not supported. |
|
469 * |
|
470 * @param string $name |
|
471 * @return array |
|
472 */ |
|
473 public function getCapabilities() |
|
474 { |
|
475 return $this->getAdapter()->getCapabilities(); |
|
476 } |
|
477 |
|
478 /** |
|
479 * Indicates if a function is supported or not. |
|
480 * |
|
481 * @param string $name |
|
482 * @return boolean |
|
483 */ |
|
484 public function isSupported($name) |
|
485 { |
|
486 $translation = array( |
|
487 'deleteQueue' => 'delete', |
|
488 'createQueue' => 'create' |
|
489 ); |
|
490 |
|
491 if (isset($translation[$name])) { |
|
492 $name = $translation[$name]; |
|
493 } |
|
494 |
|
495 return $this->getAdapter()->isSupported($name); |
|
496 } |
|
497 |
|
498 /** |
|
499 * Get an array of all available queues |
|
500 * |
|
501 * @return array |
|
502 * @throws Zend_Queue_Exception |
|
503 */ |
|
504 public function getQueues() |
|
505 { |
|
506 if (!$this->isSupported('getQueues')) { |
|
507 throw new Zend_Queue_Exception( __FUNCTION__ . '() is not supported by ' . get_class($this->getAdapter())); |
|
508 } |
|
509 |
|
510 return $this->getAdapter()->getQueues(); |
|
511 } |
|
512 |
|
513 /** |
|
514 * Set the name of the queue |
|
515 * |
|
516 * This is AN UNSUPPORTED FUNCTION |
|
517 * |
|
518 * @param string $name |
|
519 * @return Zend_Queue|false Provides a fluent interface |
|
520 */ |
|
521 protected function _setName($name) |
|
522 { |
|
523 if (!is_string($name)) { |
|
524 /** |
|
525 * @see Zend_Queue_Exception |
|
526 */ |
|
527 require_once 'Zend/Queue/Exception.php'; |
|
528 throw new Zend_Queue_Exception("$name is not a string"); |
|
529 } |
|
530 |
|
531 if ($this->getAdapter()->isSupported('create')) { |
|
532 if (!$this->getAdapter()->isExists($name)) { |
|
533 $timeout = $this->getOption(self::TIMEOUT); |
|
534 |
|
535 if (!$this->getAdapter()->create($name, $timeout)) { |
|
536 // Unable to create the new queue |
|
537 return false; |
|
538 } |
|
539 } |
|
540 } |
|
541 |
|
542 $this->setOption(self::NAME, $name); |
|
543 |
|
544 return $this; |
|
545 } |
|
546 |
|
547 /** |
|
548 * returns a listing of Zend_Queue details. |
|
549 * useful for debugging |
|
550 * |
|
551 * @return array |
|
552 */ |
|
553 public function debugInfo() |
|
554 { |
|
555 $info = array(); |
|
556 $info['self'] = get_class($this); |
|
557 $info['adapter'] = get_class($this->getAdapter()); |
|
558 foreach ($this->getAdapter()->getCapabilities() as $feature => $supported) { |
|
559 $info['adapter-' . $feature] = ($supported) ? 'yes' : 'no'; |
|
560 } |
|
561 $info['options'] = $this->getOptions(); |
|
562 $info['options']['driverOptions'] = '[hidden]'; |
|
563 $info['currentQueue'] = $this->getName(); |
|
564 $info['messageClass'] = $this->getMessageClass(); |
|
565 $info['messageSetClass'] = $this->getMessageSetClass(); |
|
566 |
|
567 return $info; |
|
568 } |
|
569 } |