summaryrefslogtreecommitdiff
path: root/framework/Web/UI/WebControls/TOutputCache.php
diff options
context:
space:
mode:
Diffstat (limited to 'framework/Web/UI/WebControls/TOutputCache.php')
-rw-r--r--framework/Web/UI/WebControls/TOutputCache.php1240
1 files changed, 620 insertions, 620 deletions
diff --git a/framework/Web/UI/WebControls/TOutputCache.php b/framework/Web/UI/WebControls/TOutputCache.php
index 64e4ff42..cc79e76f 100644
--- a/framework/Web/UI/WebControls/TOutputCache.php
+++ b/framework/Web/UI/WebControls/TOutputCache.php
@@ -1,621 +1,621 @@
-<?php
-/**
- * TOutputCache class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TOutputCache class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TOutputCache class.
- *
- * TOutputCache enables caching a portion of a Web page, also known as
- * partial caching. The content being cached can be either static or
- * dynamic.
- *
- * To use TOutputCache, simply enclose the content to be cached
- * within the TOutputCache component tag on a template, e.g.,
- * <code>
- * <com:TOutputCache>
- * content to be cached
- * </com:TOutputCache>
- * </code>
- * where content to be cached can be static text and/or component tags.
- *
- * The validity of the cached content is determined based on two factors:
- * the {@link setDuration Duration} and the cache dependency.
- * The former specifies the number of seconds that the data can remain
- * valid in cache (defaults to 60s), while the latter specifies conditions
- * that the cached data depends on. If a dependency changes,
- * (e.g. relevant data in DB are updated), the cached data will be invalidated.
- *
- * There are two ways to specify cache dependency. One may write event handlers
- * to respond to the {@link onCheckDependency OnCheckDependency} event and set
- * the event parameter's {@link TOutputCacheCheckDependencyEventParameter::getIsValid IsValid}
- * property to indicate whether the cached data remains valid or not.
- * One can also extend TOutputCache and override its {@link getCacheDependency}
- * function. While the former is easier to use, the latter offers more extensibility.
- *
- * The content fetched from cache may be variated with respect to
- * some parameters. It supports variation with respect to request parameters,
- * which is specified by {@link setVaryByParam VaryByParam} property.
- * If a specified request parameter is different, a different version of
- * cached content is used. This is extremely useful if a page's content
- * may be variated according to some GET parameters.
- * The content being cached may also be variated with user sessions if
- * {@link setVaryBySession VaryBySession} is set true.
- * To variate the cached content by other factors, override {@link calculateCacheKey()} method.
- *
- * Output caches can be nested. An outer cache takes precedence over an
- * inner cache. This means, if the content cached by the inner cache expires
- * or is invalidated, while that by the outer cache not, the outer cached
- * content will be used.
- *
- * Note, TOutputCache is effective only for non-postback page requests
- * and when cache module is enabled.
- *
- * Do not attempt to address child controls of TOutputCache when the cached
- * content is to be used. Use {@link getContentCached ContentCached} property
- * to determine whether the content is cached or not.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1
- */
-class TOutputCache extends TControl implements INamingContainer
-{
- const CACHE_ID_PREFIX='prado:outputcache';
- private $_cacheModuleID='';
- private $_dataCached=false;
- private $_cacheAvailable=false;
- private $_cacheChecked=false;
- private $_cacheKey=null;
- private $_duration=60;
- private $_cache=null;
- private $_contents;
- private $_state;
- private $_actions=array();
- private $_varyByParam='';
- private $_keyPrefix='';
- private $_varyBySession=false;
- private $_cachePostBack=false;
- private $_cacheTime=0;
-
- /**
- * Returns a value indicating whether body contents are allowed for this control.
- * This method overrides the parent implementation by checking if cached
- * content is available or not. If yes, it returns false, otherwise true.
- * @param boolean whether body contents are allowed for this control.
- */
- public function getAllowChildControls()
- {
- $this->determineCacheability();
- return !$this->_dataCached;
- }
-
- private function determineCacheability()
- {
- if(!$this->_cacheChecked)
- {
- $this->_cacheChecked=true;
- if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
- {
- if($this->_cacheModuleID!=='')
- {
- $this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
- if(!($this->_cache instanceof ICache))
- throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
- }
- else
- $this->_cache=$this->getApplication()->getCache();
- if($this->_cache!==null)
- {
- $this->_cacheAvailable=true;
- $data=$this->_cache->get($this->getCacheKey());
- if(is_array($data))
- {
- $param=new TOutputCacheCheckDependencyEventParameter;
- $param->setCacheTime(isset($data[3])?$data[3]:0);
- $this->onCheckDependency($param);
- $this->_dataCached=$param->getIsValid();
- }
- else
- $this->_dataCached=false;
- if($this->_dataCached)
- list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
- }
- }
- }
- }
-
- /**
- * Performs the Init step for the control and all its child controls.
- * This method overrides the parent implementation by setting up
- * the stack of the output cache in the page.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function initRecursive($namingContainer=null)
- {
- if($this->_cacheAvailable && !$this->_dataCached)
- {
- $stack=$this->getPage()->getCachingStack();
- $stack->push($this);
- parent::initRecursive($namingContainer);
- $stack->pop();
- }
- else
- parent::initRecursive($namingContainer);
- }
-
- /**
- * Performs the Load step for the control and all its child controls.
- * This method overrides the parent implementation by setting up
- * the stack of the output cache in the page. If the data is restored
- * from cache, it also recovers the actions associated with the cached data.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function loadRecursive()
- {
- if($this->_cacheAvailable && !$this->_dataCached)
- {
- $stack=$this->getPage()->getCachingStack();
- $stack->push($this);
- parent::loadRecursive();
- $stack->pop();
- }
- else
- {
- if($this->_dataCached)
- $this->performActions();
- parent::loadRecursive();
- }
- }
-
- private function performActions()
- {
- $page=$this->getPage();
- $cs=$page->getClientScript();
- foreach($this->_actions as $action)
- {
- if($action[0]==='Page.ClientScript')
- call_user_func_array(array($cs,$action[1]),$action[2]);
- else if($action[0]==='Page')
- call_user_func_array(array($page,$action[1]),$action[2]);
- else
- call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
- }
- }
-
- /**
- * Performs the PreRender step for the control and all its child controls.
- * This method overrides the parent implementation by setting up
- * the stack of the output cache in the page.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function preRenderRecursive()
- {
- if($this->_cacheAvailable && !$this->_dataCached)
- {
- $stack=$this->getPage()->getCachingStack();
- $stack->push($this);
- parent::preRenderRecursive();
- $stack->pop();
- }
- else
- parent::preRenderRecursive();
- }
-
- /**
- * Loads state (viewstate and controlstate) into a control and its children.
- * This method overrides the parent implementation by loading
- * cached state if available.
- * This method should only be used by framework developers.
- * @param array the collection of the state
- * @param boolean whether the viewstate should be loaded
- */
- protected function loadStateRecursive(&$state,$needViewState=true)
- {
- $st=unserialize($state);
- parent::loadStateRecursive($st,$needViewState);
- }
-
- /**
- * Saves all control state (viewstate and controlstate) as a collection.
- * This method overrides the parent implementation by saving state
- * into cache if needed.
- * This method should only be used by framework developers.
- * @param boolean whether the viewstate should be saved
- * @return array the collection of the control state (including its children's state).
- */
- protected function &saveStateRecursive($needViewState=true)
- {
- if($this->_dataCached)
- return $this->_state;
- else
- {
- $st=parent::saveStateRecursive($needViewState);
- // serialization is needed to avoid undefined classes when loading state
- $this->_state=serialize($st);
- return $this->_state;
- }
- }
-
- /**
- * Registers an action associated with the content being cached.
- * The registered action will be replayed if the content stored
- * in the cache is served to end-users.
- * @param string context of the action method. This is a property-path
- * referring to the context object (e.g. Page, Page.ClientScript)
- * @param string method name of the context object
- * @param array list of parameters to be passed to the action method
- */
- public function registerAction($context,$funcName,$funcParams)
- {
- $this->_actions[]=array($context,$funcName,$funcParams);
- }
-
- public function getCacheKey()
- {
- if($this->_cacheKey===null)
- $this->_cacheKey=$this->calculateCacheKey();
- return $this->_cacheKey;
- }
-
- /**
- * Calculates the cache key.
- * The key is calculated based on the unique ID of this control
- * and the request parameters specified via {@link setVaryByParam VaryByParam}.
- * If {@link getVaryBySession VaryBySession} is true, the session ID
- * will also participate in the key calculation.
- * This method may be overriden to support other variations in
- * the calculated cache key.
- * @return string cache key
- */
- protected function calculateCacheKey()
- {
- $key=$this->getBaseCacheKey();
- if($this->_varyBySession)
- $key.=$this->getSession()->getSessionID();
- if($this->_varyByParam!=='')
- {
- $params=array();
- $request=$this->getRequest();
- foreach(explode(',',$this->_varyByParam) as $name)
- {
- $name=trim($name);
- $params[$name]=$request->itemAt($name);
- }
- $key.=serialize($params);
- }
- $param=new TOutputCacheCalculateKeyEventParameter;
- $this->onCalculateKey($param);
- $key.=$param->getCacheKey();
- return $key;
- }
-
- /**
- * @return string basic cache key without variations
- */
- protected function getBaseCacheKey()
- {
- return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
- }
-
- /**
- * @return string the ID of the cache module. Defaults to '', meaning the primary cache module is used.
- */
- public function getCacheModuleID()
- {
- return $this->_cacheModuleID;
- }
-
- /**
- * @param string the ID of the cache module. If empty, the primary cache module will be used.
- */
- public function setCacheModuleID($value)
- {
- $this->_cacheModuleID=$value;
- }
-
- /**
- * Sets the prefix of the cache key.
- * This method is used internally by {@link TTemplate}.
- * @param string key prefix
- */
- public function setCacheKeyPrefix($value)
- {
- $this->_keyPrefix=$value;
- }
-
- /**
- * @return integer the timestamp of the cached content. This is only valid if the content is being cached.
- * @since 3.1.1
- */
- public function getCacheTime()
- {
- return $this->_cacheTime;
- }
-
- /**
- * Returns the dependency of the data to be cached.
- * The default implementation simply returns null, meaning no specific dependency.
- * This method may be overriden to associate the data to be cached
- * with additional dependencies.
- * @return ICacheDependency
- */
- protected function getCacheDependency()
- {
- return null;
- }
-
- /**
- * @return boolean whether content enclosed is cached or not
- */
- public function getContentCached()
- {
- return $this->_dataCached;
- }
-
- /**
- * @return integer number of seconds that the data can remain in cache. Defaults to 60 seconds.
- * Note, if cache dependency changes or cache space is limited,
- * the data may be purged out of cache earlier.
- */
- public function getDuration()
- {
- return $this->_duration;
- }
-
- /**
- * @param integer number of seconds that the data can remain in cache. If 0, it means data is not cached.
- * @throws TInvalidDataValueException if the value is smaller than 0.
- */
- public function setDuration($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
- $this->_duration=$value;
- }
-
- /**
- * @return string a semicolon-separated list of strings used to vary the output cache. Defaults to ''.
- */
- public function getVaryByParam()
- {
- return $this->_varyByParam;
- }
-
- /**
- * Sets the names of the request parameters that should be used in calculating the cache key.
- * The names should be concatenated by semicolons.
- * By setting this value, the output cache will use different cached data
- * for each different set of request parameter values.
- * @return string a semicolon-separated list of strings used to vary the output cache.
- */
- public function setVaryByParam($value)
- {
- $this->_varyByParam=trim($value);
- }
-
- /**
- * @return boolean whether the content being cached should be differentiated according to user sessions. Defaults to false.
- */
- public function getVaryBySession()
- {
- return $this->_varyBySession;
- }
-
- /**
- * @param boolean whether the content being cached should be differentiated according to user sessions.
- */
- public function setVaryBySession($value)
- {
- $this->_varyBySession=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return boolean whether cached output will be used on postback requests. Defaults to false.
- */
- public function getCachingPostBack()
- {
- return $this->_cachePostBack;
- }
-
- /**
- * Sets a value indicating whether cached output will be used on postback requests.
- * By default, this is disabled. Be very cautious when enabling it.
- * If the cached content including interactive user controls such as
- * TTextBox, TDropDownList, your page may fail to render on postbacks.
- * @param boolean whether cached output will be used on postback requests.
- */
- public function setCachingPostBack($value)
- {
- $this->_cachePostBack=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * This event is raised when the output cache is checking cache dependency.
- * An event handler may be written to check customized dependency conditions.
- * The checking result should be saved by setting {@link TOutputCacheCheckDependencyEventParameter::setIsValid IsValid}
- * property of the event parameter (which defaults to true).
- * @param TOutputCacheCheckDependencyEventParameter event parameter
- */
- public function onCheckDependency($param)
- {
- $this->raiseEvent('OnCheckDependency',$this,$param);
- }
-
- /**
- * This event is raised when the output cache is calculating cache key.
- * By varying cache keys, one can obtain different versions of cached content.
- * An event handler may be written to add variety of the key calculation.
- * The value set in {@link TOutputCacheCalculateKeyEventParameter::setCacheKey CacheKey} of
- * this event parameter will be appended to the default key calculation scheme.
- * @param TOutputCacheCalculateKeyEventParameter event parameter
- */
- public function onCalculateKey($param)
- {
- $this->raiseEvent('OnCalculateKey',$this,$param);
- }
-
- /**
- * Renders the output cache control.
- * This method overrides the parent implementation by capturing the output
- * from its child controls and saving it into cache, if output cache is needed.
- * @param THtmlWriter
- */
- public function render($writer)
- {
- if($this->_dataCached)
- $writer->write($this->_contents);
- else if($this->_cacheAvailable)
- {
- $textwriter = new TTextWriter();
- $multiwriter = new TOutputCacheTextWriterMulti(array($writer->getWriter(),$textwriter));
- $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $multiwriter);
-
- $stack=$this->getPage()->getCachingStack();
- $stack->push($this);
- parent::render($htmlWriter);
- $stack->pop();
-
- $content=$textwriter->flush();
- $data=array($content,$this->_state,$this->_actions,time());
- $this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
- }
- else
- parent::render($writer);
- }
-}
-
-/**
- * TOutputCacheCheckDependencyEventParameter class
- *
- * TOutputCacheCheckDependencyEventParameter encapsulates the parameter data for
- * <b>OnCheckDependency</b> event of {@link TOutputCache} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TOutputCacheCheckDependencyEventParameter extends TEventParameter
-{
- private $_isValid=true;
- private $_cacheTime=0;
-
- /**
- * @return boolean whether the dependency remains valid. Defaults to true.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
-
- /**
- * @param boolean whether the dependency remains valid
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return integer the timestamp of the cached result. You may use this to help determine any dependency is changed.
- * @since 3.1.1
- */
- public function getCacheTime()
- {
- return $this->_cacheTime;
- }
-
- /**
- * @param integer the timestamp of the cached result. This is used internally.
- * @since 3.1.1
- */
- public function setCacheTime($value)
- {
- $this->_cacheTime=TPropertyValue::ensureInteger($value);
- }
-}
-
-
-/**
- * TOutputCacheCalculateKeyEventParameter class
- *
- * TOutputCacheCalculateKeyEventParameter encapsulates the parameter data for
- * <b>OnCalculateKey</b> event of {@link TOutputCache} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TOutputCacheCalculateKeyEventParameter extends TEventParameter
-{
- /**
- * @var string cache key to be appended to the default calculation scheme.
- */
- private $_cacheKey='';
-
- /**
- * @return string cache key to be appended to the default calculation scheme.
- */
- public function getCacheKey()
- {
- return $this->_cacheKey;
- }
-
- /**
- * @param string cache key to be appended to the default calculation scheme
- */
- public function setCacheKey($value)
- {
- $this->_cacheKey=TPropertyValue::ensureString($value);
- }
-}
-
-/**
- * TOutputCacheTextWriterMulti class
- *
- * TOutputCacheTextWriterMulti is an internal class used by
- * TOutputCache to write simultaneously to multiple writers.
- *
- * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-class TOutputCacheTextWriterMulti extends TTextWriter
-{
- protected $_writers;
-
- public function __construct(Array $writers)
- {
- //parent::__construct();
- $this->_writers = $writers;
- }
-
- public function write($s)
- {
- foreach($this->_writers as $writer)
- $writer->write($s);
- }
-
- public function flush()
- {
- foreach($this->_writers as $writer)
- $s = $writer->flush();
- return $s;
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TOutputCache class.
+ *
+ * TOutputCache enables caching a portion of a Web page, also known as
+ * partial caching. The content being cached can be either static or
+ * dynamic.
+ *
+ * To use TOutputCache, simply enclose the content to be cached
+ * within the TOutputCache component tag on a template, e.g.,
+ * <code>
+ * <com:TOutputCache>
+ * content to be cached
+ * </com:TOutputCache>
+ * </code>
+ * where content to be cached can be static text and/or component tags.
+ *
+ * The validity of the cached content is determined based on two factors:
+ * the {@link setDuration Duration} and the cache dependency.
+ * The former specifies the number of seconds that the data can remain
+ * valid in cache (defaults to 60s), while the latter specifies conditions
+ * that the cached data depends on. If a dependency changes,
+ * (e.g. relevant data in DB are updated), the cached data will be invalidated.
+ *
+ * There are two ways to specify cache dependency. One may write event handlers
+ * to respond to the {@link onCheckDependency OnCheckDependency} event and set
+ * the event parameter's {@link TOutputCacheCheckDependencyEventParameter::getIsValid IsValid}
+ * property to indicate whether the cached data remains valid or not.
+ * One can also extend TOutputCache and override its {@link getCacheDependency}
+ * function. While the former is easier to use, the latter offers more extensibility.
+ *
+ * The content fetched from cache may be variated with respect to
+ * some parameters. It supports variation with respect to request parameters,
+ * which is specified by {@link setVaryByParam VaryByParam} property.
+ * If a specified request parameter is different, a different version of
+ * cached content is used. This is extremely useful if a page's content
+ * may be variated according to some GET parameters.
+ * The content being cached may also be variated with user sessions if
+ * {@link setVaryBySession VaryBySession} is set true.
+ * To variate the cached content by other factors, override {@link calculateCacheKey()} method.
+ *
+ * Output caches can be nested. An outer cache takes precedence over an
+ * inner cache. This means, if the content cached by the inner cache expires
+ * or is invalidated, while that by the outer cache not, the outer cached
+ * content will be used.
+ *
+ * Note, TOutputCache is effective only for non-postback page requests
+ * and when cache module is enabled.
+ *
+ * Do not attempt to address child controls of TOutputCache when the cached
+ * content is to be used. Use {@link getContentCached ContentCached} property
+ * to determine whether the content is cached or not.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1
+ */
+class TOutputCache extends TControl implements INamingContainer
+{
+ const CACHE_ID_PREFIX='prado:outputcache';
+ private $_cacheModuleID='';
+ private $_dataCached=false;
+ private $_cacheAvailable=false;
+ private $_cacheChecked=false;
+ private $_cacheKey=null;
+ private $_duration=60;
+ private $_cache=null;
+ private $_contents;
+ private $_state;
+ private $_actions=array();
+ private $_varyByParam='';
+ private $_keyPrefix='';
+ private $_varyBySession=false;
+ private $_cachePostBack=false;
+ private $_cacheTime=0;
+
+ /**
+ * Returns a value indicating whether body contents are allowed for this control.
+ * This method overrides the parent implementation by checking if cached
+ * content is available or not. If yes, it returns false, otherwise true.
+ * @param boolean whether body contents are allowed for this control.
+ */
+ public function getAllowChildControls()
+ {
+ $this->determineCacheability();
+ return !$this->_dataCached;
+ }
+
+ private function determineCacheability()
+ {
+ if(!$this->_cacheChecked)
+ {
+ $this->_cacheChecked=true;
+ if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
+ {
+ if($this->_cacheModuleID!=='')
+ {
+ $this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
+ if(!($this->_cache instanceof ICache))
+ throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
+ }
+ else
+ $this->_cache=$this->getApplication()->getCache();
+ if($this->_cache!==null)
+ {
+ $this->_cacheAvailable=true;
+ $data=$this->_cache->get($this->getCacheKey());
+ if(is_array($data))
+ {
+ $param=new TOutputCacheCheckDependencyEventParameter;
+ $param->setCacheTime(isset($data[3])?$data[3]:0);
+ $this->onCheckDependency($param);
+ $this->_dataCached=$param->getIsValid();
+ }
+ else
+ $this->_dataCached=false;
+ if($this->_dataCached)
+ list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
+ }
+ }
+ }
+ }
+
+ /**
+ * Performs the Init step for the control and all its child controls.
+ * This method overrides the parent implementation by setting up
+ * the stack of the output cache in the page.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function initRecursive($namingContainer=null)
+ {
+ if($this->_cacheAvailable && !$this->_dataCached)
+ {
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::initRecursive($namingContainer);
+ $stack->pop();
+ }
+ else
+ parent::initRecursive($namingContainer);
+ }
+
+ /**
+ * Performs the Load step for the control and all its child controls.
+ * This method overrides the parent implementation by setting up
+ * the stack of the output cache in the page. If the data is restored
+ * from cache, it also recovers the actions associated with the cached data.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function loadRecursive()
+ {
+ if($this->_cacheAvailable && !$this->_dataCached)
+ {
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::loadRecursive();
+ $stack->pop();
+ }
+ else
+ {
+ if($this->_dataCached)
+ $this->performActions();
+ parent::loadRecursive();
+ }
+ }
+
+ private function performActions()
+ {
+ $page=$this->getPage();
+ $cs=$page->getClientScript();
+ foreach($this->_actions as $action)
+ {
+ if($action[0]==='Page.ClientScript')
+ call_user_func_array(array($cs,$action[1]),$action[2]);
+ else if($action[0]==='Page')
+ call_user_func_array(array($page,$action[1]),$action[2]);
+ else
+ call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
+ }
+ }
+
+ /**
+ * Performs the PreRender step for the control and all its child controls.
+ * This method overrides the parent implementation by setting up
+ * the stack of the output cache in the page.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function preRenderRecursive()
+ {
+ if($this->_cacheAvailable && !$this->_dataCached)
+ {
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::preRenderRecursive();
+ $stack->pop();
+ }
+ else
+ parent::preRenderRecursive();
+ }
+
+ /**
+ * Loads state (viewstate and controlstate) into a control and its children.
+ * This method overrides the parent implementation by loading
+ * cached state if available.
+ * This method should only be used by framework developers.
+ * @param array the collection of the state
+ * @param boolean whether the viewstate should be loaded
+ */
+ protected function loadStateRecursive(&$state,$needViewState=true)
+ {
+ $st=unserialize($state);
+ parent::loadStateRecursive($st,$needViewState);
+ }
+
+ /**
+ * Saves all control state (viewstate and controlstate) as a collection.
+ * This method overrides the parent implementation by saving state
+ * into cache if needed.
+ * This method should only be used by framework developers.
+ * @param boolean whether the viewstate should be saved
+ * @return array the collection of the control state (including its children's state).
+ */
+ protected function &saveStateRecursive($needViewState=true)
+ {
+ if($this->_dataCached)
+ return $this->_state;
+ else
+ {
+ $st=parent::saveStateRecursive($needViewState);
+ // serialization is needed to avoid undefined classes when loading state
+ $this->_state=serialize($st);
+ return $this->_state;
+ }
+ }
+
+ /**
+ * Registers an action associated with the content being cached.
+ * The registered action will be replayed if the content stored
+ * in the cache is served to end-users.
+ * @param string context of the action method. This is a property-path
+ * referring to the context object (e.g. Page, Page.ClientScript)
+ * @param string method name of the context object
+ * @param array list of parameters to be passed to the action method
+ */
+ public function registerAction($context,$funcName,$funcParams)
+ {
+ $this->_actions[]=array($context,$funcName,$funcParams);
+ }
+
+ public function getCacheKey()
+ {
+ if($this->_cacheKey===null)
+ $this->_cacheKey=$this->calculateCacheKey();
+ return $this->_cacheKey;
+ }
+
+ /**
+ * Calculates the cache key.
+ * The key is calculated based on the unique ID of this control
+ * and the request parameters specified via {@link setVaryByParam VaryByParam}.
+ * If {@link getVaryBySession VaryBySession} is true, the session ID
+ * will also participate in the key calculation.
+ * This method may be overriden to support other variations in
+ * the calculated cache key.
+ * @return string cache key
+ */
+ protected function calculateCacheKey()
+ {
+ $key=$this->getBaseCacheKey();
+ if($this->_varyBySession)
+ $key.=$this->getSession()->getSessionID();
+ if($this->_varyByParam!=='')
+ {
+ $params=array();
+ $request=$this->getRequest();
+ foreach(explode(',',$this->_varyByParam) as $name)
+ {
+ $name=trim($name);
+ $params[$name]=$request->itemAt($name);
+ }
+ $key.=serialize($params);
+ }
+ $param=new TOutputCacheCalculateKeyEventParameter;
+ $this->onCalculateKey($param);
+ $key.=$param->getCacheKey();
+ return $key;
+ }
+
+ /**
+ * @return string basic cache key without variations
+ */
+ protected function getBaseCacheKey()
+ {
+ return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
+ }
+
+ /**
+ * @return string the ID of the cache module. Defaults to '', meaning the primary cache module is used.
+ */
+ public function getCacheModuleID()
+ {
+ return $this->_cacheModuleID;
+ }
+
+ /**
+ * @param string the ID of the cache module. If empty, the primary cache module will be used.
+ */
+ public function setCacheModuleID($value)
+ {
+ $this->_cacheModuleID=$value;
+ }
+
+ /**
+ * Sets the prefix of the cache key.
+ * This method is used internally by {@link TTemplate}.
+ * @param string key prefix
+ */
+ public function setCacheKeyPrefix($value)
+ {
+ $this->_keyPrefix=$value;
+ }
+
+ /**
+ * @return integer the timestamp of the cached content. This is only valid if the content is being cached.
+ * @since 3.1.1
+ */
+ public function getCacheTime()
+ {
+ return $this->_cacheTime;
+ }
+
+ /**
+ * Returns the dependency of the data to be cached.
+ * The default implementation simply returns null, meaning no specific dependency.
+ * This method may be overriden to associate the data to be cached
+ * with additional dependencies.
+ * @return ICacheDependency
+ */
+ protected function getCacheDependency()
+ {
+ return null;
+ }
+
+ /**
+ * @return boolean whether content enclosed is cached or not
+ */
+ public function getContentCached()
+ {
+ return $this->_dataCached;
+ }
+
+ /**
+ * @return integer number of seconds that the data can remain in cache. Defaults to 60 seconds.
+ * Note, if cache dependency changes or cache space is limited,
+ * the data may be purged out of cache earlier.
+ */
+ public function getDuration()
+ {
+ return $this->_duration;
+ }
+
+ /**
+ * @param integer number of seconds that the data can remain in cache. If 0, it means data is not cached.
+ * @throws TInvalidDataValueException if the value is smaller than 0.
+ */
+ public function setDuration($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
+ $this->_duration=$value;
+ }
+
+ /**
+ * @return string a semicolon-separated list of strings used to vary the output cache. Defaults to ''.
+ */
+ public function getVaryByParam()
+ {
+ return $this->_varyByParam;
+ }
+
+ /**
+ * Sets the names of the request parameters that should be used in calculating the cache key.
+ * The names should be concatenated by semicolons.
+ * By setting this value, the output cache will use different cached data
+ * for each different set of request parameter values.
+ * @return string a semicolon-separated list of strings used to vary the output cache.
+ */
+ public function setVaryByParam($value)
+ {
+ $this->_varyByParam=trim($value);
+ }
+
+ /**
+ * @return boolean whether the content being cached should be differentiated according to user sessions. Defaults to false.
+ */
+ public function getVaryBySession()
+ {
+ return $this->_varyBySession;
+ }
+
+ /**
+ * @param boolean whether the content being cached should be differentiated according to user sessions.
+ */
+ public function setVaryBySession($value)
+ {
+ $this->_varyBySession=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether cached output will be used on postback requests. Defaults to false.
+ */
+ public function getCachingPostBack()
+ {
+ return $this->_cachePostBack;
+ }
+
+ /**
+ * Sets a value indicating whether cached output will be used on postback requests.
+ * By default, this is disabled. Be very cautious when enabling it.
+ * If the cached content including interactive user controls such as
+ * TTextBox, TDropDownList, your page may fail to render on postbacks.
+ * @param boolean whether cached output will be used on postback requests.
+ */
+ public function setCachingPostBack($value)
+ {
+ $this->_cachePostBack=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * This event is raised when the output cache is checking cache dependency.
+ * An event handler may be written to check customized dependency conditions.
+ * The checking result should be saved by setting {@link TOutputCacheCheckDependencyEventParameter::setIsValid IsValid}
+ * property of the event parameter (which defaults to true).
+ * @param TOutputCacheCheckDependencyEventParameter event parameter
+ */
+ public function onCheckDependency($param)
+ {
+ $this->raiseEvent('OnCheckDependency',$this,$param);
+ }
+
+ /**
+ * This event is raised when the output cache is calculating cache key.
+ * By varying cache keys, one can obtain different versions of cached content.
+ * An event handler may be written to add variety of the key calculation.
+ * The value set in {@link TOutputCacheCalculateKeyEventParameter::setCacheKey CacheKey} of
+ * this event parameter will be appended to the default key calculation scheme.
+ * @param TOutputCacheCalculateKeyEventParameter event parameter
+ */
+ public function onCalculateKey($param)
+ {
+ $this->raiseEvent('OnCalculateKey',$this,$param);
+ }
+
+ /**
+ * Renders the output cache control.
+ * This method overrides the parent implementation by capturing the output
+ * from its child controls and saving it into cache, if output cache is needed.
+ * @param THtmlWriter
+ */
+ public function render($writer)
+ {
+ if($this->_dataCached)
+ $writer->write($this->_contents);
+ else if($this->_cacheAvailable)
+ {
+ $textwriter = new TTextWriter();
+ $multiwriter = new TOutputCacheTextWriterMulti(array($writer->getWriter(),$textwriter));
+ $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $multiwriter);
+
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::render($htmlWriter);
+ $stack->pop();
+
+ $content=$textwriter->flush();
+ $data=array($content,$this->_state,$this->_actions,time());
+ $this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
+ }
+ else
+ parent::render($writer);
+ }
+}
+
+/**
+ * TOutputCacheCheckDependencyEventParameter class
+ *
+ * TOutputCacheCheckDependencyEventParameter encapsulates the parameter data for
+ * <b>OnCheckDependency</b> event of {@link TOutputCache} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TOutputCacheCheckDependencyEventParameter extends TEventParameter
+{
+ private $_isValid=true;
+ private $_cacheTime=0;
+
+ /**
+ * @return boolean whether the dependency remains valid. Defaults to true.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+
+ /**
+ * @param boolean whether the dependency remains valid
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return integer the timestamp of the cached result. You may use this to help determine any dependency is changed.
+ * @since 3.1.1
+ */
+ public function getCacheTime()
+ {
+ return $this->_cacheTime;
+ }
+
+ /**
+ * @param integer the timestamp of the cached result. This is used internally.
+ * @since 3.1.1
+ */
+ public function setCacheTime($value)
+ {
+ $this->_cacheTime=TPropertyValue::ensureInteger($value);
+ }
+}
+
+
+/**
+ * TOutputCacheCalculateKeyEventParameter class
+ *
+ * TOutputCacheCalculateKeyEventParameter encapsulates the parameter data for
+ * <b>OnCalculateKey</b> event of {@link TOutputCache} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TOutputCacheCalculateKeyEventParameter extends TEventParameter
+{
+ /**
+ * @var string cache key to be appended to the default calculation scheme.
+ */
+ private $_cacheKey='';
+
+ /**
+ * @return string cache key to be appended to the default calculation scheme.
+ */
+ public function getCacheKey()
+ {
+ return $this->_cacheKey;
+ }
+
+ /**
+ * @param string cache key to be appended to the default calculation scheme
+ */
+ public function setCacheKey($value)
+ {
+ $this->_cacheKey=TPropertyValue::ensureString($value);
+ }
+}
+
+/**
+ * TOutputCacheTextWriterMulti class
+ *
+ * TOutputCacheTextWriterMulti is an internal class used by
+ * TOutputCache to write simultaneously to multiple writers.
+ *
+ * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+class TOutputCacheTextWriterMulti extends TTextWriter
+{
+ protected $_writers;
+
+ public function __construct(Array $writers)
+ {
+ //parent::__construct();
+ $this->_writers = $writers;
+ }
+
+ public function write($s)
+ {
+ foreach($this->_writers as $writer)
+ $writer->write($s);
+ }
+
+ public function flush()
+ {
+ foreach($this->_writers as $writer)
+ $s = $writer->flush();
+ return $s;
+ }
+}
+