PageRenderTime 38ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Wildfire/Channel/HttpHeaders.php

https://github.com/Shreef/zf2
PHP | 327 lines | 136 code | 33 blank | 158 comment | 23 complexity | 69d6810f5b201f7fe05e58a9701cd99a 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_Wildfire
  17. * @subpackage Channel
  18. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. */
  21. /**
  22. * @namespace
  23. */
  24. namespace Zend\Wildfire\Channel;
  25. use Zend\Wildfire;
  26. use Zend\Wildfire\Protocol;
  27. use Zend\Controller;
  28. /**
  29. * Implements communication via HTTP request and response headers for Wildfire Protocols.
  30. *
  31. * @uses \Zend\Controller\Front
  32. * @uses \Zend\Controller\Plugin\AbstractPlugin
  33. * @uses \Zend\Controller\Request\AbstractRequest
  34. * @uses \Zend\Controller\Response\AbstractResponse
  35. * @uses \Zend\Loader
  36. * @uses \Zend\Wildfire\Channel
  37. * @uses \Zend\Wildfire\Exception
  38. * @uses \Zend\Wildfire\Protocol\JsonStream
  39. * @category Zend
  40. * @package Zend_Wildfire
  41. * @subpackage Channel
  42. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  43. * @license http://framework.zend.com/license/new-bsd New BSD License
  44. */
  45. class HttpHeaders
  46. extends Controller\Plugin\AbstractPlugin
  47. implements Wildfire\Channel
  48. {
  49. /**
  50. * The string to be used to prefix the headers.
  51. * @var string
  52. */
  53. protected static $_headerPrefix = 'X-WF-';
  54. /**
  55. * Singleton instance
  56. * @var \Zend\Wildfire\Channel\HttpHeaders
  57. */
  58. protected static $_instance = null;
  59. /**
  60. * The index of the plugin in the controller dispatch loop plugin stack
  61. * @var integer
  62. */
  63. protected static $_controllerPluginStackIndex = 999;
  64. /**
  65. * The protocol instances for this channel
  66. * @var array
  67. */
  68. protected $_protocols = null;
  69. /**
  70. * Initialize singleton instance.
  71. *
  72. * @param string $class OPTIONAL Subclass of \Zend\Wildfire\Channel\HttpHeaders
  73. * @return \Zend\Wildfire\Channel\HttpHeaders Returns the singleton \Zend\Wildfire\Channel\HttpHeaders instance
  74. * @throws \Zend\Wildfire\Exception
  75. */
  76. public static function init($class = null)
  77. {
  78. if (self::$_instance !== null) {
  79. throw new Wildfire\Exception('Singleton instance of Zend_Wildfire_Channel_HttpHeaders already exists!');
  80. }
  81. if ($class !== null) {
  82. if (!is_string($class)) {
  83. throw new Wildfire\Exception('Third argument is not a class string');
  84. }
  85. self::$_instance = new $class();
  86. if (!self::$_instance instanceof HttpHeaders) {
  87. self::$_instance = null;
  88. throw new Wildfire\Exception('Invalid class to third argument. Must be subclass of Zend_Wildfire_Channel_HttpHeaders.');
  89. }
  90. } else {
  91. self::$_instance = new self();
  92. }
  93. return self::$_instance;
  94. }
  95. /**
  96. * Get or create singleton instance
  97. *
  98. * @param $skipCreate boolean True if an instance should not be created
  99. * @return \Zend\Wildfire\Channel\HttpHeaders
  100. */
  101. public static function getInstance($skipCreate=false)
  102. {
  103. if (self::$_instance===null && $skipCreate!==true) {
  104. return self::init();
  105. }
  106. return self::$_instance;
  107. }
  108. /**
  109. * Destroys the singleton instance
  110. *
  111. * Primarily used for testing.
  112. *
  113. * @return void
  114. */
  115. public static function destroyInstance()
  116. {
  117. self::$_instance = null;
  118. }
  119. /**
  120. * Get the instance of a give protocol for this channel
  121. *
  122. * @param string $uri The URI for the protocol
  123. * @return object Returns the protocol instance for the diven URI
  124. */
  125. public function getProtocol($uri)
  126. {
  127. if (!isset($this->_protocols[$uri])) {
  128. $this->_protocols[$uri] = $this->_initProtocol($uri);
  129. }
  130. $this->_registerControllerPlugin();
  131. return $this->_protocols[$uri];
  132. }
  133. /**
  134. * Initialize a new protocol
  135. *
  136. * @param string $uri The URI for the protocol to be initialized
  137. * @return object Returns the new initialized protocol instance
  138. * @throws \Zend\Wildfire\Exception
  139. */
  140. protected function _initProtocol($uri)
  141. {
  142. switch ($uri) {
  143. case Protocol\JsonStream::PROTOCOL_URI;
  144. return new Protocol\JsonStream();
  145. }
  146. throw new Wildfire\Exception('Tyring to initialize unknown protocol for URI "'.$uri.'".');
  147. }
  148. /**
  149. * Flush all data from all protocols and send all data to response headers.
  150. *
  151. * @return boolean Returns TRUE if data was flushed
  152. */
  153. public function flush()
  154. {
  155. if (!$this->_protocols || !$this->isReady()) {
  156. return false;
  157. }
  158. foreach ( $this->_protocols as $protocol ) {
  159. $payload = $protocol->getPayload($this);
  160. if ($payload) {
  161. foreach( $payload as $message ) {
  162. $this->getResponse()->setHeader(self::$_headerPrefix.$message[0],
  163. $message[1], true);
  164. }
  165. }
  166. }
  167. return true;
  168. }
  169. /**
  170. * Set the index of the plugin in the controller dispatch loop plugin stack
  171. *
  172. * @param integer $index The index of the plugin in the stack
  173. * @return integer The previous index.
  174. */
  175. public static function setControllerPluginStackIndex($index)
  176. {
  177. $previous = self::$_controllerPluginStackIndex;
  178. self::$_controllerPluginStackIndex = $index;
  179. return $previous;
  180. }
  181. /**
  182. * Register this object as a controller plugin.
  183. *
  184. * @return void
  185. */
  186. protected function _registerControllerPlugin()
  187. {
  188. $controller = Controller\Front::getInstance();
  189. if (!$controller->hasPlugin(get_class($this))) {
  190. $controller->registerPlugin($this, self::$_controllerPluginStackIndex);
  191. }
  192. }
  193. /*
  194. * Zend_Wildfire_Channel_Interface
  195. */
  196. /**
  197. * Determine if channel is ready.
  198. *
  199. * The channel is ready as long as the request and response objects are initialized,
  200. * can send headers and the FirePHP header exists in the User-Agent.
  201. *
  202. * If the header does not exist in the User-Agent, no appropriate client
  203. * is making this request and the messages should not be sent.
  204. *
  205. * A timing issue arises when messages are logged before the request/response
  206. * objects are initialized. In this case we do not yet know if the client
  207. * will be able to accept the messages. If we consequently indicate that
  208. * the channel is not ready, these messages will be dropped which is in
  209. * most cases not the intended behaviour. The intent is to send them at the
  210. * end of the request when the request/response objects will be available
  211. * for sure.
  212. *
  213. * If the request/response objects are not yet initialized we assume if messages are
  214. * logged, the client will be able to receive them. As soon as the request/response
  215. * objects are availoable and a message is logged this assumption is challenged.
  216. * If the client cannot accept the messages any further messages are dropped
  217. * and messages sent prior are kept but discarded when the channel is finally
  218. * flushed at the end of the request.
  219. *
  220. * When the channel is flushed the $forceCheckRequest option is used to force
  221. * a check of the request/response objects. This is the last verification to ensure
  222. * messages are only sent when the client can accept them.
  223. *
  224. * @param boolean $forceCheckRequest OPTIONAL Set to TRUE if the request must be checked
  225. * @return boolean Returns TRUE if channel is ready.
  226. */
  227. public function isReady($forceCheckRequest=false)
  228. {
  229. if (!$forceCheckRequest
  230. && !$this->_request
  231. && !$this->_response
  232. ) {
  233. return true;
  234. }
  235. return ($this->getResponse()->canSendHeaders()
  236. && (preg_match_all(
  237. '/\s?FirePHP\/([\.\d]*)\s?/si',
  238. $this->getRequest()->getHeader('User-Agent'),
  239. $m
  240. ) ||
  241. (($header = $this->getRequest()->getHeader('X-FirePHP-Version'))
  242. && preg_match_all('/^([\.\d]*)$/si', $header, $m)
  243. ))
  244. );
  245. }
  246. /*
  247. * Zend_Controller_Plugin_Abstract
  248. */
  249. /**
  250. * Flush messages to headers as late as possible but before headers have been sent.
  251. *
  252. * @return void
  253. */
  254. public function dispatchLoopShutdown()
  255. {
  256. $this->flush();
  257. }
  258. /**
  259. * Get the request object
  260. *
  261. * @return \Zend\Controller\Request\AbstractRequest
  262. * @throws \Zend\Wildfire\Exception
  263. */
  264. public function getRequest()
  265. {
  266. if (!$this->_request) {
  267. $controller = Controller\Front::getInstance();
  268. $this->setRequest($controller->getRequest());
  269. }
  270. if (!$this->_request) {
  271. throw new Wildfire\Exception('Request objects not initialized.');
  272. }
  273. return $this->_request;
  274. }
  275. /**
  276. * Get the response object
  277. *
  278. * @return \Zend\Controller\Response\AbstractResponse
  279. * @throws \Zend\Wildfire\Exception
  280. */
  281. public function getResponse()
  282. {
  283. if (!$this->_response) {
  284. $response = Controller\Front::getInstance()->getResponse();
  285. if ($response) {
  286. $this->setResponse($response);
  287. }
  288. }
  289. if (!$this->_response) {
  290. throw new Wildfire\Exception('Response objects not initialized.');
  291. }
  292. return $this->_response;
  293. }
  294. }