1. sfCacheFilter.class.php
  2. /** * sfCacheFilter deals with page caching and action caching. * * @package symfony * @subpackage filter * @author Fabien Potencier * @version SVN: $Id: sfCacheFilter.class.php 24619 2009-11-30 23:14:18Z FabianLange $ */
  3. class sfCacheFilter extends sfFilter
  4. {
  5. protected
  6. $cacheManager = null,
  7. $request = null,
  8. $response = null,
  9. $routing = null,
  10. $cache = array();
  11. /**
  12. * Initializes this Filter.
  13. *
  14. * @param sfContext $context The current application context
  15. * @param array $parameters An associative array of initialization parameters
  16. *
  17. * @return bool true, if initialization completes successfully, otherwise false
  18. *
  19. * @throws <b>sfInitializationException</b> If an error occurs while initializing this Filter
  20. */
  21. public function initialize($context, $parameters = array())
  22. {
  23. parent::initialize($context, $parameters);
  24. $this->cacheManager = $context->getViewCacheManager();
  25. $this->request = $context->getRequest();
  26. $this->response = $context->getResponse();
  27. $this->routing = $context->getRouting();
  28. }
  29. /**
  30. * Executes this filter.
  31. *
  32. * @param sfFilterChain $filterChain A sfFilterChain instance
  33. */
  34. public function execute($filterChain)
  35. {
  36. // execute this filter only once, if cache is set and no GET or POST parameters
  37. if (!sfConfig::get('sf_cache'))
  38. {
  39. $filterChain->execute();
  40. return;
  41. }
  42. if ($this->executeBeforeExecution())
  43. {
  44. $filterChain->execute();
  45. }
  46. $this->executeBeforeRendering();
  47. }
  48. public function executeBeforeExecution()
  49. {
  50. $uri = $this->cacheManager->getCurrentCacheKey();
  51. if (null === $uri)
  52. {
  53. return true;
  54. }
  55. // page cache
  56. $cacheable = $this->cacheManager->isCacheable($uri);
  57. if ($cacheable && $this->cacheManager->withLayout($uri))
  58. {
  59. $inCache = $this->cacheManager->getPageCache($uri);
  60. $this->cache[$uri] = $inCache;
  61. if ($inCache)
  62. {
  63. // page is in cache, so no need to run execution filter
  64. return false;
  65. }
  66. }
  67. return true;
  68. }
  69. /**
  70. * Executes this filter.
  71. */
  72. public function executeBeforeRendering()
  73. {
  74. // cache only 200 HTTP status
  75. if (200 != $this->response->getStatusCode())
  76. {
  77. return;
  78. }
  79. $uri = $this->cacheManager->getCurrentCacheKey();
  80. // save page in cache
  81. if (isset($this->cache[$uri]) && false === $this->cache[$uri])
  82. {
  83. $this->setCacheExpiration($uri);
  84. $this->setCacheValidation($uri);
  85. // set Vary headers
  86. foreach ($this->cacheManager->getVary($uri, 'page') as $vary)
  87. {
  88. $this->response->addVaryHttpHeader($vary);
  89. }
  90. $this->cacheManager->setPageCache($uri);
  91. }
  92. // cache validation
  93. $this->checkCacheValidation();
  94. }
  95. /**
  96. * Sets cache expiration headers.
  97. *
  98. * @param string $uri An internal URI
  99. */
  100. protected function setCacheExpiration($uri)
  101. {
  102. // don't add cache expiration (Expires) if
  103. // * the client lifetime is not set
  104. // * the response already has a cache validation (Last-Modified header)
  105. // * the Expires header has already been set
  106. if (!$lifetime = $this->cacheManager->getClientLifeTime($uri, 'page'))
  107. {
  108. return;
  109. }
  110. if ($this->response->hasHttpHeader('Last-Modified'))
  111. {
  112. return;
  113. }
  114. if (!$this->response->hasHttpHeader('Expires'))
  115. {
  116. $this->response->setHttpHeader('Expires', $this->response->getDate(time() + $lifetime), false);
  117. $this->response->addCacheControlHttpHeader('max-age', $lifetime);
  118. }
  119. }
  120. /**
  121. * Sets cache validation headers.
  122. *
  123. * @param string $uri An internal URI
  124. */
  125. protected function setCacheValidation($uri)
  126. {
  127. // don't add cache validation (Last-Modified) if
  128. // * the client lifetime is set (cache.yml)
  129. // * the response already has a Last-Modified header
  130. if ($this->cacheManager->getClientLifeTime($uri, 'page'))
  131. {
  132. return;
  133. }
  134. if (!$this->response->hasHttpHeader('Last-Modified'))
  135. {
  136. $this->response->setHttpHeader('Last-Modified', $this->response->getDate(time()), false);
  137. }
  138. if (sfConfig::get('sf_etag'))
  139. {
  140. $etag = '"'.md5($this->response->getContent()).'"';
  141. $this->response->setHttpHeader('ETag', $etag);
  142. }
  143. }
  144. /**
  145. * Checks cache validation headers.
  146. */
  147. protected function checkCacheValidation()
  148. {
  149. // Etag support
  150. if (sfConfig::get('sf_etag'))
  151. {
  152. $etag = '"'.md5($this->response->getContent()).'"';
  153. if ($this->request->getHttpHeader('IF_NONE_MATCH') == $etag)
  154. {
  155. $this->response->setStatusCode(304);
  156. $this->response->setHeaderOnly(true);
  157. if (sfConfig::get('sf_logging_enabled'))
  158. {
  159. $this->context->getEventDispatcher()->notify(new sfEvent($this, 'application.log', array('ETag matches If-None-Match (send 304)')));
  160. }
  161. }
  162. }
  163. // conditional GET support
  164. // never in debug mode
  165. if ($this->response->hasHttpHeader('Last-Modified') && !sfConfig::get('sf_debug'))
  166. {
  167. $lastModified = $this->response->getHttpHeader('Last-Modified');
  168. if ($this->request->getHttpHeader('IF_MODIFIED_SINCE') == $lastModified)
  169. {
  170. $this->response->setStatusCode(304);
  171. $this->response->setHeaderOnly(true);
  172. if (sfConfig::get('sf_logging_enabled'))
  173. {
  174. $this->context->getEventDispatcher()->notify(new sfEvent($this, 'application.log', array('Last-Modified matches If-Modified-Since (send 304)')));
  175. }
  176. }
  177. }
  178. }
  179. }

Debug toolbar