+ * @version $Revision: $ $Date: $
+ * @package System
+ * @since 3.0
+ */
+class PradoBase
+{
+ /**
+ * File extension for Prado class files.
+ */
+ const CLASS_FILE_EXT='.php';
+ /**
+ * @var array list of path aliases
+ */
+ private static $_aliases=array('System'=>PRADO_DIR);
+ /**
+ * @var array list of namespaces currently in use
+ */
+ private static $_usings=array();
+ /**
+ * @var TApplication the application instance
+ */
+ private static $_application=null;
+ /**
+ * @var TLogger logger instance
+ */
+ private static $_logger=null;
+
+ /**
+ * @return string the version of Prado framework
+ */
+ public static function getVersion()
+ {
+ return '3.0RC1';
+ }
+
+ /**
+ * Initializes error handlers.
+ * This method set error and exception handlers to be functions
+ * defined in this class.
+ */
+ public static function initErrorHandlers()
+ {
+ /**
+ * Sets error handler to be Prado::phpErrorHandler
+ */
+ set_error_handler(array('PradoBase','phpErrorHandler'),error_reporting());
+ /**
+ * Sets exception handler to be Prado::exceptionHandler
+ */
+ set_exception_handler(array('PradoBase','exceptionHandler'));
+ }
+
+ /**
+ * Class autoload loader.
+ * This method is provided to be invoked within an __auload() magic method.
+ * @param string class name
+ */
+ public static function autoload($className)
+ {
+ include_once($className.self::CLASS_FILE_EXT);
+ if(!class_exists($className,false) && !interface_exists($className,false))
+ self::fatalError("Class file for '$className' cannot be found.");
+ }
+
+ /**
+ * @return string a string that can be displayed on your Web page showing powered-by-PRADO information
+ */
+ public static function poweredByPrado()
+ {
+ return '
';
+ }
+
+ /**
+ * PHP error handler.
+ * This method should be registered as PHP error handler using
+ * {@link set_error_handler}. The method throws an exception that
+ * contains the error information.
+ * @param integer the level of the error raised
+ * @param string the error message
+ * @param string the filename that the error was raised in
+ * @param integer the line number the error was raised at
+ */
+ public static function phpErrorHandler($errno,$errstr,$errfile,$errline)
+ {
+ if(error_reporting()!=0)
+ throw new TPhpErrorException($errno,$errstr,$errfile,$errline);
+ }
+
+ /**
+ * Default exception handler.
+ * This method should be registered as default exception handler using
+ * {@link set_exception_handler}. The method tries to use the errorhandler
+ * module of the Prado application to handle the exception.
+ * If the application or the module does not exist, it simply echoes the
+ * exception.
+ * @param Exception exception that is not caught
+ */
+ public static function exceptionHandler($exception)
+ {
+ if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null)
+ {
+ $errorHandler->handleError(null,$exception);
+ }
+ else
+ {
+ echo $exception;
+ }
+ exit(1);
+ }
+
+ /**
+ * Stores the application instance in the class static member.
+ * This method helps implement a singleton pattern for TApplication.
+ * Repeated invocation of this method or the application constructor
+ * will cause the throw of an exception.
+ * This method should only be used by framework developers.
+ * @param TApplication the application instance
+ * @throws TInvalidOperationException if this method is invoked twice or more.
+ */
+ public static function setApplication($application)
+ {
+ if(self::$_application!==null)
+ throw new TInvalidOperationException('prado_application_singleton_required');
+ self::$_application=$application;
+ }
+
+ /**
+ * @return TApplication the application singleton, null if the singleton has not be created yet.
+ */
+ public static function getApplication()
+ {
+ return self::$_application;
+ }
+
+ /**
+ * @return string the path of the framework
+ */
+ public static function getFrameworkPath()
+ {
+ return PRADO_DIR;
+ }
+
+ /**
+ * Serializes a data.
+ * The original PHP serialize function has a bug that may not serialize
+ * properly an object.
+ * @param mixed data to be serialized
+ * @return string the serialized data
+ */
+ public static function serialize($data)
+ {
+ $arr[0]=$data;
+ return serialize($arr);
+ }
+
+ /**
+ * Unserializes a data.
+ * The original PHP unserialize function has a bug that may not unserialize
+ * properly an object.
+ * @param string data to be unserialized
+ * @return mixed unserialized data, null if unserialize failed
+ */
+ public static function unserialize($str)
+ {
+ $arr=unserialize($str);
+ return isset($arr[0])?$arr[0]:null;
+ }
+
+ /**
+ * Creates a component with the specified type.
+ * A component type can be either the component class name
+ * or a namespace referring to the path of the component class file.
+ * For example, 'TButton', 'System.Web.UI.WebControls.TButton' are both
+ * valid component type.
+ * This method can also pass parameters to component constructors.
+ * All paramters passed to this method except the first one (the component type)
+ * will be supplied as component constructor paramters.
+ * @param string component type
+ * @return TComponent component instance of the specified type
+ * @throws TInvalidDataValueException if the component type is unknown
+ */
+ public static function createComponent($type)
+ {
+ self::using($type);
+ if(($pos=strrpos($type,'.'))!==false)
+ $type=substr($type,$pos+1);
+ if(($n=func_num_args())>1)
+ {
+ $args=func_get_args();
+ $s='$args[1]';
+ for($i=2;$i<$n;++$i)
+ $s.=",\$args[$i]";
+ eval("\$component=new $type($s);");
+ return $component;
+ }
+ else
+ return new $type;
+ }
+
+ /**
+ * Uses a namespace.
+ * A namespace ending with an asterisk '*' refers to a directory, otherwise it represents a PHP file.
+ * If the namespace corresponds to a directory, the directory will be appended
+ * to the include path. If the namespace corresponds to a file, it will be included (include_once).
+ * @param string namespace to be used
+ * @throws TInvalidDataValueException if the namespace is invalid
+ */
+ public static function using($namespace)
+ {
+ if(isset(self::$_usings[$namespace]) || class_exists($namespace,false))
+ return;
+ if(($pos=strrpos($namespace,'.'))===false) // a class name
+ {
+ try
+ {
+ include_once($namespace.self::CLASS_FILE_EXT);
+ }
+ catch(Exception $e)
+ {
+ if(!class_exists($namespace,false))
+ throw new TInvalidOperationException('prado_component_unknown',$namespace);
+ else
+ throw $e;
+ }
+ }
+ else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null)
+ {
+ $className=substr($namespace,$pos+1);
+ if($className==='*') // a directory
+ {
+ if(is_dir($path))
+ {
+ self::$_usings[$namespace]=$path;
+ set_include_path(get_include_path().PATH_SEPARATOR.$path);
+ }
+ else
+ throw new TInvalidDataValueException('prado_using_invalid',$namespace);
+ }
+ else // a file
+ {
+ if(is_file($path))
+ {
+ self::$_usings[$namespace]=$path;
+ if(!class_exists($className,false))
+ {
+ try
+ {
+ include_once($path);
+ }
+ catch(Exception $e)
+ {
+ if(!class_exists($className,false))
+ throw new TInvalidOperationException('prado_component_unknown',$className);
+ else
+ throw $e;
+ }
+ }
+ }
+ else
+ throw new TInvalidDataValueException('prado_using_invalid',$namespace);
+ }
+ }
+ else
+ throw new TInvalidDataValueException('prado_using_invalid',$namespace);
+ }
+
+ /**
+ * Translates a namespace into a file path.
+ * The first segment of the namespace is considered as a path alias
+ * which is replaced with the actual path. The rest segments are
+ * subdirectory names appended to the aliased path.
+ * If the namespace ends with an asterisk '*', it represents a directory;
+ * Otherwise it represents a file whose extension name is specified by the second parameter (defaults to empty).
+ * Note, this method does not ensure the existence of the resulting file path.
+ * @param string namespace
+ * @param string extension to be appended if the namespace refers to a file
+ * @return string file path corresponding to the namespace, null if namespace is invalid
+ */
+ public static function getPathOfNamespace($namespace,$ext='')
+ {
+ if(isset(self::$_usings[$namespace]))
+ return self::$_usings[$namespace];
+ else if(isset(self::$_aliases[$namespace]))
+ return self::$_aliases[$namespace];
+ else
+ {
+ $segs=explode('.',$namespace);
+ $alias=array_shift($segs);
+ if(($file=array_pop($segs))!==null && ($root=self::getPathOfAlias($alias))!==null)
+ return rtrim($root.'/'.implode('/',$segs),'/').(($file==='*')?'':'/'.$file.$ext);
+ else
+ return null;
+ }
+ }
+
+ /**
+ * @param string alias to the path
+ * @return string the path corresponding to the alias, null if alias not defined.
+ */
+ public static function getPathOfAlias($alias)
+ {
+ return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null;
+ }
+
+ /**
+ * @param string alias to the path
+ * @param string the path corresponding to the alias
+ * @throws TInvalidOperationException if the alias is already defined
+ * @throws TInvalidDataValueException if the path is not a valid file path
+ */
+ public static function setPathOfAlias($alias,$path)
+ {
+ if(isset(self::$_aliases[$alias]))
+ throw new TInvalidOperationException('prado_alias_redefined',$alias);
+ else if(($rp=realpath($path))!==false && is_dir($rp))
+ {
+ if(strpos($alias,'.')===false)
+ self::$_aliases[$alias]=$rp;
+ else
+ throw new TInvalidDataValueException('prado_aliasname_invalid',$alias);
+ }
+ else
+ throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path);
+ }
+
+ /**
+ * Fatal error handler.
+ * This method displays an error message together with the current call stack.
+ * The application will exit after calling this method.
+ * @param string error message
+ */
+ public static function fatalError($msg)
+ {
+ echo 'Fatal Error
';
+ echo ''.$msg.'
';
+ if(!function_exists('debug_backtrace'))
+ return;
+ echo 'Debug Backtrace
';
+ echo '';
+ $index=-1;
+ foreach(debug_backtrace() as $t)
+ {
+ $index++;
+ if($index==0) // hide the backtrace of this function
+ continue;
+ echo '#'.$index.' ';
+ if(isset($t['file']))
+ echo basename($t['file']) . ':' . $t['line'];
+ else
+ echo '';
+ echo ' -- ';
+ if(isset($t['class']))
+ echo $t['class'] . $t['type'];
+ echo $t['function'];
+ if(isset($t['args']) && sizeof($t['args']) > 0)
+ echo '(...)';
+ else
+ echo '()';
+ echo "\n";
+ }
+ echo '
';
+ exit(1);
+ }
+
+ /**
+ * Returns a list of user preferred languages.
+ * The languages are returned as an array. Each array element
+ * represents a single language preference. The languages are ordered
+ * according to user preferences. The first language is the most preferred.
+ * @return array list of user preferred languages.
+ */
+ public static function getUserLanguages()
+ {
+ static $languages=null;
+ if($languages===null)
+ {
+ if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
+ $languages[0]='en';
+ else
+ {
+ $languages=array();
+ foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language)
+ {
+ $array=split(';q=',trim($language));
+ $languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0;
+ }
+ arsort($languages);
+ $languages=array_keys($languages);
+ if(empty($languages))
+ $languages[0]='en';
+ }
+ }
+ return $languages;
+ }
+
+ /**
+ * Returns the most preferred language by the client user.
+ * @return string the most preferred language by the client user, defaults to English.
+ */
+ public static function getPreferredLanguage()
+ {
+ static $language=null;
+ if($language===null)
+ {
+ $langs=Prado::getUserLanguages();
+ $lang=explode('-',$langs[0]);
+ if(empty($lang[0]) || !ctype_alpha($lang[0]))
+ $language='en';
+ else
+ $language=$lang[0];
+ }
+ return $language;
+ }
+
+ /**
+ * Writes a log message.
+ * This method wraps {@link log()} by checking the application mode.
+ * When the application is in Debug mode, debug backtrace information is appended
+ * to the message and the message is logged at DEBUG level.
+ * When the application is in Performance mode, this method does nothing.
+ * Otherwise, the message is logged at INFO level.
+ * @param string message to be logged
+ * @param string category of the message
+ * @see log, getLogger
+ */
+ public static function trace($msg,$category='Uncategorized')
+ {
+ if(self::$_application && self::$_application->getMode()===TApplication::STATE_PERFORMANCE)
+ return;
+ if(!self::$_application || self::$_application->getMode()===TApplication::STATE_DEBUG)
+ {
+ $trace=debug_backtrace();
+ if(isset($trace[0]['file']) && isset($trace[0]['line']))
+ $msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})";
+ $level=TLogger::DEBUG;
+ }
+ else
+ $level=TLogger::INFO;
+ self::log($msg,$level,$category);
+ }
+
+ /**
+ * Logs a message.
+ * Messages logged by this method may be retrieved via {@link TLogger::getLogs}
+ * and may be recorded in different media, such as file, email, database, using
+ * {@link TLogRouter}.
+ * @param string message to be logged
+ * @param integer level of the message. Valid values include
+ * TLogger::DEBUG, TLogger::INFO, TLogger::NOTICE, TLogger::WARNING,
+ * TLogger::ERROR, TLogger::ALERT, TLogger::FATAL.
+ * @param string category of the message
+ */
+ public static function log($msg,$level=TLogger::INFO,$category='Uncategorized')
+ {
+ if(self::$_logger===null)
+ self::$_logger=new TLogger;
+ self::$_logger->log($msg,$level,$category);
+ }
+
+ /**
+ * @return TLogger message logger
+ */
+ public static function getLogger()
+ {
+ if(self::$_logger===null)
+ self::$_logger=new TLogger;
+ return self::$_logger;
+ }
+
+ /**
+ * Converts a variable into a string representation.
+ * This method achieves the similar functionality as var_dump and print_r
+ * but is more robust when handling complex objects such as PRADO controls.
+ * @param mixed variable to be dumped
+ * @param integer maximum depth that the dumper should go into the variable. Defaults to 10.
+ * @return string the string representation of the variable
+ */
+ public static function varDump($var,$depth=10)
+ {
+ require_once(PRADO_DIR.'/Util/TVarDumper.php');
+ return TVarDumper::dump($var,$depth);
+ }
+}
+
+
+if(version_compare(phpversion(),'5.1.0','>='))
+{
+ /**
+ * TReflectionClass class.
+ * This class is written to cope with the incompatibility between different PHP versions.
+ * It is equivalent to ReflectionClass if PHP version >= 5.1.0
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System
+ * @since 3.0
+ */
+ class TReflectionClass extends ReflectionClass
+ {
+ }
+}
+else // PHP < 5.1.0
+{
+ /**
+ * TReflectionClass class.
+ * This class is written to cope with the incompatibility between different PHP versions.
+ * It mainly provides a way to detect if a method exists for a given class name.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System
+ * @since 3.0
+ */
+ class TReflectionClass extends ReflectionClass
+ {
+ /**
+ * @param string method name
+ * @return boolean whether the method exists
+ */
+ public function hasMethod($method)
+ {
+ try
+ {
+ return $this->getMethod($method)!==null;
+ }
+ catch(Exception $e)
+ {
+ return false;
+ }
+ }
+
+ /**
+ * @param string property name
+ * @return boolean whether the property exists
+ */
+ public function hasProperty($property)
+ {
+ try
+ {
+ return $this->getProperty($property)!==null;
+ }
+ catch(Exception $e)
+ {
+ return false;
+ }
+ }
+ }
+
+ if(!function_exists('property_exists'))
+ {
+ /**
+ * Detects whether an object contains the specified member variable.
+ * @param object
+ * @param string member variable (property) name
+ * @return boolean
+ */
+ function property_exists($object, $property)
+ {
+ if(is_object($object))
+ return array_key_exists($property, get_object_vars($object));
+ else
+ return false;
+ }
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/framework/TApplication.php b/framework/TApplication.php
index b94a4e53..9d8db867 100644
--- a/framework/TApplication.php
+++ b/framework/TApplication.php
@@ -11,36 +11,30 @@
*/
/**
- * Includes TErrorHandler class
+ * Includes core interfaces essential for TApplication class
*/
-require_once(PRADO_DIR.'/Exceptions/TErrorHandler.php');
+require_once(PRADO_DIR.'/interfaces.php');
+
/**
- * Includes THttpRequest class
+ * Includes core classes essential for TApplication class
*/
+require_once(PRADO_DIR.'/TApplicationComponent.php');
+require_once(PRADO_DIR.'/TModule.php');
+require_once(PRADO_DIR.'/TService.php');
+require_once(PRADO_DIR.'/Exceptions/TErrorHandler.php');
+require_once(PRADO_DIR.'/Caching/TCache.php');
+require_once(PRADO_DIR.'/IO/TTextWriter.php');
+require_once(PRADO_DIR.'/Collections/TList.php');
+require_once(PRADO_DIR.'/Collections/TMap.php');
+require_once(PRADO_DIR.'/Xml/TXmlDocument.php');
+require_once(PRADO_DIR.'/Security/TAuthorizationRule.php');
+require_once(PRADO_DIR.'/Security/TSecurityManager.php');
+require_once(PRADO_DIR.'/Web/THttpUtility.php');
+require_once(PRADO_DIR.'/Web/Javascripts/TJavaScript.php');
require_once(PRADO_DIR.'/Web/THttpRequest.php');
-/**
- * Includes THttpResponse class
- */
require_once(PRADO_DIR.'/Web/THttpResponse.php');
-/**
- * Includes THttpSession class
- */
require_once(PRADO_DIR.'/Web/THttpSession.php');
-/**
- * Includes TAuthorizationRule class
- */
-require_once(PRADO_DIR.'/Security/TAuthorizationRule.php');
-/**
- * Includes TSecurityManager class
- */
-require_once(PRADO_DIR.'/Security/TSecurityManager.php');
-/**
- * Includes TPageService class (default service)
- */
require_once(PRADO_DIR.'/Web/Services/TPageService.php');
-/**
- * Includes TAssetManager class
- */
require_once(PRADO_DIR.'/Web/TAssetManager.php');
diff --git a/framework/TModule.php b/framework/TModule.php
new file mode 100644
index 00000000..ad68ca9f
--- /dev/null
+++ b/framework/TModule.php
@@ -0,0 +1,57 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $Date: $
+ * @package System
+ */
+
+/**
+ * TModule class.
+ *
+ * TModule implements the basic methods required by IModule and may be
+ * used as the basic class for application modules.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System
+ * @since 3.0
+ */
+abstract class TModule extends TApplicationComponent implements IModule
+{
+ /**
+ * @var string module id
+ */
+ private $_id;
+
+ /**
+ * Initializes the module.
+ * This method is required by IModule and is invoked by application.
+ * @param TXmlElement module configuration
+ */
+ public function init($config)
+ {
+ }
+
+ /**
+ * @return string id of this module
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * @param string id of this module
+ */
+ public function setID($value)
+ {
+ $this->_id=$value;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/framework/TService.php b/framework/TService.php
new file mode 100644
index 00000000..f4a6244d
--- /dev/null
+++ b/framework/TService.php
@@ -0,0 +1,64 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $Date: $
+ * @package System
+ */
+
+/**
+ * TService class.
+ *
+ * TService implements the basic methods required by IService and may be
+ * used as the basic class for application services.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System
+ * @since 3.0
+ */
+abstract class TService extends TApplicationComponent implements IService
+{
+ /**
+ * @var string service id
+ */
+ private $_id;
+
+ /**
+ * Initializes the service and attaches {@link run} to the RunService event of application.
+ * This method is required by IService and is invoked by application.
+ * @param TXmlElement module configuration
+ */
+ public function init($config)
+ {
+ }
+
+ /**
+ * @return string id of this service
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * @param string id of this service
+ */
+ public function setID($value)
+ {
+ $this->_id=$value;
+ }
+
+ /**
+ * Runs the service.
+ */
+ public function run()
+ {
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/framework/Util/TDataFieldAccessor.php b/framework/Util/TDataFieldAccessor.php
new file mode 100644
index 00000000..09512a28
--- /dev/null
+++ b/framework/Util/TDataFieldAccessor.php
@@ -0,0 +1,117 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $Date: $
+ * @package System.Util
+ */
+
+/**
+ * TDataFieldAccessor class
+ *
+ * TDataFieldAccessor is a utility class that provides access to a field of some data.
+ * The accessor attempts to obtain the field value in the following order:
+ * - If the data is an array, then the field is treated as an array index
+ * and the corresponding element value is returned;
+ * - If the data is a TMap or TList object, then the field is treated as a key
+ * into the map or list, and the corresponding value is returned.
+ * - If the data is an object, the field is treated as a property or subproperty
+ * defined with getter methods. For example, if the object has a method called
+ * getMyValue(), then field 'MyValue' will retrive the result of this method call.
+ * If getMyValue() returns an object which contains a method getMySubValue(),
+ * then field 'MyValue.MySubValue' will return that method call result.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System.Util
+ * @since 3.0
+ */
+class TDataFieldAccessor
+{
+ /**
+ * Evaluates the data value at the specified field.
+ * - If the data is an array, then the field is treated as an array index
+ * and the corresponding element value is returned;
+ * - If the data is a TMap or TList object, then the field is treated as a key
+ * into the map or list, and the corresponding value is returned.
+ * - If the data is an object, the field is treated as a property or subproperty
+ * defined with getter methods. For example, if the object has a method called
+ * getMyValue(), then field 'MyValue' will retrive the result of this method call.
+ * If getMyValue() returns an object which contains a method getMySubValue(),
+ * then field 'MyValue.MySubValue' will return that method call result.
+ * @param mixed data containing the field value, can be an array, TMap, TList or object.
+ * @param mixed field value
+ * @return mixed value at the specified field
+ * @throw TInvalidDataValueException if field or data is invalid
+ */
+ public static function getDataFieldValue($data,$field)
+ {
+ if(Prado::getApplication()->getMode()===TApplication::STATE_PERFORMANCE)
+ {
+ if(is_array($data) || ($data instanceof ArrayAccess))
+ return $data[$field];
+ else if(is_object($data))
+ {
+ if(strpos($field,'.')===false) // simple field
+ {
+ if(property_exists($data,$field))
+ return $data->{$field};
+ else
+ return call_user_func(array($data,'get'.$field));
+ }
+ else // field in the format of xxx.yyy.zzz
+ {
+ $object=$data;
+ foreach(explode('.',$field) as $f)
+ $object=call_user_func(array($object,'get'.$f));
+ return $object;
+ }
+ }
+ else
+ throw new TInvalidDataValueException('datafieldaccessor_data_invalid',$field);
+ }
+ else
+ {
+ if(is_array($data) || ($data instanceof ArrayAccess))
+ {
+ if(isset($data[$field]) || $data[$field]===null)
+ return $data[$field];
+ else
+ throw new TInvalidDataValueException('datafieldaccessor_datafield_invalid',$field);
+ }
+ else if(is_object($data))
+ {
+ if(strpos($field,'.')===false) // simple field
+ {
+ if(property_exists($data,$field))
+ return $data->{$field};
+ else if(is_callable(array($data,'get'.$field)))
+ return call_user_func(array($data,'get'.$field));
+ else
+ throw new TInvalidDataValueException('datafieldaccessor_datafield_invalid',$field);
+ }
+ else // field in the format of xxx.yyy.zzz
+ {
+ $object=$data;
+ foreach(explode('.',$field) as $f)
+ {
+ $getter='get'.$f;
+ if(is_callable(array($object,$getter)))
+ $object=call_user_func(array($object,$getter));
+ else
+ throw new TInvalidDataValueException('datafieldaccessor_datafield_invalid',$field);
+ }
+ return $object;
+ }
+ }
+ else
+ throw new TInvalidDataValueException('datafieldaccessor_data_invalid',$field);
+ }
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/framework/Util/TLogRouter.php b/framework/Util/TLogRouter.php
new file mode 100644
index 00000000..bdad8649
--- /dev/null
+++ b/framework/Util/TLogRouter.php
@@ -0,0 +1,666 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $Date: $
+ * @package System.Util
+ */
+
+/**
+ * TLogRouter class.
+ *
+ * TLogRouter manages routes that record log messages in different media different ways.
+ * For example, a file log route {@link TFileLogRoute} records log messages
+ * in log files. An email log route {@link TEmailLogRoute} sends log messages
+ * to email addresses.
+ *
+ * Log routes may be configured in application or page folder configuration files
+ * or an external configuration file specified by {@link setConfigFile ConfigFile}.
+ * The format is as follows,
+ *
+ * <route class="TFileLogRoute" Categories="System.Web.UI" Levels="Warning" />
+ * <route class="TEmailLogRoute" Categories="Application" Levels="Fatal" Emails="admin@pradosoft.com" />
+ *
+ * You can specify multiple routes with different filtering conditions and different
+ * targets, even if the routes are of the same type.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System.Util
+ * @since 3.0
+ */
+class TLogRouter extends TModule
+{
+ /**
+ * File extension of external configuration file
+ */
+ const CONFIG_FILE_EXT='.xml';
+ /**
+ * @var array list of routes available
+ */
+ private $_routes=array();
+ /**
+ * @var string external configuration file
+ */
+ private $_configFile=null;
+
+ /**
+ * Initializes this module.
+ * This method is required by the IModule interface.
+ * @param TXmlElement configuration for this module, can be null
+ * @throws TConfigurationException if {@link getConfigFile ConfigFile} is invalid.
+ */
+ public function init($config)
+ {
+ if($this->_configFile!==null)
+ {
+ if(is_file($this->_configFile))
+ {
+ $dom=new TXmlDocument;
+ $dom->loadFromFile($this->_configFile);
+ $this->loadConfig($dom);
+ }
+ else
+ throw new TConfigurationException('logrouter_configfile_invalid',$this->_configFile);
+ }
+ $this->loadConfig($config);
+ $this->getApplication()->attachEventHandler('OnEndRequest',array($this,'collectLogs'));
+ }
+
+ /**
+ * Loads configuration from an XML element
+ * @param TXmlElement configuration node
+ * @throws TConfigurationException if log route class or type is not specified
+ */
+ private function loadConfig($xml)
+ {
+ foreach($xml->getElementsByTagName('route') as $routeConfig)
+ {
+ $properties=$routeConfig->getAttributes();
+ if(($class=$properties->remove('class'))===null)
+ throw new TConfigurationException('logrouter_routeclass_required');
+ $route=Prado::createComponent($class);
+ if(!($route instanceof TLogRoute))
+ throw new TConfigurationException('logrouter_routetype_invalid');
+ foreach($properties as $name=>$value)
+ $route->setSubproperty($name,$value);
+ $this->_routes[]=$route;
+ $route->init($routeConfig);
+ }
+ }
+
+ /**
+ * @return string external configuration file. Defaults to null.
+ */
+ public function getConfigFile()
+ {
+ return $this->_configFile;
+ }
+
+ /**
+ * @param string external configuration file in namespace format. The file
+ * must be suffixed with '.xml'.
+ * @throws TInvalidDataValueException if the file is invalid.
+ */
+ public function setConfigFile($value)
+ {
+ if(($this->_configFile=Prado::getPathOfNamespace($value,self::LOG_FILE_EXT))===null)
+ throw new TConfigurationException('logrouter_configfile_invalid',$value);
+ }
+
+ /**
+ * Collects log messages from a logger.
+ * This method is an event handler to application's EndRequest event.
+ * @param mixed event parameter
+ */
+ public function collectLogs($param)
+ {
+ $logger=Prado::getLogger();
+ foreach($this->_routes as $route)
+ $route->collectLogs($logger);
+ }
+}
+
+/**
+ * TLogRoute class.
+ *
+ * TLogRoute is the base class for all log route classes.
+ * A log route object retrieves log messages from a logger and sends it
+ * somewhere, such as files, emails.
+ * The messages being retrieved may be filtered first before being sent
+ * to the destination. The filters include log level filter and log category filter.
+ *
+ * To specify level filter, set {@link setLevels Levels} property,
+ * which takes a string of comma-separated desired level names (e.g. 'Error, Debug').
+ * To specify category filter, set {@link setCategories Categories} property,
+ * which takes a string of comma-separated desired category names (e.g. 'System.Web, System.IO').
+ *
+ * Level filter and category filter are combinational, i.e., only messages
+ * satisfying both filter conditions will they be returned.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System.Util
+ * @since 3.0
+ */
+abstract class TLogRoute extends TApplicationComponent
+{
+ /**
+ * @var array lookup table for level names
+ */
+ protected static $_levelNames=array(
+ TLogger::DEBUG=>'Debug',
+ TLogger::INFO=>'Info',
+ TLogger::NOTICE=>'Notice',
+ TLogger::WARNING=>'Warning',
+ TLogger::ERROR=>'Error',
+ TLogger::ALERT=>'Alert',
+ TLogger::FATAL=>'Fatal'
+ );
+ /**
+ * @var array lookup table for level values
+ */
+ protected static $_levelValues=array(
+ 'debug'=>TLogger::DEBUG,
+ 'info'=>TLogger::INFO,
+ 'notice'=>TLogger::NOTICE,
+ 'warning'=>TLogger::WARNING,
+ 'error'=>TLogger::ERROR,
+ 'alert'=>TLogger::ALERT,
+ 'fatal'=>TLogger::FATAL
+ );
+ /**
+ * @var integer log level filter (bits)
+ */
+ private $_levels=null;
+ /**
+ * @var array log category filter
+ */
+ private $_categories=null;
+
+ /**
+ * Initializes the route.
+ * @param TXmlElement configurations specified in {@link TLogRouter}.
+ */
+ public function init($config)
+ {
+ }
+
+ /**
+ * @return integer log level filter
+ */
+ public function getLevels()
+ {
+ return $this->_levels;
+ }
+
+ /**
+ * @param integer|string integer log level filter (in bits). If the value is
+ * a string, it is assumed to be comma-separated level names. Valid level names
+ * include 'Debug', 'Info', 'Notice', 'Warning', 'Error', 'Alert' and 'Fatal'.
+ */
+ public function setLevels($levels)
+ {
+ if(is_integer($levels))
+ $this->_levels=$levels;
+ else
+ {
+ $this->_levels=null;
+ $levels=strtolower($levels);
+ foreach(explode(',',$levels) as $level)
+ {
+ $level=trim($level);
+ if(isset(self::$_levelValues[$level]))
+ $this->_levels|=self::$_levelValues[$level];
+ }
+ }
+ }
+
+ /**
+ * @return array list of categories to be looked for
+ */
+ public function getCategories()
+ {
+ return $this->_categories;
+ }
+
+ /**
+ * @param array|string list of categories to be looked for. If the value is a string,
+ * it is assumed to be comma-separated category names.
+ */
+ public function setCategories($categories)
+ {
+ if(is_array($categories))
+ $this->_categories=$categories;
+ else
+ {
+ $this->_categories=null;
+ foreach(explode(',',$categories) as $category)
+ {
+ if(($category=trim($category))!=='')
+ $this->_categories[]=$category;
+ }
+ }
+ }
+
+ /**
+ * @param integer level value
+ * @return string level name
+ */
+ protected function getLevelName($level)
+ {
+ return isset(self::$_levelNames[$level])?self::$_levelNames[$level]:'Unknown';
+ }
+
+ /**
+ * @param string level name
+ * @return integer level value
+ */
+ protected function getLevelValue($level)
+ {
+ return isset(self::$_levelValues[$level])?self::$_levelValues[$level]:0;
+ }
+
+ /**
+ * Formats a log message given different fields.
+ * @param string message content
+ * @param integer message level
+ * @param string message category
+ * @param integer timestamp
+ * @return string formatted message
+ */
+ protected function formatLogMessage($message,$level,$category,$time)
+ {
+ return @date('M d H:i:s',$time).' ['.$this->getLevelName($level).'] ['.$category.'] '.$message."\n";
+ }
+
+ /**
+ * Retrieves log messages from logger to log route specific destination.
+ * @param TLogger logger instance
+ */
+ public function collectLogs(TLogger $logger)
+ {
+ $logs=$logger->getLogs($this->getLevels(),$this->getCategories());
+ if(!empty($logs))
+ $this->processLogs($logs);
+ }
+
+ /**
+ * Processes log messages and sends them to specific destination.
+ * Derived child classes must implement this method.
+ * @param array list of messages. Each array element is a (formatted) message string.
+ */
+ abstract protected function processLogs($logs);
+}
+
+/**
+ * TFileLogRoute class.
+ *
+ * TFileLogRoute records log messages in files.
+ * The log files are stored under {@link setLogPath LogPath} and the file name
+ * is specified by {@link setLogFile LogFile}. If the size of the log file is
+ * greater than {@link setMaxFileSize MaxFileSize} (in kilo-bytes), a rotation
+ * is performed, which renames the current log file by suffixing the file name
+ * with '.1'. All existing log files are moved backwards one place, i.e., '.2'
+ * to '.3', '.1' to '.2'. The property {@link setMaxLogFiles MaxLogFiles}
+ * specifies how many files to be kept.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System.Util
+ * @since 3.0
+ */
+class TFileLogRoute extends TLogRoute
+{
+ /**
+ * @var integer maximum log file size
+ */
+ private $_maxFileSize=512; // in KB
+ /**
+ * @var integer number of log files used for rotation
+ */
+ private $_maxLogFiles=2;
+ /**
+ * @var string directory storing log files
+ */
+ private $_logPath=null;
+ /**
+ * @var string log file name
+ */
+ private $_logFile='prado.log';
+
+ /**
+ * @return string directory storing log files. Defaults to application runtime path.
+ */
+ public function getLogPath()
+ {
+ if($this->_logPath===null)
+ $this->_logPath=$this->getApplication()->getRuntimePath();
+ return $this->_logPath;
+ }
+
+ /**
+ * @param string directory (in namespace format) storing log files.
+ * @throws TConfigurationException if log path is invalid
+ */
+ public function setLogPath($value)
+ {
+ if(($this->_logPath=Prado::getPathOfNamespace($value))===null || !is_dir($this->_logPath) || !is_writable($this->_logPath))
+ throw new TConfigurationException('filelogroute_logpath_invalid',$value);
+ }
+
+ /**
+ * @return string log file name. Defaults to 'prado.log'.
+ */
+ public function getLogFile()
+ {
+ return $this->_logFile;
+ }
+
+ /**
+ * @param string log file name
+ */
+ public function setLogFile($value)
+ {
+ $this->_logFile=$value;
+ }
+
+ /**
+ * @return integer maximum log file size in kilo-bytes (KB). Defaults to 1024 (1MB).
+ */
+ public function getMaxFileSize()
+ {
+ return $this->_maxFileSize;
+ }
+
+ /**
+ * @param integer maximum log file size in kilo-bytes (KB).
+ * @throws TInvalidDataValueException if the value is smaller than 1.
+ */
+ public function setMaxFileSize($value)
+ {
+ $this->_maxFileSize=TPropertyValue::ensureInteger($value);
+ if($this->_maxFileSize<=0)
+ throw new TInvalidDataValueException('filelogroute_maxfilesize_invalid');
+ }
+
+ /**
+ * @return integer number of files used for rotation. Defaults to 2.
+ */
+ public function getMaxLogFiles()
+ {
+ return $this->_maxLogFiles;
+ }
+
+ /**
+ * @param integer number of files used for rotation.
+ */
+ public function setMaxLogFiles($value)
+ {
+ $this->_maxLogFiles=TPropertyValue::ensureInteger($value);
+ if($this->_maxLogFiles<1)
+ throw new TInvalidDataValueException('filelogroute_maxlogfiles_invalid');
+ }
+
+ /**
+ * Saves log messages in files.
+ * @param array list of log messages
+ */
+ protected function processLogs($logs)
+ {
+ $logFile=$this->getLogPath().'/'.$this->getLogFile();
+ if(@filesize($logFile)>$this->_maxFileSize*1024)
+ $this->rotateFiles();
+ foreach($logs as $log)
+ error_log($this->formatLogMessage($log[0],$log[1],$log[2],$log[3]),3,$logFile);
+ }
+
+ /**
+ * Rotates log files.
+ */
+ protected function rotateFiles()
+ {
+ $file=$this->getLogPath().'/'.$this->getLogFile();
+ for($i=$this->_maxLogFiles;$i>0;--$i)
+ {
+ $rotateFile=$file.'.'.$i;
+ if(is_file($rotateFile))
+ {
+ if($i===$this->_maxLogFiles)
+ unlink($rotateFile);
+ else
+ rename($rotateFile,$file.'.'.($i+1));
+ }
+ }
+ if(is_file($file))
+ rename($file,$file.'.1');
+ }
+}
+
+/**
+ * TEmailLogRoute class.
+ *
+ * TEmailLogRoute sends selected log messages to email addresses.
+ * The target email addresses may be specified via {@link setEmails Emails} property.
+ * Optionally, you may set the email {@link setSubject Subject} and the
+ * {@link setSentFrom SentFrom} address.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System.Util
+ * @since 3.0
+ */
+class TEmailLogRoute extends TLogRoute
+{
+ /**
+ * Regex pattern for email address.
+ */
+ const EMAIL_PATTERN='/^([0-9a-zA-Z]+[-._+&])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}$/';
+ /**
+ * Default email subject.
+ */
+ const DEFAULT_SUBJECT='Prado Application Log';
+ /**
+ * @var array list of destination email addresses.
+ */
+ private $_emails=array();
+ /**
+ * @var string email subject
+ */
+ private $_subject='';
+ /**
+ * @var string email sent from address
+ */
+ private $_from='';
+
+ /**
+ * Initializes the route.
+ * @param TXmlElement configurations specified in {@link TLogRouter}.
+ * @throws TConfigurationException if {@link getSentFrom SentFrom} is empty and
+ * 'sendmail_from' in php.ini is also empty.
+ */
+ public function init($config)
+ {
+ if($this->_from==='')
+ $this->_from=ini_get('sendmail_from');
+ if($this->_from==='')
+ throw new TConfigurationException('emaillogroute_sentfrom_required');
+ }
+
+ /**
+ * Sends log messages to specified email addresses.
+ * @param array list of log messages
+ */
+ protected function processLogs($logs)
+ {
+ $message='';
+ foreach($logs as $log)
+ $message.=$this->formatLogMessage($log[0],$log[1],$log[2],$log[3]);
+ $message=wordwrap($message,70);
+ foreach($this->_emails as $email)
+ mail($email,$this->getSubject(),$message,"From:{$this->_from}\r\n");
+
+ }
+
+ /**
+ * @return array list of destination email addresses
+ */
+ public function getEmails()
+ {
+ return $this->_emails;
+ }
+
+ /**
+ * @return array|string list of destination email addresses. If the value is
+ * a string, it is assumed to be comma-separated email addresses.
+ */
+ public function setEmails($emails)
+ {
+ if(is_array($emails))
+ $this->_emails=$emails;
+ else
+ {
+ $this->_emails=array();
+ foreach(explode(',',$emails) as $email)
+ {
+ $email=trim($email);
+ if(preg_match(self::EMAIL_PATTERN,$email))
+ $this->_emails[]=$email;
+ }
+ }
+ }
+
+ /**
+ * @return string email subject. Defaults to TEmailLogRoute::DEFAULT_SUBJECT
+ */
+ public function getSubject()
+ {
+ if($this->_subject===null)
+ $this->_subject=self::DEFAULT_SUBJECT;
+ return $this->_subject;
+ }
+
+ /**
+ * @param string email subject.
+ */
+ public function setSubject($value)
+ {
+ $this->_subject=$value;
+ }
+
+ /**
+ * @return string send from address of the email
+ */
+ public function getSentFrom()
+ {
+ return $this->_from;
+ }
+
+ /**
+ * @param string send from address of the email
+ */
+ public function setSentFrom($value)
+ {
+ $this->_from=$value;
+ }
+}
+
+/**
+ * TBrowserLogRoute class.
+ *
+ * TBrowserLogRoute prints selected log messages in the response.
+ *
+ * @author Xiang Wei Zhuo
+ * @version $Revision: $ $Date: $
+ * @package System.Util
+ * @since 3.0
+ */
+class TBrowserLogRoute extends TLogRoute
+{
+ public function processLogs($logs)
+ {
+ if(empty($logs) || $this->getApplication()->getMode()==='Performance') return;
+ $first = $logs[0][3];
+ $prev = $first;
+ $even = true;
+ $response = $this->getApplication()->getResponse();
+ $response->write($this->renderHeader());
+ foreach($logs as $log)
+ {
+ $timing['total'] = $log[3] - $first;
+ $timing['delta'] = $log[3] - $prev;
+ $timing['even'] = !($even = !$even);
+ $prev=$log[3];
+ $response->write($this->renderMessage($log,$timing));
+ }
+ $response->write($this->renderFooter());
+ }
+
+ protected function renderHeader()
+ {
+ $string = <<
+
+
+ Application Log
+ |
+
+ |
+ Category | Message | Time Spent (s) | Cumulated Time Spent (s) |
+
+EOD;
+ return $string;
+ }
+
+ protected function renderMessage($log, $info)
+ {
+ $bgcolor = $info['even'] ? "#fff" : "#eee";
+ $total = sprintf('%0.6f', $info['total']);
+ $delta = sprintf('%0.6f', $info['delta']);
+ $color = $this->getColorLevel($log[1]);
+ $msg = preg_replace('/\(line[^\)]+\)$/','',$log[0]); //remove line number info
+ $msg = THttpUtility::htmlEncode($msg);
+ $string = <<
+ |
+ {$log[2]} |
+ {$msg} |
+ {$delta} |
+ {$total} |
+
+EOD;
+ return $string;
+ }
+
+ protected function getColorLevel($level)
+ {
+ switch($level)
+ {
+ case TLogger::DEBUG: return 'green';
+ case TLogger::INFO: return 'black';
+ case TLogger::NOTICE: return '#3333FF';
+ case TLogger::WARNING: return '#33FFFF';
+ case TLogger::ERROR: return '#ff9933';
+ case TLogger::ALERT: return '#ff00ff';
+ case TLogger::FATAL: return 'red';
+ }
+ return '';
+ }
+
+ protected function renderFooter()
+ {
+ $string = "";
+ foreach(self::$_levelValues as $name => $level)
+ {
+ $string .= "getColorLevel($level);
+ $string .= ";margin: 0.5em;\">".strtoupper($name)."";
+ }
+ $string .= " |
";
+ return $string;
+ }
+}
+?>
\ No newline at end of file
diff --git a/framework/Util/TLogger.php b/framework/Util/TLogger.php
new file mode 100644
index 00000000..632c46f1
--- /dev/null
+++ b/framework/Util/TLogger.php
@@ -0,0 +1,130 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $Date: $
+ * @package System.Util
+ */
+
+/**
+ * TLogger class.
+ *
+ * TLogger records log messages in memory and implements the methods to
+ * retrieve the messages with filter conditions, including log levels and
+ * log categories.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System.Util
+ * @since 3.0
+ */
+class TLogger extends TComponent
+{
+ /**
+ * Log levels.
+ */
+ const DEBUG=0x01;
+ const INFO=0x02;
+ const NOTICE=0x04;
+ const WARNING=0x08;
+ const ERROR=0x10;
+ const ALERT=0x20;
+ const FATAL=0x40;
+ /**
+ * @var array log messages
+ */
+ private $_logs=array();
+ /**
+ * @var integer log levels (bits) to be filtered
+ */
+ private $_levels;
+ /**
+ * @var array list of categories to be filtered
+ */
+ private $_categories;
+
+ /**
+ * Logs a message.
+ * Messages logged by this method may be retrieved via {@link getLogs}.
+ * @param string message to be logged
+ * @param integer level of the message. Valid values include
+ * TLogger::DEBUG, TLogger::INFO, TLogger::NOTICE, TLogger::WARNING,
+ * TLogger::ERROR, TLogger::ALERT, TLogger::FATAL.
+ * @param string category of the message
+ */
+ public function log($message,$level,$category='Uncategorized')
+ {
+ $this->_logs[]=array($message,$level,$category,microtime(true));
+ }
+
+ /**
+ * Retrieves log messages.
+ * Messages may be filtered by log levels and/or categories.
+ * A level filter is specified by an integer, whose bits indicate the levels interested.
+ * For example, (TLogger::INFO | TLogger::WARNING) specifies INFO and WARNING levels.
+ * A category filter is specified by concatenating interested category names
+ * with commas. A message whose category name starts with any filtering category
+ * will be returned. For example, a category filter 'System.Web, System.IO'
+ * will return messages under categories such as 'System.Web', 'System.IO',
+ * 'System.Web.UI', 'System.Web.UI.WebControls', etc.
+ * Level filter and category filter are combinational, i.e., only messages
+ * satisfying both filter conditions will they be returned.
+ * @param integer level filter
+ * @param string category filter
+ * @param array list of messages. Each array elements represents one message
+ * with the following structure:
+ * array(
+ * [0] => message
+ * [1] => level
+ * [2] => category
+ * [3] => timestamp);
+ */
+ public function getLogs($levels=null,$categories=null)
+ {
+ $this->_levels=$levels;
+ $this->_categories=$categories;
+ if(empty($levels) && empty($categories))
+ return $this->_logs;
+ else if(empty($levels))
+ return array_values(array_filter(array_filter($this->_logs,array($this,'filterByCategories'))));
+ else if(empty($categories))
+ return array_values(array_filter(array_filter($this->_logs,array($this,'filterByLevels'))));
+ else
+ {
+ $ret=array_values(array_filter(array_filter($this->_logs,array($this,'filterByLevels'))));
+ return array_values(array_filter(array_filter($ret,array($this,'filterByCategories'))));
+ }
+ }
+
+ /**
+ * Filter function used by {@link getLogs}
+ * @param array element to be filtered
+ */
+ private function filterByCategories($value)
+ {
+ foreach($this->_categories as $category)
+ {
+ if($value[2]===$category || strpos($value[2],$category.'.')===0)
+ return $value;
+ }
+ return false;
+ }
+
+ /**
+ * Filter function used by {@link getLogs}
+ * @param array element to be filtered
+ */
+ private function filterByLevels($value)
+ {
+ if($value[1] & $this->_levels)
+ return $value;
+ else
+ return false;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/framework/Util/TSimpleDateFormatter.php b/framework/Util/TSimpleDateFormatter.php
new file mode 100644
index 00000000..ce92a272
--- /dev/null
+++ b/framework/Util/TSimpleDateFormatter.php
@@ -0,0 +1,354 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2006 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $Date: $
+ * @package System.Util
+ */
+
+/**
+ * TSimpleDateFormatter class.
+ *
+ * Formats and parses dates using the SimpleDateFormat pattern.
+ * This pattern is compatible with the I18N and java's SimpleDateFormatter.
+ *
+ * Pattern | Description
+ * ----------------------------------------------------
+ * d | Day of month 1 to 31, no padding
+ * dd | Day of monath 01 to 31, zero leading
+ * M | Month digit 1 to 12, no padding
+ * MM | Month digit 01 to 12, zero leading
+ * yy | 2 year digit, e.g., 96, 05
+ * yyyy | 4 year digit, e.g., 2005
+ * ----------------------------------------------------
+ *
+ *
+ * Usage example, to format a date
+ *
+ * $formatter = new TSimpleDateFormatter("dd/MM/yyy");
+ * echo $formatter->format(time());
+ *
+ *
+ * To parse the date string into a date timestamp.
+ *
+ * $formatter = new TSimpleDateFormatter("d-M-yyy");
+ * echo $formatter->parse("24-6-2005");
+ *
+ *
+ * @author Wei Zhuo
+ * @version $Revision: $ $Date: $
+ * @package System.Util
+ * @since 3.0
+ */
+class TSimpleDateFormatter
+{
+ /**
+ * Formatting pattern.
+ * @var string
+ */
+ private $pattern;
+
+ /**
+ * Charset, default is 'UTF-8'
+ * @var string
+ */
+ private $charset = 'UTF-8';
+
+ /**
+ * Constructor, create a new date time formatter.
+ * @param string formatting pattern.
+ * @param string pattern and value charset
+ */
+ public function __construct($pattern, $charset='UTF-8')
+ {
+ $this->setPattern($pattern);
+ $this->setCharset($charset);
+ }
+
+ /**
+ * @return string formatting pattern.
+ */
+ public function getPattern()
+ {
+ return $this->pattern;
+ }
+
+ /**
+ * @param string formatting pattern.
+ */
+ public function setPattern($pattern)
+ {
+ $this->pattern = $pattern;
+ }
+
+ /**
+ * @return string formatting charset.
+ */
+ public function getCharset()
+ {
+ return $this->charset;
+ }
+
+ /**
+ * @param string formatting charset.
+ */
+ public function setCharset($charset)
+ {
+ $this->charset = $charset;
+ }
+
+ /**
+ * Format the date according to the pattern.
+ * @param string|int the date to format, either integer or a string readable by strtotime.
+ * @return string formatted date.
+ */
+ public function format($value)
+ {
+ $date = $this->getDate($value);
+ $bits['yyyy'] = $date['year'];
+ $bits['yy'] = substr("{$date['year']}", -2);
+
+ $bits['MM'] = str_pad("{$date['mon']}", 2, '0', STR_PAD_LEFT);
+ $bits['M'] = $date['mon'];
+
+ $bits['dd'] = str_pad("{$date['mday']}", 2, '0', STR_PAD_LEFT);
+ $bits['d'] = $date['mday'];
+
+ return str_replace(array_keys($bits), $bits, $this->pattern);
+ }
+
+ public function getMonthPattern()
+ {
+ if(is_int(strpos($this->pattern, 'MMMM')))
+ return 'MMMM';
+ if(is_int(strpos($this->pattern, 'MMM')))
+ return 'MMM';
+ if(is_int(strpos($this->pattern, 'MM')))
+ return 'MM';
+ if(is_int(strpos($this->pattern, 'M')))
+ return 'M';
+ return false;
+ }
+
+ public function getDayPattern()
+ {
+ if(is_int(strpos($this->pattern, 'dd')))
+ return 'dd';
+ if(is_int(strpos($this->pattern, 'd')))
+ return 'd';
+ return false;
+ }
+
+ public function getYearPattern()
+ {
+ if(is_int(strpos($this->pattern, 'yyyy')))
+ return 'yyyy';
+ if(is_int(strpos($this->pattern, 'yy')))
+ return 'yy';
+ return false;
+ }
+
+ public function getDayMonthYearOrdering()
+ {
+ $ordering = array();
+ if(is_int($day= strpos($this->pattern, 'd')))
+ $ordering['day'] = $day;
+ if(is_int($month= strpos($this->pattern, 'M')))
+ $ordering['month'] = $month;
+ if(is_int($year= strpos($this->pattern, 'yy')))
+ $ordering['year'] = $year;
+ asort($ordering);
+ return array_keys($ordering);
+ }
+
+ /**
+ * Gets the time stamp from string or integer.
+ * @param string|int date to parse
+ * @return int parsed date time stamp
+ */
+ private function getDate($value)
+ {
+ if(is_int($value))
+ return @getdate($value);
+ $date = @strtotime($value);
+ if($date < 0)
+ throw new TInvalidDataValueException('invalid_date', $value);
+ return @getdate($date);
+ }
+
+ /**
+ * @return boolean true if the given value matches with the date pattern.
+ */
+ public function isValidDate($value)
+ {
+ return !is_null($this->parse($value, false));
+ }
+
+ /**
+ * Parse the string according to the pattern.
+ * @param string date string to parse
+ * @return int date time stamp
+ * @throws TInvalidDataValueException if date string is malformed.
+ */
+ public function parse($value,$defaultToCurrentTime=true)
+ {
+ if(!is_string($value))
+ throw new TInvalidDataValueException('date_to_parse_must_be_string', $value);
+
+ if(empty($this->pattern)) return time();
+
+ $date = $this->getDate(time());
+
+ if($this->length(trim($value)) < 1)
+ return $defaultToCurrentTime ? $date : null;
+
+ $pattern = $this->pattern;
+
+ $i_val = 0;
+ $i_format = 0;
+ $pattern_length = $this->length($pattern);
+ $c = '';
+ $token='';
+ $x=null; $y=null;
+
+
+ if($defaultToCurrentTime)
+ {
+ $year = "{$date['year']}";
+ $month = $date['mon'];
+ $day = $date['mday'];
+ }
+ else
+ {
+ $year = null;
+ $month = null;
+ $day = null;
+ }
+
+ while ($i_format < $pattern_length)
+ {
+ $c = $this->charAt($pattern,$i_format);
+ $token='';
+ while ($this->charEqual($pattern, $i_format, $c)
+ && ($i_format < $pattern_length))
+ {
+ $token .= $this->charAt($pattern, $i_format++);
+ }
+
+ if ($token=='yyyy' || $token=='yy' || $token=='y')
+ {
+ if ($token=='yyyy') { $x=4;$y=4; }
+ if ($token=='yy') { $x=2;$y=2; }
+ if ($token=='y') { $x=2;$y=4; }
+ $year = $this->getInteger($value,$i_val,$x,$y);
+ if(is_null($year))
+ throw new TInvalidDataValueException('Invalid year', $value);
+ $i_val += strlen($year);
+ if(strlen($year) == 2)
+ {
+ $iYear = intval($year);
+ if($iYear > 70)
+ $year = $iYear + 1900;
+ else
+ $year = $iYear + 2000;
+ }
+ $year = intval($year);
+ }
+ elseif($token=='MM' || $token=='M')
+ {
+ $month=$this->getInteger($value,$i_val,
+ $this->length($token),2);
+ $iMonth = intval($month);
+ if(is_null($month) || $iMonth < 1 || $iMonth > 12 )
+ throw new TInvalidDataValueException('Invalid month', $value);
+ $i_val += strlen($month);
+ $month = $iMonth;
+ }
+ elseif ($token=='dd' || $token=='d')
+ {
+ $day = $this->getInteger($value,$i_val,
+ $this->length($token), 2);
+ $iDay = intval($day);
+ if(is_null($day) || $iDay < 1 || $iDay >31)
+ throw new TInvalidDataValueException('Invalid day', $value);
+ $i_val += strlen($day);
+ $day = $iDay;
+ }
+ else
+ {
+ if($this->substring($value, $i_val, $this->length($token)) != $token)
+ throw new TInvalidDataValueException("Subpattern '{$this->pattern}' mismatch", $value);
+ else
+ $i_val += $this->length($token);
+ }
+ }
+ if ($i_val != $this->length($value))
+ throw new TInvalidDataValueException("Pattern '{$this->pattern}' mismatch", $value);
+
+ if(!$defaultToCurrentTime && (is_null($month) || is_null($day) || is_null($year)))
+ return null;
+ else
+ return $this->getDate(@mktime(0, 0, 0, $month, $day, $year));
+ }
+
+ /**
+ * Calculate the length of a string, may be consider iconv_strlen?
+ */
+ private function length($string)
+ {
+ //use iconv_strlen or just strlen?
+ return strlen($string);
+ }
+
+ /**
+ * Get the char at a position.
+ */
+ private function charAt($string, $pos)
+ {
+ return $this->substring($string, $pos, 1);
+ }
+
+ /**
+ * Gets a portion of a string, uses iconv_substr.
+ */
+ private function substring($string, $start, $length)
+ {
+ return iconv_substr($string, $start, $length);
+ }
+
+ /**
+ * Returns true if char at position equals a particular char.
+ */
+ private function charEqual($string, $pos, $char)
+ {
+ return $this->charAt($string, $pos) == $char;
+ }
+
+ /**
+ * Gets integer from part of a string, allows integers of any length.
+ * @param string string to retrieve the integer from.
+ * @param int starting position
+ * @param int minimum integer length
+ * @param int maximum integer length
+ * @return string integer portition of the string, null otherwise
+ */
+ private function getInteger($str,$i,$minlength,$maxlength)
+ {
+ //match for digits backwards
+ for ($x = $maxlength; $x >= $minlength; $x--)
+ {
+ $token= $this->substring($str, $i,$x);
+ if ($this->length($token) < $minlength)
+ return null;
+ if (preg_match('/^\d+$/', $token))
+ return $token;
+ }
+ return null;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/framework/Util/TVarDumper.php b/framework/Util/TVarDumper.php
new file mode 100644
index 00000000..0532a6ec
--- /dev/null
+++ b/framework/Util/TVarDumper.php
@@ -0,0 +1,123 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $Date: $
+ * @package System.Util
+ */
+
+/**
+ * TVarDumper class.
+ *
+ * TVarDumper is intended to replace the buggy PHP function var_dump and print_r.
+ * It can correctly identify the recursively referenced objects in a complex
+ * object structure. It also has a recurisve depth control to avoid indefinite
+ * recursive display of some peculiar variables.
+ *
+ * TVarDumper can be used as follows,
+ *
+ * echo TVarDumper::dump($var);
+ *
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System.Util
+ * @since 3.0
+ */
+class TVarDumper
+{
+ private static $_objects;
+ private static $_output;
+ private static $_depth;
+
+ /**
+ * Converts a variable into a string representation.
+ * This method achieves the similar functionality as var_dump and print_r
+ * but is more robust when handling complex objects such as PRADO controls.
+ * @param mixed variable to be dumped
+ * @param integer maximum depth that the dumper should go into the variable. Defaults to 10.
+ * @return string the string representation of the variable
+ */
+ public static function dump($var,$depth=10)
+ {
+ self::$_output='';
+ self::$_objects=array();
+ self::$_depth=$depth;
+ self::dumpInternal($var,0);
+ return self::$_output;
+ }
+
+ private static function dumpInternal($var,$level)
+ {
+ switch(gettype($var))
+ {
+ case 'boolean':
+ self::$_output.=$var?'true':'false';
+ break;
+ case 'integer':
+ self::$_output.="$var";
+ break;
+ case 'double':
+ self::$_output.="$var";
+ break;
+ case 'string':
+ self::$_output.="'$var'";
+ break;
+ case 'resource':
+ self::$_output.='{resource}';
+ break;
+ case 'NULL':
+ self::$_output.="null";
+ break;
+ case 'unknown type':
+ self::$_output.='{unknown}';
+ break;
+ case 'array':
+ if(self::$_depth<=$level)
+ self::$_output.='array(...)';
+ else if(empty($var))
+ self::$_output.='array()';
+ else
+ {
+ $keys=array_keys($var);
+ $spaces=str_repeat(' ',$level*4);
+ self::$_output.="array\n".$spaces.'(';
+ foreach($keys as $key)
+ {
+ self::$_output.="\n".$spaces." [$key] => ";
+ self::$_output.=self::dumpInternal($var[$key],$level+1);
+ }
+ self::$_output.="\n".$spaces.')';
+ }
+ break;
+ case 'object':
+ if(($id=array_search($var,self::$_objects,true))!==false)
+ self::$_output.=get_class($var).'#'.($id+1).'(...)';
+ else if(self::$_depth<=$level)
+ self::$_output.=get_class($var).'(...)';
+ else
+ {
+ $id=array_push(self::$_objects,$var);
+ $className=get_class($var);
+ $members=(array)$var;
+ $keys=array_keys($members);
+ $spaces=str_repeat(' ',$level*4);
+ self::$_output.="$className#$id\n".$spaces.'(';
+ foreach($keys as $key)
+ {
+ $keyDisplay=strtr(trim($key),array("\0"=>':'));
+ self::$_output.="\n".$spaces." [$keyDisplay] => ";
+ self::$_output.=self::dumpInternal($members[$key],$level+1);
+ }
+ self::$_output.="\n".$spaces.')';
+ }
+ break;
+ }
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/framework/Web/TAssetManager.php b/framework/Web/TAssetManager.php
index 267505c7..bfc5ef8b 100644
--- a/framework/Web/TAssetManager.php
+++ b/framework/Web/TAssetManager.php
@@ -280,7 +280,7 @@ class TAssetManager extends TModule
throw new TIOException('assetmanager_tarfile_invalid',$path);
else
{
- Prado::using('System.Data.TTarFileExtractor');
+ Prado::using('System.IO.TTarFileExtractor');
$tar = new TTarFileExtractor($fullpath);
return $tar->extract($destination);
}
diff --git a/framework/Web/UI/TControl.php b/framework/Web/UI/TControl.php
index dba58555..52ec9bb1 100644
--- a/framework/Web/UI/TControl.php
+++ b/framework/Web/UI/TControl.php
@@ -1865,6 +1865,47 @@ interface IBroadcastEventReceiver
public function broadcastEventReceived($sender,$param);
}
+/**
+ * ITheme interface.
+ *
+ * This interface must be implemented by theme.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface ITheme
+{
+ /**
+ * Applies this theme to the specified control.
+ * @param TControl the control to be applied with this theme
+ */
+ public function applySkin($control);
+}
+
+/**
+ * ITemplate interface
+ *
+ * ITemplate specifies the interface for classes encapsulating
+ * parsed template structures.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface ITemplate
+{
+ /**
+ * Instantiates the template.
+ * Content in the template will be instantiated as components and text strings
+ * and passed to the specified parent control.
+ * @param TControl the parent control
+ */
+ public function instantiateIn($parent);
+}
+
/**
* TBroadcastEventParameter class
*
diff --git a/framework/Web/UI/WebControls/TBaseDataList.php b/framework/Web/UI/WebControls/TBaseDataList.php
index b7c79cbe..479fb2ef 100644
--- a/framework/Web/UI/WebControls/TBaseDataList.php
+++ b/framework/Web/UI/WebControls/TBaseDataList.php
@@ -11,9 +11,10 @@
*/
/**
- * Includes TDataBoundControl class
+ * Includes TDataBoundControl and TDataFieldAccessor classes
*/
Prado::using('System.Web.UI.WebControls.TDataBoundControl');
+Prado::using('System.Util.TDataFieldAccessor');
/**
* TBaseDataList class
diff --git a/framework/Web/UI/WebControls/TCompareValidator.php b/framework/Web/UI/WebControls/TCompareValidator.php
index 811ca50a..1bf4c529 100644
--- a/framework/Web/UI/WebControls/TCompareValidator.php
+++ b/framework/Web/UI/WebControls/TCompareValidator.php
@@ -201,7 +201,7 @@ class TCompareValidator extends TBaseValidator
$dateFormat = $this->getDateFormat();
if($dateFormat!=='')
{
- $formatter = Prado::createComponent('System.Data.TSimpleDateFormatter', $dateFormat);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $dateFormat);
return array($formatter->parse($value1), $formatter->parse($value2));
}
else
diff --git a/framework/Web/UI/WebControls/TDataGridColumn.php b/framework/Web/UI/WebControls/TDataGridColumn.php
index e8cc81aa..de9d9d5c 100644
--- a/framework/Web/UI/WebControls/TDataGridColumn.php
+++ b/framework/Web/UI/WebControls/TDataGridColumn.php
@@ -10,6 +10,11 @@
* @package System.Web.UI.WebControls
*/
+/**
+ * Includes TDataFieldAccessor class
+ */
+Prado::using('System.Util.TDataFieldAccessor');
+
/**
* TDataGridColumn class
*
diff --git a/framework/Web/UI/WebControls/TDataTypeValidator.php b/framework/Web/UI/WebControls/TDataTypeValidator.php
index f3cf5a3c..81c23ce4 100644
--- a/framework/Web/UI/WebControls/TDataTypeValidator.php
+++ b/framework/Web/UI/WebControls/TDataTypeValidator.php
@@ -91,7 +91,7 @@ class TDataTypeValidator extends TBaseValidator
$dateFormat = $this->getDateFormat();
if(strlen($dateFormat))
{
- $formatter = Prado::createComponent('System.Data.TSimpleDateFormatter',$dateFormat);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$dateFormat);
return $formatter->isValidDate($value);
}
else
diff --git a/framework/Web/UI/WebControls/TDatePicker.php b/framework/Web/UI/WebControls/TDatePicker.php
index 8d6d45e4..0d30636c 100644
--- a/framework/Web/UI/WebControls/TDatePicker.php
+++ b/framework/Web/UI/WebControls/TDatePicker.php
@@ -256,7 +256,7 @@ class TDatePicker extends TTextBox
public function setDate($value)
{
$date = TPropertyValue::ensureInteger($value);
- $formatter = Prado::createComponent('System.Data.TSimpleDateFormatter',
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
$this->getDateFormat());
$this->setText($formatter->format($date));
}
@@ -358,7 +358,7 @@ class TDatePicker extends TTextBox
$date = @mktime(0, 0, 0, $month, $day, $year);
$pattern = $this->getDateFormat();
$pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
- $formatter = Prado::createComponent('System.Data.TSimpleDateFormatter', $pattern);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $pattern);
return $formatter->format($date);
}
@@ -452,7 +452,7 @@ class TDatePicker extends TTextBox
protected function hasDayPattern()
{
- $formatter = Prado::createComponent('System.Data.TSimpleDateFormatter',
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
$this->getDateFormat());
return !is_null($formatter->getDayPattern());
}
@@ -464,7 +464,7 @@ class TDatePicker extends TTextBox
*/
protected function renderCalendarSelections($writer, $date)
{
- $formatter = Prado::createComponent('System.Data.TSimpleDateFormatter',
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
$this->getDateFormat());
foreach($formatter->getDayMonthYearOrdering() as $type)
{
@@ -485,7 +485,7 @@ class TDatePicker extends TTextBox
{
$pattern = $this->getDateFormat();
$pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
- $formatter = Prado::createComponent('System.Data.TSimpleDateFormatter',$pattern);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$pattern);
return $formatter->parse($this->getText());
}
@@ -550,7 +550,7 @@ class TDatePicker extends TTextBox
*/
protected function getLocalizedMonthNames($info)
{
- $formatter = Prado::createComponent('System.Data.TSimpleDateFormatter',
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
$this->getDateFormat());
switch($formatter->getMonthPattern())
{
diff --git a/framework/Web/UI/WebControls/TListControl.php b/framework/Web/UI/WebControls/TListControl.php
index 3d73556a..ccbce4d6 100644
--- a/framework/Web/UI/WebControls/TListControl.php
+++ b/framework/Web/UI/WebControls/TListControl.php
@@ -18,6 +18,10 @@ Prado::using('System.Web.UI.WebControls.TDataBoundControl');
* Includes TAttributeCollection class
*/
Prado::using('System.Collections.TAttributeCollection');
+/**
+ * Includes TDataFieldAccessor class
+ */
+Prado::using('System.Util.TDataFieldAccessor');
/**
* TListControl class
diff --git a/framework/Web/UI/WebControls/TRangeValidator.php b/framework/Web/UI/WebControls/TRangeValidator.php
index 842797ba..7ded3e71 100644
--- a/framework/Web/UI/WebControls/TRangeValidator.php
+++ b/framework/Web/UI/WebControls/TRangeValidator.php
@@ -226,7 +226,7 @@ class TRangeValidator extends TBaseValidator
$dateFormat = $this->getDateFormat();
if($dateFormat!=='')
{
- $formatter=Prado::createComponent('System.Data.TSimpleDateFormatter', $dateFormat);
+ $formatter=Prado::createComponent('System.Util.TSimpleDateFormatter', $dateFormat);
$value = $formatter->parse($value, $dateFormat);
if($minValue!=='')
$valid=$valid && ($value>=$formatter->parse($minValue));
diff --git a/framework/Web/UI/WebControls/TWizard.php b/framework/Web/UI/WebControls/TWizard.php
index 0b44872b..ef4691bd 100644
--- a/framework/Web/UI/WebControls/TWizard.php
+++ b/framework/Web/UI/WebControls/TWizard.php
@@ -16,6 +16,7 @@ Prado::using('System.Web.UI.WebControls.TButton');
Prado::using('System.Web.UI.WebControls.TLinkButton');
Prado::using('System.Web.UI.WebControls.TImageButton');
Prado::using('System.Web.UI.WebControls.TDataList');
+Prado::using('System.Collections.TStack');
/**
* Class TWizard.
diff --git a/framework/Xml/TXmlDocument.php b/framework/Xml/TXmlDocument.php
new file mode 100644
index 00000000..fb73a9f5
--- /dev/null
+++ b/framework/Xml/TXmlDocument.php
@@ -0,0 +1,455 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $Date: $
+ * @package System.Xml
+ */
+
+/**
+ * TXmlElement class.
+ *
+ * TXmlElement represents an XML element node.
+ * You can obtain its tagname, attributes, text between the openning and closing
+ * tags via the TagName, Attributes, and Value properties, respectively.
+ * You can also retrieve its parent and child elements by Parent and Elements
+ * properties, respectively.
+ *
+ * TBD: xpath
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System.Xml
+ * @since 3.0
+ */
+class TXmlElement extends TComponent
+{
+ /**
+ * @var TXmlElement parent of this element
+ */
+ private $_parent=null;
+ /**
+ * @var string tagname of this element
+ */
+ private $_tagName;
+ /**
+ * @var string text enclosed between openning and closing tags of this element
+ */
+ private $_value;
+ /**
+ * @var TXmlElementList list of child elements of this element
+ */
+ private $_elements=null;
+ /**
+ * @var TMap attributes of this element
+ */
+ private $_attributes=null;
+
+ /**
+ * Constructor.
+ * @param string tagname for this element
+ */
+ public function __construct($tagName)
+ {
+ $this->setTagName($tagName);
+ }
+
+ /**
+ * @return TXmlElement parent element of this element
+ */
+ public function getParent()
+ {
+ return $this->_parent;
+ }
+
+ /**
+ * @param TXmlElement parent element of this element
+ */
+ public function setParent($parent)
+ {
+ $this->_parent=$parent;
+ }
+
+ /**
+ * @return string tagname of this element
+ */
+ public function getTagName()
+ {
+ return $this->_tagName;
+ }
+
+ /**
+ * @param string tagname of this element
+ */
+ public function setTagName($tagName)
+ {
+ $this->_tagName=$tagName;
+ }
+
+ /**
+ * @return string text enclosed between opening and closing tag of this element
+ */
+ public function getValue()
+ {
+ return $this->_value;
+ }
+
+ /**
+ * @param string text enclosed between opening and closing tag of this element
+ */
+ public function setValue($value)
+ {
+ $this->_value=$value;
+ }
+
+ /**
+ * @return boolean true if this element has child elements
+ */
+ public function getHasElement()
+ {
+ return $this->_elements!==null && $this->_elements->getCount()>0;
+ }
+
+ /**
+ * @return boolean true if this element has attributes
+ */
+ public function getHasAttribute()
+ {
+ return $this->_attributes!==null && $this->_attributes->getCount()>0;
+ }
+
+ /**
+ * @return string the attribute specified by the name, null if no such attribute
+ */
+ public function getAttribute($name)
+ {
+ if($this->_attributes!==null)
+ return $this->_attributes->itemAt($name);
+ else
+ return null;
+ }
+
+ /**
+ * @return TXmlElementList list of child elements
+ */
+ public function getElements()
+ {
+ if(!$this->_elements)
+ $this->_elements=new TXmlElementList($this);
+ return $this->_elements;
+ }
+
+ /**
+ * @return TMap list of attributes
+ */
+ public function getAttributes()
+ {
+ if(!$this->_attributes)
+ $this->_attributes=new TMap;
+ return $this->_attributes;
+ }
+
+ /**
+ * @return TXmlElement the first child element that has the specified tagname, null if not found
+ */
+ public function getElementByTagName($tagName)
+ {
+ if($this->_elements)
+ {
+ foreach($this->_elements as $element)
+ if($element->_tagName===$tagName)
+ return $element;
+ }
+ return null;
+ }
+
+ /**
+ * @return TList list of all child elements that have the specified tagname
+ */
+ public function getElementsByTagName($tagName)
+ {
+ $list=new TList;
+ if($this->_elements)
+ {
+ foreach($this->_elements as $element)
+ if($element->_tagName===$tagName)
+ $list->add($element);
+ }
+ return $list;
+ }
+
+ /**
+ * @return string string representation of this element
+ */
+ public function toString($indent=0)
+ {
+ $attr='';
+ if($this->_attributes!==null)
+ {
+ foreach($this->_attributes as $name=>$value)
+ $attr.=" $name=\"$value\"";
+ }
+ $prefix=str_repeat(' ',$indent*4);
+ if($this->getHasElement())
+ {
+ $str=$prefix."<{$this->_tagName}$attr>\n";
+ foreach($this->getElements() as $element)
+ $str.=$element->toString($indent+1)."\n";
+ $str.=$prefix."{$this->_tagName}>";
+ return $str;
+ }
+ else if($this->getValue()!=='')
+ {
+ return $prefix."<{$this->_tagName}$attr>{$this->_value}{$this->_tagName}>";
+ }
+ else
+ return $prefix."<{$this->_tagName}$attr />";
+ }
+}
+
+/**
+ * TXmlDocument class.
+ *
+ * TXmlDocument represents a DOM representation of an XML file.
+ * Besides all properties and methods inherited from {@link TXmlElement},
+ * you can load an XML file or string by {@link loadFromFile} or {@link loadFromString}.
+ * You can also get the version and encoding of the XML document by
+ * the Version and Encoding properties.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System.Xml
+ * @since 3.0
+ */
+class TXmlDocument extends TXmlElement
+{
+ /**
+ * @var string version of this XML document
+ */
+ private $_version;
+ /**
+ * @var string encoding of this XML document
+ */
+ private $_encoding;
+
+ /**
+ * Constructor.
+ * @param string version of this XML document
+ * @param string encoding of this XML document
+ */
+ public function __construct($version='1.0',$encoding='')
+ {
+ parent::__construct('');
+ $this->setversion($version);
+ $this->setEncoding($encoding);
+ }
+
+ /**
+ * @return string version of this XML document
+ */
+ public function getVersion()
+ {
+ return $this->_version;
+ }
+
+ /**
+ * @param string version of this XML document
+ */
+ public function setVersion($version)
+ {
+ $this->_version=$version;
+ }
+
+ /**
+ * @return string encoding of this XML document
+ */
+ public function getEncoding()
+ {
+ return $this->_encoding;
+ }
+
+ /**
+ * @param string encoding of this XML document
+ */
+ public function setEncoding($encoding)
+ {
+ $this->_encoding=$encoding;
+ }
+
+ /**
+ * Loads and parses an XML document.
+ * @param string the XML file path
+ * @return boolean whether the XML file is parsed successfully
+ * @throws TIOException if the file fails to be opened.
+ */
+ public function loadFromFile($file)
+ {
+ if(($str=@file_get_contents($file))!==false)
+ return $this->loadFromString($str);
+ else
+ throw new TIOException('xmldocument_file_read_failed',$file);
+ }
+
+ /**
+ * Loads and parses an XML string.
+ * The version and encoding will be determined based on the parsing result.
+ * @param string the XML string
+ * @return boolean whether the XML string is parsed successfully
+ */
+ public function loadFromString($string)
+ {
+ // TODO: since PHP 5.1, we can get parsing errors and throw them as exception
+ $doc=new DOMDocument();
+ if($doc->loadXML($string)===false)
+ return false;
+
+ $this->setEncoding($doc->encoding);
+ $this->setVersion($doc->version);
+
+ $element=$doc->documentElement;
+ $this->setTagName($element->tagName);
+ $this->setValue($element->nodeValue);
+ $elements=$this->getElements();
+ $attributes=$this->getAttributes();
+ $elements->clear();
+ $attributes->clear();
+ foreach($element->attributes as $name=>$attr)
+ $attributes->add($name,$attr->value);
+ foreach($element->childNodes as $child)
+ {
+ if($child instanceof DOMElement)
+ $elements->add($this->buildElement($child));
+ }
+
+ return true;
+ }
+
+ /**
+ * Saves this XML document as an XML file.
+ * @param string the name of the file to be stored with XML output
+ * @throws TIOException if the file cannot be written
+ */
+ public function saveToFile($file)
+ {
+ if(($fw=fopen($file,'w'))!==false)
+ {
+ fwrite($fw,$this->saveToString());
+ fclose($fw);
+ }
+ else
+ throw new TIOException('xmldocument_file_write_failed',$file);
+ }
+
+ /**
+ * Saves this XML document as an XML string
+ * @return string the XML string of this XML document
+ */
+ public function saveToString()
+ {
+ $version=empty($this->_version)?' version="1.0"':' version="'.$this->_version.'"';
+ $encoding=empty($this->_encoding)?'':' encoding="'.$this->_encoding.'"';
+ return "\n".$this->toString(0);
+ }
+
+ /**
+ * Recursively converts DOM XML nodes into TXmlElement
+ * @param DOMXmlNode the node to be converted
+ * @return TXmlElement the converted TXmlElement
+ */
+ private function buildElement($node)
+ {
+ $element=new TXmlElement($node->tagName);
+ $element->setValue($node->nodeValue);
+ foreach($node->attributes as $name=>$attr)
+ $element->getAttributes()->add($name,$attr->value);
+ foreach($node->childNodes as $child)
+ {
+ if($child instanceof DOMElement)
+ $element->getElements()->add($this->buildElement($child));
+ }
+ return $element;
+ }
+}
+
+
+/**
+ * TXmlElement class.
+ *
+ * TXmlElement represents an XML element node.
+ * You can obtain its tagname, attributes, text between the openning and closing
+ * tags via the TagName, Attributes, and Value properties, respectively.
+ * You can also retrieve its parent and child elements by Parent and Elements
+ * properties, respectively.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System.Xml
+ * @since 3.0
+ */
+class TXmlElementList extends TList
+{
+ /**
+ * @var TXmlElement owner of this list
+ */
+ private $_o;
+
+ /**
+ * Constructor.
+ * @param TXmlElement owner of this list
+ */
+ public function __construct(TXmlElement $owner)
+ {
+ $this->_o=$owner;
+ }
+
+ /**
+ * @return TXmlElement owner of this list
+ */
+ protected function getOwner()
+ {
+ return $this->_o;
+ }
+
+
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing additional
+ * operations for each newly added TXmlElement object.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a TXmlElement object.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TXmlElement)
+ {
+ parent::insertAt($index,$item);
+ if($item->getParent()!==null)
+ $item->getParent()->getElements()->remove($item);
+ $item->setParent($this->_o);
+ }
+ else
+ throw new TInvalidDataTypeException('xmlelementlist_xmlelement_required');
+ }
+
+ /**
+ * Removes an item at the specified position.
+ * This overrides the parent implementation by performing additional
+ * cleanup work when removing a TXmlElement object.
+ * @param integer the index of the item to be removed.
+ * @return mixed the removed item.
+ */
+ public function removeAt($index)
+ {
+ $item=parent::removeAt($index);
+ if($item instanceof TXmlElement)
+ $item->setParent(null);
+ return $item;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/framework/core.php b/framework/core.php
deleted file mode 100644
index 6f7d081d..00000000
--- a/framework/core.php
+++ /dev/null
@@ -1,1094 +0,0 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Revision: $ $Date: $
- * @package System
- */
-
-/**
- * The framework installation path.
- */
-define('PRADO_DIR',dirname(__FILE__));
-
-/**
- * Includes TComponent definition
- */
-require_once(PRADO_DIR.'/TComponent.php');
-/**
- * Includes TApplicationComponent definition
- */
-require_once(PRADO_DIR.'/TApplicationComponent.php');
-/**
- * Includes exception definitions
- */
-require_once(PRADO_DIR.'/Exceptions/TException.php');
-/**
- * Includes TList definition
- */
-require_once(PRADO_DIR.'/Collections/TList.php');
-/**
- * Includes TMap definition
- */
-require_once(PRADO_DIR.'/Collections/TMap.php');
-/**
- * Includes TStack definition
- */
-require_once(PRADO_DIR.'/Collections/TStack.php');
-/**
- * Includes TXmlDocument, TXmlElement definition
- */
-require_once(PRADO_DIR.'/Data/TXmlDocument.php');
-/**
- * Includes THttpUtility definition
- */
-require_once(PRADO_DIR.'/Web/THttpUtility.php');
-/**
- * Includes TJavaScript definition
- */
-require_once(PRADO_DIR.'/Web/Javascripts/TJavaScript.php');
-/**
- * Includes TCache definition
- */
-require_once(PRADO_DIR.'/Data/TCache.php');
-/**
- * Includes TDataFieldAccessor definition
- */
-require_once(PRADO_DIR.'/Data/TDataFieldAccessor.php');
-/**
- * Includes TLogger definition
- */
-require_once(PRADO_DIR.'/Log/TLogger.php');
-
-/**
- * IModule interface.
- *
- * This interface must be implemented by application modules.
- *
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System
- * @since 3.0
- */
-interface IModule
-{
- /**
- * Initializes the module.
- * @param TXmlElement the configuration for the module
- */
- public function init($config);
- /**
- * @return string ID of the module
- */
- public function getID();
- /**
- * @param string ID of the module
- */
- public function setID($id);
-}
-
-/**
- * IService interface.
- *
- * This interface must be implemented by services.
- *
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System
- * @since 3.0
- */
-interface IService
-{
- /**
- * Initializes the service.
- * @param TXmlElement the configuration for the service
- */
- public function init($config);
- /**
- * @return string ID of the service
- */
- public function getID();
- /**
- * @param string ID of the service
- */
- public function setID($id);
- /**
- * Runs the service.
- */
- public function run();
-}
-
-/**
- * ITextWriter interface.
- *
- * This interface must be implemented by writers.
- *
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System
- * @since 3.0
- */
-interface ITextWriter
-{
- /**
- * Writes a string.
- * @param string string to be written
- */
- public function write($str);
- /**
- * Flushes the content that has been written.
- */
- public function flush();
-}
-
-/**
- * ITheme interface.
- *
- * This interface must be implemented by theme.
- *
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System
- * @since 3.0
- */
-interface ITheme
-{
- /**
- * Applies this theme to the specified control.
- * @param TControl the control to be applied with this theme
- */
- public function applySkin($control);
-}
-
-/**
- * ITemplate interface
- *
- * ITemplate specifies the interface for classes encapsulating
- * parsed template structures.
- *
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System
- * @since 3.0
- */
-interface ITemplate
-{
- /**
- * Instantiates the template.
- * Content in the template will be instantiated as components and text strings
- * and passed to the specified parent control.
- * @param TControl the parent control
- */
- public function instantiateIn($parent);
-}
-
-/**
- * IUser interface.
- *
- * This interface must be implemented by user objects.
- *
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System
- * @since 3.0
- */
-interface IUser
-{
- /**
- * @return string username
- */
- public function getName();
- /**
- * @param string username
- */
- public function setName($value);
- /**
- * @return boolean if the user is a guest
- */
- public function getIsGuest();
- /**
- * @param boolean if the user is a guest
- */
- public function setIsGuest($value);
- /**
- * @return array list of roles that the user is of
- */
- public function getRoles();
- /**
- * @return array|string list of roles that the user is of. If it is a string, roles are assumed by separated by comma
- */
- public function setRoles($value);
- /**
- * @param string role to be tested
- * @return boolean whether the user is of this role
- */
- public function isInRole($role);
- /**
- * @return string user data that is serialized and will be stored in session
- */
- public function saveToString();
- /**
- * @param string user data that is serialized and restored from session
- * @return IUser the user object
- */
- public function loadFromString($string);
-}
-
-/**
- * IStatePersister class.
- *
- * This interface must be implemented by all state persister classes (such as
- * {@link TPageStatePersister}, {@link TApplicationStatePersister}.
- *
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System
- * @since 3.0
- */
-interface IStatePersister
-{
- /**
- * Loads state from a persistent storage.
- * @return mixed the state
- */
- public function load();
- /**
- * Saves state into a persistent storage.
- * @param mixed the state to be saved
- */
- public function save($state);
-}
-
-/**
- * TModule class.
- *
- * TModule implements the basic methods required by IModule and may be
- * used as the basic class for application modules.
- *
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System
- * @since 3.0
- */
-abstract class TModule extends TApplicationComponent implements IModule
-{
- /**
- * @var string module id
- */
- private $_id;
-
- /**
- * Initializes the module.
- * This method is required by IModule and is invoked by application.
- * @param TXmlElement module configuration
- */
- public function init($config)
- {
- }
-
- /**
- * @return string id of this module
- */
- public function getID()
- {
- return $this->_id;
- }
-
- /**
- * @param string id of this module
- */
- public function setID($value)
- {
- $this->_id=$value;
- }
-}
-
-/**
- * TService class.
- *
- * TService implements the basic methods required by IService and may be
- * used as the basic class for application services.
- *
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System
- * @since 3.0
- */
-abstract class TService extends TApplicationComponent implements IService
-{
- /**
- * @var string service id
- */
- private $_id;
-
- /**
- * Initializes the service and attaches {@link run} to the RunService event of application.
- * This method is required by IService and is invoked by application.
- * @param TXmlElement module configuration
- */
- public function init($config)
- {
- }
-
- /**
- * @return string id of this service
- */
- public function getID()
- {
- return $this->_id;
- }
-
- /**
- * @param string id of this service
- */
- public function setID($value)
- {
- $this->_id=$value;
- }
-
- /**
- * Runs the service.
- */
- public function run()
- {
- }
-}
-
-/**
- * TVarDumper class.
- *
- * TVarDumper is intended to replace the buggy PHP function var_dump and print_r.
- * It can correctly identify the recursively referenced objects in a complex
- * object structure. It also has a recurisve depth control to avoid indefinite
- * recursive display of some peculiar variables.
- *
- * TVarDumper can be used as follows,
- *
- * echo TVarDumper::dump($var);
- *
- *
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System
- * @since 3.0
- */
-class TVarDumper
-{
- private static $_objects;
- private static $_output;
- private static $_depth;
-
- /**
- * Converts a variable into a string representation.
- * This method achieves the similar functionality as var_dump and print_r
- * but is more robust when handling complex objects such as PRADO controls.
- * @param mixed variable to be dumped
- * @param integer maximum depth that the dumper should go into the variable. Defaults to 10.
- * @return string the string representation of the variable
- */
- public static function dump($var,$depth=10)
- {
- self::$_output='';
- self::$_objects=array();
- self::$_depth=$depth;
- self::dumpInternal($var,0);
- return self::$_output;
- }
-
- private static function dumpInternal($var,$level)
- {
- switch(gettype($var))
- {
- case 'boolean':
- self::$_output.=$var?'true':'false';
- break;
- case 'integer':
- self::$_output.="$var";
- break;
- case 'double':
- self::$_output.="$var";
- break;
- case 'string':
- self::$_output.="'$var'";
- break;
- case 'resource':
- self::$_output.='{resource}';
- break;
- case 'NULL':
- self::$_output.="null";
- break;
- case 'unknown type':
- self::$_output.='{unknown}';
- break;
- case 'array':
- if(self::$_depth<=$level)
- self::$_output.='array(...)';
- else if(empty($var))
- self::$_output.='array()';
- else
- {
- $keys=array_keys($var);
- $spaces=str_repeat(' ',$level*4);
- self::$_output.="array\n".$spaces.'(';
- foreach($keys as $key)
- {
- self::$_output.="\n".$spaces." [$key] => ";
- self::$_output.=self::dumpInternal($var[$key],$level+1);
- }
- self::$_output.="\n".$spaces.')';
- }
- break;
- case 'object':
- if(($id=array_search($var,self::$_objects,true))!==false)
- self::$_output.=get_class($var).'#'.($id+1).'(...)';
- else if(self::$_depth<=$level)
- self::$_output.=get_class($var).'(...)';
- else
- {
- $id=array_push(self::$_objects,$var);
- $className=get_class($var);
- $members=(array)$var;
- $keys=array_keys($members);
- $spaces=str_repeat(' ',$level*4);
- self::$_output.="$className#$id\n".$spaces.'(';
- foreach($keys as $key)
- {
- $keyDisplay=strtr(trim($key),array("\0"=>':'));
- self::$_output.="\n".$spaces." [$keyDisplay] => ";
- self::$_output.=self::dumpInternal($members[$key],$level+1);
- }
- self::$_output.="\n".$spaces.')';
- }
- break;
- }
- }
-}
-
-
-/**
- * PradoBase class.
- *
- * PradoBase implements a few fundamental static methods.
- *
- * To use the static methods, Use Prado as the class name rather than PradoBase.
- * PradoBase is meant to serve as the base class of Prado. The latter might be
- * rewritten for customization.
- *
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System
- * @since 3.0
- */
-class PradoBase
-{
- /**
- * File extension for Prado class files.
- */
- const CLASS_FILE_EXT='.php';
- /**
- * @var array list of path aliases
- */
- private static $_aliases=array('System'=>PRADO_DIR);
- /**
- * @var array list of namespaces currently in use
- */
- private static $_usings=array();
- /**
- * @var TApplication the application instance
- */
- private static $_application=null;
- /**
- * @var TLogger logger instance
- */
- private static $_logger=null;
-
- /**
- * @return string the version of Prado framework
- */
- public static function getVersion()
- {
- return '3.0RC1';
- }
-
- /**
- * Initializes error handlers.
- * This method set error and exception handlers to be functions
- * defined in this class.
- */
- public static function initErrorHandlers()
- {
- /**
- * Sets error handler to be Prado::phpErrorHandler
- */
- set_error_handler(array('PradoBase','phpErrorHandler'),error_reporting());
- /**
- * Sets exception handler to be Prado::exceptionHandler
- */
- set_exception_handler(array('PradoBase','exceptionHandler'));
- }
-
- /**
- * Class autoload loader.
- * This method is provided to be invoked within an __auload() magic method.
- * @param string class name
- */
- public static function autoload($className)
- {
- include_once($className.self::CLASS_FILE_EXT);
- if(!class_exists($className,false) && !interface_exists($className,false))
- self::fatalError("Class file for '$className' cannot be found.");
- }
-
- /**
- * @return string a string that can be displayed on your Web page showing powered-by-PRADO information
- */
- public static function poweredByPrado()
- {
- return '
';
- }
-
- /**
- * PHP error handler.
- * This method should be registered as PHP error handler using
- * {@link set_error_handler}. The method throws an exception that
- * contains the error information.
- * @param integer the level of the error raised
- * @param string the error message
- * @param string the filename that the error was raised in
- * @param integer the line number the error was raised at
- */
- public static function phpErrorHandler($errno,$errstr,$errfile,$errline)
- {
- if(error_reporting()!=0)
- throw new TPhpErrorException($errno,$errstr,$errfile,$errline);
- }
-
- /**
- * Default exception handler.
- * This method should be registered as default exception handler using
- * {@link set_exception_handler}. The method tries to use the errorhandler
- * module of the Prado application to handle the exception.
- * If the application or the module does not exist, it simply echoes the
- * exception.
- * @param Exception exception that is not caught
- */
- public static function exceptionHandler($exception)
- {
- if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null)
- {
- $errorHandler->handleError(null,$exception);
- }
- else
- {
- echo $exception;
- }
- exit(1);
- }
-
- /**
- * Stores the application instance in the class static member.
- * This method helps implement a singleton pattern for TApplication.
- * Repeated invocation of this method or the application constructor
- * will cause the throw of an exception.
- * This method should only be used by framework developers.
- * @param TApplication the application instance
- * @throws TInvalidOperationException if this method is invoked twice or more.
- */
- public static function setApplication($application)
- {
- if(self::$_application!==null)
- throw new TInvalidOperationException('prado_application_singleton_required');
- self::$_application=$application;
- }
-
- /**
- * @return TApplication the application singleton, null if the singleton has not be created yet.
- */
- public static function getApplication()
- {
- return self::$_application;
- }
-
- /**
- * @return string the path of the framework
- */
- public static function getFrameworkPath()
- {
- return PRADO_DIR;
- }
-
- /**
- * Serializes a data.
- * The original PHP serialize function has a bug that may not serialize
- * properly an object.
- * @param mixed data to be serialized
- * @return string the serialized data
- */
- public static function serialize($data)
- {
- $arr[0]=$data;
- return serialize($arr);
- }
-
- /**
- * Unserializes a data.
- * The original PHP unserialize function has a bug that may not unserialize
- * properly an object.
- * @param string data to be unserialized
- * @return mixed unserialized data, null if unserialize failed
- */
- public static function unserialize($str)
- {
- $arr=unserialize($str);
- return isset($arr[0])?$arr[0]:null;
- }
-
- /**
- * Creates a component with the specified type.
- * A component type can be either the component class name
- * or a namespace referring to the path of the component class file.
- * For example, 'TButton', 'System.Web.UI.WebControls.TButton' are both
- * valid component type.
- * This method can also pass parameters to component constructors.
- * All paramters passed to this method except the first one (the component type)
- * will be supplied as component constructor paramters.
- * @param string component type
- * @return TComponent component instance of the specified type
- * @throws TInvalidDataValueException if the component type is unknown
- */
- public static function createComponent($type)
- {
- self::using($type);
- if(($pos=strrpos($type,'.'))!==false)
- $type=substr($type,$pos+1);
- if(($n=func_num_args())>1)
- {
- $args=func_get_args();
- $s='$args[1]';
- for($i=2;$i<$n;++$i)
- $s.=",\$args[$i]";
- eval("\$component=new $type($s);");
- return $component;
- }
- else
- return new $type;
- }
-
- /**
- * Uses a namespace.
- * A namespace ending with an asterisk '*' refers to a directory, otherwise it represents a PHP file.
- * If the namespace corresponds to a directory, the directory will be appended
- * to the include path. If the namespace corresponds to a file, it will be included (include_once).
- * @param string namespace to be used
- * @throws TInvalidDataValueException if the namespace is invalid
- */
- public static function using($namespace)
- {
- if(isset(self::$_usings[$namespace]) || class_exists($namespace,false))
- return;
- if(($pos=strrpos($namespace,'.'))===false) // a class name
- {
- try
- {
- include_once($namespace.self::CLASS_FILE_EXT);
- }
- catch(Exception $e)
- {
- if(!class_exists($namespace,false))
- throw new TInvalidOperationException('prado_component_unknown',$namespace);
- else
- throw $e;
- }
- }
- else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null)
- {
- $className=substr($namespace,$pos+1);
- if($className==='*') // a directory
- {
- if(is_dir($path))
- {
- self::$_usings[$namespace]=$path;
- set_include_path(get_include_path().PATH_SEPARATOR.$path);
- }
- else
- throw new TInvalidDataValueException('prado_using_invalid',$namespace);
- }
- else // a file
- {
- if(is_file($path))
- {
- self::$_usings[$namespace]=$path;
- if(!class_exists($className,false))
- {
- try
- {
- include_once($path);
- }
- catch(Exception $e)
- {
- if(!class_exists($className,false))
- throw new TInvalidOperationException('prado_component_unknown',$className);
- else
- throw $e;
- }
- }
- }
- else
- throw new TInvalidDataValueException('prado_using_invalid',$namespace);
- }
- }
- else
- throw new TInvalidDataValueException('prado_using_invalid',$namespace);
- }
-
- /**
- * Translates a namespace into a file path.
- * The first segment of the namespace is considered as a path alias
- * which is replaced with the actual path. The rest segments are
- * subdirectory names appended to the aliased path.
- * If the namespace ends with an asterisk '*', it represents a directory;
- * Otherwise it represents a file whose extension name is specified by the second parameter (defaults to empty).
- * Note, this method does not ensure the existence of the resulting file path.
- * @param string namespace
- * @param string extension to be appended if the namespace refers to a file
- * @return string file path corresponding to the namespace, null if namespace is invalid
- */
- public static function getPathOfNamespace($namespace,$ext='')
- {
- if(isset(self::$_usings[$namespace]))
- return self::$_usings[$namespace];
- else if(isset(self::$_aliases[$namespace]))
- return self::$_aliases[$namespace];
- else
- {
- $segs=explode('.',$namespace);
- $alias=array_shift($segs);
- if(($file=array_pop($segs))!==null && ($root=self::getPathOfAlias($alias))!==null)
- return rtrim($root.'/'.implode('/',$segs),'/').(($file==='*')?'':'/'.$file.$ext);
- else
- return null;
- }
- }
-
- /**
- * @param string alias to the path
- * @return string the path corresponding to the alias, null if alias not defined.
- */
- public static function getPathOfAlias($alias)
- {
- return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null;
- }
-
- /**
- * @param string alias to the path
- * @param string the path corresponding to the alias
- * @throws TInvalidOperationException if the alias is already defined
- * @throws TInvalidDataValueException if the path is not a valid file path
- */
- public static function setPathOfAlias($alias,$path)
- {
- if(isset(self::$_aliases[$alias]))
- throw new TInvalidOperationException('prado_alias_redefined',$alias);
- else if(($rp=realpath($path))!==false && is_dir($rp))
- {
- if(strpos($alias,'.')===false)
- self::$_aliases[$alias]=$rp;
- else
- throw new TInvalidDataValueException('prado_aliasname_invalid',$alias);
- }
- else
- throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path);
- }
-
- /**
- * Fatal error handler.
- * This method displays an error message together with the current call stack.
- * The application will exit after calling this method.
- * @param string error message
- */
- public static function fatalError($msg)
- {
- echo 'Fatal Error
';
- echo ''.$msg.'
';
- if(!function_exists('debug_backtrace'))
- return;
- echo 'Debug Backtrace
';
- echo '';
- $index=-1;
- foreach(debug_backtrace() as $t)
- {
- $index++;
- if($index==0) // hide the backtrace of this function
- continue;
- echo '#'.$index.' ';
- if(isset($t['file']))
- echo basename($t['file']) . ':' . $t['line'];
- else
- echo '';
- echo ' -- ';
- if(isset($t['class']))
- echo $t['class'] . $t['type'];
- echo $t['function'];
- if(isset($t['args']) && sizeof($t['args']) > 0)
- echo '(...)';
- else
- echo '()';
- echo "\n";
- }
- echo '
';
- exit(1);
- }
-
- /**
- * Returns a list of user preferred languages.
- * The languages are returned as an array. Each array element
- * represents a single language preference. The languages are ordered
- * according to user preferences. The first language is the most preferred.
- * @return array list of user preferred languages.
- */
- public static function getUserLanguages()
- {
- static $languages=null;
- if($languages===null)
- {
- if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
- $languages[0]='en';
- else
- {
- $languages=array();
- foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language)
- {
- $array=split(';q=',trim($language));
- $languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0;
- }
- arsort($languages);
- $languages=array_keys($languages);
- if(empty($languages))
- $languages[0]='en';
- }
- }
- return $languages;
- }
-
- /**
- * Returns the most preferred language by the client user.
- * @return string the most preferred language by the client user, defaults to English.
- */
- public static function getPreferredLanguage()
- {
- static $language=null;
- if($language===null)
- {
- $langs=Prado::getUserLanguages();
- $lang=explode('-',$langs[0]);
- if(empty($lang[0]) || !ctype_alpha($lang[0]))
- $language='en';
- else
- $language=$lang[0];
- }
- return $language;
- }
-
- /**
- * Writes a log message.
- * This method wraps {@link log()} by checking the application mode.
- * When the application is in Debug mode, debug backtrace information is appended
- * to the message and the message is logged at DEBUG level.
- * When the application is in Performance mode, this method does nothing.
- * Otherwise, the message is logged at INFO level.
- * @param string message to be logged
- * @param string category of the message
- * @see log, getLogger
- */
- public static function trace($msg,$category='Uncategorized')
- {
- if(self::$_application && self::$_application->getMode()===TApplication::STATE_PERFORMANCE)
- return;
- if(!self::$_application || self::$_application->getMode()===TApplication::STATE_DEBUG)
- {
- $trace=debug_backtrace();
- if(isset($trace[0]['file']) && isset($trace[0]['line']))
- $msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})";
- $level=TLogger::DEBUG;
- }
- else
- $level=TLogger::INFO;
- self::log($msg,$level,$category);
- }
-
- /**
- * Logs a message.
- * Messages logged by this method may be retrieved via {@link TLogger::getLogs}
- * and may be recorded in different media, such as file, email, database, using
- * {@link TLogRouter}.
- * @param string message to be logged
- * @param integer level of the message. Valid values include
- * TLogger::DEBUG, TLogger::INFO, TLogger::NOTICE, TLogger::WARNING,
- * TLogger::ERROR, TLogger::ALERT, TLogger::FATAL.
- * @param string category of the message
- */
- public static function log($msg,$level=TLogger::INFO,$category='Uncategorized')
- {
- if(self::$_logger===null)
- self::$_logger=new TLogger;
- self::$_logger->log($msg,$level,$category);
- }
-
- /**
- * @return TLogger message logger
- */
- public static function getLogger()
- {
- if(self::$_logger===null)
- self::$_logger=new TLogger;
- return self::$_logger;
- }
-
- /**
- * Converts a variable into a string representation.
- * This method achieves the similar functionality as var_dump and print_r
- * but is more robust when handling complex objects such as PRADO controls.
- * @param mixed variable to be dumped
- * @param integer maximum depth that the dumper should go into the variable. Defaults to 10.
- * @return string the string representation of the variable
- */
- public static function varDump($var,$depth=10)
- {
- return TVarDumper::dump($var,$depth);
- }
-}
-
-/**
- * TTextWriter class.
- *
- * TTextWriter implements a memory-based text writer.
- * Content written by TTextWriter are stored in memory
- * and can be obtained by calling {@link flush()}.
- *
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System
- * @since 3.0
- */
-class TTextWriter extends TComponent implements ITextWriter
-{
- private $_str='';
-
- /**
- * Flushes the content that has been written.
- * @return string the content being flushed
- */
- public function flush()
- {
- $str=$this->_str;
- $this->_str='';
- return $str;
- }
-
- /**
- * Writes a string.
- * @param string string to be written
- */
- public function write($str)
- {
- $this->_str.=$str;
- }
-
- /**
- * Writers a string and terminates it with a newline.
- * @param string content to be written
- * @see write
- */
- public function writeLine($str='')
- {
- $this->write($str."\n");
- }
-}
-
-if(version_compare(phpversion(),'5.1.0','>='))
-{
- /**
- * TReflectionClass class.
- * This class is written to cope with the incompatibility between different PHP versions.
- * It is equivalent to ReflectionClass if PHP version >= 5.1.0
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System
- * @since 3.0
- */
- class TReflectionClass extends ReflectionClass
- {
- }
-}
-else // PHP < 5.1.0
-{
- /**
- * TReflectionClass class.
- * This class is written to cope with the incompatibility between different PHP versions.
- * It mainly provides a way to detect if a method exists for a given class name.
- *
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System
- * @since 3.0
- */
- class TReflectionClass extends ReflectionClass
- {
- /**
- * @param string method name
- * @return boolean whether the method exists
- */
- public function hasMethod($method)
- {
- try
- {
- return $this->getMethod($method)!==null;
- }
- catch(Exception $e)
- {
- return false;
- }
- }
-
- /**
- * @param string property name
- * @return boolean whether the property exists
- */
- public function hasProperty($property)
- {
- try
- {
- return $this->getProperty($property)!==null;
- }
- catch(Exception $e)
- {
- return false;
- }
- }
- }
-
- if(!function_exists('property_exists'))
- {
- /**
- * Detects whether an object contains the specified member variable.
- * @param object
- * @param string member variable (property) name
- * @return boolean
- */
- function property_exists($object, $property)
- {
- if(is_object($object))
- return array_key_exists($property, get_object_vars($object));
- else
- return false;
- }
- }
-}
-
-?>
\ No newline at end of file
diff --git a/framework/interfaces.php b/framework/interfaces.php
new file mode 100644
index 00000000..f63da347
--- /dev/null
+++ b/framework/interfaces.php
@@ -0,0 +1,172 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $Date: $
+ * @package System
+ */
+
+/**
+ * IModule interface.
+ *
+ * This interface must be implemented by application modules.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System
+ * @since 3.0
+ */
+interface IModule
+{
+ /**
+ * Initializes the module.
+ * @param TXmlElement the configuration for the module
+ */
+ public function init($config);
+ /**
+ * @return string ID of the module
+ */
+ public function getID();
+ /**
+ * @param string ID of the module
+ */
+ public function setID($id);
+}
+
+/**
+ * IService interface.
+ *
+ * This interface must be implemented by services.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System
+ * @since 3.0
+ */
+interface IService
+{
+ /**
+ * Initializes the service.
+ * @param TXmlElement the configuration for the service
+ */
+ public function init($config);
+ /**
+ * @return string ID of the service
+ */
+ public function getID();
+ /**
+ * @param string ID of the service
+ */
+ public function setID($id);
+ /**
+ * Runs the service.
+ */
+ public function run();
+}
+
+/**
+ * ITextWriter interface.
+ *
+ * This interface must be implemented by writers.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System
+ * @since 3.0
+ */
+interface ITextWriter
+{
+ /**
+ * Writes a string.
+ * @param string string to be written
+ */
+ public function write($str);
+ /**
+ * Flushes the content that has been written.
+ */
+ public function flush();
+}
+
+
+/**
+ * IUser interface.
+ *
+ * This interface must be implemented by user objects.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System
+ * @since 3.0
+ */
+interface IUser
+{
+ /**
+ * @return string username
+ */
+ public function getName();
+ /**
+ * @param string username
+ */
+ public function setName($value);
+ /**
+ * @return boolean if the user is a guest
+ */
+ public function getIsGuest();
+ /**
+ * @param boolean if the user is a guest
+ */
+ public function setIsGuest($value);
+ /**
+ * @return array list of roles that the user is of
+ */
+ public function getRoles();
+ /**
+ * @return array|string list of roles that the user is of. If it is a string, roles are assumed by separated by comma
+ */
+ public function setRoles($value);
+ /**
+ * @param string role to be tested
+ * @return boolean whether the user is of this role
+ */
+ public function isInRole($role);
+ /**
+ * @return string user data that is serialized and will be stored in session
+ */
+ public function saveToString();
+ /**
+ * @param string user data that is serialized and restored from session
+ * @return IUser the user object
+ */
+ public function loadFromString($string);
+}
+
+/**
+ * IStatePersister class.
+ *
+ * This interface must be implemented by all state persister classes (such as
+ * {@link TPageStatePersister}, {@link TApplicationStatePersister}.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System
+ * @since 3.0
+ */
+interface IStatePersister
+{
+ /**
+ * Loads state from a persistent storage.
+ * @return mixed the state
+ */
+ public function load();
+ /**
+ * Saves state into a persistent storage.
+ * @param mixed the state to be saved
+ */
+ public function save($state);
+}
+
+?>
\ No newline at end of file
diff --git a/framework/prado.php b/framework/prado.php
index 59268105..d55898b4 100644
--- a/framework/prado.php
+++ b/framework/prado.php
@@ -4,8 +4,10 @@
*
* This file is intended to be included in the entry script of Prado applications.
* It defines Prado class by extending PradoBase, a static class providing globally
- * available functionalities to Prado applications. It also sets PHP error and
- * exception handler functions, and provides a __autoload function which automatically
+ * available functionalities that enable PRADO component model and error handling mechanism.
+ *
+ * By including this file, the PHP error and exception handlers are set as
+ * PRADO handlers, and an __autoload function is provided that automatiically
* loads a class file if the class is not defined.
*
* @author Qiang Xue
@@ -17,9 +19,9 @@
*/
/**
- * Includes the Prado core header file
+ * Includes the PradoBase class file
*/
-require_once(dirname(__FILE__).'/core.php');
+require_once(dirname(__FILE__).'/PradoBase.php');
/**
* Defines Prado class if not defined.
--
cgit v1.2.3