mirror of
https://github.com/yiisoft/yii.git
synced 2026-03-04 15:24:07 +01:00
6584 lines
180 KiB
PHP
6584 lines
180 KiB
PHP
<?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 Copyright © 2008 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_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__));
|
|
class YiiBase
|
|
{
|
|
private static $_aliases=array('system'=>YII_PATH); // alias => path
|
|
private static $_imports=array(); // alias => class name or directory
|
|
private static $_classes=array();
|
|
private static $_app;
|
|
private static $_logger;
|
|
public static function getVersion()
|
|
{
|
|
return '1.0.0';
|
|
}
|
|
public static function createWebApplication($config=null)
|
|
{
|
|
return new CWebApplication($config);
|
|
}
|
|
public static function createConsoleApplication($config=null)
|
|
{
|
|
return new CConsoleApplication($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($type)
|
|
{
|
|
$type=self::import($type,true);
|
|
if(($n=func_num_args())>1)
|
|
{
|
|
$args=func_get_args();
|
|
for($s='$args[1]',$i=2;$i<$n;++$i)
|
|
$s.=",\$args[$i]";
|
|
eval("\$component=new $type($s);");
|
|
return $component;
|
|
}
|
|
else
|
|
return new $type;
|
|
}
|
|
public static function import($alias,$forceInclude=false)
|
|
{
|
|
if(isset(self::$_imports[$alias])) // previously imported
|
|
return self::$_imports[$alias];
|
|
if(isset(self::$_coreClasses[$alias]) || ($pos=strrpos($alias,'.'))===false) // a simple class name
|
|
{
|
|
self::$_imports[$alias]=$alias;
|
|
if($forceInclude && !class_exists($alias,false))
|
|
{
|
|
if(isset(self::$_coreClasses[$alias])) // a core class
|
|
require_once(YII_PATH.self::$_coreClasses[$alias]);
|
|
else
|
|
require_once($alias.'.php');
|
|
}
|
|
return $alias;
|
|
}
|
|
if(($className=(string)substr($alias,$pos+1))!=='*' && class_exists($className,false))
|
|
return self::$_imports[$alias]=$className;
|
|
if(($path=self::getPathOfAlias($alias))!==false)
|
|
{
|
|
if($className!=='*')
|
|
{
|
|
self::$_imports[$alias]=$className;
|
|
if($forceInclude)
|
|
require_once($path.'.php');
|
|
else
|
|
self::$_classes[$className]=$path.'.php';
|
|
return $className;
|
|
}
|
|
else // a directory
|
|
{
|
|
set_include_path(get_include_path().PATH_SEPARATOR.$path);
|
|
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];
|
|
else if(($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);
|
|
}
|
|
return self::$_aliases[$alias]=false;
|
|
}
|
|
public static function setPathOfAlias($alias,$path)
|
|
{
|
|
if($path===null)
|
|
unset(self::$_aliases[$alias]);
|
|
else if(!isset(self::$_aliases[$alias]) && ($rp=realpath($path))!==false)
|
|
self::$_aliases[$alias]=rtrim($rp,'\\/');
|
|
else if(isset(self::$_aliases[$alias]))
|
|
throw new CException(Yii::t('yii','Path alias "{alias}" is redefined.',
|
|
array('{alias}'=>$alias)));
|
|
else
|
|
throw new CException(Yii::t('yii','Path alias "{alias}" points to an invalid directory "{path}".',
|
|
array('{alias}'=>$alias, '{path}'=>$path)));
|
|
}
|
|
public static function autoload($className)
|
|
{
|
|
// use include_once so that the error PHP file may appear
|
|
if(isset(self::$_coreClasses[$className]))
|
|
include_once(YII_PATH.self::$_coreClasses[$className]);
|
|
else if(isset(self::$_classes[$className]))
|
|
include_once(self::$_classes[$className]);
|
|
else
|
|
include_once($className.'.php');
|
|
}
|
|
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;
|
|
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 powered()
|
|
{
|
|
return 'Powered by <a href="http://www.yiiframework.com/">Yii Framework</a>.';
|
|
}
|
|
public static function t($category,$message,$params=array(),$source=null)
|
|
{
|
|
if(self::$_app!==null)
|
|
{
|
|
if($source===null)
|
|
$source=$category==='yii'?'coreMessages':'messages';
|
|
if(($source=self::$_app->getComponent($source))!==null)
|
|
$message=$source->translate($category,$message);
|
|
}
|
|
return $params!==array() ? strtr($message,$params) : $message;
|
|
}
|
|
private static $_coreClasses=array(
|
|
'CApplication' => '/base/CApplication.php',
|
|
'CApplicationComponent' => '/base/CApplicationComponent.php',
|
|
'CComponent' => '/base/CComponent.php',
|
|
'CErrorHandler' => '/base/CErrorHandler.php',
|
|
'CException' => '/base/CException.php',
|
|
'CHttpException' => '/base/CHttpException.php',
|
|
'CModel' => '/base/CModel.php',
|
|
'CSecurityManager' => '/base/CSecurityManager.php',
|
|
'CStatePersister' => '/base/CStatePersister.php',
|
|
'CApcCache' => '/caching/CApcCache.php',
|
|
'CCache' => '/caching/CCache.php',
|
|
'CDbCache' => '/caching/CDbCache.php',
|
|
'CMemCache' => '/caching/CMemCache.php',
|
|
'CCacheDependency' => '/caching/dependencies/CCacheDependency.php',
|
|
'CChainedCacheDependency' => '/caching/dependencies/CChainedCacheDependency.php',
|
|
'CDbCacheDependency' => '/caching/dependencies/CDbCacheDependency.php',
|
|
'CDirectoryCacheDependency' => '/caching/dependencies/CDirectoryCacheDependency.php',
|
|
'CFileCacheDependency' => '/caching/dependencies/CFileCacheDependency.php',
|
|
'CGlobalStateCacheDependency' => '/caching/dependencies/CGlobalStateCacheDependency.php',
|
|
'CAttributeCollection' => '/collections/CAttributeCollection.php',
|
|
'CConfiguration' => '/collections/CConfiguration.php',
|
|
'CList' => '/collections/CList.php',
|
|
'CMap' => '/collections/CMap.php',
|
|
'CQueue' => '/collections/CQueue.php',
|
|
'CStack' => '/collections/CStack.php',
|
|
'CTypedList' => '/collections/CTypedList.php',
|
|
'CConsoleApplication' => '/console/CConsoleApplication.php',
|
|
'CConsoleCommand' => '/console/CConsoleCommand.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',
|
|
'CDbTransaction' => '/db/CDbTransaction.php',
|
|
'CActiveFinder' => '/db/ar/CActiveFinder.php',
|
|
'CActiveRecord' => '/db/ar/CActiveRecord.php',
|
|
'CDbColumnSchema' => '/db/schema/CDbColumnSchema.php',
|
|
'CDbCommandBuilder' => '/db/schema/CDbCommandBuilder.php',
|
|
'CDbCriteria' => '/db/schema/CDbCriteria.php',
|
|
'CDbSchema' => '/db/schema/CDbSchema.php',
|
|
'CDbTableSchema' => '/db/schema/CDbTableSchema.php',
|
|
'CMysqlColumnSchema' => '/db/schema/mysql/CMysqlColumnSchema.php',
|
|
'CMysqlSchema' => '/db/schema/mysql/CMysqlSchema.php',
|
|
'CMysqlTableSchema' => '/db/schema/mysql/CMysqlTableSchema.php',
|
|
'CPgsqlColumnSchema' => '/db/schema/pgsql/CPgsqlColumnSchema.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',
|
|
'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',
|
|
'CDbLogRoute' => '/logging/CDbLogRoute.php',
|
|
'CEmailLogRoute' => '/logging/CEmailLogRoute.php',
|
|
'CFileLogRoute' => '/logging/CFileLogRoute.php',
|
|
'CLogRoute' => '/logging/CLogRoute.php',
|
|
'CLogRouter' => '/logging/CLogRouter.php',
|
|
'CLogger' => '/logging/CLogger.php',
|
|
'CProfileLogRoute' => '/logging/CProfileLogRoute.php',
|
|
'CWebLogRoute' => '/logging/CWebLogRoute.php',
|
|
'CDateParser' => '/utils/CDateParser.php',
|
|
'CFileHelper' => '/utils/CFileHelper.php',
|
|
'CMarkdownParser' => '/utils/CMarkdownParser.php',
|
|
'CTimestamp' => '/utils/CTimestamp.php',
|
|
'CVarDumper' => '/utils/CVarDumper.php',
|
|
'CCaptchaValidator' => '/validators/CCaptchaValidator.php',
|
|
'CCompareValidator' => '/validators/CCompareValidator.php',
|
|
'CEmailValidator' => '/validators/CEmailValidator.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',
|
|
'CStringValidator' => '/validators/CStringValidator.php',
|
|
'CTypeValidator' => '/validators/CTypeValidator.php',
|
|
'CUniqueValidator' => '/validators/CUniqueValidator.php',
|
|
'CUrlValidator' => '/validators/CUrlValidator.php',
|
|
'CValidator' => '/validators/CValidator.php',
|
|
'CAssetManager' => '/web/CAssetManager.php',
|
|
'CBaseController' => '/web/CBaseController.php',
|
|
'CCacheHttpSession' => '/web/CCacheHttpSession.php',
|
|
'CClientScript' => '/web/CClientScript.php',
|
|
'CController' => '/web/CController.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',
|
|
'COutputEvent' => '/web/COutputEvent.php',
|
|
'CPagination' => '/web/CPagination.php',
|
|
'CTheme' => '/web/CTheme.php',
|
|
'CThemeManager' => '/web/CThemeManager.php',
|
|
'CUploadedFile' => '/web/CUploadedFile.php',
|
|
'CUrlManager' => '/web/CUrlManager.php',
|
|
'CWebApplication' => '/web/CWebApplication.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',
|
|
'CInlineFilter' => '/web/filters/CInlineFilter.php',
|
|
'CHtml' => '/web/helpers/CHtml.php',
|
|
'CJSON' => '/web/helpers/CJSON.php',
|
|
'CJavaScript' => '/web/helpers/CJavaScript.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',
|
|
'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;
|
|
public function __get($name)
|
|
{
|
|
$getter='get'.$name;
|
|
if(method_exists($this,$getter))
|
|
return $this->$getter();
|
|
else if(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];
|
|
}
|
|
else
|
|
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))
|
|
$this->$setter($value);
|
|
else if(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;
|
|
$this->_e[$name]->add($value);
|
|
}
|
|
else 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 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))
|
|
{
|
|
try
|
|
{
|
|
$this->getEventHandlers($name)->remove($handler);
|
|
return true;
|
|
}
|
|
catch(Exception $e)
|
|
{
|
|
}
|
|
}
|
|
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);
|
|
else if(is_callable($handler,true))
|
|
{
|
|
// an array: 0 - object, 1 - method name
|
|
list($object,$method)=$handler;
|
|
if(is_string($object)) // static method call
|
|
call_user_func($handler,$event);
|
|
else if(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
|
|
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;
|
|
}
|
|
}
|
|
else if(!$this->hasEvent($name))
|
|
throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',
|
|
array('{class}'=>get_class($this), '{event}'=>$name)));
|
|
}
|
|
}
|
|
class CEvent extends CComponent
|
|
{
|
|
public $sender;
|
|
public $handled=false;
|
|
public function __construct($sender=null)
|
|
{
|
|
$this->sender=$sender;
|
|
}
|
|
}
|
|
class CEnumerable
|
|
{
|
|
}
|
|
class CPropertyValue
|
|
{
|
|
public static function ensureBoolean($value)
|
|
{
|
|
if (is_string($value))
|
|
return !strcasecmp($value,'true') || $value!=0;
|
|
else
|
|
return (boolean)$value;
|
|
}
|
|
public static function ensureString($value)
|
|
{
|
|
if (is_bool($value))
|
|
return $value?'true':'false';
|
|
else
|
|
return (string)$value;
|
|
}
|
|
public static function ensureInteger($value)
|
|
{
|
|
return (integer)$value;
|
|
}
|
|
public static function ensureFloat($value)
|
|
{
|
|
return (float)$value;
|
|
}
|
|
public static function ensureArray($value)
|
|
{
|
|
if(is_string($value))
|
|
{
|
|
$value = trim($value);
|
|
$len = strlen($value);
|
|
if ($len >= 2 && $value[0] == '(' && $value[$len-1] == ')')
|
|
{
|
|
eval('$array=array'.$value.';');
|
|
return $array;
|
|
}
|
|
else
|
|
return $len>0?array($value):array();
|
|
}
|
|
else
|
|
return (array)$value;
|
|
}
|
|
public static function ensureObject($value)
|
|
{
|
|
return (object)$value;
|
|
}
|
|
public static function ensureEnum($value,$enumType)
|
|
{
|
|
static $types=array();
|
|
if(!isset($types[$enumType]))
|
|
$types[$enumType]=new ReflectionClass($enumType);
|
|
if($types[$enumType]->hasConstant($value))
|
|
return $value;
|
|
else
|
|
throw new CException(Yii::t('yii','Invalid enumerable value "{value}". Please make sure it is among ({enum}).',
|
|
array('{value}'=>$value, '{enum}'=>implode(', ',$types[$enumType]->getConstants()))));
|
|
}
|
|
}
|
|
abstract class CApplication extends CComponent
|
|
{
|
|
public $name='My Application';
|
|
public $charset='UTF-8';
|
|
public $preload=array();
|
|
public $sourceLanguage='en_us';
|
|
private $_id;
|
|
private $_basePath;
|
|
private $_runtimePath;
|
|
private $_extensionPath;
|
|
private $_globalState;
|
|
private $_stateChanged;
|
|
private $_params;
|
|
private $_components=array();
|
|
private $_componentConfig=array();
|
|
private $_ended=false;
|
|
private $_language;
|
|
abstract public function processRequest();
|
|
public function __construct($config=null)
|
|
{
|
|
Yii::setApplication($this);
|
|
$this->initSystemHandlers();
|
|
$this->registerCoreComponents();
|
|
$this->configure($config);
|
|
$this->init();
|
|
}
|
|
protected function init()
|
|
{
|
|
$this->preloadComponents();
|
|
}
|
|
public function __get($name)
|
|
{
|
|
if($this->hasComponent($name))
|
|
return $this->getComponent($name);
|
|
else
|
|
return parent::__get($name);
|
|
}
|
|
public function run()
|
|
{
|
|
$this->onBeginRequest(new CEvent($this));
|
|
$this->processRequest();
|
|
$this->onEndRequest(new CEvent($this));
|
|
}
|
|
public function end($status=0)
|
|
{
|
|
$this->onEndRequest(new CEvent($this));
|
|
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=md5($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;
|
|
}
|
|
final public function getExtensionPath()
|
|
{
|
|
if($this->_extensionPath!==null)
|
|
return $this->_extensionPath;
|
|
else
|
|
return $this->_extensionPath=$this->getBasePath().DIRECTORY_SEPARATOR.'extensions';
|
|
}
|
|
public function setImport($aliases)
|
|
{
|
|
foreach($aliases as $alias)
|
|
Yii::import($alias);
|
|
}
|
|
public function getLanguage()
|
|
{
|
|
return $this->_language===null ? $this->sourceLanguage : $this->_language;
|
|
}
|
|
public function setLanguage($language)
|
|
{
|
|
$this->_language=$language;
|
|
}
|
|
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 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 getParams()
|
|
{
|
|
if($this->_params!==null)
|
|
return $this->_params;
|
|
else
|
|
return $this->_params=new CAttributeCollection;
|
|
}
|
|
public function setParams($value)
|
|
{
|
|
if(is_array($value))
|
|
$this->_params=new CAttributeCollection($value);
|
|
else
|
|
$this->_params=$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();
|
|
$this->_stateChanged=true;
|
|
if($value===$defaultValue)
|
|
unset($this->_globalState[$key]);
|
|
else
|
|
$this->_globalState[$key]=$value;
|
|
}
|
|
public function clearGlobalState($key)
|
|
{
|
|
if($this->_globalState===null)
|
|
$this->loadGlobalState();
|
|
if(isset($this->_globals[$key]))
|
|
{
|
|
$this->_stateChanged=true;
|
|
unset($this->_globals[$key]);
|
|
}
|
|
}
|
|
protected function loadGlobalState()
|
|
{
|
|
$persister=$this->getStatePersister();
|
|
if(($this->_globalState=$persister->load())===null)
|
|
$this->_globalState=array();
|
|
$this->_stateChanged=false;
|
|
$this->attachEventHandler('onEndRequest',array($this,'saveGlobalState'));
|
|
}
|
|
protected function saveGlobalState()
|
|
{
|
|
if($this->_stateChanged)
|
|
{
|
|
$persister=$this->getStatePersister();
|
|
$this->_stateChanged=false;
|
|
$persister->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;
|
|
$message=(string)$exception;
|
|
if(isset($_SERVER['REQUEST_URI']))
|
|
$message.=' REQUEST_URI='.$_SERVER['REQUEST_URI'];
|
|
Yii::log($message,CLogger::LEVEL_ERROR,$category);
|
|
$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);
|
|
}
|
|
$this->end(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)";
|
|
if(isset($_SERVER['REQUEST_URI']))
|
|
$log.=' REQUEST_URI='.$_SERVER['REQUEST_URI'];
|
|
Yii::log($log,CLogger::LEVEL_ERROR,'php');
|
|
$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);
|
|
}
|
|
$this->end(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>';
|
|
debug_print_backtrace();
|
|
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>';
|
|
}
|
|
}
|
|
public function hasComponent($id)
|
|
{
|
|
return isset($this->_components[$id]) || isset($this->_componentConfig[$id]);
|
|
}
|
|
public function getComponent($id)
|
|
{
|
|
if(isset($this->_components[$id]))
|
|
return $this->_components[$id];
|
|
else if(isset($this->_componentConfig[$id]))
|
|
{
|
|
$config=$this->_componentConfig[$id];
|
|
unset($this->_componentConfig[$id]);
|
|
if(!isset($config['enabled']) || $config['enabled'])
|
|
{
|
|
unset($config['enabled']);
|
|
$component=CConfiguration::createObject($config);
|
|
$component->init();
|
|
return $this->_components[$id]=$component;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
public function setComponent($id,$component)
|
|
{
|
|
$this->_components[$id]=$component;
|
|
if(!$component->getIsInitialized())
|
|
$component->init();
|
|
}
|
|
protected function configure($config)
|
|
{
|
|
$config=new CConfiguration($config);
|
|
if(($basePath=$config->remove('basePath'))===null)
|
|
$basePath='protected';
|
|
$this->setBasePath($basePath);
|
|
Yii::setPathOfAlias('application',$this->getBasePath());
|
|
$config->applyTo($this);
|
|
}
|
|
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',
|
|
),
|
|
);
|
|
$this->setComponents($components);
|
|
}
|
|
protected function preloadComponents()
|
|
{
|
|
foreach($this->preload as $id)
|
|
$this->getComponent($id);
|
|
}
|
|
public function getComponents()
|
|
{
|
|
return $this->_components;
|
|
}
|
|
public function setComponents($components)
|
|
{
|
|
foreach($components as $id=>$component)
|
|
{
|
|
if($component instanceof IApplicationComponent)
|
|
$this->setComponent($id,$component);
|
|
else if(isset($this->_componentConfig[$id]))
|
|
$this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component);
|
|
else
|
|
$this->_componentConfig[$id]=$component;
|
|
}
|
|
}
|
|
}
|
|
class CExceptionEvent extends CEvent
|
|
{
|
|
public $exception;
|
|
public function __construct($sender,$exception)
|
|
{
|
|
$this->exception=$exception;
|
|
parent::__construct($sender);
|
|
}
|
|
}
|
|
class CErrorEvent extends CEvent
|
|
{
|
|
public $code;
|
|
public $message;
|
|
public $file;
|
|
public $line;
|
|
public function __construct($sender,$code,$message,$file,$line)
|
|
{
|
|
$this->code=$code;
|
|
$this->message=$message;
|
|
$this->file=$file;
|
|
$this->line=$line;
|
|
parent::__construct($sender);
|
|
}
|
|
}
|
|
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)
|
|
$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);
|
|
}
|
|
else if($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);
|
|
}
|
|
}
|
|
else if($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)
|
|
{
|
|
foreach($b as $k=>$v)
|
|
{
|
|
if(is_integer($k))
|
|
$a[]=$v;
|
|
else if(is_array($v) && isset($a[$k]) && is_array($a[$k]))
|
|
$a[$k]=self::mergeArray($a[$k],$v);
|
|
else
|
|
$a[$k]=$v;
|
|
}
|
|
return $a;
|
|
}
|
|
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 CMapIterator implements Iterator
|
|
{
|
|
private $_d;
|
|
private $_keys;
|
|
private $_key;
|
|
public function __construct(&$data)
|
|
{
|
|
$this->_d=&$data;
|
|
$this->_keys=array_keys($data);
|
|
}
|
|
public function rewind()
|
|
{
|
|
$this->_key=reset($this->_keys);
|
|
}
|
|
public function key()
|
|
{
|
|
return $this->_key;
|
|
}
|
|
public function current()
|
|
{
|
|
return $this->_d[$this->_key];
|
|
}
|
|
public function next()
|
|
{
|
|
$this->_key=next($this->_keys);
|
|
}
|
|
public function valid()
|
|
{
|
|
return $this->_key!==false;
|
|
}
|
|
}
|
|
class CConfiguration extends CMap
|
|
{
|
|
public function __construct($data=null)
|
|
{
|
|
if(is_string($data))
|
|
parent::__construct(require($data));
|
|
else
|
|
parent::__construct($data);
|
|
}
|
|
public function loadFromFile($configFile)
|
|
{
|
|
$data=require($configFile);
|
|
if($this->getCount()>0)
|
|
$this->mergeWith($data);
|
|
else
|
|
$this->copyFrom($data);
|
|
}
|
|
public function saveAsString()
|
|
{
|
|
return str_replace("\r",'',var_export($this->toArray(),true));
|
|
}
|
|
public function applyTo($object)
|
|
{
|
|
foreach($this->toArray() as $key=>$value)
|
|
$object->$key=$value;
|
|
}
|
|
public static function createObject($config)
|
|
{
|
|
if(is_string($config))
|
|
$config=array('class'=>$config);
|
|
else if($config instanceof self)
|
|
$config=$config->toArray();
|
|
if(is_array($config) && isset($config['class']))
|
|
{
|
|
$className=Yii::import($config['class'],true);
|
|
unset($config['class']);
|
|
if(($n=func_num_args())>1)
|
|
{
|
|
$args=func_get_args();
|
|
for($s='$args[1]',$i=2;$i<$n;++$i)
|
|
$s.=",\$args[$i]";
|
|
eval("\$object=new $className($s);");
|
|
}
|
|
else
|
|
$object=new $className;
|
|
foreach($config as $key=>$value)
|
|
$object->$key=$value;
|
|
return $object;
|
|
}
|
|
else
|
|
throw new CException(Yii::t('yii','Object configuration must be an array containing a "class" element.'));
|
|
}
|
|
}
|
|
class CWebApplication extends CApplication
|
|
{
|
|
public $defaultController='site';
|
|
public $layout='main';
|
|
public $controllerMap=array();
|
|
public $catchAllRequest;
|
|
private $_controllerPath;
|
|
private $_viewPath;
|
|
private $_systemViewPath;
|
|
private $_layoutPath;
|
|
private $_controller;
|
|
private $_homeUrl;
|
|
private $_theme;
|
|
public function processRequest()
|
|
{
|
|
if(is_array($this->catchAllRequest) && isset($this->catchAllRequest[0]))
|
|
{
|
|
$segs=explode('/',$this->catchAllRequest[0]);
|
|
$controllerID=$segs[0];
|
|
$actionID=isset($segs[1])?$segs[1]:'';
|
|
foreach(array_splice($this->catchAllRequest,1) as $name=>$value)
|
|
$_GET[$name]=$value;
|
|
}
|
|
else
|
|
list($controllerID,$actionID)=$this->resolveRequest();
|
|
$this->runController($controllerID,$actionID);
|
|
}
|
|
protected function resolveRequest()
|
|
{
|
|
$route=$this->getUrlManager()->parseUrl($this->getRequest());
|
|
if(($pos=strrpos($route,'/'))!==false)
|
|
return array(substr($route,0,$pos),(string)substr($route,$pos+1));
|
|
else
|
|
return array($route,'');
|
|
}
|
|
public function runController($controllerID,$actionID)
|
|
{
|
|
if(($controller=$this->createController($controllerID))!==null)
|
|
{
|
|
$oldController=$this->_controller;
|
|
$this->_controller=$controller;
|
|
$controller->run($actionID);
|
|
$this->_controller=$oldController;
|
|
}
|
|
else
|
|
throw new CHttpException(404,Yii::t('yii','The requested controller "{controller}" does not exist.',
|
|
array('{controller}'=>$controllerID===''?$this->defaultController:$controllerID)));
|
|
}
|
|
protected function registerCoreComponents()
|
|
{
|
|
parent::registerCoreComponents();
|
|
$components=array(
|
|
'urlManager'=>array(
|
|
'class'=>'CUrlManager',
|
|
),
|
|
'request'=>array(
|
|
'class'=>'CHttpRequest',
|
|
),
|
|
'session'=>array(
|
|
'class'=>'CHttpSession',
|
|
),
|
|
'assetManager'=>array(
|
|
'class'=>'CAssetManager',
|
|
),
|
|
'user'=>array(
|
|
'class'=>'CWebUser',
|
|
),
|
|
'themeManager'=>array(
|
|
'class'=>'CThemeManager',
|
|
),
|
|
'authManager'=>array(
|
|
'class'=>'CPhpAuthManager',
|
|
),
|
|
'clientScript'=>array(
|
|
'class'=>'CClientScript',
|
|
),
|
|
);
|
|
$this->setComponents($components);
|
|
}
|
|
public function getRequest()
|
|
{
|
|
return $this->getComponent('request');
|
|
}
|
|
public function getUrlManager()
|
|
{
|
|
return $this->getComponent('urlManager');
|
|
}
|
|
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 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 createUrl($route,$params=array(),$ampersand='&')
|
|
{
|
|
return $this->getUrlManager()->createUrl($route,$params,$ampersand);
|
|
}
|
|
public function createAbsoluteUrl($route,$params=array(),$schema='',$ampersand='&')
|
|
{
|
|
return $this->getRequest()->getHostInfo($schema).$this->createUrl($route,$params,$ampersand);
|
|
}
|
|
public function getBaseUrl()
|
|
{
|
|
return $this->getRequest()->getBaseUrl();
|
|
}
|
|
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 createController($id)
|
|
{
|
|
if($id==='')
|
|
$id=$this->defaultController;
|
|
if(!preg_match('/^\w+(\.\w+)*$/',$id))
|
|
return null;
|
|
if(isset($this->controllerMap[$id]))
|
|
return CConfiguration::createObject($this->controllerMap[$id],$id);
|
|
if(($pos=strrpos($id,'.'))!==false)
|
|
{
|
|
$classFile=str_replace('.',DIRECTORY_SEPARATOR,$id).'Controller';
|
|
$classFile[$pos+1]=strtoupper($classFile[$pos+1]);
|
|
$className=basename($classFile);
|
|
$classFile=$this->getControllerPath().DIRECTORY_SEPARATOR.$classFile.'.php';
|
|
}
|
|
else
|
|
{
|
|
$className=ucfirst($id).'Controller';
|
|
$classFile=$this->getControllerPath().DIRECTORY_SEPARATOR.$className.'.php';
|
|
}
|
|
if(is_file($classFile))
|
|
{
|
|
require_once($classFile);
|
|
if(class_exists($className,false) && is_subclass_of($className,'CController'))
|
|
return new $className($id);
|
|
}
|
|
}
|
|
public function getController()
|
|
{
|
|
return $this->_controller;
|
|
}
|
|
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)));
|
|
}
|
|
}
|
|
class CLogger extends CComponent
|
|
{
|
|
const LEVEL_TRACE='trace';
|
|
const LEVEL_WARNING='warning';
|
|
const LEVEL_ERROR='error';
|
|
const LEVEL_INFO='info';
|
|
const LEVEL_PROFILE='profile';
|
|
private $_logs=array();
|
|
private $_levels;
|
|
private $_categories;
|
|
public function log($message,$level='info',$category='application')
|
|
{
|
|
$this->_logs[]=array($message,$level,$category,microtime(true));
|
|
}
|
|
public function getLogs($levels='',$categories='')
|
|
{
|
|
$this->_levels=preg_split('/[\s,]+/',strtolower($levels),-1,PREG_SPLIT_NO_EMPTY);
|
|
$this->_categories=preg_split('/[\s,]+/',strtolower($categories),-1,PREG_SPLIT_NO_EMPTY);
|
|
if(empty($levels) && empty($categories))
|
|
return $this->_logs;
|
|
else if(empty($levels))
|
|
return array_values(array_filter(array_filter($this->_logs,array($this,'filterByCategory'))));
|
|
else if(empty($categories))
|
|
return array_values(array_filter(array_filter($this->_logs,array($this,'filterByLevel'))));
|
|
else
|
|
{
|
|
$ret=array_values(array_filter(array_filter($this->_logs,array($this,'filterByLevel'))));
|
|
return array_values(array_filter(array_filter($ret,array($this,'filterByCategory'))));
|
|
}
|
|
}
|
|
private function filterByCategory($value)
|
|
{
|
|
foreach($this->_categories as $category)
|
|
{
|
|
$cat=strtolower($value[2]);
|
|
if($cat===$category || (($c=rtrim($category,'.*'))!==$category && strpos($cat,$c)===0))
|
|
return $value;
|
|
}
|
|
return false;
|
|
}
|
|
private function filterByLevel($value)
|
|
{
|
|
return in_array(strtolower($value[1]),$this->_levels)?$value:false;
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
abstract class CApplicationComponent extends CComponent implements IApplicationComponent
|
|
{
|
|
private $_initialized=false;
|
|
public function init()
|
|
{
|
|
$this->_initialized=true;
|
|
}
|
|
public function getIsInitialized()
|
|
{
|
|
return $this->_initialized;
|
|
}
|
|
}
|
|
class CUrlManager extends CApplicationComponent
|
|
{
|
|
const CACHE_KEY='CPhpMessageSource.CUrlManager.rules';
|
|
const GET_FORMAT='get';
|
|
const PATH_FORMAT='path';
|
|
public $urlSuffix='';
|
|
public $showScriptName=true;
|
|
public $routeVar='r';
|
|
private $_urlFormat=self::GET_FORMAT;
|
|
private $_rules=array();
|
|
private $_groups=array();
|
|
private $_baseUrl;
|
|
public function init()
|
|
{
|
|
parent::init();
|
|
$this->processRules();
|
|
}
|
|
protected function processRules()
|
|
{
|
|
if(empty($this->_rules) || $this->getUrlFormat()===self::GET_FORMAT)
|
|
return;
|
|
if(($cache=Yii::app()->getCache())!==null)
|
|
{
|
|
$hash=md5(serialize($this->_rules));
|
|
if(($data=$cache->get(self::CACHE_KEY))!==false && isset($data[1]) && $data[1]===$hash)
|
|
{
|
|
$this->_groups=$data[0];
|
|
return;
|
|
}
|
|
}
|
|
foreach($this->_rules as $pattern=>$route)
|
|
$this->_groups[$route][]=new CUrlRule($route,$pattern);
|
|
if($cache!==null)
|
|
$cache->set(self::CACHE_KEY,array($this->_groups,$hash));
|
|
}
|
|
public function getRules()
|
|
{
|
|
return $this->_rules;
|
|
}
|
|
public function setRules($value)
|
|
{
|
|
if($this->_rules===array())
|
|
$this->_rules=$value;
|
|
else
|
|
$this->_rules=array_merge($this->_rules,$value);
|
|
}
|
|
public function createUrl($route,$params=array(),$ampersand='&')
|
|
{
|
|
unset($params[$this->routeVar]);
|
|
if(isset($this->_groups[$route]))
|
|
{
|
|
foreach($this->_groups[$route] as $rule)
|
|
{
|
|
if(($url=$rule->createUrl($params,$this->urlSuffix,$ampersand))!==false)
|
|
return $this->getBaseUrl().'/'.$url;
|
|
}
|
|
}
|
|
return $this->createUrlDefault($route,$params,$ampersand);
|
|
}
|
|
protected function createUrlDefault($route,$params,$ampersand)
|
|
{
|
|
if($this->getUrlFormat()===self::PATH_FORMAT)
|
|
{
|
|
$url=rtrim($this->getBaseUrl().'/'.$route,'/');
|
|
foreach($params as $key=>$value)
|
|
$url.='/'.urlencode($key).'/'.urlencode($value);
|
|
return $url.$this->urlSuffix;
|
|
}
|
|
else
|
|
{
|
|
$pairs=$route!==''?array($this->routeVar.'='.$route):array();
|
|
foreach($params as $key=>$value)
|
|
$pairs[]=urlencode($key).'='.urlencode($value);
|
|
$baseUrl=$this->getBaseUrl();
|
|
if(!$this->showScriptName)
|
|
$baseUrl.='/';
|
|
if(($query=implode($ampersand,$pairs))!=='')
|
|
return $baseUrl.'?'.$query;
|
|
else
|
|
return $baseUrl;
|
|
}
|
|
}
|
|
public function parseUrl($request)
|
|
{
|
|
if($this->getUrlFormat()===self::PATH_FORMAT)
|
|
{
|
|
$pathInfo=$this->removeUrlSuffix($request->getPathInfo());
|
|
foreach($this->_groups as $rules)
|
|
{
|
|
foreach($rules as $rule)
|
|
{
|
|
if(($r=$rule->parseUrl($pathInfo))!==false)
|
|
return isset($_GET[$this->routeVar])?$_GET[$this->routeVar]:$r;
|
|
}
|
|
}
|
|
return $this->parseUrlDefault($pathInfo);
|
|
}
|
|
else if(isset($_GET[$this->routeVar]))
|
|
return $_GET[$this->routeVar];
|
|
else
|
|
return isset($_POST[$this->routeVar])?$_POST[$this->routeVar]:'';
|
|
}
|
|
protected function removeUrlSuffix($pathInfo)
|
|
{
|
|
if(($ext=$this->urlSuffix)!=='' && substr($pathInfo,-strlen($ext))===$ext)
|
|
return substr($pathInfo,0,-strlen($ext));
|
|
else
|
|
return $pathInfo;
|
|
}
|
|
protected function parseUrlDefault($pathInfo)
|
|
{
|
|
$segs=explode('/',$pathInfo.'/');
|
|
$n=count($segs);
|
|
for($i=2;$i<$n-1;$i+=2)
|
|
$_GET[$segs[$i]]=$segs[$i+1];
|
|
return $segs[0].'/'.$segs[1];
|
|
}
|
|
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 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".'));
|
|
}
|
|
}
|
|
class CUrlRule extends CComponent
|
|
{
|
|
public $route;
|
|
public $pattern;
|
|
public $template;
|
|
public $params;
|
|
public $append;
|
|
public $signature;
|
|
public function __construct($route,$pattern)
|
|
{
|
|
$this->route=$route;
|
|
if(preg_match_all('/<(\w+):?(.*?)?>/',$pattern,$matches))
|
|
$this->params=array_combine($matches[1],$matches[2]);
|
|
else
|
|
$this->params=array();
|
|
$p=rtrim($pattern,'*');
|
|
$this->append=$p!==$pattern;
|
|
$p=trim($p,'/');
|
|
$this->template=preg_replace('/<(\w+):?.*?>/','<$1>',$p);
|
|
if(($pos=strpos($p,'<'))!==false)
|
|
$this->signature=substr($p,0,$pos);
|
|
else
|
|
$this->signature=$p;
|
|
$tr['/']='\\/';
|
|
foreach($this->params as $key=>$value)
|
|
$tr["<$key>"]="(?P<$key>".($value!==''?$value:'[^\/]+').')';
|
|
$this->pattern='/^'.strtr($this->template,$tr).'\/';
|
|
if($this->append)
|
|
$this->pattern.='/u';
|
|
else
|
|
$this->pattern.='$/u';
|
|
if(@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($params,$suffix,$ampersand)
|
|
{
|
|
foreach($this->params as $key=>$value)
|
|
{
|
|
if(!isset($params[$key]))
|
|
return false;
|
|
}
|
|
$tr=array();
|
|
$rest=array();
|
|
$sep=$this->append?'/':'=';
|
|
foreach($params as $key=>$value)
|
|
{
|
|
if(isset($this->params[$key]))
|
|
$tr["<$key>"]=$value;
|
|
else
|
|
$rest[]=urlencode($key).$sep.urlencode($value);
|
|
}
|
|
$url=strtr($this->template,$tr);
|
|
if($rest===array())
|
|
return $url!=='' ? $url.$suffix : $url;
|
|
else
|
|
{
|
|
if($this->append)
|
|
{
|
|
$url.='/'.implode('/',$rest);
|
|
if($url!=='')
|
|
$url.=$suffix;
|
|
}
|
|
else
|
|
{
|
|
if($url!=='')
|
|
$url.=$suffix;
|
|
$url.='?'.implode($ampersand,$rest);
|
|
}
|
|
return $url;
|
|
}
|
|
}
|
|
public function parseUrl($pathInfo)
|
|
{
|
|
if(strncmp($pathInfo,$this->signature,strlen($this->signature)))
|
|
return false;
|
|
$pathInfo.='/';
|
|
if(preg_match($this->pattern,$pathInfo,$matches))
|
|
{
|
|
foreach($matches as $key=>$value)
|
|
{
|
|
if(is_string($key))
|
|
$_GET[$key]=$value;
|
|
}
|
|
if($pathInfo!==$matches[0])
|
|
{
|
|
$segs=explode('/',ltrim(substr($pathInfo,strlen($matches[0])),'/'));
|
|
$n=count($segs);
|
|
for($i=0;$i<$n-1;$i+=2)
|
|
$_GET[$segs[$i]]=$segs[$i+1];
|
|
}
|
|
return $this->route;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
class CHttpRequest extends CApplicationComponent
|
|
{
|
|
public $enableCookieValidation=false;
|
|
public $enableCsrfValidation=false;
|
|
public $csrfTokenName='YII_CSRF_TOKEN';
|
|
public $csrfCookie;
|
|
private $_pathInfo;
|
|
private $_scriptFile;
|
|
private $_scriptUrl;
|
|
private $_hostInfo;
|
|
private $_url;
|
|
private $_baseUrl;
|
|
private $_cookies;
|
|
private $_preferredLanguage;
|
|
private $_csrfToken;
|
|
public function init()
|
|
{
|
|
parent::init();
|
|
$this->normalizeRequest();
|
|
}
|
|
protected function normalizeRequest()
|
|
{
|
|
// normalize request
|
|
if(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 && !$this->performCsrfValidation())
|
|
throw new CHttpException(400,Yii::t('yii','The CSRF token could not be verified.'));
|
|
}
|
|
public function stripSlashes(&$data)
|
|
{
|
|
return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data);
|
|
}
|
|
public function getUrl()
|
|
{
|
|
if($this->_url!==null)
|
|
return $this->_url;
|
|
else
|
|
{
|
|
if(isset($_SERVER['REQUEST_URI']))
|
|
$this->_url=$_SERVER['REQUEST_URI'];
|
|
else
|
|
{
|
|
$this->_url=$this->getScriptUrl();
|
|
if(($pathInfo=$this->getPathInfo())!=='')
|
|
$this->_url.='/'.$pathInfo;
|
|
if(($queryString=$this->getQueryString())!=='')
|
|
$this->_url.='?'.$queryString;
|
|
}
|
|
return $this->_url;
|
|
}
|
|
}
|
|
public function getHostInfo($schema='')
|
|
{
|
|
if($this->_hostInfo===null)
|
|
{
|
|
if($secure=$this->getIsSecureConnection())
|
|
$schema='https';
|
|
else
|
|
$schema='http';
|
|
$segs=explode(':',$_SERVER['HTTP_HOST']);
|
|
$url=$schema.'://'.$segs[0];
|
|
$port=$_SERVER['SERVER_PORT'];
|
|
if(($port!=80 && !$secure) || ($port!=443 && $secure))
|
|
$url.=':'.$port;
|
|
$this->_hostInfo=$url;
|
|
}
|
|
if($schema!=='' && ($pos=strpos($this->_hostInfo,':'))!==false)
|
|
return $schema.substr($this->_hostInfo,$pos);
|
|
else
|
|
return $this->_hostInfo;
|
|
}
|
|
public function setHostInfo($value)
|
|
{
|
|
$this->_hostInfo=rtrim($value,'/');
|
|
}
|
|
public function getBaseUrl()
|
|
{
|
|
if($this->_baseUrl===null)
|
|
$this->_baseUrl=rtrim(dirname($this->getScriptUrl()),'\\/');
|
|
return $this->_baseUrl;
|
|
}
|
|
public function setBaseUrl($value)
|
|
{
|
|
$this->_baseUrl=$value;
|
|
}
|
|
public function getScriptUrl()
|
|
{
|
|
if($this->_scriptUrl!==null)
|
|
return $this->_scriptUrl;
|
|
else
|
|
{
|
|
if(isset($_SERVER['SCRIPT_NAME']))
|
|
$this->_scriptUrl=$_SERVER['SCRIPT_NAME'];
|
|
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)
|
|
$this->_pathInfo=trim(isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : $this->guessPathInfo(), '/');
|
|
return $this->_pathInfo;
|
|
}
|
|
protected function guessPathInfo()
|
|
{
|
|
if($_SERVER['PHP_SELF']!==$_SERVER['SCRIPT_NAME'])
|
|
{
|
|
if(strpos($_SERVER['PHP_SELF'],$_SERVER['SCRIPT_NAME'])===0)
|
|
return substr($_SERVER['PHP_SELF'],strlen($_SERVER['SCRIPT_NAME']));
|
|
}
|
|
else if(isset($_SERVER['REQUEST_URI']) && strpos($_SERVER['REQUEST_URI'],$_SERVER['SCRIPT_NAME'])!==0)
|
|
{
|
|
// REQUEST_URI doesn't contain SCRIPT_NAME, which means some rewrite rule is in effect
|
|
$base=strtr(dirname($_SERVER['SCRIPT_NAME']),'\\','/');
|
|
if(strpos($_SERVER['REQUEST_URI'],$base)===0)
|
|
{
|
|
$pathInfo=substr($_SERVER['REQUEST_URI'],strlen($base));
|
|
if(($pos=strpos($pathInfo,'?'))!==false)
|
|
return substr($pathInfo,0,$pos);
|
|
else
|
|
return $pathInfo;
|
|
}
|
|
}
|
|
return '';
|
|
}
|
|
public function getQueryString()
|
|
{
|
|
return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:'';
|
|
}
|
|
public function getIsSecureConnection()
|
|
{
|
|
return isset($_SERVER['HTTPS']) && !strcasecmp($_SERVER['HTTPS'],'on');
|
|
}
|
|
public function getRequestType()
|
|
{
|
|
return strtoupper(isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:'GET');
|
|
}
|
|
public function getIsPostRequest()
|
|
{
|
|
return !strcasecmp($_SERVER['REQUEST_METHOD'],'POST');
|
|
}
|
|
public function getIsAjaxRequest()
|
|
{
|
|
return isset($_SERVER['HTTP_X_REQUESTED_WITH'])?$_SERVER['HTTP_X_REQUESTED_WITH']==='XMLHttpRequest' : 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 $_SERVER['HTTP_USER_AGENT'];
|
|
}
|
|
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()
|
|
{
|
|
return get_browser();
|
|
}
|
|
public function getAcceptTypes()
|
|
{
|
|
return $_SERVER['HTTP_ACCEPT'];
|
|
}
|
|
public function getCookies()
|
|
{
|
|
if($this->_cookies!==null)
|
|
return $this->_cookies;
|
|
else
|
|
return $this->_cookies=new CCookieCollection($this);
|
|
}
|
|
public function redirect($url,$terminate=true)
|
|
{
|
|
if(strpos($url,'/')===0)
|
|
$url=$this->getHostInfo().$url;
|
|
header('Location: '.$url);
|
|
if($terminate)
|
|
Yii::app()->end();
|
|
}
|
|
public function getPreferredLanguage()
|
|
{
|
|
if($this->_preferredLanguage===null)
|
|
{
|
|
if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && ($n=preg_match_all('/([\w\-_]+)\s*(;\s*q\s*=\s*(\d*\.\d*))?/',$_SERVER['HTTP_ACCEPT_LANGUAGE'],$matches))>0)
|
|
{
|
|
$languages=array();
|
|
for($i=0;$i<$n;++$i)
|
|
$languages[$matches[1][$i]]=empty($matches[3][$i]) ? 1.0 : floatval($matches[3][$i]);
|
|
arsort($languages);
|
|
foreach($languages as $language=>$pref)
|
|
return $this->_preferredLanguage=CLocale::getCanonicalID($language);
|
|
}
|
|
return $this->_preferredLanguage=false;
|
|
}
|
|
return $this->_preferredLanguage;
|
|
}
|
|
public function sendFile($fileName,$content,$mimeType=null,$terminate=true)
|
|
{
|
|
if($mimeType===null)
|
|
{
|
|
if(($mimeType=CFileHelper::getMimeTypeByExtension($fileName))===null)
|
|
$mimeType='text/plain';
|
|
}
|
|
header('Pragma: public');
|
|
header('Expires: 0');
|
|
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
|
header("Content-type: $mimeType");
|
|
header('Content-Length: '.strlen($content));
|
|
header("Content-Disposition: attachment; filename=\"$fileName\"");
|
|
header('Content-Transfer-Encoding: binary');
|
|
echo $content;
|
|
if($terminate)
|
|
Yii::app()->end();
|
|
}
|
|
public function getCsrfToken()
|
|
{
|
|
if($this->_csrfToken===null)
|
|
{
|
|
if(($this->_csrfToken=$this->getCsrfTokenFromCookie())===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(rand(),true)));
|
|
if(is_array($this->csrfCookie))
|
|
{
|
|
foreach($this->csrfCookie as $name=>$value)
|
|
$cookie->$name=$value;
|
|
}
|
|
return $cookie;
|
|
}
|
|
protected function performCsrfValidation()
|
|
{
|
|
if(!$this->getIsPostRequest())
|
|
return true;
|
|
$cookies=$this->getCookies();
|
|
if($cookies->contains($this->csrfTokenName) && isset($_POST[$this->csrfTokenName]))
|
|
{
|
|
$tokenFromCookie=$cookies->itemAt($this->csrfTokenName)->value;
|
|
$tokenFromPost=$_POST[$this->csrfTokenName];
|
|
return $tokenFromCookie===$tokenFromPost;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
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(($value=$sm->validateData($value))!==false)
|
|
$cookies[$name]=new CHttpCookie($name,$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)
|
|
{
|
|
if(($cookie=parent::remove($name))!==null)
|
|
{
|
|
if($this->_initialized)
|
|
$this->removeCookie($cookie);
|
|
}
|
|
return $cookie;
|
|
}
|
|
protected function addCookie($cookie)
|
|
{
|
|
$value=$cookie->value;
|
|
if($this->_request->enableCookieValidation)
|
|
$value=Yii::app()->getSecurityManager()->hashData($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,null,0,$cookie->path,$cookie->domain,$cookie->secure,$cookie->httpOnly);
|
|
else
|
|
setcookie($cookie->name,null,0,$cookie->path,$cookie->domain,$cookie->secure);
|
|
}
|
|
}
|
|
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)
|
|
$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())
|
|
{
|
|
$className=Yii::import($className,true);
|
|
$widget=new $className($this);
|
|
foreach($properties as $name=>$value)
|
|
$widget->$name=$value;
|
|
$widget->init();
|
|
return $widget;
|
|
}
|
|
public function widget($className,$properties=array())
|
|
{
|
|
$widget=$this->createWidget($className,$properties);
|
|
$widget->run();
|
|
}
|
|
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,$properties=array())
|
|
{
|
|
$properties['view']=$view;
|
|
$this->beginWidget('CContentDecorator',$properties);
|
|
}
|
|
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;
|
|
public function __construct($id)
|
|
{
|
|
$this->_id=$id;
|
|
}
|
|
public function filters()
|
|
{
|
|
return array();
|
|
}
|
|
public function actions()
|
|
{
|
|
return array();
|
|
}
|
|
public function accessRules()
|
|
{
|
|
return array();
|
|
}
|
|
public function run($actionID)
|
|
{
|
|
if(($action=$this->createAction($actionID))!==null)
|
|
$this->runActionWithFilters($action,$this->filters());
|
|
else
|
|
$this->missingAction($actionID);
|
|
}
|
|
public function runActionWithFilters($action,$filters=array())
|
|
{
|
|
if(!empty($filters))
|
|
{
|
|
$priorAction=$this->_action;
|
|
$this->_action=$action;
|
|
CFilterChain::create($this,$action,$filters)->run();
|
|
$this->_action=$priorAction;
|
|
}
|
|
else
|
|
$this->runAction($action);
|
|
}
|
|
public function runAction($action)
|
|
{
|
|
$priorAction=$this->_action;
|
|
$this->_action=$action;
|
|
if($this->beforeAction($action))
|
|
{
|
|
$action->run();
|
|
$this->afterAction($action);
|
|
}
|
|
$this->_action=$priorAction;
|
|
}
|
|
public function processOutput($output)
|
|
{
|
|
Yii::app()->getClientScript()->render($output);
|
|
if($this->_dynamicOutput)
|
|
{
|
|
$output=preg_replace_callback('/<###dynamic-(\d+)###>/',array($this,'replaceDynamicOutput'),$output);
|
|
$this->_dynamicOutput=null;
|
|
}
|
|
if($this->_pageStates!==null || isset($_POST[self::STATE_INPUT_NAME]))
|
|
{
|
|
$states=$this->savePageStates();
|
|
$output=str_replace(CHtml::pageStateField(''),CHtml::pageStateField($states),$output);
|
|
}
|
|
return $output;
|
|
}
|
|
protected function replaceDynamicOutput($matches)
|
|
{
|
|
return isset($this->_dynamicOutput[$matches[1]]) ? $this->_dynamicOutput[$matches[1]] : $matches[0];
|
|
}
|
|
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);
|
|
$actionMap=$this->actions();
|
|
if(isset($actionMap[$actionID]))
|
|
{
|
|
$c=$actionMap[$actionID];
|
|
if(is_string($c))
|
|
{
|
|
$className=Yii::import($c,true);
|
|
return new $className($this,$actionID);
|
|
}
|
|
else
|
|
return CConfiguration::createObject($c,$this,$actionID);
|
|
}
|
|
return null;
|
|
}
|
|
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 getViewPath()
|
|
{
|
|
return Yii::app()->getViewPath().DIRECTORY_SEPARATOR.str_replace('.',DIRECTORY_SEPARATOR,$this->getId());
|
|
}
|
|
public function getViewFile($viewName)
|
|
{
|
|
if(($theme=Yii::app()->getTheme())!==null && ($viewFile=$theme->getViewFile($this,$viewName))!==false)
|
|
return $viewFile;
|
|
if($viewName[0]==='/')
|
|
$viewFile=Yii::app()->getViewPath().$viewName.'.php';
|
|
else
|
|
$viewFile=$this->getViewPath().DIRECTORY_SEPARATOR.$viewName.'.php';
|
|
return is_file($viewFile) ? Yii::app()->findLocalizedFile($viewFile) : false;
|
|
}
|
|
public function getLayoutFile($layoutName)
|
|
{
|
|
if(($theme=Yii::app()->getTheme())!==null && ($layoutFile=$theme->getLayoutFile($this,$layoutName))!==false)
|
|
return $layoutFile;
|
|
if($layoutName[0]==='/')
|
|
$layoutFile=Yii::app()->getViewPath().$layoutName.'.php';
|
|
else
|
|
$layoutFile=Yii::app()->getLayoutPath().DIRECTORY_SEPARATOR.$layoutName.'.php';
|
|
return is_file($layoutFile) ? Yii::app()->findLocalizedFile($layoutFile) : false;
|
|
}
|
|
public function getClips()
|
|
{
|
|
if($this->_clips!==null)
|
|
return $this->_clips;
|
|
else
|
|
return $this->_clips=new CMap;
|
|
}
|
|
public function render($view,$data=null,$return=false)
|
|
{
|
|
if(($layout=$this->layout)==null)
|
|
$layout=Yii::app()->layout;
|
|
$output=$this->renderPartial($view,$data,true);
|
|
if(!empty($layout) && ($layoutFile=$this->getLayoutFile($layout))!==false)
|
|
$output=$this->renderFile($layoutFile,array('content'=>$output),true);
|
|
$output=$this->processOutput($output);
|
|
if($return)
|
|
return $output;
|
|
else
|
|
echo $output;
|
|
}
|
|
public function renderText($text,$return=false)
|
|
{
|
|
if(($layout=$this->layout)==null)
|
|
$layout=Yii::app()->layout;
|
|
if(!empty($layout) && ($layoutFile=$this->getLayoutFile($layout))!==false)
|
|
$output=$this->renderFile($layoutFile,array('content'=>$text),true);
|
|
$output=$this->processOutput($output);
|
|
if($return)
|
|
return $output;
|
|
else
|
|
echo $output;
|
|
}
|
|
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 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)
|
|
{
|
|
if(is_string($callback) && method_exists($this,$callback))
|
|
$callback=array($this,$callback);
|
|
$this->_dynamicOutput[]=call_user_func_array($callback,$params);
|
|
$this->recordCachingAction('','renderDynamicInternal',array($callback,$params));
|
|
}
|
|
public function createUrl($route,$params=array(),$ampersand='&')
|
|
{
|
|
if(strpos($route,'/')===false)
|
|
$route=$this->getId().'/'.($route==='' ? $this->getAction()->getId() : $route);
|
|
return Yii::app()->createUrl($route,$params,$ampersand);
|
|
}
|
|
public function createAbsoluteUrl($route,$params=array(),$schema='',$ampersand='&')
|
|
{
|
|
return Yii::app()->getRequest()->getHostInfo($schema).$this->createUrl($route,$params,$ampersand);
|
|
}
|
|
public function getPageTitle()
|
|
{
|
|
if($this->_pageTitle!==null)
|
|
return $this->_pageTitle;
|
|
else
|
|
{
|
|
$name=ucfirst(basename(str_replace('.','/',$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)
|
|
{
|
|
if(is_array($url))
|
|
{
|
|
$route=isset($url[0]) ? $url[0] : '';
|
|
$url=$this->createUrl($route,array_splice($url,1));
|
|
}
|
|
Yii::app()->getRequest()->redirect($url,$terminate);
|
|
}
|
|
public function refresh($terminate=true)
|
|
{
|
|
$this->redirect(Yii::app()->getRequest()->getUrl(),$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()
|
|
{
|
|
if(!$this->_cachingStack)
|
|
$this->_cachingStack=new CStack;
|
|
return $this->_cachingStack;
|
|
}
|
|
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 not valid.'));
|
|
}
|
|
public function filterAjaxOnly($filterChain)
|
|
{
|
|
if(Yii::app()->getRequest()->getIsAjaxRequest())
|
|
$filterChain->run();
|
|
else
|
|
throw new CHttpException(400,Yii::t('yii','Your request is not valid.'));
|
|
}
|
|
public function filterAccessControl($filterChain)
|
|
{
|
|
$filter=new CAccessControlFilter;
|
|
$filter->setRules($this->accessRules());
|
|
$filter->filter($filterChain);
|
|
}
|
|
public function paginate($itemCount,$pageSize=null,$pageVar=null)
|
|
{
|
|
$pages=new CPagination;
|
|
$pages->setItemCount($itemCount);
|
|
if($pageSize!==null)
|
|
$pages->pageSize=$pageSize;
|
|
if($pageVar!==null)
|
|
$pages->pageVar=$pageVar;
|
|
return $pages;
|
|
}
|
|
public function getPageState($name,$defaultValue=null)
|
|
{
|
|
if($this->_pageStates===null)
|
|
$this->loadPageStates();
|
|
return isset($this->_pageStates[$name])?$this->_pageStates[$name]:$defaultValue;
|
|
}
|
|
public function setPageState($name,$value,$defaultValue=null)
|
|
{
|
|
if($this->_pageStates===null)
|
|
$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(isset($_POST[self::STATE_INPUT_NAME]) && !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)
|
|
{
|
|
$this->_pageStates=unserialize($data);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
$this->_pageStates=array();
|
|
}
|
|
protected function savePageStates()
|
|
{
|
|
if($this->_pageStates===null)
|
|
$this->loadPageStates();
|
|
if(empty($this->_pageStates))
|
|
return '';
|
|
else
|
|
{
|
|
$data=Yii::app()->getSecurityManager()->hashData(serialize($this->_pageStates));
|
|
if(extension_loaded('zlib'))
|
|
$data=gzcompress($data);
|
|
return base64_encode($data);
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
class CInlineAction extends CAction
|
|
{
|
|
public function run()
|
|
{
|
|
$method='action'.$this->getId();
|
|
$this->getController()->$method();
|
|
}
|
|
}
|
|
class CWebUser extends CApplicationComponent implements IWebUser
|
|
{
|
|
const FLASH_KEY_PREFIX='Yii.CWebUser.flash.';
|
|
const FLASH_COUNTERS='Yii.CWebUser.flash.counters';
|
|
public $allowAutoLogin=false;
|
|
public $guestName='Guest';
|
|
public $loginUrl=array('site/login');
|
|
private $_keyPrefix;
|
|
public function init()
|
|
{
|
|
parent::init();
|
|
Yii::app()->getSession()->open();
|
|
if($this->getIsGuest() && $this->allowAutoLogin)
|
|
$this->restoreFromCookie();
|
|
$this->updateFlash();
|
|
}
|
|
public function login($identity,$duration=0)
|
|
{
|
|
$this->changeIdentity($identity->getId(),$identity->getName(),$identity->getPersistentStates());
|
|
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))));
|
|
}
|
|
}
|
|
public function logout()
|
|
{
|
|
if($this->allowAutoLogin)
|
|
Yii::app()->getRequest()->getCookies()->remove($this->getStateKeyPrefix());
|
|
$this->clearStates();
|
|
}
|
|
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()
|
|
{
|
|
return $this->getState('_returnUrl',Yii::app()->getRequest()->getScriptUrl());
|
|
}
|
|
public function setReturnUrl($value)
|
|
{
|
|
$this->setState('_returnUrl',$value);
|
|
}
|
|
public function loginRequired()
|
|
{
|
|
$app=Yii::app();
|
|
$request=$app->getRequest();
|
|
$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);
|
|
}
|
|
else
|
|
throw new CHttpException(401,Yii::t('yii','Login Required'));
|
|
}
|
|
protected function restoreFromCookie()
|
|
{
|
|
$app=Yii::app();
|
|
$cookie=$app->getRequest()->getCookies()->itemAt($this->getStateKeyPrefix());
|
|
if($cookie && !empty($cookie->value) && ($data=$app->getSecurityManager()->validateData($cookie->value))!==false)
|
|
{
|
|
$data=unserialize($data);
|
|
if(isset($data[0],$data[1],$data[2],$data[3]))
|
|
{
|
|
list($id,$name,$address,$states)=$data;
|
|
if($address===$app->getRequest()->getUserHostAddress())
|
|
$this->changeIdentity($id,$name,$states);
|
|
}
|
|
}
|
|
}
|
|
protected function saveToCookie($duration)
|
|
{
|
|
$app=Yii::app();
|
|
$cookie=new CHttpCookie($this->getStateKeyPrefix(),'');
|
|
$cookie->expire=time()+$duration;
|
|
$data=array(
|
|
$this->getId(),
|
|
$this->getName(),
|
|
$app->getRequest()->getUserHostAddress(),
|
|
$this->saveIdentityStates(),
|
|
);
|
|
$cookie->value=$app->getSecurityManager()->hashData(serialize($data));
|
|
$app->getRequest()->getCookies()->add($cookie->name,$cookie);
|
|
}
|
|
public function onRestoreFromCookie($event)
|
|
{
|
|
$this->raiseEvent('onRestoreFromCookie',$event);
|
|
}
|
|
protected function getStateKeyPrefix()
|
|
{
|
|
if($this->_keyPrefix!==null)
|
|
return $this->_keyPrefix;
|
|
else
|
|
return $this->_keyPrefix=md5('Yii.'.get_class($this).'.'.Yii::app()->getId());
|
|
}
|
|
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 clearStates()
|
|
{
|
|
Yii::app()->getSession()->destroy();
|
|
}
|
|
public function getFlash($key,$defaultValue=null)
|
|
{
|
|
return $this->getState(self::FLASH_KEY_PREFIX.$key,$defaultValue);
|
|
}
|
|
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;
|
|
}
|
|
protected function changeIdentity($id,$name,$states)
|
|
{
|
|
$this->setId($id);
|
|
$this->setName($name);
|
|
$this->loadIdentityStates($states);
|
|
}
|
|
protected function saveIdentityStates()
|
|
{
|
|
$states=array();
|
|
foreach($this->getState('_states',array()) as $name)
|
|
$states[$name]=$this->getState($name);
|
|
return $states;
|
|
}
|
|
protected function loadIdentityStates($states)
|
|
{
|
|
if(is_array($states))
|
|
{
|
|
foreach($states as $name=>$value)
|
|
$this->setState($name,$value);
|
|
$this->setState('_states',array_keys($states));
|
|
}
|
|
else
|
|
$this->setState('_states',array());
|
|
}
|
|
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());
|
|
}
|
|
public function checkAccess($operation,$params=array())
|
|
{
|
|
return Yii::app()->getAuthManager()->checkAccess($operation,$this->getId(),$params);
|
|
}
|
|
}
|
|
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(session_id()==='')
|
|
{
|
|
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();
|
|
}
|
|
}
|
|
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 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);
|
|
session_set_cookie_params($lifetime,$path,$domain,$secure);
|
|
}
|
|
public function getCookieMode()
|
|
{
|
|
if(ini_get('session.use_cookies')==='0')
|
|
return 'none';
|
|
else if(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');
|
|
else if($value==='allow')
|
|
{
|
|
ini_set('session.use_cookies','1');
|
|
ini_set('session.use_only_cookies','0');
|
|
}
|
|
else if($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 (int)ini_get('session.gc_probability');
|
|
}
|
|
public function setGCProbability($value)
|
|
{
|
|
$value=(int)$value;
|
|
if($value>=0 && $value<=100)
|
|
{
|
|
ini_set('session.gc_probability',$value);
|
|
ini_set('session.gc_divisor','100');
|
|
}
|
|
else
|
|
throw new CException(Yii::t('yii','CHttpSession.gcProbability "{value}" is invalid. It must be an integer 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 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 CHttpSessionIterator implements Iterator
|
|
{
|
|
private $_keys;
|
|
private $_key;
|
|
public function __construct()
|
|
{
|
|
$this->_keys=array_keys($_SESSION);
|
|
}
|
|
public function rewind()
|
|
{
|
|
$this->_key=reset($this->_keys);
|
|
}
|
|
public function key()
|
|
{
|
|
return $this->_key;
|
|
}
|
|
public function current()
|
|
{
|
|
return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null;
|
|
}
|
|
public function next()
|
|
{
|
|
do
|
|
{
|
|
$this->_key=next($this->_keys);
|
|
}
|
|
while(!isset($_SESSION[$this->_key]) && $this->_key!==false);
|
|
}
|
|
public function valid()
|
|
{
|
|
return $this->_key!==false;
|
|
}
|
|
}
|
|
class CHtml
|
|
{
|
|
const ID_PREFIX='yt';
|
|
public static $errorSummaryCss='errorSummary';
|
|
public static $errorMessageCss='errorMessage';
|
|
public static $errorCss='error';
|
|
private static $_count=0;
|
|
public static function encode($text)
|
|
{
|
|
return htmlspecialchars($text,ENT_QUOTES,Yii::app()->charset);
|
|
}
|
|
public static function tag($tag,$htmlOptions=array(),$content=false,$closeTag=true)
|
|
{
|
|
$html='<' . $tag;
|
|
foreach($htmlOptions as $name=>$value)
|
|
$html .= ' ' . $name . '="' . self::encode($value) . '"';
|
|
if($content===false)
|
|
return $closeTag ? $html.'/>' : $html.'>';
|
|
else
|
|
return $closeTag ? $html.'>'.$content.'</'.$tag.'>' : $html.'>'.$content;
|
|
}
|
|
public static function openTag($tag,$htmlOptions=array())
|
|
{
|
|
$html='<' . $tag;
|
|
foreach($htmlOptions as $name=>$value)
|
|
$html .= ' ' . $name . '="' . self::encode($value) . '"';
|
|
return $html . '>';
|
|
}
|
|
public static function closeTag($tag)
|
|
{
|
|
return '</'.$tag.'>';
|
|
}
|
|
public static function cdata($text)
|
|
{
|
|
return '<![CDATA[' . $text . ']]>';
|
|
}
|
|
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 cssFile($url,$media='')
|
|
{
|
|
if($media!=='')
|
|
$media=' media="'.$media.'"';
|
|
return '<link rel="stylesheet" type="text/css" href="'.self::encode($url).'"'.$media.'/>';
|
|
}
|
|
public static function script($text)
|
|
{
|
|
return "<script type=\"text/javascript\">\n/*<![CDATA[*/\n{$text}\n/*]]>*/\n</script>";
|
|
}
|
|
public static function scriptFile($url)
|
|
{
|
|
return '<script type="text/javascript" src="'.self::encode($url).'"></script>';
|
|
}
|
|
public static function form($action='',$method='post',$htmlOptions=array())
|
|
{
|
|
$htmlOptions['action']=self::normalizeUrl($action);
|
|
$htmlOptions['method']=$method;
|
|
$form=self::tag('form',$htmlOptions,false,false);
|
|
$request=Yii::app()->request;
|
|
if($request->enableCsrfValidation)
|
|
{
|
|
$token=self::hiddenField($request->csrfTokenName,$request->getCsrfToken());
|
|
$form.="\n".$token;
|
|
}
|
|
return $form;
|
|
}
|
|
public static function statefulForm($action='',$method='post',$htmlOptions=array())
|
|
{
|
|
return self::form($action,$method,$htmlOptions)."\n".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 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']))
|
|
$htmlOptions['name']=self::ID_PREFIX.self::$_count++;
|
|
if(!isset($htmlOptions['type']))
|
|
$htmlOptions['type']='button';
|
|
if(!isset($htmlOptions['value']))
|
|
$htmlOptions['value']=$label;
|
|
self::clientChange('click',$htmlOptions);
|
|
return self::tag('input',$htmlOptions);
|
|
}
|
|
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())
|
|
{
|
|
$htmlOptions['for']=$for;
|
|
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 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);
|
|
self::clientChange('change',$htmlOptions);
|
|
return self::tag('textarea',$htmlOptions,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);
|
|
return 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);
|
|
return 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);
|
|
self::clientChange('change',$htmlOptions);
|
|
$options="\n".self::listOptions($select,$data,$htmlOptions);
|
|
return self::tag('select',$htmlOptions,$options);
|
|
}
|
|
public static function listBox($name,$select,$data,$htmlOptions=array())
|
|
{
|
|
if(!isset($htmlOptions['size']))
|
|
$htmlOptions['size']=4;
|
|
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";
|
|
unset($htmlOptions['template'],$htmlOptions['separator']);
|
|
if(substr($name,-2)!=='[]')
|
|
$name.='[]';
|
|
$items=array();
|
|
$baseID=self::getIdByName($name);
|
|
$id=0;
|
|
foreach($data as $value=>$label)
|
|
{
|
|
$checked=!is_array($select) && !strcmp($value,$select) || is_array($select) && in_array($value,$select);
|
|
$htmlOptions['value']=$value;
|
|
$htmlOptions['id']=$baseID.'_'.$id++;
|
|
$option=self::checkBox($name,$checked,$htmlOptions);
|
|
$items[]=strtr($template,array('{input}'=>$option,'{label}'=>$label));
|
|
}
|
|
return 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";
|
|
unset($htmlOptions['template'],$htmlOptions['separator']);
|
|
$items=array();
|
|
$baseID=self::getIdByName($name);
|
|
$id=0;
|
|
foreach($data as $value=>$label)
|
|
{
|
|
$checked=!strcmp($value,$select);
|
|
$htmlOptions['value']=$value;
|
|
$htmlOptions['id']=$baseID.'_'.$id++;
|
|
$option=self::radioButton($name,$checked,$htmlOptions);
|
|
$items[]=strtr($template,array('{input}'=>$option,'{label}'=>$label));
|
|
}
|
|
return 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';
|
|
return self::ajaxButton($label,$url,$ajaxOptions,$htmlOptions);
|
|
}
|
|
public static function ajax($options)
|
|
{
|
|
Yii::app()->getClientScript()->registerCoreScript('jquery');
|
|
if(!isset($options['url']))
|
|
$options['url']='js: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']='js:jQuery(this).parents("form").serialize()';
|
|
foreach(array('beforeSend','complete','error','success') as $name)
|
|
{
|
|
if(isset($options[$name]) && strpos($options[$name],'js:')!==0)
|
|
$options[$name]='js:'.$options[$name];
|
|
}
|
|
if(isset($options['update']))
|
|
{
|
|
if(!isset($options['success']))
|
|
$options['success']='js:function(html){jQuery("'.$options['update'].'").html(html)}';
|
|
unset($options['update']);
|
|
}
|
|
if(isset($options['replace']))
|
|
{
|
|
if(!isset($options['success']))
|
|
$options['success']='js: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 coreScript($name)
|
|
{
|
|
return Yii::app()->getClientScript()->renderCoreScript($name);
|
|
}
|
|
public static function normalizeUrl($url)
|
|
{
|
|
if(is_array($url))
|
|
$url=isset($url[0]) ? Yii::app()->getController()->createUrl($url[0],array_splice($url,1)) : '';
|
|
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);
|
|
return self::tag('input',$htmlOptions);
|
|
}
|
|
public static function activeLabel($model,$attribute,$htmlOptions=array())
|
|
{
|
|
if(($pos=strpos($attribute,'['))!==false)
|
|
$name=get_class($model).substr($attribute,$pos).'['.($attribute=substr($attribute,0,$pos)).']';
|
|
else
|
|
$name=get_class($model).'['.$attribute.']';
|
|
$label=$model->getAttributeLabel($attribute);
|
|
$for=self::getIdByName($name);
|
|
if($model->hasErrors($attribute))
|
|
self::addErrorCss($htmlOptions);
|
|
return self::label($label,$for,$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 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);
|
|
return self::tag('textarea',$htmlOptions,self::encode($model->$attribute));
|
|
}
|
|
public static function activeFileField($model,$attribute,$htmlOptions=array())
|
|
{
|
|
self::resolveNameID($model,$attribute,$htmlOptions);
|
|
return self::activeInputField('file',$model,$attribute,$htmlOptions);
|
|
}
|
|
public static function activeRadioButton($model,$attribute,$htmlOptions=array())
|
|
{
|
|
if(!isset($htmlOptions['value']))
|
|
$htmlOptions['value']=1;
|
|
if($model->$attribute)
|
|
$htmlOptions['checked']='checked';
|
|
self::resolveNameID($model,$attribute,$htmlOptions);
|
|
self::clientChange('click',$htmlOptions);
|
|
return self::hiddenField($htmlOptions['name'],$htmlOptions['value']?0:-1)
|
|
. self::activeInputField('radio',$model,$attribute,$htmlOptions);
|
|
}
|
|
public static function activeCheckBox($model,$attribute,$htmlOptions=array())
|
|
{
|
|
if(!isset($htmlOptions['value']))
|
|
$htmlOptions['value']=1;
|
|
if($model->$attribute)
|
|
$htmlOptions['checked']='checked';
|
|
self::resolveNameID($model,$attribute,$htmlOptions);
|
|
self::clientChange('click',$htmlOptions);
|
|
return self::hiddenField($htmlOptions['name'],'')
|
|
. self::activeInputField('checkbox',$model,$attribute,$htmlOptions);
|
|
}
|
|
public static function activeDropDownList($model,$attribute,$data,$htmlOptions=array())
|
|
{
|
|
$selection=$model->$attribute;
|
|
$options="\n".self::listOptions($selection,$data,$htmlOptions);
|
|
self::resolveNameID($model,$attribute,$htmlOptions);
|
|
self::clientChange('change',$htmlOptions);
|
|
if($model->hasErrors($attribute))
|
|
self::addErrorCss($htmlOptions);
|
|
return 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())
|
|
{
|
|
$selection=$model->$attribute;
|
|
self::resolveNameID($model,$attribute,$htmlOptions);
|
|
if($model->hasErrors($attribute))
|
|
self::addErrorCss($htmlOptions);
|
|
$name=$htmlOptions['name'];
|
|
unset($htmlOptions['name'],$htmlOptions['id']);
|
|
return self::hiddenField($name,'')
|
|
. self::checkBoxList($name,$selection,$data,$htmlOptions);
|
|
}
|
|
public static function activeRadioButtonList($model,$attribute,$data,$htmlOptions=array())
|
|
{
|
|
$selection=$model->$attribute;
|
|
self::resolveNameID($model,$attribute,$htmlOptions);
|
|
if($model->hasErrors($attribute))
|
|
self::addErrorCss($htmlOptions);
|
|
$name=$htmlOptions['name'];
|
|
unset($htmlOptions['name'],$htmlOptions['id']);
|
|
return self::hiddenField($name,'')
|
|
. self::radioButtonList($name,$selection,$data,$htmlOptions);
|
|
}
|
|
public static function getActiveId($model,$attribute)
|
|
{
|
|
return get_class($model).'_'.$attribute;
|
|
}
|
|
public static function errorSummary($model,$header='',$footer='')
|
|
{
|
|
if($header==='')
|
|
$header='<p>'.Yii::t('yii','Please fix the following input errors:').'</p>';
|
|
$content='';
|
|
if(!is_array($model))
|
|
$model=array($model);
|
|
foreach($model as $m)
|
|
{
|
|
foreach($m->getErrors() as $errors)
|
|
{
|
|
foreach($errors as $error)
|
|
$content.="<li>$error</li>\n";
|
|
}
|
|
}
|
|
if($content!=='')
|
|
return self::tag('div',array('class'=>self::$errorSummaryCss),$header."\n<ul>\n$content</ul>".$footer);
|
|
else
|
|
return '';
|
|
}
|
|
public static function error($model,$attribute)
|
|
{
|
|
$errors=$model->getErrors($attribute);
|
|
if(!empty($errors))
|
|
return self::tag('div',array('class'=>self::$errorMessageCss),reset($errors));
|
|
else
|
|
return '';
|
|
}
|
|
public static function listData($models,$valueField,$textField,$groupField='')
|
|
{
|
|
$listData=array();
|
|
if($groupField==='')
|
|
{
|
|
foreach($models as $model)
|
|
$listData[$model->$valueField]=$model->$textField;
|
|
}
|
|
else
|
|
{
|
|
foreach($models as $model)
|
|
$listData[$model->$groupField][$model->$valueField]=$model->$textField;
|
|
}
|
|
return $listData;
|
|
}
|
|
public static function getIdByName($name)
|
|
{
|
|
return str_replace(array('[]', '][', '[', ']'), array('', '_', '_', ''), $name);
|
|
}
|
|
protected static function activeInputField($type,$model,$attribute,$htmlOptions)
|
|
{
|
|
$htmlOptions['type']=$type;
|
|
if(!isset($htmlOptions['value']))
|
|
$htmlOptions['value']=$model->$attribute;
|
|
if($model->hasErrors($attribute))
|
|
self::addErrorCss($htmlOptions);
|
|
return self::tag('input',$htmlOptions);
|
|
}
|
|
protected static function listOptions($selection,$listData,&$htmlOptions)
|
|
{
|
|
$content='';
|
|
if(isset($htmlOptions['prompt']))
|
|
{
|
|
$content.='<option value="">'.self::encode($htmlOptions['prompt'])."</option>\n";
|
|
unset($htmlOptions['prompt']);
|
|
}
|
|
if(isset($htmlOptions['empty']))
|
|
{
|
|
$content.='<option value="">'.self::encode($htmlOptions['empty'])."</option>\n";
|
|
unset($htmlOptions['empty']);
|
|
}
|
|
foreach($listData as $key=>$value)
|
|
{
|
|
if(is_array($value))
|
|
{
|
|
$content.='<optgroup label="'.self::encode($key)."\">\n";
|
|
$dummy=array();
|
|
$content.=self::listOptions($value,$selection,$dummy);
|
|
$content.='</optgroup>'."\n";
|
|
}
|
|
else if(!is_array($selection) && !strcmp($key,$selection) || is_array($selection) && in_array($key,$selection))
|
|
$content.='<option value="'.self::encode((string)$key).'" selected="selected">'.self::encode((string)$value)."</option>\n";
|
|
else
|
|
$content.='<option value="'.self::encode((string)$key).'">'.self::encode((string)$value)."</option>\n";
|
|
}
|
|
return $content;
|
|
}
|
|
protected static function clientChange($event,&$htmlOptions)
|
|
{
|
|
if(isset($htmlOptions['submit']) || isset($htmlOptions['confirm']) || isset($htmlOptions['ajax']))
|
|
{
|
|
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['params']))
|
|
{
|
|
$params=CJavaScript::encode($htmlOptions['params']);
|
|
unset($htmlOptions['params']);
|
|
}
|
|
else
|
|
$params='{}';
|
|
if(isset($htmlOptions['submit']))
|
|
{
|
|
$cs->registerCoreScript('yii');
|
|
if($htmlOptions['submit']!=='')
|
|
$url=CJavaScript::quote(self::normalizeUrl($htmlOptions['submit']));
|
|
else
|
|
$url='';
|
|
$handler.="jQuery.yii.submitForm(this,'$url',$params);return false;";
|
|
unset($htmlOptions['submit']);
|
|
}
|
|
if(isset($htmlOptions['ajax']))
|
|
{
|
|
$handler.=self::ajax($htmlOptions['ajax']).'return false;';
|
|
unset($htmlOptions['ajax']);
|
|
}
|
|
if(isset($htmlOptions['confirm']))
|
|
{
|
|
$confirm='confirm(\''.CJavaScript::quote($htmlOptions['confirm']).'\')';
|
|
if($handler!=='')
|
|
$handler="if($confirm) {".$handler."} else return false;";
|
|
else
|
|
$handler="return $confirm;";
|
|
unset($htmlOptions['confirm']);
|
|
}
|
|
$cs->registerScript('Yii.CHtml.#'.$id,"jQuery('#$id').$event(function(){{$handler}});");
|
|
}
|
|
}
|
|
protected static function resolveNameID($model,&$attribute,&$htmlOptions)
|
|
{
|
|
if(!isset($htmlOptions['name']))
|
|
{
|
|
if(($pos=strpos($attribute,'['))!==false)
|
|
$htmlOptions['name']=get_class($model).substr($attribute,$pos).'['.($attribute=substr($attribute,0,$pos)).']';
|
|
else
|
|
$htmlOptions['name']=get_class($model).'['.$attribute.']';
|
|
}
|
|
if(!isset($htmlOptions['id']))
|
|
$htmlOptions['id']=self::getIdByName($htmlOptions['name']);
|
|
}
|
|
protected static function addErrorCss(&$htmlOptions)
|
|
{
|
|
if(isset($htmlOptions['class']))
|
|
$htmlOptions['class'].=' '.self::$errorCss;
|
|
else
|
|
$htmlOptions['class']=self::$errorCss;
|
|
}
|
|
}
|
|
class CWidget extends CBaseController
|
|
{
|
|
private static $_viewPaths;
|
|
private static $_counter=0;
|
|
private $_id;
|
|
private $_owner;
|
|
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;
|
|
else if($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()
|
|
{
|
|
$className=get_class($this);
|
|
if(isset(self::$_viewPaths[$className]))
|
|
return self::$_viewPaths[$className];
|
|
else
|
|
{
|
|
$class=new ReflectionClass(get_class($this));
|
|
return self::$_viewPaths[$className]=dirname($class->getFileName()).DIRECTORY_SEPARATOR.'views';
|
|
}
|
|
}
|
|
public function getViewFile($viewName)
|
|
{
|
|
$viewFile=$this->getViewPath().DIRECTORY_SEPARATOR.$viewName.'.php';
|
|
return is_file($viewFile) ? Yii::app()->findLocalizedFile($viewFile) : 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;
|
|
private $_hasScripts=false;
|
|
private $_packages;
|
|
private $_dependencies;
|
|
private $_baseUrl;
|
|
private $_coreScripts=array();
|
|
private $_cssFiles=array();
|
|
private $_css=array();
|
|
private $_scriptFiles=array();
|
|
private $_scripts=array();
|
|
public function reset()
|
|
{
|
|
$this->_hasScripts=false;
|
|
$this->_coreScripts=array();
|
|
$this->_cssFiles=array();
|
|
$this->_css=array();
|
|
$this->_scriptFiles=array();
|
|
$this->_scripts=array();
|
|
Yii::app()->getController()->recordCachingAction('clientScript','reset',array());
|
|
}
|
|
public function render(&$output)
|
|
{
|
|
if(!$this->_hasScripts)
|
|
return;
|
|
$this->renderHead($output);
|
|
if($this->enableJavaScript)
|
|
{
|
|
$this->renderBodyBegin($output);
|
|
$this->renderBodyEnd($output);
|
|
}
|
|
}
|
|
protected function renderHead(&$output)
|
|
{
|
|
$html='';
|
|
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)
|
|
{
|
|
foreach($this->_coreScripts as $name)
|
|
{
|
|
if(is_string($name))
|
|
$html.=$this->renderCoreScript($name);
|
|
}
|
|
if(isset($this->_scriptFiles[self::POS_HEAD]))
|
|
{
|
|
foreach($this->_scriptFiles[self::POS_HEAD] as $scriptFile)
|
|
$html.=CHtml::scriptFile($scriptFile)."\n";
|
|
}
|
|
if(isset($this->_scripts[self::POS_HEAD]))
|
|
$html.=CHtml::script(implode("\n",$this->_scripts[self::POS_HEAD]))."\n";
|
|
}
|
|
if($html!=='')
|
|
{
|
|
$output=preg_replace('/(<title\b[^>]*>|<\\/head\s*>)/is',$html.'$1',$output,1,$count);
|
|
if(!$count)
|
|
$output=$html.$output;
|
|
}
|
|
}
|
|
protected function renderBodyBegin(&$output)
|
|
{
|
|
$html='';
|
|
if(isset($this->_scriptFiles[self::POS_BEGIN]))
|
|
{
|
|
foreach($this->_scriptFiles[self::POS_BEGIN] as $scriptFile)
|
|
$html.=CHtml::scriptFile($scriptFile)."\n";
|
|
}
|
|
if(isset($this->_scripts[self::POS_BEGIN]))
|
|
$html.=CHtml::script(implode("\n",$this->_scripts[self::POS_BEGIN]))."\n";
|
|
if($html!=='')
|
|
{
|
|
$output=preg_replace('/(<body\b[^>]*>)/is','$1'.$html,$output,1,$count);
|
|
if(!$count)
|
|
$output=$html.$output;
|
|
}
|
|
}
|
|
protected function renderBodyEnd(&$output)
|
|
{
|
|
$html='';
|
|
if(isset($this->_scriptFiles[self::POS_END]))
|
|
{
|
|
foreach($this->_scriptFiles[self::POS_END] as $scriptFile)
|
|
$html.=CHtml::scriptFile($scriptFile)."\n";
|
|
}
|
|
$scripts=isset($this->_scripts[self::POS_END]) ? $this->_scripts[self::POS_END] : array();
|
|
if(isset($this->_scripts[self::POS_READY]))
|
|
$scripts[]="jQuery(document).ready(function() {\n".implode("\n",$this->_scripts[self::POS_READY])."\n});";
|
|
if(isset($this->_scripts[self::POS_LOAD]))
|
|
$scripts[]="window.onload=function() {\n".implode("\n",$this->_scripts[self::POS_LOAD])."\n};";
|
|
if(!empty($scripts))
|
|
$html.=CHtml::script(implode("\n",$scripts))."\n";
|
|
if($html!=='')
|
|
{
|
|
$output=preg_replace('/(<\\/body\s*>)/is',$html.'$1',$output,1,$count);
|
|
if(!$count)
|
|
$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 renderCoreScript($name)
|
|
{
|
|
if(isset($this->_coreScripts[$name]) && $this->_coreScripts[$name]===true || !$this->enableJavaScript)
|
|
return '';
|
|
$this->_coreScripts[$name]=true;
|
|
if($this->_packages===null)
|
|
{
|
|
$config=require(YII_PATH.'/web/js/packages.php');
|
|
$this->_packages=$config[0];
|
|
$this->_dependencies=$config[1];
|
|
}
|
|
$baseUrl=$this->getCoreScriptUrl();
|
|
$html='';
|
|
if(isset($this->_dependencies[$name]))
|
|
{
|
|
foreach($this->_dependencies[$name] as $depName)
|
|
$html.=$this->renderCoreScript($depName);
|
|
}
|
|
if(isset($this->_packages[$name]))
|
|
{
|
|
foreach($this->_packages[$name] as $path)
|
|
{
|
|
if(substr($path,-4)==='.css')
|
|
$html.=CHtml::cssFile($baseUrl.'/'.$path)."\n";
|
|
else
|
|
$html.=CHtml::scriptFile($baseUrl.'/'.$path)."\n";
|
|
}
|
|
}
|
|
return $html;
|
|
}
|
|
public function registerCoreScript($name)
|
|
{
|
|
$this->_hasScripts=true;
|
|
$this->_coreScripts[$name]=$name;
|
|
$params=func_get_args();
|
|
Yii::app()->getController()->recordCachingAction('clientScript','registerCoreScript',$params);
|
|
}
|
|
public function registerCssFile($url,$media='')
|
|
{
|
|
$this->_hasScripts=true;
|
|
$this->_cssFiles[$url]=$media;
|
|
$params=func_get_args();
|
|
Yii::app()->getController()->recordCachingAction('clientScript','registerCssFile',$params);
|
|
}
|
|
public function registerCss($id,$css,$media='')
|
|
{
|
|
$this->_hasScripts=true;
|
|
$this->_css[$id]=array($css,$media);
|
|
$params=func_get_args();
|
|
Yii::app()->getController()->recordCachingAction('clientScript','registerCss',$params);
|
|
}
|
|
public function registerScriptFile($url,$position=self::POS_HEAD)
|
|
{
|
|
$this->_hasScripts=true;
|
|
$this->_scriptFiles[$position][$url]=$url;
|
|
$params=func_get_args();
|
|
Yii::app()->getController()->recordCachingAction('clientScript','registerScriptFile',$params);
|
|
}
|
|
public function registerScript($id,$script,$position=self::POS_READY)
|
|
{
|
|
$this->_hasScripts=true;
|
|
$this->_scripts[$position][$id]=$script;
|
|
if($position===self::POS_READY)
|
|
$this->registerCoreScript('jquery');
|
|
$params=func_get_args();
|
|
Yii::app()->getController()->recordCachingAction('clientScript','registerScript',$params);
|
|
}
|
|
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->_bodyScriptFiles[$position][$url]);
|
|
}
|
|
public function isScriptRegistered($id,$position=self::POS_READY)
|
|
{
|
|
return isset($this->_scripts[$position][$id]);
|
|
}
|
|
}
|
|
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];
|
|
else if($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;
|
|
else if($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
|
|
throw new CException(Yii::t('yii','Unable to find the list item.'));
|
|
}
|
|
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);
|
|
}
|
|
else if($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);
|
|
}
|
|
else if($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 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;
|
|
}
|
|
}
|
|
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)
|
|
$chain->add(CInlineFilter::create($controller,trim(substr($filter,0,$pos))));
|
|
}
|
|
else
|
|
$chain->add(CInlineFilter::create($controller,$filter));
|
|
}
|
|
else if(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;
|
|
$chain->add(CConfiguration::createObject($filter));
|
|
}
|
|
else
|
|
$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);
|
|
}
|
|
}
|
|
protected function preFilter($filterChain)
|
|
{
|
|
return true;
|
|
}
|
|
protected function postFilter($filterChain)
|
|
{
|
|
}
|
|
}
|
|
class CInlineFilter extends CFilter
|
|
{
|
|
public $name;
|
|
public static function create($controller,$filterName)
|
|
{
|
|
$filter=new CInlineFilter;
|
|
$filter->name=$filterName;
|
|
return $filter;
|
|
}
|
|
public function filter($filterChain)
|
|
{
|
|
$method='filter'.$this->name;
|
|
if(method_exists($filterChain->controller,$method))
|
|
$filterChain->controller->$method($filterChain);
|
|
else
|
|
throw new CException(Yii::t('yii','Filter "{filter}" is invalid. Controller "{class}" does have the filter method "filter{filter}".',
|
|
array('{filter}'=>$this->name, '{class}'=>get_class($filterChain->controller))));
|
|
}
|
|
}
|
|
class CAccessControlFilter extends CFilter
|
|
{
|
|
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)
|
|
$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();
|
|
$action=$filterChain->action;
|
|
foreach($this->_rules as $rule)
|
|
{
|
|
if(($allow=$rule->isUserAllowed($user,$action,$ip,$verb))>0) // allowed
|
|
break;
|
|
else if($allow<0) // denied
|
|
{
|
|
if($user->getIsGuest())
|
|
{
|
|
$user->loginRequired();
|
|
return false;
|
|
}
|
|
else
|
|
throw new CHttpException(401,Yii::t('yii','You are not authorized to perform this action.'));
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
class CAccessRule extends CComponent
|
|
{
|
|
public $allow;
|
|
public $actions;
|
|
public $users;
|
|
public $roles;
|
|
public $ips;
|
|
public $verbs;
|
|
public function isUserAllowed($user,$action,$ip,$verb)
|
|
{
|
|
if($this->isActionMatched($action)
|
|
&& $this->isUserMatched($user)
|
|
&& $this->isRoleMatched($user)
|
|
&& $this->isIpMatched($ip)
|
|
&& $this->isVerbMatched($verb))
|
|
return $this->allow ? 1 : -1;
|
|
else
|
|
return 0;
|
|
}
|
|
private function isActionMatched($action)
|
|
{
|
|
return empty($this->actions) || in_array(strtolower($action->getId()),$this->actions);
|
|
}
|
|
private function isUserMatched($user)
|
|
{
|
|
if(empty($this->users))
|
|
return true;
|
|
foreach($this->users as $u)
|
|
{
|
|
if($u==='*')
|
|
return true;
|
|
else if($u==='?' && $user->getIsGuest())
|
|
return true;
|
|
else if($u==='@' && !$user->getIsGuest())
|
|
return true;
|
|
else if(!strcasecmp($u,$user->getName()))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
private function isRoleMatched($user)
|
|
{
|
|
if(empty($this->roles))
|
|
return true;
|
|
foreach($this->roles as $role)
|
|
{
|
|
if($user->checkAccess($role))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
private 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;
|
|
}
|
|
private function isVerbMatched($verb)
|
|
{
|
|
return empty($this->verbs) || in_array(strtolower($verb),$this->verbs);
|
|
}
|
|
}
|
|
abstract class CModel extends CComponent
|
|
{
|
|
private $_errors=array(); // attribute name => array of errors
|
|
public function validate($attributes=null)
|
|
{
|
|
$this->clearErrors();
|
|
if($this->beforeValidate())
|
|
{
|
|
foreach($this->createValidators() as $validator)
|
|
$validator->validate($this,$attributes);
|
|
$this->afterValidate();
|
|
return !$this->hasErrors();
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
protected function beforeValidate()
|
|
{
|
|
return true;
|
|
}
|
|
protected function afterValidate()
|
|
{
|
|
}
|
|
public function createValidators()
|
|
{
|
|
$validators=array();
|
|
foreach($this->rules() as $rule)
|
|
{
|
|
if(isset($rule[0],$rule[1])) // attributes, validator name
|
|
$validators[]=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 attributeLabels()
|
|
{
|
|
return array();
|
|
}
|
|
public function rules()
|
|
{
|
|
return array();
|
|
}
|
|
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 addError($attribute,$error)
|
|
{
|
|
$this->_errors[$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)))));
|
|
}
|
|
}
|
|
abstract class CActiveRecord extends CModel
|
|
{
|
|
const BELONGS_TO='CBelongsToRelation';
|
|
const HAS_ONE='CHasOneRelation';
|
|
const HAS_MANY='CHasManyRelation';
|
|
const MANY_MANY='CManyManyRelation';
|
|
public static $db;
|
|
public $isNewRecord=false;
|
|
private static $_models=array(); // class name => model
|
|
private $_md;
|
|
private $_attributes=array(); // attribute name => attribute value
|
|
private $_related=array(); // attribute name => related objects
|
|
public function __construct($attributes=array())
|
|
{
|
|
if($attributes===null) // internally used by populateRecord() and model()
|
|
return;
|
|
$this->isNewRecord=true;
|
|
$this->_attributes=$this->getMetaData()->attributeDefaults;
|
|
if($attributes!==array())
|
|
$this->setAttributes($attributes);
|
|
$this->afterConstruct();
|
|
}
|
|
public function __sleep()
|
|
{
|
|
$this->_md=null;
|
|
return array_keys((array)$this);
|
|
}
|
|
public function __get($name)
|
|
{
|
|
if(isset($this->_attributes[$name]))
|
|
return $this->_attributes[$name];
|
|
else if(isset($this->getMetaData()->columns[$name]))
|
|
return null;
|
|
else if(isset($this->_related[$name]))
|
|
return $this->_related[$name];
|
|
else if(isset($this->getMetaData()->relations[$name]))
|
|
{
|
|
if($this->isNewRecord)
|
|
return null;
|
|
else if(!array_key_exists($name,$this->_related))
|
|
{
|
|
$relation=$this->getMetaData()->relations[$name];
|
|
$finder=new CActiveFinder($this,array($name=>$relation->with));
|
|
$finder->lazyFind($this);
|
|
}
|
|
return $this->_related[$name];
|
|
}
|
|
else
|
|
return parent::__get($name);
|
|
}
|
|
public function __set($name,$value)
|
|
{
|
|
if(isset($this->getMetaData()->columns[$name]))
|
|
$this->_attributes[$name]=$value;
|
|
else if(isset($this->getMetaData()->relations[$name]))
|
|
$this->_related[$name]=$value;
|
|
else
|
|
parent::__set($name,$value);
|
|
}
|
|
public static function model($className=__CLASS__)
|
|
{
|
|
if(isset(self::$_models[$className]))
|
|
return self::$_models[$className];
|
|
else
|
|
{
|
|
$model=self::$_models[$className]=new $className(null);
|
|
$model->isNewRecord=false;
|
|
$model->_md=new CActiveRecordMetaData($model);
|
|
return $model;
|
|
}
|
|
}
|
|
public function getMetaData()
|
|
{
|
|
if($this->_md!==null)
|
|
return $this->_md;
|
|
else
|
|
return $this->_md=self::model(get_class($this))->_md;
|
|
}
|
|
public function tableName()
|
|
{
|
|
return get_class($this);
|
|
}
|
|
public function protectedAttributes()
|
|
{
|
|
return array();
|
|
}
|
|
public function safeAttributes()
|
|
{
|
|
$table=$this->getDbConnection()->getSchema()->getTable($this->tableName());
|
|
$protectedAttributes=array_flip($this->protectedAttributes());
|
|
$safeAttributes=array();
|
|
foreach($table->columns as $name=>$column)
|
|
{
|
|
if(!$column->isPrimaryKey && !isset($protectedAttributes[$name]))
|
|
$safeAttributes[]=$name;
|
|
}
|
|
return $safeAttributes;
|
|
}
|
|
public function relations()
|
|
{
|
|
return array();
|
|
}
|
|
public function getDbConnection()
|
|
{
|
|
if(self::$db!==null)
|
|
return self::$db;
|
|
else
|
|
{
|
|
self::$db=Yii::app()->getDb();
|
|
if(self::$db instanceof CDbConnection)
|
|
{
|
|
self::$db->setActive(true);
|
|
return self::$db;
|
|
}
|
|
else
|
|
throw new CDbException(Yii::t('yii','Active Record requires a "db" CDbConnection application component.'));
|
|
}
|
|
}
|
|
public function getAttributeLabel($attribute)
|
|
{
|
|
if(($label=$this->getMetaData()->getAttributeLabel($attribute))!==null)
|
|
return $label;
|
|
else
|
|
return $this->generateAttributeLabel($attribute);
|
|
}
|
|
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;
|
|
else if(isset($this->_attributes[$name]))
|
|
return $this->_attributes[$name];
|
|
else if(isset($this->getMetaData()->columns[$name]))
|
|
return null;
|
|
else
|
|
throw new CDbException(Yii::t('yii','{class} does not have attribute "{name}".',
|
|
array('{class}'=>get_class($this), '{name}'=>$name)));
|
|
}
|
|
public function setAttribute($name,$value)
|
|
{
|
|
if(property_exists($name))
|
|
$this->$name=$value;
|
|
else if(isset($this->getMetaData()->columns[$name]))
|
|
$this->_attributes[$name]=$value;
|
|
else
|
|
throw new CDbException(Yii::t('yii','{class} does not have attribute "{name}".',
|
|
array('{class}'=>get_class($this), '{name}'=>$name)));
|
|
}
|
|
public function addRelatedRecord($name,$record,$multiple)
|
|
{
|
|
if($multiple)
|
|
{
|
|
if(!isset($this->_related[$name]))
|
|
$this->_related[$name]=array();
|
|
if($record instanceof CActiveRecord)
|
|
$this->_related[$name][]=$record;
|
|
}
|
|
else if(!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;
|
|
else if($names===true && !isset($attributes[$name]))
|
|
$attributes[$name]=null;
|
|
}
|
|
if(is_array($names))
|
|
{
|
|
$attrs=array();
|
|
foreach($names as $name)
|
|
$attrs[$name]=isset($attributes[$name])?$attributes[$name]:null;
|
|
return $attrs;
|
|
}
|
|
else
|
|
return $attributes;
|
|
}
|
|
public function setAttributes($values,$safeAttributes=null,$safeAttributesOnly=true)
|
|
{
|
|
if(is_array($values))
|
|
{
|
|
if($safeAttributesOnly)
|
|
{
|
|
if(empty($safeAttributes))
|
|
$safeAttributes=$this->getMetaData()->safeAttributes;
|
|
else
|
|
$safeAttributes=array_flip($safeAttributes);
|
|
foreach($values as $name=>$value)
|
|
{
|
|
if(isset($safeAttributes[$name]))
|
|
$this->$name=$value;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach($values as $name=>$value)
|
|
$this->$name=$value;
|
|
}
|
|
}
|
|
}
|
|
public function save($runValidation=true,$attributes=null)
|
|
{
|
|
if(!$runValidation || $this->validate($attributes))
|
|
{
|
|
if($this->isNewRecord)
|
|
return $this->insert($attributes);
|
|
else
|
|
return $this->update($attributes);
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
public function validate($attributes=null)
|
|
{
|
|
$this->clearErrors();
|
|
if($this->beforeValidate())
|
|
{
|
|
foreach($this->getMetaData()->getValidators() as $validator)
|
|
{
|
|
if($validator->on===null || ($validator->on==='insert')===$this->isNewRecord)
|
|
$validator->validate($this,$attributes);
|
|
}
|
|
$this->afterValidate();
|
|
return !$this->hasErrors();
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
protected function beforeSave()
|
|
{
|
|
return true;
|
|
}
|
|
protected function afterSave()
|
|
{
|
|
}
|
|
protected function beforeDelete()
|
|
{
|
|
return true;
|
|
}
|
|
protected function afterDelete()
|
|
{
|
|
}
|
|
protected function afterConstruct()
|
|
{
|
|
}
|
|
protected function afterFind()
|
|
{
|
|
}
|
|
public function insert($attributes=null)
|
|
{
|
|
if(!$this->isNewRecord)
|
|
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 && is_string($primaryKey) && $this->$primaryKey===null)
|
|
$this->$primaryKey=$builder->getLastInsertID($table);
|
|
$this->afterSave();
|
|
$this->isNewRecord=false;
|
|
return true;
|
|
}
|
|
else
|
|
$this->afterSave();
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
public function update($attributes=null)
|
|
{
|
|
if($this->isNewRecord)
|
|
throw new CDbException(Yii::t('yii','The active record cannot be updated because it is new.'));
|
|
if($this->beforeSave())
|
|
{
|
|
$result=$this->updateByPk($this->getPrimaryKey(),$this->getAttributes($attributes))>0;
|
|
$this->afterSave();
|
|
return $result;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
public function saveAttributes($attributes)
|
|
{
|
|
if(!$this->isNewRecord)
|
|
{
|
|
$values=array();
|
|
foreach($attributes as $name=>$value)
|
|
{
|
|
if(is_integer($name))
|
|
$values[$value]=$this->$value;
|
|
else
|
|
$values[$name]=$this->$name=$value;
|
|
}
|
|
return $this->updateByPk($this->getPrimaryKey(),$values)>0;
|
|
}
|
|
else
|
|
throw new CDbException(Yii::t('yii','The active record cannot be updated because it is new.'));
|
|
}
|
|
public function delete()
|
|
{
|
|
if(!$this->isNewRecord)
|
|
{
|
|
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(!$this->isNewRecord && ($record=$this->findByPk($this->getPrimaryKey()))!==null)
|
|
{
|
|
$this->_attributes=array();
|
|
$this->_related=array();
|
|
foreach($this->getMetaData()->columns as $name=>$column)
|
|
$this->$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};
|
|
else if(is_array($table->primaryKey))
|
|
{
|
|
$values=array();
|
|
foreach($table->primaryKey as $name)
|
|
$values[$name]=$this->$name;
|
|
return $values;
|
|
}
|
|
else
|
|
return null;
|
|
}
|
|
public function find($condition='',$params=array())
|
|
{
|
|
$builder=$this->getCommandBuilder();
|
|
$criteria=$builder->createCriteria($condition,$params);
|
|
$criteria->limit=1;
|
|
$command=$builder->createFindCommand($this->getTableSchema(),$criteria);
|
|
return $this->populateRecord($command->queryRow());
|
|
}
|
|
public function findAll($condition='',$params=array())
|
|
{
|
|
$builder=$this->getCommandBuilder();
|
|
$criteria=$builder->createCriteria($condition,$params);
|
|
$command=$builder->createFindCommand($this->getTableSchema(),$criteria);
|
|
return $this->populateRecords($command->queryAll());
|
|
}
|
|
public function findByPk($pk,$condition='',$params=array())
|
|
{
|
|
$builder=$this->getCommandBuilder();
|
|
$criteria=$builder->createPkCriteria($this->getTableSchema(),$pk,$condition,$params);
|
|
$criteria->limit=1;
|
|
$command=$builder->createFindCommand($this->getTableSchema(),$criteria);
|
|
return $this->populateRecord($command->queryRow());
|
|
}
|
|
public function findAllByPk($pk,$condition='',$params=array())
|
|
{
|
|
$builder=$this->getCommandBuilder();
|
|
$criteria=$builder->createPkCriteria($this->getTableSchema(),$pk,$condition,$params);
|
|
$command=$builder->createFindCommand($this->getTableSchema(),$criteria);
|
|
return $this->populateRecords($command->queryAll());
|
|
}
|
|
public function findByAttributes($attributes,$condition='',$params=array())
|
|
{
|
|
$builder=$this->getCommandBuilder();
|
|
$criteria=$builder->createColumnCriteria($this->getTableSchema(),$attributes,$condition,$params);
|
|
$criteria->limit=1;
|
|
$command=$builder->createFindCommand($this->getTableSchema(),$criteria);
|
|
return $this->populateRecord($command->queryRow());
|
|
}
|
|
public function findAllByAttributes($attributes,$condition='',$params=array())
|
|
{
|
|
$builder=$this->getCommandBuilder();
|
|
$criteria=$builder->createColumnCriteria($this->getTableSchema(),$attributes,$condition,$params);
|
|
$command=$builder->createFindCommand($this->getTableSchema(),$criteria);
|
|
return $this->populateRecords($command->queryAll());
|
|
}
|
|
public function findBySql($sql,$params=array())
|
|
{
|
|
$command=$this->getCommandBuilder()->createSqlCommand($sql,$params);
|
|
return $this->populateRecord($command->queryRow());
|
|
}
|
|
public function findAllBySql($sql,$params=array())
|
|
{
|
|
$command=$this->getCommandBuilder()->createSqlCommand($sql,$params);
|
|
return $this->populateRecords($command->queryAll());
|
|
}
|
|
public function count($condition='',$params=array())
|
|
{
|
|
$builder=$this->getCommandBuilder();
|
|
$criteria=$builder->createCriteria($condition,$params);
|
|
return $builder->createCountCommand($this->getTableSchema(),$criteria)->queryScalar();
|
|
}
|
|
public function countBySql($sql,$params=array())
|
|
{
|
|
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=reset($table->columns)->rawName;
|
|
$criteria->limit=1;
|
|
return $builder->createFindCommand($table,$criteria)->queryRow()!==false;
|
|
}
|
|
public function with()
|
|
{
|
|
if(func_num_args()>0)
|
|
{
|
|
$with=func_get_args();
|
|
return new CActiveFinder($this,$with);
|
|
}
|
|
else
|
|
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 populateRecord($attributes)
|
|
{
|
|
if($attributes!==false)
|
|
{
|
|
$class=get_class($this);
|
|
$record=new $class(null);
|
|
$record->isNewRecord=false;
|
|
$record->_md=$this->getMetaData();
|
|
foreach($attributes as $name=>$value)
|
|
{
|
|
if(property_exists($record,$name))
|
|
$record->$name=$value;
|
|
else if(isset($record->_md->columns[$name]))
|
|
$record->_attributes[$name]=$value;
|
|
}
|
|
$record->afterFind();
|
|
return $record;
|
|
}
|
|
else
|
|
return null;
|
|
}
|
|
public function populateRecords($data)
|
|
{
|
|
$records=array();
|
|
$class=get_class($this);
|
|
$md=$this->getMetaData();
|
|
$table=$md->tableSchema;
|
|
foreach($data as $attributes)
|
|
{
|
|
$record=new $class(null);
|
|
$record->isNewRecord=false;
|
|
$record->_md=$md;
|
|
foreach($attributes as $name=>$value)
|
|
{
|
|
if(property_exists($record,$name))
|
|
$record->$name=$value;
|
|
else if(isset($record->_md->columns[$name]))
|
|
$record->_attributes[$name]=$value;
|
|
}
|
|
$record->afterFind();
|
|
$records[]=$record;
|
|
}
|
|
return $records;
|
|
}
|
|
public function createValidators()
|
|
{
|
|
$validators=array();
|
|
foreach($this->rules() as $rule)
|
|
{
|
|
if(isset($rule[0],$rule[1])) // attributes, validator name
|
|
$validators[]=CValidator::createValidator($rule[1],$this,$rule[0],array_slice($rule,2));
|
|
else
|
|
throw new CDbException(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;
|
|
}
|
|
}
|
|
class CActiveRelation extends CComponent
|
|
{
|
|
public $name;
|
|
public $className;
|
|
public $foreignKey;
|
|
public $joinType='LEFT OUTER JOIN';
|
|
public $select='*';
|
|
public $condition='';
|
|
public $order='';
|
|
public $aliasToken='??';
|
|
public $with=array();
|
|
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;
|
|
}
|
|
}
|
|
class CBelongsToRelation extends CActiveRelation
|
|
{
|
|
}
|
|
class CHasOneRelation extends CActiveRelation
|
|
{
|
|
}
|
|
class CHasManyRelation extends CActiveRelation
|
|
{
|
|
public $group='';
|
|
public $limit=-1;
|
|
public $offset=-1;
|
|
}
|
|
class CManyManyRelation extends CHasManyRelation
|
|
{
|
|
}
|
|
class CActiveRecordMetaData
|
|
{
|
|
public $tableSchema;
|
|
public $columns;
|
|
public $relations=array();
|
|
public $attributeDefaults=array();
|
|
public $safeAttributes=array();
|
|
private $_model;
|
|
private $_attributeLabels;
|
|
private $_validators;
|
|
public function __construct($model)
|
|
{
|
|
$this->_model=$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}'=>get_class($model),'{table}'=>$tableName)));
|
|
$this->tableSchema=$table;
|
|
$this->columns=$table->columns;
|
|
$this->safeAttributes=array_flip($model->safeAttributes($table));
|
|
foreach($table->columns as $name=>$column)
|
|
{
|
|
if(!$column->isPrimaryKey && $column->defaultValue!==null)
|
|
$this->attributeDefaults[$name]=$column->defaultValue;
|
|
}
|
|
foreach($model->relations() as $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}'=>get_class($model),'{relation}'=>$name)));
|
|
}
|
|
}
|
|
public function getAttributeLabel($attribute)
|
|
{
|
|
if($this->_attributeLabels===null)
|
|
$this->_attributeLabels=$this->_model->attributeLabels();
|
|
return isset($this->_attributeLabels[$attribute]) ? $this->_attributeLabels[$attribute] : null;
|
|
}
|
|
public function getValidators()
|
|
{
|
|
if(!$this->_validators)
|
|
$this->_validators=$this->_model->createValidators();
|
|
return $this->_validators;
|
|
}
|
|
}
|
|
class CDbConnection extends CApplicationComponent
|
|
{
|
|
public $connectionString;
|
|
public $username='';
|
|
public $password='';
|
|
public $schemaCachingDuration=0;
|
|
public $schemaCachingExclude=array();
|
|
public $autoConnect=true;
|
|
public $charset;
|
|
public $emulatePrepare=false;
|
|
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();
|
|
}
|
|
}
|
|
protected function open()
|
|
{
|
|
if($this->_pdo===null)
|
|
{
|
|
if(empty($this->connectionString))
|
|
throw new CDbException(Yii::t('yii','CDbConnection.connectionString cannot be empty.'));
|
|
try
|
|
{
|
|
$this->_pdo=new PDO($this->connectionString,$this->username,
|
|
$this->password,$this->_attributes);
|
|
$this->initConnection($this->_pdo);
|
|
$this->_active=true;
|
|
}
|
|
catch(PDOException $e)
|
|
{
|
|
throw new CDbException(Yii::t('yii','CDbConnection failed to open the DB connection: {error}',
|
|
array('{error}'=>$e->getMessage())));
|
|
}
|
|
}
|
|
}
|
|
protected function close()
|
|
{
|
|
$this->_pdo=null;
|
|
$this->_active=false;
|
|
$this->_schema=null;
|
|
}
|
|
protected function initConnection($pdo)
|
|
{
|
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
if($this->emulatePrepare && constant('PDO::ATTR_EMULATE_PREPARES'))
|
|
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,true);
|
|
if($this->charset===null)
|
|
return;
|
|
switch(strtolower($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)))
|
|
{
|
|
case 'pgsql':
|
|
$stmt=$pdo->prepare('SET client_encoding TO ?');
|
|
$stmt->execute(array($this->charset));
|
|
break;
|
|
case 'mysqli':
|
|
case 'mysql':
|
|
$stmt=$pdo->prepare('SET CHARACTER SET ?');
|
|
$stmt->execute(array($this->charset));
|
|
break;
|
|
}
|
|
}
|
|
public function getPdoInstance()
|
|
{
|
|
return $this->_pdo;
|
|
}
|
|
public function createCommand($sql)
|
|
{
|
|
if($this->getActive())
|
|
return new CDbCommand($this,$sql);
|
|
else
|
|
throw new CDbException(Yii::t('yii','CDbConnection is inactive and cannot perform any DB operations.'));
|
|
}
|
|
public function getCurrentTransaction()
|
|
{
|
|
if($this->_transaction!==null)
|
|
{
|
|
if($this->_transaction->getActive())
|
|
return $this->_transaction;
|
|
}
|
|
return null;
|
|
}
|
|
public function beginTransaction()
|
|
{
|
|
if($this->getActive())
|
|
{
|
|
$this->_pdo->beginTransaction();
|
|
return $this->_transaction=new CDbTransaction($this);
|
|
}
|
|
else
|
|
throw new CDbException(Yii::t('yii','CDbConnection is inactive and cannot perform any DB operations.'));
|
|
}
|
|
public function getSchema()
|
|
{
|
|
if($this->_schema!==null)
|
|
return $this->_schema;
|
|
else
|
|
{
|
|
if(!$this->getActive())
|
|
throw new CDbException(Yii::t('yii','CDbConnection is inactive and cannot perform any DB operations.'));
|
|
$driver=$this->getDriverName();
|
|
switch(strtolower($driver))
|
|
{
|
|
case 'pgsql':
|
|
return $this->_schema=new CPgsqlSchema($this);
|
|
case 'mysqli':
|
|
case 'mysql':
|
|
return $this->_schema=new CMysqlSchema($this);
|
|
case 'sqlite': // sqlite 3
|
|
case 'sqlite2': // sqlite 2
|
|
return $this->_schema=new CSqliteSchema($this);
|
|
case 'mssql': // Mssql driver on windows hosts
|
|
case 'dblib': // dblib drivers on linux (and maybe others os) hosts
|
|
case 'oci':
|
|
case 'ibm':
|
|
default:
|
|
throw new CDbException(Yii::t('yii','CDbConnection does not support reading schema for {driver} database.',
|
|
array('{driver}'=>$driver)));
|
|
}
|
|
}
|
|
}
|
|
public function getLastInsertID($sequenceName='')
|
|
{
|
|
if($this->getActive())
|
|
return $this->_pdo->lastInsertId($sequenceName);
|
|
else
|
|
throw new CDbException(Yii::t('yii','CDbConnection is inactive and cannot perform any DB operations.'));
|
|
}
|
|
public function quoteValue($str)
|
|
{
|
|
if($this->getActive())
|
|
return $this->_pdo->quote($str);
|
|
else
|
|
throw new CDbException(Yii::t('yii','CDbConnection is inactive and cannot perform any DB operations.'));
|
|
}
|
|
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,
|
|
'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()
|
|
{
|
|
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)
|
|
{
|
|
if($this->getActive())
|
|
return $this->_pdo->getAttribute($name);
|
|
else
|
|
throw new CDbException(Yii::t('yii','CDbConnection is inactive and cannot perform any DB operations.'));
|
|
}
|
|
public function setAttribute($name,$value)
|
|
{
|
|
if($this->_pdo instanceof PDO)
|
|
$this->_pdo->setAttribute($name,$value);
|
|
else
|
|
$this->_attributes[$name]=$value;
|
|
}
|
|
}
|
|
abstract class CDbSchema extends CComponent
|
|
{
|
|
private $_tables=array();
|
|
private $_connection;
|
|
private $_builder;
|
|
private $_cacheExclude=array();
|
|
abstract protected function createTable($name);
|
|
public function __construct($conn)
|
|
{
|
|
$conn->setActive(true);
|
|
$this->_connection=$conn;
|
|
foreach($conn->schemaCachingExclude as $name)
|
|
$this->_cacheExclude[$name]=true;
|
|
}
|
|
public function getDbConnection()
|
|
{
|
|
return $this->_connection;
|
|
}
|
|
public function getTable($name)
|
|
{
|
|
if(isset($this->_tables[$name]))
|
|
return $this->_tables[$name];
|
|
else if(!isset($this->_cacheExclude[$name]) && ($duration=$this->_connection->schemaCachingDuration)>0 && ($cache=Yii::app()->getCache())!==null)
|
|
{
|
|
$key='yii:dbschema'.$this->_connection->connectionString.':'.$this->_connection->username.':'.$name;
|
|
if(($table=$cache->get($key))===false)
|
|
{
|
|
$table=$this->createTable($name);
|
|
$cache->set($key,$table,$duration);
|
|
}
|
|
return $this->_tables[$name]=$table;
|
|
}
|
|
else
|
|
return $this->_tables[$name]=$this->createTable($name);
|
|
}
|
|
public function getCommandBuilder()
|
|
{
|
|
if($this->_builder!==null)
|
|
return $this->_builder;
|
|
else
|
|
return $this->_builder=$this->createCommandBuilder();
|
|
}
|
|
protected function createCommandBuilder()
|
|
{
|
|
return new CDbCommandBuilder($this);
|
|
}
|
|
public function refresh()
|
|
{
|
|
$this->_tables=array();
|
|
$this->_builder=null;
|
|
}
|
|
public function quoteTableName($name)
|
|
{
|
|
return "'".$name."'";
|
|
}
|
|
public function quoteColumnName($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);
|
|
return $name1===$name2;
|
|
}
|
|
}
|
|
class CSqliteSchema extends CDbSchema
|
|
{
|
|
protected function createCommandBuilder()
|
|
{
|
|
return new CSqliteCommandBuilder($this);
|
|
}
|
|
protected function createTable($name)
|
|
{
|
|
$db=$this->getDbConnection();
|
|
$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;
|
|
else if(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='';
|
|
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->init(strtolower($column['type']),$column['dflt_value']);
|
|
return $c;
|
|
}
|
|
}
|
|
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
|
|
{
|
|
private $_connection;
|
|
private $_text='';
|
|
private $_statement=null;
|
|
public function __construct(CDbConnection $connection,$text)
|
|
{
|
|
$this->_connection=$connection;
|
|
$this->setText($text);
|
|
}
|
|
public function __sleep()
|
|
{
|
|
$this->_statement=null;
|
|
return array_keys(get_object_vars($this));
|
|
}
|
|
public function getText()
|
|
{
|
|
return $this->_text;
|
|
}
|
|
public function setText($value)
|
|
{
|
|
$this->_text=$value;
|
|
$this->cancel();
|
|
}
|
|
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());
|
|
}
|
|
catch(Exception $e)
|
|
{
|
|
throw new CDbException(Yii::t('yii','CDbCommand failed to prepare the SQL statement: {error}',
|
|
array('{error}'=>$e->getMessage())));
|
|
}
|
|
}
|
|
}
|
|
public function cancel()
|
|
{
|
|
$this->_statement=null;
|
|
}
|
|
public function bindParam($name, &$value, $dataType=null, $length=null)
|
|
{
|
|
$this->prepare();
|
|
if($dataType===null)
|
|
$this->_statement->bindParam($name,$value,$this->_connection->getPdoType(gettype($value)));
|
|
else if($length===null)
|
|
$this->_statement->bindParam($name,$value,$dataType);
|
|
else
|
|
$this->_statement->bindParam($name,$value,$dataType,$length);
|
|
}
|
|
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);
|
|
}
|
|
public function execute()
|
|
{
|
|
try
|
|
{
|
|
if($this->_statement instanceof PDOStatement)
|
|
{
|
|
$this->_statement->execute();
|
|
return $this->_statement->rowCount();
|
|
}
|
|
else
|
|
return $this->getConnection()->getPdoInstance()->exec($this->getText());
|
|
}
|
|
catch(Exception $e)
|
|
{
|
|
throw new CDbException(Yii::t('yii','CDbCommand failed to execute the SQL statement: {error}',
|
|
array('{error}'=>$e->getMessage())));
|
|
}
|
|
}
|
|
public function query()
|
|
{
|
|
return $this->queryInternal('',0);
|
|
}
|
|
public function queryAll($fetchAssociative=true)
|
|
{
|
|
return $this->queryInternal('fetchAll',$fetchAssociative ? PDO::FETCH_ASSOC : PDO::FETCH_NUM);
|
|
}
|
|
public function queryRow($fetchAssociative=true)
|
|
{
|
|
return $this->queryInternal('fetch',$fetchAssociative ? PDO::FETCH_ASSOC : PDO::FETCH_NUM);
|
|
}
|
|
public function queryScalar()
|
|
{
|
|
$result=$this->queryInternal('fetchColumn',0);
|
|
if(is_resource($result) && get_resource_type($result)==='stream')
|
|
return stream_get_contents($result);
|
|
else
|
|
return $result;
|
|
}
|
|
public function queryColumn()
|
|
{
|
|
return $this->queryInternal('fetchAll',PDO::FETCH_COLUMN);
|
|
}
|
|
private function queryInternal($method,$mode)
|
|
{
|
|
try
|
|
{
|
|
if($this->_statement instanceof PDOStatement)
|
|
$this->_statement->execute();
|
|
else
|
|
$this->_statement=$this->getConnection()->getPdoInstance()->query($this->getText());
|
|
if($method==='')
|
|
return new CDbDataReader($this);
|
|
$result=$this->_statement->{$method}($mode);
|
|
$this->_statement->closeCursor();
|
|
return $result;
|
|
}
|
|
catch(Exception $e)
|
|
{
|
|
throw new CDbException(Yii::t('yii','CDbCommand failed to execute the SQL statement: {error}',
|
|
array('{error}'=>$e->getMessage())));
|
|
}
|
|
}
|
|
}
|
|
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 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)
|
|
$this->type='integer';
|
|
else if(stripos($dbType,'bool')!==false)
|
|
$this->type='boolean';
|
|
else if(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)
|
|
return $value;
|
|
if($value==='')
|
|
return $this->type==='string' ? '' : null;
|
|
switch($this->type)
|
|
{
|
|
case 'integer': return (integer)$value;
|
|
case 'boolean': return (boolean)$value;
|
|
case 'double': return (double)$value;
|
|
case 'string': return (string)$value;
|
|
default: return $value;
|
|
}
|
|
}
|
|
}
|
|
class CSqliteColumnSchema extends CDbColumnSchema
|
|
{
|
|
protected function extractDefault($defaultValue)
|
|
{
|
|
if($this->type==='string') // PHP 5.2.6 adds single quotes while 5.2.0 doesn't
|
|
$this->defaultValue=trim($defaultValue,"'\"");
|
|
else
|
|
$this->defaultValue=$this->typecast($defaultValue);
|
|
}
|
|
}
|
|
class CDbCommandBuilder extends CComponent
|
|
{
|
|
private $_schema;
|
|
private $_connection;
|
|
public function __construct($schema)
|
|
{
|
|
$this->_schema=$schema;
|
|
$this->_connection=$schema->getDbConnection();
|
|
}
|
|
public function getDbConnection()
|
|
{
|
|
return $this->_connection;
|
|
}
|
|
public function getSchema()
|
|
{
|
|
return $this->_schema;
|
|
}
|
|
public function getLastInsertID($table)
|
|
{
|
|
if($table->sequenceName!==null)
|
|
return $this->_connection->getLastInsertID($table->sequenceName);
|
|
else
|
|
return null;
|
|
}
|
|
public function createFindCommand($table,$criteria)
|
|
{
|
|
$select=is_array($criteria->select) ? implode(', ',$criteria->select) : $criteria->select;
|
|
$sql="SELECT {$select} FROM {$table->rawName}";
|
|
$sql=$this->applyJoin($sql,$criteria->join);
|
|
$sql=$this->applyCondition($sql,$criteria->condition);
|
|
$sql=$this->applyGroup($sql,$criteria->group);
|
|
$sql=$this->applyOrder($sql,$criteria->order);
|
|
$sql=$this->applyLimit($sql,$criteria->limit,$criteria->offset);
|
|
$command=$this->_connection->createCommand($sql);
|
|
$this->bindValues($command,$criteria->params);
|
|
return $command;
|
|
}
|
|
public function createCountCommand($table,$criteria)
|
|
{
|
|
$criteria->select='COUNT(*)';
|
|
return $this->createFindCommand($table,$criteria);
|
|
}
|
|
public function createDeleteCommand($table,$criteria)
|
|
{
|
|
$sql="DELETE FROM {$table->rawName}";
|
|
$sql=$this->applyJoin($sql,$criteria->join);
|
|
$sql=$this->applyCondition($sql,$criteria->condition);
|
|
$sql=$this->applyGroup($sql,$criteria->group);
|
|
$sql=$this->applyOrder($sql,$criteria->order);
|
|
$sql=$this->applyLimit($sql,$criteria->limit,$criteria->offset);
|
|
$command=$this->_connection->createCommand($sql);
|
|
$this->bindValues($command,$criteria->params);
|
|
return $command;
|
|
}
|
|
public function createInsertCommand($table,$data)
|
|
{
|
|
$fields=array();
|
|
$values=array();
|
|
$placeholders=array();
|
|
foreach($data as $name=>$value)
|
|
{
|
|
if(($column=$table->getColumn($name))!==null && ($value!==null || $column->allowNull))
|
|
{
|
|
$fields[]=$column->rawName;
|
|
$placeholders[]=':'.$name;
|
|
$values[':'.$name]=$column->typecast($value);
|
|
}
|
|
}
|
|
$sql="INSERT INTO {$table->rawName} (".implode(', ',$fields).') VALUES ('.implode(', ',$placeholders).')';
|
|
$command=$this->_connection->createCommand($sql);
|
|
foreach($values as $name=>$value)
|
|
$command->bindValue($name,$value);
|
|
return $command;
|
|
}
|
|
public function createUpdateCommand($table,$data,$criteria)
|
|
{
|
|
$fields=array();
|
|
$values=array();
|
|
$bindByPosition=isset($criteria->params[0]);
|
|
foreach($data as $name=>$value)
|
|
{
|
|
if(($column=$table->getColumn($name))!==null)
|
|
{
|
|
if($bindByPosition)
|
|
{
|
|
$fields[]=$column->rawName.'=?';
|
|
$values[]=$column->typecast($value);
|
|
}
|
|
else
|
|
{
|
|
$fields[]=$column->rawName.'=:'.$name;
|
|
$values[':'.$name]=$column->typecast($value);
|
|
}
|
|
}
|
|
}
|
|
if($fields===array())
|
|
throw new CDbException(Yii::t('yii','No columns are being updated to table "{table}".',
|
|
array('{table}'=>$table->name)));
|
|
$sql="UPDATE {$table->rawName} SET ".implode(', ',$fields);
|
|
$sql=$this->applyJoin($sql,$criteria->join);
|
|
$sql=$this->applyCondition($sql,$criteria->condition);
|
|
$sql=$this->applyOrder($sql,$criteria->order);
|
|
$sql=$this->applyLimit($sql,$criteria->limit,$criteria->offset);
|
|
$command=$this->_connection->createCommand($sql);
|
|
$this->bindValues($command,array_merge($values,$criteria->params));
|
|
return $command;
|
|
}
|
|
public function createUpdateCounterCommand($table,$counters,$criteria)
|
|
{
|
|
$fields=array();
|
|
foreach($counters as $name=>$value)
|
|
{
|
|
if(($column=$table->getColumn($name))!==null)
|
|
{
|
|
$value=(int)$value;
|
|
if($value<0)
|
|
$fields[]="{$column->rawName}={$column->rawName}-".(-$value);
|
|
else
|
|
$fields[]="{$column->rawName}={$column->rawName}+".$value;
|
|
}
|
|
}
|
|
if($fields!==array())
|
|
{
|
|
$sql="UPDATE {$table->rawName} SET ".implode(', ',$fields);
|
|
$sql=$this->applyJoin($sql,$criteria->join);
|
|
$sql=$this->applyCondition($sql,$criteria->condition);
|
|
$sql=$this->applyOrder($sql,$criteria->order);
|
|
$sql=$this->applyLimit($sql,$criteria->limit,$criteria->offset);
|
|
$command=$this->_connection->createCommand($sql);
|
|
$this->bindValues($command,$criteria->params);
|
|
return $command;
|
|
}
|
|
else
|
|
throw new CDbException(Yii::t('yii','No counter columns are being updated for table "{table}".',
|
|
array('{table}'=>$table->name)));
|
|
}
|
|
public function createSqlCommand($sql,$params=array())
|
|
{
|
|
$command=$this->_connection->createCommand($sql);
|
|
$this->bindValues($command,$params);
|
|
return $command;
|
|
}
|
|
public function applyJoin($sql,$join)
|
|
{
|
|
if($join!=='')
|
|
return $sql.' '.$join;
|
|
else
|
|
return $sql;
|
|
}
|
|
public function applyCondition($sql,$condition)
|
|
{
|
|
if($condition!=='')
|
|
return $sql.' WHERE '.$condition;
|
|
else
|
|
return $sql;
|
|
}
|
|
public function applyOrder($sql,$orderBy)
|
|
{
|
|
if($orderBy!=='')
|
|
return $sql.' ORDER BY '.$orderBy;
|
|
else
|
|
return $sql;
|
|
}
|
|
public function applyLimit($sql,$limit,$offset)
|
|
{
|
|
if($limit>=0)
|
|
$sql.=' LIMIT '.(int)$limit;
|
|
if($offset>0)
|
|
$sql.=' OFFSET '.(int)$offset;
|
|
return $sql;
|
|
}
|
|
public function applyGroup($sql,$group)
|
|
{
|
|
if($group!=='')
|
|
return $sql.' GROUP BY '.$group;
|
|
else
|
|
return $sql;
|
|
}
|
|
public function bindValues($command, $values)
|
|
{
|
|
if(($n=count($values))===0)
|
|
return;
|
|
if(isset($values[0])) // question mark placeholders
|
|
{
|
|
for($i=0;$i<$n;++$i)
|
|
$command->bindValue($i+1,$values[$i]);
|
|
}
|
|
else // named placeholders
|
|
{
|
|
foreach($values as $name=>$value)
|
|
{
|
|
if($name[0]!==':')
|
|
$name=':'.$name;
|
|
$command->bindValue($name,$value);
|
|
}
|
|
}
|
|
}
|
|
public function createCriteria($condition='',$params=array())
|
|
{
|
|
if(is_array($condition))
|
|
$criteria=new CDbCriteria($condition);
|
|
else if($condition instanceof CDbCriteria)
|
|
$criteria=clone $condition;
|
|
else
|
|
{
|
|
$criteria=new CDbCriteria;
|
|
$criteria->condition=$condition;
|
|
$criteria->params=$params;
|
|
}
|
|
return $criteria;
|
|
}
|
|
public function createPkCriteria($table,$pk,$condition='',$params=array())
|
|
{
|
|
$criteria=$this->createCriteria($condition,$params);
|
|
if(!is_array($pk)) // single key
|
|
$pk=array($pk);
|
|
if(is_array($table->primaryKey) && !isset($pk[0]) && $pk!==array()) // single composite key
|
|
$pk=array($pk);
|
|
$condition=$this->createPkCondition($table,$pk);
|
|
if($criteria->condition!=='')
|
|
$criteria->condition=$condition.' AND ('.$criteria->condition.')';
|
|
else
|
|
$criteria->condition=$condition;
|
|
return $criteria;
|
|
}
|
|
public function createPkCondition($table,$values,$prefix=null)
|
|
{
|
|
if(($n=count($values))<1)
|
|
return '0=1';
|
|
if($prefix===null)
|
|
$prefix=$table->rawName.'.';
|
|
if(is_string($table->primaryKey))
|
|
{
|
|
// simple key: $values=array(pk1,pk2,...)
|
|
$column=$table->columns[$table->primaryKey];
|
|
foreach($values as &$value)
|
|
{
|
|
$value=$column->typecast($value);
|
|
if(is_string($value))
|
|
$value=$this->_connection->quoteValue($value);
|
|
}
|
|
if($n===1)
|
|
return $prefix.$column->rawName.'='.$values[0];
|
|
else
|
|
return $prefix.$column->rawName.' IN ('.implode(', ',$values).')';
|
|
}
|
|
else if(is_array($table->primaryKey))
|
|
{
|
|
// composite key: $values=array(array('pk1'=>'v1','pk2'=>'v2'),array(...))
|
|
foreach($table->primaryKey as $name)
|
|
{
|
|
$column=$table->columns[$name];
|
|
for($i=0;$i<$n;++$i)
|
|
{
|
|
if(isset($values[$i][$name]))
|
|
{
|
|
$value=$column->typecast($values[$i][$name]);
|
|
if(is_string($value))
|
|
$values[$i][$name]=$this->_connection->quoteValue($value);
|
|
else
|
|
$values[$i][$name]=$value;
|
|
}
|
|
else
|
|
throw new CDbException(Yii::t('yii','The value for the primary key "{key}" is not supplied when querying the table "{table}".',
|
|
array('{table}'=>$table->name,'{key}'=>$name)));
|
|
}
|
|
}
|
|
if(count($values)===1)
|
|
{
|
|
$entries=array();
|
|
foreach($values[0] as $name=>$value)
|
|
$entries[]=$prefix.$table->columns[$name]->rawName.'='.$value;
|
|
return implode(' AND ',$entries);
|
|
}
|
|
else
|
|
return $this->createCompositePkCondition($table,$values,$prefix);
|
|
}
|
|
else
|
|
throw new CDbException(Yii::t('yii','Table "{table}" does not have a primary key defined.',
|
|
array('{table}'=>$table->name)));
|
|
}
|
|
protected function createCompositePkCondition($table,$values,$prefix)
|
|
{
|
|
if($prefix===null)
|
|
$prefix=$table->rawName.'.';
|
|
$keyNames=array();
|
|
foreach(array_keys($values[0]) as $name)
|
|
$keyNames[]=$prefix.$table->columns[$name]->rawName;
|
|
$vs=array();
|
|
foreach($values as $value)
|
|
$vs[]='('.implode(', ',$value).')';
|
|
return '('.implode(', ',$keyNames).') IN ('.implode(', ',$vs).')';
|
|
}
|
|
public function createColumnCriteria($table,$columns,$condition='',$params=array())
|
|
{
|
|
$criteria=$this->createCriteria($condition,$params);
|
|
$bindByPosition=isset($criteria->params[0]);
|
|
$conditions=array();
|
|
$values=array();
|
|
foreach($columns as $name=>$value)
|
|
{
|
|
if(($column=$table->getColumn($name))!==null)
|
|
{
|
|
if($value!==null)
|
|
{
|
|
if($bindByPosition)
|
|
{
|
|
$conditions[]=$table->rawName.'.'.$column->rawName.'=?';
|
|
$values[]=$value;
|
|
}
|
|
else
|
|
{
|
|
$conditions[]=$table->rawName.'.'.$column->rawName.'=:'.$name;
|
|
$values[':'.$name]=$value;
|
|
}
|
|
}
|
|
else
|
|
$conditions[]=$table->rawName.'.'.$column->rawName.' IS NULL';
|
|
}
|
|
else
|
|
throw new CDbException(Yii::t('yii','Table "{table}" does not have a column named "{column}".',
|
|
array('{table}'=>$table->name,'{column}'=>$name)));
|
|
}
|
|
$criteria->params=array_merge($values,$criteria->params);
|
|
if(isset($conditions[0]))
|
|
{
|
|
if($criteria->condition!=='')
|
|
$criteria->condition=implode(' AND ',$conditions).' AND ('.$criteria->condition.')';
|
|
else
|
|
$criteria->condition=implode(' AND ',$conditions);
|
|
}
|
|
return $criteria;
|
|
}
|
|
public function createSearchCondition($table,$columns,$keywords,$prefix=null)
|
|
{
|
|
if(!is_array($keywords))
|
|
$keywords=preg_split('/\s+/u',$keywords,-1,PREG_SPLIT_NO_EMPTY);
|
|
if(empty($keywords))
|
|
return '';
|
|
if($prefix===null)
|
|
$prefix=$table->rawName.'.';
|
|
$conditions=array();
|
|
foreach($columns as $name)
|
|
{
|
|
if(($column=$table->getColumn($name))===null)
|
|
throw new CDbException(Yii::t('yii','Table "{table}" does not have a column named "{column}".',
|
|
array('{table}'=>$table->name,'{column}'=>$name)));
|
|
$condition=array();
|
|
foreach($keywords as $keyword)
|
|
$condition[]=$prefix.$column->rawName.' LIKE '.$this->_connection->quoteValue('%'.$keyword.'%');
|
|
$conditions[]=implode(' AND ',$condition);
|
|
}
|
|
return '('.implode(' OR ',$conditions).')';
|
|
}
|
|
}
|
|
class CSqliteCommandBuilder extends CDbCommandBuilder
|
|
{
|
|
protected function createCompositePkCondition($table,$values,$prefix)
|
|
{
|
|
$keyNames=array();
|
|
foreach(array_keys($values[0]) as $name)
|
|
$keyNames[]=$prefix.$table->columns[$name]->rawName;
|
|
$vs=array();
|
|
foreach($values as $value)
|
|
$vs[]=implode("||','||",$value);
|
|
return implode("||','||",$keyNames).' IN ('.implode(', ',$vs).')';
|
|
}
|
|
}
|
|
class CDbCriteria
|
|
{
|
|
public $select='*';
|
|
public $condition='';
|
|
public $params=array();
|
|
public $limit=-1;
|
|
public $offset=-1;
|
|
public $order='';
|
|
public $group='';
|
|
public $join='';
|
|
public function __construct($data=array())
|
|
{
|
|
foreach($data as $name=>$value)
|
|
$this->$name=$value;
|
|
}
|
|
}
|
|
class CPagination extends CComponent
|
|
{
|
|
const DEFAULT_PAGE_SIZE=10;
|
|
public $pageVar='page';
|
|
public $route='';
|
|
private $_pageSize=self::DEFAULT_PAGE_SIZE;
|
|
private $_itemCount=0;
|
|
private $_currentPage;
|
|
public function getPageSize()
|
|
{
|
|
return $this->_pageSize;
|
|
}
|
|
public function setPageSize($value)
|
|
{
|
|
if(($this->_pageSize=$value)<=0)
|
|
$this->_pageSize=self::DEFAULT_PAGE_SIZE;
|
|
}
|
|
public function getItemCount()
|
|
{
|
|
return $this->_itemCount;
|
|
}
|
|
public function setItemCount($value)
|
|
{
|
|
if(($this->_itemCount=$value)<0)
|
|
$this->_itemCount=0;
|
|
}
|
|
public function getPageCount()
|
|
{
|
|
return (int)(($this->_itemCount+$this->_pageSize-1)/$this->_pageSize);
|
|
}
|
|
public function getCurrentPage($recalculate=true)
|
|
{
|
|
if($this->_currentPage===null || $recalculate)
|
|
{
|
|
if(isset($_GET[$this->pageVar]))
|
|
{
|
|
$this->_currentPage=(int)$_GET[$this->pageVar]-1;
|
|
$pageCount=$this->getPageCount();
|
|
if($this->_currentPage>=$pageCount)
|
|
$this->_currentPage=$pageCount-1;
|
|
if($this->_currentPage<0)
|
|
$this->_currentPage=0;
|
|
}
|
|
else
|
|
$this->_currentPage=0;
|
|
}
|
|
return $this->_currentPage;
|
|
}
|
|
public function setCurrentPage($value)
|
|
{
|
|
$this->_currentPage=$value;
|
|
}
|
|
public function createPageUrl($controller,$page)
|
|
{
|
|
$params=($this->route==='')?$_GET:array();
|
|
if($page>0) // page 0 is the default
|
|
$params[$this->pageVar]=$page+1;
|
|
else
|
|
unset($params[$this->pageVar]);
|
|
return $controller->createUrl($this->route,$params);
|
|
}
|
|
}
|
|
class CJavaScript
|
|
{
|
|
public static function quote($js,$forUrl=false)
|
|
{
|
|
if($forUrl)
|
|
return strtr($js,array('%'=>'%25',"\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\'));
|
|
else
|
|
return strtr($js,array("\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\'));
|
|
}
|
|
public static function encode($value)
|
|
{
|
|
if(is_string($value))
|
|
{
|
|
if(strpos($value,'js:')===0)
|
|
return substr($value,3);
|
|
else
|
|
return "'".self::quote($value)."'";
|
|
}
|
|
else if($value===null)
|
|
return 'null';
|
|
else if(is_bool($value))
|
|
return $value?'true':'false';
|
|
else if(is_integer($value))
|
|
return "$value";
|
|
else if(is_float($value))
|
|
{
|
|
if($value===-INF)
|
|
return 'Number.NEGATIVE_INFINITY';
|
|
else if($value===INF)
|
|
return 'Number.POSITIVE_INFINITY';
|
|
else
|
|
return "$value";
|
|
}
|
|
else if(is_object($value))
|
|
return self::encode(get_object_vars($value));
|
|
else if(is_array($value))
|
|
{
|
|
$es=array();
|
|
if(($n=count($value))>0 && array_keys($value)!==range(0,$n-1))
|
|
{
|
|
foreach($value as $k=>$v)
|
|
$es[]="'".self::quote($k)."':".self::encode($v);
|
|
return '{'.implode(',',$es).'}';
|
|
}
|
|
else
|
|
{
|
|
foreach($value as $v)
|
|
$es[]=self::encode($v);
|
|
return '['.implode(',',$es).']';
|
|
}
|
|
}
|
|
else
|
|
return '';
|
|
}
|
|
public static function jsonEncode($data)
|
|
{
|
|
if(function_exists('json_encode'))
|
|
return json_encode($data);
|
|
else
|
|
{
|
|
return CJSON::encode($data);
|
|
}
|
|
}
|
|
public static function jsonDecode($data,$useArray=true)
|
|
{
|
|
if(function_exists('json_decode'))
|
|
return json_decode($data,$useArray);
|
|
else
|
|
return CJSON::decode($data,$useArray);
|
|
}
|
|
}
|
|
abstract class CBasePager extends CWidget
|
|
{
|
|
private $_pages;
|
|
public function getPages()
|
|
{
|
|
if($this->_pages===null)
|
|
$this->_pages=$this->createPages();
|
|
return $this->_pages;
|
|
}
|
|
public function setPages($pages)
|
|
{
|
|
$this->_pages=$pages;
|
|
}
|
|
protected function createPages()
|
|
{
|
|
return new CPagination;
|
|
}
|
|
public function getPageSize()
|
|
{
|
|
return $this->getPages()->getPageSize();
|
|
}
|
|
public function setPageSize($value)
|
|
{
|
|
$this->getPages()->setPageSize($value);
|
|
}
|
|
public function getItemCount()
|
|
{
|
|
return $this->getPages()->getItemCount();
|
|
}
|
|
public function setItemCount($value)
|
|
{
|
|
$this->getPages()->setItemCount($value);
|
|
}
|
|
public function getPageCount()
|
|
{
|
|
return $this->getPages()->getPageCount();
|
|
}
|
|
public function getCurrentPage($recalculate=true)
|
|
{
|
|
return $this->getPages()->getCurrentPage($recalculate);
|
|
}
|
|
public function setCurrentPage($value)
|
|
{
|
|
$this->getPages()->setCurrentPage($value);
|
|
}
|
|
protected function createPageUrl($page)
|
|
{
|
|
return $this->getPages()->createPageUrl($this->getController(),$page);
|
|
}
|
|
}
|
|
class CLinkPager extends CBasePager
|
|
{
|
|
const CSS_FIRST_PAGE='first';
|
|
const CSS_LAST_PAGE='last';
|
|
const CSS_PREVIOUS_PAGE='previous';
|
|
const CSS_NEXT_PAGE='previous';
|
|
const CSS_INTERNAL_PAGE='page';
|
|
const CSS_HIDDEN_PAGE='hidden';
|
|
const CSS_SELECTED_PAGE='selected';
|
|
public $maxButtonCount=10;
|
|
public $nextPageLabel='Next >';
|
|
public $prevPageLabel='< Previous';
|
|
public $firstPageLabel='<< First';
|
|
public $lastPageLabel='Last >>';
|
|
public $header='Go to page: ';
|
|
public $footer='';
|
|
public $cssFile;
|
|
public $htmlOptions=array();
|
|
public function run()
|
|
{
|
|
$buttons=$this->createPageButtons();
|
|
if(empty($buttons))
|
|
return;
|
|
$this->registerClientScript();
|
|
$htmlOptions=$this->htmlOptions;
|
|
if(!isset($htmlOptions['id']))
|
|
$htmlOptions['id']=$this->getId();
|
|
if(!isset($htmlOptions['class']))
|
|
$htmlOptions['class']='yiiPager';
|
|
echo $this->header;
|
|
echo CHtml::tag('ul',$htmlOptions,implode("\n",$buttons));
|
|
echo $this->footer;
|
|
}
|
|
protected function createPageButtons()
|
|
{
|
|
if(($pageCount=$this->getPageCount())<=1)
|
|
return array();
|
|
list($beginPage,$endPage)=$this->getPageRange();
|
|
$currentPage=$this->getCurrentPage(false); // currentPage is calculated in getPageRange()
|
|
$buttons=array();
|
|
// first page
|
|
$buttons[]=$this->createPageButton($this->firstPageLabel,0,self::CSS_FIRST_PAGE,$beginPage<=0,false);
|
|
// prev page
|
|
if(($page=$currentPage-1)<0)
|
|
$page=0;
|
|
$buttons[]=$this->createPageButton($this->prevPageLabel,$page,self::CSS_PREVIOUS_PAGE,$currentPage<=0,false);
|
|
// internal pages
|
|
for($i=$beginPage;$i<=$endPage;++$i)
|
|
$buttons[]=$this->createPageButton($i+1,$i,self::CSS_INTERNAL_PAGE,false,$i==$currentPage);
|
|
// next page
|
|
if(($page=$currentPage+1)>=$pageCount-1)
|
|
$page=$pageCount-1;
|
|
$buttons[]=$this->createPageButton($this->nextPageLabel,$page,self::CSS_NEXT_PAGE,$currentPage>=$pageCount-1,false);
|
|
// last page
|
|
$buttons[]=$this->createPageButton($this->lastPageLabel,$pageCount-1,self::CSS_LAST_PAGE,$endPage>=$pageCount-1,false);
|
|
return $buttons;
|
|
}
|
|
protected function createPageButton($label,$page,$class,$hidden,$selected)
|
|
{
|
|
if($hidden || $selected)
|
|
$class.=' '.($hidden ? self::CSS_HIDDEN_PAGE : self::CSS_SELECTED_PAGE);
|
|
return '<li class="'.$class.'">'.CHtml::link($label,$this->createPageUrl($page)).'</li>';
|
|
}
|
|
protected function getPageRange()
|
|
{
|
|
$currentPage=$this->getCurrentPage();
|
|
$pageCount=$this->getPageCount();
|
|
$buttonCount=$this->maxButtonCount > $pageCount ? $pageCount : $this->maxButtonCount;
|
|
$beginPage=max(0, $currentPage-(int)($this->maxButtonCount/2));
|
|
if(($endPage=$beginPage+$this->maxButtonCount-1)>=$pageCount)
|
|
{
|
|
$endPage=min($pageCount-1,$currentPage+(int)($this->maxButtonCount/2));
|
|
$beginPage=max(0,$endPage-$this->maxButtonCount+1);
|
|
}
|
|
return array($beginPage,$endPage);
|
|
}
|
|
protected function registerClientScript()
|
|
{
|
|
$cs=Yii::app()->getClientScript();
|
|
if($this->cssFile===null)
|
|
$cs->registerCssFile(CHtml::asset(Yii::getPathOfAlias('system.web.widgets.pagers.pager').'.css'));
|
|
else if($this->cssFile!==false)
|
|
$cs->registerCssFile($this->cssFile);
|
|
}
|
|
}
|
|
class CAssetManager extends CApplicationComponent
|
|
{
|
|
const DEFAULT_BASEPATH='assets';
|
|
private $_basePath;
|
|
private $_baseUrl;
|
|
private $_published=array();
|
|
public function init()
|
|
{
|
|
parent::init();
|
|
$request=Yii::app()->getRequest();
|
|
if($this->getBasePath()===null)
|
|
$this->setBasePath(dirname($request->getScriptFile()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH);
|
|
if($this->getBaseUrl()===null)
|
|
$this->setBaseUrl($request->getBaseUrl().'/'.self::DEFAULT_BASEPATH);
|
|
}
|
|
public function getBasePath()
|
|
{
|
|
return $this->_basePath;
|
|
}
|
|
public function setBasePath($value)
|
|
{
|
|
if(($basePath=realpath($value))!==false && is_dir($basePath) && is_writable($basePath))
|
|
$this->_basePath=$basePath;
|
|
else
|
|
throw new CException(Yii::t('yii','CAssetManager.basePath "{path}" is invalid. Please make sure the directory exists and is writable by the Web server process.',
|
|
array('{path}'=>$value)));
|
|
}
|
|
public function getBaseUrl()
|
|
{
|
|
return $this->_baseUrl;
|
|
}
|
|
public function setBaseUrl($value)
|
|
{
|
|
$this->_baseUrl=rtrim($value,'/');
|
|
}
|
|
public function publish($path,$hashByName=false,$level=-1)
|
|
{
|
|
if(isset($this->_published[$path]))
|
|
return $this->_published[$path];
|
|
else if(($src=realpath($path))!==false)
|
|
{
|
|
if(is_file($src))
|
|
{
|
|
$dir=$this->hash($hashByName ? basename($src) : dirname($src));
|
|
$fileName=basename($src);
|
|
$dstDir=$this->getBasePath().DIRECTORY_SEPARATOR.$dir;
|
|
$dstFile=$dstDir.DIRECTORY_SEPARATOR.$fileName;
|
|
if(@filemtime($dstFile)<@filemtime($src))
|
|
{
|
|
if(!is_dir($dstDir))
|
|
{
|
|
mkdir($dstDir);
|
|
@chmod($dstDir,0777);
|
|
}
|
|
copy($src,$dstFile);
|
|
}
|
|
return $this->_published[$path]=$this->getBaseUrl()."/$dir/$fileName";
|
|
}
|
|
else
|
|
{
|
|
$dir=$this->hash($hashByName ? basename($src) : $src);
|
|
$dstDir=$this->getBasePath().DIRECTORY_SEPARATOR.$dir;
|
|
if(!is_dir($dstDir))
|
|
CFileHelper::copyDirectory($src,$dstDir,array('exclude'=>array('.svn'),'level'=>$level));
|
|
return $this->_published[$path]=$this->getBaseUrl().'/'.$dir;
|
|
}
|
|
}
|
|
else
|
|
throw new CException(Yii::t('yii','The asset "{asset}" to be pulished does not exist.',
|
|
array('{asset}'=>$path)));
|
|
}
|
|
public function getPublishedPath($path,$hashByName=false)
|
|
{
|
|
if(($path=realpath($path))!==false)
|
|
{
|
|
$base=$this->getBasePath().DIRECTORY_SEPARATOR;
|
|
if(is_file($path))
|
|
return $base . $this->hash($hashByName ? basename($path) : dirname($path)) . DIRECTORY_SEPARATOR . basename($path);
|
|
else
|
|
return $base . $this->hash($hashByName ? basename($path) : $path);
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
public function getPublishedUrl($path,$hashByName=false)
|
|
{
|
|
if(isset($this->_published[$path]))
|
|
return $this->_published[$path];
|
|
if(($path=realpath($path))!==false)
|
|
{
|
|
if(is_file($path))
|
|
return $this->getBaseUrl().'/'.$this->hash($hashByName ? basename($path) : dirname($path)).'/'.basename($path);
|
|
else
|
|
return $this->getBaseUrl().'/'.$this->hash($hashByName ? basename($path) : $path);
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
protected function hash($path)
|
|
{
|
|
return sprintf('%x',crc32($path.Yii::getVersion()));
|
|
}
|
|
}
|
|
class CFileHelper
|
|
{
|
|
public static function copyDirectory($src,$dst,$options=array())
|
|
{
|
|
$fileTypes=array();
|
|
$exclude=array();
|
|
$level=-1;
|
|
extract($options);
|
|
self::copyDirectoryRecursive($src,$dst,'',$fileTypes,$exclude,$level);
|
|
}
|
|
public static function findFiles($dir,$options=array())
|
|
{
|
|
$fileTypes=array();
|
|
$exclude=array();
|
|
$level=-1;
|
|
extract($options);
|
|
$list=self::findFilesRecursive($dir,'',$fileTypes,$exclude,$level);
|
|
sort($list);
|
|
return $list;
|
|
}
|
|
protected static function copyDirectoryRecursive($src,$dst,$base,$fileTypes,$exclude,$level)
|
|
{
|
|
@mkdir($dst);
|
|
@chmod($dst,0777);
|
|
$folder=opendir($src);
|
|
while($file=readdir($folder))
|
|
{
|
|
if($file==='.' || $file==='..')
|
|
continue;
|
|
$path=$src.DIRECTORY_SEPARATOR.$file;
|
|
$isFile=is_file($path);
|
|
if(self::validatePath($base,$file,$isFile,$fileTypes,$exclude))
|
|
{
|
|
if($isFile)
|
|
copy($path,$dst.DIRECTORY_SEPARATOR.$file);
|
|
else if($level)
|
|
self::copyDirectoryRecursive($path,$dst.DIRECTORY_SEPARATOR.$file,$base.'/'.$file,$fileTypes,$exclude,$level-1);
|
|
}
|
|
}
|
|
closedir($folder);
|
|
}
|
|
protected static function findFilesRecursive($dir,$base,$fileTypes,$exclude,$level)
|
|
{
|
|
$list=array();
|
|
$handle=opendir($dir);
|
|
while($file=readdir($handle))
|
|
{
|
|
if($file==='.' || $file==='..')
|
|
continue;
|
|
$path=$dir.DIRECTORY_SEPARATOR.$file;
|
|
$isFile=is_file($path);
|
|
if(self::validatePath($base,$file,$isFile,$fileTypes,$exclude))
|
|
{
|
|
if($isFile)
|
|
$list[]=$path;
|
|
else if($level)
|
|
$list=array_merge($list,self::findFilesRecursive($path,$base.'/'.$file,$fileTypes,$exclude,$level-1));
|
|
}
|
|
}
|
|
closedir($handle);
|
|
return $list;
|
|
}
|
|
protected static function validatePath($base,$file,$isFile,$fileTypes,$exclude)
|
|
{
|
|
foreach($exclude as $e)
|
|
{
|
|
if($file===$e || strpos($base.'/'.$file,$e)===0)
|
|
return false;
|
|
}
|
|
if(!$isFile || empty($fileTypes))
|
|
return true;
|
|
if(($pos=strrpos($file,'.'))!==false)
|
|
{
|
|
$type=substr($file,$pos+1);
|
|
return in_array($type,$fileTypes);
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
public static function getMimeType($file)
|
|
{
|
|
if(function_exists('finfo_open'))
|
|
{
|
|
if($info=finfo_open(FILEINFO_MIME))
|
|
return finfo_file($info,$file);
|
|
else
|
|
return null;
|
|
}
|
|
if(function_exists('mime_content_type'))
|
|
return mime_content_type($file);
|
|
return self::getMimeTypeByExtension($file);
|
|
}
|
|
public static function getMimeTypeByExtension($file)
|
|
{
|
|
static $extensions;
|
|
if($extensions===null)
|
|
$extensions=require(Yii::getPathOfAlias('system.utils.mimeTypes').'.php');
|
|
if(($pos=strrpos($file,'.'))!==false)
|
|
{
|
|
$ext=strtolower(substr($file,$pos+1));
|
|
if(isset($extensions[$ext]))
|
|
return $extensions[$ext];
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
interface IApplicationComponent
|
|
{
|
|
public function init();
|
|
public function getIsInitialized();
|
|
}
|
|
interface ICache
|
|
{
|
|
public function get($id);
|
|
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 run();
|
|
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());
|
|
}
|
|
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);
|
|
}
|
|
?>
|