summaryrefslogtreecommitdiff
path: root/framework
diff options
context:
space:
mode:
Diffstat (limited to 'framework')
-rw-r--r--framework/Web/UI/TPage.php2817
1 files changed, 1401 insertions, 1416 deletions
diff --git a/framework/Web/UI/TPage.php b/framework/Web/UI/TPage.php
index c633a3be..e46ee9f5 100644
--- a/framework/Web/UI/TPage.php
+++ b/framework/Web/UI/TPage.php
@@ -1,1416 +1,1401 @@
-<?php
-/**
- * TPage class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2014 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @package System.Web.UI
- */
-
-Prado::using('System.Web.UI.WebControls.*');
-Prado::using('System.Web.UI.TControl');
-Prado::using('System.Web.UI.WebControls.TWebControl');
-Prado::using('System.Web.UI.TCompositeControl');
-Prado::using('System.Web.UI.TTemplateControl');
-Prado::using('System.Web.UI.TForm');
-Prado::using('System.Web.UI.TClientScriptManager');
-
-/**
- * TPage class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @package System.Web.UI
- * @since 3.0
- */
-class TPage extends TTemplateControl
-{
- /**
- * system post fields
- */
- const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
- const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
- const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
- const FIELD_PAGESTATE='PRADO_PAGESTATE';
- const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
- const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
-
- /**
- * @var array system post fields
- */
- private static $_systemPostFields=array(
- 'PRADO_POSTBACK_TARGET'=>true,
- 'PRADO_POSTBACK_PARAMETER'=>true,
- 'PRADO_LASTFOCUS'=>true,
- 'PRADO_PAGESTATE'=>true,
- 'PRADO_CALLBACK_TARGET'=>true,
- 'PRADO_CALLBACK_PARAMETER'=>true
- );
- /**
- * @var TForm form instance
- */
- private $_form;
- /**
- * @var THead head instance
- */
- private $_head;
- /**
- * @var array list of registered validators
- */
- private $_validators=array();
- /**
- * @var boolean if validation has been performed
- */
- private $_validated=false;
- /**
- * @var TTheme page theme
- */
- private $_theme;
- /**
- * @var string page title set when Head is not in page yet
- */
- private $_title;
- /**
- * @var TTheme page stylesheet theme
- */
- private $_styleSheet;
- /**
- * @var TClientScriptManager client script manager
- */
- private $_clientScript;
- /**
- * @var TMap data post back by user
- */
- protected $_postData;
- /**
- * @var TMap postback data that is not handled during first invocation of LoadPostData.
- */
- protected $_restPostData;
- /**
- * @var array list of controls whose data have been changed due to the postback
- */
- protected $_controlsPostDataChanged=array();
- /**
- * @var array list of controls that need to load post data in the current request
- */
- protected $_controlsRequiringPostData=array();
- /**
- * @var array list of controls that need to load post data in the next postback
- */
- protected $_controlsRegisteredForPostData=array();
- /**
- * @var TControl control that needs to raise postback event
- */
- private $_postBackEventTarget;
- /**
- * @var string postback event parameter
- */
- private $_postBackEventParameter;
- /**
- * @var boolean whether the form has been rendered
- */
- protected $_formRendered=false;
- /**
- * @var boolean whether the current rendering is within a form
- */
- protected $_inFormRender=false;
- /**
- * @var TControl|string the control or the ID of the element on the page to be focused when the page is sent back to user
- */
- private $_focus;
- /**
- * @var string page path to this page
- */
- private $_pagePath='';
- /**
- * @var boolean whether page state should be HMAC validated
- */
- private $_enableStateValidation=true;
- /**
- * @var boolean whether page state should be encrypted
- */
- private $_enableStateEncryption=false;
- /**
- * @var boolean whether page state should be compressed
- * @since 3.1.6
- */
- private $_enableStateCompression=true;
- /**
- * @var string page state persister class name
- */
- private $_statePersisterClass='System.Web.UI.TPageStatePersister';
- /**
- * @var mixed page state persister
- */
- private $_statePersister;
- /**
- * @var TStack stack used to store currently active caching controls
- */
- private $_cachingStack;
- /**
- * @var string state string to be stored on the client side
- */
- private $_clientState='';
- /**
- * @var boolean true if loading post data.
- */
- protected $_isLoadingPostData=false;
- /**
- * @var boolean whether client supports javascript
- */
- private $_enableJavaScript=true;
- /**
- * @var THtmlWriter current html render writer
- */
- private $_writer;
-
- /**
- * Constructor.
- * Sets the page object to itself.
- * Derived classes must call parent implementation.
- */
- public function __construct()
- {
- $this->setPage($this);
- }
-
- /**
- * Runs through the page lifecycles.
- * @param THtmlTextWriter the HTML writer
- */
- public function run($writer)
- {
- Prado::trace("Running page life cycles",'System.Web.UI.TPage');
- $this->_writer = $writer;
-
- $this->determinePostBackMode();
-
- if($this->getIsPostBack())
- {
- if($this->getIsCallback())
- $this->processCallbackRequest($writer);
- else
- $this->processPostBackRequest($writer);
- }
- else
- $this->processNormalRequest($writer);
-
- $this->_writer = null;
- }
-
- protected function processNormalRequest($writer)
- {
- Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
- $this->onPreInit(null);
-
- Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
- $this->initRecursive();
-
- Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
- $this->onInitComplete(null);
-
- Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
- $this->onPreLoad(null);
- Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
- $this->loadRecursive();
- Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
- $this->onLoadComplete(null);
-
- Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
- $this->preRenderRecursive();
- Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
- $this->onPreRenderComplete(null);
-
- Prado::trace("Page savePageState()",'System.Web.UI.TPage');
- $this->savePageState();
- Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
- $this->onSaveStateComplete(null);
-
- Prado::trace("Page renderControl()",'System.Web.UI.TPage');
- $this->renderControl($writer);
- Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
- $this->unloadRecursive();
- }
-
- protected function processPostBackRequest($writer)
- {
- Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
- $this->onPreInit(null);
-
- Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
- $this->initRecursive();
-
- Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
- $this->onInitComplete(null);
-
- $this->_restPostData=new TMap;
- Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
- $this->loadPageState();
- Prado::trace("Page processPostData()",'System.Web.UI.TPage');
- $this->processPostData($this->_postData,true);
- Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
- $this->onPreLoad(null);
- Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
- $this->loadRecursive();
- Prado::trace("Page processPostData()",'System.Web.UI.TPage');
- $this->processPostData($this->_restPostData,false);
- Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
- $this->raiseChangedEvents();
- Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
- $this->raisePostBackEvent();
- Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
- $this->onLoadComplete(null);
-
- Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
- $this->preRenderRecursive();
- Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
- $this->onPreRenderComplete(null);
-
- Prado::trace("Page savePageState()",'System.Web.UI.TPage');
- $this->savePageState();
- Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
- $this->onSaveStateComplete(null);
-
- Prado::trace("Page renderControl()",'System.Web.UI.TPage');
- $this->renderControl($writer);
- Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
- $this->unloadRecursive();
- }
-
- protected static function decodeUTF8($data, $enc)
- {
- if(is_array($data))
- {
- foreach($data as $k=>$v)
- $data[$k]=self::decodeUTF8($v, $enc);
- return $data;
- } elseif(is_string($data)) {
- return iconv('UTF-8',$enc.'//IGNORE',$data);
- } else {
- return $data;
- }
- }
-
- /**
- * Sets Adapter to TActivePageAdapter and calls apter to process the
- * callback request.
- */
- protected function processCallbackRequest($writer)
- {
- Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
-
- $this->setAdapter(new TActivePageAdapter($this));
-
- $callbackEventParameter = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER);
- if(strlen($callbackEventParameter) > 0)
- $this->_postData[TPage::FIELD_CALLBACK_PARAMETER]=TJavaScript::jsonDecode((string)$callbackEventParameter);
-
- // Decode Callback postData from UTF-8 to current Charset
- if (($g=$this->getApplication()->getGlobalization(false))!==null &&
- strtoupper($enc=$g->getCharset())!='UTF-8')
- foreach ($this->_postData as $k=>$v)
- $this->_postData[$k]=self::decodeUTF8($v, $enc);
-
- Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
- $this->onPreInit(null);
-
- Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
- $this->initRecursive();
-
- Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
- $this->onInitComplete(null);
-
- $this->_restPostData=new TMap;
- Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
- $this->loadPageState();
- Prado::trace("Page processPostData()",'System.Web.UI.TPage');
- $this->processPostData($this->_postData,true);
- Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
- $this->onPreLoad(null);
- Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
- $this->loadRecursive();
-
- Prado::trace("Page processPostData()",'System.Web.UI.TPage');
- $this->processPostData($this->_restPostData,false);
-
- Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
- $this->raiseChangedEvents();
-
-
- $this->getAdapter()->processCallbackEvent($writer);
-
-/*
- Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
- $this->raisePostBackEvent();
-*/
- Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
- $this->onLoadComplete(null);
-
- Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
- $this->preRenderRecursive();
- Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
- $this->onPreRenderComplete(null);
-
- Prado::trace("Page savePageState()",'System.Web.UI.TPage');
- $this->savePageState();
- Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
- $this->onSaveStateComplete(null);
-
-/*
- Prado::trace("Page renderControl()",'System.Web.UI.TPage');
- $this->renderControl($writer);
-*/
- $this->getAdapter()->renderCallbackResponse($writer);
-
- Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
- $this->unloadRecursive();
- }
-
- /**
- * Gets the callback client script handler that allows javascript functions
- * to be executed during the callback response.
- * @return TCallbackClientScript interface to client-side javascript code.
- */
- public function getCallbackClient()
- {
- if($this->getAdapter() !== null)
- return $this->getAdapter()->getCallbackClientHandler();
- else
- return new TCallbackClientScript();
- }
-
- /**
- * Set a new callback client handler.
- * @param TCallbackClientScript new callback client script handler.
- */
- public function setCallbackClient($client)
- {
- $this->getAdapter()->setCallbackClientHandler($client);
- }
-
- /**
- * @return TControl the control responsible for the current callback event,
- * null if nonexistent
- */
- public function getCallbackEventTarget()
- {
- return $this->getAdapter()->getCallbackEventTarget();
- }
-
- /**
- * Registers a control to raise callback event in the current request.
- * @param TControl control registered to raise callback event.
- */
- public function setCallbackEventTarget(TControl $control)
- {
- $this->getAdapter()->setCallbackEventTarget($control);
- }
-
- /**
- * Callback parameter is decoded assuming JSON encoding.
- * @return string callback event parameter
- */
- public function getCallbackEventParameter()
- {
- return $this->getAdapter()->getCallbackEventParameter();
- }
-
- /**
- * @param mixed callback event parameter
- */
- public function setCallbackEventParameter($value)
- {
- $this->getAdapter()->setCallbackEventParameter($value);
- }
-
- /**
- * @return TForm the form on the page
- */
- public function getForm()
- {
- return $this->_form;
- }
-
- /**
- * Registers a TForm instance to the page.
- * Note, a page can contain at most one TForm instance.
- * @param TForm the form on the page
- * @throws TInvalidOperationException if this method is invoked twice or more.
- */
- public function setForm(TForm $form)
- {
- if($this->_form===null)
- $this->_form=$form;
- else
- throw new TInvalidOperationException('page_form_duplicated');
- }
-
- /**
- * Returns a list of registered validators.
- * If validation group is specified, only the validators in that group will be returned.
- * @param string validation group
- * @return TList registered validators in the requested group. If the group is null, all validators will be returned.
- */
- public function getValidators($validationGroup=null)
- {
- if(!$this->_validators)
- $this->_validators=new TList;
- if(empty($validationGroup) === true)
- return $this->_validators;
- else
- {
- $list=new TList;
- foreach($this->_validators as $validator)
- if($validator->getValidationGroup()===$validationGroup)
- $list->add($validator);
- return $list;
- }
- }
-
- /**
- * Performs input validation.
- * This method will invoke the registered validators to perform the actual validation.
- * If validation group is specified, only the validators in that group will be invoked.
- * @param string validation group. If null, all validators will perform validation.
- */
- public function validate($validationGroup=null)
- {
- Prado::trace("Page validate()",'System.Web.UI.TPage');
- $this->_validated=true;
- if($this->_validators && $this->_validators->getCount())
- {
- if($validationGroup===null)
- {
- foreach($this->_validators as $validator)
- $validator->validate();
- }
- else
- {
- foreach($this->_validators as $validator)
- {
- if($validator->getValidationGroup()===$validationGroup)
- $validator->validate();
- }
- }
- }
- }
-
- /**
- * Returns whether user input is valid or not.
- * This method must be invoked after {@link validate} is called.
- * @return boolean whether the user input is valid or not.
- * @throws TInvalidOperationException if {@link validate} is not invoked yet.
- */
- public function getIsValid()
- {
- if($this->_validated)
- {
- if($this->_validators && $this->_validators->getCount())
- {
- foreach($this->_validators as $validator)
- if(!$validator->getIsValid())
- return false;
- }
- return true;
- }
- else
- throw new TInvalidOperationException('page_isvalid_unknown');
- }
-
- /**
- * @return TTheme the theme used for the page. Defaults to null.
- */
- public function getTheme()
- {
- if(is_string($this->_theme))
- $this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
- return $this->_theme;
- }
-
- /**
- * Sets the theme to be used for the page.
- * @param string|TTheme the theme name or the theme object to be used for the page.
- */
- public function setTheme($value)
- {
- $this->_theme=empty($value)?null:$value;
- }
-
-
- /**
- * @return TTheme the stylesheet theme used for the page. Defaults to null.
- */
- public function getStyleSheetTheme()
- {
- if(is_string($this->_styleSheet))
- $this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
- return $this->_styleSheet;
- }
-
- /**
- * Sets the stylesheet theme to be used for the page.
- * @param string|TTheme the stylesheet theme name or the stylesheet theme object to be used for the page.
- */
- public function setStyleSheetTheme($value)
- {
- $this->_styleSheet=empty($value)?null:$value;
- }
-
- /**
- * Applies a skin in the current theme to a control.
- * This method should only be used by framework developers.
- * @param TControl a control to be applied skin with
- */
- public function applyControlSkin($control)
- {
- if(($theme=$this->getTheme())!==null)
- $theme->applySkin($control);
- }
-
- /**
- * Applies a stylesheet skin in the current theme to a control.
- * This method should only be used by framework developers.
- * @param TControl a control to be applied stylesheet skin with
- */
- public function applyControlStyleSheet($control)
- {
- if(($theme=$this->getStyleSheetTheme())!==null)
- $theme->applySkin($control);
- }
-
- /**
- * @return TClientScriptManager client script manager
- */
- public function getClientScript()
- {
- if(!$this->_clientScript) {
- $className = $classPath = $this->getService()->getClientScriptManagerClass();
- Prado::using($className);
- if(($pos=strrpos($className,'.'))!==false)
- $className=substr($className,$pos+1);
-
- if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
- throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
-
- $this->_clientScript=new $className($this);
- }
- return $this->_clientScript;
- }
-
- /**
- * Raises OnPreInit event.
- * This method is invoked right before {@link onInit OnInit} stage.
- * You may override this method to provide additional initialization that
- * should be done before {@link onInit OnInit} (e.g. setting {@link setTheme Theme} or
- * {@link setStyleSheetTheme StyleSheetTheme}).
- * Remember to call the parent implementation to ensure OnPreInit event is raised.
- * @param mixed event parameter
- */
- public function onPreInit($param)
- {
- $this->raiseEvent('OnPreInit',$this,$param);
- }
-
- /**
- * Raises OnInitComplete event.
- * This method is invoked right after {@link onInit OnInit} stage and before {@link onLoad OnLoad} stage.
- * You may override this method to provide additional initialization that
- * should be done after {@link onInit OnInit}.
- * Remember to call the parent implementation to ensure OnInitComplete event is raised.
- * @param mixed event parameter
- */
- public function onInitComplete($param)
- {
- $this->raiseEvent('OnInitComplete',$this,$param);
- }
-
- /**
- * Raises OnPreLoad event.
- * This method is invoked right before {@link onLoad OnLoad} stage.
- * You may override this method to provide additional page loading logic that
- * should be done before {@link onLoad OnLoad}.
- * Remember to call the parent implementation to ensure OnPreLoad event is raised.
- * @param mixed event parameter
- */
- public function onPreLoad($param)
- {
- $this->raiseEvent('OnPreLoad',$this,$param);
- }
-
- /**
- * Raises OnLoadComplete event.
- * This method is invoked right after {@link onLoad OnLoad} stage.
- * You may override this method to provide additional page loading logic that
- * should be done after {@link onLoad OnLoad}.
- * Remember to call the parent implementation to ensure OnLoadComplete event is raised.
- * @param mixed event parameter
- */
- public function onLoadComplete($param)
- {
- $this->raiseEvent('OnLoadComplete',$this,$param);
- }
-
- /**
- * Raises OnPreRenderComplete event.
- * This method is invoked right after {@link onPreRender OnPreRender} stage.
- * You may override this method to provide additional preparation for page rendering
- * that should be done after {@link onPreRender OnPreRender}.
- * Remember to call the parent implementation to ensure OnPreRenderComplete event is raised.
- * @param mixed event parameter
- */
- public function onPreRenderComplete($param)
- {
- $this->raiseEvent('OnPreRenderComplete',$this,$param);
- $cs=$this->getClientScript();
- $theme=$this->getTheme();
- if($theme instanceof ITheme)
- {
- foreach($theme->getStyleSheetFiles() as $url)
- $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
- foreach($theme->getJavaScriptFiles() as $url)
- $cs->registerHeadScriptFile($url,$url);
- }
- $styleSheet=$this->getStyleSheetTheme();
- if($styleSheet instanceof ITheme)
- {
- foreach($styleSheet->getStyleSheetFiles() as $url)
- $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
- foreach($styleSheet->getJavaScriptFiles() as $url)
- $cs->registerHeadScriptFile($url,$url);
- }
-
- if($cs->getRequiresHead() && $this->getHead()===null)
- throw new TConfigurationException('page_head_required');
- }
-
- /**
- * Determines the media type of the CSS file.
- * The media type is determined according to the following file name pattern:
- * xxx.media-type.extension
- * For example, 'mystyle.print.css' means its media type is 'print'.
- * @param string CSS URL
- * @return string media type of the CSS file
- */
- private function getCssMediaType($url)
- {
- $segs=explode('.',basename($url));
- if(isset($segs[2]))
- return $segs[count($segs)-2];
- else
- return '';
- }
-
- /**
- * Raises OnSaveStateComplete event.
- * This method is invoked right after {@link onSaveState OnSaveState} stage.
- * You may override this method to provide additional logic after page state is saved.
- * Remember to call the parent implementation to ensure OnSaveStateComplete event is raised.
- * @param mixed event parameter
- */
- public function onSaveStateComplete($param)
- {
- $this->raiseEvent('OnSaveStateComplete',$this,$param);
- }
-
- /**
- * Determines whether the current page request is a postback.
- * Call {@link getIsPostBack} to get the result.
- */
- private function determinePostBackMode()
- {
- $postData=$this->getRequest();
- if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
- $this->_postData=$postData;
- }
-
- /**
- * @return boolean whether the current page request is a postback
- */
- public function getIsPostBack()
- {
- return $this->_postData!==null;
- }
-
- /**
- * @return boolean whether this is a callback request
- */
- public function getIsCallback()
- {
- return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
- }
-
- /**
- * This method is invoked when control state is to be saved.
- * You can override this method to do last step state saving.
- * Parent implementation must be invoked.
- */
- public function saveState()
- {
- parent::saveState();
- $this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
- }
-
- /**
- * This method is invoked right after the control has loaded its state.
- * You can override this method to initialize data from the control state.
- * Parent implementation must be invoked.
- */
- public function loadState()
- {
- parent::loadState();
- $this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
- }
-
- /**
- * Loads page state from persistent storage.
- */
- protected function loadPageState()
- {
- Prado::trace("Loading state",'System.Web.UI.TPage');
- $state=$this->getStatePersister()->load();
- $this->loadStateRecursive($state,$this->getEnableViewState());
- }
-
- /**
- * Saves page state from persistent storage.
- */
- protected function savePageState()
- {
- Prado::trace("Saving state",'System.Web.UI.TPage');
- $state=&$this->saveStateRecursive($this->getEnableViewState());
- $this->getStatePersister()->save($state);
- }
-
- /**
- * @param string the field name
- * @return boolean whether the specified field is a system field in postback data
- */
- protected function isSystemPostField($field)
- {
- return isset(self::$_systemPostFields[$field]);
- }
-
- /**
- * Registers a control for loading post data in the next postback.
- * This method needs to be invoked if the control to load post data
- * may not have a post variable in some cases. For example, a checkbox,
- * if not checked, will not have a post value.
- * @param TControl control registered for loading post data
- */
- public function registerRequiresPostData($control)
- {
- $id=is_string($control)?$control:$control->getUniqueID();
- $this->_controlsRegisteredForPostData[$id]=true;
- $params=func_get_args();
- foreach($this->getCachingStack() as $item)
- $item->registerAction('Page','registerRequiresPostData',array($id));
- }
-
- /**
- * @return TControl the control responsible for the current postback event, null if nonexistent
- */
- public function getPostBackEventTarget()
- {
- if($this->_postBackEventTarget===null && $this->_postData!==null)
- {
- $eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
- if(!empty($eventTarget))
- $this->_postBackEventTarget=$this->findControl($eventTarget);
- }
- return $this->_postBackEventTarget;
- }
-
- /**
- * Registers a control to raise postback event in the current request.
- * @param TControl control registered to raise postback event.
- */
- public function setPostBackEventTarget(TControl $control)
- {
- $this->_postBackEventTarget=$control;
- }
-
- /**
- * @return string postback event parameter
- */
- public function getPostBackEventParameter()
- {
- if($this->_postBackEventParameter===null && $this->_postData!==null)
- {
- if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
- $this->_postBackEventParameter='';
- }
- return $this->_postBackEventParameter;
- }
-
- /**
- * @param string postback event parameter
- */
- public function setPostBackEventParameter($value)
- {
- $this->_postBackEventParameter=$value;
- }
-
- /**
- * Processes post data.
- * @param TMap post data to be processed
- * @param boolean whether this method is invoked before {@link onLoad OnLoad}.
- */
- protected function processPostData($postData,$beforeLoad)
- {
- $this->_isLoadingPostData=true;
- if($beforeLoad)
- $this->_restPostData=new TMap;
- foreach($postData as $key=>$value)
- {
- if($this->isSystemPostField($key))
- continue;
- else if($control=$this->findControl($key))
- {
- if($control instanceof IPostBackDataHandler)
- {
- if($control->loadPostData($key,$postData))
- $this->_controlsPostDataChanged[]=$control;
- }
- else if($control instanceof IPostBackEventHandler &&
- empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
- {
- $this->_postData->add(self::FIELD_POSTBACK_TARGET,$key); // not calling setPostBackEventTarget() because the control may be removed later
- }
- unset($this->_controlsRequiringPostData[$key]);
- }
- else if($beforeLoad)
- $this->_restPostData->add($key,$value);
- }
-
- foreach($this->_controlsRequiringPostData as $key=>$value)
- {
- if($control=$this->findControl($key))
- {
- if($control instanceof IPostBackDataHandler)
- {
- if($control->loadPostData($key,$this->_postData))
- $this->_controlsPostDataChanged[]=$control;
- }
- else
- throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
- unset($this->_controlsRequiringPostData[$key]);
- }
- }
- $this->_isLoadingPostData=false;
- }
-
- /**
- * @return boolean true if loading post data.
- */
- public function getIsLoadingPostData()
- {
- return $this->_isLoadingPostData;
- }
-
- /**
- * Raises OnPostDataChangedEvent for controls whose data have been changed due to the postback.
- */
- protected function raiseChangedEvents()
- {
- foreach($this->_controlsPostDataChanged as $control)
- $control->raisePostDataChangedEvent();
- }
-
- /**
- * Raises PostBack event.
- */
- protected function raisePostBackEvent()
- {
- if(($postBackHandler=$this->getPostBackEventTarget())===null)
- $this->validate();
- else if($postBackHandler instanceof IPostBackEventHandler)
- $postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
- }
-
- /**
- * @return boolean Whether form rendering is in progress
- */
- public function getInFormRender()
- {
- return $this->_inFormRender;
- }
-
- /**
- * Ensures the control is rendered within a form.
- * @param TControl the control to be rendered
- * @throws TConfigurationException if the control is outside of the form
- */
- public function ensureRenderInForm($control)
- {
- if(!$this->getIsCallback() && !$this->_inFormRender)
- throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
- }
-
- /**
- * @internal This method is invoked by TForm at the beginning of its rendering
- */
- public function beginFormRender($writer)
- {
- if($this->_formRendered)
- throw new TConfigurationException('page_form_duplicated');
- $this->_formRendered=true;
- $this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
- $this->_inFormRender=true;
- }
-
- /**
- * @internal This method is invoked by TForm at the end of its rendering
- */
- public function endFormRender($writer)
- {
- if($this->_focus)
- {
- if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
- $focus=$this->_focus->getClientID();
- else
- $focus=$this->_focus;
- $this->getClientScript()->registerFocusControl($focus);
- }
- else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
- $this->getClientScript()->registerFocusControl($lastFocus);
- $this->_inFormRender=false;
- }
-
- /**
- * Sets input focus on a control after the page is rendered to users.
- * @param TControl|string control to receive focus, or the ID of the element on the page to receive focus
- */
- public function setFocus($value)
- {
- $this->_focus=$value;
- }
-
- /**
- * @return boolean whether client supports javascript. Defaults to true.
- */
- public function getClientSupportsJavaScript()
- {
- return $this->_enableJavaScript;
- }
-
- /**
- * @param boolean whether client supports javascript. If false, javascript will not be generated for controls.
- */
- public function setClientSupportsJavaScript($value)
- {
- $this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return THead page head, null if not available
- */
- public function getHead()
- {
- return $this->_head;
- }
-
- /**
- * @param THead page head
- * @throws TInvalidOperationException if a head already exists
- */
- public function setHead(THead $value)
- {
- if($this->_head)
- throw new TInvalidOperationException('page_head_duplicated');
- $this->_head=$value;
- if($this->_title!==null)
- {
- $this->_head->setTitle($this->_title);
- $this->_title=null;
- }
- }
-
- /**
- * @return string page title.
- */
- public function getTitle()
- {
- if($this->_head)
- return $this->_head->getTitle();
- else
- return $this->_title===null ? '' : $this->_title;
- }
-
- /**
- * Sets the page title.
- * Note, a {@link THead} control needs to place on the page
- * in order that this title be rendered.
- * @param string page title. This will override the title set in {@link getHead Head}.
- */
- public function setTitle($value)
- {
- if($this->_head)
- $this->_head->setTitle($value);
- else
- $this->_title=$value;
- }
-
- /**
- * Returns the state to be stored on the client side.
- * This method should only be used by framework and control developers.
- * @return string the state to be stored on the client side
- */
- public function getClientState()
- {
- return $this->_clientState;
- }
-
- /**
- * Sets the state to be stored on the client side.
- * This method should only be used by framework and control developers.
- * @param string the state to be stored on the client side
- */
- public function setClientState($state)
- {
- $this->_clientState=$state;
- }
-
- /**
- * @return string the state postback from client side
- */
- public function getRequestClientState()
- {
- return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
- }
-
- /**
- * @return string class name of the page state persister. Defaults to TPageStatePersister.
- */
- public function getStatePersisterClass()
- {
- return $this->_statePersisterClass;
- }
-
- /**
- * @param string class name of the page state persister.
- */
- public function setStatePersisterClass($value)
- {
- $this->_statePersisterClass=$value;
- }
-
- /**
- * @return IPageStatePersister page state persister
- */
- public function getStatePersister()
- {
- if($this->_statePersister===null)
- {
- $this->_statePersister=Prado::createComponent($this->_statePersisterClass);
- if(!($this->_statePersister instanceof IPageStatePersister))
- throw new TInvalidDataTypeException('page_statepersister_invalid');
- $this->_statePersister->setPage($this);
- }
- return $this->_statePersister;
- }
-
- /**
- * @return boolean whether page state should be HMAC validated. Defaults to true.
- */
- public function getEnableStateValidation()
- {
- return $this->_enableStateValidation;
- }
-
- /**
- * @param boolean whether page state should be HMAC validated.
- */
- public function setEnableStateValidation($value)
- {
- $this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return boolean whether page state should be encrypted. Defaults to false.
- */
- public function getEnableStateEncryption()
- {
- return $this->_enableStateEncryption;
- }
-
- /**
- * @param boolean whether page state should be encrypted.
- */
- public function setEnableStateEncryption($value)
- {
- $this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return boolean whether page state should be compressed. Defaults to true.
- * @since 3.1.6
- */
- public function getEnableStateCompression()
- {
- return $this->_enableStateCompression;
- }
-
- /**
- * @param boolean whether page state should be compressed.
- * @since 3.1.6
- */
- public function setEnableStateCompression($value)
- {
- $this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return string the requested page path for this page
- */
- public function getPagePath()
- {
- return $this->_pagePath;
- }
-
- /**
- * @param string the requested page path for this page
- */
- public function setPagePath($value)
- {
- $this->_pagePath=$value;
- }
-
- /**
- * 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 registerCachingAction($context,$funcName,$funcParams)
- {
- if($this->_cachingStack)
- {
- foreach($this->_cachingStack as $cache)
- $cache->registerAction($context,$funcName,$funcParams);
- }
- }
-
- /**
- * @return TStack stack of {@link TOutputCache} objects
- */
- public function getCachingStack()
- {
- if(!$this->_cachingStack)
- $this->_cachingStack=new TStack;
- return $this->_cachingStack;
- }
-
- /**
- * Flushes output
- */
- public function flushWriter()
- {
- if ($this->_writer)
- $this->Response->write($this->_writer->flush());
- }
-
- /**
- * Function to update view controls with data in a given AR object.
- * View controls and AR object need to have the same name in IDs and Attrs respectively.
- * @param TActiveRecord $arObj
- * @author Daniel Sampedro <darthdaniel85@gmail.com>
- */
- public function tryToUpdateView($arObj, $throwExceptions = false)
- {
- $objAttrs = get_class_vars(get_class($arObj));
- foreach (array_keys($objAttrs) as $key)
- {
- try
- {
- if ($key != "RELATIONS")
- {
- $control = $this->{$key};
- switch (get_class($control))
- {
- default:
- case "TTextBox":
- $control->Text = $arObj->{$key};
- break;
- case "TCheckBox":
- $control->Checked = (boolean) $arObj->{$key};
- break;
- case "TDatePicker":
- $control->Date = $arObj->{$key};
- break;
- }
- } else
- {
- foreach ($objAttrs["RELATIONS"] as $relKey => $relValues)
- {
- $relControl = $this->{$relKey};
- switch ($relValues[0])
- {
- case TActiveRecord::BELONGS_TO:
- case TActiveRecord::HAS_ONE:
- $relControl->Text = $arObj->{$relKey};
- break;
- case TActiveRecord::HAS_MANY:
- if($relControl instanceof TListControl){
- $relControl->DataSource = $arObj->{$relKey};
- $relControl->dataBind();
- }
- break;
- }
- }
- break;
- }
- } catch (Exception $ex)
- {
- if ($throwExceptions)
- {
- throw $ex;
- }
- }
- }
- }
-
- /**
- * Function to try to update an AR object with data in view controls.
- * @param TActiveRecord $arObj
- * @author Daniel Sampedro <darthdaniel85@gmail.com>
- */
- public function tryToUpdateAR($arObj, $throwExceptions = false)
- {
- $objAttrs = get_class_vars(get_class($arObj));
- foreach (array_keys($objAttrs) as $key)
- {
- try
- {
- if ($key == "RELATIONS")
- {
- break;
- }
- $control = $this->{$key};
- switch (get_class($control))
- {
- default:
- case "TTextBox":
- $arObj->{$key} = $control->Text;
- break;
- case "TCheckBox":
- $arObj->{$key} = $control->Checked;
- break;
- case "TDatePicker":
- $arObj->{$key} = $control->Date;
- break;
- }
- } catch (Exception $ex)
- {
- if ($throwExceptions)
- {
- throw $ex;
- }
- }
- }
- }
-}
-
-/**
- * IPageStatePersister interface.
- *
- * IPageStatePersister interface is required for all page state persister
- * classes.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @package System.Web.UI
- * @since 3.1
- */
-interface IPageStatePersister
-{
- /**
- * @param TPage the page that this persister works for
- */
- public function getPage();
- /**
- * @param TPage the page that this persister works for
- */
- public function setPage(TPage $page);
- /**
- * Saves state to persistent storage.
- * @param mixed state to be stored
- */
- public function save($state);
- /**
- * Loads page state from persistent storage
- * @return mixed the restored state
- */
- public function load();
-}
-
-
-/**
- * TPageStateFormatter class.
- *
- * TPageStateFormatter is a utility class to transform the page state
- * into and from a string that can be properly saved in persistent storage.
- *
- * Depending on the {@link TPage::getEnableStateValidation() EnableStateValidation}
- * and {@link TPage::getEnableStateEncryption() EnableStateEncryption},
- * TPageStateFormatter may do HMAC validation and encryption to prevent
- * the state data from being tampered or viewed.
- * The private keys and hashing/encryption methods are determined by
- * {@link TApplication::getSecurityManager() SecurityManager}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Revision: $ $Date: $
- * @package System.Web.UI
- * @since 3.1
- */
-class TPageStateFormatter
-{
- /**
- * @param TPage
- * @param mixed state data
- * @return string serialized data
- */
- public static function serialize($page,$data)
- {
- $sm=$page->getApplication()->getSecurityManager();
- if($page->getEnableStateValidation())
- $str=$sm->hashData(serialize($data));
- else
- $str=serialize($data);
- if($page->getEnableStateCompression() && extension_loaded('zlib'))
- $str=gzcompress($str);
- if($page->getEnableStateEncryption())
- $str=$sm->encrypt($str);
- return base64_encode($str);
- }
-
- /**
- * @param TPage
- * @param string serialized data
- * @return mixed unserialized state data, null if data is corrupted
- */
- public static function unserialize($page,$data)
- {
- $str=base64_decode($data);
- if($str==='')
- return null;
- if($str!==false)
- {
- $sm=$page->getApplication()->getSecurityManager();
- if($page->getEnableStateEncryption())
- $str=$sm->decrypt($str);
- if($page->getEnableStateCompression() && extension_loaded('zlib'))
- $str=@gzuncompress($str);
- if($page->getEnableStateValidation())
- {
- if(($str=$sm->validateData($str))!==false)
- return unserialize($str);
- }
- else
- return unserialize($str);
- }
- return null;
- }
-}
+<?php
+/**
+ * TPage class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2014 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @package System.Web.UI
+ */
+
+Prado::using('System.Web.UI.WebControls.*');
+Prado::using('System.Web.UI.TControl');
+Prado::using('System.Web.UI.WebControls.TWebControl');
+Prado::using('System.Web.UI.TCompositeControl');
+Prado::using('System.Web.UI.TTemplateControl');
+Prado::using('System.Web.UI.TForm');
+Prado::using('System.Web.UI.TClientScriptManager');
+
+/**
+ * TPage class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TPage extends TTemplateControl
+{
+ /**
+ * system post fields
+ */
+ const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
+ const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
+ const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
+ const FIELD_PAGESTATE='PRADO_PAGESTATE';
+ const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
+ const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
+
+ /**
+ * @var array system post fields
+ */
+ private static $_systemPostFields=array(
+ 'PRADO_POSTBACK_TARGET'=>true,
+ 'PRADO_POSTBACK_PARAMETER'=>true,
+ 'PRADO_LASTFOCUS'=>true,
+ 'PRADO_PAGESTATE'=>true,
+ 'PRADO_CALLBACK_TARGET'=>true,
+ 'PRADO_CALLBACK_PARAMETER'=>true
+ );
+ /**
+ * @var TForm form instance
+ */
+ private $_form;
+ /**
+ * @var THead head instance
+ */
+ private $_head;
+ /**
+ * @var array list of registered validators
+ */
+ private $_validators=array();
+ /**
+ * @var boolean if validation has been performed
+ */
+ private $_validated=false;
+ /**
+ * @var TTheme page theme
+ */
+ private $_theme;
+ /**
+ * @var string page title set when Head is not in page yet
+ */
+ private $_title;
+ /**
+ * @var TTheme page stylesheet theme
+ */
+ private $_styleSheet;
+ /**
+ * @var TClientScriptManager client script manager
+ */
+ private $_clientScript;
+ /**
+ * @var TMap data post back by user
+ */
+ protected $_postData;
+ /**
+ * @var TMap postback data that is not handled during first invocation of LoadPostData.
+ */
+ protected $_restPostData;
+ /**
+ * @var array list of controls whose data have been changed due to the postback
+ */
+ protected $_controlsPostDataChanged=array();
+ /**
+ * @var array list of controls that need to load post data in the current request
+ */
+ protected $_controlsRequiringPostData=array();
+ /**
+ * @var array list of controls that need to load post data in the next postback
+ */
+ protected $_controlsRegisteredForPostData=array();
+ /**
+ * @var TControl control that needs to raise postback event
+ */
+ private $_postBackEventTarget;
+ /**
+ * @var string postback event parameter
+ */
+ private $_postBackEventParameter;
+ /**
+ * @var boolean whether the form has been rendered
+ */
+ protected $_formRendered=false;
+ /**
+ * @var boolean whether the current rendering is within a form
+ */
+ protected $_inFormRender=false;
+ /**
+ * @var TControl|string the control or the ID of the element on the page to be focused when the page is sent back to user
+ */
+ private $_focus;
+ /**
+ * @var string page path to this page
+ */
+ private $_pagePath='';
+ /**
+ * @var boolean whether page state should be HMAC validated
+ */
+ private $_enableStateValidation=true;
+ /**
+ * @var boolean whether page state should be encrypted
+ */
+ private $_enableStateEncryption=false;
+ /**
+ * @var boolean whether page state should be compressed
+ * @since 3.1.6
+ */
+ private $_enableStateCompression=true;
+ /**
+ * @var string page state persister class name
+ */
+ private $_statePersisterClass='System.Web.UI.TPageStatePersister';
+ /**
+ * @var mixed page state persister
+ */
+ private $_statePersister;
+ /**
+ * @var TStack stack used to store currently active caching controls
+ */
+ private $_cachingStack;
+ /**
+ * @var string state string to be stored on the client side
+ */
+ private $_clientState='';
+ /**
+ * @var boolean true if loading post data.
+ */
+ protected $_isLoadingPostData=false;
+ /**
+ * @var boolean whether client supports javascript
+ */
+ private $_enableJavaScript=true;
+ /**
+ * @var THtmlWriter current html render writer
+ */
+ private $_writer;
+
+ /**
+ * Constructor.
+ * Sets the page object to itself.
+ * Derived classes must call parent implementation.
+ */
+ public function __construct()
+ {
+ $this->setPage($this);
+ }
+
+ /**
+ * Runs through the page lifecycles.
+ * @param THtmlTextWriter the HTML writer
+ */
+ public function run($writer)
+ {
+ Prado::trace("Running page life cycles",'System.Web.UI.TPage');
+ $this->_writer = $writer;
+
+ $this->determinePostBackMode();
+
+ if($this->getIsPostBack())
+ {
+ if($this->getIsCallback())
+ $this->processCallbackRequest($writer);
+ else
+ $this->processPostBackRequest($writer);
+ }
+ else
+ $this->processNormalRequest($writer);
+
+ $this->_writer = null;
+ }
+
+ protected function processNormalRequest($writer)
+ {
+ Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
+ $this->onPreInit(null);
+
+ Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
+ $this->initRecursive();
+
+ Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
+ $this->onInitComplete(null);
+
+ Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
+ $this->onPreLoad(null);
+ Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
+ $this->loadRecursive();
+ Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
+ $this->onLoadComplete(null);
+
+ Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
+ $this->preRenderRecursive();
+ Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
+ $this->onPreRenderComplete(null);
+
+ Prado::trace("Page savePageState()",'System.Web.UI.TPage');
+ $this->savePageState();
+ Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
+ $this->onSaveStateComplete(null);
+
+ Prado::trace("Page renderControl()",'System.Web.UI.TPage');
+ $this->renderControl($writer);
+ Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
+ $this->unloadRecursive();
+ }
+
+ protected function processPostBackRequest($writer)
+ {
+ Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
+ $this->onPreInit(null);
+
+ Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
+ $this->initRecursive();
+
+ Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
+ $this->onInitComplete(null);
+
+ $this->_restPostData=new TMap;
+ Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
+ $this->loadPageState();
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_postData,true);
+ Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
+ $this->onPreLoad(null);
+ Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
+ $this->loadRecursive();
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_restPostData,false);
+ Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
+ $this->raiseChangedEvents();
+ Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
+ $this->raisePostBackEvent();
+ Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
+ $this->onLoadComplete(null);
+
+ Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
+ $this->preRenderRecursive();
+ Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
+ $this->onPreRenderComplete(null);
+
+ Prado::trace("Page savePageState()",'System.Web.UI.TPage');
+ $this->savePageState();
+ Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
+ $this->onSaveStateComplete(null);
+
+ Prado::trace("Page renderControl()",'System.Web.UI.TPage');
+ $this->renderControl($writer);
+ Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
+ $this->unloadRecursive();
+ }
+
+ protected static function decodeUTF8($data, $enc)
+ {
+ if(is_array($data))
+ {
+ foreach($data as $k=>$v)
+ $data[$k]=self::decodeUTF8($v, $enc);
+ return $data;
+ } elseif(is_string($data)) {
+ return iconv('UTF-8',$enc.'//IGNORE',$data);
+ } else {
+ return $data;
+ }
+ }
+
+ /**
+ * Sets Adapter to TActivePageAdapter and calls apter to process the
+ * callback request.
+ */
+ protected function processCallbackRequest($writer)
+ {
+ Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
+
+ $this->setAdapter(new TActivePageAdapter($this));
+
+ $callbackEventParameter = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER);
+ if(strlen($callbackEventParameter) > 0)
+ $this->_postData[TPage::FIELD_CALLBACK_PARAMETER]=TJavaScript::jsonDecode((string)$callbackEventParameter);
+
+ // Decode Callback postData from UTF-8 to current Charset
+ if (($g=$this->getApplication()->getGlobalization(false))!==null &&
+ strtoupper($enc=$g->getCharset())!='UTF-8')
+ foreach ($this->_postData as $k=>$v)
+ $this->_postData[$k]=self::decodeUTF8($v, $enc);
+
+ Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
+ $this->onPreInit(null);
+
+ Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
+ $this->initRecursive();
+
+ Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
+ $this->onInitComplete(null);
+
+ $this->_restPostData=new TMap;
+ Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
+ $this->loadPageState();
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_postData,true);
+ Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
+ $this->onPreLoad(null);
+ Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
+ $this->loadRecursive();
+
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_restPostData,false);
+
+ Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
+ $this->raiseChangedEvents();
+
+
+ $this->getAdapter()->processCallbackEvent($writer);
+
+/*
+ Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
+ $this->raisePostBackEvent();
+*/
+ Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
+ $this->onLoadComplete(null);
+
+ Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
+ $this->preRenderRecursive();
+ Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
+ $this->onPreRenderComplete(null);
+
+ Prado::trace("Page savePageState()",'System.Web.UI.TPage');
+ $this->savePageState();
+ Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
+ $this->onSaveStateComplete(null);
+
+/*
+ Prado::trace("Page renderControl()",'System.Web.UI.TPage');
+ $this->renderControl($writer);
+*/
+ $this->getAdapter()->renderCallbackResponse($writer);
+
+ Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
+ $this->unloadRecursive();
+ }
+
+ /**
+ * Gets the callback client script handler that allows javascript functions
+ * to be executed during the callback response.
+ * @return TCallbackClientScript interface to client-side javascript code.
+ */
+ public function getCallbackClient()
+ {
+ if($this->getAdapter() !== null)
+ return $this->getAdapter()->getCallbackClientHandler();
+ else
+ return new TCallbackClientScript();
+ }
+
+ /**
+ * Set a new callback client handler.
+ * @param TCallbackClientScript new callback client script handler.
+ */
+ public function setCallbackClient($client)
+ {
+ $this->getAdapter()->setCallbackClientHandler($client);
+ }
+
+ /**
+ * @return TControl the control responsible for the current callback event,
+ * null if nonexistent
+ */
+ public function getCallbackEventTarget()
+ {
+ return $this->getAdapter()->getCallbackEventTarget();
+ }
+
+ /**
+ * Registers a control to raise callback event in the current request.
+ * @param TControl control registered to raise callback event.
+ */
+ public function setCallbackEventTarget(TControl $control)
+ {
+ $this->getAdapter()->setCallbackEventTarget($control);
+ }
+
+ /**
+ * Callback parameter is decoded assuming JSON encoding.
+ * @return string callback event parameter
+ */
+ public function getCallbackEventParameter()
+ {
+ return $this->getAdapter()->getCallbackEventParameter();
+ }
+
+ /**
+ * @param mixed callback event parameter
+ */
+ public function setCallbackEventParameter($value)
+ {
+ $this->getAdapter()->setCallbackEventParameter($value);
+ }
+
+ /**
+ * @return TForm the form on the page
+ */
+ public function getForm()
+ {
+ return $this->_form;
+ }
+
+ /**
+ * Registers a TForm instance to the page.
+ * Note, a page can contain at most one TForm instance.
+ * @param TForm the form on the page
+ * @throws TInvalidOperationException if this method is invoked twice or more.
+ */
+ public function setForm(TForm $form)
+ {
+ if($this->_form===null)
+ $this->_form=$form;
+ else
+ throw new TInvalidOperationException('page_form_duplicated');
+ }
+
+ /**
+ * Returns a list of registered validators.
+ * If validation group is specified, only the validators in that group will be returned.
+ * @param string validation group
+ * @return TList registered validators in the requested group. If the group is null, all validators will be returned.
+ */
+ public function getValidators($validationGroup=null)
+ {
+ if(!$this->_validators)
+ $this->_validators=new TList;
+ if(empty($validationGroup) === true)
+ return $this->_validators;
+ else
+ {
+ $list=new TList;
+ foreach($this->_validators as $validator)
+ if($validator->getValidationGroup()===$validationGroup)
+ $list->add($validator);
+ return $list;
+ }
+ }
+
+ /**
+ * Performs input validation.
+ * This method will invoke the registered validators to perform the actual validation.
+ * If validation group is specified, only the validators in that group will be invoked.
+ * @param string validation group. If null, all validators will perform validation.
+ */
+ public function validate($validationGroup=null)
+ {
+ Prado::trace("Page validate()",'System.Web.UI.TPage');
+ $this->_validated=true;
+ if($this->_validators && $this->_validators->getCount())
+ {
+ if($validationGroup===null)
+ {
+ foreach($this->_validators as $validator)
+ $validator->validate();
+ }
+ else
+ {
+ foreach($this->_validators as $validator)
+ {
+ if($validator->getValidationGroup()===$validationGroup)
+ $validator->validate();
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns whether user input is valid or not.
+ * This method must be invoked after {@link validate} is called.
+ * @return boolean whether the user input is valid or not.
+ * @throws TInvalidOperationException if {@link validate} is not invoked yet.
+ */
+ public function getIsValid()
+ {
+ if($this->_validated)
+ {
+ if($this->_validators && $this->_validators->getCount())
+ {
+ foreach($this->_validators as $validator)
+ if(!$validator->getIsValid())
+ return false;
+ }
+ return true;
+ }
+ else
+ throw new TInvalidOperationException('page_isvalid_unknown');
+ }
+
+ /**
+ * @return TTheme the theme used for the page. Defaults to null.
+ */
+ public function getTheme()
+ {
+ if(is_string($this->_theme))
+ $this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
+ return $this->_theme;
+ }
+
+ /**
+ * Sets the theme to be used for the page.
+ * @param string|TTheme the theme name or the theme object to be used for the page.
+ */
+ public function setTheme($value)
+ {
+ $this->_theme=empty($value)?null:$value;
+ }
+
+
+ /**
+ * @return TTheme the stylesheet theme used for the page. Defaults to null.
+ */
+ public function getStyleSheetTheme()
+ {
+ if(is_string($this->_styleSheet))
+ $this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
+ return $this->_styleSheet;
+ }
+
+ /**
+ * Sets the stylesheet theme to be used for the page.
+ * @param string|TTheme the stylesheet theme name or the stylesheet theme object to be used for the page.
+ */
+ public function setStyleSheetTheme($value)
+ {
+ $this->_styleSheet=empty($value)?null:$value;
+ }
+
+ /**
+ * Applies a skin in the current theme to a control.
+ * This method should only be used by framework developers.
+ * @param TControl a control to be applied skin with
+ */
+ public function applyControlSkin($control)
+ {
+ if(($theme=$this->getTheme())!==null)
+ $theme->applySkin($control);
+ }
+
+ /**
+ * Applies a stylesheet skin in the current theme to a control.
+ * This method should only be used by framework developers.
+ * @param TControl a control to be applied stylesheet skin with
+ */
+ public function applyControlStyleSheet($control)
+ {
+ if(($theme=$this->getStyleSheetTheme())!==null)
+ $theme->applySkin($control);
+ }
+
+ /**
+ * @return TClientScriptManager client script manager
+ */
+ public function getClientScript()
+ {
+ if(!$this->_clientScript) {
+ $className = $classPath = $this->getService()->getClientScriptManagerClass();
+ Prado::using($className);
+ if(($pos=strrpos($className,'.'))!==false)
+ $className=substr($className,$pos+1);
+
+ if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
+ throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
+
+ $this->_clientScript=new $className($this);
+ }
+ return $this->_clientScript;
+ }
+
+ /**
+ * Raises OnPreInit event.
+ * This method is invoked right before {@link onInit OnInit} stage.
+ * You may override this method to provide additional initialization that
+ * should be done before {@link onInit OnInit} (e.g. setting {@link setTheme Theme} or
+ * {@link setStyleSheetTheme StyleSheetTheme}).
+ * Remember to call the parent implementation to ensure OnPreInit event is raised.
+ * @param mixed event parameter
+ */
+ public function onPreInit($param)
+ {
+ $this->raiseEvent('OnPreInit',$this,$param);
+ }
+
+ /**
+ * Raises OnInitComplete event.
+ * This method is invoked right after {@link onInit OnInit} stage and before {@link onLoad OnLoad} stage.
+ * You may override this method to provide additional initialization that
+ * should be done after {@link onInit OnInit}.
+ * Remember to call the parent implementation to ensure OnInitComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onInitComplete($param)
+ {
+ $this->raiseEvent('OnInitComplete',$this,$param);
+ }
+
+ /**
+ * Raises OnPreLoad event.
+ * This method is invoked right before {@link onLoad OnLoad} stage.
+ * You may override this method to provide additional page loading logic that
+ * should be done before {@link onLoad OnLoad}.
+ * Remember to call the parent implementation to ensure OnPreLoad event is raised.
+ * @param mixed event parameter
+ */
+ public function onPreLoad($param)
+ {
+ $this->raiseEvent('OnPreLoad',$this,$param);
+ }
+
+ /**
+ * Raises OnLoadComplete event.
+ * This method is invoked right after {@link onLoad OnLoad} stage.
+ * You may override this method to provide additional page loading logic that
+ * should be done after {@link onLoad OnLoad}.
+ * Remember to call the parent implementation to ensure OnLoadComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onLoadComplete($param)
+ {
+ $this->raiseEvent('OnLoadComplete',$this,$param);
+ }
+
+ /**
+ * Raises OnPreRenderComplete event.
+ * This method is invoked right after {@link onPreRender OnPreRender} stage.
+ * You may override this method to provide additional preparation for page rendering
+ * that should be done after {@link onPreRender OnPreRender}.
+ * Remember to call the parent implementation to ensure OnPreRenderComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onPreRenderComplete($param)
+ {
+ $this->raiseEvent('OnPreRenderComplete',$this,$param);
+ $cs=$this->getClientScript();
+ $theme=$this->getTheme();
+ if($theme instanceof ITheme)
+ {
+ foreach($theme->getStyleSheetFiles() as $url)
+ $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
+ foreach($theme->getJavaScriptFiles() as $url)
+ $cs->registerHeadScriptFile($url,$url);
+ }
+ $styleSheet=$this->getStyleSheetTheme();
+ if($styleSheet instanceof ITheme)
+ {
+ foreach($styleSheet->getStyleSheetFiles() as $url)
+ $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
+ foreach($styleSheet->getJavaScriptFiles() as $url)
+ $cs->registerHeadScriptFile($url,$url);
+ }
+
+ if($cs->getRequiresHead() && $this->getHead()===null)
+ throw new TConfigurationException('page_head_required');
+ }
+
+ /**
+ * Determines the media type of the CSS file.
+ * The media type is determined according to the following file name pattern:
+ * xxx.media-type.extension
+ * For example, 'mystyle.print.css' means its media type is 'print'.
+ * @param string CSS URL
+ * @return string media type of the CSS file
+ */
+ private function getCssMediaType($url)
+ {
+ $segs=explode('.',basename($url));
+ if(isset($segs[2]))
+ return $segs[count($segs)-2];
+ else
+ return '';
+ }
+
+ /**
+ * Raises OnSaveStateComplete event.
+ * This method is invoked right after {@link onSaveState OnSaveState} stage.
+ * You may override this method to provide additional logic after page state is saved.
+ * Remember to call the parent implementation to ensure OnSaveStateComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onSaveStateComplete($param)
+ {
+ $this->raiseEvent('OnSaveStateComplete',$this,$param);
+ }
+
+ /**
+ * Determines whether the current page request is a postback.
+ * Call {@link getIsPostBack} to get the result.
+ */
+ private function determinePostBackMode()
+ {
+ $postData=$this->getRequest();
+ if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
+ $this->_postData=$postData;
+ }
+
+ /**
+ * @return boolean whether the current page request is a postback
+ */
+ public function getIsPostBack()
+ {
+ return $this->_postData!==null;
+ }
+
+ /**
+ * @return boolean whether this is a callback request
+ */
+ public function getIsCallback()
+ {
+ return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
+ }
+
+ /**
+ * This method is invoked when control state is to be saved.
+ * You can override this method to do last step state saving.
+ * Parent implementation must be invoked.
+ */
+ public function saveState()
+ {
+ parent::saveState();
+ $this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
+ }
+
+ /**
+ * This method is invoked right after the control has loaded its state.
+ * You can override this method to initialize data from the control state.
+ * Parent implementation must be invoked.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ $this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
+ }
+
+ /**
+ * Loads page state from persistent storage.
+ */
+ protected function loadPageState()
+ {
+ Prado::trace("Loading state",'System.Web.UI.TPage');
+ $state=$this->getStatePersister()->load();
+ $this->loadStateRecursive($state,$this->getEnableViewState());
+ }
+
+ /**
+ * Saves page state from persistent storage.
+ */
+ protected function savePageState()
+ {
+ Prado::trace("Saving state",'System.Web.UI.TPage');
+ $state=&$this->saveStateRecursive($this->getEnableViewState());
+ $this->getStatePersister()->save($state);
+ }
+
+ /**
+ * @param string the field name
+ * @return boolean whether the specified field is a system field in postback data
+ */
+ protected function isSystemPostField($field)
+ {
+ return isset(self::$_systemPostFields[$field]);
+ }
+
+ /**
+ * Registers a control for loading post data in the next postback.
+ * This method needs to be invoked if the control to load post data
+ * may not have a post variable in some cases. For example, a checkbox,
+ * if not checked, will not have a post value.
+ * @param TControl control registered for loading post data
+ */
+ public function registerRequiresPostData($control)
+ {
+ $id=is_string($control)?$control:$control->getUniqueID();
+ $this->_controlsRegisteredForPostData[$id]=true;
+ $params=func_get_args();
+ foreach($this->getCachingStack() as $item)
+ $item->registerAction('Page','registerRequiresPostData',array($id));
+ }
+
+ /**
+ * @return TControl the control responsible for the current postback event, null if nonexistent
+ */
+ public function getPostBackEventTarget()
+ {
+ if($this->_postBackEventTarget===null && $this->_postData!==null)
+ {
+ $eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
+ if(!empty($eventTarget))
+ $this->_postBackEventTarget=$this->findControl($eventTarget);
+ }
+ return $this->_postBackEventTarget;
+ }
+
+ /**
+ * Registers a control to raise postback event in the current request.
+ * @param TControl control registered to raise postback event.
+ */
+ public function setPostBackEventTarget(TControl $control)
+ {
+ $this->_postBackEventTarget=$control;
+ }
+
+ /**
+ * @return string postback event parameter
+ */
+ public function getPostBackEventParameter()
+ {
+ if($this->_postBackEventParameter===null && $this->_postData!==null)
+ {
+ if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
+ $this->_postBackEventParameter='';
+ }
+ return $this->_postBackEventParameter;
+ }
+
+ /**
+ * @param string postback event parameter
+ */
+ public function setPostBackEventParameter($value)
+ {
+ $this->_postBackEventParameter=$value;
+ }
+
+ /**
+ * Processes post data.
+ * @param TMap post data to be processed
+ * @param boolean whether this method is invoked before {@link onLoad OnLoad}.
+ */
+ protected function processPostData($postData,$beforeLoad)
+ {
+ $this->_isLoadingPostData=true;
+ if($beforeLoad)
+ $this->_restPostData=new TMap;
+ foreach($postData as $key=>$value)
+ {
+ if($this->isSystemPostField($key))
+ continue;
+ else if($control=$this->findControl($key))
+ {
+ if($control instanceof IPostBackDataHandler)
+ {
+ if($control->loadPostData($key,$postData))
+ $this->_controlsPostDataChanged[]=$control;
+ }
+ else if($control instanceof IPostBackEventHandler &&
+ empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
+ {
+ $this->_postData->add(self::FIELD_POSTBACK_TARGET,$key); // not calling setPostBackEventTarget() because the control may be removed later
+ }
+ unset($this->_controlsRequiringPostData[$key]);
+ }
+ else if($beforeLoad)
+ $this->_restPostData->add($key,$value);
+ }
+
+ foreach($this->_controlsRequiringPostData as $key=>$value)
+ {
+ if($control=$this->findControl($key))
+ {
+ if($control instanceof IPostBackDataHandler)
+ {
+ if($control->loadPostData($key,$this->_postData))
+ $this->_controlsPostDataChanged[]=$control;
+ }
+ else
+ throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
+ unset($this->_controlsRequiringPostData[$key]);
+ }
+ }
+ $this->_isLoadingPostData=false;
+ }
+
+ /**
+ * @return boolean true if loading post data.
+ */
+ public function getIsLoadingPostData()
+ {
+ return $this->_isLoadingPostData;
+ }
+
+ /**
+ * Raises OnPostDataChangedEvent for controls whose data have been changed due to the postback.
+ */
+ protected function raiseChangedEvents()
+ {
+ foreach($this->_controlsPostDataChanged as $control)
+ $control->raisePostDataChangedEvent();
+ }
+
+ /**
+ * Raises PostBack event.
+ */
+ protected function raisePostBackEvent()
+ {
+ if(($postBackHandler=$this->getPostBackEventTarget())===null)
+ $this->validate();
+ else if($postBackHandler instanceof IPostBackEventHandler)
+ $postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
+ }
+
+ /**
+ * @return boolean Whether form rendering is in progress
+ */
+ public function getInFormRender()
+ {
+ return $this->_inFormRender;
+ }
+
+ /**
+ * Ensures the control is rendered within a form.
+ * @param TControl the control to be rendered
+ * @throws TConfigurationException if the control is outside of the form
+ */
+ public function ensureRenderInForm($control)
+ {
+ if(!$this->getIsCallback() && !$this->_inFormRender)
+ throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
+ }
+
+ /**
+ * @internal This method is invoked by TForm at the beginning of its rendering
+ */
+ public function beginFormRender($writer)
+ {
+ if($this->_formRendered)
+ throw new TConfigurationException('page_form_duplicated');
+ $this->_formRendered=true;
+ $this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
+ $this->_inFormRender=true;
+ }
+
+ /**
+ * @internal This method is invoked by TForm at the end of its rendering
+ */
+ public function endFormRender($writer)
+ {
+ if($this->_focus)
+ {
+ if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
+ $focus=$this->_focus->getClientID();
+ else
+ $focus=$this->_focus;
+ $this->getClientScript()->registerFocusControl($focus);
+ }
+ else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
+ $this->getClientScript()->registerFocusControl($lastFocus);
+ $this->_inFormRender=false;
+ }
+
+ /**
+ * Sets input focus on a control after the page is rendered to users.
+ * @param TControl|string control to receive focus, or the ID of the element on the page to receive focus
+ */
+ public function setFocus($value)
+ {
+ $this->_focus=$value;
+ }
+
+ /**
+ * @return boolean whether client supports javascript. Defaults to true.
+ */
+ public function getClientSupportsJavaScript()
+ {
+ return $this->_enableJavaScript;
+ }
+
+ /**
+ * @param boolean whether client supports javascript. If false, javascript will not be generated for controls.
+ */
+ public function setClientSupportsJavaScript($value)
+ {
+ $this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return THead page head, null if not available
+ */
+ public function getHead()
+ {
+ return $this->_head;
+ }
+
+ /**
+ * @param THead page head
+ * @throws TInvalidOperationException if a head already exists
+ */
+ public function setHead(THead $value)
+ {
+ if($this->_head)
+ throw new TInvalidOperationException('page_head_duplicated');
+ $this->_head=$value;
+ if($this->_title!==null)
+ {
+ $this->_head->setTitle($this->_title);
+ $this->_title=null;
+ }
+ }
+
+ /**
+ * @return string page title.
+ */
+ public function getTitle()
+ {
+ if($this->_head)
+ return $this->_head->getTitle();
+ else
+ return $this->_title===null ? '' : $this->_title;
+ }
+
+ /**
+ * Sets the page title.
+ * Note, a {@link THead} control needs to place on the page
+ * in order that this title be rendered.
+ * @param string page title. This will override the title set in {@link getHead Head}.
+ */
+ public function setTitle($value)
+ {
+ if($this->_head)
+ $this->_head->setTitle($value);
+ else
+ $this->_title=$value;
+ }
+
+ /**
+ * Returns the state to be stored on the client side.
+ * This method should only be used by framework and control developers.
+ * @return string the state to be stored on the client side
+ */
+ public function getClientState()
+ {
+ return $this->_clientState;
+ }
+
+ /**
+ * Sets the state to be stored on the client side.
+ * This method should only be used by framework and control developers.
+ * @param string the state to be stored on the client side
+ */
+ public function setClientState($state)
+ {
+ $this->_clientState=$state;
+ }
+
+ /**
+ * @return string the state postback from client side
+ */
+ public function getRequestClientState()
+ {
+ return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
+ }
+
+ /**
+ * @return string class name of the page state persister. Defaults to TPageStatePersister.
+ */
+ public function getStatePersisterClass()
+ {
+ return $this->_statePersisterClass;
+ }
+
+ /**
+ * @param string class name of the page state persister.
+ */
+ public function setStatePersisterClass($value)
+ {
+ $this->_statePersisterClass=$value;
+ }
+
+ /**
+ * @return IPageStatePersister page state persister
+ */
+ public function getStatePersister()
+ {
+ if($this->_statePersister===null)
+ {
+ $this->_statePersister=Prado::createComponent($this->_statePersisterClass);
+ if(!($this->_statePersister instanceof IPageStatePersister))
+ throw new TInvalidDataTypeException('page_statepersister_invalid');
+ $this->_statePersister->setPage($this);
+ }
+ return $this->_statePersister;
+ }
+
+ /**
+ * @return boolean whether page state should be HMAC validated. Defaults to true.
+ */
+ public function getEnableStateValidation()
+ {
+ return $this->_enableStateValidation;
+ }
+
+ /**
+ * @param boolean whether page state should be HMAC validated.
+ */
+ public function setEnableStateValidation($value)
+ {
+ $this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether page state should be encrypted. Defaults to false.
+ */
+ public function getEnableStateEncryption()
+ {
+ return $this->_enableStateEncryption;
+ }
+
+ /**
+ * @param boolean whether page state should be encrypted.
+ */
+ public function setEnableStateEncryption($value)
+ {
+ $this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether page state should be compressed. Defaults to true.
+ * @since 3.1.6
+ */
+ public function getEnableStateCompression()
+ {
+ return $this->_enableStateCompression;
+ }
+
+ /**
+ * @param boolean whether page state should be compressed.
+ * @since 3.1.6
+ */
+ public function setEnableStateCompression($value)
+ {
+ $this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return string the requested page path for this page
+ */
+ public function getPagePath()
+ {
+ return $this->_pagePath;
+ }
+
+ /**
+ * @param string the requested page path for this page
+ */
+ public function setPagePath($value)
+ {
+ $this->_pagePath=$value;
+ }
+
+ /**
+ * 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 registerCachingAction($context,$funcName,$funcParams)
+ {
+ if($this->_cachingStack)
+ {
+ foreach($this->_cachingStack as $cache)
+ $cache->registerAction($context,$funcName,$funcParams);
+ }
+ }
+
+ /**
+ * @return TStack stack of {@link TOutputCache} objects
+ */
+ public function getCachingStack()
+ {
+ if(!$this->_cachingStack)
+ $this->_cachingStack=new TStack;
+ return $this->_cachingStack;
+ }
+
+ /**
+ * Flushes output
+ */
+ public function flushWriter()
+ {
+ if ($this->_writer)
+ $this->Response->write($this->_writer->flush());
+ }
+
+ /**
+ * Function to update view controls with data in a given AR object.
+ * View controls and AR object need to have the same name in IDs and Attrs respectively.
+ * @param TActiveRecord $arObj
+ * @param Boolean $throwExceptions Wheter or not to throw exceptions
+ * @author Daniel Sampedro <darthdaniel85@gmail.com>
+ */
+ public function tryToUpdateView($arObj, $throwExceptions = false)
+ {
+ $objAttrs = get_class_vars(get_class($arObj));
+ foreach (array_keys($objAttrs) as $key)
+ {
+ try
+ {
+ if ($key != "RELATIONS")
+ {
+ $control = $this->{$key};
+ if ($control instanceof TTextBox)
+ $control->Text = $arObj->{$key};
+ elseif ($control instanceof TCheckBox)
+ $control->Checked = (boolean) $arObj->{$key};
+ elseif ($control instanceof TDatePicker)
+ $control->Date = $arObj->{$key};
+ }
+ else
+ {
+ foreach ($objAttrs["RELATIONS"] as $relKey => $relValues)
+ {
+ $relControl = $this->{$relKey};
+ switch ($relValues[0])
+ {
+ case TActiveRecord::BELONGS_TO:
+ case TActiveRecord::HAS_ONE:
+ $relControl->Text = $arObj->{$relKey};
+ break;
+ case TActiveRecord::HAS_MANY:
+ if ($relControl instanceof TListControl)
+ {
+ $relControl->DataSource = $arObj->{$relKey};
+ $relControl->dataBind();
+ }
+ break;
+ }
+ }
+ break;
+ }
+ } catch (Exception $ex)
+ {
+ if ($throwExceptions)
+ throw $ex;
+ }
+ }
+ }
+
+ /**
+ * Function to try to update an AR object with data in view controls.
+ * @param TActiveRecord $arObj
+ * @param Boolean $throwExceptions Wheter or not to throw exceptions
+ * @author Daniel Sampedro <darthdaniel85@gmail.com>
+ */
+ public function tryToUpdateAR($arObj, $throwExceptions = false)
+ {
+ $objAttrs = get_class_vars(get_class($arObj));
+ foreach (array_keys($objAttrs) as $key)
+ {
+ try
+ {
+ if ($key == "RELATIONS")
+ break;
+ $control = $this->{$key};
+ if ($control instanceof TTextBox)
+ $arObj->{$key} = $control->Text;
+ elseif ($control instanceof TCheckBox)
+ $arObj->{$key} = $control->Checked;
+ elseif ($control instanceof TDatePicker)
+ $arObj->{$key} = $control->Date;
+ } catch (Exception $ex)
+ {
+ if ($throwExceptions)
+ throw $ex;
+ }
+ }
+ }
+
+}
+
+/**
+ * IPageStatePersister interface.
+ *
+ * IPageStatePersister interface is required for all page state persister
+ * classes.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System.Web.UI
+ * @since 3.1
+ */
+interface IPageStatePersister
+{
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function getPage();
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function setPage(TPage $page);
+ /**
+ * Saves state to persistent storage.
+ * @param mixed state to be stored
+ */
+ public function save($state);
+ /**
+ * Loads page state from persistent storage
+ * @return mixed the restored state
+ */
+ public function load();
+}
+
+
+/**
+ * TPageStateFormatter class.
+ *
+ * TPageStateFormatter is a utility class to transform the page state
+ * into and from a string that can be properly saved in persistent storage.
+ *
+ * Depending on the {@link TPage::getEnableStateValidation() EnableStateValidation}
+ * and {@link TPage::getEnableStateEncryption() EnableStateEncryption},
+ * TPageStateFormatter may do HMAC validation and encryption to prevent
+ * the state data from being tampered or viewed.
+ * The private keys and hashing/encryption methods are determined by
+ * {@link TApplication::getSecurityManager() SecurityManager}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI
+ * @since 3.1
+ */
+class TPageStateFormatter
+{
+ /**
+ * @param TPage
+ * @param mixed state data
+ * @return string serialized data
+ */
+ public static function serialize($page,$data)
+ {
+ $sm=$page->getApplication()->getSecurityManager();
+ if($page->getEnableStateValidation())
+ $str=$sm->hashData(serialize($data));
+ else
+ $str=serialize($data);
+ if($page->getEnableStateCompression() && extension_loaded('zlib'))
+ $str=gzcompress($str);
+ if($page->getEnableStateEncryption())
+ $str=$sm->encrypt($str);
+ return base64_encode($str);
+ }
+
+ /**
+ * @param TPage
+ * @param string serialized data
+ * @return mixed unserialized state data, null if data is corrupted
+ */
+ public static function unserialize($page,$data)
+ {
+ $str=base64_decode($data);
+ if($str==='')
+ return null;
+ if($str!==false)
+ {
+ $sm=$page->getApplication()->getSecurityManager();
+ if($page->getEnableStateEncryption())
+ $str=$sm->decrypt($str);
+ if($page->getEnableStateCompression() && extension_loaded('zlib'))
+ $str=@gzuncompress($str);
+ if($page->getEnableStateValidation())
+ {
+ if(($str=$sm->validateData($str))!==false)
+ return unserialize($str);
+ }
+ else
+ return unserialize($str);
+ }
+ return null;
+ }
+}