summaryrefslogtreecommitdiff
path: root/lib/prado/framework/TApplication.php
diff options
context:
space:
mode:
authoremkael <emkael@tlen.pl>2016-02-24 23:18:07 +0100
committeremkael <emkael@tlen.pl>2016-02-24 23:18:07 +0100
commit6f7fdef0f500cd4bb540affd3bc1482243f337c1 (patch)
tree4853eecd0769a903e6130c1896e1d070848150dd /lib/prado/framework/TApplication.php
parent61f2ea48a4e11cb5fb941b3783e19c9e9ef38a45 (diff)
* Prado 3.3.0
Diffstat (limited to 'lib/prado/framework/TApplication.php')
-rw-r--r--lib/prado/framework/TApplication.php1874
1 files changed, 1874 insertions, 0 deletions
diff --git a/lib/prado/framework/TApplication.php b/lib/prado/framework/TApplication.php
new file mode 100644
index 0000000..1ae868d
--- /dev/null
+++ b/lib/prado/framework/TApplication.php
@@ -0,0 +1,1874 @@
+<?php
+/**
+ * TApplication class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link https://github.com/pradosoft/prado
+ * @copyright Copyright &copy; 2005-2015 The PRADO Group
+ * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT
+ * @package System
+ */
+
+/**
+ * Includes core interfaces essential for TApplication class
+ */
+require_once(PRADO_DIR.'/interfaces.php');
+
+/**
+ * Includes core classes essential for TApplication class
+ */
+Prado::using('System.TApplicationComponent');
+Prado::using('System.TModule');
+Prado::using('System.TService');
+Prado::using('System.Exceptions.TErrorHandler');
+Prado::using('System.Caching.TCache');
+Prado::using('System.IO.TTextWriter');
+Prado::using('System.Collections.TPriorityList');
+Prado::using('System.Collections.TPriorityMap');
+Prado::using('System.Collections.TStack');
+Prado::using('System.Xml.TXmlDocument');
+Prado::using('System.Security.TAuthorizationRule');
+Prado::using('System.Security.TSecurityManager');
+Prado::using('System.Web.THttpUtility');
+Prado::using('System.Web.Javascripts.TJavaScript');
+Prado::using('System.Web.THttpRequest');
+Prado::using('System.Web.THttpResponse');
+Prado::using('System.Web.THttpSession');
+Prado::using('System.Web.Services.TPageService');
+Prado::using('System.Web.TAssetManager');
+Prado::using('System.I18N.TGlobalization');
+
+/**
+ * TApplication class.
+ *
+ * TApplication coordinates modules and services, and serves as a configuration
+ * context for all Prado components.
+ *
+ * TApplication uses a configuration file to specify the settings of
+ * the application, the modules, the services, the parameters, and so on.
+ *
+ * TApplication adopts a modular structure. A TApplication instance is a composition
+ * of multiple modules. A module is an instance of class implementing
+ * {@link IModule} interface. Each module accomplishes certain functionalities
+ * that are shared by all Prado components in an application.
+ * There are default modules and user-defined modules. The latter offers extreme
+ * flexibility of extending TApplication in a plug-and-play fashion.
+ * Modules cooperate with each other to serve a user request by following
+ * a sequence of lifecycles predefined in TApplication.
+ *
+ * TApplication has four modes that can be changed by setting {@link setMode Mode}
+ * property (in the application configuration file).
+ * - <b>Off</b> mode will prevent the application from serving user requests.
+ * - <b>Debug</b> mode is mainly used during application development. It ensures
+ * the cache is always up-to-date if caching is enabled. It also allows
+ * exceptions are displayed with rich context information if they occur.
+ * - <b>Normal</b> mode is mainly used during production stage. Exception information
+ * will only be recorded in system error logs. The cache is ensured to be
+ * up-to-date if it is enabled.
+ * - <b>Performance</b> mode is similar to <b>Normal</b> mode except that it
+ * does not ensure the cache is up-to-date.
+ *
+ * TApplication dispatches each user request to a particular service which
+ * finishes the actual work for the request with the aid from the application
+ * modules.
+ *
+ * TApplication maintains a lifecycle with the following stages:
+ * - [construct] : construction of the application instance
+ * - [initApplication] : load application configuration and instantiate modules and the requested service
+ * - onBeginRequest : this event happens right after application initialization
+ * - onAuthentication : this event happens when authentication is needed for the current request
+ * - onAuthenticationComplete : this event happens right after the authentication is done for the current request
+ * - onAuthorization : this event happens when authorization is needed for the current request
+ * - onAuthorizationComplete : this event happens right after the authorization is done for the current request
+ * - onLoadState : this event happens when application state needs to be loaded
+ * - onLoadStateComplete : this event happens right after the application state is loaded
+ * - onPreRunService : this event happens right before the requested service is to run
+ * - runService : the requested service runs
+ * - onSaveState : this event happens when application needs to save its state
+ * - onSaveStateComplete : this event happens right after the application saves its state
+ * - onPreFlushOutput : this event happens right before the application flushes output to client side.
+ * - flushOutput : the application flushes output to client side.
+ * - onEndRequest : this is the last stage a request is being completed
+ * - [destruct] : destruction of the application instance
+ * Modules and services can attach their methods to one or several of the above
+ * events and do appropriate processing when the events are raised. By this way,
+ * the application is able to coordinate the activities of modules and services
+ * in the above order. To terminate an application before the whole lifecycle
+ * completes, call {@link completeRequest}.
+ *
+ * Examples:
+ * - Create and run a Prado application:
+ * <code>
+ * $application=new TApplication($configFile);
+ * $application->run();
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System
+ * @since 3.0
+ */
+class TApplication extends TComponent
+{
+ /**
+ * possible application mode.
+ * @deprecated deprecated since version 3.0.4 (use TApplicationMode constants instead)
+ */
+ const STATE_OFF='Off';
+ const STATE_DEBUG='Debug';
+ const STATE_NORMAL='Normal';
+ const STATE_PERFORMANCE='Performance';
+
+ /**
+ * Page service ID
+ */
+ const PAGE_SERVICE_ID='page';
+ /**
+ * Application configuration file name
+ */
+ const CONFIG_FILE_XML='application.xml';
+ /**
+ * File extension for external config files
+ */
+ const CONFIG_FILE_EXT_XML='.xml';
+ /**
+ * Configuration file type, application.xml and config.xml
+ */
+ const CONFIG_TYPE_XML = 'xml';
+ /**
+ * Application configuration file name
+ */
+ const CONFIG_FILE_PHP='application.php';
+ /**
+ * File extension for external config files
+ */
+ const CONFIG_FILE_EXT_PHP='.php';
+ /**
+ * Configuration file type, application.php and config.php
+ */
+ const CONFIG_TYPE_PHP = 'php';
+ /**
+ * Runtime directory name
+ */
+ const RUNTIME_PATH='runtime';
+ /**
+ * 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
+ */
+ private static $_steps=array(
+ 'onBeginRequest',
+ 'onLoadState',
+ 'onLoadStateComplete',
+ 'onAuthentication',
+ 'onAuthenticationComplete',
+ 'onAuthorization',
+ 'onAuthorizationComplete',
+ 'onPreRunService',
+ 'runService',
+ 'onSaveState',
+ 'onSaveStateComplete',
+ 'onPreFlushOutput',
+ 'flushOutput'
+ );
+
+ /**
+ * @var string application ID
+ */
+ private $_id;
+ /**
+ * @var string unique application ID
+ */
+ private $_uniqueID;
+ /**
+ * @var boolean whether the request is completed
+ */
+ private $_requestCompleted=false;
+ /**
+ * @var integer application state
+ */
+ private $_step;
+ /**
+ * @var array available services and their configurations indexed by service IDs
+ */
+ private $_services;
+ /**
+ * @var IService current service instance
+ */
+ private $_service;
+ /**
+ * @var array list of loaded application modules
+ */
+ private $_modules=array();
+ /**
+ * @var array list of application modules yet to be loaded
+ */
+ private $_lazyModules=array();
+ /**
+ * @var TMap list of application parameters
+ */
+ private $_parameters;
+ /**
+ * @var string configuration file
+ */
+ private $_configFile;
+ /**
+ * @var string configuration file extension
+ */
+ private $_configFileExt;
+ /**
+ * @var string configuration type
+ */
+ private $_configType;
+ /**
+ * @var string application base path
+ */
+ private $_basePath;
+ /**
+ * @var string directory storing application state
+ */
+ private $_runtimePath;
+ /**
+ * @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
+ */
+ private $_cacheFile;
+ /**
+ * @var TErrorHandler error handler module
+ */
+ private $_errorHandler;
+ /**
+ * @var THttpRequest request module
+ */
+ private $_request;
+ /**
+ * @var THttpResponse response module
+ */
+ private $_response;
+ /**
+ * @var THttpSession session module, could be null
+ */
+ private $_session;
+ /**
+ * @var ICache cache module, could be null
+ */
+ private $_cache;
+ /**
+ * @var IStatePersister application state persister
+ */
+ private $_statePersister;
+ /**
+ * @var IUser user instance, could be null
+ */
+ private $_user;
+ /**
+ * @var TGlobalization module, could be null
+ */
+ private $_globalization;
+ /**
+ * @var TSecurityManager security manager module
+ */
+ private $_security;
+ /**
+ * @var TAssetManager asset manager module
+ */
+ private $_assetManager;
+ /**
+ * @var TAuthorizationRuleCollection collection of authorization rules
+ */
+ private $_authRules;
+ /**
+ * @var TApplicationMode application mode
+ */
+ private $_mode=TApplicationMode::Debug;
+
+ /**
+ * @var string Customizable page service ID
+ */
+ private $_pageServiceID = self::PAGE_SERVICE_ID;
+
+ /**
+ * Constructor.
+ * Sets application base path and initializes the application singleton.
+ * Application base path refers to the root directory storing application
+ * data and code not directly accessible by Web users.
+ * By default, the base path is assumed to be the <b>protected</b>
+ * directory under the directory containing the current running script.
+ * @param string application base path or configuration file path.
+ * If the parameter is a file, it is assumed to be the application
+ * configuration file, and the directory containing the file is treated
+ * as the application base path.
+ * If it is a directory, it is assumed to be the application base path,
+ * and within that directory, a file named <b>application.xml</b>
+ * will be looked for. If found, the file is considered as the application
+ * configuration file.
+ * @param boolean whether to cache application configuration. Defaults to true.
+ * @throws TConfigurationException if configuration file cannot be read or the runtime path is invalid.
+ */
+ public function __construct($basePath='protected',$cacheConfig=true, $configType=self::CONFIG_TYPE_XML)
+ {
+ // register application as a singleton
+ Prado::setApplication($this);
+ $this->setConfigurationType($configType);
+ $this->resolvePaths($basePath);
+
+ if($cacheConfig)
+ $this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
+
+ // generates unique ID by hashing the runtime path
+ $this->_uniqueID=md5($this->_runtimePath);
+ $this->_parameters=new TMap;
+ $this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
+
+ Prado::setPathOfAlias('Application',$this->_basePath);
+ }
+
+ /**
+ * Resolves application-relevant paths.
+ * This method is invoked by the application constructor
+ * to determine the application configuration file,
+ * application root path and the runtime path.
+ * @param string the application root path or the application configuration file
+ * @see setBasePath
+ * @see setRuntimePath
+ * @see setConfigurationFile
+ */
+ protected function resolvePaths($basePath)
+ {
+ // determine configuration path and file
+ if(empty($basePath) || ($basePath=realpath($basePath))===false)
+ throw new TConfigurationException('application_basepath_invalid',$basePath);
+ if(is_dir($basePath) && is_file($basePath.DIRECTORY_SEPARATOR.$this->getConfigurationFileName()))
+ $configFile=$basePath.DIRECTORY_SEPARATOR.$this->getConfigurationFileName();
+ else if(is_file($basePath))
+ {
+ $configFile=$basePath;
+ $basePath=dirname($configFile);
+ }
+ else
+ $configFile=null;
+
+ // determine runtime path
+ $runtimePath=$basePath.DIRECTORY_SEPARATOR.self::RUNTIME_PATH;
+ if(is_writable($runtimePath))
+ {
+ if($configFile!==null)
+ {
+ $runtimePath.=DIRECTORY_SEPARATOR.basename($configFile).'-'.Prado::getVersion();
+ if(!is_dir($runtimePath))
+ {
+ if(@mkdir($runtimePath)===false)
+ throw new TConfigurationException('application_runtimepath_failed',$runtimePath);
+ @chmod($runtimePath, PRADO_CHMOD); //make it deletable
+ }
+ $this->setConfigurationFile($configFile);
+ }
+ $this->setBasePath($basePath);
+ $this->setRuntimePath($runtimePath);
+ }
+ else
+ throw new TConfigurationException('application_runtimepath_invalid',$runtimePath);
+
+ }
+
+ /**
+ * Executes the lifecycles of the application.
+ * This is the main entry function that leads to the running of the whole
+ * Prado application.
+ */
+ public function run()
+ {
+ try
+ {
+ $this->initApplication();
+ $n=count(self::$_steps);
+ $this->_step=0;
+ $this->_requestCompleted=false;
+ while($this->_step<$n)
+ {
+ if($this->_mode===self::STATE_OFF)
+ throw new THttpException(503,'application_unavailable');
+ if($this->_requestCompleted)
+ break;
+ $method=self::$_steps[$this->_step];
+ Prado::trace("Executing $method()",'System.TApplication');
+ $this->$method();
+ $this->_step++;
+ }
+ }
+ catch(Exception $e)
+ {
+ $this->onError($e);
+ }
+ $this->onEndRequest();
+ }
+
+ /**
+ * Completes current request processing.
+ * This method can be used to exit the application lifecycles after finishing
+ * the current cycle.
+ */
+ public function completeRequest()
+ {
+ $this->_requestCompleted=true;
+ }
+
+ /**
+ * @return boolean whether the current request is processed.
+ */
+ public function getRequestCompleted()
+ {
+ return $this->_requestCompleted;
+ }
+
+ /**
+ * 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 getGlobalState($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 set
+ * @param mixed the global value to be set
+ * @param mixed the default value. If $key is not found, $defaultValue will be returned
+ * @param boolean wheter to force an immediate GlobalState save. defaults to false
+ */
+ public function setGlobalState($key,$value,$defaultValue=null,$forceSave=false)
+ {
+ $this->_stateChanged=true;
+ if($value===$defaultValue)
+ unset($this->_globals[$key]);
+ else
+ $this->_globals[$key]=$value;
+ if($forceSave)
+ $this->saveGlobals();
+ }
+
+ /**
+ * Clears a global value.
+ *
+ * The value cleared will no longer be available in this request and the following requests.
+ * @param string the name of the value to be cleared
+ */
+ public function clearGlobalState($key)
+ {
+ $this->_stateChanged=true;
+ unset($this->_globals[$key]);
+ }
+
+ /**
+ * Loads global values from persistent storage.
+ * This method is invoked when {@link onLoadState OnLoadState} event is raised.
+ * After this method, values that are stored in previous requests become
+ * available to the current request via {@link getGlobalState}.
+ */
+ protected function loadGlobals()
+ {
+ $this->_globals=$this->getApplicationStatePersister()->load();
+ }
+
+ /**
+ * Saves global values into persistent storage.
+ * This method is invoked when {@link onSaveState OnSaveState} event is raised.
+ */
+ protected function saveGlobals()
+ {
+ if($this->_stateChanged)
+ {
+ $this->_stateChanged=false;
+ $this->getApplicationStatePersister()->save($this->_globals);
+ }
+ }
+
+ /**
+ * @return string application ID
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * @param string application ID
+ */
+ public function setID($value)
+ {
+ $this->_id=$value;
+ }
+
+ /**
+ * @return string page service ID
+ */
+ public function getPageServiceID()
+ {
+ return $this->_pageServiceID;
+ }
+
+ /**
+ * @param string page service ID
+ */
+ public function setPageServiceID($value)
+ {
+ $this->_pageServiceID=$value;
+ }
+
+ /**
+ * @return string an ID that uniquely identifies this Prado application from the others
+ */
+ public function getUniqueID()
+ {
+ return $this->_uniqueID;
+ }
+
+ /**
+ * @return TApplicationMode application mode. Defaults to TApplicationMode::Debug.
+ */
+ public function getMode()
+ {
+ return $this->_mode;
+ }
+
+ /**
+ * @param TApplicationMode application mode
+ */
+ public function setMode($value)
+ {
+ $this->_mode=TPropertyValue::ensureEnum($value,'TApplicationMode');
+ }
+
+ /**
+ * @return string the directory containing the application configuration file (absolute path)
+ */
+ public function getBasePath()
+ {
+ return $this->_basePath;
+ }
+
+ /**
+ * @param string the directory containing the application configuration file
+ */
+ public function setBasePath($value)
+ {
+ $this->_basePath=$value;
+ }
+
+ /**
+ * @return string the application configuration file (absolute path)
+ */
+ public function getConfigurationFile()
+ {
+ return $this->_configFile;
+ }
+
+ /**
+ * @param string the application configuration file (absolute path)
+ */
+ public function setConfigurationFile($value)
+ {
+ $this->_configFile=$value;
+ }
+
+ /**
+ * @return string the application configuration file (absolute path)
+ */
+ public function getConfigurationType()
+ {
+ return $this->_configType;
+ }
+
+ /**
+ * @param string the application configuration type. 'xml' and 'php' are valid values
+ */
+ public function setConfigurationType($value)
+ {
+ $this->_configType = $value;
+ }
+
+ /**
+ * @return string the application configuration type. default is 'xml'
+ */
+ public function getConfigurationFileExt()
+ {
+ if($this->_configFileExt===null)
+ {
+ switch($this->_configType)
+ {
+ case TApplication::CONFIG_TYPE_PHP:
+ $this->_configFileExt = TApplication::CONFIG_FILE_EXT_PHP;
+ break;
+ default:
+ $this->_configFileExt = TApplication::CONFIG_FILE_EXT_XML;
+ }
+ }
+ return $this->_configFileExt;
+ }
+
+ /**
+ * @return string the default configuration file name
+ */
+ public function getConfigurationFileName()
+ {
+ static $fileName;
+ if($fileName == null)
+ {
+ switch($this->_configType)
+ {
+ case TApplication::CONFIG_TYPE_PHP:
+ $fileName = TApplication::CONFIG_FILE_PHP;
+ break;
+ default:
+ $fileName = TApplication::CONFIG_FILE_XML;
+ }
+ }
+ return $fileName;
+ }
+
+ /**
+ * @return string the directory storing cache data and application-level persistent data. (absolute path)
+ */
+ public function getRuntimePath()
+ {
+ return $this->_runtimePath;
+ }
+
+ /**
+ * @param string the directory storing cache data and application-level persistent data. (absolute path)
+ */
+ public function setRuntimePath($value)
+ {
+ $this->_runtimePath=$value;
+ if($this->_cacheFile)
+ $this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
+ // generates unique ID by hashing the runtime path
+ $this->_uniqueID=md5($this->_runtimePath);
+ }
+
+ /**
+ * @return IService the currently requested service
+ */
+ public function getService()
+ {
+ return $this->_service;
+ }
+
+ /**
+ * @param IService the currently requested service
+ */
+ public function setService($value)
+ {
+ $this->_service=$value;
+ }
+
+ /**
+ * Adds a module to application.
+ * Note, this method does not do module initialization.
+ * @param string ID of the module
+ * @param IModule module object or null if the module has not been loaded yet
+ */
+ public function setModule($id,IModule $module=null)
+ {
+ if(isset($this->_modules[$id]))
+ throw new TConfigurationException('application_moduleid_duplicated',$id);
+ else
+ $this->_modules[$id]=$module;
+ }
+
+ /**
+ * @return IModule the module with the specified ID, null if not found
+ */
+ public function getModule($id)
+ {
+ if(!array_key_exists($id, $this->_modules))
+ return null;
+
+ // force loading of a lazy module
+ if($this->_modules[$id]===null)
+ {
+ $module = $this->internalLoadModule($id, true);
+ $module[0]->init($module[1]);
+ }
+
+ return $this->_modules[$id];
+ }
+
+ /**
+ * Returns a list of application modules indexed by module IDs.
+ * Modules that have not been loaded yet are returned as null objects.
+ * @return array list of loaded application modules, indexed by module IDs
+ */
+ public function getModules()
+ {
+ return $this->_modules;
+ }
+
+ /**
+ * Returns the list of application parameters.
+ * Since the parameters are returned as a {@link TMap} object, you may use
+ * the returned result to access, add or remove individual parameters.
+ * @return TMap the list of application parameters
+ */
+ public function getParameters()
+ {
+ return $this->_parameters;
+ }
+
+ /**
+ * @return THttpRequest the request module
+ */
+ public function getRequest()
+ {
+ if(!$this->_request)
+ {
+ $this->_request=new THttpRequest;
+ $this->_request->init(null);
+ }
+ return $this->_request;
+ }
+
+ /**
+ * @param THttpRequest the request module
+ */
+ public function setRequest(THttpRequest $request)
+ {
+ $this->_request=$request;
+ }
+
+ /**
+ * @return THttpResponse the response module
+ */
+ public function getResponse()
+ {
+ if(!$this->_response)
+ {
+ $this->_response=new THttpResponse;
+ $this->_response->init(null);
+ }
+ return $this->_response;
+ }
+
+ /**
+ * @param THttpRequest the request module
+ */
+ public function setResponse(THttpResponse $response)
+ {
+ $this->_response=$response;
+ }
+
+ /**
+ * @return THttpSession the session module, null if session module is not installed
+ */
+ public function getSession()
+ {
+ if(!$this->_session)
+ {
+ $this->_session=new THttpSession;
+ $this->_session->init(null);
+ }
+ return $this->_session;
+ }
+
+ /**
+ * @param THttpSession the session module
+ */
+ public function setSession(THttpSession $session)
+ {
+ $this->_session=$session;
+ }
+
+ /**
+ * @return TErrorHandler the error handler module
+ */
+ public function getErrorHandler()
+ {
+ if(!$this->_errorHandler)
+ {
+ $this->_errorHandler=new TErrorHandler;
+ $this->_errorHandler->init(null);
+ }
+ return $this->_errorHandler;
+ }
+
+ /**
+ * @param TErrorHandler the error handler module
+ */
+ public function setErrorHandler(TErrorHandler $handler)
+ {
+ $this->_errorHandler=$handler;
+ }
+
+ /**
+ * @return TSecurityManager the security manager module
+ */
+ public function getSecurityManager()
+ {
+ if(!$this->_security)
+ {
+ $this->_security=new TSecurityManager;
+ $this->_security->init(null);
+ }
+ return $this->_security;
+ }
+
+ /**
+ * @param TSecurityManager the security manager module
+ */
+ public function setSecurityManager(TSecurityManager $sm)
+ {
+ $this->_security=$sm;
+ }
+
+ /**
+ * @return TAssetManager asset manager
+ */
+ public function getAssetManager()
+ {
+ if(!$this->_assetManager)
+ {
+ $this->_assetManager=new TAssetManager;
+ $this->_assetManager->init(null);
+ }
+ return $this->_assetManager;
+ }
+
+ /**
+ * @param TAssetManager asset manager
+ */
+ public function setAssetManager(TAssetManager $value)
+ {
+ $this->_assetManager=$value;
+ }
+
+ /**
+ * @return IStatePersister application state persister
+ */
+ public function getApplicationStatePersister()
+ {
+ if(!$this->_statePersister)
+ {
+ $this->_statePersister=new TApplicationStatePersister;
+ $this->_statePersister->init(null);
+ }
+ return $this->_statePersister;
+ }
+
+ /**
+ * @param IStatePersister application state persister
+ */
+ public function setApplicationStatePersister(IStatePersister $persister)
+ {
+ $this->_statePersister=$persister;
+ }
+
+ /**
+ * @return ICache the cache module, null if cache module is not installed
+ */
+ public function getCache()
+ {
+ return $this->_cache;
+ }
+
+ /**
+ * @param ICache the cache module
+ */
+ public function setCache(ICache $cache)
+ {
+ $this->_cache=$cache;
+ }
+
+ /**
+ * @return IUser the application user
+ */
+ public function getUser()
+ {
+ return $this->_user;
+ }
+
+ /**
+ * @param IUser the application user
+ */
+ public function setUser(IUser $user)
+ {
+ $this->_user=$user;
+ }
+
+ /**
+ * @param boolean whether to create globalization if it does not exist
+ * @return TGlobalization globalization module
+ */
+ public function getGlobalization($createIfNotExists=true)
+ {
+ if($this->_globalization===null && $createIfNotExists)
+ {
+ $this->_globalization=new TGlobalization;
+ $this->_globalization->init(null);
+ }
+ return $this->_globalization;
+ }
+
+ /**
+ * @param TGlobalization globalization module
+ */
+ public function setGlobalization(TGlobalization $glob)
+ {
+ $this->_globalization=$glob;
+ }
+
+ /**
+ * @return TAuthorizationRuleCollection list of authorization rules for the current request
+ */
+ public function getAuthorizationRules()
+ {
+ if($this->_authRules===null)
+ $this->_authRules=new TAuthorizationRuleCollection;
+ return $this->_authRules;
+ }
+
+ protected function getApplicationConfigurationClass()
+ {
+ return 'TApplicationConfiguration';
+ }
+
+ protected function internalLoadModule($id, $force=false)
+ {
+ list($moduleClass, $initProperties, $configElement)=$this->_lazyModules[$id];
+ if(isset($initProperties['lazy']) && $initProperties['lazy'] && !$force)
+ {
+ Prado::trace("Postponed loading of lazy module $id ({$moduleClass})",'System.TApplication');
+ $this->setModule($id, null);
+ return null;
+ }
+
+ Prado::trace("Loading module $id ({$moduleClass})",'System.TApplication');
+ $module=Prado::createComponent($moduleClass);
+ foreach($initProperties as $name=>$value)
+ {
+ if($name==='lazy') continue;
+ $module->setSubProperty($name,$value);
+ }
+ $this->setModule($id,$module);
+ // keep the key to avoid reuse of the old module id
+ $this->_lazyModules[$id]=null;
+
+ return array($module,$configElement);
+ }
+ /**
+ * Applies an application configuration.
+ * @param TApplicationConfiguration the configuration
+ * @param boolean whether the configuration is specified within a service.
+ */
+ public function applyConfiguration($config,$withinService=false)
+ {
+ if($config->getIsEmpty())
+ return;
+
+ // set path aliases and using namespaces
+ foreach($config->getAliases() as $alias=>$path)
+ Prado::setPathOfAlias($alias,$path);
+ foreach($config->getUsings() as $using)
+ Prado::using($using);
+
+ // set application properties
+ if(!$withinService)
+ {
+ foreach($config->getProperties() as $name=>$value)
+ $this->setSubProperty($name,$value);
+ }
+
+ if(empty($this->_services))
+ $this->_services=array($this->getPageServiceID()=>array('TPageService',array(),null));
+
+ // load parameters
+ foreach($config->getParameters() as $id=>$parameter)
+ {
+ if(is_array($parameter))
+ {
+ $component=Prado::createComponent($parameter[0]);
+ foreach($parameter[1] as $name=>$value)
+ $component->setSubProperty($name,$value);
+ $this->_parameters->add($id,$component);
+ }
+ else
+ $this->_parameters->add($id,$parameter);
+ }
+
+ // load and init modules specified in app config
+ $modules=array();
+ foreach($config->getModules() as $id=>$moduleConfig)
+ {
+ if(!is_string($id))
+ $id='_module'.count($this->_lazyModules);
+ $this->_lazyModules[$id]=$moduleConfig;
+ if($module = $this->internalLoadModule($id))
+ $modules[]=$module;
+ }
+ foreach($modules as $module)
+ $module[0]->init($module[1]);
+
+ // load service
+ foreach($config->getServices() as $serviceID=>$serviceConfig)
+ $this->_services[$serviceID]=$serviceConfig;
+
+ // external configurations
+ foreach($config->getExternalConfigurations() as $filePath=>$condition)
+ {
+ if($condition!==true)
+ $condition=$this->evaluateExpression($condition);
+ if($condition)
+ {
+ if(($path=Prado::getPathOfNamespace($filePath,$this->getConfigurationFileExt()))===null || !is_file($path))
+ throw new TConfigurationException('application_includefile_invalid',$filePath);
+ $cn=$this->getApplicationConfigurationClass();
+ $c=new $cn;
+ $c->loadFromFile($path);
+ $this->applyConfiguration($c,$withinService);
+ }
+ }
+ }
+
+ /**
+ * Loads configuration and initializes application.
+ * Configuration file will be read and parsed (if a valid cached version exists,
+ * it will be used instead). Then, modules are created and initialized;
+ * Afterwards, the requested service is created and initialized.
+ * @param string configuration file path (absolute or relative to current executing script)
+ * @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()
+ {
+ Prado::trace('Initializing application','System.TApplication');
+
+ if($this->_configFile!==null)
+ {
+ if($this->_cacheFile===null || @filemtime($this->_cacheFile)<filemtime($this->_configFile))
+ {
+ $config=new TApplicationConfiguration;
+ $config->loadFromFile($this->_configFile);
+ if($this->_cacheFile!==null)
+ file_put_contents($this->_cacheFile,serialize($config),LOCK_EX);
+ }
+ else
+ $config=unserialize(file_get_contents($this->_cacheFile));
+
+ $this->applyConfiguration($config,false);
+ }
+
+ if(($serviceID=$this->getRequest()->resolveRequest(array_keys($this->_services)))===null)
+ $serviceID=$this->getPageServiceID();
+
+ $this->startService($serviceID);
+ }
+
+ /**
+ * Starts the specified service.
+ * The service instance will be created. Its properties will be initialized
+ * and the configurations will be applied, if any.
+ * @param string service ID
+ */
+ public function startService($serviceID)
+ {
+ if(isset($this->_services[$serviceID]))
+ {
+ list($serviceClass,$initProperties,$configElement)=$this->_services[$serviceID];
+ $service=Prado::createComponent($serviceClass);
+ if(!($service instanceof IService))
+ throw new THttpException(500,'application_service_invalid',$serviceClass);
+ if(!$service->getEnabled())
+ throw new THttpException(500,'application_service_unavailable',$serviceClass);
+ $service->setID($serviceID);
+ $this->setService($service);
+
+ foreach($initProperties as $name=>$value)
+ $service->setSubProperty($name,$value);
+
+ if($configElement!==null)
+ {
+ $config=new TApplicationConfiguration;
+ if($this->getConfigurationType()==self::CONFIG_TYPE_PHP)
+ $config->loadFromPhp($configElement,$this->getBasePath());
+ else
+ $config->loadFromXml($configElement,$this->getBasePath());
+ $this->applyConfiguration($config,true);
+ }
+
+ $service->init($configElement);
+ }
+ else
+ throw new THttpException(500,'application_service_unknown',$serviceID);
+ }
+
+ /**
+ * Raises OnError event.
+ * This method is invoked when an exception is raised during the lifecycles
+ * of the application.
+ * @param mixed event parameter
+ */
+ public function onError($param)
+ {
+ Prado::log($param->getMessage(),TLogger::ERROR,'System.TApplication');
+ $this->raiseEvent('OnError',$this,$param);
+ $this->getErrorHandler()->handleError($this,$param);
+ }
+
+ /**
+ * Raises OnBeginRequest event.
+ * At the time when this method is invoked, application modules are loaded
+ * and initialized, user request is resolved and the corresponding service
+ * is loaded and initialized. The application is about to start processing
+ * the user request.
+ */
+ public function onBeginRequest()
+ {
+ $this->raiseEvent('OnBeginRequest',$this,null);
+ }
+
+ /**
+ * Raises OnAuthentication event.
+ * This method is invoked when the user request needs to be authenticated.
+ */
+ public function onAuthentication()
+ {
+ $this->raiseEvent('OnAuthentication',$this,null);
+ }
+
+ /**
+ * Raises OnAuthenticationComplete event.
+ * This method is invoked right after the user request is authenticated.
+ */
+ public function onAuthenticationComplete()
+ {
+ $this->raiseEvent('OnAuthenticationComplete',$this,null);
+ }
+
+ /**
+ * Raises OnAuthorization event.
+ * This method is invoked when the user request needs to be authorized.
+ */
+ public function onAuthorization()
+ {
+ $this->raiseEvent('OnAuthorization',$this,null);
+ }
+
+ /**
+ * Raises OnAuthorizationComplete event.
+ * This method is invoked right after the user request is authorized.
+ */
+ public function onAuthorizationComplete()
+ {
+ $this->raiseEvent('OnAuthorizationComplete',$this,null);
+ }
+
+ /**
+ * Raises OnLoadState event.
+ * This method is invoked when the application needs to load state (probably stored in session).
+ */
+ public function onLoadState()
+ {
+ $this->loadGlobals();
+ $this->raiseEvent('OnLoadState',$this,null);
+ }
+
+ /**
+ * Raises OnLoadStateComplete event.
+ * This method is invoked right after the application state has been loaded.
+ */
+ public function onLoadStateComplete()
+ {
+ $this->raiseEvent('OnLoadStateComplete',$this,null);
+ }
+
+ /**
+ * Raises OnPreRunService event.
+ * This method is invoked right before the service is to be run.
+ */
+ public function onPreRunService()
+ {
+ $this->raiseEvent('OnPreRunService',$this,null);
+ }
+
+ /**
+ * Runs the requested service.
+ */
+ public function runService()
+ {
+ if($this->_service)
+ $this->_service->run();
+ }
+
+ /**
+ * Raises OnSaveState event.
+ * This method is invoked when the application needs to save state (probably stored in session).
+ */
+ public function onSaveState()
+ {
+ $this->raiseEvent('OnSaveState',$this,null);
+ $this->saveGlobals();
+ }
+
+ /**
+ * Raises OnSaveStateComplete event.
+ * This method is invoked right after the application state has been saved.
+ */
+ public function onSaveStateComplete()
+ {
+ $this->raiseEvent('OnSaveStateComplete',$this,null);
+ }
+
+ /**
+ * Raises OnPreFlushOutput event.
+ * This method is invoked right before the application flushes output to client.
+ */
+ public function onPreFlushOutput()
+ {
+ $this->raiseEvent('OnPreFlushOutput',$this,null);
+ }
+
+ /**
+ * Flushes output to client side.
+ * @param boolean whether to continue buffering after flush if buffering was active
+ */
+ public function flushOutput($continueBuffering = true)
+ {
+ $this->getResponse()->flush($continueBuffering);
+ }
+
+ /**
+ * Raises OnEndRequest event.
+ * This method is invoked when the application completes the processing of the request.
+ */
+ public function onEndRequest()
+ {
+ $this->flushOutput(false); // flush all remaining content in the buffer
+ $this->saveGlobals(); // save global state
+ $this->raiseEvent('OnEndRequest',$this,null);
+ }
+}
+
+/**
+ * TApplicationMode class.
+ * TApplicationMode defines the possible mode that an application can be set at by
+ * setting {@link TApplication::setMode Mode}.
+ * In particular, the following modes are defined
+ * - Off: the application is not running. Any request to the application will obtain an error.
+ * - Debug: the application is running in debug mode.
+ * - Normal: the application is running in normal production mode.
+ * - Performance: the application is running in performance mode.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System
+ * @since 3.0.4
+ */
+class TApplicationMode extends TEnumerable
+{
+ const Off='Off';
+ const Debug='Debug';
+ const Normal='Normal';
+ const Performance='Performance';
+}
+
+
+/**
+ * TApplicationConfiguration class.
+ *
+ * This class is used internally by TApplication to parse and represent application configuration.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @author Carl G. Mathisen <carlgmathisen@gmail.com>
+ * @package System
+ * @since 3.0
+ */
+class TApplicationConfiguration extends TComponent
+{
+ /**
+ * @var array list of application initial property values, indexed by property names
+ */
+ private $_properties=array();
+ /**
+ * @var array list of namespaces to be used
+ */
+ private $_usings=array();
+ /**
+ * @var array list of path aliases, indexed by alias names
+ */
+ private $_aliases=array();
+ /**
+ * @var array list of module configurations
+ */
+ private $_modules=array();
+ /**
+ * @var array list of service configurations
+ */
+ private $_services=array();
+ /**
+ * @var array list of parameters
+ */
+ private $_parameters=array();
+ /**
+ * @var array list of included configurations
+ */
+ private $_includes=array();
+ /**
+ * @var boolean whether this configuration contains actual stuff
+ */
+ private $_empty=true;
+
+ /**
+ * Parses the application configuration file.
+ * @param string configuration file name
+ * @throws TConfigurationException if there is any parsing error
+ */
+ public function loadFromFile($fname)
+ {
+ if(Prado::getApplication()->getConfigurationType()==TApplication::CONFIG_TYPE_PHP)
+ {
+ $fcontent = include $fname;
+ $this->loadFromPhp($fcontent,dirname($fname));
+ }
+ else
+ {
+ $dom=new TXmlDocument;
+ $dom->loadFromFile($fname);
+ $this->loadFromXml($dom,dirname($fname));
+ }
+ }
+
+ /**
+ * @return boolean whether this configuration contains actual stuff
+ */
+ public function getIsEmpty()
+ {
+ return $this->_empty;
+ }
+
+ /**
+ * Parses the application configuration given in terms of a PHP array.
+ * @param array the PHP array
+ * @param string the context path (for specifying relative paths)
+ */
+ public function loadFromPhp($config, $configPath)
+ {
+ // application properties
+ if(isset($config['application']))
+ {
+ foreach($config['application'] as $name=>$value)
+ {
+ $this->_properties[$name]=$value;
+ }
+ $this->_empty = false;
+ }
+
+ if(isset($config['paths']) && is_array($config['paths']))
+ $this->loadPathsPhp($config['paths'],$configPath);
+
+ if(isset($config['modules']) && is_array($config['modules']))
+ $this->loadModulesPhp($config['modules'],$configPath);
+
+ if(isset($config['services']) && is_array($config['services']))
+ $this->loadServicesPhp($config['services'],$configPath);
+
+ if(isset($config['parameters']) && is_array($config['parameters']))
+ $this->loadParametersPhp($config['parameters'], $configPath);
+
+ if(isset($config['includes']) && is_array($config['includes']))
+ $this->loadExternalXml($config['includes'],$configPath);
+ }
+
+ /**
+ * Parses the application configuration given in terms of a TXmlElement.
+ * @param TXmlElement the XML element
+ * @param string the context path (for specifying relative paths)
+ */
+ public function loadFromXml($dom,$configPath)
+ {
+ // application properties
+ foreach($dom->getAttributes() as $name=>$value)
+ {
+ $this->_properties[$name]=$value;
+ $this->_empty=false;
+ }
+
+ foreach($dom->getElements() as $element)
+ {
+ switch($element->getTagName())
+ {
+ case 'paths':
+ $this->loadPathsXml($element,$configPath);
+ break;
+ case 'modules':
+ $this->loadModulesXml($element,$configPath);
+ break;
+ case 'services':
+ $this->loadServicesXml($element,$configPath);
+ break;
+ case 'parameters':
+ $this->loadParametersXml($element,$configPath);
+ break;
+ case 'include':
+ $this->loadExternalXml($element,$configPath);
+ break;
+ default:
+ //throw new TConfigurationException('appconfig_tag_invalid',$element->getTagName());
+ break;
+ }
+ }
+ }
+
+ /**
+ * Loads the paths PHP array
+ * @param array the paths PHP array
+ * @param string the context path (for specifying relative paths)
+ */
+ protected function loadPathsPhp($pathsNode, $configPath)
+ {
+ if(isset($pathsNode['aliases']) && is_array($pathsNode['aliases']))
+ {
+ foreach($pathsNode['aliases'] as $id=>$path)
+ {
+ $path=str_replace('\\','/',$path);
+ if(preg_match('/^\\/|.:\\/|.:\\\\/',$path)) // if absolute path
+ $p=realpath($path);
+ else
+ $p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
+ if($p===false || !is_dir($p))
+ throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
+ if(isset($this->_aliases[$id]))
+ throw new TConfigurationException('appconfig_alias_redefined',$id);
+ $this->_aliases[$id]=$p;
+ }
+ }
+
+ if(isset($pathsNode['using']) && is_array($pathsNode['using']))
+ {
+ foreach($pathsNode['using'] as $namespace)
+ {
+ $this->_usings[] = $namespace;
+ }
+ }
+ }
+
+ /**
+ * Loads the paths XML node.
+ * @param TXmlElement the paths XML node
+ * @param string the context path (for specifying relative paths)
+ */
+ protected function loadPathsXml($pathsNode,$configPath)
+ {
+ foreach($pathsNode->getElements() as $element)
+ {
+ switch($element->getTagName())
+ {
+ case 'alias':
+ {
+ if(($id=$element->getAttribute('id'))!==null && ($path=$element->getAttribute('path'))!==null)
+ {
+ $path=str_replace('\\','/',$path);
+ if(preg_match('/^\\/|.:\\/|.:\\\\/',$path)) // if absolute path
+ $p=realpath($path);
+ else
+ $p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
+ if($p===false || !is_dir($p))
+ throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
+ if(isset($this->_aliases[$id]))
+ throw new TConfigurationException('appconfig_alias_redefined',$id);
+ $this->_aliases[$id]=$p;
+ }
+ else
+ throw new TConfigurationException('appconfig_alias_invalid');
+ $this->_empty=false;
+ break;
+ }
+ case 'using':
+ {
+ if(($namespace=$element->getAttribute('namespace'))!==null)
+ $this->_usings[]=$namespace;
+ else
+ throw new TConfigurationException('appconfig_using_invalid');
+ $this->_empty=false;
+ break;
+ }
+ default:
+ throw new TConfigurationException('appconfig_paths_invalid',$element->getTagName());
+ }
+ }
+ }
+
+ /**
+ * Loads the modules PHP array.
+ * @param array the modules PHP array
+ * @param string the context path (for specifying relative paths)
+ */
+ protected function loadModulesPhp($modulesNode, $configPath)
+ {
+ foreach($modulesNode as $id=>$module)
+ {
+ if(!isset($module['class']))
+ throw new TConfigurationException('appconfig_moduletype_required',$id);
+ $type = $module['class'];
+ unset($module['class']);
+ $properties = array();
+ if(isset($module['properties']))
+ {
+ $properties = $module['properties'];
+ unset($module['properties']);
+ }
+ $properties['id'] = $id;
+ $this->_modules[$id]=array($type,$properties,$module);
+ $this->_empty=false;
+ }
+ }
+
+ /**
+ * Loads the modules XML node.
+ * @param TXmlElement the modules XML node
+ * @param string the context path (for specifying relative paths)
+ */
+ protected function loadModulesXml($modulesNode,$configPath)
+ {
+ foreach($modulesNode->getElements() as $element)
+ {
+ if($element->getTagName()==='module')
+ {
+ $properties=$element->getAttributes();
+ $id=$properties->itemAt('id');
+ $type=$properties->remove('class');
+ if($type===null)
+ throw new TConfigurationException('appconfig_moduletype_required',$id);
+ $element->setParent(null);
+ if($id===null)
+ $this->_modules[]=array($type,$properties->toArray(),$element);
+ else
+ $this->_modules[$id]=array($type,$properties->toArray(),$element);
+ $this->_empty=false;
+ }
+ else
+ throw new TConfigurationException('appconfig_modules_invalid',$element->getTagName());
+ }
+ }
+
+ /**
+ * Loads the services PHP array.
+ * @param array the services PHP array
+ * @param string the context path (for specifying relative paths)
+ */
+ protected function loadServicesPhp($servicesNode,$configPath)
+ {
+ foreach($servicesNode as $id => $service)
+ {
+ if(!isset($service['class']))
+ throw new TConfigurationException('appconfig_servicetype_required');
+ $type = $service['class'];
+ $properties = isset($service['properties']) ? $service['properties'] : array();
+ unset($service['properties']);
+ $properties['id'] = $id;
+ $this->_services[$id] = array($type,$properties,$service);
+ $this->_empty = false;
+ }
+ }
+
+ /**
+ * Loads the services XML node.
+ * @param TXmlElement the services XML node
+ * @param string the context path (for specifying relative paths)
+ */
+ protected function loadServicesXml($servicesNode,$configPath)
+ {
+ foreach($servicesNode->getElements() as $element)
+ {
+ if($element->getTagName()==='service')
+ {
+ $properties=$element->getAttributes();
+ if(($id=$properties->itemAt('id'))===null)
+ throw new TConfigurationException('appconfig_serviceid_required');
+ if(($type=$properties->remove('class'))===null)
+ throw new TConfigurationException('appconfig_servicetype_required',$id);
+ $element->setParent(null);
+ $this->_services[$id]=array($type,$properties->toArray(),$element);
+ $this->_empty=false;
+ }
+ else
+ throw new TConfigurationException('appconfig_services_invalid',$element->getTagName());
+ }
+ }
+
+ /**
+ * Loads the parameters PHP array.
+ * @param array the parameters PHP array
+ * @param string the context path (for specifying relative paths)
+ */
+ protected function loadParametersPhp($parametersNode,$configPath)
+ {
+ foreach($parametersNode as $id => $parameter)
+ {
+ if(is_array($parameter))
+ {
+ if(isset($parameter['class']))
+ {
+ $type = $parameter['class'];
+ unset($parameter['class']);
+ $properties = isset($service['properties']) ? $service['properties'] : array();
+ $properties['id'] = $id;
+ $this->_parameters[$id] = array($type,$properties);
+ }
+ }
+ else
+ {
+ $this->_parameters[$id] = $parameter;
+ }
+ }
+ }
+
+ /**
+ * Loads the parameters XML node.
+ * @param TXmlElement the parameters XML node
+ * @param string the context path (for specifying relative paths)
+ */
+ protected function loadParametersXml($parametersNode,$configPath)
+ {
+ foreach($parametersNode->getElements() as $element)
+ {
+ if($element->getTagName()==='parameter')
+ {
+ $properties=$element->getAttributes();
+ if(($id=$properties->remove('id'))===null)
+ throw new TConfigurationException('appconfig_parameterid_required');
+ if(($type=$properties->remove('class'))===null)
+ {
+ if(($value=$properties->remove('value'))===null)
+ $this->_parameters[$id]=$element;
+ else
+ $this->_parameters[$id]=$value;
+ }
+ else
+ $this->_parameters[$id]=array($type,$properties->toArray());
+ $this->_empty=false;
+ }
+ else
+ throw new TConfigurationException('appconfig_parameters_invalid',$element->getTagName());
+ }
+ }
+
+ /**
+ * Loads the external PHP array.
+ * @param array the application PHP array
+ * @param string the context path (for specifying relative paths)
+ */
+ protected function loadExternalPhp($includeNode,$configPath)
+ {
+ foreach($includeNode as $include)
+ {
+ $when = isset($include['when'])?true:false;
+ if(!isset($include['file']))
+ throw new TConfigurationException('appconfig_includefile_required');
+ $filePath = $include['file'];
+ if(isset($this->_includes[$filePath]))
+ $this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
+ else
+ $$this->_includes[$filePath]=$when;
+ $this->_empty=false;
+ }
+ }
+
+ /**
+ * Loads the external XML configurations.
+ * @param TXmlElement the application DOM element
+ * @param string the context path (for specifying relative paths)
+ */
+ protected function loadExternalXml($includeNode,$configPath)
+ {
+ if(($when=$includeNode->getAttribute('when'))===null)
+ $when=true;
+ if(($filePath=$includeNode->getAttribute('file'))===null)
+ throw new TConfigurationException('appconfig_includefile_required');
+ if(isset($this->_includes[$filePath]))
+ $this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
+ else
+ $this->_includes[$filePath]=$when;
+ $this->_empty=false;
+ }
+
+ /**
+ * Returns list of page initial property values.
+ * Each array element represents a single property with the key
+ * being the property name and the value the initial property value.
+ * @return array list of page initial property values
+ */
+ public function getProperties()
+ {
+ return $this->_properties;
+ }
+
+ /**
+ * Returns list of path alias definitions.
+ * The definitions are aggregated (top-down) from configuration files along the path
+ * to the specified page. Each array element represents a single alias definition,
+ * with the key being the alias name and the value the absolute path.
+ * @return array list of path alias definitions
+ */
+ public function getAliases()
+ {
+ return $this->_aliases;
+ }
+
+ /**
+ * Returns list of namespaces to be used.
+ * The namespaces are aggregated (top-down) from configuration files along the path
+ * to the specified page. Each array element represents a single namespace usage,
+ * with the value being the namespace to be used.
+ * @return array list of namespaces to be used
+ */
+ public function getUsings()
+ {
+ return $this->_usings;
+ }
+
+ /**
+ * Returns list of module configurations.
+ * The module configurations are aggregated (top-down) from configuration files
+ * along the path to the specified page. Each array element represents
+ * a single module configuration, with the key being the module ID and
+ * the value the module configuration. Each module configuration is
+ * stored in terms of an array with the following content
+ * ([0]=>module type, [1]=>module properties, [2]=>complete module configuration)
+ * The module properties are an array of property values indexed by property names.
+ * The complete module configuration is a TXmlElement object representing
+ * the raw module configuration which may contain contents enclosed within
+ * module tags.
+ * @return array list of module configurations to be used
+ */
+ public function getModules()
+ {
+ return $this->_modules;
+ }
+
+ /**
+ * @return array list of service configurations
+ */
+ public function getServices()
+ {
+ return $this->_services;
+ }
+
+ /**
+ * Returns list of parameter definitions.
+ * The parameter definitions are aggregated (top-down) from configuration files
+ * along the path to the specified page. Each array element represents
+ * a single parameter definition, with the key being the parameter ID and
+ * the value the parameter definition. A parameter definition can be either
+ * a string representing a string-typed parameter, or an array.
+ * The latter defines a component-typed parameter whose format is as follows,
+ * ([0]=>component type, [1]=>component properties)
+ * The component properties are an array of property values indexed by property names.
+ * @return array list of parameter definitions to be used
+ */
+ public function getParameters()
+ {
+ return $this->_parameters;
+ }
+
+ /**
+ * @return array list of external configuration files. Each element is like $filePath=>$condition
+ */
+ public function getExternalConfigurations()
+ {
+ return $this->_includes;
+ }
+}
+
+/**
+ * TApplicationStatePersister class.
+ * TApplicationStatePersister provides a file-based persistent storage
+ * for application state. Application state, when serialized, is stored
+ * in a file named 'global.cache' under the 'runtime' directory of the application.
+ * Cache will be exploited if it is enabled.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @package System
+ * @since 3.0
+ */
+class TApplicationStatePersister extends TModule implements IStatePersister
+{
+ /**
+ * Name of the value stored in cache
+ */
+ const CACHE_NAME='prado:appstate';
+
+ /**
+ * Initializes module.
+ * @param TXmlElement module configuration (may be null)
+ */
+ public function init($config)
+ {
+ $this->getApplication()->setApplicationStatePersister($this);
+ }
+
+ /**
+ * @return string the file path storing the application state
+ */
+ protected function getStateFilePath()
+ {
+ return $this->getApplication()->getRuntimePath().'/global.cache';
+ }
+
+ /**
+ * Loads application state from persistent storage.
+ * @return mixed application state
+ */
+ public function load()
+ {
+ if(($cache=$this->getApplication()->getCache())!==null && ($value=$cache->get(self::CACHE_NAME))!==false)
+ return unserialize($value);
+ else
+ {
+ if(($content=@file_get_contents($this->getStateFilePath()))!==false)
+ return unserialize($content);
+ else
+ return null;
+ }
+ }
+
+ /**
+ * Saves application state in persistent storage.
+ * @param mixed application state
+ */
+ public function save($state)
+ {
+ $content=serialize($state);
+ $saveFile=true;
+ if(($cache=$this->getApplication()->getCache())!==null)
+ {
+ if($cache->get(self::CACHE_NAME)===$content)
+ $saveFile=false;
+ else
+ $cache->set(self::CACHE_NAME,$content);
+ }
+ if($saveFile)
+ {
+ $fileName=$this->getStateFilePath();
+ file_put_contents($fileName,$content,LOCK_EX);
+ }
+ }
+
+}