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