".$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.='\n";
unset($htmlOptions['prompt']);
}
if(isset($htmlOptions['empty']))
{
$content.='\n";
unset($htmlOptions['empty']);
}
foreach($listData as $key=>$value)
{
if(is_array($value))
{
$content.=''."\n";
}
else if(!is_array($selection) && !strcmp($key,$selection) || is_array($selection) && in_array($key,$selection))
$content.='\n";
else
$content.='\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('/(]*>|<\\/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('/(]*>)/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('/(? 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 '
';
}
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);
}
?>