From e08aa82e5e4d2bc06bb8f98654806a15bdefc994 Mon Sep 17 00:00:00 2001 From: xue <> Date: Wed, 21 Dec 2005 17:06:12 +0000 Subject: Added support to global state. --- .gitattributes | 4 +- demos/controls/index.php | 2 +- demos/controls/protected/application.xml | 3 + demos/controls/protected/pages/HomePage.php | 2 +- demos/controls/protected/pages/HomePage.tpl | 8 +- demos/controls/protected/pages/config.xml | 3 - demos/hangman/index.php | 2 +- demos/hangman/protected/application.xml | 14 -- demos/hangman/protected/data/application.xml | 14 ++ demos/personal/index.php | 2 +- demos/personal/protected/Data/application.xml | 31 +++++ demos/personal/protected/application.xml | 31 ----- framework/Exceptions/messages.txt | 1 + framework/TApplication.php | 178 +++++++++++++++++++++++--- framework/Web/UI/TControl.php | 15 +-- 15 files changed, 224 insertions(+), 86 deletions(-) delete mode 100644 demos/hangman/protected/application.xml create mode 100644 demos/hangman/protected/data/application.xml create mode 100644 demos/personal/protected/Data/application.xml delete mode 100644 demos/personal/protected/application.xml diff --git a/.gitattributes b/.gitattributes index 6c27cc00..d58b5f76 100644 --- a/.gitattributes +++ b/.gitattributes @@ -20,7 +20,7 @@ demos/controls/themes/BlueTheme/labels.skin -text demos/controls/themes/BlueTheme/simple.css -text demos/hangman/index.php -text demos/hangman/protected/.htaccess -text -demos/hangman/protected/application.xml -text +demos/hangman/protected/data/application.xml -text demos/hangman/protected/data/words.txt -text demos/hangman/protected/pages/HomePage.php -text demos/hangman/protected/pages/HomePage.tpl -text @@ -28,6 +28,7 @@ demos/hangman/protected/pages/Layout.php -text demos/hangman/protected/pages/Layout.tpl -text demos/hangman/protected/pages/config.xml -text demos/personal/index.php -text +demos/personal/protected/Data/application.xml -text demos/personal/protected/Modules/DataModule.php -text demos/personal/protected/Pages/HomePage.php -text demos/personal/protected/Pages/HomePage.tpl -text @@ -36,7 +37,6 @@ demos/personal/protected/Pages/Layout.tpl -text demos/personal/protected/Pages/LoginPage.php -text demos/personal/protected/Pages/LoginPage.tpl -text demos/personal/protected/Pages/config.xml -text -demos/personal/protected/application.xml -text demos/personal/themes/BlueTheme/buttons.skin -text demos/personal/themes/BlueTheme/icon_profile.gif -text demos/personal/themes/BlueTheme/labels.skin -text diff --git a/demos/controls/index.php b/demos/controls/index.php index d5f7caf3..95d06df0 100644 --- a/demos/controls/index.php +++ b/demos/controls/index.php @@ -2,7 +2,7 @@ require_once(dirname(__FILE__).'/../../framework/prado.php'); -$application=new TApplication(dirname(__FILE__).'/protected/application.xml',dirname(__FILE__).'/protected/application.cache'); +$application=new TApplication(dirname(__FILE__).'/protected/application.xml'); $application->run(); ?> \ No newline at end of file diff --git a/demos/controls/protected/application.xml b/demos/controls/protected/application.xml index 56f37d03..20c84e3f 100644 --- a/demos/controls/protected/application.xml +++ b/demos/controls/protected/application.xml @@ -27,4 +27,7 @@ + + foo@foo.com + \ No newline at end of file diff --git a/demos/controls/protected/pages/HomePage.php b/demos/controls/protected/pages/HomePage.php index 50bdc9e7..1b513aba 100644 --- a/demos/controls/protected/pages/HomePage.php +++ b/demos/controls/protected/pages/HomePage.php @@ -14,7 +14,7 @@ class HomePage extends TPage parent::onLoad($param); if(!$this->IsPostBack) { - $this->dataBind(); + //$this->dataBind(); } } diff --git a/demos/controls/protected/pages/HomePage.tpl b/demos/controls/protected/pages/HomePage.tpl index d1dd7724..5d016682 100644 --- a/demos/controls/protected/pages/HomePage.tpl +++ b/demos/controls/protected/pages/HomePage.tpl @@ -55,10 +55,10 @@ Click="linkClicked" onclick="javascript:alert('you hit me')"/> - + + - + /> @@ -69,7 +69,7 @@ -!> + <%# $this->Page->TextBox->Text %> diff --git a/demos/controls/protected/pages/config.xml b/demos/controls/protected/pages/config.xml index c90a6974..ce3ced8a 100644 --- a/demos/controls/protected/pages/config.xml +++ b/demos/controls/protected/pages/config.xml @@ -1,9 +1,6 @@ - - - diff --git a/demos/hangman/index.php b/demos/hangman/index.php index 8ec5d000..af488b0a 100644 --- a/demos/hangman/index.php +++ b/demos/hangman/index.php @@ -2,7 +2,7 @@ $basePath=dirname(__FILE__); require_once($basePath.'/../../framework/prado.php'); -$application=new TApplication($basePath.'/protected/application.xml'); +$application=new TApplication($basePath.'/protected/data/application.xml'); $application->run(); ?> \ No newline at end of file diff --git a/demos/hangman/protected/application.xml b/demos/hangman/protected/application.xml deleted file mode 100644 index 1f91fcff..00000000 --- a/demos/hangman/protected/application.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - Application.data.words - - \ No newline at end of file diff --git a/demos/hangman/protected/data/application.xml b/demos/hangman/protected/data/application.xml new file mode 100644 index 00000000..7cdc3a0b --- /dev/null +++ b/demos/hangman/protected/data/application.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + Application.data.words + + \ No newline at end of file diff --git a/demos/personal/index.php b/demos/personal/index.php index 4b7e8a5f..3e4985cc 100644 --- a/demos/personal/index.php +++ b/demos/personal/index.php @@ -8,7 +8,7 @@ if(!is_writable(APPLICATION_PATH.'/assets')) die('Please make sure that the directory "'.APPLICATION_PATH.'/assets'.'" is writable by Web server process.'); require_once(APPLICATION_PATH.'/../../framework/prado.php'); -$application=new TApplication(APPLICATION_PATH.'/protected/application.xml',APPLICATION_PATH.'/protected/Data/application.cache'); +$application=new TApplication(APPLICATION_PATH.'/protected/Data/application.xml'); $application->run(); ?> \ No newline at end of file diff --git a/demos/personal/protected/Data/application.xml b/demos/personal/protected/Data/application.xml new file mode 100644 index 00000000..d0403a50 --- /dev/null +++ b/demos/personal/protected/Data/application.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demos/personal/protected/application.xml b/demos/personal/protected/application.xml deleted file mode 100644 index 9013121e..00000000 --- a/demos/personal/protected/application.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/framework/Exceptions/messages.txt b/framework/Exceptions/messages.txt index 39945661..651287e1 100644 --- a/framework/Exceptions/messages.txt +++ b/framework/Exceptions/messages.txt @@ -24,6 +24,7 @@ map_item_unremovable = The item cannot be removed from the map. map_data_not_iterable = Data must be either an array or an object implementing Traversable interface. application_configfile_inexistent = Application configuration file '%s' does not exist. +application_statepath_invalid = Application state path '%s' does not exist or is not writable by Web server process. application_module_existing = Application module '%s' cannot be registered twice. application_service_invalid = Service '%s' must implement IService interface. application_service_unknown = Requested service '%s' is not defined. diff --git a/framework/TApplication.php b/framework/TApplication.php index 6e43fbf1..4136afdd 100644 --- a/framework/TApplication.php +++ b/framework/TApplication.php @@ -98,11 +98,6 @@ require_once(PRADO_DIR.'/Web/Services/TPageService.php'); * $application=new TApplication($configFile); * $application->run(); * - * - The parsed application configuration file is cached. - * - * $application=new TApplication($configFile,$cacheFile); - * $application->run(); - * * * @author Qiang Xue * @version $Revision: $ $Date: $ @@ -111,10 +106,27 @@ require_once(PRADO_DIR.'/Web/Services/TPageService.php'); */ class TApplication extends TComponent { + /** + * application state + */ + const STATE_OFF='Off'; + const STATE_DEBUG='Debug'; + const STATE_NORMAL='Normal'; + const STATE_PERFORMANCE='Performance'; + /** * Default service ID */ const DEFAULT_SERVICE='page'; + /** + * Config cache file + */ + const CONFIGCACHE_FILE='config.cache'; + /** + * Global data file + */ + const GLOBAL_FILE='global.cache'; + /** * @var array list of events that define application lifecycles */ @@ -166,6 +178,18 @@ class TApplication extends TComponent * @var string configuration file */ private $_configFile; + /** + * @var string directory storing application state + */ + private $_statePath; + /** + * @var boolean if any global state is changed during the current request + */ + private $_stateChanged=false; + /** + * @var array global variables (persistent across sessions, requests) + */ + private $_globals=array(); /** * @var string cache file */ @@ -208,16 +232,24 @@ class TApplication extends TComponent * Initializes the application singleton. This method ensures that users can * only create one application instance. * @param string configuration file path (absolute or relative to current running script) - * @param string cache file path. This is optional. If it is present, it will - * be used to store and load parsed application configuration (to improve performance). + * @param string a directory used to store application-level persistent data. Defaults to the path having the application configuration file. + * @param boolean whether to cache application configuration. Defaults to true. + * @throws TConfigurationException if configuration file cannot be read or the state path is invalid. */ - public function __construct($configFile,$cacheFile=null) + public function __construct($configFile,$statePath=null,$cacheConfig=true) { parent::__construct(); Prado::setApplication($this); if(($this->_configFile=realpath($configFile))===false || !is_file($this->_configFile)) - throw new TIOException('application_configfile_inexistent',$configFile); - $this->_cacheFile=$cacheFile; + throw new TConfigurationException('application_configfile_inexistent',$configFile); + if($statePath===null) + $this->_statePath=dirname($this->_configFile); + else if(is_dir($statePath) && is_writable($statePath)) + $this->_statePath=$statePath; + else + throw new TConfigurationException('application_statepath_invalid',$statePath); + $this->_cacheFile=$cacheConfig ? $this->_statePath.'/'.self::CONFIGCACHE_FILE : null; + // generates unique ID by hashing the configuration file path $this->_uniqueID=md5($this->_configFile); } @@ -232,7 +264,7 @@ class TApplication extends TComponent { try { - $this->initApplication($this->_configFile,$this->_cacheFile); + $this->initApplication(); $n=count(self::$_steps); $this->_step=0; $this->_requestCompleted=false; @@ -264,6 +296,82 @@ class TApplication extends TComponent $this->_requestCompleted=true; } + /** + * Returns a global value. + * + * A global value is one that is persistent across users sessions and requests. + * @param string the name of the value to be returned + * @param mixed the default value. If $key is not found, $defaultValue will be returned + * @return mixed the global value corresponding to $key + */ + public function getGlobal($key,$defaultValue=null) + { + return isset($this->_globals[$key])?$this->_globals[$key]:$defaultValue; + } + + /** + * Sets a global value. + * + * A global value is one that is persistent across users sessions and requests. + * Make sure that the value is serializable and unserializable. + * @param string the name of the value to be returned + * @param mixed the global value to be set + * @param mixed the default value. If $key is not found, $defaultValue will be returned + */ + public function setGlobal($key,$value,$defaultValue=null) + { + if(!$this->_stateChanged && isset($this->_globals[$key]) && $this->_globals[$key]===$value) + $this->_stateChanged=true; + if($value===$defaultValue) + unset($this->_globals[$key]); + else + $this->_globals[$key]=$value; + } + + /** + * Loads global values from persistent storage. + * This method is invoked when {@link onLoadState LoadState} event is raised. + * After this method, values that are stored in previous requests become + * available to the current request via {@link getGlobal}. + */ + protected function loadGlobals() + { + if(($cache=$this->getCache())!==null && ($value=$cache->get('prado:globals'))!==false) + $this->_globals=$value; + else + { + if(($content=@file_get_contents($this->getStatePath().'/'.self::GLOBAL_FILE))!==false) + $this->_globals=unserialize($content); + } + } + + /** + * Saves global values into persistent storage. + * This method is invoked when {@link onSaveState SaveState} event is raised. + */ + protected function saveGlobals() + { + if(!$this->_stateChanged) + return; + $content=serialize($this->_globals); + $saveFile=true; + if(($cache=$this->getCache())!==null) + { + if($cache->get('prado:globals')!==$content) + $cache->set('prado:globals',$content); + else + $saveFile=false; + } + if($saveFile) + { + $fileName=$this->getStatePath().'/'.self::GLOBAL_FILE; + if(version_compare(phpversion(),'5.1.0','>=')) + file_put_contents($fileName,$content,LOCK_EX); + else + file_put_contents($fileName,$content); + } + } + /** * @return string application ID */ @@ -301,7 +409,7 @@ class TApplication extends TComponent */ public function setMode($value) { - $this->_mode=TPropertyValue::ensureEnum($value,array('Off','Debug','Normal','Performance')); + $this->_mode=TPropertyValue::ensureEnum($value,array(self::STATE_OFF,self::STATE_DEBUG,self::STATE_NORMAL,self::STATE_PERFORMANCE)); } /** @@ -312,6 +420,15 @@ class TApplication extends TComponent return $this->_configFile; } + /** + * Gets the directory storing application-level persistent data. + * @return string application state path + */ + public function getStatePath() + { + return $this->_statePath; + } + /** * @return IService the currently requested service */ @@ -379,6 +496,27 @@ class TApplication extends TComponent $this->_request=$request; } + /** + * @return TSecurityManager security manager module + */ + public function getSecurityManager() + { + if(!$this->_security) + { + $this->_security=new TSecurityManager; + $this->_security->init($this,null); + } + return $this->_security; + } + + /** + * @param TSecurityManager security manager module + */ + public function setSecurityManager(TSecurityManager $manager) + { + $this->_security=$manager; + } + /** * @return THttpResponse the response module */ @@ -493,26 +631,26 @@ class TApplication extends TComponent * @param string cache file path, empty if no present or needed * @throws TConfigurationException if module is redefined of invalid type, or service not defined or of invalid type */ - protected function initApplication($configFile,$cacheFile) + protected function initApplication() { - if($cacheFile===null || @filemtime($cacheFile)_cacheFile===null || @filemtime($this->_cacheFile)_configFile)) { $config=new TApplicationConfiguration; - $config->loadFromFile($configFile); - if($cacheFile!==null) + $config->loadFromFile($this->_configFile); + if($this->_cacheFile!==null) { - if(($fp=fopen($cacheFile,'wb'))!==false) + if(($fp=fopen($this->_cacheFile,'wb'))!==false) { fputs($fp,Prado::serialize($config)); fclose($fp); } else - syslog(LOG_WARNING,'Prado application config cache file "'.$cacheFile.'" cannot be created.'); + syslog(LOG_WARNING,'Prado application config cache file "'.$this->_cacheFile.'" cannot be created.'); } } else { - $config=Prado::unserialize(file_get_contents($cacheFile)); + $config=Prado::unserialize(file_get_contents($this->_cacheFile)); } @@ -644,6 +782,7 @@ class TApplication extends TComponent */ public function onLoadState($param) { + $this->loadGlobals(); $this->raiseEvent('LoadState',$this,$param); } @@ -695,6 +834,7 @@ class TApplication extends TComponent public function onSaveState($param) { $this->raiseEvent('SaveState',$this,$param); + $this->saveGlobals(); } /** diff --git a/framework/Web/UI/TControl.php b/framework/Web/UI/TControl.php index 5c3eecc6..dcd48ba2 100644 --- a/framework/Web/UI/TControl.php +++ b/framework/Web/UI/TControl.php @@ -728,14 +728,12 @@ class TControl extends TComponent /** * Performs the databinding for this control. - * @param boolean whether to raise DataBinding event. */ - public function dataBind($raiseDataBindingEvent=true) + public function dataBind() { - $this->dataBindProperties($raiseDataBindingEvent); - if($raiseDataBindingEvent) - $this->onDataBinding(null); - $this->dataBindChildren($raiseDataBindingEvent); + $this->dataBindProperties(); + $this->onDataBinding(null); + $this->dataBindChildren(); } /** @@ -752,15 +750,14 @@ class TControl extends TComponent /** * Databinding child controls. - * @param boolean whether to raise DataBinding event. */ - protected function dataBindChildren($raiseDataBindingEvent) + protected function dataBindChildren() { if(isset($this->_rf[self::RF_CONTROLS])) { foreach($this->_rf[self::RF_CONTROLS] as $control) if($control instanceof TControl) - $control->dataBind($raiseDataBindingEvent); + $control->dataBind(); } } -- cgit v1.2.3