Development

/branches/1.2/lib/view/sfViewCacheManager.class.php

You must first sign up to be able to contribute.

root/branches/1.2/lib/view/sfViewCacheManager.class.php

Revision 24513, 27.6 kB (checked in by FabianLange, 5 years ago)

[1.2, 1.3, 1.4] fixed vary cache key again (fixes #7605)

  • Property svn:mime-type set to text/x-php
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Rev Date
Line 
1 <?php
2
3 /*
4  * This file is part of the symfony package.
5  * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
6  *
7  * For the full copyright and license information, please view the LICENSE
8  * file that was distributed with this source code.
9  */
10
11 /**
12  * Cache class to cache the HTML results for actions and templates.
13  *
14  * This class uses a sfCache instance implementation to store cache.
15  *
16  * To disable all caching, you can set the [sf_cache] constant to false.
17  *
18  * @package    symfony
19  * @subpackage view
20  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
21  * @version    SVN: $Id$
22  */
23 class sfViewCacheManager
24 {
25   protected
26     $cache       = null,
27     $cacheConfig = array(),
28     $context     = null,
29     $dispatcher  = null,
30     $controller  = null,
31     $routing     = null,
32     $loaded      = array();
33
34   /**
35    * Class constructor.
36    *
37    * @see initialize()
38    */
39   public function __construct($context, sfCache $cache)
40   {
41     $this->initialize($context, $cache);
42   }
43
44   /**
45    * Initializes the cache manager.
46    *
47    * @param sfContext $context  Current application context
48    * @param sfCache   $cache    An sfCache instance
49    */
50   public function initialize($context, sfCache $cache)
51   {
52     $this->context    = $context;
53     $this->dispatcher = $context->getEventDispatcher();
54     $this->controller = $context->getController();
55
56     if (sfConfig::get('sf_web_debug'))
57     {
58       $this->dispatcher->connect('view.cache.filter_content', array($this, 'decorateContentWithDebug'));
59     }
60
61     // empty configuration
62     $this->cacheConfig = array();
63
64     // cache instance
65     $this->cache = $cache;
66
67     // routing instance
68     $this->routing = $context->getRouting();
69   }
70
71   /**
72    * Retrieves the current cache context.
73    *
74    * @return sfContext The sfContext instance
75    */
76   public function getContext()
77   {
78     return $this->context;
79   }
80
81   /**
82    * Retrieves the current cache object.
83    *
84    * @return sfCache The current cache object
85    */
86   public function getCache()
87   {
88     return $this->cache;
89   }
90
91   /**
92    * Generates a unique cache key for an internal URI.
93    * This cache key can be used by any of the cache engines as a unique identifier to a cached resource
94    *
95    * Basically, the cache key generated for the following internal URI:
96    *   module/action?key1=value1&key2=value2
97    * Looks like:
98    *   /localhost/all/module/action/key1/value1/key2/value2
99    *
100    * @param  string $internalUri       The internal unified resource identifier
101    *                                   Accepts rules formatted like 'module/action?key1=value1&key2=value2'
102    *                                   Does not accept rules starting with a route name, except for '@sf_cache_partial'
103    * @param  string $hostName          The host name
104    *                                   Optional - defaults to the current host name bu default
105    * @param  string $vary              The vary headers, separated by |, or "all" for all vary headers
106    *                                   Defaults to 'all'
107    * @param  string $contextualPrefix  The contextual prefix for contextual partials.
108    *                                   Defaults to 'currentModule/currentAction/currentPAram1/currentvalue1'
109    *                                   Used only by the sfViewCacheManager::remove() method
110    *
111    * @return string The cache key
112    *                If some of the parameters contained wildcards (* or **), the generated key will also have wildcards
113    */
114   public function generateCacheKey($internalUri, $hostName = '', $vary = '', $contextualPrefix = '')
115   {
116     if ($callable = sfConfig::get('sf_cache_namespace_callable'))
117     {
118       if (!is_callable($callable))
119       {
120         throw new sfException(sprintf('"%s" cannot be called as a function.', var_export($callable, true)));
121       }
122
123       return call_user_func($callable, $internalUri, $hostName, $vary, $contextualPrefix, $this);
124     }
125
126     if (strpos($internalUri, '@') === 0 && strpos($internalUri, '@sf_cache_partial') === false)
127     {
128       throw new sfException('A cache key cannot be generated for an internal URI using the @rule syntax');
129     }
130
131     $cacheKey = '';
132
133     if ($this->isContextual($internalUri))
134     {
135       // Contextual partial
136       if (!$contextualPrefix)
137       {
138         list($route_name, $params) = $this->controller->convertUrlStringToParameters($this->routing->getCurrentInternalUri());
139         $cacheKey = $this->convertParametersToKey($params);
140       }
141       else
142       {
143         $cacheKey = $contextualPrefix;
144       }
145       list($route_name, $params) = $this->controller->convertUrlStringToParameters($internalUri);
146       $cacheKey .= sprintf('/%s/%s/%s', $params['module'], $params['action'], isset($params['sf_cache_key']) ? $params['sf_cache_key'] : '');
147     }
148     else
149     {
150       // Regular action or non-contextual partial
151       list($route_name, $params) = $this->controller->convertUrlStringToParameters($internalUri);
152       if ($route_name == 'sf_cache_partial')
153       {
154         $cacheKey = 'sf_cache_partial/';
155       }
156
157       $cacheKey .= $this->convertParametersToKey($params);
158     }
159
160     // prefix with vary headers
161     if (!$vary)
162     {
163       $varyHeaders = $this->getVary($internalUri);
164       if ($varyHeaders)
165       {
166         sort($varyHeaders);
167         $request = $this->context->getRequest();
168         $vary = '';
169
170         foreach ($varyHeaders as $header)
171         {
172           $vary .= $header . '_' . $request->getHttpHeader($header) . '_';
173         }
174
175         $vary = preg_replace('/[^a-z0-9]/i', '_', $vary);
176         $vary = preg_replace('/_+/', '_', $vary);
177       }
178       else
179       {
180         $vary = 'all';
181       }
182     }
183
184     // prefix with hostname
185     if (!$hostName)
186     {
187       $request = $this->context->getRequest();
188       $hostName = $request->getHost();
189     }
190     $hostName = preg_replace('/[^a-z0-9\*]/i', '_', $hostName);
191     $hostName = strtolower(preg_replace('/_+/', '_', $hostName));
192
193     $cacheKey = sprintf('/%s/%s/%s', $hostName, $vary, $cacheKey);
194
195     // replace multiple /
196     $cacheKey = preg_replace('#/+#', '/', $cacheKey);
197
198     return $cacheKey;
199   }
200
201   /**
202    * Transforms an associative array of parameters from an URI into a unique key
203    *
204    * @param  array $params  Associative array of parameters from the URI (including, at least, module and action)
205    *
206    * @return string Unique key
207    */
208   protected function convertParametersToKey($params)
209   {
210     if(!isset($params['module']) || !isset($params['action']))
211     {
212       throw new sfException('A cache key must contain both a module and an action parameter');
213     }
214     $module = $params['module'];
215     unset($params['module']);
216     $action = $params['action'];
217     unset($params['action']);
218     ksort($params);
219     $cacheKey = sprintf('%s/%s', $module, $action);
220     foreach ($params as $key => $value)
221     {
222       $cacheKey .= sprintf('/%s/%s', $key, $value);
223     }
224
225     return $cacheKey;
226   }
227
228   /**
229    * Adds a cache to the manager.
230    *
231    * @param string $moduleName  Module name
232    * @param string $actionName  Action name
233    * @param array  $options     Options for the cache
234    */
235   public function addCache($moduleName, $actionName, $options = array())
236   {
237     // normalize vary headers
238     if (isset($options['vary']))
239     {
240       foreach ($options['vary'] as $key => $name)
241       {
242         $options['vary'][$key] = strtr(strtolower($name), '_', '-');
243       }
244     }
245
246     $options['lifeTime'] = isset($options['lifeTime']) ? $options['lifeTime'] : 0;
247     if (!isset($this->cacheConfig[$moduleName]))
248     {
249       $this->cacheConfig[$moduleName] = array();
250     }
251     $this->cacheConfig[$moduleName][$actionName] = array(
252       'withLayout'     => isset($options['withLayout']) ? $options['withLayout'] : false,
253       'lifeTime'       => $options['lifeTime'],
254       'clientLifeTime' => isset($options['clientLifeTime']) ? $options['clientLifeTime'] : $options['lifeTime'],
255       'contextual'     => isset($options['contextual']) ? $options['contextual'] : false,
256       'vary'           => isset($options['vary']) ? $options['vary'] : array(),
257     );
258   }
259
260   /**
261    * Registers configuration options for the cache.
262    *
263    * @param string $moduleName  Module name
264    */
265   public function registerConfiguration($moduleName)
266   {
267     if (!isset($this->loaded[$moduleName]))
268     {
269       require($this->context->getConfigCache()->checkConfig('modules/'.$moduleName.'/config/cache.yml'));
270       $this->loaded[$moduleName] = true;
271     }
272   }
273
274   /**
275    * Retrieves the layout from the cache option list.
276    *
277    * @param  string $internalUri  Internal uniform resource identifier
278    *
279    * @return bool true, if have layout otherwise false
280    */
281   public function withLayout($internalUri)
282   {
283     return $this->getCacheConfig($internalUri, 'withLayout', false);
284   }
285
286   /**
287    * Retrieves lifetime from the cache option list.
288    *
289    * @param  string $internalUri  Internal uniform resource identifier
290    *
291    * @return int LifeTime
292    */
293   public function getLifeTime($internalUri)
294   {
295     return $this->getCacheConfig($internalUri, 'lifeTime', 0);
296   }
297
298   /**
299    * Retrieves client lifetime from the cache option list
300    *
301    * @param  string $internalUri  Internal uniform resource identifier
302    *
303    * @return int Client lifetime
304    */
305   public function getClientLifeTime($internalUri)
306   {
307     return $this->getCacheConfig($internalUri, 'clientLifeTime', 0);
308   }
309
310   /**
311    * Retrieves contextual option from the cache option list.
312    *
313    * @param  string $internalUri  Internal uniform resource identifier
314    *
315    * @return boolean true, if is contextual otherwise false
316    */
317   public function isContextual($internalUri)
318   {
319     return $this->getCacheConfig($internalUri, 'contextual', false);
320   }
321
322   /**
323    * Retrieves vary option from the cache option list.
324    *
325    * @param  string $internalUri  Internal uniform resource identifier
326    *
327    * @return array Vary options for the cache
328    */
329   public function getVary($internalUri)
330   {
331     return $this->getCacheConfig($internalUri, 'vary', array());
332   }
333
334   /**
335    * Gets a config option from the cache.
336    *
337    * @param string $internalUri   Internal uniform resource identifier
338    * @param string $key           Option name
339    * @param string $defaultValue  Default value of the option
340    *
341    * @return mixed Value of the option
342    */
343   protected function getCacheConfig($internalUri, $key, $defaultValue = null)
344   {
345     list($route_name, $params) = $this->controller->convertUrlStringToParameters($internalUri);
346
347     $this->registerConfiguration($params['module']);
348
349     $value = $defaultValue;
350     if (isset($this->cacheConfig[$params['module']][$params['action']][$key]))
351     {
352       $value = $this->cacheConfig[$params['module']][$params['action']][$key];
353     }
354     else if (isset($this->cacheConfig[$params['module']]['DEFAULT'][$key]))
355     {
356       $value = $this->cacheConfig[$params['module']]['DEFAULT'][$key];
357     }
358
359     return $value;
360   }
361
362   /**
363    * Returns true if the current content is cacheable.
364    *
365    * Possible break in backward compatibility: If the sf_lazy_cache_key
366    * setting is turned on in settings.yml, this method is not used when
367    * initially checking a partial's cacheability.
368    *
369    * @see sfPartialView, isActionCacheable()
370    *
371    * @param  string $internalUri  Internal uniform resource identifier
372    *
373    * @return bool true, if the content is cacheable otherwise false
374    */
375   public function isCacheable($internalUri)
376   {
377     if (count($_GET) || count($_POST))
378     {
379       return false;
380     }
381
382     list($route_name, $params) = $this->controller->convertUrlStringToParameters($internalUri);
383
384     $this->registerConfiguration($params['module']);
385
386     if (isset($this->cacheConfig[$params['module']][$params['action']]))
387     {
388       return ($this->cacheConfig[$params['module']][$params['action']]['lifeTime'] > 0);
389     }
390     else if (isset($this->cacheConfig[$params['module']]['DEFAULT']))
391     {
392       return ($this->cacheConfig[$params['module']]['DEFAULT']['lifeTime'] > 0);
393     }
394
395     return false;
396   }
397
398   /**
399    * Returns true if the action is cacheable.
400    *
401    * @param  string $moduleName A module name
402    * @param  string $actionName An action or partial template name
403    *
404    * @return boolean True if the action is cacheable
405    *
406    * @see isCacheable()
407    */
408   public function isActionCacheable($moduleName, $actionName)
409   {
410     if (count($_GET) || count($_POST))
411     {
412       return false;
413     }
414
415     $this->registerConfiguration($moduleName);
416
417     if (isset($this->cacheConfig[$moduleName][$actionName]))
418     {
419       return $this->cacheConfig[$moduleName][$actionName]['lifeTime'] > 0;
420     }
421     else if (isset($this->cacheConfig[$moduleName]['DEFAULT']))
422     {
423       return $this->cacheConfig[$moduleName]['DEFAULT']['lifeTime'] > 0;
424     }
425
426     return false;
427   }
428
429   /**
430    * Retrieves content in the cache.
431    *
432    * @param  string $internalUri  Internal uniform resource identifier
433    *
434    * @return string The content in the cache
435    */
436   public function get($internalUri)
437   {
438     // no cache or no cache set for this action
439     if (!$this->isCacheable($internalUri) || $this->ignore())
440     {
441       return null;
442     }
443
444     $retval = $this->cache->get($this->generateCacheKey($internalUri));
445
446     if (sfConfig::get('sf_logging_enabled'))
447     {
448       $this->dispatcher->notify(new sfEvent($this, 'application.log', array(sprintf('Cache for "%s" %s', $internalUri, $retval !== null ? 'exists' : 'does not exist'))));
449     }
450
451     return $retval;
452   }
453
454   /**
455    * Returns true if there is a cache.
456    *
457    * @param  string $internalUri  Internal uniform resource identifier
458    *
459    * @return bool true, if there is a cache otherwise false
460    */
461   public function has($internalUri)
462   {
463     if (!$this->isCacheable($internalUri) || $this->ignore())
464     {
465       return null;
466     }
467
468     return $this->cache->has($this->generateCacheKey($internalUri));
469   }
470
471   /**
472    * Ignores the cache functionality.
473    *
474    * @return bool true, if the cache is ignore otherwise false
475    */
476   protected function ignore()
477   {
478     // ignore cache parameter? (only available in debug mode)
479     if (sfConfig::get('sf_debug') && $this->context->getRequest()->getAttribute('sf_ignore_cache'))
480     {
481       if (sfConfig::get('sf_logging_enabled'))
482       {
483         $this->dispatcher->notify(new sfEvent($this, 'application.log', array('Discard cache')));
484       }
485
486       return true;
487     }
488
489     return false;
490   }
491
492   /**
493    * Sets the cache content.
494    *
495    * @param  string $data         Data to put in the cache
496    * @param  string $internalUri  Internal uniform resource identifier
497    *
498    * @return boolean true, if the data get set successfully otherwise false
499    */
500   public function set($data, $internalUri)
501   {
502     if (!$this->isCacheable($internalUri))
503     {
504       return false;
505     }
506
507     try
508     {
509       $ret = $this->cache->set($this->generateCacheKey($internalUri), $data, $this->getLifeTime($internalUri));
510     }
511     catch (Exception $e)
512     {
513       return false;
514     }
515
516     if (sfConfig::get('sf_logging_enabled'))
517     {
518       $this->dispatcher->notify(new sfEvent($this, 'application.log', array(sprintf('Save cache for "%s"', $internalUri))));
519     }
520
521     return true;
522   }
523
524   /**
525    * Removes the content in the cache.
526    *
527    * @param  string $internalUri       Internal uniform resource identifier
528    * @param  string $hostName          The host name
529    * @param  string $vary              The vary headers, separated by |, or "all" for all vary headers
530    * @param  string $contextualPrefix  The removal prefix for contextual partials. Defaults to '**' (all actions, all params)
531    *
532    * @return bool true, if the remove happened, false otherwise
533    */
534   public function remove($internalUri, $hostName = '', $vary = '', $contextualPrefix = '**')
535   {
536     if (sfConfig::get('sf_logging_enabled'))
537     {
538       $this->dispatcher->notify(new sfEvent($this, 'application.log', array(sprintf('Remove cache for "%s"', $internalUri))));
539     }
540
541     $cacheKey = $this->generateCacheKey($internalUri, $hostName, $vary, $contextualPrefix);
542
543     if(strpos($cacheKey, '*'))
544     {
545       return $this->cache->removePattern($cacheKey);
546     }
547     elseif ($this->cache->has($cacheKey))
548     {
549       return $this->cache->remove($cacheKey);
550     }
551   }
552
553   /**
554    * Retrieves the last modified time.
555    *
556    * @param  string $internalUri  Internal uniform resource identifier
557    *
558    * @return int    The last modified datetime
559    */
560   public function getLastModified($internalUri)
561   {
562     if (!$this->isCacheable($internalUri))
563     {
564       return 0;
565     }
566
567     return $this->cache->getLastModified($this->generateCacheKey($internalUri));
568   }
569
570   /**
571    * Retrieves the timeout.
572    *
573    * @param  string $internalUri  Internal uniform resource identifier
574    *
575    * @return int    The timeout datetime
576    */
577   public function getTimeout($internalUri)
578   {
579     if (!$this->isCacheable($internalUri))
580     {
581       return 0;
582     }
583
584     return $this->cache->getTimeout($this->generateCacheKey($internalUri));
585   }
586
587   /**
588    * Starts the fragment cache.
589    *
590    * @param  string $name            Unique fragment name
591    * @param  string $lifeTime        Life time for the cache
592    * @param  string $clientLifeTime  Client life time for the cache
593    * @param  array  $vary            Vary options for the cache
594    *
595    * @return bool true, if success otherwise false
596    */
597   public function start($name, $lifeTime, $clientLifeTime = null, $vary = array())
598   {
599     $internalUri = $this->routing->getCurrentInternalUri();
600
601     if (!$clientLifeTime)
602     {
603       $clientLifeTime = $lifeTime;
604     }
605
606     // add cache config to cache manager
607     list($route_name, $params) = $this->controller->convertUrlStringToParameters($internalUri);
608     $this->addCache($params['module'], $params['action'], array('withLayout' => false, 'lifeTime' => $lifeTime, 'clientLifeTime' => $clientLifeTime, 'vary' => $vary));
609
610     // get data from cache if available
611     $data = $this->get($internalUri.(strpos($internalUri, '?') ? '&' : '?').'_sf_cache_key='.$name);
612     if ($data !== null)
613     {
614       return $data;
615     }
616     else
617     {
618       ob_start();
619       ob_implicit_flush(0);
620
621       return null;
622     }
623   }
624
625   /**
626    * Stops the fragment cache.
627    *
628    * @param  string $name Unique fragment name
629    *
630    * @return bool true, if success otherwise false
631    */
632   public function stop($name)
633   {
634     $data = ob_get_clean();
635
636     // save content to cache
637     $internalUri = $this->routing->getCurrentInternalUri();
638     try
639     {
640       $this->set($data, $internalUri.(strpos($internalUri, '?') ? '&' : '?').'_sf_cache_key='.$name);
641     }
642     catch (Exception $e)
643     {
644     }
645
646     return $data;
647   }
648
649   /**
650    * Computes the cache key based on the passed parameters.
651    *
652    * @param array $parameters  An array of parameters
653    */
654   public function computeCacheKey(array $parameters)
655   {
656     if (isset($parameters['sf_cache_key']))
657     {
658       return $parameters['sf_cache_key'];
659     }
660
661     if (sfConfig::get('sf_logging_enabled'))
662     {
663       $this->dispatcher->notify(new sfEvent($this, 'application.log', array('Generate cache key')));
664     }
665
666     return md5(serialize($parameters));
667   }
668
669   /**
670    * Checks that the supplied parameters include a cache key.
671    *
672    * If no 'sf_cache_key' parameter is present one is added to the array as
673    * it is passed by reference.
674    *
675    * @param  array  $parameters An array of parameters
676    *
677    * @return string The cache key
678    */
679   public function checkCacheKey(array & $parameters)
680   {
681     $parameters['sf_cache_key'] = $this->computeCacheKey($parameters);
682
683     return $parameters['sf_cache_key'];
684   }
685
686   /**
687    * Computes a partial internal URI.
688    *
689    * @param  string $module    The module name
690    * @param  string $action    The action name
691    * @param  string $cacheKey  The cache key
692    *
693    * @return string The internal URI
694    */
695   public function getPartialUri($module, $action, $cacheKey)
696   {
697     return sprintf('@sf_cache_partial?module=%s&action=%s&sf_cache_key=%s', $module, $action, $cacheKey);
698   }
699
700   /**
701    * Returns whether a partial template is in the cache.
702    *
703    * @param  string $module    The module name
704    * @param  string $action    The action name
705    * @param  string $cacheKey  The cache key
706    *
707    * @return bool true if a partial is in the cache, false otherwise
708    */
709   public function hasPartialCache($module, $action, $cacheKey)
710   {
711     return $this->has($this->getPartialUri($module, $action, $cacheKey));
712   }
713
714   /**
715    * Gets a partial template from the cache.
716    *
717    * @param  string $module    The module name
718    * @param  string $action    The action name
719    * @param  string $cacheKey  The cache key
720    *
721    * @return string The cache content
722    */
723   public function getPartialCache($module, $action, $cacheKey)
724   {
725     $uri = $this->getPartialUri($module, $action, $cacheKey);
726
727     if (!$this->isCacheable($uri))
728     {
729       return null;
730     }
731
732     // retrieve content from cache
733     $cache = $this->get($uri);
734
735     if (is_null($cache))
736     {
737       return null;
738     }
739
740     $cache = unserialize($cache);
741     $content = $cache['content'];
742     $this->context->getResponse()->merge($cache['response']);
743
744     if (sfConfig::get('sf_web_debug'))
745     {
746       $content = $this->dispatcher->filter(new sfEvent($this, 'view.cache.filter_content', array('response' => $this->context->getResponse(), 'uri' => $uri, 'new' => false)), $content)->getReturnValue();
747     }
748
749     return $content;
750   }
751
752   /**
753    * Sets an action template in the cache.
754    *
755    * @param  string $module    The module name
756    * @param  string $action    The action name
757    * @param  string $cacheKey  The cache key
758    * @param  string $content   The content to cache
759    *
760    * @return string The cached content
761    */
762   public function setPartialCache($module, $action, $cacheKey, $content)
763   {
764     $uri = $this->getPartialUri($module, $action, $cacheKey);
765     if (!$this->isCacheable($uri))
766     {
767       return $content;
768     }
769
770     $saved = $this->set(serialize(array('content' => $content, 'response' => $this->context->getResponse())), $uri);
771
772     if ($saved && sfConfig::get('sf_web_debug'))
773     {
774       $content = $this->dispatcher->filter(new sfEvent($this, 'view.cache.filter_content', array('response' => $this->context->getResponse(), 'uri' => $uri, 'new' => true)), $content)->getReturnValue();
775     }
776
777     return $content;
778   }
779
780   /**
781    * Returns whether an action template is in the cache.
782    *
783    * @param  string  $uri  The internal URI
784    *
785    * @return bool true if an action is in the cache, false otherwise
786    */
787   public function hasActionCache($uri)
788   {
789     return $this->has($uri) && !$this->withLayout($uri);
790   }
791
792   /**
793    * Gets an action template from the cache.
794    *
795    * @param  string $uri  The internal URI
796    *
797    * @return array  An array composed of the cached content and the view attribute holder
798    */
799   public function getActionCache($uri)
800   {
801     if (!$this->isCacheable($uri) || $this->withLayout($uri))
802     {
803       return null;
804     }
805
806     // retrieve content from cache
807     $cache = $this->get($uri);
808
809     if (is_null($cache))
810     {
811       return null;
812     }
813
814     $cache = unserialize($cache);
815     $content = $cache['content'];
816     $cache['response']->setEventDispatcher($this->dispatcher);
817     $this->context->getResponse()->copyProperties($cache['response']);
818
819     if (sfConfig::get('sf_web_debug'))
820     {
821       $content = $this->dispatcher->filter(new sfEvent($this, 'view.cache.filter_content', array('response' => $this->context->getResponse(), 'uri' => $uri, 'new' => false)), $content)->getReturnValue();
822     }
823
824     return array($content, $cache['decoratorTemplate']);
825   }
826
827   /**
828    * Sets an action template in the cache.
829    *
830    * @param  string $uri                The internal URI
831    * @param  string $content            The content to cache
832    * @param  string $decoratorTemplate  The view attribute holder to cache
833    *
834    * @return string The cached content
835    */
836   public function setActionCache($uri, $content, $decoratorTemplate)
837   {
838     if (!$this->isCacheable($uri) || $this->withLayout($uri))
839     {
840       return $content;
841     }
842
843     $saved = $this->set(serialize(array('content' => $content, 'decoratorTemplate' => $decoratorTemplate, 'response' => $this->context->getResponse())), $uri);
844
845     if ($saved && sfConfig::get('sf_web_debug'))
846     {
847       $content = $this->dispatcher->filter(new sfEvent($this, 'view.cache.filter_content', array('response' => $this->context->getResponse(), 'uri' => $uri, 'new' => true)), $content)->getReturnValue();
848     }
849
850     return $content;
851   }
852
853   /**
854    * Sets a page in the cache.
855    *
856    * @param string $uri  The internal URI
857    */
858   public function setPageCache($uri)
859   {
860     if (sfView::RENDER_CLIENT != $this->controller->getRenderMode())
861     {
862       return;
863     }
864
865     // save content in cache
866     $saved = $this->set(serialize($this->context->getResponse()), $uri);
867
868     if ($saved && sfConfig::get('sf_web_debug'))
869     {
870       $content = $this->dispatcher->filter(new sfEvent($this, 'view.cache.filter_content', array('response' => $this->context->getResponse(), 'uri' => $uri, 'new' => true)), $this->context->getResponse()->getContent())->getReturnValue();
871
872       $this->context->getResponse()->setContent($content);
873     }
874   }
875
876   /**
877    * Gets a page from the cache.
878    *
879    * @param  string $uri  The internal URI
880    *
881    * @return string The cached page
882    */
883   public function getPageCache($uri)
884   {
885     $retval = $this->get($uri);
886
887     if (is_null($retval))
888     {
889       return false;
890     }
891
892     $cachedResponse = unserialize($retval);
893     $cachedResponse->setEventDispatcher($this->dispatcher);
894
895     if (sfView::RENDER_VAR == $this->controller->getRenderMode())
896     {
897       $this->controller->getActionStack()->getLastEntry()->setPresentation($cachedResponse->getContent());
898       $this->context->getResponse()->setContent('');
899     }
900     else
901     {
902       $this->context->setResponse($cachedResponse);
903
904       if (sfConfig::get('sf_web_debug'))
905       {
906         $content = $this->dispatcher->filter(new sfEvent($this, 'view.cache.filter_content', array('response' => $this->context->getResponse(), 'uri' => $uri, 'new' => false)), $this->context->getResponse()->getContent())->getReturnValue();
907
908         $this->context->getResponse()->setContent($content);
909       }
910     }
911
912     return true;
913   }
914
915   /**
916    * Listens to the 'view.cache.filter_content' event to decorate a chunk of HTML with cache information.
917    *
918    * @param sfEvent $event   A sfEvent instance
919    * @param string  $content The HTML content
920    *
921    * @return string The decorated HTML string
922    */
923   public function decorateContentWithDebug(sfEvent $event, $content)
924   {
925     // don't decorate if not html or if content is null
926     if (!$content || false === strpos($event['response']->getContentType(), 'html'))
927     {
928       return $content;
929     }
930
931     $this->context->getConfiguration()->loadHelpers(array('Helper', 'Url', 'Asset', 'Tag'));
932
933     $bgColor      = $event['new'] ? '#9ff' : '#ff9';
934     $lastModified = $this->getLastModified($event['uri']);
935     $id           = md5($event['uri']);
936
937     return '
938       <div id="main_'.$id.'" class="sfWebDebugActionCache" style="border: 1px solid #f00">
939       <div id="sub_main_'.$id.'" class="sfWebDebugCache" style="background-color: '.$bgColor.'; border-right: 1px solid #f00; border-bottom: 1px solid #f00;">
940       <div style="height: 16px; padding: 2px"><a href="#" onclick="sfWebDebugToggle(\'sub_main_info_'.$id.'\'); return false;"><strong>cache information</strong></a>&nbsp;<a href="#" onclick="sfWebDebugToggle(\'sub_main_'.$id.'\'); document.getElementById(\'main_'.$id.'\').style.border = \'none\'; return false;">'.image_tag(sfConfig::get('sf_web_debug_web_dir').'/images/close.png', array('alt' => 'close')).'</a>&nbsp;</div>
941         <div style="padding: 2px; display: none" id="sub_main_info_'.$id.'">
942         [uri]&nbsp;'.htmlspecialchars($event['uri'], ENT_QUOTES, sfConfig::get('sf_charset')).'<br />
943         [life&nbsp;time]&nbsp;'.$this->getLifeTime($event['uri']).'&nbsp;seconds<br />
944         [last&nbsp;modified]&nbsp;'.(time() - $lastModified).'&nbsp;seconds<br />
945         &nbsp;<br />&nbsp;
946         </div>
947       </div><div>
948       '.$content.'
949       </div></div>
950     ';
951   }
952 }
953
Note: See TracBrowser for help on using the browser.