File indexing completed on 2024-04-28 06:00:03

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Queue
0017  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0018  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0019  * @version    $Id$
0020  */
0021 
0022 /**
0023  * Class for connecting to queues performing common operations.
0024  *
0025  * @category   Zend
0026  * @package    Zend_Queue
0027  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0028  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0029  */
0030 class Zend_Queue implements Countable
0031 {
0032     /**
0033      * Use the TIMEOUT constant in the config of a Zend_Queue
0034      */
0035     const TIMEOUT = 'timeout';
0036 
0037     /**
0038      * Default visibility passed to count
0039      */
0040     const VISIBILITY_TIMEOUT = 30;
0041 
0042     /**
0043      * Use the NAME constant in the config of Zend_Queue
0044      */
0045     const NAME = 'name';
0046 
0047     /**
0048      * @var Zend_Queue_Adapter_AdapterInterface
0049      */
0050     protected $_adapter = null;
0051 
0052     /**
0053      * User-provided configuration
0054      *
0055      * @var array
0056      */
0057     protected $_options = array();
0058 
0059     /**
0060      * Zend_Queue_Message class
0061      *
0062      * @var string
0063      */
0064     protected $_messageClass = 'Zend_Queue_Message';
0065 
0066     /**
0067      * Zend_Queue_Message_Iterator class
0068      *
0069      * @var string
0070      */
0071     protected $_messageSetClass = 'Zend_Queue_Message_Iterator';
0072 
0073     /**
0074      * @var Zend_Log
0075      */
0076     protected $_logger = null;
0077 
0078     /**
0079      * Constructor
0080      *
0081      * Can be called as
0082      * $queue = new Zend_Queue($config);
0083      * - or -
0084      * $queue = new Zend_Queue('array', $config);
0085      * - or -
0086      * $queue = new Zend_Queue(null, $config); // Zend_Queue->createQueue();
0087      *
0088      * @param  string|Zend_Queue_Adapter|array|Zend_Config|null String or adapter instance, or options array or Zend_Config instance
0089      * @param  Zend_Config|array $options Zend_Config or a configuration array
0090      * @return void
0091      */
0092     public function __construct($spec, $options = array())
0093     {
0094         $adapter = null;
0095         if ($spec instanceof Zend_Queue_Adapter_AdapterInterface) {
0096             $adapter = $spec;
0097         } elseif (is_string($spec)) {
0098             $adapter = $spec;
0099         } elseif ($spec instanceof Zend_Config) {
0100             $options = $spec->toArray();
0101         } elseif (is_array($spec)) {
0102             $options = $spec;
0103         }
0104 
0105         // last minute error checking
0106         if ((null === $adapter)
0107             && (!is_array($options) && (!$options instanceof Zend_Config))
0108         ) {
0109             // require_once 'Zend/Queue/Exception.php';
0110             throw new Zend_Queue_Exception('No valid params passed to constructor');
0111         }
0112 
0113         // Now continue as we would if we were a normal constructor
0114         if ($options instanceof Zend_Config) {
0115             $options = $options->toArray();
0116         } elseif (!is_array($options)) {
0117             $options = array();
0118         }
0119 
0120         // Make sure we have some defaults to work with
0121         if (!isset($options[self::TIMEOUT])) {
0122             $options[self::TIMEOUT] = self::VISIBILITY_TIMEOUT;
0123         }
0124 
0125         // Make sure all defaults are appropriately set.
0126         if (!array_key_exists('timeout', $options)) {
0127             $options[self::TIMEOUT] = self::VISIBILITY_TIMEOUT;
0128         }
0129         if (array_key_exists('messageClass', $options)) {
0130             $this->setMessageClass($options['messageClass']);
0131         }
0132         if (array_key_exists('messageSetClass', $options)) {
0133             $this->setMessageSetClass($options['messageSetClass']);
0134         }
0135 
0136         $this->setOptions($options);
0137 
0138         // if we were passed an adapter we either build the $adapter or use it
0139         if (null !== $adapter) {
0140             $this->setAdapter($adapter);
0141         }
0142     }
0143 
0144     /**
0145      * Set queue options
0146      *
0147      * @param  array $options
0148      * @return Zend_Queue
0149      */
0150     public function setOptions(array $options)
0151     {
0152         $this->_options = array_merge($this->_options, $options);
0153         return $this;
0154     }
0155 
0156     /**
0157      * Set an individual configuration option
0158      *
0159      * @param  string $name
0160      * @param  mixed $value
0161      * @return Zend_Queue
0162      */
0163     public function setOption($name, $value)
0164     {
0165         $this->_options[(string) $name] = $value;
0166         return $this;
0167     }
0168 
0169     /**
0170      * Returns the configuration options for the queue
0171      *
0172      * @return array
0173      */
0174     public function getOptions()
0175     {
0176         return $this->_options;
0177     }
0178 
0179     /**
0180      * Determine if a requested option has been defined
0181      *
0182      * @param  string $name
0183      * @return bool
0184      */
0185     public function hasOption($name)
0186     {
0187         return array_key_exists($name, $this->_options);
0188     }
0189 
0190     /**
0191      * Retrieve a single option
0192      *
0193      * @param  string $name
0194      * @return null|mixed Returns null if option does not exist; option value otherwise
0195      */
0196     public function getOption($name)
0197     {
0198         if ($this->hasOption($name)) {
0199             return $this->_options[$name];
0200         }
0201         return null;
0202     }
0203 
0204     /**
0205      * Set the adapter for this queue
0206      *
0207      * @param  string|Zend_Queue_Adapter_AdapterInterface $adapter
0208      * @return Zend_Queue Provides a fluent interface
0209      */
0210     public function setAdapter($adapter)
0211     {
0212         if (is_string($adapter)) {
0213             if (null === ($adapterNamespace = $this->getOption('adapterNamespace'))) {
0214                 $adapterNamespace = 'Zend_Queue_Adapter';
0215             }
0216 
0217             $adapterName = str_replace(
0218                 ' ',
0219                 '_',
0220                 ucwords(
0221                     str_replace(
0222                         '_',
0223                         ' ',
0224                         strtolower($adapterNamespace . '_' . $adapter)
0225                     )
0226                 )
0227             );
0228 
0229             if (!class_exists($adapterName)) {
0230                 // require_once 'Zend/Loader.php';
0231                 Zend_Loader::loadClass($adapterName);
0232             }
0233 
0234             /*
0235              * Create an instance of the adapter class.
0236              * Pass the configuration to the adapter class constructor.
0237              */
0238             $adapter = new $adapterName($this->getOptions(), $this);
0239         }
0240 
0241         if (!$adapter instanceof Zend_Queue_Adapter_AdapterInterface) {
0242             // require_once 'Zend/Queue/Exception.php';
0243             throw new Zend_Queue_Exception("Adapter class '" . get_class($adapterName) . "' does not implement Zend_Queue_Adapter_AdapterInterface");
0244         }
0245 
0246         $this->_adapter = $adapter;
0247 
0248         $this->_adapter->setQueue($this);
0249 
0250         if (null !== ($name = $this->getOption(self::NAME))) {
0251             $this->_setName($name);
0252         }
0253 
0254         return $this;
0255     }
0256 
0257     /**
0258      * Get the adapter for this queue
0259      *
0260      * @return Zend_Queue_Adapter_AdapterInterface
0261      */
0262     public function getAdapter()
0263     {
0264         return $this->_adapter;
0265     }
0266 
0267     /**
0268      * @param  string $className
0269      * @return Zend_Queue Provides a fluent interface
0270      */
0271     public function setMessageClass($className)
0272     {
0273         $this->_messageClass = (string) $className;
0274         return $this;
0275     }
0276 
0277     /**
0278      * @return string
0279      */
0280     public function getMessageClass()
0281     {
0282         return $this->_messageClass;
0283     }
0284 
0285     /**
0286      * @param  string $className
0287      * @return Zend_Queue Provides a fluent interface
0288      */
0289     public function setMessageSetClass($className)
0290     {
0291         $this->_messageSetClass = (string) $className;
0292         return $this;
0293     }
0294 
0295     /**
0296      * @return string
0297      */
0298     public function getMessageSetClass()
0299     {
0300         return $this->_messageSetClass;
0301     }
0302 
0303     /**
0304      * Get the name of the queue
0305      *
0306      * Note: _setName() used to exist, but it caused confusion with createQueue
0307      * Will evaluate later to see if we should add it back in.
0308      *
0309      * @return string
0310      */
0311     public function getName()
0312     {
0313         return $this->getOption(self::NAME);
0314     }
0315 
0316     /**
0317      * Create a new queue
0318      *
0319      * @param  string           $name    queue name
0320      * @param  integer          $timeout default visibility timeout
0321      * @return Zend_Queue|false
0322      * @throws Zend_Queue_Exception
0323      */
0324     public function createQueue($name, $timeout = null)
0325     {
0326         if (!is_string($name)) {
0327             // require_once 'Zend/Queue/Exception.php';
0328             throw new Zend_Queue_Exception('$name is not a string');
0329         }
0330 
0331         if ((null !== $timeout) && !is_integer($timeout)) {
0332             // require_once 'Zend/Queue/Exception.php';
0333             throw new Zend_Queue_Exception('$timeout must be an integer');
0334         }
0335 
0336         // Default to standard timeout
0337         if (null === $timeout) {
0338             $timeout = $this->getOption(self::TIMEOUT);
0339         }
0340 
0341         // Some queues allow you to create on the fly, but cannot return
0342         // a list of queues.  Stomp protocol for example.
0343         if ($this->isSupported('create')) {
0344             if ($this->getAdapter()->isExists($name)) {
0345                 return false;
0346             }
0347 
0348             if (!$this->getAdapter()->create($name, $timeout)) {
0349                 return false;
0350             }
0351         }
0352 
0353         $options = array(
0354             self::NAME  => $name,
0355             'timeout'   => $timeout
0356         );
0357 
0358         return new self($this->getAdapter(), $options);
0359     }
0360 
0361     /**
0362      * Delete the queue this object is working on.
0363      *
0364      * This queue is disabled, regardless of the outcome of the deletion
0365      * of the queue, because the programmers intent is to disable this queue.
0366      *
0367      * @return boolean
0368      */
0369     public function deleteQueue()
0370     {
0371         if ($this->isSupported('delete')) {
0372             $deleted = $this->getAdapter()->delete($this->getName());
0373         }
0374         else {
0375             $deleted = true;
0376         }
0377 
0378         /**
0379          * @see Zend_Queue_Adapter_Null
0380          */
0381         // require_once('Zend/Queue/Adapter/Null.php');
0382         $this->setAdapter(new Zend_Queue_Adapter_Null($this->getOptions()));
0383 
0384         return $deleted;
0385     }
0386 
0387     /**
0388      * Delete a message from the queue
0389      *
0390      * Returns true if the message is deleted, false if the deletion is
0391      * unsuccessful.
0392      *
0393      * Returns true if the adapter doesn't support message deletion.
0394      *
0395      * @param  Zend_Queue_Message $message
0396      * @return boolean
0397      * @throws Zend_Queue_Exception
0398      */
0399     public function deleteMessage(Zend_Queue_Message $message)
0400     {
0401         if ($this->getAdapter()->isSupported('deleteMessage')) {
0402             return $this->getAdapter()->deleteMessage($message);
0403         }
0404         return true;
0405     }
0406 
0407     /**
0408      * Send a message to the queue
0409      *
0410      * @param  mixed $message message
0411      * @return Zend_Queue_Message
0412      * @throws Zend_Queue_Exception
0413      */
0414     public function send($message)
0415     {
0416         return $this->getAdapter()->send($message);
0417     }
0418 
0419     /**
0420      * Returns the approximate number of messages in the queue
0421      *
0422      * @return integer
0423      */
0424     public function count()
0425     {
0426         if ($this->getAdapter()->isSupported('count')) {
0427             return $this->getAdapter()->count();
0428         }
0429         return 0;
0430     }
0431 
0432     /**
0433      * Return the first element in the queue
0434      *
0435      * @param  integer $maxMessages
0436      * @param  integer $timeout
0437      * @return Zend_Queue_Message_Iterator
0438      */
0439     public function receive($maxMessages=null, $timeout=null)
0440     {
0441         if (($maxMessages !== null) && !is_integer($maxMessages)) {
0442             // require_once 'Zend/Queue/Exception.php';
0443             throw new Zend_Queue_Exception('$maxMessages must be an integer or null');
0444         }
0445 
0446         if (($timeout !== null) && !is_integer($timeout)) {
0447             // require_once 'Zend/Queue/Exception.php';
0448             throw new Zend_Queue_Exception('$timeout must be an integer or null');
0449         }
0450 
0451         // Default to returning only one message
0452         if ($maxMessages === null) {
0453             $maxMessages = 1;
0454         }
0455 
0456         // Default to standard timeout
0457         if ($timeout === null) {
0458             $timeout = $this->getOption(self::TIMEOUT);
0459         }
0460 
0461         return $this->getAdapter()->receive($maxMessages, $timeout);
0462     }
0463 
0464     /**
0465      * Return a list of queue capabilities functions
0466      *
0467      * $array['function name'] = true or false
0468      * true is supported, false is not supported.
0469      *
0470      * @param  string $name
0471      * @return array
0472      */
0473     public function getCapabilities()
0474     {
0475         return $this->getAdapter()->getCapabilities();
0476     }
0477 
0478     /**
0479      * Indicates if a function is supported or not.
0480      *
0481      * @param  string $name
0482      * @return boolean
0483      */
0484     public function isSupported($name)
0485     {
0486         $translation = array(
0487             'deleteQueue' => 'delete',
0488             'createQueue' => 'create'
0489         );
0490 
0491         if (isset($translation[$name])) {
0492             $name = $translation[$name];
0493         }
0494 
0495         return $this->getAdapter()->isSupported($name);
0496     }
0497 
0498     /**
0499      * Get an array of all available queues
0500      *
0501      * @return array
0502      * @throws Zend_Queue_Exception
0503      */
0504     public function getQueues()
0505     {
0506         if (!$this->isSupported('getQueues')) {
0507             throw new Zend_Queue_Exception( __FUNCTION__ . '() is not supported by ' . get_class($this->getAdapter()));
0508         }
0509 
0510         return $this->getAdapter()->getQueues();
0511     }
0512 
0513     /**
0514      * Set the name of the queue
0515      *
0516      * This is AN UNSUPPORTED FUNCTION
0517      *
0518      * @param  string           $name
0519      * @return Zend_Queue|false Provides a fluent interface
0520      */
0521     protected function _setName($name)
0522     {
0523         if (!is_string($name)) {
0524             /**
0525              * @see Zend_Queue_Exception
0526              */
0527             // require_once 'Zend/Queue/Exception.php';
0528             throw new Zend_Queue_Exception("$name is not a string");
0529         }
0530 
0531         if ($this->getAdapter()->isSupported('create')) {
0532             if (!$this->getAdapter()->isExists($name)) {
0533                 $timeout = $this->getOption(self::TIMEOUT);
0534 
0535                 if (!$this->getAdapter()->create($name, $timeout)) {
0536                     // Unable to create the new queue
0537                     return false;
0538                 }
0539             }
0540         }
0541 
0542         $this->setOption(self::NAME, $name);
0543 
0544         return $this;
0545     }
0546 
0547     /**
0548      * returns a listing of Zend_Queue details.
0549      * useful for debugging
0550      *
0551      * @return array
0552      */
0553     public function debugInfo()
0554     {
0555         $info = array();
0556         $info['self']                     = get_class($this);
0557         $info['adapter']                  = get_class($this->getAdapter());
0558         foreach ($this->getAdapter()->getCapabilities() as $feature => $supported) {
0559             $info['adapter-' . $feature]  = ($supported) ? 'yes' : 'no';
0560         }
0561         $info['options']                  = $this->getOptions();
0562         $info['options']['driverOptions'] = '[hidden]';
0563         $info['currentQueue']             = $this->getName();
0564         $info['messageClass']             = $this->getMessageClass();
0565         $info['messageSetClass']          = $this->getMessageSetClass();
0566 
0567         return $info;
0568     }
0569 }