10406 lines
		
	
	
		
			298 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			10406 lines
		
	
	
		
			298 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * Yii bootstrap file.
 | |
|  *
 | |
|  * This file is automatically generated using 'build lite' command.
 | |
|  * It is the result of merging commonly used Yii class files with
 | |
|  * comments and trace statements removed away.
 | |
|  *
 | |
|  * By using this file instead of yii.php, an Yii application may
 | |
|  * improve performance due to the reduction of PHP parsing time.
 | |
|  * The performance improvement is especially obvious when PHP APC extension
 | |
|  * is enabled.
 | |
|  *
 | |
|  * DO NOT modify this file manually.
 | |
|  *
 | |
|  * @author Qiang Xue <qiang.xue@gmail.com>
 | |
|  * @link http://www.yiiframework.com/
 | |
|  * @copyright 2008-2013 Yii Software LLC
 | |
|  * @license http://www.yiiframework.com/license/
 | |
|  * @version $Id: $
 | |
|  * @since 1.0
 | |
|  */
 | |
| 
 | |
| 
 | |
| defined('YII_BEGIN_TIME') or define('YII_BEGIN_TIME',microtime(true));
 | |
| defined('YII_DEBUG') or define('YII_DEBUG',false);
 | |
| defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',0);
 | |
| defined('YII_ENABLE_EXCEPTION_HANDLER') or define('YII_ENABLE_EXCEPTION_HANDLER',true);
 | |
| defined('YII_ENABLE_ERROR_HANDLER') or define('YII_ENABLE_ERROR_HANDLER',true);
 | |
| defined('YII_PATH') or define('YII_PATH',dirname(__FILE__));
 | |
| defined('YII_ZII_PATH') or define('YII_ZII_PATH',YII_PATH.DIRECTORY_SEPARATOR.'zii');
 | |
| class YiiBase
 | |
| {
 | |
| 	public static $classMap=array();
 | |
| 	public static $enableIncludePath=true;
 | |
| 	private static $_aliases=array('system'=>YII_PATH,'zii'=>YII_ZII_PATH); // alias => path
 | |
| 	private static $_imports=array();					// alias => class name or directory
 | |
| 	private static $_includePaths;						// list of include paths
 | |
| 	private static $_app;
 | |
| 	private static $_logger;
 | |
| 	public static function getVersion()
 | |
| 	{
 | |
| 		return '1.1.14';
 | |
| 	}
 | |
| 	public static function createWebApplication($config=null)
 | |
| 	{
 | |
| 		return self::createApplication('CWebApplication',$config);
 | |
| 	}
 | |
| 	public static function createConsoleApplication($config=null)
 | |
| 	{
 | |
| 		return self::createApplication('CConsoleApplication',$config);
 | |
| 	}
 | |
| 	public static function createApplication($class,$config=null)
 | |
| 	{
 | |
| 		return new $class($config);
 | |
| 	}
 | |
| 	public static function app()
 | |
| 	{
 | |
| 		return self::$_app;
 | |
| 	}
 | |
| 	public static function setApplication($app)
 | |
| 	{
 | |
| 		if(self::$_app===null || $app===null)
 | |
| 			self::$_app=$app;
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','Yii application can only be created once.'));
 | |
| 	}
 | |
| 	public static function getFrameworkPath()
 | |
| 	{
 | |
| 		return YII_PATH;
 | |
| 	}
 | |
| 	public static function createComponent($config)
 | |
| 	{
 | |
| 		if(is_string($config))
 | |
| 		{
 | |
| 			$type=$config;
 | |
| 			$config=array();
 | |
| 		}
 | |
| 		elseif(isset($config['class']))
 | |
| 		{
 | |
| 			$type=$config['class'];
 | |
| 			unset($config['class']);
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','Object configuration must be an array containing a "class" element.'));
 | |
| 		if(!class_exists($type,false))
 | |
| 			$type=Yii::import($type,true);
 | |
| 		if(($n=func_num_args())>1)
 | |
| 		{
 | |
| 			$args=func_get_args();
 | |
| 			if($n===2)
 | |
| 				$object=new $type($args[1]);
 | |
| 			elseif($n===3)
 | |
| 				$object=new $type($args[1],$args[2]);
 | |
| 			elseif($n===4)
 | |
| 				$object=new $type($args[1],$args[2],$args[3]);
 | |
| 			else
 | |
| 			{
 | |
| 				unset($args[0]);
 | |
| 				$class=new ReflectionClass($type);
 | |
| 				// Note: ReflectionClass::newInstanceArgs() is available for PHP 5.1.3+
 | |
| 				// $object=$class->newInstanceArgs($args);
 | |
| 				$object=call_user_func_array(array($class,'newInstance'),$args);
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 			$object=new $type;
 | |
| 		foreach($config as $key=>$value)
 | |
| 			$object->$key=$value;
 | |
| 		return $object;
 | |
| 	}
 | |
| 	public static function import($alias,$forceInclude=false)
 | |
| 	{
 | |
| 		if(isset(self::$_imports[$alias]))  // previously imported
 | |
| 			return self::$_imports[$alias];
 | |
| 		if(class_exists($alias,false) || interface_exists($alias,false))
 | |
| 			return self::$_imports[$alias]=$alias;
 | |
| 		if(($pos=strrpos($alias,'\\'))!==false) // a class name in PHP 5.3 namespace format
 | |
| 		{
 | |
| 			$namespace=str_replace('\\','.',ltrim(substr($alias,0,$pos),'\\'));
 | |
| 			if(($path=self::getPathOfAlias($namespace))!==false)
 | |
| 			{
 | |
| 				$classFile=$path.DIRECTORY_SEPARATOR.substr($alias,$pos+1).'.php';
 | |
| 				if($forceInclude)
 | |
| 				{
 | |
| 					if(is_file($classFile))
 | |
| 						require($classFile);
 | |
| 					else
 | |
| 						throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing PHP file and the file is readable.',array('{alias}'=>$alias)));
 | |
| 					self::$_imports[$alias]=$alias;
 | |
| 				}
 | |
| 				else
 | |
| 					self::$classMap[$alias]=$classFile;
 | |
| 				return $alias;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				// try to autoload the class with an autoloader
 | |
| 				if (class_exists($alias,true))
 | |
| 					return self::$_imports[$alias]=$alias;
 | |
| 				else
 | |
| 					throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing directory or file.',
 | |
| 						array('{alias}'=>$namespace)));
 | |
| 			}
 | |
| 		}
 | |
| 		if(($pos=strrpos($alias,'.'))===false)  // a simple class name
 | |
| 		{
 | |
| 			if($forceInclude && self::autoload($alias))
 | |
| 				self::$_imports[$alias]=$alias;
 | |
| 			return $alias;
 | |
| 		}
 | |
| 		$className=(string)substr($alias,$pos+1);
 | |
| 		$isClass=$className!=='*';
 | |
| 		if($isClass && (class_exists($className,false) || interface_exists($className,false)))
 | |
| 			return self::$_imports[$alias]=$className;
 | |
| 		if(($path=self::getPathOfAlias($alias))!==false)
 | |
| 		{
 | |
| 			if($isClass)
 | |
| 			{
 | |
| 				if($forceInclude)
 | |
| 				{
 | |
| 					if(is_file($path.'.php'))
 | |
| 						require($path.'.php');
 | |
| 					else
 | |
| 						throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing PHP file and the file is readable.',array('{alias}'=>$alias)));
 | |
| 					self::$_imports[$alias]=$className;
 | |
| 				}
 | |
| 				else
 | |
| 					self::$classMap[$className]=$path.'.php';
 | |
| 				return $className;
 | |
| 			}
 | |
| 			else  // a directory
 | |
| 			{
 | |
| 				if(self::$_includePaths===null)
 | |
| 				{
 | |
| 					self::$_includePaths=array_unique(explode(PATH_SEPARATOR,get_include_path()));
 | |
| 					if(($pos=array_search('.',self::$_includePaths,true))!==false)
 | |
| 						unset(self::$_includePaths[$pos]);
 | |
| 				}
 | |
| 				array_unshift(self::$_includePaths,$path);
 | |
| 				if(self::$enableIncludePath && set_include_path('.'.PATH_SEPARATOR.implode(PATH_SEPARATOR,self::$_includePaths))===false)
 | |
| 					self::$enableIncludePath=false;
 | |
| 				return self::$_imports[$alias]=$path;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','Alias "{alias}" is invalid. Make sure it points to an existing directory or file.',
 | |
| 				array('{alias}'=>$alias)));
 | |
| 	}
 | |
| 	public static function getPathOfAlias($alias)
 | |
| 	{
 | |
| 		if(isset(self::$_aliases[$alias]))
 | |
| 			return self::$_aliases[$alias];
 | |
| 		elseif(($pos=strpos($alias,'.'))!==false)
 | |
| 		{
 | |
| 			$rootAlias=substr($alias,0,$pos);
 | |
| 			if(isset(self::$_aliases[$rootAlias]))
 | |
| 				return self::$_aliases[$alias]=rtrim(self::$_aliases[$rootAlias].DIRECTORY_SEPARATOR.str_replace('.',DIRECTORY_SEPARATOR,substr($alias,$pos+1)),'*'.DIRECTORY_SEPARATOR);
 | |
| 			elseif(self::$_app instanceof CWebApplication)
 | |
| 			{
 | |
| 				if(self::$_app->findModule($rootAlias)!==null)
 | |
| 					return self::getPathOfAlias($alias);
 | |
| 			}
 | |
| 		}
 | |
| 		return false;
 | |
| 	}
 | |
| 	public static function setPathOfAlias($alias,$path)
 | |
| 	{
 | |
| 		if(empty($path))
 | |
| 			unset(self::$_aliases[$alias]);
 | |
| 		else
 | |
| 			self::$_aliases[$alias]=rtrim($path,'\\/');
 | |
| 	}
 | |
| 	public static function autoload($className)
 | |
| 	{
 | |
| 		// use include so that the error PHP file may appear
 | |
| 		if(isset(self::$classMap[$className]))
 | |
| 			include(self::$classMap[$className]);
 | |
| 		elseif(isset(self::$_coreClasses[$className]))
 | |
| 			include(YII_PATH.self::$_coreClasses[$className]);
 | |
| 		else
 | |
| 		{
 | |
| 			// include class file relying on include_path
 | |
| 			if(strpos($className,'\\')===false)  // class without namespace
 | |
| 			{
 | |
| 				if(self::$enableIncludePath===false)
 | |
| 				{
 | |
| 					foreach(self::$_includePaths as $path)
 | |
| 					{
 | |
| 						$classFile=$path.DIRECTORY_SEPARATOR.$className.'.php';
 | |
| 						if(is_file($classFile))
 | |
| 						{
 | |
| 							include($classFile);
 | |
| 							if(YII_DEBUG && basename(realpath($classFile))!==$className.'.php')
 | |
| 								throw new CException(Yii::t('yii','Class name "{class}" does not match class file "{file}".', array(
 | |
| 									'{class}'=>$className,
 | |
| 									'{file}'=>$classFile,
 | |
| 								)));
 | |
| 							break;
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				else
 | |
| 					include($className.'.php');
 | |
| 			}
 | |
| 			else  // class name with namespace in PHP 5.3
 | |
| 			{
 | |
| 				$namespace=str_replace('\\','.',ltrim($className,'\\'));
 | |
| 				if(($path=self::getPathOfAlias($namespace))!==false)
 | |
| 					include($path.'.php');
 | |
| 				else
 | |
| 					return false;
 | |
| 			}
 | |
| 			return class_exists($className,false) || interface_exists($className,false);
 | |
| 		}
 | |
| 		return true;
 | |
| 	}
 | |
| 	public static function trace($msg,$category='application')
 | |
| 	{
 | |
| 		if(YII_DEBUG)
 | |
| 			self::log($msg,CLogger::LEVEL_TRACE,$category);
 | |
| 	}
 | |
| 	public static function log($msg,$level=CLogger::LEVEL_INFO,$category='application')
 | |
| 	{
 | |
| 		if(self::$_logger===null)
 | |
| 			self::$_logger=new CLogger;
 | |
| 		if(YII_DEBUG && YII_TRACE_LEVEL>0 && $level!==CLogger::LEVEL_PROFILE)
 | |
| 		{
 | |
| 			$traces=debug_backtrace();
 | |
| 			$count=0;
 | |
| 			foreach($traces as $trace)
 | |
| 			{
 | |
| 				if(isset($trace['file'],$trace['line']) && strpos($trace['file'],YII_PATH)!==0)
 | |
| 				{
 | |
| 					$msg.="\nin ".$trace['file'].' ('.$trace['line'].')';
 | |
| 					if(++$count>=YII_TRACE_LEVEL)
 | |
| 						break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		self::$_logger->log($msg,$level,$category);
 | |
| 	}
 | |
| 	public static function beginProfile($token,$category='application')
 | |
| 	{
 | |
| 		self::log('begin:'.$token,CLogger::LEVEL_PROFILE,$category);
 | |
| 	}
 | |
| 	public static function endProfile($token,$category='application')
 | |
| 	{
 | |
| 		self::log('end:'.$token,CLogger::LEVEL_PROFILE,$category);
 | |
| 	}
 | |
| 	public static function getLogger()
 | |
| 	{
 | |
| 		if(self::$_logger!==null)
 | |
| 			return self::$_logger;
 | |
| 		else
 | |
| 			return self::$_logger=new CLogger;
 | |
| 	}
 | |
| 	public static function setLogger($logger)
 | |
| 	{
 | |
| 		self::$_logger=$logger;
 | |
| 	}
 | |
| 	public static function powered()
 | |
| 	{
 | |
| 		return Yii::t('yii','Powered by {yii}.', array('{yii}'=>'<a href="http://www.yiiframework.com/" rel="external">Yii Framework</a>'));
 | |
| 	}
 | |
| 	public static function t($category,$message,$params=array(),$source=null,$language=null)
 | |
| 	{
 | |
| 		if(self::$_app!==null)
 | |
| 		{
 | |
| 			if($source===null)
 | |
| 				$source=($category==='yii'||$category==='zii')?'coreMessages':'messages';
 | |
| 			if(($source=self::$_app->getComponent($source))!==null)
 | |
| 				$message=$source->translate($category,$message,$language);
 | |
| 		}
 | |
| 		if($params===array())
 | |
| 			return $message;
 | |
| 		if(!is_array($params))
 | |
| 			$params=array($params);
 | |
| 		if(isset($params[0])) // number choice
 | |
| 		{
 | |
| 			if(strpos($message,'|')!==false)
 | |
| 			{
 | |
| 				if(strpos($message,'#')===false)
 | |
| 				{
 | |
| 					$chunks=explode('|',$message);
 | |
| 					$expressions=self::$_app->getLocale($language)->getPluralRules();
 | |
| 					if($n=min(count($chunks),count($expressions)))
 | |
| 					{
 | |
| 						for($i=0;$i<$n;$i++)
 | |
| 							$chunks[$i]=$expressions[$i].'#'.$chunks[$i];
 | |
| 						$message=implode('|',$chunks);
 | |
| 					}
 | |
| 				}
 | |
| 				$message=CChoiceFormat::format($message,$params[0]);
 | |
| 			}
 | |
| 			if(!isset($params['{n}']))
 | |
| 				$params['{n}']=$params[0];
 | |
| 			unset($params[0]);
 | |
| 		}
 | |
| 		return $params!==array() ? strtr($message,$params) : $message;
 | |
| 	}
 | |
| 	public static function registerAutoloader($callback, $append=false)
 | |
| 	{
 | |
| 		if($append)
 | |
| 		{
 | |
| 			self::$enableIncludePath=false;
 | |
| 			spl_autoload_register($callback);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			spl_autoload_unregister(array('YiiBase','autoload'));
 | |
| 			spl_autoload_register($callback);
 | |
| 			spl_autoload_register(array('YiiBase','autoload'));
 | |
| 		}
 | |
| 	}
 | |
| 	private static $_coreClasses=array(
 | |
| 		'CApplication' => '/base/CApplication.php',
 | |
| 		'CApplicationComponent' => '/base/CApplicationComponent.php',
 | |
| 		'CBehavior' => '/base/CBehavior.php',
 | |
| 		'CComponent' => '/base/CComponent.php',
 | |
| 		'CErrorEvent' => '/base/CErrorEvent.php',
 | |
| 		'CErrorHandler' => '/base/CErrorHandler.php',
 | |
| 		'CException' => '/base/CException.php',
 | |
| 		'CExceptionEvent' => '/base/CExceptionEvent.php',
 | |
| 		'CHttpException' => '/base/CHttpException.php',
 | |
| 		'CModel' => '/base/CModel.php',
 | |
| 		'CModelBehavior' => '/base/CModelBehavior.php',
 | |
| 		'CModelEvent' => '/base/CModelEvent.php',
 | |
| 		'CModule' => '/base/CModule.php',
 | |
| 		'CSecurityManager' => '/base/CSecurityManager.php',
 | |
| 		'CStatePersister' => '/base/CStatePersister.php',
 | |
| 		'CApcCache' => '/caching/CApcCache.php',
 | |
| 		'CCache' => '/caching/CCache.php',
 | |
| 		'CDbCache' => '/caching/CDbCache.php',
 | |
| 		'CDummyCache' => '/caching/CDummyCache.php',
 | |
| 		'CEAcceleratorCache' => '/caching/CEAcceleratorCache.php',
 | |
| 		'CFileCache' => '/caching/CFileCache.php',
 | |
| 		'CMemCache' => '/caching/CMemCache.php',
 | |
| 		'CRedisCache' => '/caching/CRedisCache.php',
 | |
| 		'CWinCache' => '/caching/CWinCache.php',
 | |
| 		'CXCache' => '/caching/CXCache.php',
 | |
| 		'CZendDataCache' => '/caching/CZendDataCache.php',
 | |
| 		'CCacheDependency' => '/caching/dependencies/CCacheDependency.php',
 | |
| 		'CChainedCacheDependency' => '/caching/dependencies/CChainedCacheDependency.php',
 | |
| 		'CDbCacheDependency' => '/caching/dependencies/CDbCacheDependency.php',
 | |
| 		'CDirectoryCacheDependency' => '/caching/dependencies/CDirectoryCacheDependency.php',
 | |
| 		'CExpressionDependency' => '/caching/dependencies/CExpressionDependency.php',
 | |
| 		'CFileCacheDependency' => '/caching/dependencies/CFileCacheDependency.php',
 | |
| 		'CGlobalStateCacheDependency' => '/caching/dependencies/CGlobalStateCacheDependency.php',
 | |
| 		'CAttributeCollection' => '/collections/CAttributeCollection.php',
 | |
| 		'CConfiguration' => '/collections/CConfiguration.php',
 | |
| 		'CList' => '/collections/CList.php',
 | |
| 		'CListIterator' => '/collections/CListIterator.php',
 | |
| 		'CMap' => '/collections/CMap.php',
 | |
| 		'CMapIterator' => '/collections/CMapIterator.php',
 | |
| 		'CQueue' => '/collections/CQueue.php',
 | |
| 		'CQueueIterator' => '/collections/CQueueIterator.php',
 | |
| 		'CStack' => '/collections/CStack.php',
 | |
| 		'CStackIterator' => '/collections/CStackIterator.php',
 | |
| 		'CTypedList' => '/collections/CTypedList.php',
 | |
| 		'CTypedMap' => '/collections/CTypedMap.php',
 | |
| 		'CConsoleApplication' => '/console/CConsoleApplication.php',
 | |
| 		'CConsoleCommand' => '/console/CConsoleCommand.php',
 | |
| 		'CConsoleCommandBehavior' => '/console/CConsoleCommandBehavior.php',
 | |
| 		'CConsoleCommandEvent' => '/console/CConsoleCommandEvent.php',
 | |
| 		'CConsoleCommandRunner' => '/console/CConsoleCommandRunner.php',
 | |
| 		'CHelpCommand' => '/console/CHelpCommand.php',
 | |
| 		'CDbCommand' => '/db/CDbCommand.php',
 | |
| 		'CDbConnection' => '/db/CDbConnection.php',
 | |
| 		'CDbDataReader' => '/db/CDbDataReader.php',
 | |
| 		'CDbException' => '/db/CDbException.php',
 | |
| 		'CDbMigration' => '/db/CDbMigration.php',
 | |
| 		'CDbTransaction' => '/db/CDbTransaction.php',
 | |
| 		'CActiveFinder' => '/db/ar/CActiveFinder.php',
 | |
| 		'CActiveRecord' => '/db/ar/CActiveRecord.php',
 | |
| 		'CActiveRecordBehavior' => '/db/ar/CActiveRecordBehavior.php',
 | |
| 		'CDbColumnSchema' => '/db/schema/CDbColumnSchema.php',
 | |
| 		'CDbCommandBuilder' => '/db/schema/CDbCommandBuilder.php',
 | |
| 		'CDbCriteria' => '/db/schema/CDbCriteria.php',
 | |
| 		'CDbExpression' => '/db/schema/CDbExpression.php',
 | |
| 		'CDbSchema' => '/db/schema/CDbSchema.php',
 | |
| 		'CDbTableSchema' => '/db/schema/CDbTableSchema.php',
 | |
| 		'CMssqlColumnSchema' => '/db/schema/mssql/CMssqlColumnSchema.php',
 | |
| 		'CMssqlCommandBuilder' => '/db/schema/mssql/CMssqlCommandBuilder.php',
 | |
| 		'CMssqlPdoAdapter' => '/db/schema/mssql/CMssqlPdoAdapter.php',
 | |
| 		'CMssqlSchema' => '/db/schema/mssql/CMssqlSchema.php',
 | |
| 		'CMssqlSqlsrvPdoAdapter' => '/db/schema/mssql/CMssqlSqlsrvPdoAdapter.php',
 | |
| 		'CMssqlTableSchema' => '/db/schema/mssql/CMssqlTableSchema.php',
 | |
| 		'CMysqlColumnSchema' => '/db/schema/mysql/CMysqlColumnSchema.php',
 | |
| 		'CMysqlCommandBuilder' => '/db/schema/mysql/CMysqlCommandBuilder.php',
 | |
| 		'CMysqlSchema' => '/db/schema/mysql/CMysqlSchema.php',
 | |
| 		'CMysqlTableSchema' => '/db/schema/mysql/CMysqlTableSchema.php',
 | |
| 		'COciColumnSchema' => '/db/schema/oci/COciColumnSchema.php',
 | |
| 		'COciCommandBuilder' => '/db/schema/oci/COciCommandBuilder.php',
 | |
| 		'COciSchema' => '/db/schema/oci/COciSchema.php',
 | |
| 		'COciTableSchema' => '/db/schema/oci/COciTableSchema.php',
 | |
| 		'CPgsqlColumnSchema' => '/db/schema/pgsql/CPgsqlColumnSchema.php',
 | |
| 		'CPgsqlCommandBuilder' => '/db/schema/pgsql/CPgsqlCommandBuilder.php',
 | |
| 		'CPgsqlSchema' => '/db/schema/pgsql/CPgsqlSchema.php',
 | |
| 		'CPgsqlTableSchema' => '/db/schema/pgsql/CPgsqlTableSchema.php',
 | |
| 		'CSqliteColumnSchema' => '/db/schema/sqlite/CSqliteColumnSchema.php',
 | |
| 		'CSqliteCommandBuilder' => '/db/schema/sqlite/CSqliteCommandBuilder.php',
 | |
| 		'CSqliteSchema' => '/db/schema/sqlite/CSqliteSchema.php',
 | |
| 		'CChoiceFormat' => '/i18n/CChoiceFormat.php',
 | |
| 		'CDateFormatter' => '/i18n/CDateFormatter.php',
 | |
| 		'CDbMessageSource' => '/i18n/CDbMessageSource.php',
 | |
| 		'CGettextMessageSource' => '/i18n/CGettextMessageSource.php',
 | |
| 		'CLocale' => '/i18n/CLocale.php',
 | |
| 		'CMessageSource' => '/i18n/CMessageSource.php',
 | |
| 		'CNumberFormatter' => '/i18n/CNumberFormatter.php',
 | |
| 		'CPhpMessageSource' => '/i18n/CPhpMessageSource.php',
 | |
| 		'CGettextFile' => '/i18n/gettext/CGettextFile.php',
 | |
| 		'CGettextMoFile' => '/i18n/gettext/CGettextMoFile.php',
 | |
| 		'CGettextPoFile' => '/i18n/gettext/CGettextPoFile.php',
 | |
| 		'CChainedLogFilter' => '/logging/CChainedLogFilter.php',
 | |
| 		'CDbLogRoute' => '/logging/CDbLogRoute.php',
 | |
| 		'CEmailLogRoute' => '/logging/CEmailLogRoute.php',
 | |
| 		'CFileLogRoute' => '/logging/CFileLogRoute.php',
 | |
| 		'CLogFilter' => '/logging/CLogFilter.php',
 | |
| 		'CLogRoute' => '/logging/CLogRoute.php',
 | |
| 		'CLogRouter' => '/logging/CLogRouter.php',
 | |
| 		'CLogger' => '/logging/CLogger.php',
 | |
| 		'CProfileLogRoute' => '/logging/CProfileLogRoute.php',
 | |
| 		'CWebLogRoute' => '/logging/CWebLogRoute.php',
 | |
| 		'CDateTimeParser' => '/utils/CDateTimeParser.php',
 | |
| 		'CFileHelper' => '/utils/CFileHelper.php',
 | |
| 		'CFormatter' => '/utils/CFormatter.php',
 | |
| 		'CLocalizedFormatter' => '/utils/CLocalizedFormatter.php',
 | |
| 		'CMarkdownParser' => '/utils/CMarkdownParser.php',
 | |
| 		'CPasswordHelper' => '/utils/CPasswordHelper.php',
 | |
| 		'CPropertyValue' => '/utils/CPropertyValue.php',
 | |
| 		'CTimestamp' => '/utils/CTimestamp.php',
 | |
| 		'CVarDumper' => '/utils/CVarDumper.php',
 | |
| 		'CBooleanValidator' => '/validators/CBooleanValidator.php',
 | |
| 		'CCaptchaValidator' => '/validators/CCaptchaValidator.php',
 | |
| 		'CCompareValidator' => '/validators/CCompareValidator.php',
 | |
| 		'CDateValidator' => '/validators/CDateValidator.php',
 | |
| 		'CDefaultValueValidator' => '/validators/CDefaultValueValidator.php',
 | |
| 		'CEmailValidator' => '/validators/CEmailValidator.php',
 | |
| 		'CExistValidator' => '/validators/CExistValidator.php',
 | |
| 		'CFileValidator' => '/validators/CFileValidator.php',
 | |
| 		'CFilterValidator' => '/validators/CFilterValidator.php',
 | |
| 		'CInlineValidator' => '/validators/CInlineValidator.php',
 | |
| 		'CNumberValidator' => '/validators/CNumberValidator.php',
 | |
| 		'CRangeValidator' => '/validators/CRangeValidator.php',
 | |
| 		'CRegularExpressionValidator' => '/validators/CRegularExpressionValidator.php',
 | |
| 		'CRequiredValidator' => '/validators/CRequiredValidator.php',
 | |
| 		'CSafeValidator' => '/validators/CSafeValidator.php',
 | |
| 		'CStringValidator' => '/validators/CStringValidator.php',
 | |
| 		'CTypeValidator' => '/validators/CTypeValidator.php',
 | |
| 		'CUniqueValidator' => '/validators/CUniqueValidator.php',
 | |
| 		'CUnsafeValidator' => '/validators/CUnsafeValidator.php',
 | |
| 		'CUrlValidator' => '/validators/CUrlValidator.php',
 | |
| 		'CValidator' => '/validators/CValidator.php',
 | |
| 		'CActiveDataProvider' => '/web/CActiveDataProvider.php',
 | |
| 		'CArrayDataProvider' => '/web/CArrayDataProvider.php',
 | |
| 		'CAssetManager' => '/web/CAssetManager.php',
 | |
| 		'CBaseController' => '/web/CBaseController.php',
 | |
| 		'CCacheHttpSession' => '/web/CCacheHttpSession.php',
 | |
| 		'CClientScript' => '/web/CClientScript.php',
 | |
| 		'CController' => '/web/CController.php',
 | |
| 		'CDataProvider' => '/web/CDataProvider.php',
 | |
| 		'CDataProviderIterator' => '/web/CDataProviderIterator.php',
 | |
| 		'CDbHttpSession' => '/web/CDbHttpSession.php',
 | |
| 		'CExtController' => '/web/CExtController.php',
 | |
| 		'CFormModel' => '/web/CFormModel.php',
 | |
| 		'CHttpCookie' => '/web/CHttpCookie.php',
 | |
| 		'CHttpRequest' => '/web/CHttpRequest.php',
 | |
| 		'CHttpSession' => '/web/CHttpSession.php',
 | |
| 		'CHttpSessionIterator' => '/web/CHttpSessionIterator.php',
 | |
| 		'COutputEvent' => '/web/COutputEvent.php',
 | |
| 		'CPagination' => '/web/CPagination.php',
 | |
| 		'CSort' => '/web/CSort.php',
 | |
| 		'CSqlDataProvider' => '/web/CSqlDataProvider.php',
 | |
| 		'CTheme' => '/web/CTheme.php',
 | |
| 		'CThemeManager' => '/web/CThemeManager.php',
 | |
| 		'CUploadedFile' => '/web/CUploadedFile.php',
 | |
| 		'CUrlManager' => '/web/CUrlManager.php',
 | |
| 		'CWebApplication' => '/web/CWebApplication.php',
 | |
| 		'CWebModule' => '/web/CWebModule.php',
 | |
| 		'CWidgetFactory' => '/web/CWidgetFactory.php',
 | |
| 		'CAction' => '/web/actions/CAction.php',
 | |
| 		'CInlineAction' => '/web/actions/CInlineAction.php',
 | |
| 		'CViewAction' => '/web/actions/CViewAction.php',
 | |
| 		'CAccessControlFilter' => '/web/auth/CAccessControlFilter.php',
 | |
| 		'CAuthAssignment' => '/web/auth/CAuthAssignment.php',
 | |
| 		'CAuthItem' => '/web/auth/CAuthItem.php',
 | |
| 		'CAuthManager' => '/web/auth/CAuthManager.php',
 | |
| 		'CBaseUserIdentity' => '/web/auth/CBaseUserIdentity.php',
 | |
| 		'CDbAuthManager' => '/web/auth/CDbAuthManager.php',
 | |
| 		'CPhpAuthManager' => '/web/auth/CPhpAuthManager.php',
 | |
| 		'CUserIdentity' => '/web/auth/CUserIdentity.php',
 | |
| 		'CWebUser' => '/web/auth/CWebUser.php',
 | |
| 		'CFilter' => '/web/filters/CFilter.php',
 | |
| 		'CFilterChain' => '/web/filters/CFilterChain.php',
 | |
| 		'CHttpCacheFilter' => '/web/filters/CHttpCacheFilter.php',
 | |
| 		'CInlineFilter' => '/web/filters/CInlineFilter.php',
 | |
| 		'CForm' => '/web/form/CForm.php',
 | |
| 		'CFormButtonElement' => '/web/form/CFormButtonElement.php',
 | |
| 		'CFormElement' => '/web/form/CFormElement.php',
 | |
| 		'CFormElementCollection' => '/web/form/CFormElementCollection.php',
 | |
| 		'CFormInputElement' => '/web/form/CFormInputElement.php',
 | |
| 		'CFormStringElement' => '/web/form/CFormStringElement.php',
 | |
| 		'CGoogleApi' => '/web/helpers/CGoogleApi.php',
 | |
| 		'CHtml' => '/web/helpers/CHtml.php',
 | |
| 		'CJSON' => '/web/helpers/CJSON.php',
 | |
| 		'CJavaScript' => '/web/helpers/CJavaScript.php',
 | |
| 		'CJavaScriptExpression' => '/web/helpers/CJavaScriptExpression.php',
 | |
| 		'CPradoViewRenderer' => '/web/renderers/CPradoViewRenderer.php',
 | |
| 		'CViewRenderer' => '/web/renderers/CViewRenderer.php',
 | |
| 		'CWebService' => '/web/services/CWebService.php',
 | |
| 		'CWebServiceAction' => '/web/services/CWebServiceAction.php',
 | |
| 		'CWsdlGenerator' => '/web/services/CWsdlGenerator.php',
 | |
| 		'CActiveForm' => '/web/widgets/CActiveForm.php',
 | |
| 		'CAutoComplete' => '/web/widgets/CAutoComplete.php',
 | |
| 		'CClipWidget' => '/web/widgets/CClipWidget.php',
 | |
| 		'CContentDecorator' => '/web/widgets/CContentDecorator.php',
 | |
| 		'CFilterWidget' => '/web/widgets/CFilterWidget.php',
 | |
| 		'CFlexWidget' => '/web/widgets/CFlexWidget.php',
 | |
| 		'CHtmlPurifier' => '/web/widgets/CHtmlPurifier.php',
 | |
| 		'CInputWidget' => '/web/widgets/CInputWidget.php',
 | |
| 		'CMarkdown' => '/web/widgets/CMarkdown.php',
 | |
| 		'CMaskedTextField' => '/web/widgets/CMaskedTextField.php',
 | |
| 		'CMultiFileUpload' => '/web/widgets/CMultiFileUpload.php',
 | |
| 		'COutputCache' => '/web/widgets/COutputCache.php',
 | |
| 		'COutputProcessor' => '/web/widgets/COutputProcessor.php',
 | |
| 		'CStarRating' => '/web/widgets/CStarRating.php',
 | |
| 		'CTabView' => '/web/widgets/CTabView.php',
 | |
| 		'CTextHighlighter' => '/web/widgets/CTextHighlighter.php',
 | |
| 		'CTreeView' => '/web/widgets/CTreeView.php',
 | |
| 		'CWidget' => '/web/widgets/CWidget.php',
 | |
| 		'CCaptcha' => '/web/widgets/captcha/CCaptcha.php',
 | |
| 		'CCaptchaAction' => '/web/widgets/captcha/CCaptchaAction.php',
 | |
| 		'CBasePager' => '/web/widgets/pagers/CBasePager.php',
 | |
| 		'CLinkPager' => '/web/widgets/pagers/CLinkPager.php',
 | |
| 		'CListPager' => '/web/widgets/pagers/CListPager.php',
 | |
| 	);
 | |
| }
 | |
| spl_autoload_register(array('YiiBase','autoload'));
 | |
| class Yii extends YiiBase
 | |
| {
 | |
| }
 | |
| class CComponent
 | |
| {
 | |
| 	private $_e;
 | |
| 	private $_m;
 | |
| 	public function __get($name)
 | |
| 	{
 | |
| 		$getter='get'.$name;
 | |
| 		if(method_exists($this,$getter))
 | |
| 			return $this->$getter();
 | |
| 		elseif(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
 | |
| 		{
 | |
| 			// duplicating getEventHandlers() here for performance
 | |
| 			$name=strtolower($name);
 | |
| 			if(!isset($this->_e[$name]))
 | |
| 				$this->_e[$name]=new CList;
 | |
| 			return $this->_e[$name];
 | |
| 		}
 | |
| 		elseif(isset($this->_m[$name]))
 | |
| 			return $this->_m[$name];
 | |
| 		elseif(is_array($this->_m))
 | |
| 		{
 | |
| 			foreach($this->_m as $object)
 | |
| 			{
 | |
| 				if($object->getEnabled() && (property_exists($object,$name) || $object->canGetProperty($name)))
 | |
| 					return $object->$name;
 | |
| 			}
 | |
| 		}
 | |
| 		throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.',
 | |
| 			array('{class}'=>get_class($this), '{property}'=>$name)));
 | |
| 	}
 | |
| 	public function __set($name,$value)
 | |
| 	{
 | |
| 		$setter='set'.$name;
 | |
| 		if(method_exists($this,$setter))
 | |
| 			return $this->$setter($value);
 | |
| 		elseif(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
 | |
| 		{
 | |
| 			// duplicating getEventHandlers() here for performance
 | |
| 			$name=strtolower($name);
 | |
| 			if(!isset($this->_e[$name]))
 | |
| 				$this->_e[$name]=new CList;
 | |
| 			return $this->_e[$name]->add($value);
 | |
| 		}
 | |
| 		elseif(is_array($this->_m))
 | |
| 		{
 | |
| 			foreach($this->_m as $object)
 | |
| 			{
 | |
| 				if($object->getEnabled() && (property_exists($object,$name) || $object->canSetProperty($name)))
 | |
| 					return $object->$name=$value;
 | |
| 			}
 | |
| 		}
 | |
| 		if(method_exists($this,'get'.$name))
 | |
| 			throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.',
 | |
| 				array('{class}'=>get_class($this), '{property}'=>$name)));
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.',
 | |
| 				array('{class}'=>get_class($this), '{property}'=>$name)));
 | |
| 	}
 | |
| 	public function __isset($name)
 | |
| 	{
 | |
| 		$getter='get'.$name;
 | |
| 		if(method_exists($this,$getter))
 | |
| 			return $this->$getter()!==null;
 | |
| 		elseif(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
 | |
| 		{
 | |
| 			$name=strtolower($name);
 | |
| 			return isset($this->_e[$name]) && $this->_e[$name]->getCount();
 | |
| 		}
 | |
| 		elseif(is_array($this->_m))
 | |
| 		{
 | |
|  			if(isset($this->_m[$name]))
 | |
|  				return true;
 | |
| 			foreach($this->_m as $object)
 | |
| 			{
 | |
| 				if($object->getEnabled() && (property_exists($object,$name) || $object->canGetProperty($name)))
 | |
| 					return $object->$name!==null;
 | |
| 			}
 | |
| 		}
 | |
| 		return false;
 | |
| 	}
 | |
| 	public function __unset($name)
 | |
| 	{
 | |
| 		$setter='set'.$name;
 | |
| 		if(method_exists($this,$setter))
 | |
| 			$this->$setter(null);
 | |
| 		elseif(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
 | |
| 			unset($this->_e[strtolower($name)]);
 | |
| 		elseif(is_array($this->_m))
 | |
| 		{
 | |
| 			if(isset($this->_m[$name]))
 | |
| 				$this->detachBehavior($name);
 | |
| 			else
 | |
| 			{
 | |
| 				foreach($this->_m as $object)
 | |
| 				{
 | |
| 					if($object->getEnabled())
 | |
| 					{
 | |
| 						if(property_exists($object,$name))
 | |
| 							return $object->$name=null;
 | |
| 						elseif($object->canSetProperty($name))
 | |
| 							return $object->$setter(null);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		elseif(method_exists($this,'get'.$name))
 | |
| 			throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.',
 | |
| 				array('{class}'=>get_class($this), '{property}'=>$name)));
 | |
| 	}
 | |
| 	public function __call($name,$parameters)
 | |
| 	{
 | |
| 		if($this->_m!==null)
 | |
| 		{
 | |
| 			foreach($this->_m as $object)
 | |
| 			{
 | |
| 				if($object->getEnabled() && method_exists($object,$name))
 | |
| 					return call_user_func_array(array($object,$name),$parameters);
 | |
| 			}
 | |
| 		}
 | |
| 		if(class_exists('Closure', false) && $this->canGetProperty($name) && $this->$name instanceof Closure)
 | |
| 			return call_user_func_array($this->$name, $parameters);
 | |
| 		throw new CException(Yii::t('yii','{class} and its behaviors do not have a method or closure named "{name}".',
 | |
| 			array('{class}'=>get_class($this), '{name}'=>$name)));
 | |
| 	}
 | |
| 	public function asa($behavior)
 | |
| 	{
 | |
| 		return isset($this->_m[$behavior]) ? $this->_m[$behavior] : null;
 | |
| 	}
 | |
| 	public function attachBehaviors($behaviors)
 | |
| 	{
 | |
| 		foreach($behaviors as $name=>$behavior)
 | |
| 			$this->attachBehavior($name,$behavior);
 | |
| 	}
 | |
| 	public function detachBehaviors()
 | |
| 	{
 | |
| 		if($this->_m!==null)
 | |
| 		{
 | |
| 			foreach($this->_m as $name=>$behavior)
 | |
| 				$this->detachBehavior($name);
 | |
| 			$this->_m=null;
 | |
| 		}
 | |
| 	}
 | |
| 	public function attachBehavior($name,$behavior)
 | |
| 	{
 | |
| 		if(!($behavior instanceof IBehavior))
 | |
| 			$behavior=Yii::createComponent($behavior);
 | |
| 		$behavior->setEnabled(true);
 | |
| 		$behavior->attach($this);
 | |
| 		return $this->_m[$name]=$behavior;
 | |
| 	}
 | |
| 	public function detachBehavior($name)
 | |
| 	{
 | |
| 		if(isset($this->_m[$name]))
 | |
| 		{
 | |
| 			$this->_m[$name]->detach($this);
 | |
| 			$behavior=$this->_m[$name];
 | |
| 			unset($this->_m[$name]);
 | |
| 			return $behavior;
 | |
| 		}
 | |
| 	}
 | |
| 	public function enableBehaviors()
 | |
| 	{
 | |
| 		if($this->_m!==null)
 | |
| 		{
 | |
| 			foreach($this->_m as $behavior)
 | |
| 				$behavior->setEnabled(true);
 | |
| 		}
 | |
| 	}
 | |
| 	public function disableBehaviors()
 | |
| 	{
 | |
| 		if($this->_m!==null)
 | |
| 		{
 | |
| 			foreach($this->_m as $behavior)
 | |
| 				$behavior->setEnabled(false);
 | |
| 		}
 | |
| 	}
 | |
| 	public function enableBehavior($name)
 | |
| 	{
 | |
| 		if(isset($this->_m[$name]))
 | |
| 			$this->_m[$name]->setEnabled(true);
 | |
| 	}
 | |
| 	public function disableBehavior($name)
 | |
| 	{
 | |
| 		if(isset($this->_m[$name]))
 | |
| 			$this->_m[$name]->setEnabled(false);
 | |
| 	}
 | |
| 	public function hasProperty($name)
 | |
| 	{
 | |
| 		return method_exists($this,'get'.$name) || method_exists($this,'set'.$name);
 | |
| 	}
 | |
| 	public function canGetProperty($name)
 | |
| 	{
 | |
| 		return method_exists($this,'get'.$name);
 | |
| 	}
 | |
| 	public function canSetProperty($name)
 | |
| 	{
 | |
| 		return method_exists($this,'set'.$name);
 | |
| 	}
 | |
| 	public function hasEvent($name)
 | |
| 	{
 | |
| 		return !strncasecmp($name,'on',2) && method_exists($this,$name);
 | |
| 	}
 | |
| 	public function hasEventHandler($name)
 | |
| 	{
 | |
| 		$name=strtolower($name);
 | |
| 		return isset($this->_e[$name]) && $this->_e[$name]->getCount()>0;
 | |
| 	}
 | |
| 	public function getEventHandlers($name)
 | |
| 	{
 | |
| 		if($this->hasEvent($name))
 | |
| 		{
 | |
| 			$name=strtolower($name);
 | |
| 			if(!isset($this->_e[$name]))
 | |
| 				$this->_e[$name]=new CList;
 | |
| 			return $this->_e[$name];
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',
 | |
| 				array('{class}'=>get_class($this), '{event}'=>$name)));
 | |
| 	}
 | |
| 	public function attachEventHandler($name,$handler)
 | |
| 	{
 | |
| 		$this->getEventHandlers($name)->add($handler);
 | |
| 	}
 | |
| 	public function detachEventHandler($name,$handler)
 | |
| 	{
 | |
| 		if($this->hasEventHandler($name))
 | |
| 			return $this->getEventHandlers($name)->remove($handler)!==false;
 | |
| 		else
 | |
| 			return false;
 | |
| 	}
 | |
| 	public function raiseEvent($name,$event)
 | |
| 	{
 | |
| 		$name=strtolower($name);
 | |
| 		if(isset($this->_e[$name]))
 | |
| 		{
 | |
| 			foreach($this->_e[$name] as $handler)
 | |
| 			{
 | |
| 				if(is_string($handler))
 | |
| 					call_user_func($handler,$event);
 | |
| 				elseif(is_callable($handler,true))
 | |
| 				{
 | |
| 					if(is_array($handler))
 | |
| 					{
 | |
| 						// an array: 0 - object, 1 - method name
 | |
| 						list($object,$method)=$handler;
 | |
| 						if(is_string($object))	// static method call
 | |
| 							call_user_func($handler,$event);
 | |
| 						elseif(method_exists($object,$method))
 | |
| 							$object->$method($event);
 | |
| 						else
 | |
| 							throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',
 | |
| 								array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>$handler[1])));
 | |
| 					}
 | |
| 					else // PHP 5.3: anonymous function
 | |
| 						call_user_func($handler,$event);
 | |
| 				}
 | |
| 				else
 | |
| 					throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',
 | |
| 						array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>gettype($handler))));
 | |
| 				// stop further handling if param.handled is set true
 | |
| 				if(($event instanceof CEvent) && $event->handled)
 | |
| 					return;
 | |
| 			}
 | |
| 		}
 | |
| 		elseif(YII_DEBUG && !$this->hasEvent($name))
 | |
| 			throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',
 | |
| 				array('{class}'=>get_class($this), '{event}'=>$name)));
 | |
| 	}
 | |
| 	public function evaluateExpression($_expression_,$_data_=array())
 | |
| 	{
 | |
| 		if(is_string($_expression_))
 | |
| 		{
 | |
| 			extract($_data_);
 | |
| 			return eval('return '.$_expression_.';');
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$_data_[]=$this;
 | |
| 			return call_user_func_array($_expression_, $_data_);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| class CEvent extends CComponent
 | |
| {
 | |
| 	public $sender;
 | |
| 	public $handled=false;
 | |
| 	public $params;
 | |
| 	public function __construct($sender=null,$params=null)
 | |
| 	{
 | |
| 		$this->sender=$sender;
 | |
| 		$this->params=$params;
 | |
| 	}
 | |
| }
 | |
| class CEnumerable
 | |
| {
 | |
| }
 | |
| abstract class CModule extends CComponent
 | |
| {
 | |
| 	public $preload=array();
 | |
| 	public $behaviors=array();
 | |
| 	private $_id;
 | |
| 	private $_parentModule;
 | |
| 	private $_basePath;
 | |
| 	private $_modulePath;
 | |
| 	private $_params;
 | |
| 	private $_modules=array();
 | |
| 	private $_moduleConfig=array();
 | |
| 	private $_components=array();
 | |
| 	private $_componentConfig=array();
 | |
| 	public function __construct($id,$parent,$config=null)
 | |
| 	{
 | |
| 		$this->_id=$id;
 | |
| 		$this->_parentModule=$parent;
 | |
| 		// set basePath at early as possible to avoid trouble
 | |
| 		if(is_string($config))
 | |
| 			$config=require($config);
 | |
| 		if(isset($config['basePath']))
 | |
| 		{
 | |
| 			$this->setBasePath($config['basePath']);
 | |
| 			unset($config['basePath']);
 | |
| 		}
 | |
| 		Yii::setPathOfAlias($id,$this->getBasePath());
 | |
| 		$this->preinit();
 | |
| 		$this->configure($config);
 | |
| 		$this->attachBehaviors($this->behaviors);
 | |
| 		$this->preloadComponents();
 | |
| 		$this->init();
 | |
| 	}
 | |
| 	public function __get($name)
 | |
| 	{
 | |
| 		if($this->hasComponent($name))
 | |
| 			return $this->getComponent($name);
 | |
| 		else
 | |
| 			return parent::__get($name);
 | |
| 	}
 | |
| 	public function __isset($name)
 | |
| 	{
 | |
| 		if($this->hasComponent($name))
 | |
| 			return $this->getComponent($name)!==null;
 | |
| 		else
 | |
| 			return parent::__isset($name);
 | |
| 	}
 | |
| 	public function getId()
 | |
| 	{
 | |
| 		return $this->_id;
 | |
| 	}
 | |
| 	public function setId($id)
 | |
| 	{
 | |
| 		$this->_id=$id;
 | |
| 	}
 | |
| 	public function getBasePath()
 | |
| 	{
 | |
| 		if($this->_basePath===null)
 | |
| 		{
 | |
| 			$class=new ReflectionClass(get_class($this));
 | |
| 			$this->_basePath=dirname($class->getFileName());
 | |
| 		}
 | |
| 		return $this->_basePath;
 | |
| 	}
 | |
| 	public function setBasePath($path)
 | |
| 	{
 | |
| 		if(($this->_basePath=realpath($path))===false || !is_dir($this->_basePath))
 | |
| 			throw new CException(Yii::t('yii','Base path "{path}" is not a valid directory.',
 | |
| 				array('{path}'=>$path)));
 | |
| 	}
 | |
| 	public function getParams()
 | |
| 	{
 | |
| 		if($this->_params!==null)
 | |
| 			return $this->_params;
 | |
| 		else
 | |
| 		{
 | |
| 			$this->_params=new CAttributeCollection;
 | |
| 			$this->_params->caseSensitive=true;
 | |
| 			return $this->_params;
 | |
| 		}
 | |
| 	}
 | |
| 	public function setParams($value)
 | |
| 	{
 | |
| 		$params=$this->getParams();
 | |
| 		foreach($value as $k=>$v)
 | |
| 			$params->add($k,$v);
 | |
| 	}
 | |
| 	public function getModulePath()
 | |
| 	{
 | |
| 		if($this->_modulePath!==null)
 | |
| 			return $this->_modulePath;
 | |
| 		else
 | |
| 			return $this->_modulePath=$this->getBasePath().DIRECTORY_SEPARATOR.'modules';
 | |
| 	}
 | |
| 	public function setModulePath($value)
 | |
| 	{
 | |
| 		if(($this->_modulePath=realpath($value))===false || !is_dir($this->_modulePath))
 | |
| 			throw new CException(Yii::t('yii','The module path "{path}" is not a valid directory.',
 | |
| 				array('{path}'=>$value)));
 | |
| 	}
 | |
| 	public function setImport($aliases)
 | |
| 	{
 | |
| 		foreach($aliases as $alias)
 | |
| 			Yii::import($alias);
 | |
| 	}
 | |
| 	public function setAliases($mappings)
 | |
| 	{
 | |
| 		foreach($mappings as $name=>$alias)
 | |
| 		{
 | |
| 			if(($path=Yii::getPathOfAlias($alias))!==false)
 | |
| 				Yii::setPathOfAlias($name,$path);
 | |
| 			else
 | |
| 				Yii::setPathOfAlias($name,$alias);
 | |
| 		}
 | |
| 	}
 | |
| 	public function getParentModule()
 | |
| 	{
 | |
| 		return $this->_parentModule;
 | |
| 	}
 | |
| 	public function getModule($id)
 | |
| 	{
 | |
| 		if(isset($this->_modules[$id]) || array_key_exists($id,$this->_modules))
 | |
| 			return $this->_modules[$id];
 | |
| 		elseif(isset($this->_moduleConfig[$id]))
 | |
| 		{
 | |
| 			$config=$this->_moduleConfig[$id];
 | |
| 			if(!isset($config['enabled']) || $config['enabled'])
 | |
| 			{
 | |
| 				$class=$config['class'];
 | |
| 				unset($config['class'], $config['enabled']);
 | |
| 				if($this===Yii::app())
 | |
| 					$module=Yii::createComponent($class,$id,null,$config);
 | |
| 				else
 | |
| 					$module=Yii::createComponent($class,$this->getId().'/'.$id,$this,$config);
 | |
| 				return $this->_modules[$id]=$module;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	public function hasModule($id)
 | |
| 	{
 | |
| 		return isset($this->_moduleConfig[$id]) || isset($this->_modules[$id]);
 | |
| 	}
 | |
| 	public function getModules()
 | |
| 	{
 | |
| 		return $this->_moduleConfig;
 | |
| 	}
 | |
| 	public function setModules($modules)
 | |
| 	{
 | |
| 		foreach($modules as $id=>$module)
 | |
| 		{
 | |
| 			if(is_int($id))
 | |
| 			{
 | |
| 				$id=$module;
 | |
| 				$module=array();
 | |
| 			}
 | |
| 			if(!isset($module['class']))
 | |
| 			{
 | |
| 				Yii::setPathOfAlias($id,$this->getModulePath().DIRECTORY_SEPARATOR.$id);
 | |
| 				$module['class']=$id.'.'.ucfirst($id).'Module';
 | |
| 			}
 | |
| 			if(isset($this->_moduleConfig[$id]))
 | |
| 				$this->_moduleConfig[$id]=CMap::mergeArray($this->_moduleConfig[$id],$module);
 | |
| 			else
 | |
| 				$this->_moduleConfig[$id]=$module;
 | |
| 		}
 | |
| 	}
 | |
| 	public function hasComponent($id)
 | |
| 	{
 | |
| 		return isset($this->_components[$id]) || isset($this->_componentConfig[$id]);
 | |
| 	}
 | |
| 	public function getComponent($id,$createIfNull=true)
 | |
| 	{
 | |
| 		if(isset($this->_components[$id]))
 | |
| 			return $this->_components[$id];
 | |
| 		elseif(isset($this->_componentConfig[$id]) && $createIfNull)
 | |
| 		{
 | |
| 			$config=$this->_componentConfig[$id];
 | |
| 			if(!isset($config['enabled']) || $config['enabled'])
 | |
| 			{
 | |
| 				unset($config['enabled']);
 | |
| 				$component=Yii::createComponent($config);
 | |
| 				$component->init();
 | |
| 				return $this->_components[$id]=$component;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	public function setComponent($id,$component,$merge=true)
 | |
| 	{
 | |
| 		if($component===null)
 | |
| 		{
 | |
| 			unset($this->_components[$id]);
 | |
| 			return;
 | |
| 		}
 | |
| 		elseif($component instanceof IApplicationComponent)
 | |
| 		{
 | |
| 			$this->_components[$id]=$component;
 | |
| 			if(!$component->getIsInitialized())
 | |
| 				$component->init();
 | |
| 			return;
 | |
| 		}
 | |
| 		elseif(isset($this->_components[$id]))
 | |
| 		{
 | |
| 			if(isset($component['class']) && get_class($this->_components[$id])!==$component['class'])
 | |
| 			{
 | |
| 				unset($this->_components[$id]);
 | |
| 				$this->_componentConfig[$id]=$component; //we should ignore merge here
 | |
| 				return;
 | |
| 			}
 | |
| 			foreach($component as $key=>$value)
 | |
| 			{
 | |
| 				if($key!=='class')
 | |
| 					$this->_components[$id]->$key=$value;
 | |
| 			}
 | |
| 		}
 | |
| 		elseif(isset($this->_componentConfig[$id]['class'],$component['class'])
 | |
| 			&& $this->_componentConfig[$id]['class']!==$component['class'])
 | |
| 		{
 | |
| 			$this->_componentConfig[$id]=$component; //we should ignore merge here
 | |
| 			return;
 | |
| 		}
 | |
| 		if(isset($this->_componentConfig[$id]) && $merge)
 | |
| 			$this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component);
 | |
| 		else
 | |
| 			$this->_componentConfig[$id]=$component;
 | |
| 	}
 | |
| 	public function getComponents($loadedOnly=true)
 | |
| 	{
 | |
| 		if($loadedOnly)
 | |
| 			return $this->_components;
 | |
| 		else
 | |
| 			return array_merge($this->_componentConfig, $this->_components);
 | |
| 	}
 | |
| 	public function setComponents($components,$merge=true)
 | |
| 	{
 | |
| 		foreach($components as $id=>$component)
 | |
| 			$this->setComponent($id,$component,$merge);
 | |
| 	}
 | |
| 	public function configure($config)
 | |
| 	{
 | |
| 		if(is_array($config))
 | |
| 		{
 | |
| 			foreach($config as $key=>$value)
 | |
| 				$this->$key=$value;
 | |
| 		}
 | |
| 	}
 | |
| 	protected function preloadComponents()
 | |
| 	{
 | |
| 		foreach($this->preload as $id)
 | |
| 			$this->getComponent($id);
 | |
| 	}
 | |
| 	protected function preinit()
 | |
| 	{
 | |
| 	}
 | |
| 	protected function init()
 | |
| 	{
 | |
| 	}
 | |
| }
 | |
| abstract class CApplication extends CModule
 | |
| {
 | |
| 	public $name='My Application';
 | |
| 	public $charset='UTF-8';
 | |
| 	public $sourceLanguage='en_us';
 | |
| 	private $_id;
 | |
| 	private $_basePath;
 | |
| 	private $_runtimePath;
 | |
| 	private $_extensionPath;
 | |
| 	private $_globalState;
 | |
| 	private $_stateChanged;
 | |
| 	private $_ended=false;
 | |
| 	private $_language;
 | |
| 	private $_homeUrl;
 | |
| 	abstract public function processRequest();
 | |
| 	public function __construct($config=null)
 | |
| 	{
 | |
| 		Yii::setApplication($this);
 | |
| 		// set basePath at early as possible to avoid trouble
 | |
| 		if(is_string($config))
 | |
| 			$config=require($config);
 | |
| 		if(isset($config['basePath']))
 | |
| 		{
 | |
| 			$this->setBasePath($config['basePath']);
 | |
| 			unset($config['basePath']);
 | |
| 		}
 | |
| 		else
 | |
| 			$this->setBasePath('protected');
 | |
| 		Yii::setPathOfAlias('application',$this->getBasePath());
 | |
| 		Yii::setPathOfAlias('webroot',dirname($_SERVER['SCRIPT_FILENAME']));
 | |
| 		if(isset($config['extensionPath']))
 | |
| 		{
 | |
| 			$this->setExtensionPath($config['extensionPath']);
 | |
| 			unset($config['extensionPath']);
 | |
| 		}
 | |
| 		else
 | |
| 			Yii::setPathOfAlias('ext',$this->getBasePath().DIRECTORY_SEPARATOR.'extensions');
 | |
| 		if(isset($config['aliases']))
 | |
| 		{
 | |
| 			$this->setAliases($config['aliases']);
 | |
| 			unset($config['aliases']);
 | |
| 		}
 | |
| 		$this->preinit();
 | |
| 		$this->initSystemHandlers();
 | |
| 		$this->registerCoreComponents();
 | |
| 		$this->configure($config);
 | |
| 		$this->attachBehaviors($this->behaviors);
 | |
| 		$this->preloadComponents();
 | |
| 		$this->init();
 | |
| 	}
 | |
| 	public function run()
 | |
| 	{
 | |
| 		if($this->hasEventHandler('onBeginRequest'))
 | |
| 			$this->onBeginRequest(new CEvent($this));
 | |
| 		register_shutdown_function(array($this,'end'),0,false);
 | |
| 		$this->processRequest();
 | |
| 		if($this->hasEventHandler('onEndRequest'))
 | |
| 			$this->onEndRequest(new CEvent($this));
 | |
| 	}
 | |
| 	public function end($status=0,$exit=true)
 | |
| 	{
 | |
| 		if($this->hasEventHandler('onEndRequest'))
 | |
| 			$this->onEndRequest(new CEvent($this));
 | |
| 		if($exit)
 | |
| 			exit($status);
 | |
| 	}
 | |
| 	public function onBeginRequest($event)
 | |
| 	{
 | |
| 		$this->raiseEvent('onBeginRequest',$event);
 | |
| 	}
 | |
| 	public function onEndRequest($event)
 | |
| 	{
 | |
| 		if(!$this->_ended)
 | |
| 		{
 | |
| 			$this->_ended=true;
 | |
| 			$this->raiseEvent('onEndRequest',$event);
 | |
| 		}
 | |
| 	}
 | |
| 	public function getId()
 | |
| 	{
 | |
| 		if($this->_id!==null)
 | |
| 			return $this->_id;
 | |
| 		else
 | |
| 			return $this->_id=sprintf('%x',crc32($this->getBasePath().$this->name));
 | |
| 	}
 | |
| 	public function setId($id)
 | |
| 	{
 | |
| 		$this->_id=$id;
 | |
| 	}
 | |
| 	public function getBasePath()
 | |
| 	{
 | |
| 		return $this->_basePath;
 | |
| 	}
 | |
| 	public function setBasePath($path)
 | |
| 	{
 | |
| 		if(($this->_basePath=realpath($path))===false || !is_dir($this->_basePath))
 | |
| 			throw new CException(Yii::t('yii','Application base path "{path}" is not a valid directory.',
 | |
| 				array('{path}'=>$path)));
 | |
| 	}
 | |
| 	public function getRuntimePath()
 | |
| 	{
 | |
| 		if($this->_runtimePath!==null)
 | |
| 			return $this->_runtimePath;
 | |
| 		else
 | |
| 		{
 | |
| 			$this->setRuntimePath($this->getBasePath().DIRECTORY_SEPARATOR.'runtime');
 | |
| 			return $this->_runtimePath;
 | |
| 		}
 | |
| 	}
 | |
| 	public function setRuntimePath($path)
 | |
| 	{
 | |
| 		if(($runtimePath=realpath($path))===false || !is_dir($runtimePath) || !is_writable($runtimePath))
 | |
| 			throw new CException(Yii::t('yii','Application runtime path "{path}" is not valid. Please make sure it is a directory writable by the Web server process.',
 | |
| 				array('{path}'=>$path)));
 | |
| 		$this->_runtimePath=$runtimePath;
 | |
| 	}
 | |
| 	public function getExtensionPath()
 | |
| 	{
 | |
| 		return Yii::getPathOfAlias('ext');
 | |
| 	}
 | |
| 	public function setExtensionPath($path)
 | |
| 	{
 | |
| 		if(($extensionPath=realpath($path))===false || !is_dir($extensionPath))
 | |
| 			throw new CException(Yii::t('yii','Extension path "{path}" does not exist.',
 | |
| 				array('{path}'=>$path)));
 | |
| 		Yii::setPathOfAlias('ext',$extensionPath);
 | |
| 	}
 | |
| 	public function getLanguage()
 | |
| 	{
 | |
| 		return $this->_language===null ? $this->sourceLanguage : $this->_language;
 | |
| 	}
 | |
| 	public function setLanguage($language)
 | |
| 	{
 | |
| 		$this->_language=$language;
 | |
| 	}
 | |
| 	public function getTimeZone()
 | |
| 	{
 | |
| 		return date_default_timezone_get();
 | |
| 	}
 | |
| 	public function setTimeZone($value)
 | |
| 	{
 | |
| 		date_default_timezone_set($value);
 | |
| 	}
 | |
| 	public function findLocalizedFile($srcFile,$srcLanguage=null,$language=null)
 | |
| 	{
 | |
| 		if($srcLanguage===null)
 | |
| 			$srcLanguage=$this->sourceLanguage;
 | |
| 		if($language===null)
 | |
| 			$language=$this->getLanguage();
 | |
| 		if($language===$srcLanguage)
 | |
| 			return $srcFile;
 | |
| 		$desiredFile=dirname($srcFile).DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.basename($srcFile);
 | |
| 		return is_file($desiredFile) ? $desiredFile : $srcFile;
 | |
| 	}
 | |
| 	public function getLocale($localeID=null)
 | |
| 	{
 | |
| 		return CLocale::getInstance($localeID===null?$this->getLanguage():$localeID);
 | |
| 	}
 | |
| 	public function getLocaleDataPath()
 | |
| 	{
 | |
| 		return CLocale::$dataPath===null ? Yii::getPathOfAlias('system.i18n.data') : CLocale::$dataPath;
 | |
| 	}
 | |
| 	public function setLocaleDataPath($value)
 | |
| 	{
 | |
| 		CLocale::$dataPath=$value;
 | |
| 	}
 | |
| 	public function getNumberFormatter()
 | |
| 	{
 | |
| 		return $this->getLocale()->getNumberFormatter();
 | |
| 	}
 | |
| 	public function getDateFormatter()
 | |
| 	{
 | |
| 		return $this->getLocale()->getDateFormatter();
 | |
| 	}
 | |
| 	public function getDb()
 | |
| 	{
 | |
| 		return $this->getComponent('db');
 | |
| 	}
 | |
| 	public function getErrorHandler()
 | |
| 	{
 | |
| 		return $this->getComponent('errorHandler');
 | |
| 	}
 | |
| 	public function getSecurityManager()
 | |
| 	{
 | |
| 		return $this->getComponent('securityManager');
 | |
| 	}
 | |
| 	public function getStatePersister()
 | |
| 	{
 | |
| 		return $this->getComponent('statePersister');
 | |
| 	}
 | |
| 	public function getCache()
 | |
| 	{
 | |
| 		return $this->getComponent('cache');
 | |
| 	}
 | |
| 	public function getCoreMessages()
 | |
| 	{
 | |
| 		return $this->getComponent('coreMessages');
 | |
| 	}
 | |
| 	public function getMessages()
 | |
| 	{
 | |
| 		return $this->getComponent('messages');
 | |
| 	}
 | |
| 	public function getRequest()
 | |
| 	{
 | |
| 		return $this->getComponent('request');
 | |
| 	}
 | |
| 	public function getUrlManager()
 | |
| 	{
 | |
| 		return $this->getComponent('urlManager');
 | |
| 	}
 | |
| 	public function getController()
 | |
| 	{
 | |
| 		return null;
 | |
| 	}
 | |
| 	public function createUrl($route,$params=array(),$ampersand='&')
 | |
| 	{
 | |
| 		return $this->getUrlManager()->createUrl($route,$params,$ampersand);
 | |
| 	}
 | |
| 	public function createAbsoluteUrl($route,$params=array(),$schema='',$ampersand='&')
 | |
| 	{
 | |
| 		$url=$this->createUrl($route,$params,$ampersand);
 | |
| 		if(strpos($url,'http')===0)
 | |
| 			return $url;
 | |
| 		else
 | |
| 			return $this->getRequest()->getHostInfo($schema).$url;
 | |
| 	}
 | |
| 	public function getBaseUrl($absolute=false)
 | |
| 	{
 | |
| 		return $this->getRequest()->getBaseUrl($absolute);
 | |
| 	}
 | |
| 	public function getHomeUrl()
 | |
| 	{
 | |
| 		if($this->_homeUrl===null)
 | |
| 		{
 | |
| 			if($this->getUrlManager()->showScriptName)
 | |
| 				return $this->getRequest()->getScriptUrl();
 | |
| 			else
 | |
| 				return $this->getRequest()->getBaseUrl().'/';
 | |
| 		}
 | |
| 		else
 | |
| 			return $this->_homeUrl;
 | |
| 	}
 | |
| 	public function setHomeUrl($value)
 | |
| 	{
 | |
| 		$this->_homeUrl=$value;
 | |
| 	}
 | |
| 	public function getGlobalState($key,$defaultValue=null)
 | |
| 	{
 | |
| 		if($this->_globalState===null)
 | |
| 			$this->loadGlobalState();
 | |
| 		if(isset($this->_globalState[$key]))
 | |
| 			return $this->_globalState[$key];
 | |
| 		else
 | |
| 			return $defaultValue;
 | |
| 	}
 | |
| 	public function setGlobalState($key,$value,$defaultValue=null)
 | |
| 	{
 | |
| 		if($this->_globalState===null)
 | |
| 			$this->loadGlobalState();
 | |
| 		$changed=$this->_stateChanged;
 | |
| 		if($value===$defaultValue)
 | |
| 		{
 | |
| 			if(isset($this->_globalState[$key]))
 | |
| 			{
 | |
| 				unset($this->_globalState[$key]);
 | |
| 				$this->_stateChanged=true;
 | |
| 			}
 | |
| 		}
 | |
| 		elseif(!isset($this->_globalState[$key]) || $this->_globalState[$key]!==$value)
 | |
| 		{
 | |
| 			$this->_globalState[$key]=$value;
 | |
| 			$this->_stateChanged=true;
 | |
| 		}
 | |
| 		if($this->_stateChanged!==$changed)
 | |
| 			$this->attachEventHandler('onEndRequest',array($this,'saveGlobalState'));
 | |
| 	}
 | |
| 	public function clearGlobalState($key)
 | |
| 	{
 | |
| 		$this->setGlobalState($key,true,true);
 | |
| 	}
 | |
| 	public function loadGlobalState()
 | |
| 	{
 | |
| 		$persister=$this->getStatePersister();
 | |
| 		if(($this->_globalState=$persister->load())===null)
 | |
| 			$this->_globalState=array();
 | |
| 		$this->_stateChanged=false;
 | |
| 		$this->detachEventHandler('onEndRequest',array($this,'saveGlobalState'));
 | |
| 	}
 | |
| 	public function saveGlobalState()
 | |
| 	{
 | |
| 		if($this->_stateChanged)
 | |
| 		{
 | |
| 			$this->_stateChanged=false;
 | |
| 			$this->detachEventHandler('onEndRequest',array($this,'saveGlobalState'));
 | |
| 			$this->getStatePersister()->save($this->_globalState);
 | |
| 		}
 | |
| 	}
 | |
| 	public function handleException($exception)
 | |
| 	{
 | |
| 		// disable error capturing to avoid recursive errors
 | |
| 		restore_error_handler();
 | |
| 		restore_exception_handler();
 | |
| 		$category='exception.'.get_class($exception);
 | |
| 		if($exception instanceof CHttpException)
 | |
| 			$category.='.'.$exception->statusCode;
 | |
| 		// php <5.2 doesn't support string conversion auto-magically
 | |
| 		$message=$exception->__toString();
 | |
| 		if(isset($_SERVER['REQUEST_URI']))
 | |
| 			$message.="\nREQUEST_URI=".$_SERVER['REQUEST_URI'];
 | |
| 		if(isset($_SERVER['HTTP_REFERER']))
 | |
| 			$message.="\nHTTP_REFERER=".$_SERVER['HTTP_REFERER'];
 | |
| 		$message.="\n---";
 | |
| 		Yii::log($message,CLogger::LEVEL_ERROR,$category);
 | |
| 		try
 | |
| 		{
 | |
| 			$event=new CExceptionEvent($this,$exception);
 | |
| 			$this->onException($event);
 | |
| 			if(!$event->handled)
 | |
| 			{
 | |
| 				// try an error handler
 | |
| 				if(($handler=$this->getErrorHandler())!==null)
 | |
| 					$handler->handle($event);
 | |
| 				else
 | |
| 					$this->displayException($exception);
 | |
| 			}
 | |
| 		}
 | |
| 		catch(Exception $e)
 | |
| 		{
 | |
| 			$this->displayException($e);
 | |
| 		}
 | |
| 		try
 | |
| 		{
 | |
| 			$this->end(1);
 | |
| 		}
 | |
| 		catch(Exception $e)
 | |
| 		{
 | |
| 			// use the most primitive way to log error
 | |
| 			$msg = get_class($e).': '.$e->getMessage().' ('.$e->getFile().':'.$e->getLine().")\n";
 | |
| 			$msg .= $e->getTraceAsString()."\n";
 | |
| 			$msg .= "Previous exception:\n";
 | |
| 			$msg .= get_class($exception).': '.$exception->getMessage().' ('.$exception->getFile().':'.$exception->getLine().")\n";
 | |
| 			$msg .= $exception->getTraceAsString()."\n";
 | |
| 			$msg .= '$_SERVER='.var_export($_SERVER,true);
 | |
| 			error_log($msg);
 | |
| 			exit(1);
 | |
| 		}
 | |
| 	}
 | |
| 	public function handleError($code,$message,$file,$line)
 | |
| 	{
 | |
| 		if($code & error_reporting())
 | |
| 		{
 | |
| 			// disable error capturing to avoid recursive errors
 | |
| 			restore_error_handler();
 | |
| 			restore_exception_handler();
 | |
| 			$log="$message ($file:$line)\nStack trace:\n";
 | |
| 			$trace=debug_backtrace();
 | |
| 			// skip the first 3 stacks as they do not tell the error position
 | |
| 			if(count($trace)>3)
 | |
| 				$trace=array_slice($trace,3);
 | |
| 			foreach($trace as $i=>$t)
 | |
| 			{
 | |
| 				if(!isset($t['file']))
 | |
| 					$t['file']='unknown';
 | |
| 				if(!isset($t['line']))
 | |
| 					$t['line']=0;
 | |
| 				if(!isset($t['function']))
 | |
| 					$t['function']='unknown';
 | |
| 				$log.="#$i {$t['file']}({$t['line']}): ";
 | |
| 				if(isset($t['object']) && is_object($t['object']))
 | |
| 					$log.=get_class($t['object']).'->';
 | |
| 				$log.="{$t['function']}()\n";
 | |
| 			}
 | |
| 			if(isset($_SERVER['REQUEST_URI']))
 | |
| 				$log.='REQUEST_URI='.$_SERVER['REQUEST_URI'];
 | |
| 			Yii::log($log,CLogger::LEVEL_ERROR,'php');
 | |
| 			try
 | |
| 			{
 | |
| 				Yii::import('CErrorEvent',true);
 | |
| 				$event=new CErrorEvent($this,$code,$message,$file,$line);
 | |
| 				$this->onError($event);
 | |
| 				if(!$event->handled)
 | |
| 				{
 | |
| 					// try an error handler
 | |
| 					if(($handler=$this->getErrorHandler())!==null)
 | |
| 						$handler->handle($event);
 | |
| 					else
 | |
| 						$this->displayError($code,$message,$file,$line);
 | |
| 				}
 | |
| 			}
 | |
| 			catch(Exception $e)
 | |
| 			{
 | |
| 				$this->displayException($e);
 | |
| 			}
 | |
| 			try
 | |
| 			{
 | |
| 				$this->end(1);
 | |
| 			}
 | |
| 			catch(Exception $e)
 | |
| 			{
 | |
| 				// use the most primitive way to log error
 | |
| 				$msg = get_class($e).': '.$e->getMessage().' ('.$e->getFile().':'.$e->getLine().")\n";
 | |
| 				$msg .= $e->getTraceAsString()."\n";
 | |
| 				$msg .= "Previous error:\n";
 | |
| 				$msg .= $log."\n";
 | |
| 				$msg .= '$_SERVER='.var_export($_SERVER,true);
 | |
| 				error_log($msg);
 | |
| 				exit(1);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	public function onException($event)
 | |
| 	{
 | |
| 		$this->raiseEvent('onException',$event);
 | |
| 	}
 | |
| 	public function onError($event)
 | |
| 	{
 | |
| 		$this->raiseEvent('onError',$event);
 | |
| 	}
 | |
| 	public function displayError($code,$message,$file,$line)
 | |
| 	{
 | |
| 		if(YII_DEBUG)
 | |
| 		{
 | |
| 			echo "<h1>PHP Error [$code]</h1>\n";
 | |
| 			echo "<p>$message ($file:$line)</p>\n";
 | |
| 			echo '<pre>';
 | |
| 			$trace=debug_backtrace();
 | |
| 			// skip the first 3 stacks as they do not tell the error position
 | |
| 			if(count($trace)>3)
 | |
| 				$trace=array_slice($trace,3);
 | |
| 			foreach($trace as $i=>$t)
 | |
| 			{
 | |
| 				if(!isset($t['file']))
 | |
| 					$t['file']='unknown';
 | |
| 				if(!isset($t['line']))
 | |
| 					$t['line']=0;
 | |
| 				if(!isset($t['function']))
 | |
| 					$t['function']='unknown';
 | |
| 				echo "#$i {$t['file']}({$t['line']}): ";
 | |
| 				if(isset($t['object']) && is_object($t['object']))
 | |
| 					echo get_class($t['object']).'->';
 | |
| 				echo "{$t['function']}()\n";
 | |
| 			}
 | |
| 			echo '</pre>';
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			echo "<h1>PHP Error [$code]</h1>\n";
 | |
| 			echo "<p>$message</p>\n";
 | |
| 		}
 | |
| 	}
 | |
| 	public function displayException($exception)
 | |
| 	{
 | |
| 		if(YII_DEBUG)
 | |
| 		{
 | |
| 			echo '<h1>'.get_class($exception)."</h1>\n";
 | |
| 			echo '<p>'.$exception->getMessage().' ('.$exception->getFile().':'.$exception->getLine().')</p>';
 | |
| 			echo '<pre>'.$exception->getTraceAsString().'</pre>';
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			echo '<h1>'.get_class($exception)."</h1>\n";
 | |
| 			echo '<p>'.$exception->getMessage().'</p>';
 | |
| 		}
 | |
| 	}
 | |
| 	protected function initSystemHandlers()
 | |
| 	{
 | |
| 		if(YII_ENABLE_EXCEPTION_HANDLER)
 | |
| 			set_exception_handler(array($this,'handleException'));
 | |
| 		if(YII_ENABLE_ERROR_HANDLER)
 | |
| 			set_error_handler(array($this,'handleError'),error_reporting());
 | |
| 	}
 | |
| 	protected function registerCoreComponents()
 | |
| 	{
 | |
| 		$components=array(
 | |
| 			'coreMessages'=>array(
 | |
| 				'class'=>'CPhpMessageSource',
 | |
| 				'language'=>'en_us',
 | |
| 				'basePath'=>YII_PATH.DIRECTORY_SEPARATOR.'messages',
 | |
| 			),
 | |
| 			'db'=>array(
 | |
| 				'class'=>'CDbConnection',
 | |
| 			),
 | |
| 			'messages'=>array(
 | |
| 				'class'=>'CPhpMessageSource',
 | |
| 			),
 | |
| 			'errorHandler'=>array(
 | |
| 				'class'=>'CErrorHandler',
 | |
| 			),
 | |
| 			'securityManager'=>array(
 | |
| 				'class'=>'CSecurityManager',
 | |
| 			),
 | |
| 			'statePersister'=>array(
 | |
| 				'class'=>'CStatePersister',
 | |
| 			),
 | |
| 			'urlManager'=>array(
 | |
| 				'class'=>'CUrlManager',
 | |
| 			),
 | |
| 			'request'=>array(
 | |
| 				'class'=>'CHttpRequest',
 | |
| 			),
 | |
| 			'format'=>array(
 | |
| 				'class'=>'CFormatter',
 | |
| 			),
 | |
| 		);
 | |
| 		$this->setComponents($components);
 | |
| 	}
 | |
| }
 | |
| class CWebApplication extends CApplication
 | |
| {
 | |
| 	public $defaultController='site';
 | |
| 	public $layout='main';
 | |
| 	public $controllerMap=array();
 | |
| 	public $catchAllRequest;
 | |
| 	public $controllerNamespace;
 | |
| 	private $_controllerPath;
 | |
| 	private $_viewPath;
 | |
| 	private $_systemViewPath;
 | |
| 	private $_layoutPath;
 | |
| 	private $_controller;
 | |
| 	private $_theme;
 | |
| 	public function processRequest()
 | |
| 	{
 | |
| 		if(is_array($this->catchAllRequest) && isset($this->catchAllRequest[0]))
 | |
| 		{
 | |
| 			$route=$this->catchAllRequest[0];
 | |
| 			foreach(array_splice($this->catchAllRequest,1) as $name=>$value)
 | |
| 				$_GET[$name]=$value;
 | |
| 		}
 | |
| 		else
 | |
| 			$route=$this->getUrlManager()->parseUrl($this->getRequest());
 | |
| 		$this->runController($route);
 | |
| 	}
 | |
| 	protected function registerCoreComponents()
 | |
| 	{
 | |
| 		parent::registerCoreComponents();
 | |
| 		$components=array(
 | |
| 			'session'=>array(
 | |
| 				'class'=>'CHttpSession',
 | |
| 			),
 | |
| 			'assetManager'=>array(
 | |
| 				'class'=>'CAssetManager',
 | |
| 			),
 | |
| 			'user'=>array(
 | |
| 				'class'=>'CWebUser',
 | |
| 			),
 | |
| 			'themeManager'=>array(
 | |
| 				'class'=>'CThemeManager',
 | |
| 			),
 | |
| 			'authManager'=>array(
 | |
| 				'class'=>'CPhpAuthManager',
 | |
| 			),
 | |
| 			'clientScript'=>array(
 | |
| 				'class'=>'CClientScript',
 | |
| 			),
 | |
| 			'widgetFactory'=>array(
 | |
| 				'class'=>'CWidgetFactory',
 | |
| 			),
 | |
| 		);
 | |
| 		$this->setComponents($components);
 | |
| 	}
 | |
| 	public function getAuthManager()
 | |
| 	{
 | |
| 		return $this->getComponent('authManager');
 | |
| 	}
 | |
| 	public function getAssetManager()
 | |
| 	{
 | |
| 		return $this->getComponent('assetManager');
 | |
| 	}
 | |
| 	public function getSession()
 | |
| 	{
 | |
| 		return $this->getComponent('session');
 | |
| 	}
 | |
| 	public function getUser()
 | |
| 	{
 | |
| 		return $this->getComponent('user');
 | |
| 	}
 | |
| 	public function getViewRenderer()
 | |
| 	{
 | |
| 		return $this->getComponent('viewRenderer');
 | |
| 	}
 | |
| 	public function getClientScript()
 | |
| 	{
 | |
| 		return $this->getComponent('clientScript');
 | |
| 	}
 | |
| 	public function getWidgetFactory()
 | |
| 	{
 | |
| 		return $this->getComponent('widgetFactory');
 | |
| 	}
 | |
| 	public function getThemeManager()
 | |
| 	{
 | |
| 		return $this->getComponent('themeManager');
 | |
| 	}
 | |
| 	public function getTheme()
 | |
| 	{
 | |
| 		if(is_string($this->_theme))
 | |
| 			$this->_theme=$this->getThemeManager()->getTheme($this->_theme);
 | |
| 		return $this->_theme;
 | |
| 	}
 | |
| 	public function setTheme($value)
 | |
| 	{
 | |
| 		$this->_theme=$value;
 | |
| 	}
 | |
| 	public function runController($route)
 | |
| 	{
 | |
| 		if(($ca=$this->createController($route))!==null)
 | |
| 		{
 | |
| 			list($controller,$actionID)=$ca;
 | |
| 			$oldController=$this->_controller;
 | |
| 			$this->_controller=$controller;
 | |
| 			$controller->init();
 | |
| 			$controller->run($actionID);
 | |
| 			$this->_controller=$oldController;
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CHttpException(404,Yii::t('yii','Unable to resolve the request "{route}".',
 | |
| 				array('{route}'=>$route===''?$this->defaultController:$route)));
 | |
| 	}
 | |
| 	public function createController($route,$owner=null)
 | |
| 	{
 | |
| 		if($owner===null)
 | |
| 			$owner=$this;
 | |
| 		if(($route=trim($route,'/'))==='')
 | |
| 			$route=$owner->defaultController;
 | |
| 		$caseSensitive=$this->getUrlManager()->caseSensitive;
 | |
| 		$route.='/';
 | |
| 		while(($pos=strpos($route,'/'))!==false)
 | |
| 		{
 | |
| 			$id=substr($route,0,$pos);
 | |
| 			if(!preg_match('/^\w+$/',$id))
 | |
| 				return null;
 | |
| 			if(!$caseSensitive)
 | |
| 				$id=strtolower($id);
 | |
| 			$route=(string)substr($route,$pos+1);
 | |
| 			if(!isset($basePath))  // first segment
 | |
| 			{
 | |
| 				if(isset($owner->controllerMap[$id]))
 | |
| 				{
 | |
| 					return array(
 | |
| 						Yii::createComponent($owner->controllerMap[$id],$id,$owner===$this?null:$owner),
 | |
| 						$this->parseActionParams($route),
 | |
| 					);
 | |
| 				}
 | |
| 				if(($module=$owner->getModule($id))!==null)
 | |
| 					return $this->createController($route,$module);
 | |
| 				$basePath=$owner->getControllerPath();
 | |
| 				$controllerID='';
 | |
| 			}
 | |
| 			else
 | |
| 				$controllerID.='/';
 | |
| 			$className=ucfirst($id).'Controller';
 | |
| 			$classFile=$basePath.DIRECTORY_SEPARATOR.$className.'.php';
 | |
| 			if($owner->controllerNamespace!==null)
 | |
| 				$className=$owner->controllerNamespace.'\\'.$className;
 | |
| 			if(is_file($classFile))
 | |
| 			{
 | |
| 				if(!class_exists($className,false))
 | |
| 					require($classFile);
 | |
| 				if(class_exists($className,false) && is_subclass_of($className,'CController'))
 | |
| 				{
 | |
| 					$id[0]=strtolower($id[0]);
 | |
| 					return array(
 | |
| 						new $className($controllerID.$id,$owner===$this?null:$owner),
 | |
| 						$this->parseActionParams($route),
 | |
| 					);
 | |
| 				}
 | |
| 				return null;
 | |
| 			}
 | |
| 			$controllerID.=$id;
 | |
| 			$basePath.=DIRECTORY_SEPARATOR.$id;
 | |
| 		}
 | |
| 	}
 | |
| 	protected function parseActionParams($pathInfo)
 | |
| 	{
 | |
| 		if(($pos=strpos($pathInfo,'/'))!==false)
 | |
| 		{
 | |
| 			$manager=$this->getUrlManager();
 | |
| 			$manager->parsePathInfo((string)substr($pathInfo,$pos+1));
 | |
| 			$actionID=substr($pathInfo,0,$pos);
 | |
| 			return $manager->caseSensitive ? $actionID : strtolower($actionID);
 | |
| 		}
 | |
| 		else
 | |
| 			return $pathInfo;
 | |
| 	}
 | |
| 	public function getController()
 | |
| 	{
 | |
| 		return $this->_controller;
 | |
| 	}
 | |
| 	public function setController($value)
 | |
| 	{
 | |
| 		$this->_controller=$value;
 | |
| 	}
 | |
| 	public function getControllerPath()
 | |
| 	{
 | |
| 		if($this->_controllerPath!==null)
 | |
| 			return $this->_controllerPath;
 | |
| 		else
 | |
| 			return $this->_controllerPath=$this->getBasePath().DIRECTORY_SEPARATOR.'controllers';
 | |
| 	}
 | |
| 	public function setControllerPath($value)
 | |
| 	{
 | |
| 		if(($this->_controllerPath=realpath($value))===false || !is_dir($this->_controllerPath))
 | |
| 			throw new CException(Yii::t('yii','The controller path "{path}" is not a valid directory.',
 | |
| 				array('{path}'=>$value)));
 | |
| 	}
 | |
| 	public function getViewPath()
 | |
| 	{
 | |
| 		if($this->_viewPath!==null)
 | |
| 			return $this->_viewPath;
 | |
| 		else
 | |
| 			return $this->_viewPath=$this->getBasePath().DIRECTORY_SEPARATOR.'views';
 | |
| 	}
 | |
| 	public function setViewPath($path)
 | |
| 	{
 | |
| 		if(($this->_viewPath=realpath($path))===false || !is_dir($this->_viewPath))
 | |
| 			throw new CException(Yii::t('yii','The view path "{path}" is not a valid directory.',
 | |
| 				array('{path}'=>$path)));
 | |
| 	}
 | |
| 	public function getSystemViewPath()
 | |
| 	{
 | |
| 		if($this->_systemViewPath!==null)
 | |
| 			return $this->_systemViewPath;
 | |
| 		else
 | |
| 			return $this->_systemViewPath=$this->getViewPath().DIRECTORY_SEPARATOR.'system';
 | |
| 	}
 | |
| 	public function setSystemViewPath($path)
 | |
| 	{
 | |
| 		if(($this->_systemViewPath=realpath($path))===false || !is_dir($this->_systemViewPath))
 | |
| 			throw new CException(Yii::t('yii','The system view path "{path}" is not a valid directory.',
 | |
| 				array('{path}'=>$path)));
 | |
| 	}
 | |
| 	public function getLayoutPath()
 | |
| 	{
 | |
| 		if($this->_layoutPath!==null)
 | |
| 			return $this->_layoutPath;
 | |
| 		else
 | |
| 			return $this->_layoutPath=$this->getViewPath().DIRECTORY_SEPARATOR.'layouts';
 | |
| 	}
 | |
| 	public function setLayoutPath($path)
 | |
| 	{
 | |
| 		if(($this->_layoutPath=realpath($path))===false || !is_dir($this->_layoutPath))
 | |
| 			throw new CException(Yii::t('yii','The layout path "{path}" is not a valid directory.',
 | |
| 				array('{path}'=>$path)));
 | |
| 	}
 | |
| 	public function beforeControllerAction($controller,$action)
 | |
| 	{
 | |
| 		return true;
 | |
| 	}
 | |
| 	public function afterControllerAction($controller,$action)
 | |
| 	{
 | |
| 	}
 | |
| 	public function findModule($id)
 | |
| 	{
 | |
| 		if(($controller=$this->getController())!==null && ($module=$controller->getModule())!==null)
 | |
| 		{
 | |
| 			do
 | |
| 			{
 | |
| 				if(($m=$module->getModule($id))!==null)
 | |
| 					return $m;
 | |
| 			} while(($module=$module->getParentModule())!==null);
 | |
| 		}
 | |
| 		if(($m=$this->getModule($id))!==null)
 | |
| 			return $m;
 | |
| 	}
 | |
| 	protected function init()
 | |
| 	{
 | |
| 		parent::init();
 | |
| 		// preload 'request' so that it has chance to respond to onBeginRequest event.
 | |
| 		$this->getRequest();
 | |
| 	}
 | |
| }
 | |
| class CMap extends CComponent implements IteratorAggregate,ArrayAccess,Countable
 | |
| {
 | |
| 	private $_d=array();
 | |
| 	private $_r=false;
 | |
| 	public function __construct($data=null,$readOnly=false)
 | |
| 	{
 | |
| 		if($data!==null)
 | |
| 			$this->copyFrom($data);
 | |
| 		$this->setReadOnly($readOnly);
 | |
| 	}
 | |
| 	public function getReadOnly()
 | |
| 	{
 | |
| 		return $this->_r;
 | |
| 	}
 | |
| 	protected function setReadOnly($value)
 | |
| 	{
 | |
| 		$this->_r=$value;
 | |
| 	}
 | |
| 	public function getIterator()
 | |
| 	{
 | |
| 		return new CMapIterator($this->_d);
 | |
| 	}
 | |
| 	public function count()
 | |
| 	{
 | |
| 		return $this->getCount();
 | |
| 	}
 | |
| 	public function getCount()
 | |
| 	{
 | |
| 		return count($this->_d);
 | |
| 	}
 | |
| 	public function getKeys()
 | |
| 	{
 | |
| 		return array_keys($this->_d);
 | |
| 	}
 | |
| 	public function itemAt($key)
 | |
| 	{
 | |
| 		if(isset($this->_d[$key]))
 | |
| 			return $this->_d[$key];
 | |
| 		else
 | |
| 			return null;
 | |
| 	}
 | |
| 	public function add($key,$value)
 | |
| 	{
 | |
| 		if(!$this->_r)
 | |
| 		{
 | |
| 			if($key===null)
 | |
| 				$this->_d[]=$value;
 | |
| 			else
 | |
| 				$this->_d[$key]=$value;
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','The map is read only.'));
 | |
| 	}
 | |
| 	public function remove($key)
 | |
| 	{
 | |
| 		if(!$this->_r)
 | |
| 		{
 | |
| 			if(isset($this->_d[$key]))
 | |
| 			{
 | |
| 				$value=$this->_d[$key];
 | |
| 				unset($this->_d[$key]);
 | |
| 				return $value;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				// it is possible the value is null, which is not detected by isset
 | |
| 				unset($this->_d[$key]);
 | |
| 				return null;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','The map is read only.'));
 | |
| 	}
 | |
| 	public function clear()
 | |
| 	{
 | |
| 		foreach(array_keys($this->_d) as $key)
 | |
| 			$this->remove($key);
 | |
| 	}
 | |
| 	public function contains($key)
 | |
| 	{
 | |
| 		return isset($this->_d[$key]) || array_key_exists($key,$this->_d);
 | |
| 	}
 | |
| 	public function toArray()
 | |
| 	{
 | |
| 		return $this->_d;
 | |
| 	}
 | |
| 	public function copyFrom($data)
 | |
| 	{
 | |
| 		if(is_array($data) || $data instanceof Traversable)
 | |
| 		{
 | |
| 			if($this->getCount()>0)
 | |
| 				$this->clear();
 | |
| 			if($data instanceof CMap)
 | |
| 				$data=$data->_d;
 | |
| 			foreach($data as $key=>$value)
 | |
| 				$this->add($key,$value);
 | |
| 		}
 | |
| 		elseif($data!==null)
 | |
| 			throw new CException(Yii::t('yii','Map data must be an array or an object implementing Traversable.'));
 | |
| 	}
 | |
| 	public function mergeWith($data,$recursive=true)
 | |
| 	{
 | |
| 		if(is_array($data) || $data instanceof Traversable)
 | |
| 		{
 | |
| 			if($data instanceof CMap)
 | |
| 				$data=$data->_d;
 | |
| 			if($recursive)
 | |
| 			{
 | |
| 				if($data instanceof Traversable)
 | |
| 				{
 | |
| 					$d=array();
 | |
| 					foreach($data as $key=>$value)
 | |
| 						$d[$key]=$value;
 | |
| 					$this->_d=self::mergeArray($this->_d,$d);
 | |
| 				}
 | |
| 				else
 | |
| 					$this->_d=self::mergeArray($this->_d,$data);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				foreach($data as $key=>$value)
 | |
| 					$this->add($key,$value);
 | |
| 			}
 | |
| 		}
 | |
| 		elseif($data!==null)
 | |
| 			throw new CException(Yii::t('yii','Map data must be an array or an object implementing Traversable.'));
 | |
| 	}
 | |
| 	public static function mergeArray($a,$b)
 | |
| 	{
 | |
| 		$args=func_get_args();
 | |
| 		$res=array_shift($args);
 | |
| 		while(!empty($args))
 | |
| 		{
 | |
| 			$next=array_shift($args);
 | |
| 			foreach($next as $k => $v)
 | |
| 			{
 | |
| 				if(is_integer($k))
 | |
| 					isset($res[$k]) ? $res[]=$v : $res[$k]=$v;
 | |
| 				elseif(is_array($v) && isset($res[$k]) && is_array($res[$k]))
 | |
| 					$res[$k]=self::mergeArray($res[$k],$v);
 | |
| 				else
 | |
| 					$res[$k]=$v;
 | |
| 			}
 | |
| 		}
 | |
| 		return $res;
 | |
| 	}
 | |
| 	public function offsetExists($offset)
 | |
| 	{
 | |
| 		return $this->contains($offset);
 | |
| 	}
 | |
| 	public function offsetGet($offset)
 | |
| 	{
 | |
| 		return $this->itemAt($offset);
 | |
| 	}
 | |
| 	public function offsetSet($offset,$item)
 | |
| 	{
 | |
| 		$this->add($offset,$item);
 | |
| 	}
 | |
| 	public function offsetUnset($offset)
 | |
| 	{
 | |
| 		$this->remove($offset);
 | |
| 	}
 | |
| }
 | |
| class CLogger extends CComponent
 | |
| {
 | |
| 	const LEVEL_TRACE='trace';
 | |
| 	const LEVEL_WARNING='warning';
 | |
| 	const LEVEL_ERROR='error';
 | |
| 	const LEVEL_INFO='info';
 | |
| 	const LEVEL_PROFILE='profile';
 | |
| 	public $autoFlush=10000;
 | |
| 	public $autoDump=false;
 | |
| 	private $_logs=array();
 | |
| 	private $_logCount=0;
 | |
| 	private $_levels;
 | |
| 	private $_categories;
 | |
| 	private $_except=array();
 | |
| 	private $_timings;
 | |
| 	private $_processing=false;
 | |
| 	public function log($message,$level='info',$category='application')
 | |
| 	{
 | |
| 		$this->_logs[]=array($message,$level,$category,microtime(true));
 | |
| 		$this->_logCount++;
 | |
| 		if($this->autoFlush>0 && $this->_logCount>=$this->autoFlush && !$this->_processing)
 | |
| 		{
 | |
| 			$this->_processing=true;
 | |
| 			$this->flush($this->autoDump);
 | |
| 			$this->_processing=false;
 | |
| 		}
 | |
| 	}
 | |
| 	public function getLogs($levels='',$categories=array(), $except=array())
 | |
| 	{
 | |
| 		$this->_levels=preg_split('/[\s,]+/',strtolower($levels),-1,PREG_SPLIT_NO_EMPTY);
 | |
| 		if (is_string($categories))
 | |
| 			$this->_categories=preg_split('/[\s,]+/',strtolower($categories),-1,PREG_SPLIT_NO_EMPTY);
 | |
| 		else
 | |
| 			$this->_categories=array_filter(array_map('strtolower',$categories));
 | |
| 		if (is_string($except))
 | |
| 			$this->_except=preg_split('/[\s,]+/',strtolower($except),-1,PREG_SPLIT_NO_EMPTY);
 | |
| 		else
 | |
| 			$this->_except=array_filter(array_map('strtolower',$except));
 | |
| 		$ret=$this->_logs;
 | |
| 		if(!empty($levels))
 | |
| 			$ret=array_values(array_filter($ret,array($this,'filterByLevel')));
 | |
| 		if(!empty($this->_categories) || !empty($this->_except))
 | |
| 			$ret=array_values(array_filter($ret,array($this,'filterByCategory')));
 | |
| 		return $ret;
 | |
| 	}
 | |
| 	private function filterByCategory($value)
 | |
| 	{
 | |
| 		return $this->filterAllCategories($value, 2);
 | |
| 	}
 | |
| 	private function filterTimingByCategory($value)
 | |
| 	{
 | |
| 		return $this->filterAllCategories($value, 1);
 | |
| 	}
 | |
| 	private function filterAllCategories($value, $index)
 | |
| 	{
 | |
| 		$cat=strtolower($value[$index]);
 | |
| 		$ret=empty($this->_categories);
 | |
| 		foreach($this->_categories as $category)
 | |
| 		{
 | |
| 			if($cat===$category || (($c=rtrim($category,'.*'))!==$category && strpos($cat,$c)===0))
 | |
| 				$ret=true;
 | |
| 		}
 | |
| 		if($ret)
 | |
| 		{
 | |
| 			foreach($this->_except as $category)
 | |
| 			{
 | |
| 				if($cat===$category || (($c=rtrim($category,'.*'))!==$category && strpos($cat,$c)===0))
 | |
| 					$ret=false;
 | |
| 			}
 | |
| 		}
 | |
| 		return $ret;
 | |
| 	}
 | |
| 	private function filterByLevel($value)
 | |
| 	{
 | |
| 		return in_array(strtolower($value[1]),$this->_levels);
 | |
| 	}
 | |
| 	public function getExecutionTime()
 | |
| 	{
 | |
| 		return microtime(true)-YII_BEGIN_TIME;
 | |
| 	}
 | |
| 	public function getMemoryUsage()
 | |
| 	{
 | |
| 		if(function_exists('memory_get_usage'))
 | |
| 			return memory_get_usage();
 | |
| 		else
 | |
| 		{
 | |
| 			$output=array();
 | |
| 			if(strncmp(PHP_OS,'WIN',3)===0)
 | |
| 			{
 | |
| 				exec('tasklist /FI "PID eq ' . getmypid() . '" /FO LIST',$output);
 | |
| 				return isset($output[5])?preg_replace('/[\D]/','',$output[5])*1024 : 0;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				$pid=getmypid();
 | |
| 				exec("ps -eo%mem,rss,pid | grep $pid", $output);
 | |
| 				$output=explode("  ",$output[0]);
 | |
| 				return isset($output[1]) ? $output[1]*1024 : 0;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	public function getProfilingResults($token=null,$categories=null,$refresh=false)
 | |
| 	{
 | |
| 		if($this->_timings===null || $refresh)
 | |
| 			$this->calculateTimings();
 | |
| 		if($token===null && $categories===null)
 | |
| 			return $this->_timings;
 | |
| 		$timings = $this->_timings;
 | |
| 		if($categories!==null) {
 | |
| 			$this->_categories=preg_split('/[\s,]+/',strtolower($categories),-1,PREG_SPLIT_NO_EMPTY);
 | |
| 			$timings=array_filter($timings,array($this,'filterTimingByCategory'));
 | |
| 		}
 | |
| 		$results=array();
 | |
| 		foreach($timings as $timing)
 | |
| 		{
 | |
| 			if($token===null || $timing[0]===$token)
 | |
| 				$results[]=$timing[2];
 | |
| 		}
 | |
| 		return $results;
 | |
| 	}
 | |
| 	private function calculateTimings()
 | |
| 	{
 | |
| 		$this->_timings=array();
 | |
| 		$stack=array();
 | |
| 		foreach($this->_logs as $log)
 | |
| 		{
 | |
| 			if($log[1]!==CLogger::LEVEL_PROFILE)
 | |
| 				continue;
 | |
| 			list($message,$level,$category,$timestamp)=$log;
 | |
| 			if(!strncasecmp($message,'begin:',6))
 | |
| 			{
 | |
| 				$log[0]=substr($message,6);
 | |
| 				$stack[]=$log;
 | |
| 			}
 | |
| 			elseif(!strncasecmp($message,'end:',4))
 | |
| 			{
 | |
| 				$token=substr($message,4);
 | |
| 				if(($last=array_pop($stack))!==null && $last[0]===$token)
 | |
| 				{
 | |
| 					$delta=$log[3]-$last[3];
 | |
| 					$this->_timings[]=array($message,$category,$delta);
 | |
| 				}
 | |
| 				else
 | |
| 					throw new CException(Yii::t('yii','CProfileLogRoute found a mismatching code block "{token}". Make sure the calls to Yii::beginProfile() and Yii::endProfile() be properly nested.',
 | |
| 						array('{token}'=>$token)));
 | |
| 			}
 | |
| 		}
 | |
| 		$now=microtime(true);
 | |
| 		while(($last=array_pop($stack))!==null)
 | |
| 		{
 | |
| 			$delta=$now-$last[3];
 | |
| 			$this->_timings[]=array($last[0],$last[2],$delta);
 | |
| 		}
 | |
| 	}
 | |
| 	public function flush($dumpLogs=false)
 | |
| 	{
 | |
| 		$this->onFlush(new CEvent($this, array('dumpLogs'=>$dumpLogs)));
 | |
| 		$this->_logs=array();
 | |
| 		$this->_logCount=0;
 | |
| 	}
 | |
| 	public function onFlush($event)
 | |
| 	{
 | |
| 		$this->raiseEvent('onFlush', $event);
 | |
| 	}
 | |
| }
 | |
| abstract class CApplicationComponent extends CComponent implements IApplicationComponent
 | |
| {
 | |
| 	public $behaviors=array();
 | |
| 	private $_initialized=false;
 | |
| 	public function init()
 | |
| 	{
 | |
| 		$this->attachBehaviors($this->behaviors);
 | |
| 		$this->_initialized=true;
 | |
| 	}
 | |
| 	public function getIsInitialized()
 | |
| 	{
 | |
| 		return $this->_initialized;
 | |
| 	}
 | |
| }
 | |
| class CHttpRequest extends CApplicationComponent
 | |
| {
 | |
| 	public $enableCookieValidation=false;
 | |
| 	public $enableCsrfValidation=false;
 | |
| 	public $csrfTokenName='YII_CSRF_TOKEN';
 | |
| 	public $csrfCookie;
 | |
| 	private $_requestUri;
 | |
| 	private $_pathInfo;
 | |
| 	private $_scriptFile;
 | |
| 	private $_scriptUrl;
 | |
| 	private $_hostInfo;
 | |
| 	private $_baseUrl;
 | |
| 	private $_cookies;
 | |
| 	private $_preferredAcceptTypes;
 | |
| 	private $_preferredLanguages;
 | |
| 	private $_csrfToken;
 | |
| 	private $_restParams;
 | |
| 	public function init()
 | |
| 	{
 | |
| 		parent::init();
 | |
| 		$this->normalizeRequest();
 | |
| 	}
 | |
| 	protected function normalizeRequest()
 | |
| 	{
 | |
| 		// normalize request
 | |
| 		if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc())
 | |
| 		{
 | |
| 			if(isset($_GET))
 | |
| 				$_GET=$this->stripSlashes($_GET);
 | |
| 			if(isset($_POST))
 | |
| 				$_POST=$this->stripSlashes($_POST);
 | |
| 			if(isset($_REQUEST))
 | |
| 				$_REQUEST=$this->stripSlashes($_REQUEST);
 | |
| 			if(isset($_COOKIE))
 | |
| 				$_COOKIE=$this->stripSlashes($_COOKIE);
 | |
| 		}
 | |
| 		if($this->enableCsrfValidation)
 | |
| 			Yii::app()->attachEventHandler('onBeginRequest',array($this,'validateCsrfToken'));
 | |
| 	}
 | |
| 	public function stripSlashes(&$data)
 | |
| 	{
 | |
| 		if(is_array($data))
 | |
| 		{
 | |
| 			if(count($data) == 0)
 | |
| 				return $data;
 | |
| 			$keys=array_map('stripslashes',array_keys($data));
 | |
| 			$data=array_combine($keys,array_values($data));
 | |
| 			return array_map(array($this,'stripSlashes'),$data);
 | |
| 		}
 | |
| 		else
 | |
| 			return stripslashes($data);
 | |
| 	}
 | |
| 	public function getParam($name,$defaultValue=null)
 | |
| 	{
 | |
| 		return isset($_GET[$name]) ? $_GET[$name] : (isset($_POST[$name]) ? $_POST[$name] : $defaultValue);
 | |
| 	}
 | |
| 	public function getQuery($name,$defaultValue=null)
 | |
| 	{
 | |
| 		return isset($_GET[$name]) ? $_GET[$name] : $defaultValue;
 | |
| 	}
 | |
| 	public function getPost($name,$defaultValue=null)
 | |
| 	{
 | |
| 		return isset($_POST[$name]) ? $_POST[$name] : $defaultValue;
 | |
| 	}
 | |
| 	public function getDelete($name,$defaultValue=null)
 | |
| 	{
 | |
| 		if($this->getIsDeleteViaPostRequest())
 | |
| 			return $this->getPost($name, $defaultValue);
 | |
| 		if($this->getIsDeleteRequest())
 | |
| 		{
 | |
| 			$restParams=$this->getRestParams();
 | |
| 			return isset($restParams[$name]) ? $restParams[$name] : $defaultValue;
 | |
| 		}
 | |
| 		else
 | |
| 			return $defaultValue;
 | |
| 	}
 | |
| 	public function getPut($name,$defaultValue=null)
 | |
| 	{
 | |
| 		if($this->getIsPutViaPostRequest())
 | |
| 			return $this->getPost($name, $defaultValue);
 | |
| 		if($this->getIsPutRequest())
 | |
| 		{
 | |
| 			$restParams=$this->getRestParams();
 | |
| 			return isset($restParams[$name]) ? $restParams[$name] : $defaultValue;
 | |
| 		}
 | |
| 		else
 | |
| 			return $defaultValue;
 | |
| 	}
 | |
| 	public function getRestParams()
 | |
| 	{
 | |
| 		if($this->_restParams===null)
 | |
| 		{
 | |
| 			$result=array();
 | |
| 			if(function_exists('mb_parse_str'))
 | |
| 				mb_parse_str($this->getRawBody(), $result);
 | |
| 			else
 | |
| 				parse_str($this->getRawBody(), $result);
 | |
| 			$this->_restParams=$result;
 | |
| 		}
 | |
| 		return $this->_restParams;
 | |
| 	}
 | |
| 	public function getRawBody()
 | |
| 	{
 | |
| 		static $rawBody;
 | |
| 		if($rawBody===null)
 | |
| 			$rawBody=file_get_contents('php://input');
 | |
| 		return $rawBody;
 | |
| 	}
 | |
| 	public function getUrl()
 | |
| 	{
 | |
| 		return $this->getRequestUri();
 | |
| 	}
 | |
| 	public function getHostInfo($schema='')
 | |
| 	{
 | |
| 		if($this->_hostInfo===null)
 | |
| 		{
 | |
| 			if($secure=$this->getIsSecureConnection())
 | |
| 				$http='https';
 | |
| 			else
 | |
| 				$http='http';
 | |
| 			if(isset($_SERVER['HTTP_HOST']))
 | |
| 				$this->_hostInfo=$http.'://'.$_SERVER['HTTP_HOST'];
 | |
| 			else
 | |
| 			{
 | |
| 				$this->_hostInfo=$http.'://'.$_SERVER['SERVER_NAME'];
 | |
| 				$port=$secure ? $this->getSecurePort() : $this->getPort();
 | |
| 				if(($port!==80 && !$secure) || ($port!==443 && $secure))
 | |
| 					$this->_hostInfo.=':'.$port;
 | |
| 			}
 | |
| 		}
 | |
| 		if($schema!=='')
 | |
| 		{
 | |
| 			$secure=$this->getIsSecureConnection();
 | |
| 			if($secure && $schema==='https' || !$secure && $schema==='http')
 | |
| 				return $this->_hostInfo;
 | |
| 			$port=$schema==='https' ? $this->getSecurePort() : $this->getPort();
 | |
| 			if($port!==80 && $schema==='http' || $port!==443 && $schema==='https')
 | |
| 				$port=':'.$port;
 | |
| 			else
 | |
| 				$port='';
 | |
| 			$pos=strpos($this->_hostInfo,':');
 | |
| 			return $schema.substr($this->_hostInfo,$pos,strcspn($this->_hostInfo,':',$pos+1)+1).$port;
 | |
| 		}
 | |
| 		else
 | |
| 			return $this->_hostInfo;
 | |
| 	}
 | |
| 	public function setHostInfo($value)
 | |
| 	{
 | |
| 		$this->_hostInfo=rtrim($value,'/');
 | |
| 	}
 | |
| 	public function getBaseUrl($absolute=false)
 | |
| 	{
 | |
| 		if($this->_baseUrl===null)
 | |
| 			$this->_baseUrl=rtrim(dirname($this->getScriptUrl()),'\\/');
 | |
| 		return $absolute ? $this->getHostInfo() . $this->_baseUrl : $this->_baseUrl;
 | |
| 	}
 | |
| 	public function setBaseUrl($value)
 | |
| 	{
 | |
| 		$this->_baseUrl=$value;
 | |
| 	}
 | |
| 	public function getScriptUrl()
 | |
| 	{
 | |
| 		if($this->_scriptUrl===null)
 | |
| 		{
 | |
| 			$scriptName=basename($_SERVER['SCRIPT_FILENAME']);
 | |
| 			if(basename($_SERVER['SCRIPT_NAME'])===$scriptName)
 | |
| 				$this->_scriptUrl=$_SERVER['SCRIPT_NAME'];
 | |
| 			elseif(basename($_SERVER['PHP_SELF'])===$scriptName)
 | |
| 				$this->_scriptUrl=$_SERVER['PHP_SELF'];
 | |
| 			elseif(isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME'])===$scriptName)
 | |
| 				$this->_scriptUrl=$_SERVER['ORIG_SCRIPT_NAME'];
 | |
| 			elseif(($pos=strpos($_SERVER['PHP_SELF'],'/'.$scriptName))!==false)
 | |
| 				$this->_scriptUrl=substr($_SERVER['SCRIPT_NAME'],0,$pos).'/'.$scriptName;
 | |
| 			elseif(isset($_SERVER['DOCUMENT_ROOT']) && strpos($_SERVER['SCRIPT_FILENAME'],$_SERVER['DOCUMENT_ROOT'])===0)
 | |
| 				$this->_scriptUrl=str_replace('\\','/',str_replace($_SERVER['DOCUMENT_ROOT'],'',$_SERVER['SCRIPT_FILENAME']));
 | |
| 			else
 | |
| 				throw new CException(Yii::t('yii','CHttpRequest is unable to determine the entry script URL.'));
 | |
| 		}
 | |
| 		return $this->_scriptUrl;
 | |
| 	}
 | |
| 	public function setScriptUrl($value)
 | |
| 	{
 | |
| 		$this->_scriptUrl='/'.trim($value,'/');
 | |
| 	}
 | |
| 	public function getPathInfo()
 | |
| 	{
 | |
| 		if($this->_pathInfo===null)
 | |
| 		{
 | |
| 			$pathInfo=$this->getRequestUri();
 | |
| 			if(($pos=strpos($pathInfo,'?'))!==false)
 | |
| 			   $pathInfo=substr($pathInfo,0,$pos);
 | |
| 			$pathInfo=$this->decodePathInfo($pathInfo);
 | |
| 			$scriptUrl=$this->getScriptUrl();
 | |
| 			$baseUrl=$this->getBaseUrl();
 | |
| 			if(strpos($pathInfo,$scriptUrl)===0)
 | |
| 				$pathInfo=substr($pathInfo,strlen($scriptUrl));
 | |
| 			elseif($baseUrl==='' || strpos($pathInfo,$baseUrl)===0)
 | |
| 				$pathInfo=substr($pathInfo,strlen($baseUrl));
 | |
| 			elseif(strpos($_SERVER['PHP_SELF'],$scriptUrl)===0)
 | |
| 				$pathInfo=substr($_SERVER['PHP_SELF'],strlen($scriptUrl));
 | |
| 			else
 | |
| 				throw new CException(Yii::t('yii','CHttpRequest is unable to determine the path info of the request.'));
 | |
| 			$this->_pathInfo=trim($pathInfo,'/');
 | |
| 		}
 | |
| 		return $this->_pathInfo;
 | |
| 	}
 | |
| 	protected function decodePathInfo($pathInfo)
 | |
| 	{
 | |
| 		$pathInfo = urldecode($pathInfo);
 | |
| 		// is it UTF-8?
 | |
| 		// http://w3.org/International/questions/qa-forms-utf-8.html
 | |
| 		if(preg_match('%^(?:
 | |
| 		   [\x09\x0A\x0D\x20-\x7E]            # ASCII
 | |
| 		 | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
 | |
| 		 | \xE0[\xA0-\xBF][\x80-\xBF]         # excluding overlongs
 | |
| 		 | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
 | |
| 		 | \xED[\x80-\x9F][\x80-\xBF]         # excluding surrogates
 | |
| 		 | \xF0[\x90-\xBF][\x80-\xBF]{2}      # planes 1-3
 | |
| 		 | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
 | |
| 		 | \xF4[\x80-\x8F][\x80-\xBF]{2}      # plane 16
 | |
| 		)*$%xs', $pathInfo))
 | |
| 		{
 | |
| 			return $pathInfo;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			return utf8_encode($pathInfo);
 | |
| 		}
 | |
| 	}
 | |
| 	public function getRequestUri()
 | |
| 	{
 | |
| 		if($this->_requestUri===null)
 | |
| 		{
 | |
| 			if(isset($_SERVER['HTTP_X_REWRITE_URL'])) // IIS
 | |
| 				$this->_requestUri=$_SERVER['HTTP_X_REWRITE_URL'];
 | |
| 			elseif(isset($_SERVER['REQUEST_URI']))
 | |
| 			{
 | |
| 				$this->_requestUri=$_SERVER['REQUEST_URI'];
 | |
| 				if(!empty($_SERVER['HTTP_HOST']))
 | |
| 				{
 | |
| 					if(strpos($this->_requestUri,$_SERVER['HTTP_HOST'])!==false)
 | |
| 						$this->_requestUri=preg_replace('/^\w+:\/\/[^\/]+/','',$this->_requestUri);
 | |
| 				}
 | |
| 				else
 | |
| 					$this->_requestUri=preg_replace('/^(http|https):\/\/[^\/]+/i','',$this->_requestUri);
 | |
| 			}
 | |
| 			elseif(isset($_SERVER['ORIG_PATH_INFO']))  // IIS 5.0 CGI
 | |
| 			{
 | |
| 				$this->_requestUri=$_SERVER['ORIG_PATH_INFO'];
 | |
| 				if(!empty($_SERVER['QUERY_STRING']))
 | |
| 					$this->_requestUri.='?'.$_SERVER['QUERY_STRING'];
 | |
| 			}
 | |
| 			else
 | |
| 				throw new CException(Yii::t('yii','CHttpRequest is unable to determine the request URI.'));
 | |
| 		}
 | |
| 		return $this->_requestUri;
 | |
| 	}
 | |
| 	public function getQueryString()
 | |
| 	{
 | |
| 		return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:'';
 | |
| 	}
 | |
| 	public function getIsSecureConnection()
 | |
| 	{
 | |
| 		return isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS']=='on' || $_SERVER['HTTPS']==1)
 | |
| 			|| isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO']=='https';
 | |
| 	}
 | |
| 	public function getRequestType()
 | |
| 	{
 | |
| 		if(isset($_POST['_method']))
 | |
| 			return strtoupper($_POST['_method']);
 | |
| 		return strtoupper(isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:'GET');
 | |
| 	}
 | |
| 	public function getIsPostRequest()
 | |
| 	{
 | |
| 		return isset($_SERVER['REQUEST_METHOD']) && !strcasecmp($_SERVER['REQUEST_METHOD'],'POST');
 | |
| 	}
 | |
| 	public function getIsDeleteRequest()
 | |
| 	{
 | |
| 		return (isset($_SERVER['REQUEST_METHOD']) && !strcasecmp($_SERVER['REQUEST_METHOD'],'DELETE')) || $this->getIsDeleteViaPostRequest();
 | |
| 	}
 | |
| 	protected function getIsDeleteViaPostRequest()
 | |
| 	{
 | |
| 		return isset($_POST['_method']) && !strcasecmp($_POST['_method'],'DELETE');
 | |
| 	}
 | |
| 	public function getIsPutRequest()
 | |
| 	{
 | |
| 		return (isset($_SERVER['REQUEST_METHOD']) && !strcasecmp($_SERVER['REQUEST_METHOD'],'PUT')) || $this->getIsPutViaPostRequest();
 | |
| 	}
 | |
| 	protected function getIsPutViaPostRequest()
 | |
| 	{
 | |
| 		return isset($_POST['_method']) && !strcasecmp($_POST['_method'],'PUT');
 | |
| 	}
 | |
| 	public function getIsAjaxRequest()
 | |
| 	{
 | |
| 		return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH']==='XMLHttpRequest';
 | |
| 	}
 | |
| 	public function getIsFlashRequest()
 | |
| 	{
 | |
| 		return isset($_SERVER['HTTP_USER_AGENT']) && (stripos($_SERVER['HTTP_USER_AGENT'],'Shockwave')!==false || stripos($_SERVER['HTTP_USER_AGENT'],'Flash')!==false);
 | |
| 	}
 | |
| 	public function getServerName()
 | |
| 	{
 | |
| 		return $_SERVER['SERVER_NAME'];
 | |
| 	}
 | |
| 	public function getServerPort()
 | |
| 	{
 | |
| 		return $_SERVER['SERVER_PORT'];
 | |
| 	}
 | |
| 	public function getUrlReferrer()
 | |
| 	{
 | |
| 		return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null;
 | |
| 	}
 | |
| 	public function getUserAgent()
 | |
| 	{
 | |
| 		return isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:null;
 | |
| 	}
 | |
| 	public function getUserHostAddress()
 | |
| 	{
 | |
| 		return isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:'127.0.0.1';
 | |
| 	}
 | |
| 	public function getUserHost()
 | |
| 	{
 | |
| 		return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null;
 | |
| 	}
 | |
| 	public function getScriptFile()
 | |
| 	{
 | |
| 		if($this->_scriptFile!==null)
 | |
| 			return $this->_scriptFile;
 | |
| 		else
 | |
| 			return $this->_scriptFile=realpath($_SERVER['SCRIPT_FILENAME']);
 | |
| 	}
 | |
| 	public function getBrowser($userAgent=null)
 | |
| 	{
 | |
| 		return get_browser($userAgent,true);
 | |
| 	}
 | |
| 	public function getAcceptTypes()
 | |
| 	{
 | |
| 		return isset($_SERVER['HTTP_ACCEPT'])?$_SERVER['HTTP_ACCEPT']:null;
 | |
| 	}
 | |
| 	private $_port;
 | |
| 	public function getPort()
 | |
| 	{
 | |
| 		if($this->_port===null)
 | |
| 			$this->_port=!$this->getIsSecureConnection() && isset($_SERVER['SERVER_PORT']) ? (int)$_SERVER['SERVER_PORT'] : 80;
 | |
| 		return $this->_port;
 | |
| 	}
 | |
| 	public function setPort($value)
 | |
| 	{
 | |
| 		$this->_port=(int)$value;
 | |
| 		$this->_hostInfo=null;
 | |
| 	}
 | |
| 	private $_securePort;
 | |
| 	public function getSecurePort()
 | |
| 	{
 | |
| 		if($this->_securePort===null)
 | |
| 			$this->_securePort=$this->getIsSecureConnection() && isset($_SERVER['SERVER_PORT']) ? (int)$_SERVER['SERVER_PORT'] : 443;
 | |
| 		return $this->_securePort;
 | |
| 	}
 | |
| 	public function setSecurePort($value)
 | |
| 	{
 | |
| 		$this->_securePort=(int)$value;
 | |
| 		$this->_hostInfo=null;
 | |
| 	}
 | |
| 	public function getCookies()
 | |
| 	{
 | |
| 		if($this->_cookies!==null)
 | |
| 			return $this->_cookies;
 | |
| 		else
 | |
| 			return $this->_cookies=new CCookieCollection($this);
 | |
| 	}
 | |
| 	public function redirect($url,$terminate=true,$statusCode=302)
 | |
| 	{
 | |
| 		if(strpos($url,'/')===0 && strpos($url,'//')!==0)
 | |
| 			$url=$this->getHostInfo().$url;
 | |
| 		header('Location: '.$url, true, $statusCode);
 | |
| 		if($terminate)
 | |
| 			Yii::app()->end();
 | |
| 	}
 | |
| 	public static function parseAcceptHeader($header)
 | |
| 	{
 | |
| 		$matches=array();
 | |
| 		$accepts=array();
 | |
| 		// get individual entries with their type, subtype, basetype and params
 | |
| 		preg_match_all('/(?:\G\s?,\s?|^)(\w+|\*)\/(\w+|\*)(?:\+(\w+))?|(?<!^)\G(?:\s?;\s?(\w+)=([\w\.]+))/',$header,$matches);
 | |
| 		// the regexp should (in theory) always return an array of 6 arrays
 | |
| 		if(count($matches)===6)
 | |
| 		{
 | |
| 			$i=0;
 | |
| 			$itemLen=count($matches[1]);
 | |
| 			while($i<$itemLen)
 | |
| 			{
 | |
| 				// fill out a content type
 | |
| 				$accept=array(
 | |
| 					'type'=>$matches[1][$i],
 | |
| 					'subType'=>$matches[2][$i],
 | |
| 					'baseType'=>null,
 | |
| 					'params'=>array(),
 | |
| 				);
 | |
| 				// fill in the base type if it exists
 | |
| 				if($matches[3][$i]!==null && $matches[3][$i]!=='')
 | |
| 					$accept['baseType']=$matches[3][$i];
 | |
| 				// continue looping while there is no new content type, to fill in all accompanying params
 | |
| 				for($i++;$i<$itemLen;$i++)
 | |
| 				{
 | |
| 					// if the next content type is null, then the item is a param for the current content type
 | |
| 					if($matches[1][$i]===null || $matches[1][$i]==='')
 | |
| 					{
 | |
| 						// if this is the quality param, convert it to a double
 | |
| 						if($matches[4][$i]==='q')
 | |
| 						{
 | |
| 							// sanity check on q value
 | |
| 							$q=(double)$matches[5][$i];
 | |
| 							if($q>1)
 | |
| 								$q=(double)1;
 | |
| 							elseif($q<0)
 | |
| 								$q=(double)0;
 | |
| 							$accept['params'][$matches[4][$i]]=$q;
 | |
| 						}
 | |
| 						else
 | |
| 							$accept['params'][$matches[4][$i]]=$matches[5][$i];
 | |
| 					}
 | |
| 					else
 | |
| 						break;
 | |
| 				}
 | |
| 				// q defaults to 1 if not explicitly given
 | |
| 				if(!isset($accept['params']['q']))
 | |
| 					$accept['params']['q']=(double)1;
 | |
| 				$accepts[] = $accept;
 | |
| 			}
 | |
| 		}
 | |
| 		return $accepts;
 | |
| 	}
 | |
| 	public static function compareAcceptTypes($a,$b)
 | |
| 	{
 | |
| 		// check for equal quality first
 | |
| 		if($a['params']['q']===$b['params']['q'])
 | |
| 			if(!($a['type']==='*' xor $b['type']==='*'))
 | |
| 				if (!($a['subType']==='*' xor $b['subType']==='*'))
 | |
| 					// finally, higher number of parameters counts as greater precedence
 | |
| 					if(count($a['params'])===count($b['params']))
 | |
| 						return 0;
 | |
| 					else
 | |
| 						return count($a['params'])<count($b['params']) ? 1 : -1;
 | |
| 				// more specific takes precedence - whichever one doesn't have a * subType
 | |
| 				else
 | |
| 					return $a['subType']==='*' ? 1 : -1;
 | |
| 			// more specific takes precedence - whichever one doesn't have a * type
 | |
| 			else
 | |
| 				return $a['type']==='*' ? 1 : -1;
 | |
| 		else
 | |
| 			return ($a['params']['q']<$b['params']['q']) ? 1 : -1;
 | |
| 	}
 | |
| 	public function getPreferredAcceptTypes()
 | |
| 	{
 | |
| 		if($this->_preferredAcceptTypes===null)
 | |
| 		{
 | |
| 			$accepts=self::parseAcceptHeader($this->getAcceptTypes());
 | |
| 			usort($accepts,array(get_class($this),'compareAcceptTypes'));
 | |
| 			$this->_preferredAcceptTypes=$accepts;
 | |
| 		}
 | |
| 		return $this->_preferredAcceptTypes;
 | |
| 	}
 | |
| 	public function getPreferredAcceptType()
 | |
| 	{
 | |
| 		$preferredAcceptTypes=$this->getPreferredAcceptTypes();
 | |
| 		return empty($preferredAcceptTypes) ? false : $preferredAcceptTypes[0];
 | |
| 	}
 | |
| 	public function getPreferredLanguages()
 | |
| 	{
 | |
| 		if($this->_preferredLanguages===null)
 | |
| 		{
 | |
| 			$sortedLanguages=array();
 | |
| 			if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && $n=preg_match_all('/([\w\-_]+)(?:\s*;\s*q\s*=\s*(\d*\.?\d*))?/',$_SERVER['HTTP_ACCEPT_LANGUAGE'],$matches))
 | |
| 			{
 | |
| 				$languages=array();
 | |
| 				for($i=0;$i<$n;++$i)
 | |
| 				{
 | |
| 					$q=$matches[2][$i];
 | |
| 					if($q==='')
 | |
| 						$q=1;
 | |
| 					if($q)
 | |
| 						$languages[]=array((float)$q,$matches[1][$i]);
 | |
| 				}
 | |
| 				usort($languages,create_function('$a,$b','if($a[0]==$b[0]) {return 0;} return ($a[0]<$b[0]) ? 1 : -1;'));
 | |
| 				foreach($languages as $language)
 | |
| 					$sortedLanguages[]=$language[1];
 | |
| 			}
 | |
| 			$this->_preferredLanguages=$sortedLanguages;
 | |
| 		}
 | |
| 		return $this->_preferredLanguages;
 | |
| 	}
 | |
| 	public function getPreferredLanguage()
 | |
| 	{
 | |
| 		$preferredLanguages=$this->getPreferredLanguages();
 | |
| 		return !empty($preferredLanguages) ? CLocale::getCanonicalID($preferredLanguages[0]) : false;
 | |
| 	}
 | |
| 	public function sendFile($fileName,$content,$mimeType=null,$terminate=true)
 | |
| 	{
 | |
| 		if($mimeType===null)
 | |
| 		{
 | |
| 			if(($mimeType=CFileHelper::getMimeTypeByExtension($fileName))===null)
 | |
| 				$mimeType='text/plain';
 | |
| 		}
 | |
| 		$fileSize=(function_exists('mb_strlen') ? mb_strlen($content,'8bit') : strlen($content));
 | |
| 		$contentStart=0;
 | |
| 		$contentEnd=$fileSize-1;
 | |
| 		if(isset($_SERVER['HTTP_RANGE']))
 | |
| 		{
 | |
| 			header('Accept-Ranges: bytes');
 | |
| 			//client sent us a multibyte range, can not hold this one for now
 | |
| 			if(strpos($_SERVER['HTTP_RANGE'],',')!==false)
 | |
| 			{
 | |
| 				header("Content-Range: bytes $contentStart-$contentEnd/$fileSize");
 | |
| 				throw new CHttpException(416,'Requested Range Not Satisfiable');
 | |
| 			}
 | |
| 			$range=str_replace('bytes=','',$_SERVER['HTTP_RANGE']);
 | |
| 			//range requests starts from "-", so it means that data must be dumped the end point.
 | |
| 			if($range[0]==='-')
 | |
| 				$contentStart=$fileSize-substr($range,1);
 | |
| 			else
 | |
| 			{
 | |
| 				$range=explode('-',$range);
 | |
| 				$contentStart=$range[0];
 | |
| 				// check if the last-byte-pos presents in header
 | |
| 				if((isset($range[1]) && is_numeric($range[1])))
 | |
| 					$contentEnd=$range[1];
 | |
| 			}
 | |
| 			/* Check the range and make sure it's treated according to the specs.
 | |
| 			 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
 | |
| 			 */
 | |
| 			// End bytes can not be larger than $end.
 | |
| 			$contentEnd=($contentEnd > $fileSize) ? $fileSize-1 : $contentEnd;
 | |
| 			// Validate the requested range and return an error if it's not correct.
 | |
| 			$wrongContentStart=($contentStart>$contentEnd || $contentStart>$fileSize-1 || $contentStart<0);
 | |
| 			if($wrongContentStart)
 | |
| 			{
 | |
| 				header("Content-Range: bytes $contentStart-$contentEnd/$fileSize");
 | |
| 				throw new CHttpException(416,'Requested Range Not Satisfiable');
 | |
| 			}
 | |
| 			header('HTTP/1.1 206 Partial Content');
 | |
| 			header("Content-Range: bytes $contentStart-$contentEnd/$fileSize");
 | |
| 		}
 | |
| 		else
 | |
| 			header('HTTP/1.1 200 OK');
 | |
| 		$length=$contentEnd-$contentStart+1; // Calculate new content length
 | |
| 		header('Pragma: public');
 | |
| 		header('Expires: 0');
 | |
| 		header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
 | |
| 		header("Content-Type: $mimeType");
 | |
| 		header('Content-Length: '.$length);
 | |
| 		header("Content-Disposition: attachment; filename=\"$fileName\"");
 | |
| 		header('Content-Transfer-Encoding: binary');
 | |
| 		$content=function_exists('mb_substr') ? mb_substr($content,$contentStart,$length) : substr($content,$contentStart,$length);
 | |
| 		if($terminate)
 | |
| 		{
 | |
| 			// clean up the application first because the file downloading could take long time
 | |
| 			// which may cause timeout of some resources (such as DB connection)
 | |
| 			ob_start();
 | |
| 			Yii::app()->end(0,false);
 | |
| 			ob_end_clean();
 | |
| 			echo $content;
 | |
| 			exit(0);
 | |
| 		}
 | |
| 		else
 | |
| 			echo $content;
 | |
| 	}
 | |
| 	public function xSendFile($filePath, $options=array())
 | |
| 	{
 | |
| 		if(!isset($options['forceDownload']) || $options['forceDownload'])
 | |
| 			$disposition='attachment';
 | |
| 		else
 | |
| 			$disposition='inline';
 | |
| 		if(!isset($options['saveName']))
 | |
| 			$options['saveName']=basename($filePath);
 | |
| 		if(!isset($options['mimeType']))
 | |
| 		{
 | |
| 			if(($options['mimeType']=CFileHelper::getMimeTypeByExtension($filePath))===null)
 | |
| 				$options['mimeType']='text/plain';
 | |
| 		}
 | |
| 		if(!isset($options['xHeader']))
 | |
| 			$options['xHeader']='X-Sendfile';
 | |
| 		if($options['mimeType']!==null)
 | |
| 			header('Content-Type: '.$options['mimeType']);
 | |
| 		header('Content-Disposition: '.$disposition.'; filename="'.$options['saveName'].'"');
 | |
| 		if(isset($options['addHeaders']))
 | |
| 		{
 | |
| 			foreach($options['addHeaders'] as $header=>$value)
 | |
| 				header($header.': '.$value);
 | |
| 		}
 | |
| 		header(trim($options['xHeader']).': '.$filePath);
 | |
| 		if(!isset($options['terminate']) || $options['terminate'])
 | |
| 			Yii::app()->end();
 | |
| 	}
 | |
| 	public function getCsrfToken()
 | |
| 	{
 | |
| 		if($this->_csrfToken===null)
 | |
| 		{
 | |
| 			$cookie=$this->getCookies()->itemAt($this->csrfTokenName);
 | |
| 			if(!$cookie || ($this->_csrfToken=$cookie->value)==null)
 | |
| 			{
 | |
| 				$cookie=$this->createCsrfCookie();
 | |
| 				$this->_csrfToken=$cookie->value;
 | |
| 				$this->getCookies()->add($cookie->name,$cookie);
 | |
| 			}
 | |
| 		}
 | |
| 		return $this->_csrfToken;
 | |
| 	}
 | |
| 	protected function createCsrfCookie()
 | |
| 	{
 | |
| 		$cookie=new CHttpCookie($this->csrfTokenName,sha1(uniqid(mt_rand(),true)));
 | |
| 		if(is_array($this->csrfCookie))
 | |
| 		{
 | |
| 			foreach($this->csrfCookie as $name=>$value)
 | |
| 				$cookie->$name=$value;
 | |
| 		}
 | |
| 		return $cookie;
 | |
| 	}
 | |
| 	public function validateCsrfToken($event)
 | |
| 	{
 | |
| 		if ($this->getIsPostRequest() ||
 | |
| 			$this->getIsPutRequest() ||
 | |
| 			$this->getIsDeleteRequest())
 | |
| 		{
 | |
| 			$cookies=$this->getCookies();
 | |
| 			$method=$this->getRequestType();
 | |
| 			switch($method)
 | |
| 			{
 | |
| 				case 'POST':
 | |
| 					$userToken=$this->getPost($this->csrfTokenName);
 | |
| 				break;
 | |
| 				case 'PUT':
 | |
| 					$userToken=$this->getPut($this->csrfTokenName);
 | |
| 				break;
 | |
| 				case 'DELETE':
 | |
| 					$userToken=$this->getDelete($this->csrfTokenName);
 | |
| 			}
 | |
| 			if (!empty($userToken) && $cookies->contains($this->csrfTokenName))
 | |
| 			{
 | |
| 				$cookieToken=$cookies->itemAt($this->csrfTokenName)->value;
 | |
| 				$valid=$cookieToken===$userToken;
 | |
| 			}
 | |
| 			else
 | |
| 				$valid = false;
 | |
| 			if (!$valid)
 | |
| 				throw new CHttpException(400,Yii::t('yii','The CSRF token could not be verified.'));
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| class CCookieCollection extends CMap
 | |
| {
 | |
| 	private $_request;
 | |
| 	private $_initialized=false;
 | |
| 	public function __construct(CHttpRequest $request)
 | |
| 	{
 | |
| 		$this->_request=$request;
 | |
| 		$this->copyfrom($this->getCookies());
 | |
| 		$this->_initialized=true;
 | |
| 	}
 | |
| 	public function getRequest()
 | |
| 	{
 | |
| 		return $this->_request;
 | |
| 	}
 | |
| 	protected function getCookies()
 | |
| 	{
 | |
| 		$cookies=array();
 | |
| 		if($this->_request->enableCookieValidation)
 | |
| 		{
 | |
| 			$sm=Yii::app()->getSecurityManager();
 | |
| 			foreach($_COOKIE as $name=>$value)
 | |
| 			{
 | |
| 				if(is_string($value) && ($value=$sm->validateData($value))!==false)
 | |
| 					$cookies[$name]=new CHttpCookie($name,@unserialize($value));
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			foreach($_COOKIE as $name=>$value)
 | |
| 				$cookies[$name]=new CHttpCookie($name,$value);
 | |
| 		}
 | |
| 		return $cookies;
 | |
| 	}
 | |
| 	public function add($name,$cookie)
 | |
| 	{
 | |
| 		if($cookie instanceof CHttpCookie)
 | |
| 		{
 | |
| 			$this->remove($name);
 | |
| 			parent::add($name,$cookie);
 | |
| 			if($this->_initialized)
 | |
| 				$this->addCookie($cookie);
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','CHttpCookieCollection can only hold CHttpCookie objects.'));
 | |
| 	}
 | |
| 	public function remove($name,$options=array())
 | |
| 	{
 | |
| 		if(($cookie=parent::remove($name))!==null)
 | |
| 		{
 | |
| 			if($this->_initialized)
 | |
| 			{
 | |
| 				$cookie->configure($options);
 | |
| 				$this->removeCookie($cookie);
 | |
| 			}
 | |
| 		}
 | |
| 		return $cookie;
 | |
| 	}
 | |
| 	protected function addCookie($cookie)
 | |
| 	{
 | |
| 		$value=$cookie->value;
 | |
| 		if($this->_request->enableCookieValidation)
 | |
| 			$value=Yii::app()->getSecurityManager()->hashData(serialize($value));
 | |
| 		if(version_compare(PHP_VERSION,'5.2.0','>='))
 | |
| 			setcookie($cookie->name,$value,$cookie->expire,$cookie->path,$cookie->domain,$cookie->secure,$cookie->httpOnly);
 | |
| 		else
 | |
| 			setcookie($cookie->name,$value,$cookie->expire,$cookie->path,$cookie->domain,$cookie->secure);
 | |
| 	}
 | |
| 	protected function removeCookie($cookie)
 | |
| 	{
 | |
| 		if(version_compare(PHP_VERSION,'5.2.0','>='))
 | |
| 			setcookie($cookie->name,'',0,$cookie->path,$cookie->domain,$cookie->secure,$cookie->httpOnly);
 | |
| 		else
 | |
| 			setcookie($cookie->name,'',0,$cookie->path,$cookie->domain,$cookie->secure);
 | |
| 	}
 | |
| }
 | |
| class CUrlManager extends CApplicationComponent
 | |
| {
 | |
| 	const CACHE_KEY='Yii.CUrlManager.rules';
 | |
| 	const GET_FORMAT='get';
 | |
| 	const PATH_FORMAT='path';
 | |
| 	public $rules=array();
 | |
| 	public $urlSuffix='';
 | |
| 	public $showScriptName=true;
 | |
| 	public $appendParams=true;
 | |
| 	public $routeVar='r';
 | |
| 	public $caseSensitive=true;
 | |
| 	public $matchValue=false;
 | |
| 	public $cacheID='cache';
 | |
| 	public $useStrictParsing=false;
 | |
| 	public $urlRuleClass='CUrlRule';
 | |
| 	private $_urlFormat=self::GET_FORMAT;
 | |
| 	private $_rules=array();
 | |
| 	private $_baseUrl;
 | |
| 	public function init()
 | |
| 	{
 | |
| 		parent::init();
 | |
| 		$this->processRules();
 | |
| 	}
 | |
| 	protected function processRules()
 | |
| 	{
 | |
| 		if(empty($this->rules) || $this->getUrlFormat()===self::GET_FORMAT)
 | |
| 			return;
 | |
| 		if($this->cacheID!==false && ($cache=Yii::app()->getComponent($this->cacheID))!==null)
 | |
| 		{
 | |
| 			$hash=md5(serialize($this->rules));
 | |
| 			if(($data=$cache->get(self::CACHE_KEY))!==false && isset($data[1]) && $data[1]===$hash)
 | |
| 			{
 | |
| 				$this->_rules=$data[0];
 | |
| 				return;
 | |
| 			}
 | |
| 		}
 | |
| 		foreach($this->rules as $pattern=>$route)
 | |
| 			$this->_rules[]=$this->createUrlRule($route,$pattern);
 | |
| 		if(isset($cache))
 | |
| 			$cache->set(self::CACHE_KEY,array($this->_rules,$hash));
 | |
| 	}
 | |
| 	public function addRules($rules,$append=true)
 | |
| 	{
 | |
| 		if ($append)
 | |
| 		{
 | |
| 			foreach($rules as $pattern=>$route)
 | |
| 				$this->_rules[]=$this->createUrlRule($route,$pattern);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$rules=array_reverse($rules);
 | |
| 			foreach($rules as $pattern=>$route)
 | |
| 				array_unshift($this->_rules, $this->createUrlRule($route,$pattern));
 | |
| 		}
 | |
| 	}
 | |
| 	protected function createUrlRule($route,$pattern)
 | |
| 	{
 | |
| 		if(is_array($route) && isset($route['class']))
 | |
| 			return $route;
 | |
| 		else
 | |
| 		{
 | |
| 			$urlRuleClass=Yii::import($this->urlRuleClass,true);
 | |
| 			return new $urlRuleClass($route,$pattern);
 | |
| 		}
 | |
| 	}
 | |
| 	public function createUrl($route,$params=array(),$ampersand='&')
 | |
| 	{
 | |
| 		unset($params[$this->routeVar]);
 | |
| 		foreach($params as $i=>$param)
 | |
| 			if($param===null)
 | |
| 				$params[$i]='';
 | |
| 		if(isset($params['#']))
 | |
| 		{
 | |
| 			$anchor='#'.$params['#'];
 | |
| 			unset($params['#']);
 | |
| 		}
 | |
| 		else
 | |
| 			$anchor='';
 | |
| 		$route=trim($route,'/');
 | |
| 		foreach($this->_rules as $i=>$rule)
 | |
| 		{
 | |
| 			if(is_array($rule))
 | |
| 				$this->_rules[$i]=$rule=Yii::createComponent($rule);
 | |
| 			if(($url=$rule->createUrl($this,$route,$params,$ampersand))!==false)
 | |
| 			{
 | |
| 				if($rule->hasHostInfo)
 | |
| 					return $url==='' ? '/'.$anchor : $url.$anchor;
 | |
| 				else
 | |
| 					return $this->getBaseUrl().'/'.$url.$anchor;
 | |
| 			}
 | |
| 		}
 | |
| 		return $this->createUrlDefault($route,$params,$ampersand).$anchor;
 | |
| 	}
 | |
| 	protected function createUrlDefault($route,$params,$ampersand)
 | |
| 	{
 | |
| 		if($this->getUrlFormat()===self::PATH_FORMAT)
 | |
| 		{
 | |
| 			$url=rtrim($this->getBaseUrl().'/'.$route,'/');
 | |
| 			if($this->appendParams)
 | |
| 			{
 | |
| 				$url=rtrim($url.'/'.$this->createPathInfo($params,'/','/'),'/');
 | |
| 				return $route==='' ? $url : $url.$this->urlSuffix;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				if($route!=='')
 | |
| 					$url.=$this->urlSuffix;
 | |
| 				$query=$this->createPathInfo($params,'=',$ampersand);
 | |
| 				return $query==='' ? $url : $url.'?'.$query;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$url=$this->getBaseUrl();
 | |
| 			if(!$this->showScriptName)
 | |
| 				$url.='/';
 | |
| 			if($route!=='')
 | |
| 			{
 | |
| 				$url.='?'.$this->routeVar.'='.$route;
 | |
| 				if(($query=$this->createPathInfo($params,'=',$ampersand))!=='')
 | |
| 					$url.=$ampersand.$query;
 | |
| 			}
 | |
| 			elseif(($query=$this->createPathInfo($params,'=',$ampersand))!=='')
 | |
| 				$url.='?'.$query;
 | |
| 			return $url;
 | |
| 		}
 | |
| 	}
 | |
| 	public function parseUrl($request)
 | |
| 	{
 | |
| 		if($this->getUrlFormat()===self::PATH_FORMAT)
 | |
| 		{
 | |
| 			$rawPathInfo=$request->getPathInfo();
 | |
| 			$pathInfo=$this->removeUrlSuffix($rawPathInfo,$this->urlSuffix);
 | |
| 			foreach($this->_rules as $i=>$rule)
 | |
| 			{
 | |
| 				if(is_array($rule))
 | |
| 					$this->_rules[$i]=$rule=Yii::createComponent($rule);
 | |
| 				if(($r=$rule->parseUrl($this,$request,$pathInfo,$rawPathInfo))!==false)
 | |
| 					return isset($_GET[$this->routeVar]) ? $_GET[$this->routeVar] : $r;
 | |
| 			}
 | |
| 			if($this->useStrictParsing)
 | |
| 				throw new CHttpException(404,Yii::t('yii','Unable to resolve the request "{route}".',
 | |
| 					array('{route}'=>$pathInfo)));
 | |
| 			else
 | |
| 				return $pathInfo;
 | |
| 		}
 | |
| 		elseif(isset($_GET[$this->routeVar]))
 | |
| 			return $_GET[$this->routeVar];
 | |
| 		elseif(isset($_POST[$this->routeVar]))
 | |
| 			return $_POST[$this->routeVar];
 | |
| 		else
 | |
| 			return '';
 | |
| 	}
 | |
| 	public function parsePathInfo($pathInfo)
 | |
| 	{
 | |
| 		if($pathInfo==='')
 | |
| 			return;
 | |
| 		$segs=explode('/',$pathInfo.'/');
 | |
| 		$n=count($segs);
 | |
| 		for($i=0;$i<$n-1;$i+=2)
 | |
| 		{
 | |
| 			$key=$segs[$i];
 | |
| 			if($key==='') continue;
 | |
| 			$value=$segs[$i+1];
 | |
| 			if(($pos=strpos($key,'['))!==false && ($m=preg_match_all('/\[(.*?)\]/',$key,$matches))>0)
 | |
| 			{
 | |
| 				$name=substr($key,0,$pos);
 | |
| 				for($j=$m-1;$j>=0;--$j)
 | |
| 				{
 | |
| 					if($matches[1][$j]==='')
 | |
| 						$value=array($value);
 | |
| 					else
 | |
| 						$value=array($matches[1][$j]=>$value);
 | |
| 				}
 | |
| 				if(isset($_GET[$name]) && is_array($_GET[$name]))
 | |
| 					$value=CMap::mergeArray($_GET[$name],$value);
 | |
| 				$_REQUEST[$name]=$_GET[$name]=$value;
 | |
| 			}
 | |
| 			else
 | |
| 				$_REQUEST[$key]=$_GET[$key]=$value;
 | |
| 		}
 | |
| 	}
 | |
| 	public function createPathInfo($params,$equal,$ampersand, $key=null)
 | |
| 	{
 | |
| 		$pairs = array();
 | |
| 		foreach($params as $k => $v)
 | |
| 		{
 | |
| 			if ($key!==null)
 | |
| 				$k = $key.'['.$k.']';
 | |
| 			if (is_array($v))
 | |
| 				$pairs[]=$this->createPathInfo($v,$equal,$ampersand, $k);
 | |
| 			else
 | |
| 				$pairs[]=urlencode($k).$equal.urlencode($v);
 | |
| 		}
 | |
| 		return implode($ampersand,$pairs);
 | |
| 	}
 | |
| 	public function removeUrlSuffix($pathInfo,$urlSuffix)
 | |
| 	{
 | |
| 		if($urlSuffix!=='' && substr($pathInfo,-strlen($urlSuffix))===$urlSuffix)
 | |
| 			return substr($pathInfo,0,-strlen($urlSuffix));
 | |
| 		else
 | |
| 			return $pathInfo;
 | |
| 	}
 | |
| 	public function getBaseUrl()
 | |
| 	{
 | |
| 		if($this->_baseUrl!==null)
 | |
| 			return $this->_baseUrl;
 | |
| 		else
 | |
| 		{
 | |
| 			if($this->showScriptName)
 | |
| 				$this->_baseUrl=Yii::app()->getRequest()->getScriptUrl();
 | |
| 			else
 | |
| 				$this->_baseUrl=Yii::app()->getRequest()->getBaseUrl();
 | |
| 			return $this->_baseUrl;
 | |
| 		}
 | |
| 	}
 | |
| 	public function setBaseUrl($value)
 | |
| 	{
 | |
| 		$this->_baseUrl=$value;
 | |
| 	}
 | |
| 	public function getUrlFormat()
 | |
| 	{
 | |
| 		return $this->_urlFormat;
 | |
| 	}
 | |
| 	public function setUrlFormat($value)
 | |
| 	{
 | |
| 		if($value===self::PATH_FORMAT || $value===self::GET_FORMAT)
 | |
| 			$this->_urlFormat=$value;
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','CUrlManager.UrlFormat must be either "path" or "get".'));
 | |
| 	}
 | |
| }
 | |
| abstract class CBaseUrlRule extends CComponent
 | |
| {
 | |
| 	public $hasHostInfo=false;
 | |
| 	abstract public function createUrl($manager,$route,$params,$ampersand);
 | |
| 	abstract public function parseUrl($manager,$request,$pathInfo,$rawPathInfo);
 | |
| }
 | |
| class CUrlRule extends CBaseUrlRule
 | |
| {
 | |
| 	public $urlSuffix;
 | |
| 	public $caseSensitive;
 | |
| 	public $defaultParams=array();
 | |
| 	public $matchValue;
 | |
| 	public $verb;
 | |
| 	public $parsingOnly=false;
 | |
| 	public $route;
 | |
| 	public $references=array();
 | |
| 	public $routePattern;
 | |
| 	public $pattern;
 | |
| 	public $template;
 | |
| 	public $params=array();
 | |
| 	public $append;
 | |
| 	public $hasHostInfo;
 | |
| 	public function __construct($route,$pattern)
 | |
| 	{
 | |
| 		if(is_array($route))
 | |
| 		{
 | |
| 			foreach(array('urlSuffix', 'caseSensitive', 'defaultParams', 'matchValue', 'verb', 'parsingOnly') as $name)
 | |
| 			{
 | |
| 				if(isset($route[$name]))
 | |
| 					$this->$name=$route[$name];
 | |
| 			}
 | |
| 			if(isset($route['pattern']))
 | |
| 				$pattern=$route['pattern'];
 | |
| 			$route=$route[0];
 | |
| 		}
 | |
| 		$this->route=trim($route,'/');
 | |
| 		$tr2['/']=$tr['/']='\\/';
 | |
| 		if(strpos($route,'<')!==false && preg_match_all('/<(\w+)>/',$route,$matches2))
 | |
| 		{
 | |
| 			foreach($matches2[1] as $name)
 | |
| 				$this->references[$name]="<$name>";
 | |
| 		}
 | |
| 		$this->hasHostInfo=!strncasecmp($pattern,'http://',7) || !strncasecmp($pattern,'https://',8);
 | |
| 		if($this->verb!==null)
 | |
| 			$this->verb=preg_split('/[\s,]+/',strtoupper($this->verb),-1,PREG_SPLIT_NO_EMPTY);
 | |
| 		if(preg_match_all('/<(\w+):?(.*?)?>/',$pattern,$matches))
 | |
| 		{
 | |
| 			$tokens=array_combine($matches[1],$matches[2]);
 | |
| 			foreach($tokens as $name=>$value)
 | |
| 			{
 | |
| 				if($value==='')
 | |
| 					$value='[^\/]+';
 | |
| 				$tr["<$name>"]="(?P<$name>$value)";
 | |
| 				if(isset($this->references[$name]))
 | |
| 					$tr2["<$name>"]=$tr["<$name>"];
 | |
| 				else
 | |
| 					$this->params[$name]=$value;
 | |
| 			}
 | |
| 		}
 | |
| 		$p=rtrim($pattern,'*');
 | |
| 		$this->append=$p!==$pattern;
 | |
| 		$p=trim($p,'/');
 | |
| 		$this->template=preg_replace('/<(\w+):?.*?>/','<$1>',$p);
 | |
| 		$this->pattern='/^'.strtr($this->template,$tr).'\/';
 | |
| 		if($this->append)
 | |
| 			$this->pattern.='/u';
 | |
| 		else
 | |
| 			$this->pattern.='$/u';
 | |
| 		if($this->references!==array())
 | |
| 			$this->routePattern='/^'.strtr($this->route,$tr2).'$/u';
 | |
| 		if(YII_DEBUG && @preg_match($this->pattern,'test')===false)
 | |
| 			throw new CException(Yii::t('yii','The URL pattern "{pattern}" for route "{route}" is not a valid regular expression.',
 | |
| 				array('{route}'=>$route,'{pattern}'=>$pattern)));
 | |
| 	}
 | |
| 	public function createUrl($manager,$route,$params,$ampersand)
 | |
| 	{
 | |
| 		if($this->parsingOnly)
 | |
| 			return false;
 | |
| 		if($manager->caseSensitive && $this->caseSensitive===null || $this->caseSensitive)
 | |
| 			$case='';
 | |
| 		else
 | |
| 			$case='i';
 | |
| 		$tr=array();
 | |
| 		if($route!==$this->route)
 | |
| 		{
 | |
| 			if($this->routePattern!==null && preg_match($this->routePattern.$case,$route,$matches))
 | |
| 			{
 | |
| 				foreach($this->references as $key=>$name)
 | |
| 					$tr[$name]=$matches[$key];
 | |
| 			}
 | |
| 			else
 | |
| 				return false;
 | |
| 		}
 | |
| 		foreach($this->defaultParams as $key=>$value)
 | |
| 		{
 | |
| 			if(isset($params[$key]))
 | |
| 			{
 | |
| 				if($params[$key]==$value)
 | |
| 					unset($params[$key]);
 | |
| 				else
 | |
| 					return false;
 | |
| 			}
 | |
| 		}
 | |
| 		foreach($this->params as $key=>$value)
 | |
| 			if(!isset($params[$key]))
 | |
| 				return false;
 | |
| 		if($manager->matchValue && $this->matchValue===null || $this->matchValue)
 | |
| 		{
 | |
| 			foreach($this->params as $key=>$value)
 | |
| 			{
 | |
| 				if(!preg_match('/\A'.$value.'\z/u'.$case,$params[$key]))
 | |
| 					return false;
 | |
| 			}
 | |
| 		}
 | |
| 		foreach($this->params as $key=>$value)
 | |
| 		{
 | |
| 			$tr["<$key>"]=urlencode($params[$key]);
 | |
| 			unset($params[$key]);
 | |
| 		}
 | |
| 		$suffix=$this->urlSuffix===null ? $manager->urlSuffix : $this->urlSuffix;
 | |
| 		$url=strtr($this->template,$tr);
 | |
| 		if($this->hasHostInfo)
 | |
| 		{
 | |
| 			$hostInfo=Yii::app()->getRequest()->getHostInfo();
 | |
| 			if(stripos($url,$hostInfo)===0)
 | |
| 				$url=substr($url,strlen($hostInfo));
 | |
| 		}
 | |
| 		if(empty($params))
 | |
| 			return $url!=='' ? $url.$suffix : $url;
 | |
| 		if($this->append)
 | |
| 			$url.='/'.$manager->createPathInfo($params,'/','/').$suffix;
 | |
| 		else
 | |
| 		{
 | |
| 			if($url!=='')
 | |
| 				$url.=$suffix;
 | |
| 			$url.='?'.$manager->createPathInfo($params,'=',$ampersand);
 | |
| 		}
 | |
| 		return $url;
 | |
| 	}
 | |
| 	public function parseUrl($manager,$request,$pathInfo,$rawPathInfo)
 | |
| 	{
 | |
| 		if($this->verb!==null && !in_array($request->getRequestType(), $this->verb, true))
 | |
| 			return false;
 | |
| 		if($manager->caseSensitive && $this->caseSensitive===null || $this->caseSensitive)
 | |
| 			$case='';
 | |
| 		else
 | |
| 			$case='i';
 | |
| 		if($this->urlSuffix!==null)
 | |
| 			$pathInfo=$manager->removeUrlSuffix($rawPathInfo,$this->urlSuffix);
 | |
| 		// URL suffix required, but not found in the requested URL
 | |
| 		if($manager->useStrictParsing && $pathInfo===$rawPathInfo)
 | |
| 		{
 | |
| 			$urlSuffix=$this->urlSuffix===null ? $manager->urlSuffix : $this->urlSuffix;
 | |
| 			if($urlSuffix!='' && $urlSuffix!=='/')
 | |
| 				return false;
 | |
| 		}
 | |
| 		if($this->hasHostInfo)
 | |
| 			$pathInfo=strtolower($request->getHostInfo()).rtrim('/'.$pathInfo,'/');
 | |
| 		$pathInfo.='/';
 | |
| 		if(preg_match($this->pattern.$case,$pathInfo,$matches))
 | |
| 		{
 | |
| 			foreach($this->defaultParams as $name=>$value)
 | |
| 			{
 | |
| 				if(!isset($_GET[$name]))
 | |
| 					$_REQUEST[$name]=$_GET[$name]=$value;
 | |
| 			}
 | |
| 			$tr=array();
 | |
| 			foreach($matches as $key=>$value)
 | |
| 			{
 | |
| 				if(isset($this->references[$key]))
 | |
| 					$tr[$this->references[$key]]=$value;
 | |
| 				elseif(isset($this->params[$key]))
 | |
| 					$_REQUEST[$key]=$_GET[$key]=$value;
 | |
| 			}
 | |
| 			if($pathInfo!==$matches[0]) // there're additional GET params
 | |
| 				$manager->parsePathInfo(ltrim(substr($pathInfo,strlen($matches[0])),'/'));
 | |
| 			if($this->routePattern!==null)
 | |
| 				return strtr($this->route,$tr);
 | |
| 			else
 | |
| 				return $this->route;
 | |
| 		}
 | |
| 		else
 | |
| 			return false;
 | |
| 	}
 | |
| }
 | |
| abstract class CBaseController extends CComponent
 | |
| {
 | |
| 	private $_widgetStack=array();
 | |
| 	abstract public function getViewFile($viewName);
 | |
| 	public function renderFile($viewFile,$data=null,$return=false)
 | |
| 	{
 | |
| 		$widgetCount=count($this->_widgetStack);
 | |
| 		if(($renderer=Yii::app()->getViewRenderer())!==null && $renderer->fileExtension==='.'.CFileHelper::getExtension($viewFile))
 | |
| 			$content=$renderer->renderFile($this,$viewFile,$data,$return);
 | |
| 		else
 | |
| 			$content=$this->renderInternal($viewFile,$data,$return);
 | |
| 		if(count($this->_widgetStack)===$widgetCount)
 | |
| 			return $content;
 | |
| 		else
 | |
| 		{
 | |
| 			$widget=end($this->_widgetStack);
 | |
| 			throw new CException(Yii::t('yii','{controller} contains improperly nested widget tags in its view "{view}". A {widget} widget does not have an endWidget() call.',
 | |
| 				array('{controller}'=>get_class($this), '{view}'=>$viewFile, '{widget}'=>get_class($widget))));
 | |
| 		}
 | |
| 	}
 | |
| 	public function renderInternal($_viewFile_,$_data_=null,$_return_=false)
 | |
| 	{
 | |
| 		// we use special variable names here to avoid conflict when extracting data
 | |
| 		if(is_array($_data_))
 | |
| 			extract($_data_,EXTR_PREFIX_SAME,'data');
 | |
| 		else
 | |
| 			$data=$_data_;
 | |
| 		if($_return_)
 | |
| 		{
 | |
| 			ob_start();
 | |
| 			ob_implicit_flush(false);
 | |
| 			require($_viewFile_);
 | |
| 			return ob_get_clean();
 | |
| 		}
 | |
| 		else
 | |
| 			require($_viewFile_);
 | |
| 	}
 | |
| 	public function createWidget($className,$properties=array())
 | |
| 	{
 | |
| 		$widget=Yii::app()->getWidgetFactory()->createWidget($this,$className,$properties);
 | |
| 		$widget->init();
 | |
| 		return $widget;
 | |
| 	}
 | |
| 	public function widget($className,$properties=array(),$captureOutput=false)
 | |
| 	{
 | |
| 		if($captureOutput)
 | |
| 		{
 | |
| 			ob_start();
 | |
| 			ob_implicit_flush(false);
 | |
| 			$widget=$this->createWidget($className,$properties);
 | |
| 			$widget->run();
 | |
| 			return ob_get_clean();
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$widget=$this->createWidget($className,$properties);
 | |
| 			$widget->run();
 | |
| 			return $widget;
 | |
| 		}
 | |
| 	}
 | |
| 	public function beginWidget($className,$properties=array())
 | |
| 	{
 | |
| 		$widget=$this->createWidget($className,$properties);
 | |
| 		$this->_widgetStack[]=$widget;
 | |
| 		return $widget;
 | |
| 	}
 | |
| 	public function endWidget($id='')
 | |
| 	{
 | |
| 		if(($widget=array_pop($this->_widgetStack))!==null)
 | |
| 		{
 | |
| 			$widget->run();
 | |
| 			return $widget;
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','{controller} has an extra endWidget({id}) call in its view.',
 | |
| 				array('{controller}'=>get_class($this),'{id}'=>$id)));
 | |
| 	}
 | |
| 	public function beginClip($id,$properties=array())
 | |
| 	{
 | |
| 		$properties['id']=$id;
 | |
| 		$this->beginWidget('CClipWidget',$properties);
 | |
| 	}
 | |
| 	public function endClip()
 | |
| 	{
 | |
| 		$this->endWidget('CClipWidget');
 | |
| 	}
 | |
| 	public function beginCache($id,$properties=array())
 | |
| 	{
 | |
| 		$properties['id']=$id;
 | |
| 		$cache=$this->beginWidget('COutputCache',$properties);
 | |
| 		if($cache->getIsContentCached())
 | |
| 		{
 | |
| 			$this->endCache();
 | |
| 			return false;
 | |
| 		}
 | |
| 		else
 | |
| 			return true;
 | |
| 	}
 | |
| 	public function endCache()
 | |
| 	{
 | |
| 		$this->endWidget('COutputCache');
 | |
| 	}
 | |
| 	public function beginContent($view=null,$data=array())
 | |
| 	{
 | |
| 		$this->beginWidget('CContentDecorator',array('view'=>$view, 'data'=>$data));
 | |
| 	}
 | |
| 	public function endContent()
 | |
| 	{
 | |
| 		$this->endWidget('CContentDecorator');
 | |
| 	}
 | |
| }
 | |
| class CController extends CBaseController
 | |
| {
 | |
| 	const STATE_INPUT_NAME='YII_PAGE_STATE';
 | |
| 	public $layout;
 | |
| 	public $defaultAction='index';
 | |
| 	private $_id;
 | |
| 	private $_action;
 | |
| 	private $_pageTitle;
 | |
| 	private $_cachingStack;
 | |
| 	private $_clips;
 | |
| 	private $_dynamicOutput;
 | |
| 	private $_pageStates;
 | |
| 	private $_module;
 | |
| 	public function __construct($id,$module=null)
 | |
| 	{
 | |
| 		$this->_id=$id;
 | |
| 		$this->_module=$module;
 | |
| 		$this->attachBehaviors($this->behaviors());
 | |
| 	}
 | |
| 	public function init()
 | |
| 	{
 | |
| 	}
 | |
| 	public function filters()
 | |
| 	{
 | |
| 		return array();
 | |
| 	}
 | |
| 	public function actions()
 | |
| 	{
 | |
| 		return array();
 | |
| 	}
 | |
| 	public function behaviors()
 | |
| 	{
 | |
| 		return array();
 | |
| 	}
 | |
| 	public function accessRules()
 | |
| 	{
 | |
| 		return array();
 | |
| 	}
 | |
| 	public function run($actionID)
 | |
| 	{
 | |
| 		if(($action=$this->createAction($actionID))!==null)
 | |
| 		{
 | |
| 			if(($parent=$this->getModule())===null)
 | |
| 				$parent=Yii::app();
 | |
| 			if($parent->beforeControllerAction($this,$action))
 | |
| 			{
 | |
| 				$this->runActionWithFilters($action,$this->filters());
 | |
| 				$parent->afterControllerAction($this,$action);
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 			$this->missingAction($actionID);
 | |
| 	}
 | |
| 	public function runActionWithFilters($action,$filters)
 | |
| 	{
 | |
| 		if(empty($filters))
 | |
| 			$this->runAction($action);
 | |
| 		else
 | |
| 		{
 | |
| 			$priorAction=$this->_action;
 | |
| 			$this->_action=$action;
 | |
| 			CFilterChain::create($this,$action,$filters)->run();
 | |
| 			$this->_action=$priorAction;
 | |
| 		}
 | |
| 	}
 | |
| 	public function runAction($action)
 | |
| 	{
 | |
| 		$priorAction=$this->_action;
 | |
| 		$this->_action=$action;
 | |
| 		if($this->beforeAction($action))
 | |
| 		{
 | |
| 			if($action->runWithParams($this->getActionParams())===false)
 | |
| 				$this->invalidActionParams($action);
 | |
| 			else
 | |
| 				$this->afterAction($action);
 | |
| 		}
 | |
| 		$this->_action=$priorAction;
 | |
| 	}
 | |
| 	public function getActionParams()
 | |
| 	{
 | |
| 		return $_GET;
 | |
| 	}
 | |
| 	public function invalidActionParams($action)
 | |
| 	{
 | |
| 		throw new CHttpException(400,Yii::t('yii','Your request is invalid.'));
 | |
| 	}
 | |
| 	public function processOutput($output)
 | |
| 	{
 | |
| 		Yii::app()->getClientScript()->render($output);
 | |
| 		// if using page caching, we should delay dynamic output replacement
 | |
| 		if($this->_dynamicOutput!==null && $this->isCachingStackEmpty())
 | |
| 		{
 | |
| 			$output=$this->processDynamicOutput($output);
 | |
| 			$this->_dynamicOutput=null;
 | |
| 		}
 | |
| 		if($this->_pageStates===null)
 | |
| 			$this->_pageStates=$this->loadPageStates();
 | |
| 		if(!empty($this->_pageStates))
 | |
| 			$this->savePageStates($this->_pageStates,$output);
 | |
| 		return $output;
 | |
| 	}
 | |
| 	public function processDynamicOutput($output)
 | |
| 	{
 | |
| 		if($this->_dynamicOutput)
 | |
| 		{
 | |
| 			$output=preg_replace_callback('/<###dynamic-(\d+)###>/',array($this,'replaceDynamicOutput'),$output);
 | |
| 		}
 | |
| 		return $output;
 | |
| 	}
 | |
| 	protected function replaceDynamicOutput($matches)
 | |
| 	{
 | |
| 		$content=$matches[0];
 | |
| 		if(isset($this->_dynamicOutput[$matches[1]]))
 | |
| 		{
 | |
| 			$content=$this->_dynamicOutput[$matches[1]];
 | |
| 			$this->_dynamicOutput[$matches[1]]=null;
 | |
| 		}
 | |
| 		return $content;
 | |
| 	}
 | |
| 	public function createAction($actionID)
 | |
| 	{
 | |
| 		if($actionID==='')
 | |
| 			$actionID=$this->defaultAction;
 | |
| 		if(method_exists($this,'action'.$actionID) && strcasecmp($actionID,'s')) // we have actions method
 | |
| 			return new CInlineAction($this,$actionID);
 | |
| 		else
 | |
| 		{
 | |
| 			$action=$this->createActionFromMap($this->actions(),$actionID,$actionID);
 | |
| 			if($action!==null && !method_exists($action,'run'))
 | |
| 				throw new CException(Yii::t('yii', 'Action class {class} must implement the "run" method.', array('{class}'=>get_class($action))));
 | |
| 			return $action;
 | |
| 		}
 | |
| 	}
 | |
| 	protected function createActionFromMap($actionMap,$actionID,$requestActionID,$config=array())
 | |
| 	{
 | |
| 		if(($pos=strpos($actionID,'.'))===false && isset($actionMap[$actionID]))
 | |
| 		{
 | |
| 			$baseConfig=is_array($actionMap[$actionID]) ? $actionMap[$actionID] : array('class'=>$actionMap[$actionID]);
 | |
| 			return Yii::createComponent(empty($config)?$baseConfig:array_merge($baseConfig,$config),$this,$requestActionID);
 | |
| 		}
 | |
| 		elseif($pos===false)
 | |
| 			return null;
 | |
| 		// the action is defined in a provider
 | |
| 		$prefix=substr($actionID,0,$pos+1);
 | |
| 		if(!isset($actionMap[$prefix]))
 | |
| 			return null;
 | |
| 		$actionID=(string)substr($actionID,$pos+1);
 | |
| 		$provider=$actionMap[$prefix];
 | |
| 		if(is_string($provider))
 | |
| 			$providerType=$provider;
 | |
| 		elseif(is_array($provider) && isset($provider['class']))
 | |
| 		{
 | |
| 			$providerType=$provider['class'];
 | |
| 			if(isset($provider[$actionID]))
 | |
| 			{
 | |
| 				if(is_string($provider[$actionID]))
 | |
| 					$config=array_merge(array('class'=>$provider[$actionID]),$config);
 | |
| 				else
 | |
| 					$config=array_merge($provider[$actionID],$config);
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','Object configuration must be an array containing a "class" element.'));
 | |
| 		$class=Yii::import($providerType,true);
 | |
| 		$map=call_user_func(array($class,'actions'));
 | |
| 		return $this->createActionFromMap($map,$actionID,$requestActionID,$config);
 | |
| 	}
 | |
| 	public function missingAction($actionID)
 | |
| 	{
 | |
| 		throw new CHttpException(404,Yii::t('yii','The system is unable to find the requested action "{action}".',
 | |
| 			array('{action}'=>$actionID==''?$this->defaultAction:$actionID)));
 | |
| 	}
 | |
| 	public function getAction()
 | |
| 	{
 | |
| 		return $this->_action;
 | |
| 	}
 | |
| 	public function setAction($value)
 | |
| 	{
 | |
| 		$this->_action=$value;
 | |
| 	}
 | |
| 	public function getId()
 | |
| 	{
 | |
| 		return $this->_id;
 | |
| 	}
 | |
| 	public function getUniqueId()
 | |
| 	{
 | |
| 		return $this->_module ? $this->_module->getId().'/'.$this->_id : $this->_id;
 | |
| 	}
 | |
| 	public function getRoute()
 | |
| 	{
 | |
| 		if(($action=$this->getAction())!==null)
 | |
| 			return $this->getUniqueId().'/'.$action->getId();
 | |
| 		else
 | |
| 			return $this->getUniqueId();
 | |
| 	}
 | |
| 	public function getModule()
 | |
| 	{
 | |
| 		return $this->_module;
 | |
| 	}
 | |
| 	public function getViewPath()
 | |
| 	{
 | |
| 		if(($module=$this->getModule())===null)
 | |
| 			$module=Yii::app();
 | |
| 		return $module->getViewPath().DIRECTORY_SEPARATOR.$this->getId();
 | |
| 	}
 | |
| 	public function getViewFile($viewName)
 | |
| 	{
 | |
| 		if(($theme=Yii::app()->getTheme())!==null && ($viewFile=$theme->getViewFile($this,$viewName))!==false)
 | |
| 			return $viewFile;
 | |
| 		$moduleViewPath=$basePath=Yii::app()->getViewPath();
 | |
| 		if(($module=$this->getModule())!==null)
 | |
| 			$moduleViewPath=$module->getViewPath();
 | |
| 		return $this->resolveViewFile($viewName,$this->getViewPath(),$basePath,$moduleViewPath);
 | |
| 	}
 | |
| 	public function getLayoutFile($layoutName)
 | |
| 	{
 | |
| 		if($layoutName===false)
 | |
| 			return false;
 | |
| 		if(($theme=Yii::app()->getTheme())!==null && ($layoutFile=$theme->getLayoutFile($this,$layoutName))!==false)
 | |
| 			return $layoutFile;
 | |
| 		if(empty($layoutName))
 | |
| 		{
 | |
| 			$module=$this->getModule();
 | |
| 			while($module!==null)
 | |
| 			{
 | |
| 				if($module->layout===false)
 | |
| 					return false;
 | |
| 				if(!empty($module->layout))
 | |
| 					break;
 | |
| 				$module=$module->getParentModule();
 | |
| 			}
 | |
| 			if($module===null)
 | |
| 				$module=Yii::app();
 | |
| 			$layoutName=$module->layout;
 | |
| 		}
 | |
| 		elseif(($module=$this->getModule())===null)
 | |
| 			$module=Yii::app();
 | |
| 		return $this->resolveViewFile($layoutName,$module->getLayoutPath(),Yii::app()->getViewPath(),$module->getViewPath());
 | |
| 	}
 | |
| 	public function resolveViewFile($viewName,$viewPath,$basePath,$moduleViewPath=null)
 | |
| 	{
 | |
| 		if(empty($viewName))
 | |
| 			return false;
 | |
| 		if($moduleViewPath===null)
 | |
| 			$moduleViewPath=$basePath;
 | |
| 		if(($renderer=Yii::app()->getViewRenderer())!==null)
 | |
| 			$extension=$renderer->fileExtension;
 | |
| 		else
 | |
| 			$extension='.php';
 | |
| 		if($viewName[0]==='/')
 | |
| 		{
 | |
| 			if(strncmp($viewName,'//',2)===0)
 | |
| 				$viewFile=$basePath.$viewName;
 | |
| 			else
 | |
| 				$viewFile=$moduleViewPath.$viewName;
 | |
| 		}
 | |
| 		elseif(strpos($viewName,'.'))
 | |
| 			$viewFile=Yii::getPathOfAlias($viewName);
 | |
| 		else
 | |
| 			$viewFile=$viewPath.DIRECTORY_SEPARATOR.$viewName;
 | |
| 		if(is_file($viewFile.$extension))
 | |
| 			return Yii::app()->findLocalizedFile($viewFile.$extension);
 | |
| 		elseif($extension!=='.php' && is_file($viewFile.'.php'))
 | |
| 			return Yii::app()->findLocalizedFile($viewFile.'.php');
 | |
| 		else
 | |
| 			return false;
 | |
| 	}
 | |
| 	public function getClips()
 | |
| 	{
 | |
| 		if($this->_clips!==null)
 | |
| 			return $this->_clips;
 | |
| 		else
 | |
| 			return $this->_clips=new CMap;
 | |
| 	}
 | |
| 	public function forward($route,$exit=true)
 | |
| 	{
 | |
| 		if(strpos($route,'/')===false)
 | |
| 			$this->run($route);
 | |
| 		else
 | |
| 		{
 | |
| 			if($route[0]!=='/' && ($module=$this->getModule())!==null)
 | |
| 				$route=$module->getId().'/'.$route;
 | |
| 			Yii::app()->runController($route);
 | |
| 		}
 | |
| 		if($exit)
 | |
| 			Yii::app()->end();
 | |
| 	}
 | |
| 	public function render($view,$data=null,$return=false)
 | |
| 	{
 | |
| 		if($this->beforeRender($view))
 | |
| 		{
 | |
| 			$output=$this->renderPartial($view,$data,true);
 | |
| 			if(($layoutFile=$this->getLayoutFile($this->layout))!==false)
 | |
| 				$output=$this->renderFile($layoutFile,array('content'=>$output),true);
 | |
| 			$this->afterRender($view,$output);
 | |
| 			$output=$this->processOutput($output);
 | |
| 			if($return)
 | |
| 				return $output;
 | |
| 			else
 | |
| 				echo $output;
 | |
| 		}
 | |
| 	}
 | |
| 	protected function beforeRender($view)
 | |
| 	{
 | |
| 		return true;
 | |
| 	}
 | |
| 	protected function afterRender($view, &$output)
 | |
| 	{
 | |
| 	}
 | |
| 	public function renderText($text,$return=false)
 | |
| 	{
 | |
| 		if(($layoutFile=$this->getLayoutFile($this->layout))!==false)
 | |
| 			$text=$this->renderFile($layoutFile,array('content'=>$text),true);
 | |
| 		$text=$this->processOutput($text);
 | |
| 		if($return)
 | |
| 			return $text;
 | |
| 		else
 | |
| 			echo $text;
 | |
| 	}
 | |
| 	public function renderPartial($view,$data=null,$return=false,$processOutput=false)
 | |
| 	{
 | |
| 		if(($viewFile=$this->getViewFile($view))!==false)
 | |
| 		{
 | |
| 			$output=$this->renderFile($viewFile,$data,true);
 | |
| 			if($processOutput)
 | |
| 				$output=$this->processOutput($output);
 | |
| 			if($return)
 | |
| 				return $output;
 | |
| 			else
 | |
| 				echo $output;
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','{controller} cannot find the requested view "{view}".',
 | |
| 				array('{controller}'=>get_class($this), '{view}'=>$view)));
 | |
| 	}
 | |
| 	public function renderClip($name,$params=array(),$return=false)
 | |
| 	{
 | |
| 		$text=isset($this->clips[$name]) ? strtr($this->clips[$name], $params) : '';
 | |
| 		if($return)
 | |
| 			return $text;
 | |
| 		else
 | |
| 			echo $text;
 | |
| 	}
 | |
| 	public function renderDynamic($callback)
 | |
| 	{
 | |
| 		$n=count($this->_dynamicOutput);
 | |
| 		echo "<###dynamic-$n###>";
 | |
| 		$params=func_get_args();
 | |
| 		array_shift($params);
 | |
| 		$this->renderDynamicInternal($callback,$params);
 | |
| 	}
 | |
| 	public function renderDynamicInternal($callback,$params)
 | |
| 	{
 | |
| 		$this->recordCachingAction('','renderDynamicInternal',array($callback,$params));
 | |
| 		if(is_string($callback) && method_exists($this,$callback))
 | |
| 			$callback=array($this,$callback);
 | |
| 		$this->_dynamicOutput[]=call_user_func_array($callback,$params);
 | |
| 	}
 | |
| 	public function createUrl($route,$params=array(),$ampersand='&')
 | |
| 	{
 | |
| 		if($route==='')
 | |
| 			$route=$this->getId().'/'.$this->getAction()->getId();
 | |
| 		elseif(strpos($route,'/')===false)
 | |
| 			$route=$this->getId().'/'.$route;
 | |
| 		if($route[0]!=='/' && ($module=$this->getModule())!==null)
 | |
| 			$route=$module->getId().'/'.$route;
 | |
| 		return Yii::app()->createUrl(trim($route,'/'),$params,$ampersand);
 | |
| 	}
 | |
| 	public function createAbsoluteUrl($route,$params=array(),$schema='',$ampersand='&')
 | |
| 	{
 | |
| 		$url=$this->createUrl($route,$params,$ampersand);
 | |
| 		if(strpos($url,'http')===0)
 | |
| 			return $url;
 | |
| 		else
 | |
| 			return Yii::app()->getRequest()->getHostInfo($schema).$url;
 | |
| 	}
 | |
| 	public function getPageTitle()
 | |
| 	{
 | |
| 		if($this->_pageTitle!==null)
 | |
| 			return $this->_pageTitle;
 | |
| 		else
 | |
| 		{
 | |
| 			$name=ucfirst(basename($this->getId()));
 | |
| 			if($this->getAction()!==null && strcasecmp($this->getAction()->getId(),$this->defaultAction))
 | |
| 				return $this->_pageTitle=Yii::app()->name.' - '.ucfirst($this->getAction()->getId()).' '.$name;
 | |
| 			else
 | |
| 				return $this->_pageTitle=Yii::app()->name.' - '.$name;
 | |
| 		}
 | |
| 	}
 | |
| 	public function setPageTitle($value)
 | |
| 	{
 | |
| 		$this->_pageTitle=$value;
 | |
| 	}
 | |
| 	public function redirect($url,$terminate=true,$statusCode=302)
 | |
| 	{
 | |
| 		if(is_array($url))
 | |
| 		{
 | |
| 			$route=isset($url[0]) ? $url[0] : '';
 | |
| 			$url=$this->createUrl($route,array_splice($url,1));
 | |
| 		}
 | |
| 		Yii::app()->getRequest()->redirect($url,$terminate,$statusCode);
 | |
| 	}
 | |
| 	public function refresh($terminate=true,$anchor='')
 | |
| 	{
 | |
| 		$this->redirect(Yii::app()->getRequest()->getUrl().$anchor,$terminate);
 | |
| 	}
 | |
| 	public function recordCachingAction($context,$method,$params)
 | |
| 	{
 | |
| 		if($this->_cachingStack) // record only when there is an active output cache
 | |
| 		{
 | |
| 			foreach($this->_cachingStack as $cache)
 | |
| 				$cache->recordAction($context,$method,$params);
 | |
| 		}
 | |
| 	}
 | |
| 	public function getCachingStack($createIfNull=true)
 | |
| 	{
 | |
| 		if(!$this->_cachingStack)
 | |
| 			$this->_cachingStack=new CStack;
 | |
| 		return $this->_cachingStack;
 | |
| 	}
 | |
| 	public function isCachingStackEmpty()
 | |
| 	{
 | |
| 		return $this->_cachingStack===null || !$this->_cachingStack->getCount();
 | |
| 	}
 | |
| 	protected function beforeAction($action)
 | |
| 	{
 | |
| 		return true;
 | |
| 	}
 | |
| 	protected function afterAction($action)
 | |
| 	{
 | |
| 	}
 | |
| 	public function filterPostOnly($filterChain)
 | |
| 	{
 | |
| 		if(Yii::app()->getRequest()->getIsPostRequest())
 | |
| 			$filterChain->run();
 | |
| 		else
 | |
| 			throw new CHttpException(400,Yii::t('yii','Your request is invalid.'));
 | |
| 	}
 | |
| 	public function filterAjaxOnly($filterChain)
 | |
| 	{
 | |
| 		if(Yii::app()->getRequest()->getIsAjaxRequest())
 | |
| 			$filterChain->run();
 | |
| 		else
 | |
| 			throw new CHttpException(400,Yii::t('yii','Your request is invalid.'));
 | |
| 	}
 | |
| 	public function filterAccessControl($filterChain)
 | |
| 	{
 | |
| 		$filter=new CAccessControlFilter;
 | |
| 		$filter->setRules($this->accessRules());
 | |
| 		$filter->filter($filterChain);
 | |
| 	}
 | |
| 	public function getPageState($name,$defaultValue=null)
 | |
| 	{
 | |
| 		if($this->_pageStates===null)
 | |
| 			$this->_pageStates=$this->loadPageStates();
 | |
| 		return isset($this->_pageStates[$name])?$this->_pageStates[$name]:$defaultValue;
 | |
| 	}
 | |
| 	public function setPageState($name,$value,$defaultValue=null)
 | |
| 	{
 | |
| 		if($this->_pageStates===null)
 | |
| 			$this->_pageStates=$this->loadPageStates();
 | |
| 		if($value===$defaultValue)
 | |
| 			unset($this->_pageStates[$name]);
 | |
| 		else
 | |
| 			$this->_pageStates[$name]=$value;
 | |
| 		$params=func_get_args();
 | |
| 		$this->recordCachingAction('','setPageState',$params);
 | |
| 	}
 | |
| 	public function clearPageStates()
 | |
| 	{
 | |
| 		$this->_pageStates=array();
 | |
| 	}
 | |
| 	protected function loadPageStates()
 | |
| 	{
 | |
| 		if(!empty($_POST[self::STATE_INPUT_NAME]))
 | |
| 		{
 | |
| 			if(($data=base64_decode($_POST[self::STATE_INPUT_NAME]))!==false)
 | |
| 			{
 | |
| 				if(extension_loaded('zlib'))
 | |
| 					$data=@gzuncompress($data);
 | |
| 				if(($data=Yii::app()->getSecurityManager()->validateData($data))!==false)
 | |
| 					return unserialize($data);
 | |
| 			}
 | |
| 		}
 | |
| 		return array();
 | |
| 	}
 | |
| 	protected function savePageStates($states,&$output)
 | |
| 	{
 | |
| 		$data=Yii::app()->getSecurityManager()->hashData(serialize($states));
 | |
| 		if(extension_loaded('zlib'))
 | |
| 			$data=gzcompress($data);
 | |
| 		$value=base64_encode($data);
 | |
| 		$output=str_replace(CHtml::pageStateField(''),CHtml::pageStateField($value),$output);
 | |
| 	}
 | |
| }
 | |
| abstract class CAction extends CComponent implements IAction
 | |
| {
 | |
| 	private $_id;
 | |
| 	private $_controller;
 | |
| 	public function __construct($controller,$id)
 | |
| 	{
 | |
| 		$this->_controller=$controller;
 | |
| 		$this->_id=$id;
 | |
| 	}
 | |
| 	public function getController()
 | |
| 	{
 | |
| 		return $this->_controller;
 | |
| 	}
 | |
| 	public function getId()
 | |
| 	{
 | |
| 		return $this->_id;
 | |
| 	}
 | |
| 	public function runWithParams($params)
 | |
| 	{
 | |
| 		$method=new ReflectionMethod($this, 'run');
 | |
| 		if($method->getNumberOfParameters()>0)
 | |
| 			return $this->runWithParamsInternal($this, $method, $params);
 | |
| 		else
 | |
| 			return $this->run();
 | |
| 	}
 | |
| 	protected function runWithParamsInternal($object, $method, $params)
 | |
| 	{
 | |
| 		$ps=array();
 | |
| 		foreach($method->getParameters() as $i=>$param)
 | |
| 		{
 | |
| 			$name=$param->getName();
 | |
| 			if(isset($params[$name]))
 | |
| 			{
 | |
| 				if($param->isArray())
 | |
| 					$ps[]=is_array($params[$name]) ? $params[$name] : array($params[$name]);
 | |
| 				elseif(!is_array($params[$name]))
 | |
| 					$ps[]=$params[$name];
 | |
| 				else
 | |
| 					return false;
 | |
| 			}
 | |
| 			elseif($param->isDefaultValueAvailable())
 | |
| 				$ps[]=$param->getDefaultValue();
 | |
| 			else
 | |
| 				return false;
 | |
| 		}
 | |
| 		$method->invokeArgs($object,$ps);
 | |
| 		return true;
 | |
| 	}
 | |
| }
 | |
| class CInlineAction extends CAction
 | |
| {
 | |
| 	public function run()
 | |
| 	{
 | |
| 		$method='action'.$this->getId();
 | |
| 		$this->getController()->$method();
 | |
| 	}
 | |
| 	public function runWithParams($params)
 | |
| 	{
 | |
| 		$methodName='action'.$this->getId();
 | |
| 		$controller=$this->getController();
 | |
| 		$method=new ReflectionMethod($controller, $methodName);
 | |
| 		if($method->getNumberOfParameters()>0)
 | |
| 			return $this->runWithParamsInternal($controller, $method, $params);
 | |
| 		else
 | |
| 			return $controller->$methodName();
 | |
| 	}
 | |
| }
 | |
| class CWebUser extends CApplicationComponent implements IWebUser
 | |
| {
 | |
| 	const FLASH_KEY_PREFIX='Yii.CWebUser.flash.';
 | |
| 	const FLASH_COUNTERS='Yii.CWebUser.flashcounters';
 | |
| 	const STATES_VAR='__states';
 | |
| 	const AUTH_TIMEOUT_VAR='__timeout';
 | |
| 	const AUTH_ABSOLUTE_TIMEOUT_VAR='__absolute_timeout';
 | |
| 	public $allowAutoLogin=false;
 | |
| 	public $guestName='Guest';
 | |
| 	public $loginUrl=array('/site/login');
 | |
| 	public $identityCookie;
 | |
| 	public $authTimeout;
 | |
| 	public $absoluteAuthTimeout;
 | |
| 	public $autoRenewCookie=false;
 | |
| 	public $autoUpdateFlash=true;
 | |
| 	public $loginRequiredAjaxResponse;
 | |
| 	private $_keyPrefix;
 | |
| 	private $_access=array();
 | |
| 	public function __get($name)
 | |
| 	{
 | |
| 		if($this->hasState($name))
 | |
| 			return $this->getState($name);
 | |
| 		else
 | |
| 			return parent::__get($name);
 | |
| 	}
 | |
| 	public function __set($name,$value)
 | |
| 	{
 | |
| 		if($this->hasState($name))
 | |
| 			$this->setState($name,$value);
 | |
| 		else
 | |
| 			parent::__set($name,$value);
 | |
| 	}
 | |
| 	public function __isset($name)
 | |
| 	{
 | |
| 		if($this->hasState($name))
 | |
| 			return $this->getState($name)!==null;
 | |
| 		else
 | |
| 			return parent::__isset($name);
 | |
| 	}
 | |
| 	public function __unset($name)
 | |
| 	{
 | |
| 		if($this->hasState($name))
 | |
| 			$this->setState($name,null);
 | |
| 		else
 | |
| 			parent::__unset($name);
 | |
| 	}
 | |
| 	public function init()
 | |
| 	{
 | |
| 		parent::init();
 | |
| 		Yii::app()->getSession()->open();
 | |
| 		if($this->getIsGuest() && $this->allowAutoLogin)
 | |
| 			$this->restoreFromCookie();
 | |
| 		elseif($this->autoRenewCookie && $this->allowAutoLogin)
 | |
| 			$this->renewCookie();
 | |
| 		if($this->autoUpdateFlash)
 | |
| 			$this->updateFlash();
 | |
| 		$this->updateAuthStatus();
 | |
| 	}
 | |
| 	public function login($identity,$duration=0)
 | |
| 	{
 | |
| 		$id=$identity->getId();
 | |
| 		$states=$identity->getPersistentStates();
 | |
| 		if($this->beforeLogin($id,$states,false))
 | |
| 		{
 | |
| 			$this->changeIdentity($id,$identity->getName(),$states);
 | |
| 			if($duration>0)
 | |
| 			{
 | |
| 				if($this->allowAutoLogin)
 | |
| 					$this->saveToCookie($duration);
 | |
| 				else
 | |
| 					throw new CException(Yii::t('yii','{class}.allowAutoLogin must be set true in order to use cookie-based authentication.',
 | |
| 						array('{class}'=>get_class($this))));
 | |
| 			}
 | |
| 			if ($this->absoluteAuthTimeout)
 | |
| 				$this->setState(self::AUTH_ABSOLUTE_TIMEOUT_VAR, time()+$this->absoluteAuthTimeout);
 | |
| 			$this->afterLogin(false);
 | |
| 		}
 | |
| 		return !$this->getIsGuest();
 | |
| 	}
 | |
| 	public function logout($destroySession=true)
 | |
| 	{
 | |
| 		if($this->beforeLogout())
 | |
| 		{
 | |
| 			if($this->allowAutoLogin)
 | |
| 			{
 | |
| 				Yii::app()->getRequest()->getCookies()->remove($this->getStateKeyPrefix());
 | |
| 				if($this->identityCookie!==null)
 | |
| 				{
 | |
| 					$cookie=$this->createIdentityCookie($this->getStateKeyPrefix());
 | |
| 					$cookie->value=null;
 | |
| 					$cookie->expire=0;
 | |
| 					Yii::app()->getRequest()->getCookies()->add($cookie->name,$cookie);
 | |
| 				}
 | |
| 			}
 | |
| 			if($destroySession)
 | |
| 				Yii::app()->getSession()->destroy();
 | |
| 			else
 | |
| 				$this->clearStates();
 | |
| 			$this->_access=array();
 | |
| 			$this->afterLogout();
 | |
| 		}
 | |
| 	}
 | |
| 	public function getIsGuest()
 | |
| 	{
 | |
| 		return $this->getState('__id')===null;
 | |
| 	}
 | |
| 	public function getId()
 | |
| 	{
 | |
| 		return $this->getState('__id');
 | |
| 	}
 | |
| 	public function setId($value)
 | |
| 	{
 | |
| 		$this->setState('__id',$value);
 | |
| 	}
 | |
| 	public function getName()
 | |
| 	{
 | |
| 		if(($name=$this->getState('__name'))!==null)
 | |
| 			return $name;
 | |
| 		else
 | |
| 			return $this->guestName;
 | |
| 	}
 | |
| 	public function setName($value)
 | |
| 	{
 | |
| 		$this->setState('__name',$value);
 | |
| 	}
 | |
| 	public function getReturnUrl($defaultUrl=null)
 | |
| 	{
 | |
| 		if($defaultUrl===null)
 | |
| 		{
 | |
| 			$defaultReturnUrl=Yii::app()->getUrlManager()->showScriptName ? Yii::app()->getRequest()->getScriptUrl() : Yii::app()->getRequest()->getBaseUrl().'/';
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$defaultReturnUrl=CHtml::normalizeUrl($defaultUrl);
 | |
| 		}
 | |
| 		return $this->getState('__returnUrl',$defaultReturnUrl);
 | |
| 	}
 | |
| 	public function setReturnUrl($value)
 | |
| 	{
 | |
| 		$this->setState('__returnUrl',$value);
 | |
| 	}
 | |
| 	public function loginRequired()
 | |
| 	{
 | |
| 		$app=Yii::app();
 | |
| 		$request=$app->getRequest();
 | |
| 		if(!$request->getIsAjaxRequest())
 | |
| 		{
 | |
| 			$this->setReturnUrl($request->getUrl());
 | |
| 			if(($url=$this->loginUrl)!==null)
 | |
| 			{
 | |
| 				if(is_array($url))
 | |
| 				{
 | |
| 					$route=isset($url[0]) ? $url[0] : $app->defaultController;
 | |
| 					$url=$app->createUrl($route,array_splice($url,1));
 | |
| 				}
 | |
| 				$request->redirect($url);
 | |
| 			}
 | |
| 		}
 | |
| 		elseif(isset($this->loginRequiredAjaxResponse))
 | |
| 		{
 | |
| 			echo $this->loginRequiredAjaxResponse;
 | |
| 			Yii::app()->end();
 | |
| 		}
 | |
| 		throw new CHttpException(403,Yii::t('yii','Login Required'));
 | |
| 	}
 | |
| 	protected function beforeLogin($id,$states,$fromCookie)
 | |
| 	{
 | |
| 		return true;
 | |
| 	}
 | |
| 	protected function afterLogin($fromCookie)
 | |
| 	{
 | |
| 	}
 | |
| 	protected function beforeLogout()
 | |
| 	{
 | |
| 		return true;
 | |
| 	}
 | |
| 	protected function afterLogout()
 | |
| 	{
 | |
| 	}
 | |
| 	protected function restoreFromCookie()
 | |
| 	{
 | |
| 		$app=Yii::app();
 | |
| 		$request=$app->getRequest();
 | |
| 		$cookie=$request->getCookies()->itemAt($this->getStateKeyPrefix());
 | |
| 		if($cookie && !empty($cookie->value) && is_string($cookie->value) && ($data=$app->getSecurityManager()->validateData($cookie->value))!==false)
 | |
| 		{
 | |
| 			$data=@unserialize($data);
 | |
| 			if(is_array($data) && isset($data[0],$data[1],$data[2],$data[3]))
 | |
| 			{
 | |
| 				list($id,$name,$duration,$states)=$data;
 | |
| 				if($this->beforeLogin($id,$states,true))
 | |
| 				{
 | |
| 					$this->changeIdentity($id,$name,$states);
 | |
| 					if($this->autoRenewCookie)
 | |
| 					{
 | |
| 						$this->saveToCookie($duration);
 | |
| 					}
 | |
| 					$this->afterLogin(true);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	protected function renewCookie()
 | |
| 	{
 | |
| 		$request=Yii::app()->getRequest();
 | |
| 		$cookies=$request->getCookies();
 | |
| 		$cookie=$cookies->itemAt($this->getStateKeyPrefix());
 | |
| 		if($cookie && !empty($cookie->value) && ($data=Yii::app()->getSecurityManager()->validateData($cookie->value))!==false)
 | |
| 		{
 | |
| 			$data=@unserialize($data);
 | |
| 			if(is_array($data) && isset($data[0],$data[1],$data[2],$data[3]))
 | |
| 			{
 | |
| 				$this->saveToCookie($data[2]);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	protected function saveToCookie($duration)
 | |
| 	{
 | |
| 		$app=Yii::app();
 | |
| 		$cookie=$this->createIdentityCookie($this->getStateKeyPrefix());
 | |
| 		$cookie->expire=time()+$duration;
 | |
| 		$data=array(
 | |
| 			$this->getId(),
 | |
| 			$this->getName(),
 | |
| 			$duration,
 | |
| 			$this->saveIdentityStates(),
 | |
| 		);
 | |
| 		$cookie->value=$app->getSecurityManager()->hashData(serialize($data));
 | |
| 		$app->getRequest()->getCookies()->add($cookie->name,$cookie);
 | |
| 	}
 | |
| 	protected function createIdentityCookie($name)
 | |
| 	{
 | |
| 		$cookie=new CHttpCookie($name,'');
 | |
| 		if(is_array($this->identityCookie))
 | |
| 		{
 | |
| 			foreach($this->identityCookie as $name=>$value)
 | |
| 				$cookie->$name=$value;
 | |
| 		}
 | |
| 		return $cookie;
 | |
| 	}
 | |
| 	public function getStateKeyPrefix()
 | |
| 	{
 | |
| 		if($this->_keyPrefix!==null)
 | |
| 			return $this->_keyPrefix;
 | |
| 		else
 | |
| 			return $this->_keyPrefix=md5('Yii.'.get_class($this).'.'.Yii::app()->getId());
 | |
| 	}
 | |
| 	public function setStateKeyPrefix($value)
 | |
| 	{
 | |
| 		$this->_keyPrefix=$value;
 | |
| 	}
 | |
| 	public function getState($key,$defaultValue=null)
 | |
| 	{
 | |
| 		$key=$this->getStateKeyPrefix().$key;
 | |
| 		return isset($_SESSION[$key]) ? $_SESSION[$key] : $defaultValue;
 | |
| 	}
 | |
| 	public function setState($key,$value,$defaultValue=null)
 | |
| 	{
 | |
| 		$key=$this->getStateKeyPrefix().$key;
 | |
| 		if($value===$defaultValue)
 | |
| 			unset($_SESSION[$key]);
 | |
| 		else
 | |
| 			$_SESSION[$key]=$value;
 | |
| 	}
 | |
| 	public function hasState($key)
 | |
| 	{
 | |
| 		$key=$this->getStateKeyPrefix().$key;
 | |
| 		return isset($_SESSION[$key]);
 | |
| 	}
 | |
| 	public function clearStates()
 | |
| 	{
 | |
| 		$keys=array_keys($_SESSION);
 | |
| 		$prefix=$this->getStateKeyPrefix();
 | |
| 		$n=strlen($prefix);
 | |
| 		foreach($keys as $key)
 | |
| 		{
 | |
| 			if(!strncmp($key,$prefix,$n))
 | |
| 				unset($_SESSION[$key]);
 | |
| 		}
 | |
| 	}
 | |
| 	public function getFlashes($delete=true)
 | |
| 	{
 | |
| 		$flashes=array();
 | |
| 		$prefix=$this->getStateKeyPrefix().self::FLASH_KEY_PREFIX;
 | |
| 		$keys=array_keys($_SESSION);
 | |
| 		$n=strlen($prefix);
 | |
| 		foreach($keys as $key)
 | |
| 		{
 | |
| 			if(!strncmp($key,$prefix,$n))
 | |
| 			{
 | |
| 				$flashes[substr($key,$n)]=$_SESSION[$key];
 | |
| 				if($delete)
 | |
| 					unset($_SESSION[$key]);
 | |
| 			}
 | |
| 		}
 | |
| 		if($delete)
 | |
| 			$this->setState(self::FLASH_COUNTERS,array());
 | |
| 		return $flashes;
 | |
| 	}
 | |
| 	public function getFlash($key,$defaultValue=null,$delete=true)
 | |
| 	{
 | |
| 		$value=$this->getState(self::FLASH_KEY_PREFIX.$key,$defaultValue);
 | |
| 		if($delete)
 | |
| 			$this->setFlash($key,null);
 | |
| 		return $value;
 | |
| 	}
 | |
| 	public function setFlash($key,$value,$defaultValue=null)
 | |
| 	{
 | |
| 		$this->setState(self::FLASH_KEY_PREFIX.$key,$value,$defaultValue);
 | |
| 		$counters=$this->getState(self::FLASH_COUNTERS,array());
 | |
| 		if($value===$defaultValue)
 | |
| 			unset($counters[$key]);
 | |
| 		else
 | |
| 			$counters[$key]=0;
 | |
| 		$this->setState(self::FLASH_COUNTERS,$counters,array());
 | |
| 	}
 | |
| 	public function hasFlash($key)
 | |
| 	{
 | |
| 		return $this->getFlash($key, null, false)!==null;
 | |
| 	}
 | |
| 	protected function changeIdentity($id,$name,$states)
 | |
| 	{
 | |
| 		Yii::app()->getSession()->regenerateID(true);
 | |
| 		$this->setId($id);
 | |
| 		$this->setName($name);
 | |
| 		$this->loadIdentityStates($states);
 | |
| 	}
 | |
| 	protected function saveIdentityStates()
 | |
| 	{
 | |
| 		$states=array();
 | |
| 		foreach($this->getState(self::STATES_VAR,array()) as $name=>$dummy)
 | |
| 			$states[$name]=$this->getState($name);
 | |
| 		return $states;
 | |
| 	}
 | |
| 	protected function loadIdentityStates($states)
 | |
| 	{
 | |
| 		$names=array();
 | |
| 		if(is_array($states))
 | |
| 		{
 | |
| 			foreach($states as $name=>$value)
 | |
| 			{
 | |
| 				$this->setState($name,$value);
 | |
| 				$names[$name]=true;
 | |
| 			}
 | |
| 		}
 | |
| 		$this->setState(self::STATES_VAR,$names);
 | |
| 	}
 | |
| 	protected function updateFlash()
 | |
| 	{
 | |
| 		$counters=$this->getState(self::FLASH_COUNTERS);
 | |
| 		if(!is_array($counters))
 | |
| 			return;
 | |
| 		foreach($counters as $key=>$count)
 | |
| 		{
 | |
| 			if($count)
 | |
| 			{
 | |
| 				unset($counters[$key]);
 | |
| 				$this->setState(self::FLASH_KEY_PREFIX.$key,null);
 | |
| 			}
 | |
| 			else
 | |
| 				$counters[$key]++;
 | |
| 		}
 | |
| 		$this->setState(self::FLASH_COUNTERS,$counters,array());
 | |
| 	}
 | |
| 	protected function updateAuthStatus()
 | |
| 	{
 | |
| 		if(($this->authTimeout!==null || $this->absoluteAuthTimeout!==null) && !$this->getIsGuest())
 | |
| 		{
 | |
| 			$expires=$this->getState(self::AUTH_TIMEOUT_VAR);
 | |
| 			$expiresAbsolute=$this->getState(self::AUTH_ABSOLUTE_TIMEOUT_VAR);
 | |
| 			if ($expires!==null && $expires < time() || $expiresAbsolute!==null && $expiresAbsolute < time())
 | |
| 				$this->logout(false);
 | |
| 			else
 | |
| 				$this->setState(self::AUTH_TIMEOUT_VAR,time()+$this->authTimeout);
 | |
| 		}
 | |
| 	}
 | |
| 	public function checkAccess($operation,$params=array(),$allowCaching=true)
 | |
| 	{
 | |
| 		if($allowCaching && $params===array() && isset($this->_access[$operation]))
 | |
| 			return $this->_access[$operation];
 | |
| 		$access=Yii::app()->getAuthManager()->checkAccess($operation,$this->getId(),$params);
 | |
| 		if($allowCaching && $params===array())
 | |
| 			$this->_access[$operation]=$access;
 | |
| 		return $access;
 | |
| 	}
 | |
| }
 | |
| class CHttpSession extends CApplicationComponent implements IteratorAggregate,ArrayAccess,Countable
 | |
| {
 | |
| 	public $autoStart=true;
 | |
| 	public function init()
 | |
| 	{
 | |
| 		parent::init();
 | |
| 		if($this->autoStart)
 | |
| 			$this->open();
 | |
| 		register_shutdown_function(array($this,'close'));
 | |
| 	}
 | |
| 	public function getUseCustomStorage()
 | |
| 	{
 | |
| 		return false;
 | |
| 	}
 | |
| 	public function open()
 | |
| 	{
 | |
| 		if($this->getUseCustomStorage())
 | |
| 			@session_set_save_handler(array($this,'openSession'),array($this,'closeSession'),array($this,'readSession'),array($this,'writeSession'),array($this,'destroySession'),array($this,'gcSession'));
 | |
| 		@session_start();
 | |
| 		if(YII_DEBUG && session_id()=='')
 | |
| 		{
 | |
| 			$message=Yii::t('yii','Failed to start session.');
 | |
| 			if(function_exists('error_get_last'))
 | |
| 			{
 | |
| 				$error=error_get_last();
 | |
| 				if(isset($error['message']))
 | |
| 					$message=$error['message'];
 | |
| 			}
 | |
| 			Yii::log($message, CLogger::LEVEL_WARNING, 'system.web.CHttpSession');
 | |
| 		}
 | |
| 	}
 | |
| 	public function close()
 | |
| 	{
 | |
| 		if(session_id()!=='')
 | |
| 			@session_write_close();
 | |
| 	}
 | |
| 	public function destroy()
 | |
| 	{
 | |
| 		if(session_id()!=='')
 | |
| 		{
 | |
| 			@session_unset();
 | |
| 			@session_destroy();
 | |
| 		}
 | |
| 	}
 | |
| 	public function getIsStarted()
 | |
| 	{
 | |
| 		return session_id()!=='';
 | |
| 	}
 | |
| 	public function getSessionID()
 | |
| 	{
 | |
| 		return session_id();
 | |
| 	}
 | |
| 	public function setSessionID($value)
 | |
| 	{
 | |
| 		session_id($value);
 | |
| 	}
 | |
| 	public function regenerateID($deleteOldSession=false)
 | |
| 	{
 | |
| 		session_regenerate_id($deleteOldSession);
 | |
| 	}
 | |
| 	public function getSessionName()
 | |
| 	{
 | |
| 		return session_name();
 | |
| 	}
 | |
| 	public function setSessionName($value)
 | |
| 	{
 | |
| 		session_name($value);
 | |
| 	}
 | |
| 	public function getSavePath()
 | |
| 	{
 | |
| 		return session_save_path();
 | |
| 	}
 | |
| 	public function setSavePath($value)
 | |
| 	{
 | |
| 		if(is_dir($value))
 | |
| 			session_save_path($value);
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','CHttpSession.savePath "{path}" is not a valid directory.',
 | |
| 				array('{path}'=>$value)));
 | |
| 	}
 | |
| 	public function getCookieParams()
 | |
| 	{
 | |
| 		return session_get_cookie_params();
 | |
| 	}
 | |
| 	public function setCookieParams($value)
 | |
| 	{
 | |
| 		$data=session_get_cookie_params();
 | |
| 		extract($data);
 | |
| 		extract($value);
 | |
| 		if(isset($httponly))
 | |
| 			session_set_cookie_params($lifetime,$path,$domain,$secure,$httponly);
 | |
| 		else
 | |
| 			session_set_cookie_params($lifetime,$path,$domain,$secure);
 | |
| 	}
 | |
| 	public function getCookieMode()
 | |
| 	{
 | |
| 		if(ini_get('session.use_cookies')==='0')
 | |
| 			return 'none';
 | |
| 		elseif(ini_get('session.use_only_cookies')==='0')
 | |
| 			return 'allow';
 | |
| 		else
 | |
| 			return 'only';
 | |
| 	}
 | |
| 	public function setCookieMode($value)
 | |
| 	{
 | |
| 		if($value==='none')
 | |
| 		{
 | |
| 			ini_set('session.use_cookies','0');
 | |
| 			ini_set('session.use_only_cookies','0');
 | |
| 		}
 | |
| 		elseif($value==='allow')
 | |
| 		{
 | |
| 			ini_set('session.use_cookies','1');
 | |
| 			ini_set('session.use_only_cookies','0');
 | |
| 		}
 | |
| 		elseif($value==='only')
 | |
| 		{
 | |
| 			ini_set('session.use_cookies','1');
 | |
| 			ini_set('session.use_only_cookies','1');
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','CHttpSession.cookieMode can only be "none", "allow" or "only".'));
 | |
| 	}
 | |
| 	public function getGCProbability()
 | |
| 	{
 | |
| 		return (float)(ini_get('session.gc_probability')/ini_get('session.gc_divisor')*100);
 | |
| 	}
 | |
| 	public function setGCProbability($value)
 | |
| 	{
 | |
| 		if($value>=0 && $value<=100)
 | |
| 		{
 | |
| 			// percent * 21474837 / 2147483647 ≈ percent * 0.01
 | |
| 			ini_set('session.gc_probability',floor($value*21474836.47));
 | |
| 			ini_set('session.gc_divisor',2147483647);
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','CHttpSession.gcProbability "{value}" is invalid. It must be a float between 0 and 100.',
 | |
| 				array('{value}'=>$value)));
 | |
| 	}
 | |
| 	public function getUseTransparentSessionID()
 | |
| 	{
 | |
| 		return ini_get('session.use_trans_sid')==1;
 | |
| 	}
 | |
| 	public function setUseTransparentSessionID($value)
 | |
| 	{
 | |
| 		ini_set('session.use_trans_sid',$value?'1':'0');
 | |
| 	}
 | |
| 	public function getTimeout()
 | |
| 	{
 | |
| 		return (int)ini_get('session.gc_maxlifetime');
 | |
| 	}
 | |
| 	public function setTimeout($value)
 | |
| 	{
 | |
| 		ini_set('session.gc_maxlifetime',$value);
 | |
| 	}
 | |
| 	public function openSession($savePath,$sessionName)
 | |
| 	{
 | |
| 		return true;
 | |
| 	}
 | |
| 	public function closeSession()
 | |
| 	{
 | |
| 		return true;
 | |
| 	}
 | |
| 	public function readSession($id)
 | |
| 	{
 | |
| 		return '';
 | |
| 	}
 | |
| 	public function writeSession($id,$data)
 | |
| 	{
 | |
| 		return true;
 | |
| 	}
 | |
| 	public function destroySession($id)
 | |
| 	{
 | |
| 		return true;
 | |
| 	}
 | |
| 	public function gcSession($maxLifetime)
 | |
| 	{
 | |
| 		return true;
 | |
| 	}
 | |
| 	//------ The following methods enable CHttpSession to be CMap-like -----
 | |
| 	public function getIterator()
 | |
| 	{
 | |
| 		return new CHttpSessionIterator;
 | |
| 	}
 | |
| 	public function getCount()
 | |
| 	{
 | |
| 		return count($_SESSION);
 | |
| 	}
 | |
| 	public function count()
 | |
| 	{
 | |
| 		return $this->getCount();
 | |
| 	}
 | |
| 	public function getKeys()
 | |
| 	{
 | |
| 		return array_keys($_SESSION);
 | |
| 	}
 | |
| 	public function get($key,$defaultValue=null)
 | |
| 	{
 | |
| 		return isset($_SESSION[$key]) ? $_SESSION[$key] : $defaultValue;
 | |
| 	}
 | |
| 	public function itemAt($key)
 | |
| 	{
 | |
| 		return isset($_SESSION[$key]) ? $_SESSION[$key] : null;
 | |
| 	}
 | |
| 	public function add($key,$value)
 | |
| 	{
 | |
| 		$_SESSION[$key]=$value;
 | |
| 	}
 | |
| 	public function remove($key)
 | |
| 	{
 | |
| 		if(isset($_SESSION[$key]))
 | |
| 		{
 | |
| 			$value=$_SESSION[$key];
 | |
| 			unset($_SESSION[$key]);
 | |
| 			return $value;
 | |
| 		}
 | |
| 		else
 | |
| 			return null;
 | |
| 	}
 | |
| 	public function clear()
 | |
| 	{
 | |
| 		foreach(array_keys($_SESSION) as $key)
 | |
| 			unset($_SESSION[$key]);
 | |
| 	}
 | |
| 	public function contains($key)
 | |
| 	{
 | |
| 		return isset($_SESSION[$key]);
 | |
| 	}
 | |
| 	public function toArray()
 | |
| 	{
 | |
| 		return $_SESSION;
 | |
| 	}
 | |
| 	public function offsetExists($offset)
 | |
| 	{
 | |
| 		return isset($_SESSION[$offset]);
 | |
| 	}
 | |
| 	public function offsetGet($offset)
 | |
| 	{
 | |
| 		return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
 | |
| 	}
 | |
| 	public function offsetSet($offset,$item)
 | |
| 	{
 | |
| 		$_SESSION[$offset]=$item;
 | |
| 	}
 | |
| 	public function offsetUnset($offset)
 | |
| 	{
 | |
| 		unset($_SESSION[$offset]);
 | |
| 	}
 | |
| }
 | |
| class CHtml
 | |
| {
 | |
| 	const ID_PREFIX='yt';
 | |
| 	public static $errorSummaryCss='errorSummary';
 | |
| 	public static $errorMessageCss='errorMessage';
 | |
| 	public static $errorCss='error';
 | |
| 	public static $errorContainerTag='div';
 | |
| 	public static $requiredCss='required';
 | |
| 	public static $beforeRequiredLabel='';
 | |
| 	public static $afterRequiredLabel=' <span class="required">*</span>';
 | |
| 	public static $count=0;
 | |
| 	public static $liveEvents=true;
 | |
| 	public static $closeSingleTags=true;
 | |
| 	public static $renderSpecialAttributesValue=true;
 | |
| 	private static $_modelNameConverter;
 | |
| 	public static function encode($text)
 | |
| 	{
 | |
| 		return htmlspecialchars($text,ENT_QUOTES,Yii::app()->charset);
 | |
| 	}
 | |
| 	public static function decode($text)
 | |
| 	{
 | |
| 		return htmlspecialchars_decode($text,ENT_QUOTES);
 | |
| 	}
 | |
| 	public static function encodeArray($data)
 | |
| 	{
 | |
| 		$d=array();
 | |
| 		foreach($data as $key=>$value)
 | |
| 		{
 | |
| 			if(is_string($key))
 | |
| 				$key=htmlspecialchars($key,ENT_QUOTES,Yii::app()->charset);
 | |
| 			if(is_string($value))
 | |
| 				$value=htmlspecialchars($value,ENT_QUOTES,Yii::app()->charset);
 | |
| 			elseif(is_array($value))
 | |
| 				$value=self::encodeArray($value);
 | |
| 			$d[$key]=$value;
 | |
| 		}
 | |
| 		return $d;
 | |
| 	}
 | |
| 	public static function tag($tag,$htmlOptions=array(),$content=false,$closeTag=true)
 | |
| 	{
 | |
| 		$html='<' . $tag . self::renderAttributes($htmlOptions);
 | |
| 		if($content===false)
 | |
| 			return $closeTag && self::$closeSingleTags ? $html.' />' : $html.'>';
 | |
| 		else
 | |
| 			return $closeTag ? $html.'>'.$content.'</'.$tag.'>' : $html.'>'.$content;
 | |
| 	}
 | |
| 	public static function openTag($tag,$htmlOptions=array())
 | |
| 	{
 | |
| 		return '<' . $tag . self::renderAttributes($htmlOptions) . '>';
 | |
| 	}
 | |
| 	public static function closeTag($tag)
 | |
| 	{
 | |
| 		return '</'.$tag.'>';
 | |
| 	}
 | |
| 	public static function cdata($text)
 | |
| 	{
 | |
| 		return '<![CDATA[' . $text . ']]>';
 | |
| 	}
 | |
| 	public static function metaTag($content,$name=null,$httpEquiv=null,$options=array())
 | |
| 	{
 | |
| 		if($name!==null)
 | |
| 			$options['name']=$name;
 | |
| 		if($httpEquiv!==null)
 | |
| 			$options['http-equiv']=$httpEquiv;
 | |
| 		$options['content']=$content;
 | |
| 		return self::tag('meta',$options);
 | |
| 	}
 | |
| 	public static function linkTag($relation=null,$type=null,$href=null,$media=null,$options=array())
 | |
| 	{
 | |
| 		if($relation!==null)
 | |
| 			$options['rel']=$relation;
 | |
| 		if($type!==null)
 | |
| 			$options['type']=$type;
 | |
| 		if($href!==null)
 | |
| 			$options['href']=$href;
 | |
| 		if($media!==null)
 | |
| 			$options['media']=$media;
 | |
| 		return self::tag('link',$options);
 | |
| 	}
 | |
| 	public static function css($text,$media='')
 | |
| 	{
 | |
| 		if($media!=='')
 | |
| 			$media=' media="'.$media.'"';
 | |
| 		return "<style type=\"text/css\"{$media}>\n/*<![CDATA[*/\n{$text}\n/*]]>*/\n</style>";
 | |
| 	}
 | |
| 	public static function refresh($seconds,$url='')
 | |
| 	{
 | |
| 		$content="$seconds";
 | |
| 		if($url!=='')
 | |
| 			$content.=';url='.self::normalizeUrl($url);
 | |
| 		Yii::app()->clientScript->registerMetaTag($content,null,'refresh');
 | |
| 	}
 | |
| 	public static function cssFile($url,$media='')
 | |
| 	{
 | |
| 		return CHtml::linkTag('stylesheet','text/css',$url,$media!=='' ? $media : null);
 | |
| 	}
 | |
| 	public static function script($text,array $htmlOptions=array())
 | |
| 	{
 | |
| 		$defaultHtmlOptions=array(
 | |
| 			'type'=>'text/javascript',
 | |
| 		);
 | |
| 		$htmlOptions=array_merge($defaultHtmlOptions,$htmlOptions);
 | |
| 		return self::tag('script',$htmlOptions,"\n/*<![CDATA[*/\n{$text}\n/*]]>*/\n");
 | |
| 	}
 | |
| 	public static function scriptFile($url,array $htmlOptions=array())
 | |
| 	{
 | |
| 		$defaultHtmlOptions=array(
 | |
| 			'type'=>'text/javascript',
 | |
| 			'src'=>$url
 | |
| 		);
 | |
| 		$htmlOptions=array_merge($defaultHtmlOptions,$htmlOptions);
 | |
| 		return self::tag('script',$htmlOptions,'');
 | |
| 	}
 | |
| 	public static function form($action='',$method='post',$htmlOptions=array())
 | |
| 	{
 | |
| 		return self::beginForm($action,$method,$htmlOptions);
 | |
| 	}
 | |
| 	public static function beginForm($action='',$method='post',$htmlOptions=array())
 | |
| 	{
 | |
| 		$htmlOptions['action']=$url=self::normalizeUrl($action);
 | |
| 		$htmlOptions['method']=$method;
 | |
| 		$form=self::tag('form',$htmlOptions,false,false);
 | |
| 		$hiddens=array();
 | |
| 		if(!strcasecmp($method,'get') && ($pos=strpos($url,'?'))!==false)
 | |
| 		{
 | |
| 			foreach(explode('&',substr($url,$pos+1)) as $pair)
 | |
| 			{
 | |
| 				if(($pos=strpos($pair,'='))!==false)
 | |
| 					$hiddens[]=self::hiddenField(urldecode(substr($pair,0,$pos)),urldecode(substr($pair,$pos+1)),array('id'=>false));
 | |
| 				else
 | |
| 					$hiddens[]=self::hiddenField(urldecode($pair),'',array('id'=>false));
 | |
| 			}
 | |
| 		}
 | |
| 		$request=Yii::app()->request;
 | |
| 		if($request->enableCsrfValidation && !strcasecmp($method,'post'))
 | |
| 			$hiddens[]=self::hiddenField($request->csrfTokenName,$request->getCsrfToken(),array('id'=>false));
 | |
| 		if($hiddens!==array())
 | |
| 			$form.="\n".self::tag('div',array('style'=>'display:none'),implode("\n",$hiddens));
 | |
| 		return $form;
 | |
| 	}
 | |
| 	public static function endForm()
 | |
| 	{
 | |
| 		return '</form>';
 | |
| 	}
 | |
| 	public static function statefulForm($action='',$method='post',$htmlOptions=array())
 | |
| 	{
 | |
| 		return self::form($action,$method,$htmlOptions)."\n".
 | |
| 			self::tag('div',array('style'=>'display:none'),self::pageStateField(''));
 | |
| 	}
 | |
| 	public static function pageStateField($value)
 | |
| 	{
 | |
| 		return '<input type="hidden" name="'.CController::STATE_INPUT_NAME.'" value="'.$value.'" />';
 | |
| 	}
 | |
| 	public static function link($text,$url='#',$htmlOptions=array())
 | |
| 	{
 | |
| 		if($url!=='')
 | |
| 			$htmlOptions['href']=self::normalizeUrl($url);
 | |
| 		self::clientChange('click',$htmlOptions);
 | |
| 		return self::tag('a',$htmlOptions,$text);
 | |
| 	}
 | |
| 	public static function mailto($text,$email='',$htmlOptions=array())
 | |
| 	{
 | |
| 		if($email==='')
 | |
| 			$email=$text;
 | |
| 		return self::link($text,'mailto:'.$email,$htmlOptions);
 | |
| 	}
 | |
| 	public static function image($src,$alt='',$htmlOptions=array())
 | |
| 	{
 | |
| 		$htmlOptions['src']=$src;
 | |
| 		$htmlOptions['alt']=$alt;
 | |
| 		return self::tag('img',$htmlOptions);
 | |
| 	}
 | |
| 	public static function button($label='button',$htmlOptions=array())
 | |
| 	{
 | |
| 		if(!isset($htmlOptions['name']))
 | |
| 		{
 | |
| 			if(!array_key_exists('name',$htmlOptions))
 | |
| 				$htmlOptions['name']=self::ID_PREFIX.self::$count++;
 | |
| 		}
 | |
| 		if(!isset($htmlOptions['type']))
 | |
| 			$htmlOptions['type']='button';
 | |
| 		if(!isset($htmlOptions['value']) && $htmlOptions['type']!='image')
 | |
| 			$htmlOptions['value']=$label;
 | |
| 		self::clientChange('click',$htmlOptions);
 | |
| 		return self::tag('input',$htmlOptions);
 | |
| 	}
 | |
| 	public static function htmlButton($label='button',$htmlOptions=array())
 | |
| 	{
 | |
| 		if(!isset($htmlOptions['name']))
 | |
| 			$htmlOptions['name']=self::ID_PREFIX.self::$count++;
 | |
| 		if(!isset($htmlOptions['type']))
 | |
| 			$htmlOptions['type']='button';
 | |
| 		self::clientChange('click',$htmlOptions);
 | |
| 		return self::tag('button',$htmlOptions,$label);
 | |
| 	}
 | |
| 	public static function submitButton($label='submit',$htmlOptions=array())
 | |
| 	{
 | |
| 		$htmlOptions['type']='submit';
 | |
| 		return self::button($label,$htmlOptions);
 | |
| 	}
 | |
| 	public static function resetButton($label='reset',$htmlOptions=array())
 | |
| 	{
 | |
| 		$htmlOptions['type']='reset';
 | |
| 		return self::button($label,$htmlOptions);
 | |
| 	}
 | |
| 	public static function imageButton($src,$htmlOptions=array())
 | |
| 	{
 | |
| 		$htmlOptions['src']=$src;
 | |
| 		$htmlOptions['type']='image';
 | |
| 		return self::button('submit',$htmlOptions);
 | |
| 	}
 | |
| 	public static function linkButton($label='submit',$htmlOptions=array())
 | |
| 	{
 | |
| 		if(!isset($htmlOptions['submit']))
 | |
| 			$htmlOptions['submit']=isset($htmlOptions['href']) ? $htmlOptions['href'] : '';
 | |
| 		return self::link($label,'#',$htmlOptions);
 | |
| 	}
 | |
| 	public static function label($label,$for,$htmlOptions=array())
 | |
| 	{
 | |
| 		if($for===false)
 | |
| 			unset($htmlOptions['for']);
 | |
| 		else
 | |
| 			$htmlOptions['for']=$for;
 | |
| 		if(isset($htmlOptions['required']))
 | |
| 		{
 | |
| 			if($htmlOptions['required'])
 | |
| 			{
 | |
| 				if(isset($htmlOptions['class']))
 | |
| 					$htmlOptions['class'].=' '.self::$requiredCss;
 | |
| 				else
 | |
| 					$htmlOptions['class']=self::$requiredCss;
 | |
| 				$label=self::$beforeRequiredLabel.$label.self::$afterRequiredLabel;
 | |
| 			}
 | |
| 			unset($htmlOptions['required']);
 | |
| 		}
 | |
| 		return self::tag('label',$htmlOptions,$label);
 | |
| 	}
 | |
| 	public static function textField($name,$value='',$htmlOptions=array())
 | |
| 	{
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::inputField('text',$name,$value,$htmlOptions);
 | |
| 	}
 | |
| 	public static function numberField($name,$value='',$htmlOptions=array())
 | |
| 	{
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::inputField('number',$name,$value,$htmlOptions);
 | |
| 	}
 | |
| 	public static function rangeField($name,$value='',$htmlOptions=array())
 | |
| 	{
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::inputField('range',$name,$value,$htmlOptions);
 | |
| 	}
 | |
| 	public static function dateField($name,$value='',$htmlOptions=array())
 | |
| 	{
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::inputField('date',$name,$value,$htmlOptions);
 | |
| 	}
 | |
| 	public static function timeField($name,$value='',$htmlOptions=array())
 | |
| 	{
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::inputField('time',$name,$value,$htmlOptions);
 | |
| 	}
 | |
| 	public static function emailField($name,$value='',$htmlOptions=array())
 | |
| 	{
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::inputField('email',$name,$value,$htmlOptions);
 | |
| 	}
 | |
| 	public static function telField($name,$value='',$htmlOptions=array())
 | |
| 	{
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::inputField('tel',$name,$value,$htmlOptions);
 | |
| 	}
 | |
| 	public static function urlField($name,$value='',$htmlOptions=array())
 | |
| 	{
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::inputField('url',$name,$value,$htmlOptions);
 | |
| 	}
 | |
| 	public static function hiddenField($name,$value='',$htmlOptions=array())
 | |
| 	{
 | |
| 		return self::inputField('hidden',$name,$value,$htmlOptions);
 | |
| 	}
 | |
| 	public static function passwordField($name,$value='',$htmlOptions=array())
 | |
| 	{
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::inputField('password',$name,$value,$htmlOptions);
 | |
| 	}
 | |
| 	public static function fileField($name,$value='',$htmlOptions=array())
 | |
| 	{
 | |
| 		return self::inputField('file',$name,$value,$htmlOptions);
 | |
| 	}
 | |
| 	public static function textArea($name,$value='',$htmlOptions=array())
 | |
| 	{
 | |
| 		$htmlOptions['name']=$name;
 | |
| 		if(!isset($htmlOptions['id']))
 | |
| 			$htmlOptions['id']=self::getIdByName($name);
 | |
| 		elseif($htmlOptions['id']===false)
 | |
| 			unset($htmlOptions['id']);
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::tag('textarea',$htmlOptions,isset($htmlOptions['encode']) && !$htmlOptions['encode'] ? $value : self::encode($value));
 | |
| 	}
 | |
| 	public static function radioButton($name,$checked=false,$htmlOptions=array())
 | |
| 	{
 | |
| 		if($checked)
 | |
| 			$htmlOptions['checked']='checked';
 | |
| 		else
 | |
| 			unset($htmlOptions['checked']);
 | |
| 		$value=isset($htmlOptions['value']) ? $htmlOptions['value'] : 1;
 | |
| 		self::clientChange('click',$htmlOptions);
 | |
| 		if(array_key_exists('uncheckValue',$htmlOptions))
 | |
| 		{
 | |
| 			$uncheck=$htmlOptions['uncheckValue'];
 | |
| 			unset($htmlOptions['uncheckValue']);
 | |
| 		}
 | |
| 		else
 | |
| 			$uncheck=null;
 | |
| 		if($uncheck!==null)
 | |
| 		{
 | |
| 			// add a hidden field so that if the radio button is not selected, it still submits a value
 | |
| 			if(isset($htmlOptions['id']) && $htmlOptions['id']!==false)
 | |
| 				$uncheckOptions=array('id'=>self::ID_PREFIX.$htmlOptions['id']);
 | |
| 			else
 | |
| 				$uncheckOptions=array('id'=>false);
 | |
| 			$hidden=self::hiddenField($name,$uncheck,$uncheckOptions);
 | |
| 		}
 | |
| 		else
 | |
| 			$hidden='';
 | |
| 		// add a hidden field so that if the radio button is not selected, it still submits a value
 | |
| 		return $hidden . self::inputField('radio',$name,$value,$htmlOptions);
 | |
| 	}
 | |
| 	public static function checkBox($name,$checked=false,$htmlOptions=array())
 | |
| 	{
 | |
| 		if($checked)
 | |
| 			$htmlOptions['checked']='checked';
 | |
| 		else
 | |
| 			unset($htmlOptions['checked']);
 | |
| 		$value=isset($htmlOptions['value']) ? $htmlOptions['value'] : 1;
 | |
| 		self::clientChange('click',$htmlOptions);
 | |
| 		if(array_key_exists('uncheckValue',$htmlOptions))
 | |
| 		{
 | |
| 			$uncheck=$htmlOptions['uncheckValue'];
 | |
| 			unset($htmlOptions['uncheckValue']);
 | |
| 		}
 | |
| 		else
 | |
| 			$uncheck=null;
 | |
| 		if($uncheck!==null)
 | |
| 		{
 | |
| 			// add a hidden field so that if the check box is not checked, it still submits a value
 | |
| 			if(isset($htmlOptions['id']) && $htmlOptions['id']!==false)
 | |
| 				$uncheckOptions=array('id'=>self::ID_PREFIX.$htmlOptions['id']);
 | |
| 			else
 | |
| 				$uncheckOptions=array('id'=>false);
 | |
| 			$hidden=self::hiddenField($name,$uncheck,$uncheckOptions);
 | |
| 		}
 | |
| 		else
 | |
| 			$hidden='';
 | |
| 		// add a hidden field so that if the check box is not checked, it still submits a value
 | |
| 		return $hidden . self::inputField('checkbox',$name,$value,$htmlOptions);
 | |
| 	}
 | |
| 	public static function dropDownList($name,$select,$data,$htmlOptions=array())
 | |
| 	{
 | |
| 		$htmlOptions['name']=$name;
 | |
| 		if(!isset($htmlOptions['id']))
 | |
| 			$htmlOptions['id']=self::getIdByName($name);
 | |
| 		elseif($htmlOptions['id']===false)
 | |
| 			unset($htmlOptions['id']);
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		$options="\n".self::listOptions($select,$data,$htmlOptions);
 | |
| 		$hidden='';
 | |
| 		if(!empty($htmlOptions['multiple']))
 | |
| 		{
 | |
| 			if(substr($htmlOptions['name'],-2)!=='[]')
 | |
| 				$htmlOptions['name'].='[]';
 | |
| 			if(isset($htmlOptions['unselectValue']))
 | |
| 			{
 | |
| 				$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
 | |
| 				$hidden=self::hiddenField(substr($htmlOptions['name'],0,-2),$htmlOptions['unselectValue'],$hiddenOptions);
 | |
| 				unset($htmlOptions['unselectValue']);
 | |
| 			}
 | |
| 		}
 | |
| 		// add a hidden field so that if the option is not selected, it still submits a value
 | |
| 		return $hidden . self::tag('select',$htmlOptions,$options);
 | |
| 	}
 | |
| 	public static function listBox($name,$select,$data,$htmlOptions=array())
 | |
| 	{
 | |
| 		if(!isset($htmlOptions['size']))
 | |
| 			$htmlOptions['size']=4;
 | |
| 		if(!empty($htmlOptions['multiple']))
 | |
| 		{
 | |
| 			if(substr($name,-2)!=='[]')
 | |
| 				$name.='[]';
 | |
| 		}
 | |
| 		return self::dropDownList($name,$select,$data,$htmlOptions);
 | |
| 	}
 | |
| 	public static function checkBoxList($name,$select,$data,$htmlOptions=array())
 | |
| 	{
 | |
| 		$template=isset($htmlOptions['template'])?$htmlOptions['template']:'{input} {label}';
 | |
| 		$separator=isset($htmlOptions['separator'])?$htmlOptions['separator']:"<br/>\n";
 | |
| 		$container=isset($htmlOptions['container'])?$htmlOptions['container']:'span';
 | |
| 		unset($htmlOptions['template'],$htmlOptions['separator'],$htmlOptions['container']);
 | |
| 		if(substr($name,-2)!=='[]')
 | |
| 			$name.='[]';
 | |
| 		if(isset($htmlOptions['checkAll']))
 | |
| 		{
 | |
| 			$checkAllLabel=$htmlOptions['checkAll'];
 | |
| 			$checkAllLast=isset($htmlOptions['checkAllLast']) && $htmlOptions['checkAllLast'];
 | |
| 		}
 | |
| 		unset($htmlOptions['checkAll'],$htmlOptions['checkAllLast']);
 | |
| 		$labelOptions=isset($htmlOptions['labelOptions'])?$htmlOptions['labelOptions']:array();
 | |
| 		unset($htmlOptions['labelOptions']);
 | |
| 		$items=array();
 | |
| 		$baseID=isset($htmlOptions['baseID']) ? $htmlOptions['baseID'] : self::getIdByName($name);
 | |
| 		unset($htmlOptions['baseID']);
 | |
| 		$id=0;
 | |
| 		$checkAll=true;
 | |
| 		foreach($data as $value=>$labelTitle)
 | |
| 		{
 | |
| 			$checked=!is_array($select) && !strcmp($value,$select) || is_array($select) && in_array($value,$select);
 | |
| 			$checkAll=$checkAll && $checked;
 | |
| 			$htmlOptions['value']=$value;
 | |
| 			$htmlOptions['id']=$baseID.'_'.$id++;
 | |
| 			$option=self::checkBox($name,$checked,$htmlOptions);
 | |
| 			$beginLabel=self::openTag('label',$labelOptions);
 | |
| 			$label=self::label($labelTitle,$htmlOptions['id'],$labelOptions);
 | |
| 			$endLabel=self::closeTag('label');
 | |
| 			$items[]=strtr($template,array(
 | |
| 				'{input}'=>$option,
 | |
| 				'{beginLabel}'=>$beginLabel,
 | |
| 				'{label}'=>$label,
 | |
| 				'{labelTitle}'=>$labelTitle,
 | |
| 				'{endLabel}'=>$endLabel,
 | |
| 			));
 | |
| 		}
 | |
| 		if(isset($checkAllLabel))
 | |
| 		{
 | |
| 			$htmlOptions['value']=1;
 | |
| 			$htmlOptions['id']=$id=$baseID.'_all';
 | |
| 			$option=self::checkBox($id,$checkAll,$htmlOptions);
 | |
| 			$beginLabel=self::openTag('label',$labelOptions);
 | |
| 			$label=self::label($checkAllLabel,$id,$labelOptions);
 | |
| 			$endLabel=self::closeTag('label');
 | |
| 			$item=strtr($template,array(
 | |
| 				'{input}'=>$option,
 | |
| 				'{beginLabel}'=>$beginLabel,
 | |
| 				'{label}'=>$label,
 | |
| 				'{labelTitle}'=>$checkAllLabel,
 | |
| 				'{endLabel}'=>$endLabel,
 | |
| 			));
 | |
| 			if($checkAllLast)
 | |
| 				$items[]=$item;
 | |
| 			else
 | |
| 				array_unshift($items,$item);
 | |
| 			$name=strtr($name,array('['=>'\\[',']'=>'\\]'));
 | |
| 			$js=<<<EOD
 | |
| jQuery('#$id').click(function() {
 | |
| 	jQuery("input[name='$name']").prop('checked', this.checked);
 | |
| });
 | |
| jQuery("input[name='$name']").click(function() {
 | |
| 	jQuery('#$id').prop('checked', !jQuery("input[name='$name']:not(:checked)").length);
 | |
| });
 | |
| jQuery('#$id').prop('checked', !jQuery("input[name='$name']:not(:checked)").length);
 | |
| EOD;
 | |
| 			$cs=Yii::app()->getClientScript();
 | |
| 			$cs->registerCoreScript('jquery');
 | |
| 			$cs->registerScript($id,$js);
 | |
| 		}
 | |
| 		if(empty($container))
 | |
| 			return implode($separator,$items);
 | |
| 		else
 | |
| 			return self::tag($container,array('id'=>$baseID),implode($separator,$items));
 | |
| 	}
 | |
| 	public static function radioButtonList($name,$select,$data,$htmlOptions=array())
 | |
| 	{
 | |
| 		$template=isset($htmlOptions['template'])?$htmlOptions['template']:'{input} {label}';
 | |
| 		$separator=isset($htmlOptions['separator'])?$htmlOptions['separator']:"<br/>\n";
 | |
| 		$container=isset($htmlOptions['container'])?$htmlOptions['container']:'span';
 | |
| 		unset($htmlOptions['template'],$htmlOptions['separator'],$htmlOptions['container']);
 | |
| 		$labelOptions=isset($htmlOptions['labelOptions'])?$htmlOptions['labelOptions']:array();
 | |
| 		unset($htmlOptions['labelOptions']);
 | |
| 		if(isset($htmlOptions['empty']))
 | |
| 		{
 | |
| 			if(!is_array($htmlOptions['empty']))
 | |
| 				$htmlOptions['empty']=array(''=>$htmlOptions['empty']);
 | |
| 			$data=array_merge($htmlOptions['empty'],$data);
 | |
| 			unset($htmlOptions['empty']);
 | |
| 		}
 | |
| 		$items=array();
 | |
| 		$baseID=isset($htmlOptions['baseID']) ? $htmlOptions['baseID'] : self::getIdByName($name);
 | |
| 		unset($htmlOptions['baseID']);
 | |
| 		$id=0;
 | |
| 		foreach($data as $value=>$labelTitle)
 | |
| 		{
 | |
| 			$checked=!strcmp($value,$select);
 | |
| 			$htmlOptions['value']=$value;
 | |
| 			$htmlOptions['id']=$baseID.'_'.$id++;
 | |
| 			$option=self::radioButton($name,$checked,$htmlOptions);
 | |
| 			$beginLabel=self::openTag('label',$labelOptions);
 | |
| 			$label=self::label($labelTitle,$htmlOptions['id'],$labelOptions);
 | |
| 			$endLabel=self::closeTag('label');
 | |
| 			$items[]=strtr($template,array(
 | |
| 				'{input}'=>$option,
 | |
| 				'{beginLabel}'=>$beginLabel,
 | |
| 				'{label}'=>$label,
 | |
| 				'{labelTitle}'=>$labelTitle,
 | |
| 				'{endLabel}'=>$endLabel,
 | |
| 			));
 | |
| 		}
 | |
| 		if(empty($container))
 | |
| 			return implode($separator,$items);
 | |
| 		else
 | |
| 			return self::tag($container,array('id'=>$baseID),implode($separator,$items));
 | |
| 	}
 | |
| 	public static function ajaxLink($text,$url,$ajaxOptions=array(),$htmlOptions=array())
 | |
| 	{
 | |
| 		if(!isset($htmlOptions['href']))
 | |
| 			$htmlOptions['href']='#';
 | |
| 		$ajaxOptions['url']=$url;
 | |
| 		$htmlOptions['ajax']=$ajaxOptions;
 | |
| 		self::clientChange('click',$htmlOptions);
 | |
| 		return self::tag('a',$htmlOptions,$text);
 | |
| 	}
 | |
| 	public static function ajaxButton($label,$url,$ajaxOptions=array(),$htmlOptions=array())
 | |
| 	{
 | |
| 		$ajaxOptions['url']=$url;
 | |
| 		$htmlOptions['ajax']=$ajaxOptions;
 | |
| 		return self::button($label,$htmlOptions);
 | |
| 	}
 | |
| 	public static function ajaxSubmitButton($label,$url,$ajaxOptions=array(),$htmlOptions=array())
 | |
| 	{
 | |
| 		$ajaxOptions['type']='POST';
 | |
| 		$htmlOptions['type']='submit';
 | |
| 		return self::ajaxButton($label,$url,$ajaxOptions,$htmlOptions);
 | |
| 	}
 | |
| 	public static function ajax($options)
 | |
| 	{
 | |
| 		Yii::app()->getClientScript()->registerCoreScript('jquery');
 | |
| 		if(!isset($options['url']))
 | |
| 			$options['url']=new CJavaScriptExpression('location.href');
 | |
| 		else
 | |
| 			$options['url']=self::normalizeUrl($options['url']);
 | |
| 		if(!isset($options['cache']))
 | |
| 			$options['cache']=false;
 | |
| 		if(!isset($options['data']) && isset($options['type']))
 | |
| 			$options['data']=new CJavaScriptExpression('jQuery(this).parents("form").serialize()');
 | |
| 		foreach(array('beforeSend','complete','error','success') as $name)
 | |
| 		{
 | |
| 			if(isset($options[$name]) && !($options[$name] instanceof CJavaScriptExpression))
 | |
| 				$options[$name]=new CJavaScriptExpression($options[$name]);
 | |
| 		}
 | |
| 		if(isset($options['update']))
 | |
| 		{
 | |
| 			if(!isset($options['success']))
 | |
| 				$options['success']=new CJavaScriptExpression('function(html){jQuery("'.$options['update'].'").html(html)}');
 | |
| 			unset($options['update']);
 | |
| 		}
 | |
| 		if(isset($options['replace']))
 | |
| 		{
 | |
| 			if(!isset($options['success']))
 | |
| 				$options['success']=new CJavaScriptExpression('function(html){jQuery("'.$options['replace'].'").replaceWith(html)}');
 | |
| 			unset($options['replace']);
 | |
| 		}
 | |
| 		return 'jQuery.ajax('.CJavaScript::encode($options).');';
 | |
| 	}
 | |
| 	public static function asset($path,$hashByName=false)
 | |
| 	{
 | |
| 		return Yii::app()->getAssetManager()->publish($path,$hashByName);
 | |
| 	}
 | |
| 	public static function normalizeUrl($url)
 | |
| 	{
 | |
| 		if(is_array($url))
 | |
| 		{
 | |
| 			if(isset($url[0]))
 | |
| 			{
 | |
| 				if(($c=Yii::app()->getController())!==null)
 | |
| 					$url=$c->createUrl($url[0],array_splice($url,1));
 | |
| 				else
 | |
| 					$url=Yii::app()->createUrl($url[0],array_splice($url,1));
 | |
| 			}
 | |
| 			else
 | |
| 				$url='';
 | |
| 		}
 | |
| 		return $url==='' ? Yii::app()->getRequest()->getUrl() : $url;
 | |
| 	}
 | |
| 	protected static function inputField($type,$name,$value,$htmlOptions)
 | |
| 	{
 | |
| 		$htmlOptions['type']=$type;
 | |
| 		$htmlOptions['value']=$value;
 | |
| 		$htmlOptions['name']=$name;
 | |
| 		if(!isset($htmlOptions['id']))
 | |
| 			$htmlOptions['id']=self::getIdByName($name);
 | |
| 		elseif($htmlOptions['id']===false)
 | |
| 			unset($htmlOptions['id']);
 | |
| 		return self::tag('input',$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeLabel($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		$inputName=self::resolveName($model,$attribute);
 | |
| 		if(isset($htmlOptions['for']))
 | |
| 		{
 | |
| 			$for=$htmlOptions['for'];
 | |
| 			unset($htmlOptions['for']);
 | |
| 		}
 | |
| 		else
 | |
| 			$for=self::getIdByName($inputName);
 | |
| 		if(isset($htmlOptions['label']))
 | |
| 		{
 | |
| 			if(($label=$htmlOptions['label'])===false)
 | |
| 				return '';
 | |
| 			unset($htmlOptions['label']);
 | |
| 		}
 | |
| 		else
 | |
| 			$label=$model->getAttributeLabel($attribute);
 | |
| 		if($model->hasErrors($attribute))
 | |
| 			self::addErrorCss($htmlOptions);
 | |
| 		return self::label($label,$for,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeLabelEx($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		$realAttribute=$attribute;
 | |
| 		self::resolveName($model,$attribute); // strip off square brackets if any
 | |
| 		$htmlOptions['required']=$model->isAttributeRequired($attribute);
 | |
| 		return self::activeLabel($model,$realAttribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeTextField($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::activeInputField('text',$model,$attribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeSearchField($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::activeInputField('search',$model,$attribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeUrlField($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::activeInputField('url',$model,$attribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeEmailField($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::activeInputField('email',$model,$attribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeNumberField($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::activeInputField('number',$model,$attribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeRangeField($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::activeInputField('range',$model,$attribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeDateField($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::activeInputField('date',$model,$attribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeTimeField($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::activeInputField('time',$model,$attribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeTelField($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::activeInputField('tel',$model,$attribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeHiddenField($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		return self::activeInputField('hidden',$model,$attribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activePasswordField($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		return self::activeInputField('password',$model,$attribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeTextArea($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		if($model->hasErrors($attribute))
 | |
| 			self::addErrorCss($htmlOptions);
 | |
| 		if(isset($htmlOptions['value']))
 | |
| 		{
 | |
| 			$text=$htmlOptions['value'];
 | |
| 			unset($htmlOptions['value']);
 | |
| 		}
 | |
| 		else
 | |
| 			$text=self::resolveValue($model,$attribute);
 | |
| 		return self::tag('textarea',$htmlOptions,isset($htmlOptions['encode']) && !$htmlOptions['encode'] ? $text : self::encode($text));
 | |
| 	}
 | |
| 	public static function activeFileField($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		// add a hidden field so that if a model only has a file field, we can
 | |
| 		// still use isset($_POST[$modelClass]) to detect if the input is submitted
 | |
| 		$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
 | |
| 		return self::hiddenField($htmlOptions['name'],'',$hiddenOptions)
 | |
| 			. self::activeInputField('file',$model,$attribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeRadioButton($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		if(!isset($htmlOptions['value']))
 | |
| 			$htmlOptions['value']=1;
 | |
| 		if(!isset($htmlOptions['checked']) && self::resolveValue($model,$attribute)==$htmlOptions['value'])
 | |
| 			$htmlOptions['checked']='checked';
 | |
| 		self::clientChange('click',$htmlOptions);
 | |
| 		if(array_key_exists('uncheckValue',$htmlOptions))
 | |
| 		{
 | |
| 			$uncheck=$htmlOptions['uncheckValue'];
 | |
| 			unset($htmlOptions['uncheckValue']);
 | |
| 		}
 | |
| 		else
 | |
| 			$uncheck='0';
 | |
| 		$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
 | |
| 		$hidden=$uncheck!==null ? self::hiddenField($htmlOptions['name'],$uncheck,$hiddenOptions) : '';
 | |
| 		// add a hidden field so that if the radio button is not selected, it still submits a value
 | |
| 		return $hidden . self::activeInputField('radio',$model,$attribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeCheckBox($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		if(!isset($htmlOptions['value']))
 | |
| 			$htmlOptions['value']=1;
 | |
| 		if(!isset($htmlOptions['checked']) && self::resolveValue($model,$attribute)==$htmlOptions['value'])
 | |
| 			$htmlOptions['checked']='checked';
 | |
| 		self::clientChange('click',$htmlOptions);
 | |
| 		if(array_key_exists('uncheckValue',$htmlOptions))
 | |
| 		{
 | |
| 			$uncheck=$htmlOptions['uncheckValue'];
 | |
| 			unset($htmlOptions['uncheckValue']);
 | |
| 		}
 | |
| 		else
 | |
| 			$uncheck='0';
 | |
| 		$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
 | |
| 		$hidden=$uncheck!==null ? self::hiddenField($htmlOptions['name'],$uncheck,$hiddenOptions) : '';
 | |
| 		return $hidden . self::activeInputField('checkbox',$model,$attribute,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeDropDownList($model,$attribute,$data,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		$selection=self::resolveValue($model,$attribute);
 | |
| 		$options="\n".self::listOptions($selection,$data,$htmlOptions);
 | |
| 		self::clientChange('change',$htmlOptions);
 | |
| 		if($model->hasErrors($attribute))
 | |
| 			self::addErrorCss($htmlOptions);
 | |
| 		$hidden='';
 | |
| 		if(!empty($htmlOptions['multiple']))
 | |
| 		{
 | |
| 			if(substr($htmlOptions['name'],-2)!=='[]')
 | |
| 				$htmlOptions['name'].='[]';
 | |
| 			if(isset($htmlOptions['unselectValue']))
 | |
| 			{
 | |
| 				$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
 | |
| 				$hidden=self::hiddenField(substr($htmlOptions['name'],0,-2),$htmlOptions['unselectValue'],$hiddenOptions);
 | |
| 				unset($htmlOptions['unselectValue']);
 | |
| 			}
 | |
| 		}
 | |
| 		return $hidden . self::tag('select',$htmlOptions,$options);
 | |
| 	}
 | |
| 	public static function activeListBox($model,$attribute,$data,$htmlOptions=array())
 | |
| 	{
 | |
| 		if(!isset($htmlOptions['size']))
 | |
| 			$htmlOptions['size']=4;
 | |
| 		return self::activeDropDownList($model,$attribute,$data,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeCheckBoxList($model,$attribute,$data,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		$selection=self::resolveValue($model,$attribute);
 | |
| 		if($model->hasErrors($attribute))
 | |
| 			self::addErrorCss($htmlOptions);
 | |
| 		$name=$htmlOptions['name'];
 | |
| 		unset($htmlOptions['name']);
 | |
| 		if(array_key_exists('uncheckValue',$htmlOptions))
 | |
| 		{
 | |
| 			$uncheck=$htmlOptions['uncheckValue'];
 | |
| 			unset($htmlOptions['uncheckValue']);
 | |
| 		}
 | |
| 		else
 | |
| 			$uncheck='';
 | |
| 		$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
 | |
| 		$hidden=$uncheck!==null ? self::hiddenField($name,$uncheck,$hiddenOptions) : '';
 | |
| 		return $hidden . self::checkBoxList($name,$selection,$data,$htmlOptions);
 | |
| 	}
 | |
| 	public static function activeRadioButtonList($model,$attribute,$data,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveNameID($model,$attribute,$htmlOptions);
 | |
| 		$selection=self::resolveValue($model,$attribute);
 | |
| 		if($model->hasErrors($attribute))
 | |
| 			self::addErrorCss($htmlOptions);
 | |
| 		$name=$htmlOptions['name'];
 | |
| 		unset($htmlOptions['name']);
 | |
| 		if(array_key_exists('uncheckValue',$htmlOptions))
 | |
| 		{
 | |
| 			$uncheck=$htmlOptions['uncheckValue'];
 | |
| 			unset($htmlOptions['uncheckValue']);
 | |
| 		}
 | |
| 		else
 | |
| 			$uncheck='';
 | |
| 		$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
 | |
| 		$hidden=$uncheck!==null ? self::hiddenField($name,$uncheck,$hiddenOptions) : '';
 | |
| 		return $hidden . self::radioButtonList($name,$selection,$data,$htmlOptions);
 | |
| 	}
 | |
| 	public static function errorSummary($model,$header=null,$footer=null,$htmlOptions=array())
 | |
| 	{
 | |
| 		$content='';
 | |
| 		if(!is_array($model))
 | |
| 			$model=array($model);
 | |
| 		if(isset($htmlOptions['firstError']))
 | |
| 		{
 | |
| 			$firstError=$htmlOptions['firstError'];
 | |
| 			unset($htmlOptions['firstError']);
 | |
| 		}
 | |
| 		else
 | |
| 			$firstError=false;
 | |
| 		foreach($model as $m)
 | |
| 		{
 | |
| 			foreach($m->getErrors() as $errors)
 | |
| 			{
 | |
| 				foreach($errors as $error)
 | |
| 				{
 | |
| 					if($error!='')
 | |
| 						$content.="<li>$error</li>\n";
 | |
| 					if($firstError)
 | |
| 						break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		if($content!=='')
 | |
| 		{
 | |
| 			if($header===null)
 | |
| 				$header='<p>'.Yii::t('yii','Please fix the following input errors:').'</p>';
 | |
| 			if(!isset($htmlOptions['class']))
 | |
| 				$htmlOptions['class']=self::$errorSummaryCss;
 | |
| 			return self::tag('div',$htmlOptions,$header."\n<ul>\n$content</ul>".$footer);
 | |
| 		}
 | |
| 		else
 | |
| 			return '';
 | |
| 	}
 | |
| 	public static function error($model,$attribute,$htmlOptions=array())
 | |
| 	{
 | |
| 		self::resolveName($model,$attribute); // turn [a][b]attr into attr
 | |
| 		$error=$model->getError($attribute);
 | |
| 		if($error!='')
 | |
| 		{
 | |
| 			if(!isset($htmlOptions['class']))
 | |
| 				$htmlOptions['class']=self::$errorMessageCss;
 | |
| 			return self::tag(self::$errorContainerTag,$htmlOptions,$error);
 | |
| 		}
 | |
| 		else
 | |
| 			return '';
 | |
| 	}
 | |
| 	public static function listData($models,$valueField,$textField,$groupField='')
 | |
| 	{
 | |
| 		$listData=array();
 | |
| 		if($groupField==='')
 | |
| 		{
 | |
| 			foreach($models as $model)
 | |
| 			{
 | |
| 				$value=self::value($model,$valueField);
 | |
| 				$text=self::value($model,$textField);
 | |
| 				$listData[$value]=$text;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			foreach($models as $model)
 | |
| 			{
 | |
| 				$group=self::value($model,$groupField);
 | |
| 				$value=self::value($model,$valueField);
 | |
| 				$text=self::value($model,$textField);
 | |
| 				if($group===null)
 | |
| 					$listData[$value]=$text;
 | |
| 				else
 | |
| 					$listData[$group][$value]=$text;
 | |
| 			}
 | |
| 		}
 | |
| 		return $listData;
 | |
| 	}
 | |
| 	public static function value($model,$attribute,$defaultValue=null)
 | |
| 	{
 | |
| 		if(is_scalar($attribute) || $attribute===null)
 | |
| 			foreach(explode('.',$attribute) as $name)
 | |
| 			{
 | |
| 				if(is_object($model) && isset($model->$name))
 | |
| 					$model=$model->$name;
 | |
| 				elseif(is_array($model) && isset($model[$name]))
 | |
| 					$model=$model[$name];
 | |
| 				else
 | |
| 					return $defaultValue;
 | |
| 			}
 | |
| 		else
 | |
| 			return call_user_func($attribute,$model);
 | |
| 		return $model;
 | |
| 	}
 | |
| 	public static function getIdByName($name)
 | |
| 	{
 | |
| 		return str_replace(array('[]','][','[',']',' '),array('','_','_','','_'),$name);
 | |
| 	}
 | |
| 	public static function activeId($model,$attribute)
 | |
| 	{
 | |
| 		return self::getIdByName(self::activeName($model,$attribute));
 | |
| 	}
 | |
| 	public static function modelName($model)
 | |
| 	{
 | |
| 		if(is_callable(self::$_modelNameConverter))
 | |
| 			return call_user_func(self::$_modelNameConverter,$model);
 | |
| 		$className=is_object($model) ? get_class($model) : (string)$model;
 | |
| 		return trim(str_replace('\\','_',$className),'_');
 | |
| 	}
 | |
| 	public static function setModelNameConverter($converter)
 | |
| 	{
 | |
| 		if(is_callable($converter))
 | |
| 			self::$_modelNameConverter=$converter;
 | |
| 		elseif($converter===null)
 | |
| 			self::$_modelNameConverter=null;
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','The $converter argument must be a valid callback or null.'));
 | |
| 	}
 | |
| 	public static function activeName($model,$attribute)
 | |
| 	{
 | |
| 		$a=$attribute; // because the attribute name may be changed by resolveName
 | |
| 		return self::resolveName($model,$a);
 | |
| 	}
 | |
| 	protected static function activeInputField($type,$model,$attribute,$htmlOptions)
 | |
| 	{
 | |
| 		$htmlOptions['type']=$type;
 | |
| 		if($type==='text' || $type==='password')
 | |
| 		{
 | |
| 			if(!isset($htmlOptions['maxlength']))
 | |
| 			{
 | |
| 				foreach($model->getValidators($attribute) as $validator)
 | |
| 				{
 | |
| 					if($validator instanceof CStringValidator && $validator->max!==null)
 | |
| 					{
 | |
| 						$htmlOptions['maxlength']=$validator->max;
 | |
| 						break;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			elseif($htmlOptions['maxlength']===false)
 | |
| 				unset($htmlOptions['maxlength']);
 | |
| 		}
 | |
| 		if($type==='file')
 | |
| 			unset($htmlOptions['value']);
 | |
| 		elseif(!isset($htmlOptions['value']))
 | |
| 			$htmlOptions['value']=self::resolveValue($model,$attribute);
 | |
| 		if($model->hasErrors($attribute))
 | |
| 			self::addErrorCss($htmlOptions);
 | |
| 		return self::tag('input',$htmlOptions);
 | |
| 	}
 | |
| 	public static function listOptions($selection,$listData,&$htmlOptions)
 | |
| 	{
 | |
| 		$raw=isset($htmlOptions['encode']) && !$htmlOptions['encode'];
 | |
| 		$content='';
 | |
| 		if(isset($htmlOptions['prompt']))
 | |
| 		{
 | |
| 			$content.='<option value="">'.strtr($htmlOptions['prompt'],array('<'=>'<','>'=>'>'))."</option>\n";
 | |
| 			unset($htmlOptions['prompt']);
 | |
| 		}
 | |
| 		if(isset($htmlOptions['empty']))
 | |
| 		{
 | |
| 			if(!is_array($htmlOptions['empty']))
 | |
| 				$htmlOptions['empty']=array(''=>$htmlOptions['empty']);
 | |
| 			foreach($htmlOptions['empty'] as $value=>$label)
 | |
| 				$content.='<option value="'.self::encode($value).'">'.strtr($label,array('<'=>'<','>'=>'>'))."</option>\n";
 | |
| 			unset($htmlOptions['empty']);
 | |
| 		}
 | |
| 		if(isset($htmlOptions['options']))
 | |
| 		{
 | |
| 			$options=$htmlOptions['options'];
 | |
| 			unset($htmlOptions['options']);
 | |
| 		}
 | |
| 		else
 | |
| 			$options=array();
 | |
| 		$key=isset($htmlOptions['key']) ? $htmlOptions['key'] : 'primaryKey';
 | |
| 		if(is_array($selection))
 | |
| 		{
 | |
| 			foreach($selection as $i=>$item)
 | |
| 			{
 | |
| 				if(is_object($item))
 | |
| 					$selection[$i]=$item->$key;
 | |
| 			}
 | |
| 		}
 | |
| 		elseif(is_object($selection))
 | |
| 			$selection=$selection->$key;
 | |
| 		foreach($listData as $key=>$value)
 | |
| 		{
 | |
| 			if(is_array($value))
 | |
| 			{
 | |
| 				$content.='<optgroup label="'.($raw?$key : self::encode($key))."\">\n";
 | |
| 				$dummy=array('options'=>$options);
 | |
| 				if(isset($htmlOptions['encode']))
 | |
| 					$dummy['encode']=$htmlOptions['encode'];
 | |
| 				$content.=self::listOptions($selection,$value,$dummy);
 | |
| 				$content.='</optgroup>'."\n";
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				$attributes=array('value'=>(string)$key,'encode'=>!$raw);
 | |
| 				if(!is_array($selection) && !strcmp($key,$selection) || is_array($selection) && in_array($key,$selection))
 | |
| 					$attributes['selected']='selected';
 | |
| 				if(isset($options[$key]))
 | |
| 					$attributes=array_merge($attributes,$options[$key]);
 | |
| 				$content.=self::tag('option',$attributes,$raw?(string)$value : self::encode((string)$value))."\n";
 | |
| 			}
 | |
| 		}
 | |
| 		unset($htmlOptions['key']);
 | |
| 		return $content;
 | |
| 	}
 | |
| 	protected static function clientChange($event,&$htmlOptions)
 | |
| 	{
 | |
| 		if(!isset($htmlOptions['submit']) && !isset($htmlOptions['confirm']) && !isset($htmlOptions['ajax']))
 | |
| 			return;
 | |
| 		if(isset($htmlOptions['live']))
 | |
| 		{
 | |
| 			$live=$htmlOptions['live'];
 | |
| 			unset($htmlOptions['live']);
 | |
| 		}
 | |
| 		else
 | |
| 			$live = self::$liveEvents;
 | |
| 		if(isset($htmlOptions['return']) && $htmlOptions['return'])
 | |
| 			$return='return true';
 | |
| 		else
 | |
| 			$return='return false';
 | |
| 		if(isset($htmlOptions['on'.$event]))
 | |
| 		{
 | |
| 			$handler=trim($htmlOptions['on'.$event],';').';';
 | |
| 			unset($htmlOptions['on'.$event]);
 | |
| 		}
 | |
| 		else
 | |
| 			$handler='';
 | |
| 		if(isset($htmlOptions['id']))
 | |
| 			$id=$htmlOptions['id'];
 | |
| 		else
 | |
| 			$id=$htmlOptions['id']=isset($htmlOptions['name'])?$htmlOptions['name']:self::ID_PREFIX.self::$count++;
 | |
| 		$cs=Yii::app()->getClientScript();
 | |
| 		$cs->registerCoreScript('jquery');
 | |
| 		if(isset($htmlOptions['submit']))
 | |
| 		{
 | |
| 			$cs->registerCoreScript('yii');
 | |
| 			$request=Yii::app()->getRequest();
 | |
| 			if($request->enableCsrfValidation && isset($htmlOptions['csrf']) && $htmlOptions['csrf'])
 | |
| 				$htmlOptions['params'][$request->csrfTokenName]=$request->getCsrfToken();
 | |
| 			if(isset($htmlOptions['params']))
 | |
| 				$params=CJavaScript::encode($htmlOptions['params']);
 | |
| 			else
 | |
| 				$params='{}';
 | |
| 			if($htmlOptions['submit']!=='')
 | |
| 				$url=CJavaScript::quote(self::normalizeUrl($htmlOptions['submit']));
 | |
| 			else
 | |
| 				$url='';
 | |
| 			$handler.="jQuery.yii.submitForm(this,'$url',$params);{$return};";
 | |
| 		}
 | |
| 		if(isset($htmlOptions['ajax']))
 | |
| 			$handler.=self::ajax($htmlOptions['ajax'])."{$return};";
 | |
| 		if(isset($htmlOptions['confirm']))
 | |
| 		{
 | |
| 			$confirm='confirm(\''.CJavaScript::quote($htmlOptions['confirm']).'\')';
 | |
| 			if($handler!=='')
 | |
| 				$handler="if($confirm) {".$handler."} else return false;";
 | |
| 			else
 | |
| 				$handler="return $confirm;";
 | |
| 		}
 | |
| 		if($live)
 | |
| 			$cs->registerScript('Yii.CHtml.#' . $id,"jQuery('body').on('$event','#$id',function(){{$handler}});");
 | |
| 		else
 | |
| 			$cs->registerScript('Yii.CHtml.#' . $id,"jQuery('#$id').on('$event', function(){{$handler}});");
 | |
| 		unset($htmlOptions['params'],$htmlOptions['submit'],$htmlOptions['ajax'],$htmlOptions['confirm'],$htmlOptions['return'],$htmlOptions['csrf']);
 | |
| 	}
 | |
| 	public static function resolveNameID($model,&$attribute,&$htmlOptions)
 | |
| 	{
 | |
| 		if(!isset($htmlOptions['name']))
 | |
| 			$htmlOptions['name']=self::resolveName($model,$attribute);
 | |
| 		if(!isset($htmlOptions['id']))
 | |
| 			$htmlOptions['id']=self::getIdByName($htmlOptions['name']);
 | |
| 		elseif($htmlOptions['id']===false)
 | |
| 			unset($htmlOptions['id']);
 | |
| 	}
 | |
| 	public static function resolveName($model,&$attribute)
 | |
| 	{
 | |
| 		$modelName=self::modelName($model);
 | |
| 		if(($pos=strpos($attribute,'['))!==false)
 | |
| 		{
 | |
| 			if($pos!==0)  // e.g. name[a][b]
 | |
| 				return $modelName.'['.substr($attribute,0,$pos).']'.substr($attribute,$pos);
 | |
| 			if(($pos=strrpos($attribute,']'))!==false && $pos!==strlen($attribute)-1)  // e.g. [a][b]name
 | |
| 			{
 | |
| 				$sub=substr($attribute,0,$pos+1);
 | |
| 				$attribute=substr($attribute,$pos+1);
 | |
| 				return $modelName.$sub.'['.$attribute.']';
 | |
| 			}
 | |
| 			if(preg_match('/\](\w+\[.*)$/',$attribute,$matches))
 | |
| 			{
 | |
| 				$name=$modelName.'['.str_replace(']','][',trim(strtr($attribute,array(']['=>']','['=>']')),']')).']';
 | |
| 				$attribute=$matches[1];
 | |
| 				return $name;
 | |
| 			}
 | |
| 		}
 | |
| 		return $modelName.'['.$attribute.']';
 | |
| 	}
 | |
| 	public static function resolveValue($model,$attribute)
 | |
| 	{
 | |
| 		if(($pos=strpos($attribute,'['))!==false)
 | |
| 		{
 | |
| 			if($pos===0) // [a]name[b][c], should ignore [a]
 | |
| 			{
 | |
| 				if(preg_match('/\](\w+(\[.+)?)/',$attribute,$matches))
 | |
| 					$attribute=$matches[1]; // we get: name[b][c]
 | |
| 				if(($pos=strpos($attribute,'['))===false)
 | |
| 					return $model->$attribute;
 | |
| 			}
 | |
| 			$name=substr($attribute,0,$pos);
 | |
| 			$value=$model->$name;
 | |
| 			foreach(explode('][',rtrim(substr($attribute,$pos+1),']')) as $id)
 | |
| 			{
 | |
| 				if((is_array($value) || $value instanceof ArrayAccess) && isset($value[$id]))
 | |
| 					$value=$value[$id];
 | |
| 				else
 | |
| 					return null;
 | |
| 			}
 | |
| 			return $value;
 | |
| 		}
 | |
| 		else
 | |
| 			return $model->$attribute;
 | |
| 	}
 | |
| 	protected static function addErrorCss(&$htmlOptions)
 | |
| 	{
 | |
| 		if(empty(self::$errorCss))
 | |
| 			return;
 | |
| 		if(isset($htmlOptions['class']))
 | |
| 			$htmlOptions['class'].=' '.self::$errorCss;
 | |
| 		else
 | |
| 			$htmlOptions['class']=self::$errorCss;
 | |
| 	}
 | |
| 	public static function renderAttributes($htmlOptions)
 | |
| 	{
 | |
| 		static $specialAttributes=array(
 | |
| 			'async'=>1,
 | |
| 			'autofocus'=>1,
 | |
| 			'autoplay'=>1,
 | |
| 			'checked'=>1,
 | |
| 			'controls'=>1,
 | |
| 			'declare'=>1,
 | |
| 			'default'=>1,
 | |
| 			'defer'=>1,
 | |
| 			'disabled'=>1,
 | |
| 			'formnovalidate'=>1,
 | |
| 			'hidden'=>1,
 | |
| 			'ismap'=>1,
 | |
| 			'loop'=>1,
 | |
| 			'multiple'=>1,
 | |
| 			'muted'=>1,
 | |
| 			'nohref'=>1,
 | |
| 			'noresize'=>1,
 | |
| 			'novalidate'=>1,
 | |
| 			'open'=>1,
 | |
| 			'readonly'=>1,
 | |
| 			'required'=>1,
 | |
| 			'reversed'=>1,
 | |
| 			'scoped'=>1,
 | |
| 			'seamless'=>1,
 | |
| 			'selected'=>1,
 | |
| 			'typemustmatch'=>1,
 | |
| 		);
 | |
| 		if($htmlOptions===array())
 | |
| 			return '';
 | |
| 		$html='';
 | |
| 		if(isset($htmlOptions['encode']))
 | |
| 		{
 | |
| 			$raw=!$htmlOptions['encode'];
 | |
| 			unset($htmlOptions['encode']);
 | |
| 		}
 | |
| 		else
 | |
| 			$raw=false;
 | |
| 		foreach($htmlOptions as $name=>$value)
 | |
| 		{
 | |
| 			if(isset($specialAttributes[$name]))
 | |
| 			{
 | |
| 				if($value)
 | |
| 				{
 | |
| 					$html .= ' ' . $name;
 | |
| 					if(self::$renderSpecialAttributesValue)
 | |
| 						$html .= '="' . $name . '"';
 | |
| 				}
 | |
| 			}
 | |
| 			elseif($value!==null)
 | |
| 				$html .= ' ' . $name . '="' . ($raw ? $value : self::encode($value)) . '"';
 | |
| 		}
 | |
| 		return $html;
 | |
| 	}
 | |
| }
 | |
| class CWidgetFactory extends CApplicationComponent implements IWidgetFactory
 | |
| {
 | |
| 	public $enableSkin=false;
 | |
| 	public $widgets=array();
 | |
| 	public $skinnableWidgets;
 | |
| 	public $skinPath;
 | |
| 	private $_skins=array();  // class name, skin name, property name => value
 | |
| 	public function init()
 | |
| 	{
 | |
| 		parent::init();
 | |
| 		if($this->enableSkin && $this->skinPath===null)
 | |
| 			$this->skinPath=Yii::app()->getViewPath().DIRECTORY_SEPARATOR.'skins';
 | |
| 	}
 | |
| 	public function createWidget($owner,$className,$properties=array())
 | |
| 	{
 | |
| 		$className=Yii::import($className,true);
 | |
| 		$widget=new $className($owner);
 | |
| 		if(isset($this->widgets[$className]))
 | |
| 			$properties=$properties===array() ? $this->widgets[$className] : CMap::mergeArray($this->widgets[$className],$properties);
 | |
| 		if($this->enableSkin)
 | |
| 		{
 | |
| 			if($this->skinnableWidgets===null || in_array($className,$this->skinnableWidgets))
 | |
| 			{
 | |
| 				$skinName=isset($properties['skin']) ? $properties['skin'] : 'default';
 | |
| 				if($skinName!==false && ($skin=$this->getSkin($className,$skinName))!==array())
 | |
| 					$properties=$properties===array() ? $skin : CMap::mergeArray($skin,$properties);
 | |
| 			}
 | |
| 		}
 | |
| 		foreach($properties as $name=>$value)
 | |
| 			$widget->$name=$value;
 | |
| 		return $widget;
 | |
| 	}
 | |
| 	protected function getSkin($className,$skinName)
 | |
| 	{
 | |
| 		if(!isset($this->_skins[$className][$skinName]))
 | |
| 		{
 | |
| 			$skinFile=$this->skinPath.DIRECTORY_SEPARATOR.$className.'.php';
 | |
| 			if(is_file($skinFile))
 | |
| 				$this->_skins[$className]=require($skinFile);
 | |
| 			else
 | |
| 				$this->_skins[$className]=array();
 | |
| 			if(($theme=Yii::app()->getTheme())!==null)
 | |
| 			{
 | |
| 				$skinFile=$theme->getSkinPath().DIRECTORY_SEPARATOR.$className.'.php';
 | |
| 				if(is_file($skinFile))
 | |
| 				{
 | |
| 					$skins=require($skinFile);
 | |
| 					foreach($skins as $name=>$skin)
 | |
| 						$this->_skins[$className][$name]=$skin;
 | |
| 				}
 | |
| 			}
 | |
| 			if(!isset($this->_skins[$className][$skinName]))
 | |
| 				$this->_skins[$className][$skinName]=array();
 | |
| 		}
 | |
| 		return $this->_skins[$className][$skinName];
 | |
| 	}
 | |
| }
 | |
| class CWidget extends CBaseController
 | |
| {
 | |
| 	public $actionPrefix;
 | |
| 	public $skin='default';
 | |
| 	private static $_viewPaths;
 | |
| 	private static $_counter=0;
 | |
| 	private $_id;
 | |
| 	private $_owner;
 | |
| 	public static function actions()
 | |
| 	{
 | |
| 		return array();
 | |
| 	}
 | |
| 	public function __construct($owner=null)
 | |
| 	{
 | |
| 		$this->_owner=$owner===null?Yii::app()->getController():$owner;
 | |
| 	}
 | |
| 	public function getOwner()
 | |
| 	{
 | |
| 		return $this->_owner;
 | |
| 	}
 | |
| 	public function getId($autoGenerate=true)
 | |
| 	{
 | |
| 		if($this->_id!==null)
 | |
| 			return $this->_id;
 | |
| 		elseif($autoGenerate)
 | |
| 			return $this->_id='yw'.self::$_counter++;
 | |
| 	}
 | |
| 	public function setId($value)
 | |
| 	{
 | |
| 		$this->_id=$value;
 | |
| 	}
 | |
| 	public function getController()
 | |
| 	{
 | |
| 		if($this->_owner instanceof CController)
 | |
| 			return $this->_owner;
 | |
| 		else
 | |
| 			return Yii::app()->getController();
 | |
| 	}
 | |
| 	public function init()
 | |
| 	{
 | |
| 	}
 | |
| 	public function run()
 | |
| 	{
 | |
| 	}
 | |
| 	public function getViewPath($checkTheme=false)
 | |
| 	{
 | |
| 		$className=get_class($this);
 | |
| 		$scope=$checkTheme?'theme':'local';
 | |
| 		if(isset(self::$_viewPaths[$className][$scope]))
 | |
| 			return self::$_viewPaths[$className][$scope];
 | |
| 		else
 | |
| 		{
 | |
| 			if($checkTheme && ($theme=Yii::app()->getTheme())!==null)
 | |
| 			{
 | |
| 				$path=$theme->getViewPath().DIRECTORY_SEPARATOR;
 | |
| 				if(strpos($className,'\\')!==false) // namespaced class
 | |
| 					$path.=str_replace('\\','_',ltrim($className,'\\'));
 | |
| 				else
 | |
| 					$path.=$className;
 | |
| 				if(is_dir($path))
 | |
| 					return self::$_viewPaths[$className]['theme']=$path;
 | |
| 			}
 | |
| 			$class=new ReflectionClass($className);
 | |
| 			return self::$_viewPaths[$className]['local']=dirname($class->getFileName()).DIRECTORY_SEPARATOR.'views';
 | |
| 		}
 | |
| 	}
 | |
| 	public function getViewFile($viewName)
 | |
| 	{
 | |
| 		if(($renderer=Yii::app()->getViewRenderer())!==null)
 | |
| 			$extension=$renderer->fileExtension;
 | |
| 		else
 | |
| 			$extension='.php';
 | |
| 		if(strpos($viewName,'.')) // a path alias
 | |
| 			$viewFile=Yii::getPathOfAlias($viewName);
 | |
| 		else
 | |
| 		{
 | |
| 			$viewFile=$this->getViewPath(true).DIRECTORY_SEPARATOR.$viewName;
 | |
| 			if(is_file($viewFile.$extension))
 | |
| 				return Yii::app()->findLocalizedFile($viewFile.$extension);
 | |
| 			elseif($extension!=='.php' && is_file($viewFile.'.php'))
 | |
| 				return Yii::app()->findLocalizedFile($viewFile.'.php');
 | |
| 			$viewFile=$this->getViewPath(false).DIRECTORY_SEPARATOR.$viewName;
 | |
| 		}
 | |
| 		if(is_file($viewFile.$extension))
 | |
| 			return Yii::app()->findLocalizedFile($viewFile.$extension);
 | |
| 		elseif($extension!=='.php' && is_file($viewFile.'.php'))
 | |
| 			return Yii::app()->findLocalizedFile($viewFile.'.php');
 | |
| 		else
 | |
| 			return false;
 | |
| 	}
 | |
| 	public function render($view,$data=null,$return=false)
 | |
| 	{
 | |
| 		if(($viewFile=$this->getViewFile($view))!==false)
 | |
| 			return $this->renderFile($viewFile,$data,$return);
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','{widget} cannot find the view "{view}".',
 | |
| 				array('{widget}'=>get_class($this), '{view}'=>$view)));
 | |
| 	}
 | |
| }
 | |
| class CClientScript extends CApplicationComponent
 | |
| {
 | |
| 	const POS_HEAD=0;
 | |
| 	const POS_BEGIN=1;
 | |
| 	const POS_END=2;
 | |
| 	const POS_LOAD=3;
 | |
| 	const POS_READY=4;
 | |
| 	public $enableJavaScript=true;
 | |
| 	public $scriptMap=array();
 | |
| 	public $packages=array();
 | |
| 	public $corePackages;
 | |
| 	public $scripts=array();
 | |
| 	protected $cssFiles=array();
 | |
| 	protected $scriptFiles=array();
 | |
| 	protected $metaTags=array();
 | |
| 	protected $linkTags=array();
 | |
| 	protected $css=array();
 | |
| 	protected $hasScripts=false;
 | |
| 	protected $coreScripts=array();
 | |
| 	public $coreScriptPosition=self::POS_HEAD;
 | |
| 	public $defaultScriptFilePosition=self::POS_HEAD;
 | |
| 	public $defaultScriptPosition=self::POS_READY;
 | |
| 	private $_baseUrl;
 | |
| 	public function reset()
 | |
| 	{
 | |
| 		$this->hasScripts=false;
 | |
| 		$this->coreScripts=array();
 | |
| 		$this->cssFiles=array();
 | |
| 		$this->css=array();
 | |
| 		$this->scriptFiles=array();
 | |
| 		$this->scripts=array();
 | |
| 		$this->metaTags=array();
 | |
| 		$this->linkTags=array();
 | |
| 		$this->recordCachingAction('clientScript','reset',array());
 | |
| 	}
 | |
| 	public function render(&$output)
 | |
| 	{
 | |
| 		if(!$this->hasScripts)
 | |
| 			return;
 | |
| 		$this->renderCoreScripts();
 | |
| 		if(!empty($this->scriptMap))
 | |
| 			$this->remapScripts();
 | |
| 		$this->unifyScripts();
 | |
| 		$this->renderHead($output);
 | |
| 		if($this->enableJavaScript)
 | |
| 		{
 | |
| 			$this->renderBodyBegin($output);
 | |
| 			$this->renderBodyEnd($output);
 | |
| 		}
 | |
| 	}
 | |
| 	protected function unifyScripts()
 | |
| 	{
 | |
| 		if(!$this->enableJavaScript)
 | |
| 			return;
 | |
| 		$map=array();
 | |
| 		if(isset($this->scriptFiles[self::POS_HEAD]))
 | |
| 			$map=$this->scriptFiles[self::POS_HEAD];
 | |
| 		if(isset($this->scriptFiles[self::POS_BEGIN]))
 | |
| 		{
 | |
| 			foreach($this->scriptFiles[self::POS_BEGIN] as $scriptFile=>$scriptFileValue)
 | |
| 			{
 | |
| 				if(isset($map[$scriptFile]))
 | |
| 					unset($this->scriptFiles[self::POS_BEGIN][$scriptFile]);
 | |
| 				else
 | |
| 					$map[$scriptFile]=true;
 | |
| 			}
 | |
| 		}
 | |
| 		if(isset($this->scriptFiles[self::POS_END]))
 | |
| 		{
 | |
| 			foreach($this->scriptFiles[self::POS_END] as $key=>$scriptFile)
 | |
| 			{
 | |
| 				if(isset($map[$key]))
 | |
| 					unset($this->scriptFiles[self::POS_END][$key]);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	protected function remapScripts()
 | |
| 	{
 | |
| 		$cssFiles=array();
 | |
| 		foreach($this->cssFiles as $url=>$media)
 | |
| 		{
 | |
| 			$name=basename($url);
 | |
| 			if(isset($this->scriptMap[$name]))
 | |
| 			{
 | |
| 				if($this->scriptMap[$name]!==false)
 | |
| 					$cssFiles[$this->scriptMap[$name]]=$media;
 | |
| 			}
 | |
| 			elseif(isset($this->scriptMap['*.css']))
 | |
| 			{
 | |
| 				if($this->scriptMap['*.css']!==false)
 | |
| 					$cssFiles[$this->scriptMap['*.css']]=$media;
 | |
| 			}
 | |
| 			else
 | |
| 				$cssFiles[$url]=$media;
 | |
| 		}
 | |
| 		$this->cssFiles=$cssFiles;
 | |
| 		$jsFiles=array();
 | |
| 		foreach($this->scriptFiles as $position=>$scriptFiles)
 | |
| 		{
 | |
| 			$jsFiles[$position]=array();
 | |
| 			foreach($scriptFiles as $scriptFile=>$scriptFileValue)
 | |
| 			{
 | |
| 				$name=basename($scriptFile);
 | |
| 				if(isset($this->scriptMap[$name]))
 | |
| 				{
 | |
| 					if($this->scriptMap[$name]!==false)
 | |
| 						$jsFiles[$position][$this->scriptMap[$name]]=$this->scriptMap[$name];
 | |
| 				}
 | |
| 				elseif(isset($this->scriptMap['*.js']))
 | |
| 				{
 | |
| 					if($this->scriptMap['*.js']!==false)
 | |
| 						$jsFiles[$position][$this->scriptMap['*.js']]=$this->scriptMap['*.js'];
 | |
| 				}
 | |
| 				else
 | |
| 					$jsFiles[$position][$scriptFile]=$scriptFileValue;
 | |
| 			}
 | |
| 		}
 | |
| 		$this->scriptFiles=$jsFiles;
 | |
| 	}
 | |
| 	protected function renderScriptBatch(array $scripts)
 | |
| 	{
 | |
| 		$html = '';
 | |
| 		$scriptBatches = array();
 | |
| 		foreach($scripts as $scriptValue)
 | |
| 		{
 | |
| 			if(is_array($scriptValue))
 | |
| 			{
 | |
| 				$scriptContent = $scriptValue['content'];
 | |
| 				unset($scriptValue['content']);
 | |
| 				$scriptHtmlOptions = $scriptValue;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				$scriptContent = $scriptValue;
 | |
| 				$scriptHtmlOptions = array();
 | |
| 			}
 | |
| 			$key=serialize(ksort($scriptHtmlOptions));
 | |
| 			$scriptBatches[$key]['htmlOptions']=$scriptHtmlOptions;
 | |
| 			$scriptBatches[$key]['scripts'][]=$scriptContent;
 | |
| 		}
 | |
| 		foreach($scriptBatches as $scriptBatch)
 | |
| 			if(!empty($scriptBatch['scripts']))
 | |
| 				$html.=CHtml::script(implode("\n",$scriptBatch['scripts']),$scriptBatch['htmlOptions'])."\n";
 | |
| 		return $html;
 | |
| 	}
 | |
| 	public function renderCoreScripts()
 | |
| 	{
 | |
| 		if($this->coreScripts===null)
 | |
| 			return;
 | |
| 		$cssFiles=array();
 | |
| 		$jsFiles=array();
 | |
| 		foreach($this->coreScripts as $name=>$package)
 | |
| 		{
 | |
| 			$baseUrl=$this->getPackageBaseUrl($name);
 | |
| 			if(!empty($package['js']))
 | |
| 			{
 | |
| 				foreach($package['js'] as $js)
 | |
| 					$jsFiles[$baseUrl.'/'.$js]=$baseUrl.'/'.$js;
 | |
| 			}
 | |
| 			if(!empty($package['css']))
 | |
| 			{
 | |
| 				foreach($package['css'] as $css)
 | |
| 					$cssFiles[$baseUrl.'/'.$css]='';
 | |
| 			}
 | |
| 		}
 | |
| 		// merge in place
 | |
| 		if($cssFiles!==array())
 | |
| 		{
 | |
| 			foreach($this->cssFiles as $cssFile=>$media)
 | |
| 				$cssFiles[$cssFile]=$media;
 | |
| 			$this->cssFiles=$cssFiles;
 | |
| 		}
 | |
| 		if($jsFiles!==array())
 | |
| 		{
 | |
| 			if(isset($this->scriptFiles[$this->coreScriptPosition]))
 | |
| 			{
 | |
| 				foreach($this->scriptFiles[$this->coreScriptPosition] as $url => $value)
 | |
| 					$jsFiles[$url]=$value;
 | |
| 			}
 | |
| 			$this->scriptFiles[$this->coreScriptPosition]=$jsFiles;
 | |
| 		}
 | |
| 	}
 | |
| 	public function renderHead(&$output)
 | |
| 	{
 | |
| 		$html='';
 | |
| 		foreach($this->metaTags as $meta)
 | |
| 			$html.=CHtml::metaTag($meta['content'],null,null,$meta)."\n";
 | |
| 		foreach($this->linkTags as $link)
 | |
| 			$html.=CHtml::linkTag(null,null,null,null,$link)."\n";
 | |
| 		foreach($this->cssFiles as $url=>$media)
 | |
| 			$html.=CHtml::cssFile($url,$media)."\n";
 | |
| 		foreach($this->css as $css)
 | |
| 			$html.=CHtml::css($css[0],$css[1])."\n";
 | |
| 		if($this->enableJavaScript)
 | |
| 		{
 | |
| 			if(isset($this->scriptFiles[self::POS_HEAD]))
 | |
| 			{
 | |
| 				foreach($this->scriptFiles[self::POS_HEAD] as $scriptFileValueUrl=>$scriptFileValue)
 | |
| 				{
 | |
| 					if(is_array($scriptFileValue))
 | |
| 						$html.=CHtml::scriptFile($scriptFileValueUrl,$scriptFileValue)."\n";
 | |
| 					else
 | |
| 						$html.=CHtml::scriptFile($scriptFileValueUrl)."\n";
 | |
| 				}
 | |
| 			}
 | |
| 			if(isset($this->scripts[self::POS_HEAD]))
 | |
| 				$html.=$this->renderScriptBatch($this->scripts[self::POS_HEAD]);
 | |
| 		}
 | |
| 		if($html!=='')
 | |
| 		{
 | |
| 			$count=0;
 | |
| 			$output=preg_replace('/(<title\b[^>]*>|<\\/head\s*>)/is','<###head###>$1',$output,1,$count);
 | |
| 			if($count)
 | |
| 				$output=str_replace('<###head###>',$html,$output);
 | |
| 			else
 | |
| 				$output=$html.$output;
 | |
| 		}
 | |
| 	}
 | |
| 	public function renderBodyBegin(&$output)
 | |
| 	{
 | |
| 		$html='';
 | |
| 		if(isset($this->scriptFiles[self::POS_BEGIN]))
 | |
| 		{
 | |
| 			foreach($this->scriptFiles[self::POS_BEGIN] as $scriptFileUrl=>$scriptFileValue)
 | |
| 			{
 | |
| 				if(is_array($scriptFileValue))
 | |
| 					$html.=CHtml::scriptFile($scriptFileUrl,$scriptFileValue)."\n";
 | |
| 				else
 | |
| 					$html.=CHtml::scriptFile($scriptFileUrl)."\n";
 | |
| 			}
 | |
| 		}
 | |
| 		if(isset($this->scripts[self::POS_BEGIN]))
 | |
| 			$html.=$this->renderScriptBatch($this->scripts[self::POS_BEGIN]);
 | |
| 		if($html!=='')
 | |
| 		{
 | |
| 			$count=0;
 | |
| 			$output=preg_replace('/(<body\b[^>]*>)/is','$1<###begin###>',$output,1,$count);
 | |
| 			if($count)
 | |
| 				$output=str_replace('<###begin###>',$html,$output);
 | |
| 			else
 | |
| 				$output=$html.$output;
 | |
| 		}
 | |
| 	}
 | |
| 	public function renderBodyEnd(&$output)
 | |
| 	{
 | |
| 		if(!isset($this->scriptFiles[self::POS_END]) && !isset($this->scripts[self::POS_END])
 | |
| 			&& !isset($this->scripts[self::POS_READY]) && !isset($this->scripts[self::POS_LOAD]))
 | |
| 			return;
 | |
| 		$fullPage=0;
 | |
| 		$output=preg_replace('/(<\\/body\s*>)/is','<###end###>$1',$output,1,$fullPage);
 | |
| 		$html='';
 | |
| 		if(isset($this->scriptFiles[self::POS_END]))
 | |
| 		{
 | |
| 			foreach($this->scriptFiles[self::POS_END] as $scriptFileUrl=>$scriptFileValue)
 | |
| 			{
 | |
| 				if(is_array($scriptFileValue))
 | |
| 					$html.=CHtml::scriptFile($scriptFileUrl,$scriptFileValue)."\n";
 | |
| 				else
 | |
| 					$html.=CHtml::scriptFile($scriptFileUrl)."\n";
 | |
| 			}
 | |
| 		}
 | |
| 		$scripts=isset($this->scripts[self::POS_END]) ? $this->scripts[self::POS_END] : array();
 | |
| 		if(isset($this->scripts[self::POS_READY]))
 | |
| 		{
 | |
| 			if($fullPage)
 | |
| 				$scripts[]="jQuery(function($) {\n".implode("\n",$this->scripts[self::POS_READY])."\n});";
 | |
| 			else
 | |
| 				$scripts[]=implode("\n",$this->scripts[self::POS_READY]);
 | |
| 		}
 | |
| 		if(isset($this->scripts[self::POS_LOAD]))
 | |
| 		{
 | |
| 			if($fullPage)
 | |
| 				$scripts[]="jQuery(window).on('load',function() {\n".implode("\n",$this->scripts[self::POS_LOAD])."\n});";
 | |
| 			else
 | |
| 				$scripts[]=implode("\n",$this->scripts[self::POS_LOAD]);
 | |
| 		}
 | |
| 		if(!empty($scripts))
 | |
| 			$html.=$this->renderScriptBatch($scripts);
 | |
| 		if($fullPage)
 | |
| 			$output=str_replace('<###end###>',$html,$output);
 | |
| 		else
 | |
| 			$output=$output.$html;
 | |
| 	}
 | |
| 	public function getCoreScriptUrl()
 | |
| 	{
 | |
| 		if($this->_baseUrl!==null)
 | |
| 			return $this->_baseUrl;
 | |
| 		else
 | |
| 			return $this->_baseUrl=Yii::app()->getAssetManager()->publish(YII_PATH.'/web/js/source');
 | |
| 	}
 | |
| 	public function setCoreScriptUrl($value)
 | |
| 	{
 | |
| 		$this->_baseUrl=$value;
 | |
| 	}
 | |
| 	public function getPackageBaseUrl($name)
 | |
| 	{
 | |
| 		if(!isset($this->coreScripts[$name]))
 | |
| 			return false;
 | |
| 		$package=$this->coreScripts[$name];
 | |
| 		if(isset($package['baseUrl']))
 | |
| 		{
 | |
| 			$baseUrl=$package['baseUrl'];
 | |
| 			if($baseUrl==='' || $baseUrl[0]!=='/' && strpos($baseUrl,'://')===false)
 | |
| 				$baseUrl=Yii::app()->getRequest()->getBaseUrl().'/'.$baseUrl;
 | |
| 			$baseUrl=rtrim($baseUrl,'/');
 | |
| 		}
 | |
| 		elseif(isset($package['basePath']))
 | |
| 			$baseUrl=Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias($package['basePath']));
 | |
| 		else
 | |
| 			$baseUrl=$this->getCoreScriptUrl();
 | |
| 		return $this->coreScripts[$name]['baseUrl']=$baseUrl;
 | |
| 	}
 | |
| 	public function registerPackage($name)
 | |
| 	{
 | |
| 		return $this->registerCoreScript($name);
 | |
| 	}
 | |
| 	public function registerCoreScript($name)
 | |
| 	{
 | |
| 		if(isset($this->coreScripts[$name]))
 | |
| 			return $this;
 | |
| 		if(isset($this->packages[$name]))
 | |
| 			$package=$this->packages[$name];
 | |
| 		else
 | |
| 		{
 | |
| 			if($this->corePackages===null)
 | |
| 				$this->corePackages=require(YII_PATH.'/web/js/packages.php');
 | |
| 			if(isset($this->corePackages[$name]))
 | |
| 				$package=$this->corePackages[$name];
 | |
| 		}
 | |
| 		if(isset($package))
 | |
| 		{
 | |
| 			if(!empty($package['depends']))
 | |
| 			{
 | |
| 				foreach($package['depends'] as $p)
 | |
| 					$this->registerCoreScript($p);
 | |
| 			}
 | |
| 			$this->coreScripts[$name]=$package;
 | |
| 			$this->hasScripts=true;
 | |
| 			$params=func_get_args();
 | |
| 			$this->recordCachingAction('clientScript','registerCoreScript',$params);
 | |
| 		}
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function registerCssFile($url,$media='')
 | |
| 	{
 | |
| 		$this->hasScripts=true;
 | |
| 		$this->cssFiles[$url]=$media;
 | |
| 		$params=func_get_args();
 | |
| 		$this->recordCachingAction('clientScript','registerCssFile',$params);
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function registerCss($id,$css,$media='')
 | |
| 	{
 | |
| 		$this->hasScripts=true;
 | |
| 		$this->css[$id]=array($css,$media);
 | |
| 		$params=func_get_args();
 | |
| 		$this->recordCachingAction('clientScript','registerCss',$params);
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function registerScriptFile($url,$position=null,array $htmlOptions=array())
 | |
| 	{
 | |
| 		if($position===null)
 | |
| 			$position=$this->defaultScriptFilePosition;
 | |
| 		$this->hasScripts=true;
 | |
| 		if(empty($htmlOptions))
 | |
| 			$value=$url;
 | |
| 		else
 | |
| 		{
 | |
| 			$value=$htmlOptions;
 | |
| 			$value['src']=$url;
 | |
| 		}
 | |
| 		$this->scriptFiles[$position][$url]=$value;
 | |
| 		$params=func_get_args();
 | |
| 		$this->recordCachingAction('clientScript','registerScriptFile',$params);
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function registerScript($id,$script,$position=null,array $htmlOptions=array())
 | |
| 	{
 | |
| 		if($position===null)
 | |
| 			$position=$this->defaultScriptPosition;
 | |
| 		$this->hasScripts=true;
 | |
| 		if(empty($htmlOptions))
 | |
| 			$scriptValue=$script;
 | |
| 		else
 | |
| 		{
 | |
| 			if($position==self::POS_LOAD || $position==self::POS_READY)
 | |
| 				throw new CException(Yii::t('yii','Script HTML options are not allowed for "CClientScript::POS_LOAD" and "CClientScript::POS_READY".'));
 | |
| 			$scriptValue=$htmlOptions;
 | |
| 			$scriptValue['content']=$script;
 | |
| 		}
 | |
| 		$this->scripts[$position][$id]=$scriptValue;
 | |
| 		if($position===self::POS_READY || $position===self::POS_LOAD)
 | |
| 			$this->registerCoreScript('jquery');
 | |
| 		$params=func_get_args();
 | |
| 		$this->recordCachingAction('clientScript','registerScript',$params);
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function registerMetaTag($content,$name=null,$httpEquiv=null,$options=array(),$id=null)
 | |
| 	{
 | |
| 		$this->hasScripts=true;
 | |
| 		if($name!==null)
 | |
| 			$options['name']=$name;
 | |
| 		if($httpEquiv!==null)
 | |
| 			$options['http-equiv']=$httpEquiv;
 | |
| 		$options['content']=$content;
 | |
| 		$this->metaTags[null===$id?count($this->metaTags):$id]=$options;
 | |
| 		$params=func_get_args();
 | |
| 		$this->recordCachingAction('clientScript','registerMetaTag',$params);
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function registerLinkTag($relation=null,$type=null,$href=null,$media=null,$options=array())
 | |
| 	{
 | |
| 		$this->hasScripts=true;
 | |
| 		if($relation!==null)
 | |
| 			$options['rel']=$relation;
 | |
| 		if($type!==null)
 | |
| 			$options['type']=$type;
 | |
| 		if($href!==null)
 | |
| 			$options['href']=$href;
 | |
| 		if($media!==null)
 | |
| 			$options['media']=$media;
 | |
| 		$this->linkTags[serialize($options)]=$options;
 | |
| 		$params=func_get_args();
 | |
| 		$this->recordCachingAction('clientScript','registerLinkTag',$params);
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function isCssFileRegistered($url)
 | |
| 	{
 | |
| 		return isset($this->cssFiles[$url]);
 | |
| 	}
 | |
| 	public function isCssRegistered($id)
 | |
| 	{
 | |
| 		return isset($this->css[$id]);
 | |
| 	}
 | |
| 	public function isScriptFileRegistered($url,$position=self::POS_HEAD)
 | |
| 	{
 | |
| 		return isset($this->scriptFiles[$position][$url]);
 | |
| 	}
 | |
| 	public function isScriptRegistered($id,$position=self::POS_READY)
 | |
| 	{
 | |
| 		return isset($this->scripts[$position][$id]);
 | |
| 	}
 | |
| 	protected function recordCachingAction($context,$method,$params)
 | |
| 	{
 | |
| 		if(($controller=Yii::app()->getController())!==null)
 | |
| 			$controller->recordCachingAction($context,$method,$params);
 | |
| 	}
 | |
| 	public function addPackage($name,$definition)
 | |
| 	{
 | |
| 		$this->packages[$name]=$definition;
 | |
| 		return $this;
 | |
| 	}
 | |
| }
 | |
| class CList extends CComponent implements IteratorAggregate,ArrayAccess,Countable
 | |
| {
 | |
| 	private $_d=array();
 | |
| 	private $_c=0;
 | |
| 	private $_r=false;
 | |
| 	public function __construct($data=null,$readOnly=false)
 | |
| 	{
 | |
| 		if($data!==null)
 | |
| 			$this->copyFrom($data);
 | |
| 		$this->setReadOnly($readOnly);
 | |
| 	}
 | |
| 	public function getReadOnly()
 | |
| 	{
 | |
| 		return $this->_r;
 | |
| 	}
 | |
| 	protected function setReadOnly($value)
 | |
| 	{
 | |
| 		$this->_r=$value;
 | |
| 	}
 | |
| 	public function getIterator()
 | |
| 	{
 | |
| 		return new CListIterator($this->_d);
 | |
| 	}
 | |
| 	public function count()
 | |
| 	{
 | |
| 		return $this->getCount();
 | |
| 	}
 | |
| 	public function getCount()
 | |
| 	{
 | |
| 		return $this->_c;
 | |
| 	}
 | |
| 	public function itemAt($index)
 | |
| 	{
 | |
| 		if(isset($this->_d[$index]))
 | |
| 			return $this->_d[$index];
 | |
| 		elseif($index>=0 && $index<$this->_c) // in case the value is null
 | |
| 			return $this->_d[$index];
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','List index "{index}" is out of bound.',
 | |
| 				array('{index}'=>$index)));
 | |
| 	}
 | |
| 	public function add($item)
 | |
| 	{
 | |
| 		$this->insertAt($this->_c,$item);
 | |
| 		return $this->_c-1;
 | |
| 	}
 | |
| 	public function insertAt($index,$item)
 | |
| 	{
 | |
| 		if(!$this->_r)
 | |
| 		{
 | |
| 			if($index===$this->_c)
 | |
| 				$this->_d[$this->_c++]=$item;
 | |
| 			elseif($index>=0 && $index<$this->_c)
 | |
| 			{
 | |
| 				array_splice($this->_d,$index,0,array($item));
 | |
| 				$this->_c++;
 | |
| 			}
 | |
| 			else
 | |
| 				throw new CException(Yii::t('yii','List index "{index}" is out of bound.',
 | |
| 					array('{index}'=>$index)));
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','The list is read only.'));
 | |
| 	}
 | |
| 	public function remove($item)
 | |
| 	{
 | |
| 		if(($index=$this->indexOf($item))>=0)
 | |
| 		{
 | |
| 			$this->removeAt($index);
 | |
| 			return $index;
 | |
| 		}
 | |
| 		else
 | |
| 			return false;
 | |
| 	}
 | |
| 	public function removeAt($index)
 | |
| 	{
 | |
| 		if(!$this->_r)
 | |
| 		{
 | |
| 			if($index>=0 && $index<$this->_c)
 | |
| 			{
 | |
| 				$this->_c--;
 | |
| 				if($index===$this->_c)
 | |
| 					return array_pop($this->_d);
 | |
| 				else
 | |
| 				{
 | |
| 					$item=$this->_d[$index];
 | |
| 					array_splice($this->_d,$index,1);
 | |
| 					return $item;
 | |
| 				}
 | |
| 			}
 | |
| 			else
 | |
| 				throw new CException(Yii::t('yii','List index "{index}" is out of bound.',
 | |
| 					array('{index}'=>$index)));
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','The list is read only.'));
 | |
| 	}
 | |
| 	public function clear()
 | |
| 	{
 | |
| 		for($i=$this->_c-1;$i>=0;--$i)
 | |
| 			$this->removeAt($i);
 | |
| 	}
 | |
| 	public function contains($item)
 | |
| 	{
 | |
| 		return $this->indexOf($item)>=0;
 | |
| 	}
 | |
| 	public function indexOf($item)
 | |
| 	{
 | |
| 		if(($index=array_search($item,$this->_d,true))!==false)
 | |
| 			return $index;
 | |
| 		else
 | |
| 			return -1;
 | |
| 	}
 | |
| 	public function toArray()
 | |
| 	{
 | |
| 		return $this->_d;
 | |
| 	}
 | |
| 	public function copyFrom($data)
 | |
| 	{
 | |
| 		if(is_array($data) || ($data instanceof Traversable))
 | |
| 		{
 | |
| 			if($this->_c>0)
 | |
| 				$this->clear();
 | |
| 			if($data instanceof CList)
 | |
| 				$data=$data->_d;
 | |
| 			foreach($data as $item)
 | |
| 				$this->add($item);
 | |
| 		}
 | |
| 		elseif($data!==null)
 | |
| 			throw new CException(Yii::t('yii','List data must be an array or an object implementing Traversable.'));
 | |
| 	}
 | |
| 	public function mergeWith($data)
 | |
| 	{
 | |
| 		if(is_array($data) || ($data instanceof Traversable))
 | |
| 		{
 | |
| 			if($data instanceof CList)
 | |
| 				$data=$data->_d;
 | |
| 			foreach($data as $item)
 | |
| 				$this->add($item);
 | |
| 		}
 | |
| 		elseif($data!==null)
 | |
| 			throw new CException(Yii::t('yii','List data must be an array or an object implementing Traversable.'));
 | |
| 	}
 | |
| 	public function offsetExists($offset)
 | |
| 	{
 | |
| 		return ($offset>=0 && $offset<$this->_c);
 | |
| 	}
 | |
| 	public function offsetGet($offset)
 | |
| 	{
 | |
| 		return $this->itemAt($offset);
 | |
| 	}
 | |
| 	public function offsetSet($offset,$item)
 | |
| 	{
 | |
| 		if($offset===null || $offset===$this->_c)
 | |
| 			$this->insertAt($this->_c,$item);
 | |
| 		else
 | |
| 		{
 | |
| 			$this->removeAt($offset);
 | |
| 			$this->insertAt($offset,$item);
 | |
| 		}
 | |
| 	}
 | |
| 	public function offsetUnset($offset)
 | |
| 	{
 | |
| 		$this->removeAt($offset);
 | |
| 	}
 | |
| }
 | |
| class CFilterChain extends CList
 | |
| {
 | |
| 	public $controller;
 | |
| 	public $action;
 | |
| 	public $filterIndex=0;
 | |
| 	public function __construct($controller,$action)
 | |
| 	{
 | |
| 		$this->controller=$controller;
 | |
| 		$this->action=$action;
 | |
| 	}
 | |
| 	public static function create($controller,$action,$filters)
 | |
| 	{
 | |
| 		$chain=new CFilterChain($controller,$action);
 | |
| 		$actionID=$action->getId();
 | |
| 		foreach($filters as $filter)
 | |
| 		{
 | |
| 			if(is_string($filter))  // filterName [+|- action1 action2]
 | |
| 			{
 | |
| 				if(($pos=strpos($filter,'+'))!==false || ($pos=strpos($filter,'-'))!==false)
 | |
| 				{
 | |
| 					$matched=preg_match("/\b{$actionID}\b/i",substr($filter,$pos+1))>0;
 | |
| 					if(($filter[$pos]==='+')===$matched)
 | |
| 						$filter=CInlineFilter::create($controller,trim(substr($filter,0,$pos)));
 | |
| 				}
 | |
| 				else
 | |
| 					$filter=CInlineFilter::create($controller,$filter);
 | |
| 			}
 | |
| 			elseif(is_array($filter))  // array('path.to.class [+|- action1, action2]','param1'=>'value1',...)
 | |
| 			{
 | |
| 				if(!isset($filter[0]))
 | |
| 					throw new CException(Yii::t('yii','The first element in a filter configuration must be the filter class.'));
 | |
| 				$filterClass=$filter[0];
 | |
| 				unset($filter[0]);
 | |
| 				if(($pos=strpos($filterClass,'+'))!==false || ($pos=strpos($filterClass,'-'))!==false)
 | |
| 				{
 | |
| 					$matched=preg_match("/\b{$actionID}\b/i",substr($filterClass,$pos+1))>0;
 | |
| 					if(($filterClass[$pos]==='+')===$matched)
 | |
| 						$filterClass=trim(substr($filterClass,0,$pos));
 | |
| 					else
 | |
| 						continue;
 | |
| 				}
 | |
| 				$filter['class']=$filterClass;
 | |
| 				$filter=Yii::createComponent($filter);
 | |
| 			}
 | |
| 			if(is_object($filter))
 | |
| 			{
 | |
| 				$filter->init();
 | |
| 				$chain->add($filter);
 | |
| 			}
 | |
| 		}
 | |
| 		return $chain;
 | |
| 	}
 | |
| 	public function insertAt($index,$item)
 | |
| 	{
 | |
| 		if($item instanceof IFilter)
 | |
| 			parent::insertAt($index,$item);
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','CFilterChain can only take objects implementing the IFilter interface.'));
 | |
| 	}
 | |
| 	public function run()
 | |
| 	{
 | |
| 		if($this->offsetExists($this->filterIndex))
 | |
| 		{
 | |
| 			$filter=$this->itemAt($this->filterIndex++);
 | |
| 			$filter->filter($this);
 | |
| 		}
 | |
| 		else
 | |
| 			$this->controller->runAction($this->action);
 | |
| 	}
 | |
| }
 | |
| class CFilter extends CComponent implements IFilter
 | |
| {
 | |
| 	public function filter($filterChain)
 | |
| 	{
 | |
| 		if($this->preFilter($filterChain))
 | |
| 		{
 | |
| 			$filterChain->run();
 | |
| 			$this->postFilter($filterChain);
 | |
| 		}
 | |
| 	}
 | |
| 	public function init()
 | |
| 	{
 | |
| 	}
 | |
| 	protected function preFilter($filterChain)
 | |
| 	{
 | |
| 		return true;
 | |
| 	}
 | |
| 	protected function postFilter($filterChain)
 | |
| 	{
 | |
| 	}
 | |
| }
 | |
| class CInlineFilter extends CFilter
 | |
| {
 | |
| 	public $name;
 | |
| 	public static function create($controller,$filterName)
 | |
| 	{
 | |
| 		if(method_exists($controller,'filter'.$filterName))
 | |
| 		{
 | |
| 			$filter=new CInlineFilter;
 | |
| 			$filter->name=$filterName;
 | |
| 			return $filter;
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CException(Yii::t('yii','Filter "{filter}" is invalid. Controller "{class}" does not have the filter method "filter{filter}".',
 | |
| 				array('{filter}'=>$filterName, '{class}'=>get_class($controller))));
 | |
| 	}
 | |
| 	public function filter($filterChain)
 | |
| 	{
 | |
| 		$method='filter'.$this->name;
 | |
| 		$filterChain->controller->$method($filterChain);
 | |
| 	}
 | |
| }
 | |
| class CAccessControlFilter extends CFilter
 | |
| {
 | |
| 	public $message;
 | |
| 	private $_rules=array();
 | |
| 	public function getRules()
 | |
| 	{
 | |
| 		return $this->_rules;
 | |
| 	}
 | |
| 	public function setRules($rules)
 | |
| 	{
 | |
| 		foreach($rules as $rule)
 | |
| 		{
 | |
| 			if(is_array($rule) && isset($rule[0]))
 | |
| 			{
 | |
| 				$r=new CAccessRule;
 | |
| 				$r->allow=$rule[0]==='allow';
 | |
| 				foreach(array_slice($rule,1) as $name=>$value)
 | |
| 				{
 | |
| 					if($name==='expression' || $name==='roles' || $name==='message' || $name==='deniedCallback')
 | |
| 						$r->$name=$value;
 | |
| 					else
 | |
| 						$r->$name=array_map('strtolower',$value);
 | |
| 				}
 | |
| 				$this->_rules[]=$r;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	protected function preFilter($filterChain)
 | |
| 	{
 | |
| 		$app=Yii::app();
 | |
| 		$request=$app->getRequest();
 | |
| 		$user=$app->getUser();
 | |
| 		$verb=$request->getRequestType();
 | |
| 		$ip=$request->getUserHostAddress();
 | |
| 		foreach($this->getRules() as $rule)
 | |
| 		{
 | |
| 			if(($allow=$rule->isUserAllowed($user,$filterChain->controller,$filterChain->action,$ip,$verb))>0) // allowed
 | |
| 				break;
 | |
| 			elseif($allow<0) // denied
 | |
| 			{
 | |
| 				if(isset($rule->deniedCallback))
 | |
| 					call_user_func($rule->deniedCallback, $rule);
 | |
| 				else
 | |
| 					$this->accessDenied($user,$this->resolveErrorMessage($rule));
 | |
| 				return false;
 | |
| 			}
 | |
| 		}
 | |
| 		return true;
 | |
| 	}
 | |
| 	protected function resolveErrorMessage($rule)
 | |
| 	{
 | |
| 		if($rule->message!==null)
 | |
| 			return $rule->message;
 | |
| 		elseif($this->message!==null)
 | |
| 			return $this->message;
 | |
| 		else
 | |
| 			return Yii::t('yii','You are not authorized to perform this action.');
 | |
| 	}
 | |
| 	protected function accessDenied($user,$message)
 | |
| 	{
 | |
| 		if($user->getIsGuest())
 | |
| 			$user->loginRequired();
 | |
| 		else
 | |
| 			throw new CHttpException(403,$message);
 | |
| 	}
 | |
| }
 | |
| class CAccessRule extends CComponent
 | |
| {
 | |
| 	public $allow;
 | |
| 	public $actions;
 | |
| 	public $controllers;
 | |
| 	public $users;
 | |
| 	public $roles;
 | |
| 	public $ips;
 | |
| 	public $verbs;
 | |
| 	public $expression;
 | |
| 	public $message;
 | |
| 	public $deniedCallback;
 | |
| 	public function isUserAllowed($user,$controller,$action,$ip,$verb)
 | |
| 	{
 | |
| 		if($this->isActionMatched($action)
 | |
| 			&& $this->isUserMatched($user)
 | |
| 			&& $this->isRoleMatched($user)
 | |
| 			&& $this->isIpMatched($ip)
 | |
| 			&& $this->isVerbMatched($verb)
 | |
| 			&& $this->isControllerMatched($controller)
 | |
| 			&& $this->isExpressionMatched($user))
 | |
| 			return $this->allow ? 1 : -1;
 | |
| 		else
 | |
| 			return 0;
 | |
| 	}
 | |
| 	protected function isActionMatched($action)
 | |
| 	{
 | |
| 		return empty($this->actions) || in_array(strtolower($action->getId()),$this->actions);
 | |
| 	}
 | |
| 	protected function isControllerMatched($controller)
 | |
| 	{
 | |
| 		return empty($this->controllers) || in_array(strtolower($controller->getUniqueId()),$this->controllers);
 | |
| 	}
 | |
| 	protected function isUserMatched($user)
 | |
| 	{
 | |
| 		if(empty($this->users))
 | |
| 			return true;
 | |
| 		foreach($this->users as $u)
 | |
| 		{
 | |
| 			if($u==='*')
 | |
| 				return true;
 | |
| 			elseif($u==='?' && $user->getIsGuest())
 | |
| 				return true;
 | |
| 			elseif($u==='@' && !$user->getIsGuest())
 | |
| 				return true;
 | |
| 			elseif(!strcasecmp($u,$user->getName()))
 | |
| 				return true;
 | |
| 		}
 | |
| 		return false;
 | |
| 	}
 | |
| 	protected function isRoleMatched($user)
 | |
| 	{
 | |
| 		if(empty($this->roles))
 | |
| 			return true;
 | |
| 		foreach($this->roles as $key=>$role)
 | |
| 		{
 | |
| 			if(is_numeric($key))
 | |
| 			{
 | |
| 				if($user->checkAccess($role))
 | |
| 					return true;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				if($user->checkAccess($key,$role))
 | |
| 					return true;
 | |
| 			}
 | |
| 		}
 | |
| 		return false;
 | |
| 	}
 | |
| 	protected function isIpMatched($ip)
 | |
| 	{
 | |
| 		if(empty($this->ips))
 | |
| 			return true;
 | |
| 		foreach($this->ips as $rule)
 | |
| 		{
 | |
| 			if($rule==='*' || $rule===$ip || (($pos=strpos($rule,'*'))!==false && !strncmp($ip,$rule,$pos)))
 | |
| 				return true;
 | |
| 		}
 | |
| 		return false;
 | |
| 	}
 | |
| 	protected function isVerbMatched($verb)
 | |
| 	{
 | |
| 		return empty($this->verbs) || in_array(strtolower($verb),$this->verbs);
 | |
| 	}
 | |
| 	protected function isExpressionMatched($user)
 | |
| 	{
 | |
| 		if($this->expression===null)
 | |
| 			return true;
 | |
| 		else
 | |
| 			return $this->evaluateExpression($this->expression, array('user'=>$user));
 | |
| 	}
 | |
| }
 | |
| abstract class CModel extends CComponent implements IteratorAggregate, ArrayAccess
 | |
| {
 | |
| 	private $_errors=array();	// attribute name => array of errors
 | |
| 	private $_validators;  		// validators
 | |
| 	private $_scenario='';  	// scenario
 | |
| 	abstract public function attributeNames();
 | |
| 	public function rules()
 | |
| 	{
 | |
| 		return array();
 | |
| 	}
 | |
| 	public function behaviors()
 | |
| 	{
 | |
| 		return array();
 | |
| 	}
 | |
| 	public function attributeLabels()
 | |
| 	{
 | |
| 		return array();
 | |
| 	}
 | |
| 	public function validate($attributes=null, $clearErrors=true)
 | |
| 	{
 | |
| 		if($clearErrors)
 | |
| 			$this->clearErrors();
 | |
| 		if($this->beforeValidate())
 | |
| 		{
 | |
| 			foreach($this->getValidators() as $validator)
 | |
| 				$validator->validate($this,$attributes);
 | |
| 			$this->afterValidate();
 | |
| 			return !$this->hasErrors();
 | |
| 		}
 | |
| 		else
 | |
| 			return false;
 | |
| 	}
 | |
| 	protected function afterConstruct()
 | |
| 	{
 | |
| 		if($this->hasEventHandler('onAfterConstruct'))
 | |
| 			$this->onAfterConstruct(new CEvent($this));
 | |
| 	}
 | |
| 	protected function beforeValidate()
 | |
| 	{
 | |
| 		$event=new CModelEvent($this);
 | |
| 		$this->onBeforeValidate($event);
 | |
| 		return $event->isValid;
 | |
| 	}
 | |
| 	protected function afterValidate()
 | |
| 	{
 | |
| 		$this->onAfterValidate(new CEvent($this));
 | |
| 	}
 | |
| 	public function onAfterConstruct($event)
 | |
| 	{
 | |
| 		$this->raiseEvent('onAfterConstruct',$event);
 | |
| 	}
 | |
| 	public function onBeforeValidate($event)
 | |
| 	{
 | |
| 		$this->raiseEvent('onBeforeValidate',$event);
 | |
| 	}
 | |
| 	public function onAfterValidate($event)
 | |
| 	{
 | |
| 		$this->raiseEvent('onAfterValidate',$event);
 | |
| 	}
 | |
| 	public function getValidatorList()
 | |
| 	{
 | |
| 		if($this->_validators===null)
 | |
| 			$this->_validators=$this->createValidators();
 | |
| 		return $this->_validators;
 | |
| 	}
 | |
| 	public function getValidators($attribute=null)
 | |
| 	{
 | |
| 		if($this->_validators===null)
 | |
| 			$this->_validators=$this->createValidators();
 | |
| 		$validators=array();
 | |
| 		$scenario=$this->getScenario();
 | |
| 		foreach($this->_validators as $validator)
 | |
| 		{
 | |
| 			if($validator->applyTo($scenario))
 | |
| 			{
 | |
| 				if($attribute===null || in_array($attribute,$validator->attributes,true))
 | |
| 					$validators[]=$validator;
 | |
| 			}
 | |
| 		}
 | |
| 		return $validators;
 | |
| 	}
 | |
| 	public function createValidators()
 | |
| 	{
 | |
| 		$validators=new CList;
 | |
| 		foreach($this->rules() as $rule)
 | |
| 		{
 | |
| 			if(isset($rule[0],$rule[1]))  // attributes, validator name
 | |
| 				$validators->add(CValidator::createValidator($rule[1],$this,$rule[0],array_slice($rule,2)));
 | |
| 			else
 | |
| 				throw new CException(Yii::t('yii','{class} has an invalid validation rule. The rule must specify attributes to be validated and the validator name.',
 | |
| 					array('{class}'=>get_class($this))));
 | |
| 		}
 | |
| 		return $validators;
 | |
| 	}
 | |
| 	public function isAttributeRequired($attribute)
 | |
| 	{
 | |
| 		foreach($this->getValidators($attribute) as $validator)
 | |
| 		{
 | |
| 			if($validator instanceof CRequiredValidator)
 | |
| 				return true;
 | |
| 		}
 | |
| 		return false;
 | |
| 	}
 | |
| 	public function isAttributeSafe($attribute)
 | |
| 	{
 | |
| 		$attributes=$this->getSafeAttributeNames();
 | |
| 		return in_array($attribute,$attributes);
 | |
| 	}
 | |
| 	public function getAttributeLabel($attribute)
 | |
| 	{
 | |
| 		$labels=$this->attributeLabels();
 | |
| 		if(isset($labels[$attribute]))
 | |
| 			return $labels[$attribute];
 | |
| 		else
 | |
| 			return $this->generateAttributeLabel($attribute);
 | |
| 	}
 | |
| 	public function hasErrors($attribute=null)
 | |
| 	{
 | |
| 		if($attribute===null)
 | |
| 			return $this->_errors!==array();
 | |
| 		else
 | |
| 			return isset($this->_errors[$attribute]);
 | |
| 	}
 | |
| 	public function getErrors($attribute=null)
 | |
| 	{
 | |
| 		if($attribute===null)
 | |
| 			return $this->_errors;
 | |
| 		else
 | |
| 			return isset($this->_errors[$attribute]) ? $this->_errors[$attribute] : array();
 | |
| 	}
 | |
| 	public function getError($attribute)
 | |
| 	{
 | |
| 		return isset($this->_errors[$attribute]) ? reset($this->_errors[$attribute]) : null;
 | |
| 	}
 | |
| 	public function addError($attribute,$error)
 | |
| 	{
 | |
| 		$this->_errors[$attribute][]=$error;
 | |
| 	}
 | |
| 	public function addErrors($errors)
 | |
| 	{
 | |
| 		foreach($errors as $attribute=>$error)
 | |
| 		{
 | |
| 			if(is_array($error))
 | |
| 			{
 | |
| 				foreach($error as $e)
 | |
| 					$this->addError($attribute, $e);
 | |
| 			}
 | |
| 			else
 | |
| 				$this->addError($attribute, $error);
 | |
| 		}
 | |
| 	}
 | |
| 	public function clearErrors($attribute=null)
 | |
| 	{
 | |
| 		if($attribute===null)
 | |
| 			$this->_errors=array();
 | |
| 		else
 | |
| 			unset($this->_errors[$attribute]);
 | |
| 	}
 | |
| 	public function generateAttributeLabel($name)
 | |
| 	{
 | |
| 		return ucwords(trim(strtolower(str_replace(array('-','_','.'),' ',preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $name)))));
 | |
| 	}
 | |
| 	public function getAttributes($names=null)
 | |
| 	{
 | |
| 		$values=array();
 | |
| 		foreach($this->attributeNames() as $name)
 | |
| 			$values[$name]=$this->$name;
 | |
| 		if(is_array($names))
 | |
| 		{
 | |
| 			$values2=array();
 | |
| 			foreach($names as $name)
 | |
| 				$values2[$name]=isset($values[$name]) ? $values[$name] : null;
 | |
| 			return $values2;
 | |
| 		}
 | |
| 		else
 | |
| 			return $values;
 | |
| 	}
 | |
| 	public function setAttributes($values,$safeOnly=true)
 | |
| 	{
 | |
| 		if(!is_array($values))
 | |
| 			return;
 | |
| 		$attributes=array_flip($safeOnly ? $this->getSafeAttributeNames() : $this->attributeNames());
 | |
| 		foreach($values as $name=>$value)
 | |
| 		{
 | |
| 			if(isset($attributes[$name]))
 | |
| 				$this->$name=$value;
 | |
| 			elseif($safeOnly)
 | |
| 				$this->onUnsafeAttribute($name,$value);
 | |
| 		}
 | |
| 	}
 | |
| 	public function unsetAttributes($names=null)
 | |
| 	{
 | |
| 		if($names===null)
 | |
| 			$names=$this->attributeNames();
 | |
| 		foreach($names as $name)
 | |
| 			$this->$name=null;
 | |
| 	}
 | |
| 	public function onUnsafeAttribute($name,$value)
 | |
| 	{
 | |
| 		if(YII_DEBUG)
 | |
| 			Yii::log(Yii::t('yii','Failed to set unsafe attribute "{attribute}" of "{class}".',array('{attribute}'=>$name, '{class}'=>get_class($this))),CLogger::LEVEL_WARNING);
 | |
| 	}
 | |
| 	public function getScenario()
 | |
| 	{
 | |
| 		return $this->_scenario;
 | |
| 	}
 | |
| 	public function setScenario($value)
 | |
| 	{
 | |
| 		$this->_scenario=$value;
 | |
| 	}
 | |
| 	public function getSafeAttributeNames()
 | |
| 	{
 | |
| 		$attributes=array();
 | |
| 		$unsafe=array();
 | |
| 		foreach($this->getValidators() as $validator)
 | |
| 		{
 | |
| 			if(!$validator->safe)
 | |
| 			{
 | |
| 				foreach($validator->attributes as $name)
 | |
| 					$unsafe[]=$name;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				foreach($validator->attributes as $name)
 | |
| 					$attributes[$name]=true;
 | |
| 			}
 | |
| 		}
 | |
| 		foreach($unsafe as $name)
 | |
| 			unset($attributes[$name]);
 | |
| 		return array_keys($attributes);
 | |
| 	}
 | |
| 	public function getIterator()
 | |
| 	{
 | |
| 		$attributes=$this->getAttributes();
 | |
| 		return new CMapIterator($attributes);
 | |
| 	}
 | |
| 	public function offsetExists($offset)
 | |
| 	{
 | |
| 		return property_exists($this,$offset);
 | |
| 	}
 | |
| 	public function offsetGet($offset)
 | |
| 	{
 | |
| 		return $this->$offset;
 | |
| 	}
 | |
| 	public function offsetSet($offset,$item)
 | |
| 	{
 | |
| 		$this->$offset=$item;
 | |
| 	}
 | |
| 	public function offsetUnset($offset)
 | |
| 	{
 | |
| 		unset($this->$offset);
 | |
| 	}
 | |
| }
 | |
| abstract class CActiveRecord extends CModel
 | |
| {
 | |
| 	const BELONGS_TO='CBelongsToRelation';
 | |
| 	const HAS_ONE='CHasOneRelation';
 | |
| 	const HAS_MANY='CHasManyRelation';
 | |
| 	const MANY_MANY='CManyManyRelation';
 | |
| 	const STAT='CStatRelation';
 | |
| 	public static $db;
 | |
| 	private static $_models=array();			// class name => model
 | |
| 	private static $_md=array();				// class name => meta data
 | |
| 	private $_new=false;						// whether this instance is new or not
 | |
| 	private $_attributes=array();				// attribute name => attribute value
 | |
| 	private $_related=array();					// attribute name => related objects
 | |
| 	private $_c;								// query criteria (used by finder only)
 | |
| 	private $_pk;								// old primary key value
 | |
| 	private $_alias='t';						// the table alias being used for query
 | |
| 	public function __construct($scenario='insert')
 | |
| 	{
 | |
| 		if($scenario===null) // internally used by populateRecord() and model()
 | |
| 			return;
 | |
| 		$this->setScenario($scenario);
 | |
| 		$this->setIsNewRecord(true);
 | |
| 		$this->_attributes=$this->getMetaData()->attributeDefaults;
 | |
| 		$this->init();
 | |
| 		$this->attachBehaviors($this->behaviors());
 | |
| 		$this->afterConstruct();
 | |
| 	}
 | |
| 	public function init()
 | |
| 	{
 | |
| 	}
 | |
| 	public function cache($duration, $dependency=null, $queryCount=1)
 | |
| 	{
 | |
| 		$this->getDbConnection()->cache($duration, $dependency, $queryCount);
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function __sleep()
 | |
| 	{
 | |
| 		return array_keys((array)$this);
 | |
| 	}
 | |
| 	public function __get($name)
 | |
| 	{
 | |
| 		if(isset($this->_attributes[$name]))
 | |
| 			return $this->_attributes[$name];
 | |
| 		elseif(isset($this->getMetaData()->columns[$name]))
 | |
| 			return null;
 | |
| 		elseif(isset($this->_related[$name]))
 | |
| 			return $this->_related[$name];
 | |
| 		elseif(isset($this->getMetaData()->relations[$name]))
 | |
| 			return $this->getRelated($name);
 | |
| 		else
 | |
| 			return parent::__get($name);
 | |
| 	}
 | |
| 	public function __set($name,$value)
 | |
| 	{
 | |
| 		if($this->setAttribute($name,$value)===false)
 | |
| 		{
 | |
| 			if(isset($this->getMetaData()->relations[$name]))
 | |
| 				$this->_related[$name]=$value;
 | |
| 			else
 | |
| 				parent::__set($name,$value);
 | |
| 		}
 | |
| 	}
 | |
| 	public function __isset($name)
 | |
| 	{
 | |
| 		if(isset($this->_attributes[$name]))
 | |
| 			return true;
 | |
| 		elseif(isset($this->getMetaData()->columns[$name]))
 | |
| 			return false;
 | |
| 		elseif(isset($this->_related[$name]))
 | |
| 			return true;
 | |
| 		elseif(isset($this->getMetaData()->relations[$name]))
 | |
| 			return $this->getRelated($name)!==null;
 | |
| 		else
 | |
| 			return parent::__isset($name);
 | |
| 	}
 | |
| 	public function __unset($name)
 | |
| 	{
 | |
| 		if(isset($this->getMetaData()->columns[$name]))
 | |
| 			unset($this->_attributes[$name]);
 | |
| 		elseif(isset($this->getMetaData()->relations[$name]))
 | |
| 			unset($this->_related[$name]);
 | |
| 		else
 | |
| 			parent::__unset($name);
 | |
| 	}
 | |
| 	public function __call($name,$parameters)
 | |
| 	{
 | |
| 		if(isset($this->getMetaData()->relations[$name]))
 | |
| 		{
 | |
| 			if(empty($parameters))
 | |
| 				return $this->getRelated($name,false);
 | |
| 			else
 | |
| 				return $this->getRelated($name,false,$parameters[0]);
 | |
| 		}
 | |
| 		$scopes=$this->scopes();
 | |
| 		if(isset($scopes[$name]))
 | |
| 		{
 | |
| 			$this->getDbCriteria()->mergeWith($scopes[$name]);
 | |
| 			return $this;
 | |
| 		}
 | |
| 		return parent::__call($name,$parameters);
 | |
| 	}
 | |
| 	public function getRelated($name,$refresh=false,$params=array())
 | |
| 	{
 | |
| 		if(!$refresh && $params===array() && (isset($this->_related[$name]) || array_key_exists($name,$this->_related)))
 | |
| 			return $this->_related[$name];
 | |
| 		$md=$this->getMetaData();
 | |
| 		if(!isset($md->relations[$name]))
 | |
| 			throw new CDbException(Yii::t('yii','{class} does not have relation "{name}".',
 | |
| 				array('{class}'=>get_class($this), '{name}'=>$name)));
 | |
| 		$relation=$md->relations[$name];
 | |
| 		if($this->getIsNewRecord() && !$refresh && ($relation instanceof CHasOneRelation || $relation instanceof CHasManyRelation))
 | |
| 			return $relation instanceof CHasOneRelation ? null : array();
 | |
| 		if($params!==array()) // dynamic query
 | |
| 		{
 | |
| 			$exists=isset($this->_related[$name]) || array_key_exists($name,$this->_related);
 | |
| 			if($exists)
 | |
| 				$save=$this->_related[$name];
 | |
| 			if($params instanceof CDbCriteria)
 | |
| 				$params = $params->toArray();
 | |
| 			$r=array($name=>$params);
 | |
| 		}
 | |
| 		else
 | |
| 			$r=$name;
 | |
| 		unset($this->_related[$name]);
 | |
| 		$finder=$this->getActiveFinder($r);
 | |
| 		$finder->lazyFind($this);
 | |
| 		if(!isset($this->_related[$name]))
 | |
| 		{
 | |
| 			if($relation instanceof CHasManyRelation)
 | |
| 				$this->_related[$name]=array();
 | |
| 			elseif($relation instanceof CStatRelation)
 | |
| 				$this->_related[$name]=$relation->defaultValue;
 | |
| 			else
 | |
| 				$this->_related[$name]=null;
 | |
| 		}
 | |
| 		if($params!==array())
 | |
| 		{
 | |
| 			$results=$this->_related[$name];
 | |
| 			if($exists)
 | |
| 				$this->_related[$name]=$save;
 | |
| 			else
 | |
| 				unset($this->_related[$name]);
 | |
| 			return $results;
 | |
| 		}
 | |
| 		else
 | |
| 			return $this->_related[$name];
 | |
| 	}
 | |
| 	public function hasRelated($name)
 | |
| 	{
 | |
| 		return isset($this->_related[$name]) || array_key_exists($name,$this->_related);
 | |
| 	}
 | |
| 	public function getDbCriteria($createIfNull=true)
 | |
| 	{
 | |
| 		if($this->_c===null)
 | |
| 		{
 | |
| 			if(($c=$this->defaultScope())!==array() || $createIfNull)
 | |
| 				$this->_c=new CDbCriteria($c);
 | |
| 		}
 | |
| 		return $this->_c;
 | |
| 	}
 | |
| 	public function setDbCriteria($criteria)
 | |
| 	{
 | |
| 		$this->_c=$criteria;
 | |
| 	}
 | |
| 	public function defaultScope()
 | |
| 	{
 | |
| 		return array();
 | |
| 	}
 | |
| 	public function resetScope($resetDefault=true)
 | |
| 	{
 | |
| 		if($resetDefault)
 | |
| 			$this->_c=new CDbCriteria();
 | |
| 		else
 | |
| 			$this->_c=null;
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public static function model($className=__CLASS__)
 | |
| 	{
 | |
| 		if(isset(self::$_models[$className]))
 | |
| 			return self::$_models[$className];
 | |
| 		else
 | |
| 		{
 | |
| 			$model=self::$_models[$className]=new $className(null);
 | |
| 			$model->attachBehaviors($model->behaviors());
 | |
| 			return $model;
 | |
| 		}
 | |
| 	}
 | |
| 	public function getMetaData()
 | |
| 	{
 | |
| 		$className=get_class($this);
 | |
| 		if(!array_key_exists($className,self::$_md))
 | |
| 		{
 | |
| 			self::$_md[$className]=null; // preventing recursive invokes of {@link getMetaData()} via {@link __get()}
 | |
| 			self::$_md[$className]=new CActiveRecordMetaData($this);
 | |
| 		}
 | |
| 		return self::$_md[$className];
 | |
| 	}
 | |
| 	public function refreshMetaData()
 | |
| 	{
 | |
| 		$className=get_class($this);
 | |
| 		if(array_key_exists($className,self::$_md))
 | |
| 			unset(self::$_md[$className]);
 | |
| 	}
 | |
| 	public function tableName()
 | |
| 	{
 | |
| 		return get_class($this);
 | |
| 	}
 | |
| 	public function primaryKey()
 | |
| 	{
 | |
| 	}
 | |
| 	public function relations()
 | |
| 	{
 | |
| 		return array();
 | |
| 	}
 | |
| 	public function scopes()
 | |
| 	{
 | |
| 		return array();
 | |
| 	}
 | |
| 	public function attributeNames()
 | |
| 	{
 | |
| 		return array_keys($this->getMetaData()->columns);
 | |
| 	}
 | |
| 	public function getAttributeLabel($attribute)
 | |
| 	{
 | |
| 		$labels=$this->attributeLabels();
 | |
| 		if(isset($labels[$attribute]))
 | |
| 			return $labels[$attribute];
 | |
| 		elseif(strpos($attribute,'.')!==false)
 | |
| 		{
 | |
| 			$segs=explode('.',$attribute);
 | |
| 			$name=array_pop($segs);
 | |
| 			$model=$this;
 | |
| 			foreach($segs as $seg)
 | |
| 			{
 | |
| 				$relations=$model->getMetaData()->relations;
 | |
| 				if(isset($relations[$seg]))
 | |
| 					$model=CActiveRecord::model($relations[$seg]->className);
 | |
| 				else
 | |
| 					break;
 | |
| 			}
 | |
| 			return $model->getAttributeLabel($name);
 | |
| 		}
 | |
| 		else
 | |
| 			return $this->generateAttributeLabel($attribute);
 | |
| 	}
 | |
| 	public function getDbConnection()
 | |
| 	{
 | |
| 		if(self::$db!==null)
 | |
| 			return self::$db;
 | |
| 		else
 | |
| 		{
 | |
| 			self::$db=Yii::app()->getDb();
 | |
| 			if(self::$db instanceof CDbConnection)
 | |
| 				return self::$db;
 | |
| 			else
 | |
| 				throw new CDbException(Yii::t('yii','Active Record requires a "db" CDbConnection application component.'));
 | |
| 		}
 | |
| 	}
 | |
| 	public function getActiveRelation($name)
 | |
| 	{
 | |
| 		return isset($this->getMetaData()->relations[$name]) ? $this->getMetaData()->relations[$name] : null;
 | |
| 	}
 | |
| 	public function getTableSchema()
 | |
| 	{
 | |
| 		return $this->getMetaData()->tableSchema;
 | |
| 	}
 | |
| 	public function getCommandBuilder()
 | |
| 	{
 | |
| 		return $this->getDbConnection()->getSchema()->getCommandBuilder();
 | |
| 	}
 | |
| 	public function hasAttribute($name)
 | |
| 	{
 | |
| 		return isset($this->getMetaData()->columns[$name]);
 | |
| 	}
 | |
| 	public function getAttribute($name)
 | |
| 	{
 | |
| 		if(property_exists($this,$name))
 | |
| 			return $this->$name;
 | |
| 		elseif(isset($this->_attributes[$name]))
 | |
| 			return $this->_attributes[$name];
 | |
| 	}
 | |
| 	public function setAttribute($name,$value)
 | |
| 	{
 | |
| 		if(property_exists($this,$name))
 | |
| 			$this->$name=$value;
 | |
| 		elseif(isset($this->getMetaData()->columns[$name]))
 | |
| 			$this->_attributes[$name]=$value;
 | |
| 		else
 | |
| 			return false;
 | |
| 		return true;
 | |
| 	}
 | |
| 	public function addRelatedRecord($name,$record,$index)
 | |
| 	{
 | |
| 		if($index!==false)
 | |
| 		{
 | |
| 			if(!isset($this->_related[$name]))
 | |
| 				$this->_related[$name]=array();
 | |
| 			if($record instanceof CActiveRecord)
 | |
| 			{
 | |
| 				if($index===true)
 | |
| 					$this->_related[$name][]=$record;
 | |
| 				else
 | |
| 					$this->_related[$name][$index]=$record;
 | |
| 			}
 | |
| 		}
 | |
| 		elseif(!isset($this->_related[$name]))
 | |
| 			$this->_related[$name]=$record;
 | |
| 	}
 | |
| 	public function getAttributes($names=true)
 | |
| 	{
 | |
| 		$attributes=$this->_attributes;
 | |
| 		foreach($this->getMetaData()->columns as $name=>$column)
 | |
| 		{
 | |
| 			if(property_exists($this,$name))
 | |
| 				$attributes[$name]=$this->$name;
 | |
| 			elseif($names===true && !isset($attributes[$name]))
 | |
| 				$attributes[$name]=null;
 | |
| 		}
 | |
| 		if(is_array($names))
 | |
| 		{
 | |
| 			$attrs=array();
 | |
| 			foreach($names as $name)
 | |
| 			{
 | |
| 				if(property_exists($this,$name))
 | |
| 					$attrs[$name]=$this->$name;
 | |
| 				else
 | |
| 					$attrs[$name]=isset($attributes[$name])?$attributes[$name]:null;
 | |
| 			}
 | |
| 			return $attrs;
 | |
| 		}
 | |
| 		else
 | |
| 			return $attributes;
 | |
| 	}
 | |
| 	public function save($runValidation=true,$attributes=null)
 | |
| 	{
 | |
| 		if(!$runValidation || $this->validate($attributes))
 | |
| 			return $this->getIsNewRecord() ? $this->insert($attributes) : $this->update($attributes);
 | |
| 		else
 | |
| 			return false;
 | |
| 	}
 | |
| 	public function getIsNewRecord()
 | |
| 	{
 | |
| 		return $this->_new;
 | |
| 	}
 | |
| 	public function setIsNewRecord($value)
 | |
| 	{
 | |
| 		$this->_new=$value;
 | |
| 	}
 | |
| 	public function onBeforeSave($event)
 | |
| 	{
 | |
| 		$this->raiseEvent('onBeforeSave',$event);
 | |
| 	}
 | |
| 	public function onAfterSave($event)
 | |
| 	{
 | |
| 		$this->raiseEvent('onAfterSave',$event);
 | |
| 	}
 | |
| 	public function onBeforeDelete($event)
 | |
| 	{
 | |
| 		$this->raiseEvent('onBeforeDelete',$event);
 | |
| 	}
 | |
| 	public function onAfterDelete($event)
 | |
| 	{
 | |
| 		$this->raiseEvent('onAfterDelete',$event);
 | |
| 	}
 | |
| 	public function onBeforeFind($event)
 | |
| 	{
 | |
| 		$this->raiseEvent('onBeforeFind',$event);
 | |
| 	}
 | |
| 	public function onAfterFind($event)
 | |
| 	{
 | |
| 		$this->raiseEvent('onAfterFind',$event);
 | |
| 	}
 | |
| 	public function getActiveFinder($with)
 | |
| 	{
 | |
| 		return new CActiveFinder($this,$with);
 | |
| 	}
 | |
| 	public function onBeforeCount($event)
 | |
| 	{
 | |
| 		$this->raiseEvent('onBeforeCount',$event);
 | |
| 	}
 | |
| 	protected function beforeSave()
 | |
| 	{
 | |
| 		if($this->hasEventHandler('onBeforeSave'))
 | |
| 		{
 | |
| 			$event=new CModelEvent($this);
 | |
| 			$this->onBeforeSave($event);
 | |
| 			return $event->isValid;
 | |
| 		}
 | |
| 		else
 | |
| 			return true;
 | |
| 	}
 | |
| 	protected function afterSave()
 | |
| 	{
 | |
| 		if($this->hasEventHandler('onAfterSave'))
 | |
| 			$this->onAfterSave(new CEvent($this));
 | |
| 	}
 | |
| 	protected function beforeDelete()
 | |
| 	{
 | |
| 		if($this->hasEventHandler('onBeforeDelete'))
 | |
| 		{
 | |
| 			$event=new CModelEvent($this);
 | |
| 			$this->onBeforeDelete($event);
 | |
| 			return $event->isValid;
 | |
| 		}
 | |
| 		else
 | |
| 			return true;
 | |
| 	}
 | |
| 	protected function afterDelete()
 | |
| 	{
 | |
| 		if($this->hasEventHandler('onAfterDelete'))
 | |
| 			$this->onAfterDelete(new CEvent($this));
 | |
| 	}
 | |
| 	protected function beforeFind()
 | |
| 	{
 | |
| 		if($this->hasEventHandler('onBeforeFind'))
 | |
| 		{
 | |
| 			$event=new CModelEvent($this);
 | |
| 			$this->onBeforeFind($event);
 | |
| 		}
 | |
| 	}
 | |
| 	protected function beforeCount()
 | |
| 	{
 | |
| 		if($this->hasEventHandler('onBeforeCount'))
 | |
| 			$this->onBeforeCount(new CEvent($this));
 | |
| 	}
 | |
| 	protected function afterFind()
 | |
| 	{
 | |
| 		if($this->hasEventHandler('onAfterFind'))
 | |
| 			$this->onAfterFind(new CEvent($this));
 | |
| 	}
 | |
| 	public function beforeFindInternal()
 | |
| 	{
 | |
| 		$this->beforeFind();
 | |
| 	}
 | |
| 	public function afterFindInternal()
 | |
| 	{
 | |
| 		$this->afterFind();
 | |
| 	}
 | |
| 	public function insert($attributes=null)
 | |
| 	{
 | |
| 		if(!$this->getIsNewRecord())
 | |
| 			throw new CDbException(Yii::t('yii','The active record cannot be inserted to database because it is not new.'));
 | |
| 		if($this->beforeSave())
 | |
| 		{
 | |
| 			$builder=$this->getCommandBuilder();
 | |
| 			$table=$this->getMetaData()->tableSchema;
 | |
| 			$command=$builder->createInsertCommand($table,$this->getAttributes($attributes));
 | |
| 			if($command->execute())
 | |
| 			{
 | |
| 				$primaryKey=$table->primaryKey;
 | |
| 				if($table->sequenceName!==null)
 | |
| 				{
 | |
| 					if(is_string($primaryKey) && $this->$primaryKey===null)
 | |
| 						$this->$primaryKey=$builder->getLastInsertID($table);
 | |
| 					elseif(is_array($primaryKey))
 | |
| 					{
 | |
| 						foreach($primaryKey as $pk)
 | |
| 						{
 | |
| 							if($this->$pk===null)
 | |
| 							{
 | |
| 								$this->$pk=$builder->getLastInsertID($table);
 | |
| 								break;
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				$this->_pk=$this->getPrimaryKey();
 | |
| 				$this->afterSave();
 | |
| 				$this->setIsNewRecord(false);
 | |
| 				$this->setScenario('update');
 | |
| 				return true;
 | |
| 			}
 | |
| 		}
 | |
| 		return false;
 | |
| 	}
 | |
| 	public function update($attributes=null)
 | |
| 	{
 | |
| 		if($this->getIsNewRecord())
 | |
| 			throw new CDbException(Yii::t('yii','The active record cannot be updated because it is new.'));
 | |
| 		if($this->beforeSave())
 | |
| 		{
 | |
| 			if($this->_pk===null)
 | |
| 				$this->_pk=$this->getPrimaryKey();
 | |
| 			$this->updateByPk($this->getOldPrimaryKey(),$this->getAttributes($attributes));
 | |
| 			$this->_pk=$this->getPrimaryKey();
 | |
| 			$this->afterSave();
 | |
| 			return true;
 | |
| 		}
 | |
| 		else
 | |
| 			return false;
 | |
| 	}
 | |
| 	public function saveAttributes($attributes)
 | |
| 	{
 | |
| 		if(!$this->getIsNewRecord())
 | |
| 		{
 | |
| 			$values=array();
 | |
| 			foreach($attributes as $name=>$value)
 | |
| 			{
 | |
| 				if(is_integer($name))
 | |
| 					$values[$value]=$this->$value;
 | |
| 				else
 | |
| 					$values[$name]=$this->$name=$value;
 | |
| 			}
 | |
| 			if($this->_pk===null)
 | |
| 				$this->_pk=$this->getPrimaryKey();
 | |
| 			if($this->updateByPk($this->getOldPrimaryKey(),$values)>0)
 | |
| 			{
 | |
| 				$this->_pk=$this->getPrimaryKey();
 | |
| 				return true;
 | |
| 			}
 | |
| 			else
 | |
| 				return false;
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CDbException(Yii::t('yii','The active record cannot be updated because it is new.'));
 | |
| 	}
 | |
| 	public function saveCounters($counters)
 | |
| 	{
 | |
| 		$builder=$this->getCommandBuilder();
 | |
| 		$table=$this->getTableSchema();
 | |
| 		$criteria=$builder->createPkCriteria($table,$this->getOldPrimaryKey());
 | |
| 		$command=$builder->createUpdateCounterCommand($this->getTableSchema(),$counters,$criteria);
 | |
| 		if($command->execute())
 | |
| 		{
 | |
| 			foreach($counters as $name=>$value)
 | |
| 				$this->$name=$this->$name+$value;
 | |
| 			return true;
 | |
| 		}
 | |
| 		else
 | |
| 			return false;
 | |
| 	}
 | |
| 	public function delete()
 | |
| 	{
 | |
| 		if(!$this->getIsNewRecord())
 | |
| 		{
 | |
| 			if($this->beforeDelete())
 | |
| 			{
 | |
| 				$result=$this->deleteByPk($this->getPrimaryKey())>0;
 | |
| 				$this->afterDelete();
 | |
| 				return $result;
 | |
| 			}
 | |
| 			else
 | |
| 				return false;
 | |
| 		}
 | |
| 		else
 | |
| 			throw new CDbException(Yii::t('yii','The active record cannot be deleted because it is new.'));
 | |
| 	}
 | |
| 	public function refresh()
 | |
| 	{
 | |
| 		if(($record=$this->findByPk($this->getPrimaryKey()))!==null)
 | |
| 		{
 | |
| 			$this->_attributes=array();
 | |
| 			$this->_related=array();
 | |
| 			foreach($this->getMetaData()->columns as $name=>$column)
 | |
| 			{
 | |
| 				if(property_exists($this,$name))
 | |
| 					$this->$name=$record->$name;
 | |
| 				else
 | |
| 					$this->_attributes[$name]=$record->$name;
 | |
| 			}
 | |
| 			return true;
 | |
| 		}
 | |
| 		else
 | |
| 			return false;
 | |
| 	}
 | |
| 	public function equals($record)
 | |
| 	{
 | |
| 		return $this->tableName()===$record->tableName() && $this->getPrimaryKey()===$record->getPrimaryKey();
 | |
| 	}
 | |
| 	public function getPrimaryKey()
 | |
| 	{
 | |
| 		$table=$this->getMetaData()->tableSchema;
 | |
| 		if(is_string($table->primaryKey))
 | |
| 			return $this->{$table->primaryKey};
 | |
| 		elseif(is_array($table->primaryKey))
 | |
| 		{
 | |
| 			$values=array();
 | |
| 			foreach($table->primaryKey as $name)
 | |
| 				$values[$name]=$this->$name;
 | |
| 			return $values;
 | |
| 		}
 | |
| 		else
 | |
| 			return null;
 | |
| 	}
 | |
| 	public function setPrimaryKey($value)
 | |
| 	{
 | |
| 		$this->_pk=$this->getPrimaryKey();
 | |
| 		$table=$this->getMetaData()->tableSchema;
 | |
| 		if(is_string($table->primaryKey))
 | |
| 			$this->{$table->primaryKey}=$value;
 | |
| 		elseif(is_array($table->primaryKey))
 | |
| 		{
 | |
| 			foreach($table->primaryKey as $name)
 | |
| 				$this->$name=$value[$name];
 | |
| 		}
 | |
| 	}
 | |
| 	public function getOldPrimaryKey()
 | |
| 	{
 | |
| 		return $this->_pk;
 | |
| 	}
 | |
| 	public function setOldPrimaryKey($value)
 | |
| 	{
 | |
| 		$this->_pk=$value;
 | |
| 	}
 | |
| 	protected function query($criteria,$all=false)
 | |
| 	{
 | |
| 		$this->beforeFind();
 | |
| 		$this->applyScopes($criteria);
 | |
| 		if(empty($criteria->with))
 | |
| 		{
 | |
| 			if(!$all)
 | |
| 				$criteria->limit=1;
 | |
| 			$command=$this->getCommandBuilder()->createFindCommand($this->getTableSchema(),$criteria,$this->getTableAlias());
 | |
| 			return $all ? $this->populateRecords($command->queryAll(), true, $criteria->index) : $this->populateRecord($command->queryRow());
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$finder=$this->getActiveFinder($criteria->with);
 | |
| 			return $finder->query($criteria,$all);
 | |
| 		}
 | |
| 	}
 | |
| 	public function applyScopes(&$criteria)
 | |
| 	{
 | |
| 		if(!empty($criteria->scopes))
 | |
| 		{
 | |
| 			$scs=$this->scopes();
 | |
| 			$c=$this->getDbCriteria();
 | |
| 			foreach((array)$criteria->scopes as $k=>$v)
 | |
| 			{
 | |
| 				if(is_integer($k))
 | |
| 				{
 | |
| 					if(is_string($v))
 | |
| 					{
 | |
| 						if(isset($scs[$v]))
 | |
| 						{
 | |
| 							$c->mergeWith($scs[$v],true);
 | |
| 							continue;
 | |
| 						}
 | |
| 						$scope=$v;
 | |
| 						$params=array();
 | |
| 					}
 | |
| 					elseif(is_array($v))
 | |
| 					{
 | |
| 						$scope=key($v);
 | |
| 						$params=current($v);
 | |
| 					}
 | |
| 				}
 | |
| 				elseif(is_string($k))
 | |
| 				{
 | |
| 					$scope=$k;
 | |
| 					$params=$v;
 | |
| 				}
 | |
| 				call_user_func_array(array($this,$scope),(array)$params);
 | |
| 			}
 | |
| 		}
 | |
| 		if(isset($c) || ($c=$this->getDbCriteria(false))!==null)
 | |
| 		{
 | |
| 			$c->mergeWith($criteria);
 | |
| 			$criteria=$c;
 | |
| 			$this->resetScope(false);
 | |
| 		}
 | |
| 	}
 | |
| 	public function getTableAlias($quote=false, $checkScopes=true)
 | |
| 	{
 | |
| 		if($checkScopes && ($criteria=$this->getDbCriteria(false))!==null && $criteria->alias!='')
 | |
| 			$alias=$criteria->alias;
 | |
| 		else
 | |
| 			$alias=$this->_alias;
 | |
| 		return $quote ? $this->getDbConnection()->getSchema()->quoteTableName($alias) : $alias;
 | |
| 	}
 | |
| 	public function setTableAlias($alias)
 | |
| 	{
 | |
| 		$this->_alias=$alias;
 | |
| 	}
 | |
| 	public function find($condition='',$params=array())
 | |
| 	{
 | |
| 		$criteria=$this->getCommandBuilder()->createCriteria($condition,$params);
 | |
| 		return $this->query($criteria);
 | |
| 	}
 | |
| 	public function findAll($condition='',$params=array())
 | |
| 	{
 | |
| 		$criteria=$this->getCommandBuilder()->createCriteria($condition,$params);
 | |
| 		return $this->query($criteria,true);
 | |
| 	}
 | |
| 	public function findByPk($pk,$condition='',$params=array())
 | |
| 	{
 | |
| 		$prefix=$this->getTableAlias(true).'.';
 | |
| 		$criteria=$this->getCommandBuilder()->createPkCriteria($this->getTableSchema(),$pk,$condition,$params,$prefix);
 | |
| 		return $this->query($criteria);
 | |
| 	}
 | |
| 	public function findAllByPk($pk,$condition='',$params=array())
 | |
| 	{
 | |
| 		$prefix=$this->getTableAlias(true).'.';
 | |
| 		$criteria=$this->getCommandBuilder()->createPkCriteria($this->getTableSchema(),$pk,$condition,$params,$prefix);
 | |
| 		return $this->query($criteria,true);
 | |
| 	}
 | |
| 	public function findByAttributes($attributes,$condition='',$params=array())
 | |
| 	{
 | |
| 		$prefix=$this->getTableAlias(true).'.';
 | |
| 		$criteria=$this->getCommandBuilder()->createColumnCriteria($this->getTableSchema(),$attributes,$condition,$params,$prefix);
 | |
| 		return $this->query($criteria);
 | |
| 	}
 | |
| 	public function findAllByAttributes($attributes,$condition='',$params=array())
 | |
| 	{
 | |
| 		$prefix=$this->getTableAlias(true).'.';
 | |
| 		$criteria=$this->getCommandBuilder()->createColumnCriteria($this->getTableSchema(),$attributes,$condition,$params,$prefix);
 | |
| 		return $this->query($criteria,true);
 | |
| 	}
 | |
| 	public function findBySql($sql,$params=array())
 | |
| 	{
 | |
| 		$this->beforeFind();
 | |
| 		if(($criteria=$this->getDbCriteria(false))!==null && !empty($criteria->with))
 | |
| 		{
 | |
| 			$this->resetScope(false);
 | |
| 			$finder=$this->getActiveFinder($criteria->with);
 | |
| 			return $finder->findBySql($sql,$params);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$command=$this->getCommandBuilder()->createSqlCommand($sql,$params);
 | |
| 			return $this->populateRecord($command->queryRow());
 | |
| 		}
 | |
| 	}
 | |
| 	public function findAllBySql($sql,$params=array())
 | |
| 	{
 | |
| 		$this->beforeFind();
 | |
| 		if(($criteria=$this->getDbCriteria(false))!==null && !empty($criteria->with))
 | |
| 		{
 | |
| 			$this->resetScope(false);
 | |
| 			$finder=$this->getActiveFinder($criteria->with);
 | |
| 			return $finder->findAllBySql($sql,$params);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$command=$this->getCommandBuilder()->createSqlCommand($sql,$params);
 | |
| 			return $this->populateRecords($command->queryAll());
 | |
| 		}
 | |
| 	}
 | |
| 	public function count($condition='',$params=array())
 | |
| 	{
 | |
| 		$builder=$this->getCommandBuilder();
 | |
| 		$this->beforeCount();
 | |
| 		$criteria=$builder->createCriteria($condition,$params);
 | |
| 		$this->applyScopes($criteria);
 | |
| 		if(empty($criteria->with))
 | |
| 			return $builder->createCountCommand($this->getTableSchema(),$criteria)->queryScalar();
 | |
| 		else
 | |
| 		{
 | |
| 			$finder=$this->getActiveFinder($criteria->with);
 | |
| 			return $finder->count($criteria);
 | |
| 		}
 | |
| 	}
 | |
| 	public function countByAttributes($attributes,$condition='',$params=array())
 | |
| 	{
 | |
| 		$prefix=$this->getTableAlias(true).'.';
 | |
| 		$builder=$this->getCommandBuilder();
 | |
| 		$this->beforeCount();
 | |
| 		$criteria=$builder->createColumnCriteria($this->getTableSchema(),$attributes,$condition,$params,$prefix);
 | |
| 		$this->applyScopes($criteria);
 | |
| 		if(empty($criteria->with))
 | |
| 			return $builder->createCountCommand($this->getTableSchema(),$criteria)->queryScalar();
 | |
| 		else
 | |
| 		{
 | |
| 			$finder=$this->getActiveFinder($criteria->with);
 | |
| 			return $finder->count($criteria);
 | |
| 		}
 | |
| 	}
 | |
| 	public function countBySql($sql,$params=array())
 | |
| 	{
 | |
| 		$this->beforeCount();
 | |
| 		return $this->getCommandBuilder()->createSqlCommand($sql,$params)->queryScalar();
 | |
| 	}
 | |
| 	public function exists($condition='',$params=array())
 | |
| 	{
 | |
| 		$builder=$this->getCommandBuilder();
 | |
| 		$criteria=$builder->createCriteria($condition,$params);
 | |
| 		$table=$this->getTableSchema();
 | |
| 		$criteria->select='1';
 | |
| 		$criteria->limit=1;
 | |
| 		$this->applyScopes($criteria);
 | |
| 		if(empty($criteria->with))
 | |
| 			return $builder->createFindCommand($table,$criteria,$this->getTableAlias(false, false))->queryRow()!==false;
 | |
| 		else
 | |
| 		{
 | |
| 			$criteria->select='*';
 | |
| 			$finder=$this->getActiveFinder($criteria->with);
 | |
| 			return $finder->count($criteria)>0;
 | |
| 		}
 | |
| 	}
 | |
| 	public function with()
 | |
| 	{
 | |
| 		if(func_num_args()>0)
 | |
| 		{
 | |
| 			$with=func_get_args();
 | |
| 			if(is_array($with[0]))  // the parameter is given as an array
 | |
| 				$with=$with[0];
 | |
| 			if(!empty($with))
 | |
| 				$this->getDbCriteria()->mergeWith(array('with'=>$with));
 | |
| 		}
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function together()
 | |
| 	{
 | |
| 		$this->getDbCriteria()->together=true;
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function updateByPk($pk,$attributes,$condition='',$params=array())
 | |
| 	{
 | |
| 		$builder=$this->getCommandBuilder();
 | |
| 		$table=$this->getTableSchema();
 | |
| 		$criteria=$builder->createPkCriteria($table,$pk,$condition,$params);
 | |
| 		$command=$builder->createUpdateCommand($table,$attributes,$criteria);
 | |
| 		return $command->execute();
 | |
| 	}
 | |
| 	public function updateAll($attributes,$condition='',$params=array())
 | |
| 	{
 | |
| 		$builder=$this->getCommandBuilder();
 | |
| 		$criteria=$builder->createCriteria($condition,$params);
 | |
| 		$command=$builder->createUpdateCommand($this->getTableSchema(),$attributes,$criteria);
 | |
| 		return $command->execute();
 | |
| 	}
 | |
| 	public function updateCounters($counters,$condition='',$params=array())
 | |
| 	{
 | |
| 		$builder=$this->getCommandBuilder();
 | |
| 		$criteria=$builder->createCriteria($condition,$params);
 | |
| 		$command=$builder->createUpdateCounterCommand($this->getTableSchema(),$counters,$criteria);
 | |
| 		return $command->execute();
 | |
| 	}
 | |
| 	public function deleteByPk($pk,$condition='',$params=array())
 | |
| 	{
 | |
| 		$builder=$this->getCommandBuilder();
 | |
| 		$criteria=$builder->createPkCriteria($this->getTableSchema(),$pk,$condition,$params);
 | |
| 		$command=$builder->createDeleteCommand($this->getTableSchema(),$criteria);
 | |
| 		return $command->execute();
 | |
| 	}
 | |
| 	public function deleteAll($condition='',$params=array())
 | |
| 	{
 | |
| 		$builder=$this->getCommandBuilder();
 | |
| 		$criteria=$builder->createCriteria($condition,$params);
 | |
| 		$command=$builder->createDeleteCommand($this->getTableSchema(),$criteria);
 | |
| 		return $command->execute();
 | |
| 	}
 | |
| 	public function deleteAllByAttributes($attributes,$condition='',$params=array())
 | |
| 	{
 | |
| 		$builder=$this->getCommandBuilder();
 | |
| 		$table=$this->getTableSchema();
 | |
| 		$criteria=$builder->createColumnCriteria($table,$attributes,$condition,$params);
 | |
| 		$command=$builder->createDeleteCommand($table,$criteria);
 | |
| 		return $command->execute();
 | |
| 	}
 | |
| 	public function populateRecord($attributes,$callAfterFind=true)
 | |
| 	{
 | |
| 		if($attributes!==false)
 | |
| 		{
 | |
| 			$record=$this->instantiate($attributes);
 | |
| 			$record->setScenario('update');
 | |
| 			$record->init();
 | |
| 			$md=$record->getMetaData();
 | |
| 			foreach($attributes as $name=>$value)
 | |
| 			{
 | |
| 				if(property_exists($record,$name))
 | |
| 					$record->$name=$value;
 | |
| 				elseif(isset($md->columns[$name]))
 | |
| 					$record->_attributes[$name]=$value;
 | |
| 			}
 | |
| 			$record->_pk=$record->getPrimaryKey();
 | |
| 			$record->attachBehaviors($record->behaviors());
 | |
| 			if($callAfterFind)
 | |
| 				$record->afterFind();
 | |
| 			return $record;
 | |
| 		}
 | |
| 		else
 | |
| 			return null;
 | |
| 	}
 | |
| 	public function populateRecords($data,$callAfterFind=true,$index=null)
 | |
| 	{
 | |
| 		$records=array();
 | |
| 		foreach($data as $attributes)
 | |
| 		{
 | |
| 			if(($record=$this->populateRecord($attributes,$callAfterFind))!==null)
 | |
| 			{
 | |
| 				if($index===null)
 | |
| 					$records[]=$record;
 | |
| 				else
 | |
| 					$records[$record->$index]=$record;
 | |
| 			}
 | |
| 		}
 | |
| 		return $records;
 | |
| 	}
 | |
| 	protected function instantiate($attributes)
 | |
| 	{
 | |
| 		$class=get_class($this);
 | |
| 		$model=new $class(null);
 | |
| 		return $model;
 | |
| 	}
 | |
| 	public function offsetExists($offset)
 | |
| 	{
 | |
| 		return $this->__isset($offset);
 | |
| 	}
 | |
| }
 | |
| class CBaseActiveRelation extends CComponent
 | |
| {
 | |
| 	public $name;
 | |
| 	public $className;
 | |
| 	public $foreignKey;
 | |
| 	public $select='*';
 | |
| 	public $condition='';
 | |
| 	public $params=array();
 | |
| 	public $group='';
 | |
| 	public $join='';
 | |
| 	public $having='';
 | |
| 	public $order='';
 | |
| 	public function __construct($name,$className,$foreignKey,$options=array())
 | |
| 	{
 | |
| 		$this->name=$name;
 | |
| 		$this->className=$className;
 | |
| 		$this->foreignKey=$foreignKey;
 | |
| 		foreach($options as $name=>$value)
 | |
| 			$this->$name=$value;
 | |
| 	}
 | |
| 	public function mergeWith($criteria,$fromScope=false)
 | |
| 	{
 | |
| 		if($criteria instanceof CDbCriteria)
 | |
| 			$criteria=$criteria->toArray();
 | |
| 		if(isset($criteria['select']) && $this->select!==$criteria['select'])
 | |
| 		{
 | |
| 			if($this->select==='*')
 | |
| 				$this->select=$criteria['select'];
 | |
| 			elseif($criteria['select']!=='*')
 | |
| 			{
 | |
| 				$select1=is_string($this->select)?preg_split('/\s*,\s*/',trim($this->select),-1,PREG_SPLIT_NO_EMPTY):$this->select;
 | |
| 				$select2=is_string($criteria['select'])?preg_split('/\s*,\s*/',trim($criteria['select']),-1,PREG_SPLIT_NO_EMPTY):$criteria['select'];
 | |
| 				$this->select=array_merge($select1,array_diff($select2,$select1));
 | |
| 			}
 | |
| 		}
 | |
| 		if(isset($criteria['condition']) && $this->condition!==$criteria['condition'])
 | |
| 		{
 | |
| 			if($this->condition==='')
 | |
| 				$this->condition=$criteria['condition'];
 | |
| 			elseif($criteria['condition']!=='')
 | |
| 				$this->condition="({$this->condition}) AND ({$criteria['condition']})";
 | |
| 		}
 | |
| 		if(isset($criteria['params']) && $this->params!==$criteria['params'])
 | |
| 			$this->params=array_merge($this->params,$criteria['params']);
 | |
| 		if(isset($criteria['order']) && $this->order!==$criteria['order'])
 | |
| 		{
 | |
| 			if($this->order==='')
 | |
| 				$this->order=$criteria['order'];
 | |
| 			elseif($criteria['order']!=='')
 | |
| 				$this->order=$criteria['order'].', '.$this->order;
 | |
| 		}
 | |
| 		if(isset($criteria['group']) && $this->group!==$criteria['group'])
 | |
| 		{
 | |
| 			if($this->group==='')
 | |
| 				$this->group=$criteria['group'];
 | |
| 			elseif($criteria['group']!=='')
 | |
| 				$this->group.=', '.$criteria['group'];
 | |
| 		}
 | |
| 		if(isset($criteria['join']) && $this->join!==$criteria['join'])
 | |
| 		{
 | |
| 			if($this->join==='')
 | |
| 				$this->join=$criteria['join'];
 | |
| 			elseif($criteria['join']!=='')
 | |
| 				$this->join.=' '.$criteria['join'];
 | |
| 		}
 | |
| 		if(isset($criteria['having']) && $this->having!==$criteria['having'])
 | |
| 		{
 | |
| 			if($this->having==='')
 | |
| 				$this->having=$criteria['having'];
 | |
| 			elseif($criteria['having']!=='')
 | |
| 				$this->having="({$this->having}) AND ({$criteria['having']})";
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| class CStatRelation extends CBaseActiveRelation
 | |
| {
 | |
| 	public $select='COUNT(*)';
 | |
| 	public $defaultValue=0;
 | |
| 	public function mergeWith($criteria,$fromScope=false)
 | |
| 	{
 | |
| 		if($criteria instanceof CDbCriteria)
 | |
| 			$criteria=$criteria->toArray();
 | |
| 		parent::mergeWith($criteria,$fromScope);
 | |
| 		if(isset($criteria['defaultValue']))
 | |
| 			$this->defaultValue=$criteria['defaultValue'];
 | |
| 	}
 | |
| }
 | |
| class CActiveRelation extends CBaseActiveRelation
 | |
| {
 | |
| 	public $joinType='LEFT OUTER JOIN';
 | |
| 	public $on='';
 | |
| 	public $alias;
 | |
| 	public $with=array();
 | |
| 	public $together;
 | |
| 	 public $scopes;
 | |
| 	public $through;
 | |
| 	public function mergeWith($criteria,$fromScope=false)
 | |
| 	{
 | |
| 		if($criteria instanceof CDbCriteria)
 | |
| 			$criteria=$criteria->toArray();
 | |
| 		if($fromScope)
 | |
| 		{
 | |
| 			if(isset($criteria['condition']) && $this->on!==$criteria['condition'])
 | |
| 			{
 | |
| 				if($this->on==='')
 | |
| 					$this->on=$criteria['condition'];
 | |
| 				elseif($criteria['condition']!=='')
 | |
| 					$this->on="({$this->on}) AND ({$criteria['condition']})";
 | |
| 			}
 | |
| 			unset($criteria['condition']);
 | |
| 		}
 | |
| 		parent::mergeWith($criteria);
 | |
| 		if(isset($criteria['joinType']))
 | |
| 			$this->joinType=$criteria['joinType'];
 | |
| 		if(isset($criteria['on']) && $this->on!==$criteria['on'])
 | |
| 		{
 | |
| 			if($this->on==='')
 | |
| 				$this->on=$criteria['on'];
 | |
| 			elseif($criteria['on']!=='')
 | |
| 				$this->on="({$this->on}) AND ({$criteria['on']})";
 | |
| 		}
 | |
| 		if(isset($criteria['with']))
 | |
| 			$this->with=$criteria['with'];
 | |
| 		if(isset($criteria['alias']))
 | |
| 			$this->alias=$criteria['alias'];
 | |
| 		if(isset($criteria['together']))
 | |
| 			$this->together=$criteria['together'];
 | |
| 	}
 | |
| }
 | |
| class CBelongsToRelation extends CActiveRelation
 | |
| {
 | |
| }
 | |
| class CHasOneRelation extends CActiveRelation
 | |
| {
 | |
| }
 | |
| class CHasManyRelation extends CActiveRelation
 | |
| {
 | |
| 	public $limit=-1;
 | |
| 	public $offset=-1;
 | |
| 	public $index;
 | |
| 	public function mergeWith($criteria,$fromScope=false)
 | |
| 	{
 | |
| 		if($criteria instanceof CDbCriteria)
 | |
| 			$criteria=$criteria->toArray();
 | |
| 		parent::mergeWith($criteria,$fromScope);
 | |
| 		if(isset($criteria['limit']) && $criteria['limit']>0)
 | |
| 			$this->limit=$criteria['limit'];
 | |
| 		if(isset($criteria['offset']) && $criteria['offset']>=0)
 | |
| 			$this->offset=$criteria['offset'];
 | |
| 		if(isset($criteria['index']))
 | |
| 			$this->index=$criteria['index'];
 | |
| 	}
 | |
| }
 | |
| class CManyManyRelation extends CHasManyRelation
 | |
| {
 | |
| 	private $_junctionTableName=null;
 | |
| 	private $_junctionForeignKeys=null;
 | |
| 	public function getJunctionTableName()
 | |
| 	{
 | |
| 		if ($this->_junctionTableName===null)
 | |
| 			$this->initJunctionData();
 | |
| 		return $this->_junctionTableName;
 | |
| 	}
 | |
| 	public function getJunctionForeignKeys()
 | |
| 	{
 | |
| 		if ($this->_junctionForeignKeys===null)
 | |
| 			$this->initJunctionData();
 | |
| 		return $this->_junctionForeignKeys;
 | |
| 	}
 | |
| 	private function initJunctionData()
 | |
| 	{
 | |
| 		if(!preg_match('/^\s*(.*?)\((.*)\)\s*$/',$this->foreignKey,$matches))
 | |
| 			throw new CDbException(Yii::t('yii','The relation "{relation}" in active record class "{class}" is specified with an invalid foreign key. The format of the foreign key must be "joinTable(fk1,fk2,...)".',
 | |
| 				array('{class}'=>$this->className,'{relation}'=>$this->name)));
 | |
| 		$this->_junctionTableName=$matches[1];
 | |
| 		$this->_junctionForeignKeys=preg_split('/\s*,\s*/',$matches[2],-1,PREG_SPLIT_NO_EMPTY);
 | |
| 	}
 | |
| }
 | |
| class CActiveRecordMetaData
 | |
| {
 | |
| 	public $tableSchema;
 | |
| 	public $columns;
 | |
| 	public $relations=array();
 | |
| 	public $attributeDefaults=array();
 | |
| 	private $_modelClassName;
 | |
| 	public function __construct($model)
 | |
| 	{
 | |
| 		$this->_modelClassName=get_class($model);
 | |
| 		$tableName=$model->tableName();
 | |
| 		if(($table=$model->getDbConnection()->getSchema()->getTable($tableName))===null)
 | |
| 			throw new CDbException(Yii::t('yii','The table "{table}" for active record class "{class}" cannot be found in the database.',
 | |
| 				array('{class}'=>$this->_modelClassName,'{table}'=>$tableName)));
 | |
| 		if($table->primaryKey===null)
 | |
| 		{
 | |
| 			$table->primaryKey=$model->primaryKey();
 | |
| 			if(is_string($table->primaryKey) && isset($table->columns[$table->primaryKey]))
 | |
| 				$table->columns[$table->primaryKey]->isPrimaryKey=true;
 | |
| 			elseif(is_array($table->primaryKey))
 | |
| 			{
 | |
| 				foreach($table->primaryKey as $name)
 | |
| 				{
 | |
| 					if(isset($table->columns[$name]))
 | |
| 						$table->columns[$name]->isPrimaryKey=true;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		$this->tableSchema=$table;
 | |
| 		$this->columns=$table->columns;
 | |
| 		foreach($table->columns as $name=>$column)
 | |
| 		{
 | |
| 			if(!$column->isPrimaryKey && $column->defaultValue!==null)
 | |
| 				$this->attributeDefaults[$name]=$column->defaultValue;
 | |
| 		}
 | |
| 		foreach($model->relations() as $name=>$config)
 | |
| 		{
 | |
| 			$this->addRelation($name,$config);
 | |
| 		}
 | |
| 	}
 | |
| 	public function addRelation($name,$config)
 | |
| 	{
 | |
| 		if(isset($config[0],$config[1],$config[2]))  // relation class, AR class, FK
 | |
| 			$this->relations[$name]=new $config[0]($name,$config[1],$config[2],array_slice($config,3));
 | |
| 		else
 | |
| 			throw new CDbException(Yii::t('yii','Active record "{class}" has an invalid configuration for relation "{relation}". It must specify the relation type, the related active record class and the foreign key.', array('{class}'=>$this->_modelClassName,'{relation}'=>$name)));
 | |
| 	}
 | |
| 	public function hasRelation($name)
 | |
| 	{
 | |
| 		return isset($this->relations[$name]);
 | |
| 	}
 | |
| 	public function removeRelation($name)
 | |
| 	{
 | |
| 		unset($this->relations[$name]);
 | |
| 	}
 | |
| }
 | |
| class CDbConnection extends CApplicationComponent
 | |
| {
 | |
| 	public $connectionString;
 | |
| 	public $username='';
 | |
| 	public $password='';
 | |
| 	public $schemaCachingDuration=0;
 | |
| 	public $schemaCachingExclude=array();
 | |
| 	public $schemaCacheID='cache';
 | |
| 	public $queryCachingDuration=0;
 | |
| 	public $queryCachingDependency;
 | |
| 	public $queryCachingCount=0;
 | |
| 	public $queryCacheID='cache';
 | |
| 	public $autoConnect=true;
 | |
| 	public $charset;
 | |
| 	public $emulatePrepare;
 | |
| 	public $enableParamLogging=false;
 | |
| 	public $enableProfiling=false;
 | |
| 	public $tablePrefix;
 | |
| 	public $initSQLs;
 | |
| 	public $driverMap=array(
 | |
| 		'pgsql'=>'CPgsqlSchema',    // PostgreSQL
 | |
| 		'mysqli'=>'CMysqlSchema',   // MySQL
 | |
| 		'mysql'=>'CMysqlSchema',    // MySQL
 | |
| 		'sqlite'=>'CSqliteSchema',  // sqlite 3
 | |
| 		'sqlite2'=>'CSqliteSchema', // sqlite 2
 | |
| 		'mssql'=>'CMssqlSchema',    // Mssql driver on windows hosts
 | |
| 		'dblib'=>'CMssqlSchema',    // dblib drivers on linux (and maybe others os) hosts
 | |
| 		'sqlsrv'=>'CMssqlSchema',   // Mssql
 | |
| 		'oci'=>'COciSchema',        // Oracle driver
 | |
| 	);
 | |
| 	public $pdoClass = 'PDO';
 | |
| 	private $_attributes=array();
 | |
| 	private $_active=false;
 | |
| 	private $_pdo;
 | |
| 	private $_transaction;
 | |
| 	private $_schema;
 | |
| 	public function __construct($dsn='',$username='',$password='')
 | |
| 	{
 | |
| 		$this->connectionString=$dsn;
 | |
| 		$this->username=$username;
 | |
| 		$this->password=$password;
 | |
| 	}
 | |
| 	public function __sleep()
 | |
| 	{
 | |
| 		$this->close();
 | |
| 		return array_keys(get_object_vars($this));
 | |
| 	}
 | |
| 	public static function getAvailableDrivers()
 | |
| 	{
 | |
| 		return PDO::getAvailableDrivers();
 | |
| 	}
 | |
| 	public function init()
 | |
| 	{
 | |
| 		parent::init();
 | |
| 		if($this->autoConnect)
 | |
| 			$this->setActive(true);
 | |
| 	}
 | |
| 	public function getActive()
 | |
| 	{
 | |
| 		return $this->_active;
 | |
| 	}
 | |
| 	public function setActive($value)
 | |
| 	{
 | |
| 		if($value!=$this->_active)
 | |
| 		{
 | |
| 			if($value)
 | |
| 				$this->open();
 | |
| 			else
 | |
| 				$this->close();
 | |
| 		}
 | |
| 	}
 | |
| 	public function cache($duration, $dependency=null, $queryCount=1)
 | |
| 	{
 | |
| 		$this->queryCachingDuration=$duration;
 | |
| 		$this->queryCachingDependency=$dependency;
 | |
| 		$this->queryCachingCount=$queryCount;
 | |
| 		return $this;
 | |
| 	}
 | |
| 	protected function open()
 | |
| 	{
 | |
| 		if($this->_pdo===null)
 | |
| 		{
 | |
| 			if(empty($this->connectionString))
 | |
| 				throw new CDbException('CDbConnection.connectionString cannot be empty.');
 | |
| 			try
 | |
| 			{
 | |
| 				$this->_pdo=$this->createPdoInstance();
 | |
| 				$this->initConnection($this->_pdo);
 | |
| 				$this->_active=true;
 | |
| 			}
 | |
| 			catch(PDOException $e)
 | |
| 			{
 | |
| 				if(YII_DEBUG)
 | |
| 				{
 | |
| 					throw new CDbException('CDbConnection failed to open the DB connection: '.
 | |
| 						$e->getMessage(),(int)$e->getCode(),$e->errorInfo);
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					Yii::log($e->getMessage(),CLogger::LEVEL_ERROR,'exception.CDbException');
 | |
| 					throw new CDbException('CDbConnection failed to open the DB connection.',(int)$e->getCode(),$e->errorInfo);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	protected function close()
 | |
| 	{
 | |
| 		$this->_pdo=null;
 | |
| 		$this->_active=false;
 | |
| 		$this->_schema=null;
 | |
| 	}
 | |
| 	protected function createPdoInstance()
 | |
| 	{
 | |
| 		$pdoClass=$this->pdoClass;
 | |
| 		if(($pos=strpos($this->connectionString,':'))!==false)
 | |
| 		{
 | |
| 			$driver=strtolower(substr($this->connectionString,0,$pos));
 | |
| 			if($driver==='mssql' || $driver==='dblib')
 | |
| 				$pdoClass='CMssqlPdoAdapter';
 | |
| 			elseif($driver==='sqlsrv')
 | |
| 				$pdoClass='CMssqlSqlsrvPdoAdapter';
 | |
| 		}
 | |
| 		if(!class_exists($pdoClass))
 | |
| 			throw new CDbException(Yii::t('yii','CDbConnection is unable to find PDO class "{className}". Make sure PDO is installed correctly.',
 | |
| 				array('{className}'=>$pdoClass)));
 | |
| 		@$instance=new $pdoClass($this->connectionString,$this->username,$this->password,$this->_attributes);
 | |
| 		if(!$instance)
 | |
| 			throw new CDbException(Yii::t('yii','CDbConnection failed to open the DB connection.'));
 | |
| 		return $instance;
 | |
| 	}
 | |
| 	protected function initConnection($pdo)
 | |
| 	{
 | |
| 		$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 | |
| 		if($this->emulatePrepare!==null && constant('PDO::ATTR_EMULATE_PREPARES'))
 | |
| 			$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,$this->emulatePrepare);
 | |
| 		if($this->charset!==null)
 | |
| 		{
 | |
| 			$driver=strtolower($pdo->getAttribute(PDO::ATTR_DRIVER_NAME));
 | |
| 			if(in_array($driver,array('pgsql','mysql','mysqli')))
 | |
| 				$pdo->exec('SET NAMES '.$pdo->quote($this->charset));
 | |
| 		}
 | |
| 		if($this->initSQLs!==null)
 | |
| 		{
 | |
| 			foreach($this->initSQLs as $sql)
 | |
| 				$pdo->exec($sql);
 | |
| 		}
 | |
| 	}
 | |
| 	public function getPdoInstance()
 | |
| 	{
 | |
| 		return $this->_pdo;
 | |
| 	}
 | |
| 	public function createCommand($query=null)
 | |
| 	{
 | |
| 		$this->setActive(true);
 | |
| 		return new CDbCommand($this,$query);
 | |
| 	}
 | |
| 	public function getCurrentTransaction()
 | |
| 	{
 | |
| 		if($this->_transaction!==null)
 | |
| 		{
 | |
| 			if($this->_transaction->getActive())
 | |
| 				return $this->_transaction;
 | |
| 		}
 | |
| 		return null;
 | |
| 	}
 | |
| 	public function beginTransaction()
 | |
| 	{
 | |
| 		$this->setActive(true);
 | |
| 		$this->_pdo->beginTransaction();
 | |
| 		return $this->_transaction=new CDbTransaction($this);
 | |
| 	}
 | |
| 	public function getSchema()
 | |
| 	{
 | |
| 		if($this->_schema!==null)
 | |
| 			return $this->_schema;
 | |
| 		else
 | |
| 		{
 | |
| 			$driver=$this->getDriverName();
 | |
| 			if(isset($this->driverMap[$driver]))
 | |
| 				return $this->_schema=Yii::createComponent($this->driverMap[$driver], $this);
 | |
| 			else
 | |
| 				throw new CDbException(Yii::t('yii','CDbConnection does not support reading schema for {driver} database.',
 | |
| 					array('{driver}'=>$driver)));
 | |
| 		}
 | |
| 	}
 | |
| 	public function getCommandBuilder()
 | |
| 	{
 | |
| 		return $this->getSchema()->getCommandBuilder();
 | |
| 	}
 | |
| 	public function getLastInsertID($sequenceName='')
 | |
| 	{
 | |
| 		$this->setActive(true);
 | |
| 		return $this->_pdo->lastInsertId($sequenceName);
 | |
| 	}
 | |
| 	public function quoteValue($str)
 | |
| 	{
 | |
| 		if(is_int($str) || is_float($str))
 | |
| 			return $str;
 | |
| 		$this->setActive(true);
 | |
| 		if(($value=$this->_pdo->quote($str))!==false)
 | |
| 			return $value;
 | |
| 		else  // the driver doesn't support quote (e.g. oci)
 | |
| 			return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") . "'";
 | |
| 	}
 | |
| 	public function quoteTableName($name)
 | |
| 	{
 | |
| 		return $this->getSchema()->quoteTableName($name);
 | |
| 	}
 | |
| 	public function quoteColumnName($name)
 | |
| 	{
 | |
| 		return $this->getSchema()->quoteColumnName($name);
 | |
| 	}
 | |
| 	public function getPdoType($type)
 | |
| 	{
 | |
| 		static $map=array
 | |
| 		(
 | |
| 			'boolean'=>PDO::PARAM_BOOL,
 | |
| 			'integer'=>PDO::PARAM_INT,
 | |
| 			'string'=>PDO::PARAM_STR,
 | |
| 			'resource'=>PDO::PARAM_LOB,
 | |
| 			'NULL'=>PDO::PARAM_NULL,
 | |
| 		);
 | |
| 		return isset($map[$type]) ? $map[$type] : PDO::PARAM_STR;
 | |
| 	}
 | |
| 	public function getColumnCase()
 | |
| 	{
 | |
| 		return $this->getAttribute(PDO::ATTR_CASE);
 | |
| 	}
 | |
| 	public function setColumnCase($value)
 | |
| 	{
 | |
| 		$this->setAttribute(PDO::ATTR_CASE,$value);
 | |
| 	}
 | |
| 	public function getNullConversion()
 | |
| 	{
 | |
| 		return $this->getAttribute(PDO::ATTR_ORACLE_NULLS);
 | |
| 	}
 | |
| 	public function setNullConversion($value)
 | |
| 	{
 | |
| 		$this->setAttribute(PDO::ATTR_ORACLE_NULLS,$value);
 | |
| 	}
 | |
| 	public function getAutoCommit()
 | |
| 	{
 | |
| 		return $this->getAttribute(PDO::ATTR_AUTOCOMMIT);
 | |
| 	}
 | |
| 	public function setAutoCommit($value)
 | |
| 	{
 | |
| 		$this->setAttribute(PDO::ATTR_AUTOCOMMIT,$value);
 | |
| 	}
 | |
| 	public function getPersistent()
 | |
| 	{
 | |
| 		return $this->getAttribute(PDO::ATTR_PERSISTENT);
 | |
| 	}
 | |
| 	public function setPersistent($value)
 | |
| 	{
 | |
| 		return $this->setAttribute(PDO::ATTR_PERSISTENT,$value);
 | |
| 	}
 | |
| 	public function getDriverName()
 | |
| 	{
 | |
| 		if(($pos=strpos($this->connectionString, ':'))!==false)
 | |
| 			return strtolower(substr($this->connectionString, 0, $pos));
 | |
| 		// return $this->getAttribute(PDO::ATTR_DRIVER_NAME);
 | |
| 	}
 | |
| 	public function getClientVersion()
 | |
| 	{
 | |
| 		return $this->getAttribute(PDO::ATTR_CLIENT_VERSION);
 | |
| 	}
 | |
| 	public function getConnectionStatus()
 | |
| 	{
 | |
| 		return $this->getAttribute(PDO::ATTR_CONNECTION_STATUS);
 | |
| 	}
 | |
| 	public function getPrefetch()
 | |
| 	{
 | |
| 		return $this->getAttribute(PDO::ATTR_PREFETCH);
 | |
| 	}
 | |
| 	public function getServerInfo()
 | |
| 	{
 | |
| 		return $this->getAttribute(PDO::ATTR_SERVER_INFO);
 | |
| 	}
 | |
| 	public function getServerVersion()
 | |
| 	{
 | |
| 		return $this->getAttribute(PDO::ATTR_SERVER_VERSION);
 | |
| 	}
 | |
| 	public function getTimeout()
 | |
| 	{
 | |
| 		return $this->getAttribute(PDO::ATTR_TIMEOUT);
 | |
| 	}
 | |
| 	public function getAttribute($name)
 | |
| 	{
 | |
| 		$this->setActive(true);
 | |
| 		return $this->_pdo->getAttribute($name);
 | |
| 	}
 | |
| 	public function setAttribute($name,$value)
 | |
| 	{
 | |
| 		if($this->_pdo instanceof PDO)
 | |
| 			$this->_pdo->setAttribute($name,$value);
 | |
| 		else
 | |
| 			$this->_attributes[$name]=$value;
 | |
| 	}
 | |
| 	public function getAttributes()
 | |
| 	{
 | |
| 		return $this->_attributes;
 | |
| 	}
 | |
| 	public function setAttributes($values)
 | |
| 	{
 | |
| 		foreach($values as $name=>$value)
 | |
| 			$this->_attributes[$name]=$value;
 | |
| 	}
 | |
| 	public function getStats()
 | |
| 	{
 | |
| 		$logger=Yii::getLogger();
 | |
| 		$timings=$logger->getProfilingResults(null,'system.db.CDbCommand.query');
 | |
| 		$count=count($timings);
 | |
| 		$time=array_sum($timings);
 | |
| 		$timings=$logger->getProfilingResults(null,'system.db.CDbCommand.execute');
 | |
| 		$count+=count($timings);
 | |
| 		$time+=array_sum($timings);
 | |
| 		return array($count,$time);
 | |
| 	}
 | |
| }
 | |
| abstract class CDbSchema extends CComponent
 | |
| {
 | |
| 	public $columnTypes=array();
 | |
| 	private $_tableNames=array();
 | |
| 	private $_tables=array();
 | |
| 	private $_connection;
 | |
| 	private $_builder;
 | |
| 	private $_cacheExclude=array();
 | |
| 	abstract protected function loadTable($name);
 | |
| 	public function __construct($conn)
 | |
| 	{
 | |
| 		$this->_connection=$conn;
 | |
| 		foreach($conn->schemaCachingExclude as $name)
 | |
| 			$this->_cacheExclude[$name]=true;
 | |
| 	}
 | |
| 	public function getDbConnection()
 | |
| 	{
 | |
| 		return $this->_connection;
 | |
| 	}
 | |
| 	public function getTable($name,$refresh=false)
 | |
| 	{
 | |
| 		if($refresh===false && isset($this->_tables[$name]))
 | |
| 			return $this->_tables[$name];
 | |
| 		else
 | |
| 		{
 | |
| 			if($this->_connection->tablePrefix!==null && strpos($name,'{{')!==false)
 | |
| 				$realName=preg_replace('/\{\{(.*?)\}\}/',$this->_connection->tablePrefix.'$1',$name);
 | |
| 			else
 | |
| 				$realName=$name;
 | |
| 			// temporarily disable query caching
 | |
| 			if($this->_connection->queryCachingDuration>0)
 | |
| 			{
 | |
| 				$qcDuration=$this->_connection->queryCachingDuration;
 | |
| 				$this->_connection->queryCachingDuration=0;
 | |
| 			}
 | |
| 			if(!isset($this->_cacheExclude[$name]) && ($duration=$this->_connection->schemaCachingDuration)>0 && $this->_connection->schemaCacheID!==false && ($cache=Yii::app()->getComponent($this->_connection->schemaCacheID))!==null)
 | |
| 			{
 | |
| 				$key='yii:dbschema'.$this->_connection->connectionString.':'.$this->_connection->username.':'.$name;
 | |
| 				$table=$cache->get($key);
 | |
| 				if($refresh===true || $table===false)
 | |
| 				{
 | |
| 					$table=$this->loadTable($realName);
 | |
| 					if($table!==null)
 | |
| 						$cache->set($key,$table,$duration);
 | |
| 				}
 | |
| 				$this->_tables[$name]=$table;
 | |
| 			}
 | |
| 			else
 | |
| 				$this->_tables[$name]=$table=$this->loadTable($realName);
 | |
| 			if(isset($qcDuration))  // re-enable query caching
 | |
| 				$this->_connection->queryCachingDuration=$qcDuration;
 | |
| 			return $table;
 | |
| 		}
 | |
| 	}
 | |
| 	public function getTables($schema='')
 | |
| 	{
 | |
| 		$tables=array();
 | |
| 		foreach($this->getTableNames($schema) as $name)
 | |
| 		{
 | |
| 			if(($table=$this->getTable($name))!==null)
 | |
| 				$tables[$name]=$table;
 | |
| 		}
 | |
| 		return $tables;
 | |
| 	}
 | |
| 	public function getTableNames($schema='')
 | |
| 	{
 | |
| 		if(!isset($this->_tableNames[$schema]))
 | |
| 			$this->_tableNames[$schema]=$this->findTableNames($schema);
 | |
| 		return $this->_tableNames[$schema];
 | |
| 	}
 | |
| 	public function getCommandBuilder()
 | |
| 	{
 | |
| 		if($this->_builder!==null)
 | |
| 			return $this->_builder;
 | |
| 		else
 | |
| 			return $this->_builder=$this->createCommandBuilder();
 | |
| 	}
 | |
| 	public function refresh()
 | |
| 	{
 | |
| 		if(($duration=$this->_connection->schemaCachingDuration)>0 && $this->_connection->schemaCacheID!==false && ($cache=Yii::app()->getComponent($this->_connection->schemaCacheID))!==null)
 | |
| 		{
 | |
| 			foreach(array_keys($this->_tables) as $name)
 | |
| 			{
 | |
| 				if(!isset($this->_cacheExclude[$name]))
 | |
| 				{
 | |
| 					$key='yii:dbschema'.$this->_connection->connectionString.':'.$this->_connection->username.':'.$name;
 | |
| 					$cache->delete($key);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		$this->_tables=array();
 | |
| 		$this->_tableNames=array();
 | |
| 		$this->_builder=null;
 | |
| 	}
 | |
| 	public function quoteTableName($name)
 | |
| 	{
 | |
| 		if(strpos($name,'.')===false)
 | |
| 			return $this->quoteSimpleTableName($name);
 | |
| 		$parts=explode('.',$name);
 | |
| 		foreach($parts as $i=>$part)
 | |
| 			$parts[$i]=$this->quoteSimpleTableName($part);
 | |
| 		return implode('.',$parts);
 | |
| 	}
 | |
| 	public function quoteSimpleTableName($name)
 | |
| 	{
 | |
| 		return "'".$name."'";
 | |
| 	}
 | |
| 	public function quoteColumnName($name)
 | |
| 	{
 | |
| 		if(($pos=strrpos($name,'.'))!==false)
 | |
| 		{
 | |
| 			$prefix=$this->quoteTableName(substr($name,0,$pos)).'.';
 | |
| 			$name=substr($name,$pos+1);
 | |
| 		}
 | |
| 		else
 | |
| 			$prefix='';
 | |
| 		return $prefix . ($name==='*' ? $name : $this->quoteSimpleColumnName($name));
 | |
| 	}
 | |
| 	public function quoteSimpleColumnName($name)
 | |
| 	{
 | |
| 		return '"'.$name.'"';
 | |
| 	}
 | |
| 	public function compareTableNames($name1,$name2)
 | |
| 	{
 | |
| 		$name1=str_replace(array('"','`',"'"),'',$name1);
 | |
| 		$name2=str_replace(array('"','`',"'"),'',$name2);
 | |
| 		if(($pos=strrpos($name1,'.'))!==false)
 | |
| 			$name1=substr($name1,$pos+1);
 | |
| 		if(($pos=strrpos($name2,'.'))!==false)
 | |
| 			$name2=substr($name2,$pos+1);
 | |
| 		if($this->_connection->tablePrefix!==null)
 | |
| 		{
 | |
| 			if(strpos($name1,'{')!==false)
 | |
| 				$name1=$this->_connection->tablePrefix.str_replace(array('{','}'),'',$name1);
 | |
| 			if(strpos($name2,'{')!==false)
 | |
| 				$name2=$this->_connection->tablePrefix.str_replace(array('{','}'),'',$name2);
 | |
| 		}
 | |
| 		return $name1===$name2;
 | |
| 	}
 | |
| 	public function resetSequence($table,$value=null)
 | |
| 	{
 | |
| 	}
 | |
| 	public function checkIntegrity($check=true,$schema='')
 | |
| 	{
 | |
| 	}
 | |
| 	protected function createCommandBuilder()
 | |
| 	{
 | |
| 		return new CDbCommandBuilder($this);
 | |
| 	}
 | |
| 	protected function findTableNames($schema='')
 | |
| 	{
 | |
| 		throw new CDbException(Yii::t('yii','{class} does not support fetching all table names.',
 | |
| 			array('{class}'=>get_class($this))));
 | |
| 	}
 | |
| 	public function getColumnType($type)
 | |
| 	{
 | |
| 		if(isset($this->columnTypes[$type]))
 | |
| 			return $this->columnTypes[$type];
 | |
| 		elseif(($pos=strpos($type,' '))!==false)
 | |
| 		{
 | |
| 			$t=substr($type,0,$pos);
 | |
| 			return (isset($this->columnTypes[$t]) ? $this->columnTypes[$t] : $t).substr($type,$pos);
 | |
| 		}
 | |
| 		else
 | |
| 			return $type;
 | |
| 	}
 | |
| 	public function createTable($table, $columns, $options=null)
 | |
| 	{
 | |
| 		$cols=array();
 | |
| 		foreach($columns as $name=>$type)
 | |
| 		{
 | |
| 			if(is_string($name))
 | |
| 				$cols[]="\t".$this->quoteColumnName($name).' '.$this->getColumnType($type);
 | |
| 			else
 | |
| 				$cols[]="\t".$type;
 | |
| 		}
 | |
| 		$sql="CREATE TABLE ".$this->quoteTableName($table)." (\n".implode(",\n",$cols)."\n)";
 | |
| 		return $options===null ? $sql : $sql.' '.$options;
 | |
| 	}
 | |
| 	public function renameTable($table, $newName)
 | |
| 	{
 | |
| 		return 'RENAME TABLE ' . $this->quoteTableName($table) . ' TO ' . $this->quoteTableName($newName);
 | |
| 	}
 | |
| 	public function dropTable($table)
 | |
| 	{
 | |
| 		return "DROP TABLE ".$this->quoteTableName($table);
 | |
| 	}
 | |
| 	public function truncateTable($table)
 | |
| 	{
 | |
| 		return "TRUNCATE TABLE ".$this->quoteTableName($table);
 | |
| 	}
 | |
| 	public function addColumn($table, $column, $type)
 | |
| 	{
 | |
| 		return 'ALTER TABLE ' . $this->quoteTableName($table)
 | |
| 			. ' ADD ' . $this->quoteColumnName($column) . ' '
 | |
| 			. $this->getColumnType($type);
 | |
| 	}
 | |
| 	public function dropColumn($table, $column)
 | |
| 	{
 | |
| 		return "ALTER TABLE ".$this->quoteTableName($table)
 | |
| 			." DROP COLUMN ".$this->quoteColumnName($column);
 | |
| 	}
 | |
| 	public function renameColumn($table, $name, $newName)
 | |
| 	{
 | |
| 		return "ALTER TABLE ".$this->quoteTableName($table)
 | |
| 			. " RENAME COLUMN ".$this->quoteColumnName($name)
 | |
| 			. " TO ".$this->quoteColumnName($newName);
 | |
| 	}
 | |
| 	public function alterColumn($table, $column, $type)
 | |
| 	{
 | |
| 		return 'ALTER TABLE ' . $this->quoteTableName($table) . ' CHANGE '
 | |
| 			. $this->quoteColumnName($column) . ' '
 | |
| 			. $this->quoteColumnName($column) . ' '
 | |
| 			. $this->getColumnType($type);
 | |
| 	}
 | |
| 	public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete=null, $update=null)
 | |
| 	{
 | |
| 		$columns=preg_split('/\s*,\s*/',$columns,-1,PREG_SPLIT_NO_EMPTY);
 | |
| 		foreach($columns as $i=>$col)
 | |
| 			$columns[$i]=$this->quoteColumnName($col);
 | |
| 		$refColumns=preg_split('/\s*,\s*/',$refColumns,-1,PREG_SPLIT_NO_EMPTY);
 | |
| 		foreach($refColumns as $i=>$col)
 | |
| 			$refColumns[$i]=$this->quoteColumnName($col);
 | |
| 		$sql='ALTER TABLE '.$this->quoteTableName($table)
 | |
| 			.' ADD CONSTRAINT '.$this->quoteColumnName($name)
 | |
| 			.' FOREIGN KEY ('.implode(', ', $columns).')'
 | |
| 			.' REFERENCES '.$this->quoteTableName($refTable)
 | |
| 			.' ('.implode(', ', $refColumns).')';
 | |
| 		if($delete!==null)
 | |
| 			$sql.=' ON DELETE '.$delete;
 | |
| 		if($update!==null)
 | |
| 			$sql.=' ON UPDATE '.$update;
 | |
| 		return $sql;
 | |
| 	}
 | |
| 	public function dropForeignKey($name, $table)
 | |
| 	{
 | |
| 		return 'ALTER TABLE '.$this->quoteTableName($table)
 | |
| 			.' DROP CONSTRAINT '.$this->quoteColumnName($name);
 | |
| 	}
 | |
| 	public function createIndex($name, $table, $column, $unique=false)
 | |
| 	{
 | |
| 		$cols=array();
 | |
| 		$columns=preg_split('/\s*,\s*/',$column,-1,PREG_SPLIT_NO_EMPTY);
 | |
| 		foreach($columns as $col)
 | |
| 		{
 | |
| 			if(strpos($col,'(')!==false)
 | |
| 				$cols[]=$col;
 | |
| 			else
 | |
| 				$cols[]=$this->quoteColumnName($col);
 | |
| 		}
 | |
| 		return ($unique ? 'CREATE UNIQUE INDEX ' : 'CREATE INDEX ')
 | |
| 			. $this->quoteTableName($name).' ON '
 | |
| 			. $this->quoteTableName($table).' ('.implode(', ',$cols).')';
 | |
| 	}
 | |
| 	public function dropIndex($name, $table)
 | |
| 	{
 | |
| 		return 'DROP INDEX '.$this->quoteTableName($name).' ON '.$this->quoteTableName($table);
 | |
| 	}
 | |
| 	public function addPrimaryKey($name,$table,$columns)
 | |
| 	{
 | |
| 		if(is_string($columns))
 | |
| 			$columns=preg_split('/\s*,\s*/',$columns,-1,PREG_SPLIT_NO_EMPTY);
 | |
| 		foreach($columns as $i=>$col)
 | |
| 			$columns[$i]=$this->quoteColumnName($col);
 | |
| 		return 'ALTER TABLE ' . $this->quoteTableName($table) . ' ADD CONSTRAINT '
 | |
| 			. $this->quoteColumnName($name) . '  PRIMARY KEY ('
 | |
| 			. implode(', ', $columns). ' )';
 | |
| 	}
 | |
| 	public function dropPrimaryKey($name,$table)
 | |
| 	{
 | |
| 		return 'ALTER TABLE ' . $this->quoteTableName($table) . ' DROP CONSTRAINT '
 | |
| 			. $this->quoteColumnName($name);
 | |
| 	}
 | |
| }
 | |
| class CSqliteSchema extends CDbSchema
 | |
| {
 | |
|     public $columnTypes=array(
 | |
|         'pk' => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
 | |
|         'string' => 'varchar(255)',
 | |
|         'text' => 'text',
 | |
|         'integer' => 'integer',
 | |
|         'float' => 'float',
 | |
|         'decimal' => 'decimal',
 | |
|         'datetime' => 'datetime',
 | |
|         'timestamp' => 'timestamp',
 | |
|         'time' => 'time',
 | |
|         'date' => 'date',
 | |
|         'binary' => 'blob',
 | |
|         'boolean' => 'tinyint(1)',
 | |
| 		'money' => 'decimal(19,4)',
 | |
| 	);
 | |
| 	public function resetSequence($table,$value=null)
 | |
| 	{
 | |
| 		if($table->sequenceName===null)
 | |
| 			return;
 | |
| 		if($value!==null)
 | |
| 			$value=(int)($value)-1;
 | |
| 		else
 | |
| 			$value=(int)$this->getDbConnection()
 | |
| 				->createCommand("SELECT MAX(`{$table->primaryKey}`) FROM {$table->rawName}")
 | |
| 				->queryScalar();
 | |
| 		try
 | |
| 		{
 | |
| 			// it's possible that 'sqlite_sequence' does not exist
 | |
| 			$this->getDbConnection()
 | |
| 				->createCommand("UPDATE sqlite_sequence SET seq='$value' WHERE name='{$table->name}'")
 | |
| 				->execute();
 | |
| 		}
 | |
| 		catch(Exception $e)
 | |
| 		{
 | |
| 		}
 | |
| 	}
 | |
| 	public function checkIntegrity($check=true,$schema='')
 | |
| 	{
 | |
| 		$this->getDbConnection()->createCommand('PRAGMA foreign_keys='.(int)$check)->execute();
 | |
| 	}
 | |
| 	protected function findTableNames($schema='')
 | |
| 	{
 | |
| 		$sql="SELECT DISTINCT tbl_name FROM sqlite_master WHERE tbl_name<>'sqlite_sequence'";
 | |
| 		return $this->getDbConnection()->createCommand($sql)->queryColumn();
 | |
| 	}
 | |
| 	protected function createCommandBuilder()
 | |
| 	{
 | |
| 		return new CSqliteCommandBuilder($this);
 | |
| 	}
 | |
| 	protected function loadTable($name)
 | |
| 	{
 | |
| 		$table=new CDbTableSchema;
 | |
| 		$table->name=$name;
 | |
| 		$table->rawName=$this->quoteTableName($name);
 | |
| 		if($this->findColumns($table))
 | |
| 		{
 | |
| 			$this->findConstraints($table);
 | |
| 			return $table;
 | |
| 		}
 | |
| 		else
 | |
| 			return null;
 | |
| 	}
 | |
| 	protected function findColumns($table)
 | |
| 	{
 | |
| 		$sql="PRAGMA table_info({$table->rawName})";
 | |
| 		$columns=$this->getDbConnection()->createCommand($sql)->queryAll();
 | |
| 		if(empty($columns))
 | |
| 			return false;
 | |
| 		foreach($columns as $column)
 | |
| 		{
 | |
| 			$c=$this->createColumn($column);
 | |
| 			$table->columns[$c->name]=$c;
 | |
| 			if($c->isPrimaryKey)
 | |
| 			{
 | |
| 				if($table->primaryKey===null)
 | |
| 					$table->primaryKey=$c->name;
 | |
| 				elseif(is_string($table->primaryKey))
 | |
| 					$table->primaryKey=array($table->primaryKey,$c->name);
 | |
| 				else
 | |
| 					$table->primaryKey[]=$c->name;
 | |
| 			}
 | |
| 		}
 | |
| 		if(is_string($table->primaryKey) && !strncasecmp($table->columns[$table->primaryKey]->dbType,'int',3))
 | |
| 		{
 | |
| 			$table->sequenceName='';
 | |
| 			$table->columns[$table->primaryKey]->autoIncrement=true;
 | |
| 		}
 | |
| 		return true;
 | |
| 	}
 | |
| 	protected function findConstraints($table)
 | |
| 	{
 | |
| 		$foreignKeys=array();
 | |
| 		$sql="PRAGMA foreign_key_list({$table->rawName})";
 | |
| 		$keys=$this->getDbConnection()->createCommand($sql)->queryAll();
 | |
| 		foreach($keys as $key)
 | |
| 		{
 | |
| 			$column=$table->columns[$key['from']];
 | |
| 			$column->isForeignKey=true;
 | |
| 			$foreignKeys[$key['from']]=array($key['table'],$key['to']);
 | |
| 		}
 | |
| 		$table->foreignKeys=$foreignKeys;
 | |
| 	}
 | |
| 	protected function createColumn($column)
 | |
| 	{
 | |
| 		$c=new CSqliteColumnSchema;
 | |
| 		$c->name=$column['name'];
 | |
| 		$c->rawName=$this->quoteColumnName($c->name);
 | |
| 		$c->allowNull=!$column['notnull'];
 | |
| 		$c->isPrimaryKey=$column['pk']!=0;
 | |
| 		$c->isForeignKey=false;
 | |
| 		$c->comment=null; // SQLite does not support column comments at all
 | |
| 		$c->init(strtolower($column['type']),$column['dflt_value']);
 | |
| 		return $c;
 | |
| 	}
 | |
| 	public function renameTable($table, $newName)
 | |
| 	{
 | |
| 		return 'ALTER TABLE ' . $this->quoteTableName($table) . ' RENAME TO ' . $this->quoteTableName($newName);
 | |
| 	}
 | |
| 	public function truncateTable($table)
 | |
| 	{
 | |
| 		return "DELETE FROM ".$this->quoteTableName($table);
 | |
| 	}
 | |
| 	public function dropColumn($table, $column)
 | |
| 	{
 | |
| 		throw new CDbException(Yii::t('yii', 'Dropping DB column is not supported by SQLite.'));
 | |
| 	}
 | |
| 	public function renameColumn($table, $name, $newName)
 | |
| 	{
 | |
| 		throw new CDbException(Yii::t('yii', 'Renaming a DB column is not supported by SQLite.'));
 | |
| 	}
 | |
| 	public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete=null, $update=null)
 | |
| 	{
 | |
| 		throw new CDbException(Yii::t('yii', 'Adding a foreign key constraint to an existing table is not supported by SQLite.'));
 | |
| 	}
 | |
| 	public function dropForeignKey($name, $table)
 | |
| 	{
 | |
| 		throw new CDbException(Yii::t('yii', 'Dropping a foreign key constraint is not supported by SQLite.'));
 | |
| 	}
 | |
| 	public function alterColumn($table, $column, $type)
 | |
| 	{
 | |
| 		throw new CDbException(Yii::t('yii', 'Altering a DB column is not supported by SQLite.'));
 | |
| 	}
 | |
| 	public function dropIndex($name, $table)
 | |
| 	{
 | |
| 		return 'DROP INDEX '.$this->quoteTableName($name);
 | |
| 	}
 | |
| 	public function addPrimaryKey($name,$table,$columns)
 | |
| 	{
 | |
| 		throw new CDbException(Yii::t('yii', 'Adding a primary key after table has been created is not supported by SQLite.'));
 | |
| 	}
 | |
| 	public function dropPrimaryKey($name,$table)
 | |
| 	{
 | |
| 		throw new CDbException(Yii::t('yii', 'Removing a primary key after table has been created is not supported by SQLite.'));
 | |
| 	}
 | |
| }
 | |
| class CDbTableSchema extends CComponent
 | |
| {
 | |
| 	public $name;
 | |
| 	public $rawName;
 | |
| 	public $primaryKey;
 | |
| 	public $sequenceName;
 | |
| 	public $foreignKeys=array();
 | |
| 	public $columns=array();
 | |
| 	public function getColumn($name)
 | |
| 	{
 | |
| 		return isset($this->columns[$name]) ? $this->columns[$name] : null;
 | |
| 	}
 | |
| 	public function getColumnNames()
 | |
| 	{
 | |
| 		return array_keys($this->columns);
 | |
| 	}
 | |
| }
 | |
| class CDbCommand extends CComponent
 | |
| {
 | |
| 	public $params=array();
 | |
| 	private $_connection;
 | |
| 	private $_text;
 | |
| 	private $_statement;
 | |
| 	private $_paramLog=array();
 | |
| 	private $_query;
 | |
| 	private $_fetchMode = array(PDO::FETCH_ASSOC);
 | |
| 	public function __construct(CDbConnection $connection,$query=null)
 | |
| 	{
 | |
| 		$this->_connection=$connection;
 | |
| 		if(is_array($query))
 | |
| 		{
 | |
| 			foreach($query as $name=>$value)
 | |
| 				$this->$name=$value;
 | |
| 		}
 | |
| 		else
 | |
| 			$this->setText($query);
 | |
| 	}
 | |
| 	public function __sleep()
 | |
| 	{
 | |
| 		$this->_statement=null;
 | |
| 		return array_keys(get_object_vars($this));
 | |
| 	}
 | |
| 	public function setFetchMode($mode)
 | |
| 	{
 | |
| 		$params=func_get_args();
 | |
| 		$this->_fetchMode = $params;
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function reset()
 | |
| 	{
 | |
| 		$this->_text=null;
 | |
| 		$this->_query=null;
 | |
| 		$this->_statement=null;
 | |
| 		$this->_paramLog=array();
 | |
| 		$this->params=array();
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function getText()
 | |
| 	{
 | |
| 		if($this->_text=='' && !empty($this->_query))
 | |
| 			$this->setText($this->buildQuery($this->_query));
 | |
| 		return $this->_text;
 | |
| 	}
 | |
| 	public function setText($value)
 | |
| 	{
 | |
| 		if($this->_connection->tablePrefix!==null && $value!='')
 | |
| 			$this->_text=preg_replace('/{{(.*?)}}/',$this->_connection->tablePrefix.'\1',$value);
 | |
| 		else
 | |
| 			$this->_text=$value;
 | |
| 		$this->cancel();
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function getConnection()
 | |
| 	{
 | |
| 		return $this->_connection;
 | |
| 	}
 | |
| 	public function getPdoStatement()
 | |
| 	{
 | |
| 		return $this->_statement;
 | |
| 	}
 | |
| 	public function prepare()
 | |
| 	{
 | |
| 		if($this->_statement==null)
 | |
| 		{
 | |
| 			try
 | |
| 			{
 | |
| 				$this->_statement=$this->getConnection()->getPdoInstance()->prepare($this->getText());
 | |
| 				$this->_paramLog=array();
 | |
| 			}
 | |
| 			catch(Exception $e)
 | |
| 			{
 | |
| 				Yii::log('Error in preparing SQL: '.$this->getText(),CLogger::LEVEL_ERROR,'system.db.CDbCommand');
 | |
| 				$errorInfo=$e instanceof PDOException ? $e->errorInfo : null;
 | |
| 				throw new CDbException(Yii::t('yii','CDbCommand failed to prepare the SQL statement: {error}',
 | |
| 					array('{error}'=>$e->getMessage())),(int)$e->getCode(),$errorInfo);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	public function cancel()
 | |
| 	{
 | |
| 		$this->_statement=null;
 | |
| 	}
 | |
| 	public function bindParam($name, &$value, $dataType=null, $length=null, $driverOptions=null)
 | |
| 	{
 | |
| 		$this->prepare();
 | |
| 		if($dataType===null)
 | |
| 			$this->_statement->bindParam($name,$value,$this->_connection->getPdoType(gettype($value)));
 | |
| 		elseif($length===null)
 | |
| 			$this->_statement->bindParam($name,$value,$dataType);
 | |
| 		elseif($driverOptions===null)
 | |
| 			$this->_statement->bindParam($name,$value,$dataType,$length);
 | |
| 		else
 | |
| 			$this->_statement->bindParam($name,$value,$dataType,$length,$driverOptions);
 | |
| 		$this->_paramLog[$name]=&$value;
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function bindValue($name, $value, $dataType=null)
 | |
| 	{
 | |
| 		$this->prepare();
 | |
| 		if($dataType===null)
 | |
| 			$this->_statement->bindValue($name,$value,$this->_connection->getPdoType(gettype($value)));
 | |
| 		else
 | |
| 			$this->_statement->bindValue($name,$value,$dataType);
 | |
| 		$this->_paramLog[$name]=$value;
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function bindValues($values)
 | |
| 	{
 | |
| 		$this->prepare();
 | |
| 		foreach($values as $name=>$value)
 | |
| 		{
 | |
| 			$this->_statement->bindValue($name,$value,$this->_connection->getPdoType(gettype($value)));
 | |
| 			$this->_paramLog[$name]=$value;
 | |
| 		}
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function execute($params=array())
 | |
| 	{
 | |
| 		if($this->_connection->enableParamLogging && ($pars=array_merge($this->_paramLog,$params))!==array())
 | |
| 		{
 | |
| 			$p=array();
 | |
| 			foreach($pars as $name=>$value)
 | |
| 				$p[$name]=$name.'='.var_export($value,true);
 | |
| 			$par='. Bound with ' .implode(', ',$p);
 | |
| 		}
 | |
| 		else
 | |
| 			$par='';
 | |
| 		try
 | |
| 		{
 | |
| 			if($this->_connection->enableProfiling)
 | |
| 				Yii::beginProfile('system.db.CDbCommand.execute('.$this->getText().$par.')','system.db.CDbCommand.execute');
 | |
| 			$this->prepare();
 | |
| 			if($params===array())
 | |
| 				$this->_statement->execute();
 | |
| 			else
 | |
| 				$this->_statement->execute($params);
 | |
| 			$n=$this->_statement->rowCount();
 | |
| 			if($this->_connection->enableProfiling)
 | |
| 				Yii::endProfile('system.db.CDbCommand.execute('.$this->getText().$par.')','system.db.CDbCommand.execute');
 | |
| 			return $n;
 | |
| 		}
 | |
| 		catch(Exception $e)
 | |
| 		{
 | |
| 			if($this->_connection->enableProfiling)
 | |
| 				Yii::endProfile('system.db.CDbCommand.execute('.$this->getText().$par.')','system.db.CDbCommand.execute');
 | |
| 			$errorInfo=$e instanceof PDOException ? $e->errorInfo : null;
 | |
| 			$message=$e->getMessage();
 | |
| 			Yii::log(Yii::t('yii','CDbCommand::execute() failed: {error}. The SQL statement executed was: {sql}.',
 | |
| 				array('{error}'=>$message, '{sql}'=>$this->getText().$par)),CLogger::LEVEL_ERROR,'system.db.CDbCommand');
 | |
| 			if(YII_DEBUG)
 | |
| 				$message.='. The SQL statement executed was: '.$this->getText().$par;
 | |
| 			throw new CDbException(Yii::t('yii','CDbCommand failed to execute the SQL statement: {error}',
 | |
| 				array('{error}'=>$message)),(int)$e->getCode(),$errorInfo);
 | |
| 		}
 | |
| 	}
 | |
| 	public function query($params=array())
 | |
| 	{
 | |
| 		return $this->queryInternal('',0,$params);
 | |
| 	}
 | |
| 	public function queryAll($fetchAssociative=true,$params=array())
 | |
| 	{
 | |
| 		return $this->queryInternal('fetchAll',$fetchAssociative ? $this->_fetchMode : PDO::FETCH_NUM, $params);
 | |
| 	}
 | |
| 	public function queryRow($fetchAssociative=true,$params=array())
 | |
| 	{
 | |
| 		return $this->queryInternal('fetch',$fetchAssociative ? $this->_fetchMode : PDO::FETCH_NUM, $params);
 | |
| 	}
 | |
| 	public function queryScalar($params=array())
 | |
| 	{
 | |
| 		$result=$this->queryInternal('fetchColumn',0,$params);
 | |
| 		if(is_resource($result) && get_resource_type($result)==='stream')
 | |
| 			return stream_get_contents($result);
 | |
| 		else
 | |
| 			return $result;
 | |
| 	}
 | |
| 	public function queryColumn($params=array())
 | |
| 	{
 | |
| 		return $this->queryInternal('fetchAll',array(PDO::FETCH_COLUMN, 0),$params);
 | |
| 	}
 | |
| 	private function queryInternal($method,$mode,$params=array())
 | |
| 	{
 | |
| 		$params=array_merge($this->params,$params);
 | |
| 		if($this->_connection->enableParamLogging && ($pars=array_merge($this->_paramLog,$params))!==array())
 | |
| 		{
 | |
| 			$p=array();
 | |
| 			foreach($pars as $name=>$value)
 | |
| 				$p[$name]=$name.'='.var_export($value,true);
 | |
| 			$par='. Bound with '.implode(', ',$p);
 | |
| 		}
 | |
| 		else
 | |
| 			$par='';
 | |
| 		if($this->_connection->queryCachingCount>0 && $method!==''
 | |
| 				&& $this->_connection->queryCachingDuration>0
 | |
| 				&& $this->_connection->queryCacheID!==false
 | |
| 				&& ($cache=Yii::app()->getComponent($this->_connection->queryCacheID))!==null)
 | |
| 		{
 | |
| 			$this->_connection->queryCachingCount--;
 | |
| 			$cacheKey='yii:dbquery'.$this->_connection->connectionString.':'.$this->_connection->username;
 | |
| 			$cacheKey.=':'.$this->getText().':'.serialize(array_merge($this->_paramLog,$params));
 | |
| 			if(($result=$cache->get($cacheKey))!==false)
 | |
| 			{
 | |
| 				return $result[0];
 | |
| 			}
 | |
| 		}
 | |
| 		try
 | |
| 		{
 | |
| 			if($this->_connection->enableProfiling)
 | |
| 				Yii::beginProfile('system.db.CDbCommand.query('.$this->getText().$par.')','system.db.CDbCommand.query');
 | |
| 			$this->prepare();
 | |
| 			if($params===array())
 | |
| 				$this->_statement->execute();
 | |
| 			else
 | |
| 				$this->_statement->execute($params);
 | |
| 			if($method==='')
 | |
| 				$result=new CDbDataReader($this);
 | |
| 			else
 | |
| 			{
 | |
| 				$mode=(array)$mode;
 | |
| 				call_user_func_array(array($this->_statement, 'setFetchMode'), $mode);
 | |
| 				$result=$this->_statement->$method();
 | |
| 				$this->_statement->closeCursor();
 | |
| 			}
 | |
| 			if($this->_connection->enableProfiling)
 | |
| 				Yii::endProfile('system.db.CDbCommand.query('.$this->getText().$par.')','system.db.CDbCommand.query');
 | |
| 			if(isset($cache,$cacheKey))
 | |
| 				$cache->set($cacheKey, array($result), $this->_connection->queryCachingDuration, $this->_connection->queryCachingDependency);
 | |
| 			return $result;
 | |
| 		}
 | |
| 		catch(Exception $e)
 | |
| 		{
 | |
| 			if($this->_connection->enableProfiling)
 | |
| 				Yii::endProfile('system.db.CDbCommand.query('.$this->getText().$par.')','system.db.CDbCommand.query');
 | |
| 			$errorInfo=$e instanceof PDOException ? $e->errorInfo : null;
 | |
| 			$message=$e->getMessage();
 | |
| 			Yii::log(Yii::t('yii','CDbCommand::{method}() failed: {error}. The SQL statement executed was: {sql}.',
 | |
| 				array('{method}'=>$method, '{error}'=>$message, '{sql}'=>$this->getText().$par)),CLogger::LEVEL_ERROR,'system.db.CDbCommand');
 | |
| 			if(YII_DEBUG)
 | |
| 				$message.='. The SQL statement executed was: '.$this->getText().$par;
 | |
| 			throw new CDbException(Yii::t('yii','CDbCommand failed to execute the SQL statement: {error}',
 | |
| 				array('{error}'=>$message)),(int)$e->getCode(),$errorInfo);
 | |
| 		}
 | |
| 	}
 | |
| 	public function buildQuery($query)
 | |
| 	{
 | |
| 		$sql=!empty($query['distinct']) ? 'SELECT DISTINCT' : 'SELECT';
 | |
| 		$sql.=' '.(!empty($query['select']) ? $query['select'] : '*');
 | |
| 		if(!empty($query['from']))
 | |
| 			$sql.="\nFROM ".$query['from'];
 | |
| 		else
 | |
| 			throw new CDbException(Yii::t('yii','The DB query must contain the "from" portion.'));
 | |
| 		if(!empty($query['join']))
 | |
| 			$sql.="\n".(is_array($query['join']) ? implode("\n",$query['join']) : $query['join']);
 | |
| 		if(!empty($query['where']))
 | |
| 			$sql.="\nWHERE ".$query['where'];
 | |
| 		if(!empty($query['group']))
 | |
| 			$sql.="\nGROUP BY ".$query['group'];
 | |
| 		if(!empty($query['having']))
 | |
| 			$sql.="\nHAVING ".$query['having'];
 | |
| 		if(!empty($query['union']))
 | |
| 			$sql.="\nUNION (\n".(is_array($query['union']) ? implode("\n) UNION (\n",$query['union']) : $query['union']) . ')';
 | |
| 		if(!empty($query['order']))
 | |
| 			$sql.="\nORDER BY ".$query['order'];
 | |
| 		$limit=isset($query['limit']) ? (int)$query['limit'] : -1;
 | |
| 		$offset=isset($query['offset']) ? (int)$query['offset'] : -1;
 | |
| 		if($limit>=0 || $offset>0)
 | |
| 			$sql=$this->_connection->getCommandBuilder()->applyLimit($sql,$limit,$offset);
 | |
| 		return $sql;
 | |
| 	}
 | |
| 	public function select($columns='*', $option='')
 | |
| 	{
 | |
| 		if(is_string($columns) && strpos($columns,'(')!==false)
 | |
| 			$this->_query['select']=$columns;
 | |
| 		else
 | |
| 		{
 | |
| 			if(!is_array($columns))
 | |
| 				$columns=preg_split('/\s*,\s*/',trim($columns),-1,PREG_SPLIT_NO_EMPTY);
 | |
| 			foreach($columns as $i=>$column)
 | |
| 			{
 | |
| 				if(is_object($column))
 | |
| 					$columns[$i]=(string)$column;
 | |
| 				elseif(strpos($column,'(')===false)
 | |
| 				{
 | |
| 					if(preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/',$column,$matches))
 | |
| 						$columns[$i]=$this->_connection->quoteColumnName($matches[1]).' AS '.$this->_connection->quoteColumnName($matches[2]);
 | |
| 					else
 | |
| 						$columns[$i]=$this->_connection->quoteColumnName($column);
 | |
| 				}
 | |
| 			}
 | |
| 			$this->_query['select']=implode(', ',$columns);
 | |
| 		}
 | |
| 		if($option!='')
 | |
| 			$this->_query['select']=$option.' '.$this->_query['select'];
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function getSelect()
 | |
| 	{
 | |
| 		return isset($this->_query['select']) ? $this->_query['select'] : '';
 | |
| 	}
 | |
| 	public function setSelect($value)
 | |
| 	{
 | |
| 		$this->select($value);
 | |
| 	}
 | |
| 	public function selectDistinct($columns='*')
 | |
| 	{
 | |
| 		$this->_query['distinct']=true;
 | |
| 		return $this->select($columns);
 | |
| 	}
 | |
| 	public function getDistinct()
 | |
| 	{
 | |
| 		return isset($this->_query['distinct']) ? $this->_query['distinct'] : false;
 | |
| 	}
 | |
| 	public function setDistinct($value)
 | |
| 	{
 | |
| 		$this->_query['distinct']=$value;
 | |
| 	}
 | |
| 	public function from($tables)
 | |
| 	{
 | |
| 		if(is_string($tables) && strpos($tables,'(')!==false)
 | |
| 			$this->_query['from']=$tables;
 | |
| 		else
 | |
| 		{
 | |
| 			if(!is_array($tables))
 | |
| 				$tables=preg_split('/\s*,\s*/',trim($tables),-1,PREG_SPLIT_NO_EMPTY);
 | |
| 			foreach($tables as $i=>$table)
 | |
| 			{
 | |
| 				if(strpos($table,'(')===false)
 | |
| 				{
 | |
| 					if(preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/',$table,$matches))  // with alias
 | |
| 						$tables[$i]=$this->_connection->quoteTableName($matches[1]).' '.$this->_connection->quoteTableName($matches[2]);
 | |
| 					else
 | |
| 						$tables[$i]=$this->_connection->quoteTableName($table);
 | |
| 				}
 | |
| 			}
 | |
| 			$this->_query['from']=implode(', ',$tables);
 | |
| 		}
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function getFrom()
 | |
| 	{
 | |
| 		return isset($this->_query['from']) ? $this->_query['from'] : '';
 | |
| 	}
 | |
| 	public function setFrom($value)
 | |
| 	{
 | |
| 		$this->from($value);
 | |
| 	}
 | |
| 	public function where($conditions, $params=array())
 | |
| 	{
 | |
| 		$this->_query['where']=$this->processConditions($conditions);
 | |
| 		foreach($params as $name=>$value)
 | |
| 			$this->params[$name]=$value;
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function andWhere($conditions,$params=array())
 | |
| 	{
 | |
| 		if(isset($this->_query['where']))
 | |
| 			$this->_query['where']=$this->processConditions(array('AND',$this->_query['where'],$conditions));
 | |
| 		else
 | |
| 			$this->_query['where']=$this->processConditions($conditions);
 | |
| 		foreach($params as $name=>$value)
 | |
| 			$this->params[$name]=$value;
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function orWhere($conditions,$params=array())
 | |
| 	{
 | |
| 		if(isset($this->_query['where']))
 | |
| 			$this->_query['where']=$this->processConditions(array('OR',$this->_query['where'],$conditions));
 | |
| 		else
 | |
| 			$this->_query['where']=$this->processConditions($conditions);
 | |
| 		foreach($params as $name=>$value)
 | |
| 			$this->params[$name]=$value;
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function getWhere()
 | |
| 	{
 | |
| 		return isset($this->_query['where']) ? $this->_query['where'] : '';
 | |
| 	}
 | |
| 	public function setWhere($value)
 | |
| 	{
 | |
| 		$this->where($value);
 | |
| 	}
 | |
| 	public function join($table, $conditions, $params=array())
 | |
| 	{
 | |
| 		return $this->joinInternal('join', $table, $conditions, $params);
 | |
| 	}
 | |
| 	public function getJoin()
 | |
| 	{
 | |
| 		return isset($this->_query['join']) ? $this->_query['join'] : '';
 | |
| 	}
 | |
| 	public function setJoin($value)
 | |
| 	{
 | |
| 		$this->_query['join']=$value;
 | |
| 	}
 | |
| 	public function leftJoin($table, $conditions, $params=array())
 | |
| 	{
 | |
| 		return $this->joinInternal('left join', $table, $conditions, $params);
 | |
| 	}
 | |
| 	public function rightJoin($table, $conditions, $params=array())
 | |
| 	{
 | |
| 		return $this->joinInternal('right join', $table, $conditions, $params);
 | |
| 	}
 | |
| 	public function crossJoin($table)
 | |
| 	{
 | |
| 		return $this->joinInternal('cross join', $table);
 | |
| 	}
 | |
| 	public function naturalJoin($table)
 | |
| 	{
 | |
| 		return $this->joinInternal('natural join', $table);
 | |
| 	}
 | |
| 	public function group($columns)
 | |
| 	{
 | |
| 		if(is_string($columns) && strpos($columns,'(')!==false)
 | |
| 			$this->_query['group']=$columns;
 | |
| 		else
 | |
| 		{
 | |
| 			if(!is_array($columns))
 | |
| 				$columns=preg_split('/\s*,\s*/',trim($columns),-1,PREG_SPLIT_NO_EMPTY);
 | |
| 			foreach($columns as $i=>$column)
 | |
| 			{
 | |
| 				if(is_object($column))
 | |
| 					$columns[$i]=(string)$column;
 | |
| 				elseif(strpos($column,'(')===false)
 | |
| 					$columns[$i]=$this->_connection->quoteColumnName($column);
 | |
| 			}
 | |
| 			$this->_query['group']=implode(', ',$columns);
 | |
| 		}
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function getGroup()
 | |
| 	{
 | |
| 		return isset($this->_query['group']) ? $this->_query['group'] : '';
 | |
| 	}
 | |
| 	public function setGroup($value)
 | |
| 	{
 | |
| 		$this->group($value);
 | |
| 	}
 | |
| 	public function having($conditions, $params=array())
 | |
| 	{
 | |
| 		$this->_query['having']=$this->processConditions($conditions);
 | |
| 		foreach($params as $name=>$value)
 | |
| 			$this->params[$name]=$value;
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function getHaving()
 | |
| 	{
 | |
| 		return isset($this->_query['having']) ? $this->_query['having'] : '';
 | |
| 	}
 | |
| 	public function setHaving($value)
 | |
| 	{
 | |
| 		$this->having($value);
 | |
| 	}
 | |
| 	public function order($columns)
 | |
| 	{
 | |
| 		if(is_string($columns) && strpos($columns,'(')!==false)
 | |
| 			$this->_query['order']=$columns;
 | |
| 		else
 | |
| 		{
 | |
| 			if(!is_array($columns))
 | |
| 				$columns=preg_split('/\s*,\s*/',trim($columns),-1,PREG_SPLIT_NO_EMPTY);
 | |
| 			foreach($columns as $i=>$column)
 | |
| 			{
 | |
| 				if(is_object($column))
 | |
| 					$columns[$i]=(string)$column;
 | |
| 				elseif(strpos($column,'(')===false)
 | |
| 				{
 | |
| 					if(preg_match('/^(.*?)\s+(asc|desc)$/i',$column,$matches))
 | |
| 						$columns[$i]=$this->_connection->quoteColumnName($matches[1]).' '.strtoupper($matches[2]);
 | |
| 					else
 | |
| 						$columns[$i]=$this->_connection->quoteColumnName($column);
 | |
| 				}
 | |
| 			}
 | |
| 			$this->_query['order']=implode(', ',$columns);
 | |
| 		}
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function getOrder()
 | |
| 	{
 | |
| 		return isset($this->_query['order']) ? $this->_query['order'] : '';
 | |
| 	}
 | |
| 	public function setOrder($value)
 | |
| 	{
 | |
| 		$this->order($value);
 | |
| 	}
 | |
| 	public function limit($limit, $offset=null)
 | |
| 	{
 | |
| 		$this->_query['limit']=(int)$limit;
 | |
| 		if($offset!==null)
 | |
| 			$this->offset($offset);
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function getLimit()
 | |
| 	{
 | |
| 		return isset($this->_query['limit']) ? $this->_query['limit'] : -1;
 | |
| 	}
 | |
| 	public function setLimit($value)
 | |
| 	{
 | |
| 		$this->limit($value);
 | |
| 	}
 | |
| 	public function offset($offset)
 | |
| 	{
 | |
| 		$this->_query['offset']=(int)$offset;
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function getOffset()
 | |
| 	{
 | |
| 		return isset($this->_query['offset']) ? $this->_query['offset'] : -1;
 | |
| 	}
 | |
| 	public function setOffset($value)
 | |
| 	{
 | |
| 		$this->offset($value);
 | |
| 	}
 | |
| 	public function union($sql)
 | |
| 	{
 | |
| 		if(isset($this->_query['union']) && is_string($this->_query['union']))
 | |
| 			$this->_query['union']=array($this->_query['union']);
 | |
| 		$this->_query['union'][]=$sql;
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function getUnion()
 | |
| 	{
 | |
| 		return isset($this->_query['union']) ? $this->_query['union'] : '';
 | |
| 	}
 | |
| 	public function setUnion($value)
 | |
| 	{
 | |
| 		$this->_query['union']=$value;
 | |
| 	}
 | |
| 	public function insert($table, $columns)
 | |
| 	{
 | |
| 		$params=array();
 | |
| 		$names=array();
 | |
| 		$placeholders=array();
 | |
| 		foreach($columns as $name=>$value)
 | |
| 		{
 | |
| 			$names[]=$this->_connection->quoteColumnName($name);
 | |
| 			if($value instanceof CDbExpression)
 | |
| 			{
 | |
| 				$placeholders[] = $value->expression;
 | |
| 				foreach($value->params as $n => $v)
 | |
| 					$params[$n] = $v;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				$placeholders[] = ':' . $name;
 | |
| 				$params[':' . $name] = $value;
 | |
| 			}
 | |
| 		}
 | |
| 		$sql='INSERT INTO ' . $this->_connection->quoteTableName($table)
 | |
| 			. ' (' . implode(', ',$names) . ') VALUES ('
 | |
| 			. implode(', ', $placeholders) . ')';
 | |
| 		return $this->setText($sql)->execute($params);
 | |
| 	}
 | |
| 	public function update($table, $columns, $conditions='', $params=array())
 | |
| 	{
 | |
| 		$lines=array();
 | |
| 		foreach($columns as $name=>$value)
 | |
| 		{
 | |
| 			if($value instanceof CDbExpression)
 | |
| 			{
 | |
| 				$lines[]=$this->_connection->quoteColumnName($name) . '=' . $value->expression;
 | |
| 				foreach($value->params as $n => $v)
 | |
| 					$params[$n] = $v;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				$lines[]=$this->_connection->quoteColumnName($name) . '=:' . $name;
 | |
| 				$params[':' . $name]=$value;
 | |
| 			}
 | |
| 		}
 | |
| 		$sql='UPDATE ' . $this->_connection->quoteTableName($table) . ' SET ' . implode(', ', $lines);
 | |
| 		if(($where=$this->processConditions($conditions))!='')
 | |
| 			$sql.=' WHERE '.$where;
 | |
| 		return $this->setText($sql)->execute($params);
 | |
| 	}
 | |
| 	public function delete($table, $conditions='', $params=array())
 | |
| 	{
 | |
| 		$sql='DELETE FROM ' . $this->_connection->quoteTableName($table);
 | |
| 		if(($where=$this->processConditions($conditions))!='')
 | |
| 			$sql.=' WHERE '.$where;
 | |
| 		return $this->setText($sql)->execute($params);
 | |
| 	}
 | |
| 	public function createTable($table, $columns, $options=null)
 | |
| 	{
 | |
| 		return $this->setText($this->getConnection()->getSchema()->createTable($table, $columns, $options))->execute();
 | |
| 	}
 | |
| 	public function renameTable($table, $newName)
 | |
| 	{
 | |
| 		return $this->setText($this->getConnection()->getSchema()->renameTable($table, $newName))->execute();
 | |
| 	}
 | |
| 	public function dropTable($table)
 | |
| 	{
 | |
| 		return $this->setText($this->getConnection()->getSchema()->dropTable($table))->execute();
 | |
| 	}
 | |
| 	public function truncateTable($table)
 | |
| 	{
 | |
| 		$schema=$this->getConnection()->getSchema();
 | |
| 		$n=$this->setText($schema->truncateTable($table))->execute();
 | |
| 		if(strncasecmp($this->getConnection()->getDriverName(),'sqlite',6)===0)
 | |
| 			$schema->resetSequence($schema->getTable($table));
 | |
| 		return $n;
 | |
| 	}
 | |
| 	public function addColumn($table, $column, $type)
 | |
| 	{
 | |
| 		return $this->setText($this->getConnection()->getSchema()->addColumn($table, $column, $type))->execute();
 | |
| 	}
 | |
| 	public function dropColumn($table, $column)
 | |
| 	{
 | |
| 		return $this->setText($this->getConnection()->getSchema()->dropColumn($table, $column))->execute();
 | |
| 	}
 | |
| 	public function renameColumn($table, $name, $newName)
 | |
| 	{
 | |
| 		return $this->setText($this->getConnection()->getSchema()->renameColumn($table, $name, $newName))->execute();
 | |
| 	}
 | |
| 	public function alterColumn($table, $column, $type)
 | |
| 	{
 | |
| 		return $this->setText($this->getConnection()->getSchema()->alterColumn($table, $column, $type))->execute();
 | |
| 	}
 | |
| 	public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete=null, $update=null)
 | |
| 	{
 | |
| 		return $this->setText($this->getConnection()->getSchema()->addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete, $update))->execute();
 | |
| 	}
 | |
| 	public function dropForeignKey($name, $table)
 | |
| 	{
 | |
| 		return $this->setText($this->getConnection()->getSchema()->dropForeignKey($name, $table))->execute();
 | |
| 	}
 | |
| 	public function createIndex($name, $table, $column, $unique=false)
 | |
| 	{
 | |
| 		return $this->setText($this->getConnection()->getSchema()->createIndex($name, $table, $column, $unique))->execute();
 | |
| 	}
 | |
| 	public function dropIndex($name, $table)
 | |
| 	{
 | |
| 		return $this->setText($this->getConnection()->getSchema()->dropIndex($name, $table))->execute();
 | |
| 	}
 | |
| 	private function processConditions($conditions)
 | |
| 	{
 | |
| 		if(!is_array($conditions))
 | |
| 			return $conditions;
 | |
| 		elseif($conditions===array())
 | |
| 			return '';
 | |
| 		$n=count($conditions);
 | |
| 		$operator=strtoupper($conditions[0]);
 | |
| 		if($operator==='OR' || $operator==='AND')
 | |
| 		{
 | |
| 			$parts=array();
 | |
| 			for($i=1;$i<$n;++$i)
 | |
| 			{
 | |
| 				$condition=$this->processConditions($conditions[$i]);
 | |
| 				if($condition!=='')
 | |
| 					$parts[]='('.$condition.')';
 | |
| 			}
 | |
| 			return $parts===array() ? '' : implode(' '.$operator.' ', $parts);
 | |
| 		}
 | |
| 		if(!isset($conditions[1],$conditions[2]))
 | |
| 			return '';
 | |
| 		$column=$conditions[1];
 | |
| 		if(strpos($column,'(')===false)
 | |
| 			$column=$this->_connection->quoteColumnName($column);
 | |
| 		$values=$conditions[2];
 | |
| 		if(!is_array($values))
 | |
| 			$values=array($values);
 | |
| 		if($operator==='IN' || $operator==='NOT IN')
 | |
| 		{
 | |
| 			if($values===array())
 | |
| 				return $operator==='IN' ? '0=1' : '';
 | |
| 			foreach($values as $i=>$value)
 | |
| 			{
 | |
| 				if(is_string($value))
 | |
| 					$values[$i]=$this->_connection->quoteValue($value);
 | |
| 				else
 | |
| 					$values[$i]=(string)$value;
 | |
| 			}
 | |
| 			return $column.' '.$operator.' ('.implode(', ',$values).')';
 | |
| 		}
 | |
| 		if($operator==='LIKE' || $operator==='NOT LIKE' || $operator==='OR LIKE' || $operator==='OR NOT LIKE')
 | |
| 		{
 | |
| 			if($values===array())
 | |
| 				return $operator==='LIKE' || $operator==='OR LIKE' ? '0=1' : '';
 | |
| 			if($operator==='LIKE' || $operator==='NOT LIKE')
 | |
| 				$andor=' AND ';
 | |
| 			else
 | |
| 			{
 | |
| 				$andor=' OR ';
 | |
| 				$operator=$operator==='OR LIKE' ? 'LIKE' : 'NOT LIKE';
 | |
| 			}
 | |
| 			$expressions=array();
 | |
| 			foreach($values as $value)
 | |
| 				$expressions[]=$column.' '.$operator.' '.$this->_connection->quoteValue($value);
 | |
| 			return implode($andor,$expressions);
 | |
| 		}
 | |
| 		throw new CDbException(Yii::t('yii', 'Unknown operator "{operator}".', array('{operator}'=>$operator)));
 | |
| 	}
 | |
| 	private function joinInternal($type, $table, $conditions='', $params=array())
 | |
| 	{
 | |
| 		if(strpos($table,'(')===false)
 | |
| 		{
 | |
| 			if(preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/',$table,$matches))  // with alias
 | |
| 				$table=$this->_connection->quoteTableName($matches[1]).' '.$this->_connection->quoteTableName($matches[2]);
 | |
| 			else
 | |
| 				$table=$this->_connection->quoteTableName($table);
 | |
| 		}
 | |
| 		$conditions=$this->processConditions($conditions);
 | |
| 		if($conditions!='')
 | |
| 			$conditions=' ON '.$conditions;
 | |
| 		if(isset($this->_query['join']) && is_string($this->_query['join']))
 | |
| 			$this->_query['join']=array($this->_query['join']);
 | |
| 		$this->_query['join'][]=strtoupper($type) . ' ' . $table . $conditions;
 | |
| 		foreach($params as $name=>$value)
 | |
| 			$this->params[$name]=$value;
 | |
| 		return $this;
 | |
| 	}
 | |
| 	public function addPrimaryKey($name,$table,$columns)
 | |
| 	{
 | |
| 		return $this->setText($this->getConnection()->getSchema()->addPrimaryKey($name,$table,$columns))->execute();
 | |
| 	}
 | |
| 	public function dropPrimaryKey($name,$table)
 | |
| 	{
 | |
| 		return $this->setText($this->getConnection()->getSchema()->dropPrimaryKey($name,$table))->execute();
 | |
| 	}
 | |
| }
 | |
| class CDbColumnSchema extends CComponent
 | |
| {
 | |
| 	public $name;
 | |
| 	public $rawName;
 | |
| 	public $allowNull;
 | |
| 	public $dbType;
 | |
| 	public $type;
 | |
| 	public $defaultValue;
 | |
| 	public $size;
 | |
| 	public $precision;
 | |
| 	public $scale;
 | |
| 	public $isPrimaryKey;
 | |
| 	public $isForeignKey;
 | |
| 	public $autoIncrement=false;
 | |
| 	public $comment='';
 | |
| 	public function init($dbType, $defaultValue)
 | |
| 	{
 | |
| 		$this->dbType=$dbType;
 | |
| 		$this->extractType($dbType);
 | |
| 		$this->extractLimit($dbType);
 | |
| 		if($defaultValue!==null)
 | |
| 			$this->extractDefault($defaultValue);
 | |
| 	}
 | |
| 	protected function extractType($dbType)
 | |
| 	{
 | |
| 		if(stripos($dbType,'int')!==false && stripos($dbType,'unsigned int')===false)
 | |
| 			$this->type='integer';
 | |
| 		elseif(stripos($dbType,'bool')!==false)
 | |
| 			$this->type='boolean';
 | |
| 		elseif(preg_match('/(real|floa|doub)/i',$dbType))
 | |
| 			$this->type='double';
 | |
| 		else
 | |
| 			$this->type='string';
 | |
| 	}
 | |
| 	protected function extractLimit($dbType)
 | |
| 	{
 | |
| 		if(strpos($dbType,'(') && preg_match('/\((.*)\)/',$dbType,$matches))
 | |
| 		{
 | |
| 			$values=explode(',',$matches[1]);
 | |
| 			$this->size=$this->precision=(int)$values[0];
 | |
| 			if(isset($values[1]))
 | |
| 				$this->scale=(int)$values[1];
 | |
| 		}
 | |
| 	}
 | |
| 	protected function extractDefault($defaultValue)
 | |
| 	{
 | |
| 		$this->defaultValue=$this->typecast($defaultValue);
 | |
| 	}
 | |
| 	public function typecast($value)
 | |
| 	{
 | |
| 		if(gettype($value)===$this->type || $value===null || $value instanceof CDbExpression)
 | |
| 			return $value;
 | |
| 		if($value==='' && $this->allowNull)
 | |
| 			return $this->type==='string' ? '' : null;
 | |
| 		switch($this->type)
 | |
| 		{
 | |
| 			case 'string': return (string)$value;
 | |
| 			case 'integer': return (integer)$value;
 | |
| 			case 'boolean': return (boolean)$value;
 | |
| 			case 'double':
 | |
| 			default: return $value;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| class CSqliteColumnSchema extends CDbColumnSchema
 | |
| {
 | |
| 	protected function extractDefault($defaultValue)
 | |
| 	{
 | |
| 		if($this->dbType==='timestamp' && $defaultValue==='CURRENT_TIMESTAMP')
 | |
| 			$this->defaultValue=null;
 | |
| 		else
 | |
| 			$this->defaultValue=$this->typecast(strcasecmp($defaultValue,'null') ? $defaultValue : null);
 | |
| 		if($this->type==='string' && $this->defaultValue!==null) // PHP 5.2.6 adds single quotes while 5.2.0 doesn't
 | |
| 			$this->defaultValue=trim($this->defaultValue,"'\"");
 | |
| 	}
 | |
| }
 | |
| abstract class CValidator extends CComponent
 | |
| {
 | |
| 	public static $builtInValidators=array(
 | |
| 		'required'=>'CRequiredValidator',
 | |
| 		'filter'=>'CFilterValidator',
 | |
| 		'match'=>'CRegularExpressionValidator',
 | |
| 		'email'=>'CEmailValidator',
 | |
| 		'url'=>'CUrlValidator',
 | |
| 		'unique'=>'CUniqueValidator',
 | |
| 		'compare'=>'CCompareValidator',
 | |
| 		'length'=>'CStringValidator',
 | |
| 		'in'=>'CRangeValidator',
 | |
| 		'numerical'=>'CNumberValidator',
 | |
| 		'captcha'=>'CCaptchaValidator',
 | |
| 		'type'=>'CTypeValidator',
 | |
| 		'file'=>'CFileValidator',
 | |
| 		'default'=>'CDefaultValueValidator',
 | |
| 		'exist'=>'CExistValidator',
 | |
| 		'boolean'=>'CBooleanValidator',
 | |
| 		'safe'=>'CSafeValidator',
 | |
| 		'unsafe'=>'CUnsafeValidator',
 | |
| 		'date'=>'CDateValidator',
 | |
| 	);
 | |
| 	public $attributes;
 | |
| 	public $message;
 | |
| 	public $skipOnError=false;
 | |
| 	public $on;
 | |
| 	public $except;
 | |
| 	public $safe=true;
 | |
| 	public $enableClientValidation=true;
 | |
| 	abstract protected function validateAttribute($object,$attribute);
 | |
| 	public static function createValidator($name,$object,$attributes,$params=array())
 | |
| 	{
 | |
| 		if(is_string($attributes))
 | |
| 			$attributes=preg_split('/[\s,]+/',$attributes,-1,PREG_SPLIT_NO_EMPTY);
 | |
| 		if(isset($params['on']))
 | |
| 		{
 | |
| 			if(is_array($params['on']))
 | |
| 				$on=$params['on'];
 | |
| 			else
 | |
| 				$on=preg_split('/[\s,]+/',$params['on'],-1,PREG_SPLIT_NO_EMPTY);
 | |
| 		}
 | |
| 		else
 | |
| 			$on=array();
 | |
| 		if(isset($params['except']))
 | |
| 		{
 | |
| 			if(is_array($params['except']))
 | |
| 				$except=$params['except'];
 | |
| 			else
 | |
| 				$except=preg_split('/[\s,]+/',$params['except'],-1,PREG_SPLIT_NO_EMPTY);
 | |
| 		}
 | |
| 		else
 | |
| 			$except=array();
 | |
| 		if(method_exists($object,$name))
 | |
| 		{
 | |
| 			$validator=new CInlineValidator;
 | |
| 			$validator->attributes=$attributes;
 | |
| 			$validator->method=$name;
 | |
| 			if(isset($params['clientValidate']))
 | |
| 			{
 | |
| 				$validator->clientValidate=$params['clientValidate'];
 | |
| 				unset($params['clientValidate']);
 | |
| 			}
 | |
| 			$validator->params=$params;
 | |
| 			if(isset($params['skipOnError']))
 | |
| 				$validator->skipOnError=$params['skipOnError'];
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$params['attributes']=$attributes;
 | |
| 			if(isset(self::$builtInValidators[$name]))
 | |
| 				$className=Yii::import(self::$builtInValidators[$name],true);
 | |
| 			else
 | |
| 				$className=Yii::import($name,true);
 | |
| 			$validator=new $className;
 | |
| 			foreach($params as $name=>$value)
 | |
| 				$validator->$name=$value;
 | |
| 		}
 | |
| 		$validator->on=empty($on) ? array() : array_combine($on,$on);
 | |
| 		$validator->except=empty($except) ? array() : array_combine($except,$except);
 | |
| 		return $validator;
 | |
| 	}
 | |
| 	public function validate($object,$attributes=null)
 | |
| 	{
 | |
| 		if(is_array($attributes))
 | |
| 			$attributes=array_intersect($this->attributes,$attributes);
 | |
| 		else
 | |
| 			$attributes=$this->attributes;
 | |
| 		foreach($attributes as $attribute)
 | |
| 		{
 | |
| 			if(!$this->skipOnError || !$object->hasErrors($attribute))
 | |
| 				$this->validateAttribute($object,$attribute);
 | |
| 		}
 | |
| 	}
 | |
| 	public function clientValidateAttribute($object,$attribute)
 | |
| 	{
 | |
| 	}
 | |
| 	public function applyTo($scenario)
 | |
| 	{
 | |
| 		if(isset($this->except[$scenario]))
 | |
| 			return false;
 | |
| 		return empty($this->on) || isset($this->on[$scenario]);
 | |
| 	}
 | |
| 	protected function addError($object,$attribute,$message,$params=array())
 | |
| 	{
 | |
| 		$params['{attribute}']=$object->getAttributeLabel($attribute);
 | |
| 		$object->addError($attribute,strtr($message,$params));
 | |
| 	}
 | |
| 	protected function isEmpty($value,$trim=false)
 | |
| 	{
 | |
| 		return $value===null || $value===array() || $value==='' || $trim && is_scalar($value) && trim($value)==='';
 | |
| 	}
 | |
| }
 | |
| class CStringValidator extends CValidator
 | |
| {
 | |
| 	public $max;
 | |
| 	public $min;
 | |
| 	public $is;
 | |
| 	public $tooShort;
 | |
| 	public $tooLong;
 | |
| 	public $allowEmpty=true;
 | |
| 	public $encoding;
 | |
| 	protected function validateAttribute($object,$attribute)
 | |
| 	{
 | |
| 		$value=$object->$attribute;
 | |
| 		if($this->allowEmpty && $this->isEmpty($value))
 | |
| 			return;
 | |
| 		if(is_array($value))
 | |
| 		{
 | |
| 			// https://github.com/yiisoft/yii/issues/1955
 | |
| 			$this->addError($object,$attribute,Yii::t('yii','{attribute} is invalid.'));
 | |
| 			return;
 | |
| 		}
 | |
| 		if(function_exists('mb_strlen') && $this->encoding!==false)
 | |
| 			$length=mb_strlen($value, $this->encoding ? $this->encoding : Yii::app()->charset);
 | |
| 		else
 | |
| 			$length=strlen($value);
 | |
| 		if($this->min!==null && $length<$this->min)
 | |
| 		{
 | |
| 			$message=$this->tooShort!==null?$this->tooShort:Yii::t('yii','{attribute} is too short (minimum is {min} characters).');
 | |
| 			$this->addError($object,$attribute,$message,array('{min}'=>$this->min));
 | |
| 		}
 | |
| 		if($this->max!==null && $length>$this->max)
 | |
| 		{
 | |
| 			$message=$this->tooLong!==null?$this->tooLong:Yii::t('yii','{attribute} is too long (maximum is {max} characters).');
 | |
| 			$this->addError($object,$attribute,$message,array('{max}'=>$this->max));
 | |
| 		}
 | |
| 		if($this->is!==null && $length!==$this->is)
 | |
| 		{
 | |
| 			$message=$this->message!==null?$this->message:Yii::t('yii','{attribute} is of the wrong length (should be {length} characters).');
 | |
| 			$this->addError($object,$attribute,$message,array('{length}'=>$this->is));
 | |
| 		}
 | |
| 	}
 | |
| 	public function clientValidateAttribute($object,$attribute)
 | |
| 	{
 | |
| 		$label=$object->getAttributeLabel($attribute);
 | |
| 		if(($message=$this->message)===null)
 | |
| 			$message=Yii::t('yii','{attribute} is of the wrong length (should be {length} characters).');
 | |
| 		$message=strtr($message, array(
 | |
| 			'{attribute}'=>$label,
 | |
| 			'{length}'=>$this->is,
 | |
| 		));
 | |
| 		if(($tooShort=$this->tooShort)===null)
 | |
| 			$tooShort=Yii::t('yii','{attribute} is too short (minimum is {min} characters).');
 | |
| 		$tooShort=strtr($tooShort, array(
 | |
| 			'{attribute}'=>$label,
 | |
| 			'{min}'=>$this->min,
 | |
| 		));
 | |
| 		if(($tooLong=$this->tooLong)===null)
 | |
| 			$tooLong=Yii::t('yii','{attribute} is too long (maximum is {max} characters).');
 | |
| 		$tooLong=strtr($tooLong, array(
 | |
| 			'{attribute}'=>$label,
 | |
| 			'{max}'=>$this->max,
 | |
| 		));
 | |
| 		$js='';
 | |
| 		if($this->min!==null)
 | |
| 		{
 | |
| 			$js.="
 | |
| if(value.length<{$this->min}) {
 | |
| 	messages.push(".CJSON::encode($tooShort).");
 | |
| }
 | |
| ";
 | |
| 		}
 | |
| 		if($this->max!==null)
 | |
| 		{
 | |
| 			$js.="
 | |
| if(value.length>{$this->max}) {
 | |
| 	messages.push(".CJSON::encode($tooLong).");
 | |
| }
 | |
| ";
 | |
| 		}
 | |
| 		if($this->is!==null)
 | |
| 		{
 | |
| 			$js.="
 | |
| if(value.length!={$this->is}) {
 | |
| 	messages.push(".CJSON::encode($message).");
 | |
| }
 | |
| ";
 | |
| 		}
 | |
| 		if($this->allowEmpty)
 | |
| 		{
 | |
| 			$js="
 | |
| if(jQuery.trim(value)!='') {
 | |
| 	$js
 | |
| }
 | |
| ";
 | |
| 		}
 | |
| 		return $js;
 | |
| 	}
 | |
| }
 | |
| class CRequiredValidator extends CValidator
 | |
| {
 | |
| 	public $requiredValue;
 | |
| 	public $strict=false;
 | |
| 	public $trim=true;
 | |
| 	protected function validateAttribute($object,$attribute)
 | |
| 	{
 | |
| 		$value=$object->$attribute;
 | |
| 		if($this->requiredValue!==null)
 | |
| 		{
 | |
| 			if(!$this->strict && $value!=$this->requiredValue || $this->strict && $value!==$this->requiredValue)
 | |
| 			{
 | |
| 				$message=$this->message!==null?$this->message:Yii::t('yii','{attribute} must be {value}.',
 | |
| 					array('{value}'=>$this->requiredValue));
 | |
| 				$this->addError($object,$attribute,$message);
 | |
| 			}
 | |
| 		}
 | |
| 		elseif($this->isEmpty($value,$this->trim))
 | |
| 		{
 | |
| 			$message=$this->message!==null?$this->message:Yii::t('yii','{attribute} cannot be blank.');
 | |
| 			$this->addError($object,$attribute,$message);
 | |
| 		}
 | |
| 	}
 | |
| 	public function clientValidateAttribute($object,$attribute)
 | |
| 	{
 | |
| 		$message=$this->message;
 | |
| 		if($this->requiredValue!==null)
 | |
| 		{
 | |
| 			if($message===null)
 | |
| 				$message=Yii::t('yii','{attribute} must be {value}.');
 | |
| 			$message=strtr($message, array(
 | |
| 				'{value}'=>$this->requiredValue,
 | |
| 				'{attribute}'=>$object->getAttributeLabel($attribute),
 | |
| 			));
 | |
| 			return "
 | |
| if(value!=" . CJSON::encode($this->requiredValue) . ") {
 | |
| 	messages.push(".CJSON::encode($message).");
 | |
| }
 | |
| ";
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			if($message===null)
 | |
| 				$message=Yii::t('yii','{attribute} cannot be blank.');
 | |
| 			$message=strtr($message, array(
 | |
| 				'{attribute}'=>$object->getAttributeLabel($attribute),
 | |
| 			));
 | |
| 			if($this->trim)
 | |
| 				$emptyCondition = "jQuery.trim(value)==''";
 | |
| 			else
 | |
| 				$emptyCondition = "value==''";
 | |
| 			return "
 | |
| if({$emptyCondition}) {
 | |
| 	messages.push(".CJSON::encode($message).");
 | |
| }
 | |
| ";
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| class CNumberValidator extends CValidator
 | |
| {
 | |
| 	public $integerOnly=false;
 | |
| 	public $allowEmpty=true;
 | |
| 	public $max;
 | |
| 	public $min;
 | |
| 	public $tooBig;
 | |
| 	public $tooSmall;
 | |
| 	public $integerPattern='/^\s*[+-]?\d+\s*$/';
 | |
| 	public $numberPattern='/^\s*[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\s*$/';
 | |
| 	protected function validateAttribute($object,$attribute)
 | |
| 	{
 | |
| 		$value=$object->$attribute;
 | |
| 		if($this->allowEmpty && $this->isEmpty($value))
 | |
| 			return;
 | |
| 		if(!is_numeric($value))
 | |
| 		{
 | |
| 			// https://github.com/yiisoft/yii/issues/1955
 | |
| 			// https://github.com/yiisoft/yii/issues/1669
 | |
| 			$message=$this->message!==null?$this->message:Yii::t('yii','{attribute} must be a number.');
 | |
| 			$this->addError($object,$attribute,$message);
 | |
| 			return;
 | |
| 		}
 | |
| 		if($this->integerOnly)
 | |
| 		{
 | |
| 			if(!preg_match($this->integerPattern,"$value"))
 | |
| 			{
 | |
| 				$message=$this->message!==null?$this->message:Yii::t('yii','{attribute} must be an integer.');
 | |
| 				$this->addError($object,$attribute,$message);
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			if(!preg_match($this->numberPattern,"$value"))
 | |
| 			{
 | |
| 				$message=$this->message!==null?$this->message:Yii::t('yii','{attribute} must be a number.');
 | |
| 				$this->addError($object,$attribute,$message);
 | |
| 			}
 | |
| 		}
 | |
| 		if($this->min!==null && $value<$this->min)
 | |
| 		{
 | |
| 			$message=$this->tooSmall!==null?$this->tooSmall:Yii::t('yii','{attribute} is too small (minimum is {min}).');
 | |
| 			$this->addError($object,$attribute,$message,array('{min}'=>$this->min));
 | |
| 		}
 | |
| 		if($this->max!==null && $value>$this->max)
 | |
| 		{
 | |
| 			$message=$this->tooBig!==null?$this->tooBig:Yii::t('yii','{attribute} is too big (maximum is {max}).');
 | |
| 			$this->addError($object,$attribute,$message,array('{max}'=>$this->max));
 | |
| 		}
 | |
| 	}
 | |
| 	public function clientValidateAttribute($object,$attribute)
 | |
| 	{
 | |
| 		$label=$object->getAttributeLabel($attribute);
 | |
| 		if(($message=$this->message)===null)
 | |
| 			$message=$this->integerOnly ? Yii::t('yii','{attribute} must be an integer.') : Yii::t('yii','{attribute} must be a number.');
 | |
| 		$message=strtr($message, array(
 | |
| 			'{attribute}'=>$label,
 | |
| 		));
 | |
| 		if(($tooBig=$this->tooBig)===null)
 | |
| 			$tooBig=Yii::t('yii','{attribute} is too big (maximum is {max}).');
 | |
| 		$tooBig=strtr($tooBig, array(
 | |
| 			'{attribute}'=>$label,
 | |
| 			'{max}'=>$this->max,
 | |
| 		));
 | |
| 		if(($tooSmall=$this->tooSmall)===null)
 | |
| 			$tooSmall=Yii::t('yii','{attribute} is too small (minimum is {min}).');
 | |
| 		$tooSmall=strtr($tooSmall, array(
 | |
| 			'{attribute}'=>$label,
 | |
| 			'{min}'=>$this->min,
 | |
| 		));
 | |
| 		$pattern=$this->integerOnly ? $this->integerPattern : $this->numberPattern;
 | |
| 		$js="
 | |
| if(!value.match($pattern)) {
 | |
| 	messages.push(".CJSON::encode($message).");
 | |
| }
 | |
| ";
 | |
| 		if($this->min!==null)
 | |
| 		{
 | |
| 			$js.="
 | |
| if(value<{$this->min}) {
 | |
| 	messages.push(".CJSON::encode($tooSmall).");
 | |
| }
 | |
| ";
 | |
| 		}
 | |
| 		if($this->max!==null)
 | |
| 		{
 | |
| 			$js.="
 | |
| if(value>{$this->max}) {
 | |
| 	messages.push(".CJSON::encode($tooBig).");
 | |
| }
 | |
| ";
 | |
| 		}
 | |
| 		if($this->allowEmpty)
 | |
| 		{
 | |
| 			$js="
 | |
| if(jQuery.trim(value)!='') {
 | |
| 	$js
 | |
| }
 | |
| ";
 | |
| 		}
 | |
| 		return $js;
 | |
| 	}
 | |
| }
 | |
| class CListIterator implements Iterator
 | |
| {
 | |
| 	private $_d;
 | |
| 	private $_i;
 | |
| 	private $_c;
 | |
| 	public function __construct(&$data)
 | |
| 	{
 | |
| 		$this->_d=&$data;
 | |
| 		$this->_i=0;
 | |
| 		$this->_c=count($this->_d);
 | |
| 	}
 | |
| 	public function rewind()
 | |
| 	{
 | |
| 		$this->_i=0;
 | |
| 	}
 | |
| 	public function key()
 | |
| 	{
 | |
| 		return $this->_i;
 | |
| 	}
 | |
| 	public function current()
 | |
| 	{
 | |
| 		return $this->_d[$this->_i];
 | |
| 	}
 | |
| 	public function next()
 | |
| 	{
 | |
| 		$this->_i++;
 | |
| 	}
 | |
| 	public function valid()
 | |
| 	{
 | |
| 		return $this->_i<$this->_c;
 | |
| 	}
 | |
| }
 | |
| interface IApplicationComponent
 | |
| {
 | |
| 	public function init();
 | |
| 	public function getIsInitialized();
 | |
| }
 | |
| interface ICache
 | |
| {
 | |
| 	public function get($id);
 | |
| 	public function mget($ids);
 | |
| 	public function set($id,$value,$expire=0,$dependency=null);
 | |
| 	public function add($id,$value,$expire=0,$dependency=null);
 | |
| 	public function delete($id);
 | |
| 	public function flush();
 | |
| }
 | |
| interface ICacheDependency
 | |
| {
 | |
| 	public function evaluateDependency();
 | |
| 	public function getHasChanged();
 | |
| }
 | |
| interface IStatePersister
 | |
| {
 | |
| 	public function load();
 | |
| 	public function save($state);
 | |
| }
 | |
| interface IFilter
 | |
| {
 | |
| 	public function filter($filterChain);
 | |
| }
 | |
| interface IAction
 | |
| {
 | |
| 	public function getId();
 | |
| 	public function getController();
 | |
| }
 | |
| interface IWebServiceProvider
 | |
| {
 | |
| 	public function beforeWebMethod($service);
 | |
| 	public function afterWebMethod($service);
 | |
| }
 | |
| interface IViewRenderer
 | |
| {
 | |
| 	public function renderFile($context,$file,$data,$return);
 | |
| }
 | |
| interface IUserIdentity
 | |
| {
 | |
| 	public function authenticate();
 | |
| 	public function getIsAuthenticated();
 | |
| 	public function getId();
 | |
| 	public function getName();
 | |
| 	public function getPersistentStates();
 | |
| }
 | |
| interface IWebUser
 | |
| {
 | |
| 	public function getId();
 | |
| 	public function getName();
 | |
| 	public function getIsGuest();
 | |
| 	public function checkAccess($operation,$params=array());
 | |
| 	public function loginRequired();
 | |
| }
 | |
| interface IAuthManager
 | |
| {
 | |
| 	public function checkAccess($itemName,$userId,$params=array());
 | |
| 	public function createAuthItem($name,$type,$description='',$bizRule=null,$data=null);
 | |
| 	public function removeAuthItem($name);
 | |
| 	public function getAuthItems($type=null,$userId=null);
 | |
| 	public function getAuthItem($name);
 | |
| 	public function saveAuthItem($item,$oldName=null);
 | |
| 	public function addItemChild($itemName,$childName);
 | |
| 	public function removeItemChild($itemName,$childName);
 | |
| 	public function hasItemChild($itemName,$childName);
 | |
| 	public function getItemChildren($itemName);
 | |
| 	public function assign($itemName,$userId,$bizRule=null,$data=null);
 | |
| 	public function revoke($itemName,$userId);
 | |
| 	public function isAssigned($itemName,$userId);
 | |
| 	public function getAuthAssignment($itemName,$userId);
 | |
| 	public function getAuthAssignments($userId);
 | |
| 	public function saveAuthAssignment($assignment);
 | |
| 	public function clearAll();
 | |
| 	public function clearAuthAssignments();
 | |
| 	public function save();
 | |
| 	public function executeBizRule($bizRule,$params,$data);
 | |
| }
 | |
| interface IBehavior
 | |
| {
 | |
| 	public function attach($component);
 | |
| 	public function detach($component);
 | |
| 	public function getEnabled();
 | |
| 	public function setEnabled($value);
 | |
| }
 | |
| interface IWidgetFactory
 | |
| {
 | |
| 	public function createWidget($owner,$className,$properties=array());
 | |
| }
 | |
| interface IDataProvider
 | |
| {
 | |
| 	public function getId();
 | |
| 	public function getItemCount($refresh=false);
 | |
| 	public function getTotalItemCount($refresh=false);
 | |
| 	public function getData($refresh=false);
 | |
| 	public function getKeys($refresh=false);
 | |
| 	public function getSort();
 | |
| 	public function getPagination();
 | |
| }
 | |
| interface ILogFilter
 | |
| {
 | |
| 	public function filter(&$logs);
 | |
| }
 | |
| ?> |