芝麻web文件管理V1.00
';
}
public static function statefulForm($action='',$method='post',$htmlOptions=array())
{
return self::form($action,$method,$htmlOptions)."\n".
self::tag('div',array('style'=>'display:none'),self::pageStateField(''));
}
public static function pageStateField($value)
{
return '
';
}
public static function link($text,$url='#',$htmlOptions=array())
{
if($url!=='')
$htmlOptions['href']=self::normalizeUrl($url);
self::clientChange('click',$htmlOptions);
return self::tag('a',$htmlOptions,$text);
}
public static function mailto($text,$email='',$htmlOptions=array())
{
if($email==='')
$email=$text;
return self::link($text,'mailto:'.$email,$htmlOptions);
}
public static function image($src,$alt='',$htmlOptions=array())
{
$htmlOptions['src']=$src;
$htmlOptions['alt']=$alt;
return self::tag('img',$htmlOptions);
}
public static function button($label='button',$htmlOptions=array())
{
if(!isset($htmlOptions['name']))
{
if(!array_key_exists('name',$htmlOptions))
$htmlOptions['name']=self::ID_PREFIX.self::$count++;
}
if(!isset($htmlOptions['type']))
$htmlOptions['type']='button';
if(!isset($htmlOptions['value']) && $htmlOptions['type']!='image')
$htmlOptions['value']=$label;
self::clientChange('click',$htmlOptions);
return self::tag('input',$htmlOptions);
}
public static function htmlButton($label='button',$htmlOptions=array())
{
if(!isset($htmlOptions['name']))
$htmlOptions['name']=self::ID_PREFIX.self::$count++;
if(!isset($htmlOptions['type']))
$htmlOptions['type']='button';
self::clientChange('click',$htmlOptions);
return self::tag('button',$htmlOptions,$label);
}
public static function submitButton($label='submit',$htmlOptions=array())
{
$htmlOptions['type']='submit';
return self::button($label,$htmlOptions);
}
public static function resetButton($label='reset',$htmlOptions=array())
{
$htmlOptions['type']='reset';
return self::button($label,$htmlOptions);
}
public static function imageButton($src,$htmlOptions=array())
{
$htmlOptions['src']=$src;
$htmlOptions['type']='image';
return self::button('submit',$htmlOptions);
}
public static function linkButton($label='submit',$htmlOptions=array())
{
if(!isset($htmlOptions['submit']))
$htmlOptions['submit']=isset($htmlOptions['href']) ? $htmlOptions['href'] : '';
return self::link($label,'#',$htmlOptions);
}
public static function label($label,$for,$htmlOptions=array())
{
if($for===false)
unset($htmlOptions['for']);
else
$htmlOptions['for']=$for;
if(isset($htmlOptions['required']))
{
if($htmlOptions['required'])
{
if(isset($htmlOptions['class']))
$htmlOptions['class'].=' '.self::$requiredCss;
else
$htmlOptions['class']=self::$requiredCss;
$label=self::$beforeRequiredLabel.$label.self::$afterRequiredLabel;
}
unset($htmlOptions['required']);
}
return self::tag('label',$htmlOptions,$label);
}
public static function colorField($name,$value='',$htmlOptions=array())
{
self::clientChange('change',$htmlOptions);
return self::inputField('color',$name,$value,$htmlOptions);
}
public static function textField($name,$value='',$htmlOptions=array())
{
self::clientChange('change',$htmlOptions);
return self::inputField('text',$name,$value,$htmlOptions);
}
public static function searchField($name,$value='',$htmlOptions=array())
{
self::clientChange('change',$htmlOptions);
return self::inputField('search',$name,$value,$htmlOptions);
}
public static function numberField($name,$value='',$htmlOptions=array())
{
self::clientChange('change',$htmlOptions);
return self::inputField('number',$name,$value,$htmlOptions);
}
public static function rangeField($name,$value='',$htmlOptions=array())
{
self::clientChange('change',$htmlOptions);
return self::inputField('range',$name,$value,$htmlOptions);
}
public static function dateField($name,$value='',$htmlOptions=array())
{
self::clientChange('change',$htmlOptions);
return self::inputField('date',$name,$value,$htmlOptions);
}
public static function timeField($name,$value='',$htmlOptions=array())
{
self::clientChange('change',$htmlOptions);
return self::inputField('time',$name,$value,$htmlOptions);
}
public static function dateTimeField($name,$value='',$htmlOptions=array())
{
self::clientChange('change',$htmlOptions);
return self::inputField('datetime',$name,$value,$htmlOptions);
}
public static function dateTimeLocalField($name,$value='',$htmlOptions=array())
{
self::clientChange('change',$htmlOptions);
return self::inputField('datetime-local',$name,$value,$htmlOptions);
}
public static function weekField($name,$value='',$htmlOptions=array())
{
self::clientChange('change',$htmlOptions);
return self::inputField('week',$name,$value,$htmlOptions);
}
public static function emailField($name,$value='',$htmlOptions=array())
{
self::clientChange('change',$htmlOptions);
return self::inputField('email',$name,$value,$htmlOptions);
}
public static function telField($name,$value='',$htmlOptions=array())
{
self::clientChange('change',$htmlOptions);
return self::inputField('tel',$name,$value,$htmlOptions);
}
public static function urlField($name,$value='',$htmlOptions=array())
{
self::clientChange('change',$htmlOptions);
return self::inputField('url',$name,$value,$htmlOptions);
}
public static function hiddenField($name,$value='',$htmlOptions=array())
{
return self::inputField('hidden',$name,$value,$htmlOptions);
}
public static function passwordField($name,$value='',$htmlOptions=array())
{
self::clientChange('change',$htmlOptions);
return self::inputField('password',$name,$value,$htmlOptions);
}
public static function fileField($name,$value='',$htmlOptions=array())
{
return self::inputField('file',$name,$value,$htmlOptions);
}
public static function textArea($name,$value='',$htmlOptions=array())
{
$htmlOptions['name']=$name;
if(!isset($htmlOptions['id']))
$htmlOptions['id']=self::getIdByName($name);
elseif($htmlOptions['id']===false)
unset($htmlOptions['id']);
self::clientChange('change',$htmlOptions);
return self::tag('textarea',$htmlOptions,isset($htmlOptions['encode']) && !$htmlOptions['encode'] ? $value : self::encode($value));
}
public static function radioButton($name,$checked=false,$htmlOptions=array())
{
if($checked)
$htmlOptions['checked']='checked';
else
unset($htmlOptions['checked']);
$value=isset($htmlOptions['value']) ? $htmlOptions['value'] : 1;
self::clientChange('click',$htmlOptions);
if(array_key_exists('uncheckValue',$htmlOptions))
{
$uncheck=$htmlOptions['uncheckValue'];
unset($htmlOptions['uncheckValue']);
}
else
$uncheck=null;
if($uncheck!==null)
{
// add a hidden field so that if the radio button is not selected, it still submits a value
if(isset($htmlOptions['id']) && $htmlOptions['id']!==false)
$uncheckOptions=array('id'=>self::ID_PREFIX.$htmlOptions['id']);
else
$uncheckOptions=array('id'=>false);
if(!empty($htmlOptions['disabled']))
$uncheckOptions['disabled']=$htmlOptions['disabled'];
$hidden=self::hiddenField($name,$uncheck,$uncheckOptions);
}
else
$hidden='';
// add a hidden field so that if the radio button is not selected, it still submits a value
return $hidden . self::inputField('radio',$name,$value,$htmlOptions);
}
public static function checkBox($name,$checked=false,$htmlOptions=array())
{
if($checked)
$htmlOptions['checked']='checked';
else
unset($htmlOptions['checked']);
$value=isset($htmlOptions['value']) ? $htmlOptions['value'] : 1;
self::clientChange('click',$htmlOptions);
if(array_key_exists('uncheckValue',$htmlOptions))
{
$uncheck=$htmlOptions['uncheckValue'];
unset($htmlOptions['uncheckValue']);
}
else
$uncheck=null;
if($uncheck!==null)
{
// add a hidden field so that if the check box is not checked, it still submits a value
if(isset($htmlOptions['id']) && $htmlOptions['id']!==false)
$uncheckOptions=array('id'=>self::ID_PREFIX.$htmlOptions['id']);
else
$uncheckOptions=array('id'=>false);
if(!empty($htmlOptions['disabled']))
$uncheckOptions['disabled']=$htmlOptions['disabled'];
$hidden=self::hiddenField($name,$uncheck,$uncheckOptions);
}
else
$hidden='';
// add a hidden field so that if the check box is not checked, it still submits a value
return $hidden . self::inputField('checkbox',$name,$value,$htmlOptions);
}
public static function dropDownList($name,$select,$data,$htmlOptions=array())
{
$htmlOptions['name']=$name;
if(!isset($htmlOptions['id']))
$htmlOptions['id']=self::getIdByName($name);
elseif($htmlOptions['id']===false)
unset($htmlOptions['id']);
self::clientChange('change',$htmlOptions);
$options="\n".self::listOptions($select,$data,$htmlOptions);
$hidden='';
if(!empty($htmlOptions['multiple']))
{
if(substr($htmlOptions['name'],-2)!=='[]')
$htmlOptions['name'].='[]';
if(isset($htmlOptions['unselectValue']))
{
$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
if(!empty($htmlOptions['disabled']))
$hiddenOptions['disabled']=$htmlOptions['disabled'];
$hidden=self::hiddenField(substr($htmlOptions['name'],0,-2),$htmlOptions['unselectValue'],$hiddenOptions);
unset($htmlOptions['unselectValue']);
}
}
// add a hidden field so that if the option is not selected, it still submits a value
return $hidden . self::tag('select',$htmlOptions,$options);
}
public static function listBox($name,$select,$data,$htmlOptions=array())
{
if(!isset($htmlOptions['size']))
$htmlOptions['size']=4;
if(!empty($htmlOptions['multiple']))
{
if(substr($name,-2)!=='[]')
$name.='[]';
}
return self::dropDownList($name,$select,$data,$htmlOptions);
}
public static function checkBoxList($name,$select,$data,$htmlOptions=array())
{
$template=isset($htmlOptions['template'])?$htmlOptions['template']:'{input} {label}';
$separator=isset($htmlOptions['separator'])?$htmlOptions['separator']:self::tag('br');
$container=isset($htmlOptions['container'])?$htmlOptions['container']:'span';
unset($htmlOptions['template'],$htmlOptions['separator'],$htmlOptions['container']);
if(substr($name,-2)!=='[]')
$name.='[]';
if(isset($htmlOptions['checkAll']))
{
$checkAllLabel=$htmlOptions['checkAll'];
$checkAllLast=isset($htmlOptions['checkAllLast']) && $htmlOptions['checkAllLast'];
}
unset($htmlOptions['checkAll'],$htmlOptions['checkAllLast']);
$labelOptions=isset($htmlOptions['labelOptions'])?$htmlOptions['labelOptions']:array();
unset($htmlOptions['labelOptions']);
$items=array();
$baseID=isset($htmlOptions['baseID']) ? $htmlOptions['baseID'] : self::getIdByName($name);
unset($htmlOptions['baseID']);
$id=0;
$checkAll=true;
foreach($data as $value=>$labelTitle)
{
$checked=!is_array($select) && !strcmp($value,$select) || is_array($select) && in_array($value,$select);
$checkAll=$checkAll && $checked;
$htmlOptions['value']=$value;
$htmlOptions['id']=$baseID.'_'.$id++;
$option=self::checkBox($name,$checked,$htmlOptions);
$beginLabel=self::openTag('label',$labelOptions);
$label=self::label($labelTitle,$htmlOptions['id'],$labelOptions);
$endLabel=self::closeTag('label');
$items[]=strtr($template,array(
'{input}'=>$option,
'{beginLabel}'=>$beginLabel,
'{label}'=>$label,
'{labelTitle}'=>$labelTitle,
'{endLabel}'=>$endLabel,
));
}
if(isset($checkAllLabel))
{
$htmlOptions['value']=1;
$htmlOptions['id']=$id=$baseID.'_all';
$option=self::checkBox($id,$checkAll,$htmlOptions);
$beginLabel=self::openTag('label',$labelOptions);
$label=self::label($checkAllLabel,$id,$labelOptions);
$endLabel=self::closeTag('label');
$item=strtr($template,array(
'{input}'=>$option,
'{beginLabel}'=>$beginLabel,
'{label}'=>$label,
'{labelTitle}'=>$checkAllLabel,
'{endLabel}'=>$endLabel,
));
if($checkAllLast)
$items[]=$item;
else
array_unshift($items,$item);
$name=strtr($name,array('['=>'\\[',']'=>'\\]'));
$js=<<
getClientScript();
$cs->registerCoreScript('jquery');
$cs->registerScript($id,$js);
}
if(empty($container))
return implode($separator,$items);
else
return self::tag($container,array('id'=>$baseID),implode($separator,$items));
}
public static function radioButtonList($name,$select,$data,$htmlOptions=array())
{
$template=isset($htmlOptions['template'])?$htmlOptions['template']:'{input} {label}';
$separator=isset($htmlOptions['separator'])?$htmlOptions['separator']:self::tag('br');
$container=isset($htmlOptions['container'])?$htmlOptions['container']:'span';
unset($htmlOptions['template'],$htmlOptions['separator'],$htmlOptions['container']);
$labelOptions=isset($htmlOptions['labelOptions'])?$htmlOptions['labelOptions']:array();
unset($htmlOptions['labelOptions']);
if(isset($htmlOptions['empty']))
{
if(!is_array($htmlOptions['empty']))
$htmlOptions['empty']=array(''=>$htmlOptions['empty']);
$data=CMap::mergeArray($htmlOptions['empty'],$data);
unset($htmlOptions['empty']);
}
$items=array();
$baseID=isset($htmlOptions['baseID']) ? $htmlOptions['baseID'] : self::getIdByName($name);
unset($htmlOptions['baseID']);
$id=0;
foreach($data as $value=>$labelTitle)
{
$checked=!strcmp($value,$select);
$htmlOptions['value']=$value;
$htmlOptions['id']=$baseID.'_'.$id++;
$option=self::radioButton($name,$checked,$htmlOptions);
$beginLabel=self::openTag('label',$labelOptions);
$label=self::label($labelTitle,$htmlOptions['id'],$labelOptions);
$endLabel=self::closeTag('label');
$items[]=strtr($template,array(
'{input}'=>$option,
'{beginLabel}'=>$beginLabel,
'{label}'=>$label,
'{labelTitle}'=>$labelTitle,
'{endLabel}'=>$endLabel,
));
}
if(empty($container))
return implode($separator,$items);
else
return self::tag($container,array('id'=>$baseID),implode($separator,$items));
}
public static function ajaxLink($text,$url,$ajaxOptions=array(),$htmlOptions=array())
{
if(!isset($htmlOptions['href']))
$htmlOptions['href']='#';
$ajaxOptions['url']=$url;
$htmlOptions['ajax']=$ajaxOptions;
self::clientChange('click',$htmlOptions);
return self::tag('a',$htmlOptions,$text);
}
public static function ajaxButton($label,$url,$ajaxOptions=array(),$htmlOptions=array())
{
$ajaxOptions['url']=$url;
$htmlOptions['ajax']=$ajaxOptions;
return self::button($label,$htmlOptions);
}
public static function ajaxSubmitButton($label,$url,$ajaxOptions=array(),$htmlOptions=array())
{
$ajaxOptions['type']='POST';
$htmlOptions['type']='submit';
return self::ajaxButton($label,$url,$ajaxOptions,$htmlOptions);
}
public static function ajax($options)
{
Yii::app()->getClientScript()->registerCoreScript('jquery');
if(!isset($options['url']))
$options['url']=new CJavaScriptExpression('location.href');
else
$options['url']=self::normalizeUrl($options['url']);
if(!isset($options['cache']))
$options['cache']=false;
if(!isset($options['data']) && isset($options['type']))
$options['data']=new CJavaScriptExpression('jQuery(this).parents("form").serialize()');
foreach(array('beforeSend','complete','error','success') as $name)
{
if(isset($options[$name]) && !($options[$name] instanceof CJavaScriptExpression))
$options[$name]=new CJavaScriptExpression($options[$name]);
}
if(isset($options['update']))
{
if(!isset($options['success']))
$options['success']=new CJavaScriptExpression('function(html){jQuery("'.$options['update'].'").html(html)}');
unset($options['update']);
}
if(isset($options['replace']))
{
if(!isset($options['success']))
$options['success']=new CJavaScriptExpression('function(html){jQuery("'.$options['replace'].'").replaceWith(html)}');
unset($options['replace']);
}
return 'jQuery.ajax('.CJavaScript::encode($options).');';
}
public static function asset($path,$hashByName=false)
{
return Yii::app()->getAssetManager()->publish($path,$hashByName);
}
public static function normalizeUrl($url)
{
if(is_array($url))
{
if(isset($url[0]))
{
if(($c=Yii::app()->getController())!==null)
$url=$c->createUrl($url[0],array_splice($url,1));
else
$url=Yii::app()->createUrl($url[0],array_splice($url,1));
}
else
$url='';
}
return $url==='' ? Yii::app()->getRequest()->getUrl() : $url;
}
protected static function inputField($type,$name,$value,$htmlOptions)
{
$htmlOptions['type']=$type;
$htmlOptions['value']=$value;
$htmlOptions['name']=$name;
if(!isset($htmlOptions['id']))
$htmlOptions['id']=self::getIdByName($name);
elseif($htmlOptions['id']===false)
unset($htmlOptions['id']);
return self::tag('input',$htmlOptions);
}
public static function activeLabel($model,$attribute,$htmlOptions=array())
{
$inputName=self::resolveName($model,$attribute);
if(isset($htmlOptions['for']))
{
$for=$htmlOptions['for'];
unset($htmlOptions['for']);
}
else
$for=self::getIdByName($inputName);
if(isset($htmlOptions['label']))
{
if(($label=$htmlOptions['label'])===false)
return '';
unset($htmlOptions['label']);
}
else
$label=$model->getAttributeLabel($attribute);
if($model->hasErrors($attribute))
self::addErrorCss($htmlOptions);
return self::label($label,$for,$htmlOptions);
}
public static function activeLabelEx($model,$attribute,$htmlOptions=array())
{
$realAttribute=$attribute;
self::resolveName($model,$attribute); // strip off square brackets if any
if (!isset($htmlOptions['required']))
$htmlOptions['required']=$model->isAttributeRequired($attribute);
return self::activeLabel($model,$realAttribute,$htmlOptions);
}
public static function activeTextField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('text',$model,$attribute,$htmlOptions);
}
public static function activeSearchField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('search',$model,$attribute,$htmlOptions);
}
public static function activeUrlField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('url',$model,$attribute,$htmlOptions);
}
public static function activeEmailField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('email',$model,$attribute,$htmlOptions);
}
public static function activeNumberField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('number',$model,$attribute,$htmlOptions);
}
public static function activeRangeField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('range',$model,$attribute,$htmlOptions);
}
public static function activeDateField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('date',$model,$attribute,$htmlOptions);
}
public static function activeTimeField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('time',$model,$attribute,$htmlOptions);
}
public static function activeDateTimeField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('datetime',$model,$attribute,$htmlOptions);
}
public static function activeDateTimeLocalField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('datetime-local',$model,$attribute,$htmlOptions);
}
public static function activeWeekField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('week',$model,$attribute,$htmlOptions);
}
public static function activeColorField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('color',$model,$attribute,$htmlOptions);
}
public static function activeTelField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('tel',$model,$attribute,$htmlOptions);
}
public static function activeHiddenField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
return self::activeInputField('hidden',$model,$attribute,$htmlOptions);
}
public static function activePasswordField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('password',$model,$attribute,$htmlOptions);
}
public static function activeTextArea($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
if($model->hasErrors($attribute))
self::addErrorCss($htmlOptions);
if(isset($htmlOptions['value']))
{
$text=$htmlOptions['value'];
unset($htmlOptions['value']);
}
else
$text=self::resolveValue($model,$attribute);
return self::tag('textarea',$htmlOptions,isset($htmlOptions['encode']) && !$htmlOptions['encode'] ? $text : self::encode($text));
}
public static function activeFileField($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
// add a hidden field so that if a model only has a file field, we can
// still use isset($_POST[$modelClass]) to detect if the input is submitted
$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
if(!empty($htmlOptions['disabled']))
$hiddenOptions['disabled']=$htmlOptions['disabled'];
return self::hiddenField($htmlOptions['name'],'',$hiddenOptions)
. self::activeInputField('file',$model,$attribute,$htmlOptions);
}
public static function activeRadioButton($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
if(!isset($htmlOptions['value']))
$htmlOptions['value']=1;
if(!isset($htmlOptions['checked']) && self::resolveValue($model,$attribute)==$htmlOptions['value'])
$htmlOptions['checked']='checked';
self::clientChange('click',$htmlOptions);
if(array_key_exists('uncheckValue',$htmlOptions))
{
$uncheck=$htmlOptions['uncheckValue'];
unset($htmlOptions['uncheckValue']);
}
else
$uncheck='0';
$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
if(!empty($htmlOptions['disabled']))
$hiddenOptions['disabled']=$htmlOptions['disabled'];
$hidden=$uncheck!==null ? self::hiddenField($htmlOptions['name'],$uncheck,$hiddenOptions) : '';
// add a hidden field so that if the radio button is not selected, it still submits a value
return $hidden . self::activeInputField('radio',$model,$attribute,$htmlOptions);
}
public static function activeCheckBox($model,$attribute,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
if(!isset($htmlOptions['value']))
$htmlOptions['value']=1;
if(!isset($htmlOptions['checked']) && self::resolveValue($model,$attribute)==$htmlOptions['value'])
$htmlOptions['checked']='checked';
self::clientChange('click',$htmlOptions);
if(array_key_exists('uncheckValue',$htmlOptions))
{
$uncheck=$htmlOptions['uncheckValue'];
unset($htmlOptions['uncheckValue']);
}
else
$uncheck='0';
$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
if(!empty($htmlOptions['disabled']))
$hiddenOptions['disabled']=$htmlOptions['disabled'];
$hidden=$uncheck!==null ? self::hiddenField($htmlOptions['name'],$uncheck,$hiddenOptions) : '';
return $hidden . self::activeInputField('checkbox',$model,$attribute,$htmlOptions);
}
public static function activeDropDownList($model,$attribute,$data,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
$selection=self::resolveValue($model,$attribute);
$options="\n".self::listOptions($selection,$data,$htmlOptions);
self::clientChange('change',$htmlOptions);
if($model->hasErrors($attribute))
self::addErrorCss($htmlOptions);
$hidden='';
if(!empty($htmlOptions['multiple']))
{
if(substr($htmlOptions['name'],-2)!=='[]')
$htmlOptions['name'].='[]';
if(isset($htmlOptions['unselectValue']))
{
$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
if(!empty($htmlOptions['disabled']))
$hiddenOptions['disabled']=$htmlOptions['disabled'];
$hidden=self::hiddenField(substr($htmlOptions['name'],0,-2),$htmlOptions['unselectValue'],$hiddenOptions);
unset($htmlOptions['unselectValue']);
}
}
return $hidden . self::tag('select',$htmlOptions,$options);
}
public static function activeListBox($model,$attribute,$data,$htmlOptions=array())
{
if(!isset($htmlOptions['size']))
$htmlOptions['size']=4;
return self::activeDropDownList($model,$attribute,$data,$htmlOptions);
}
public static function activeCheckBoxList($model,$attribute,$data,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
$selection=self::resolveValue($model,$attribute);
if($model->hasErrors($attribute))
self::addErrorCss($htmlOptions);
$name=$htmlOptions['name'];
unset($htmlOptions['name']);
if(array_key_exists('uncheckValue',$htmlOptions))
{
$uncheck=$htmlOptions['uncheckValue'];
unset($htmlOptions['uncheckValue']);
}
else
$uncheck='';
$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
if(!empty($htmlOptions['disabled']))
$hiddenOptions['disabled']=$htmlOptions['disabled'];
$hidden=$uncheck!==null ? self::hiddenField($name,$uncheck,$hiddenOptions) : '';
return $hidden . self::checkBoxList($name,$selection,$data,$htmlOptions);
}
public static function activeRadioButtonList($model,$attribute,$data,$htmlOptions=array())
{
self::resolveNameID($model,$attribute,$htmlOptions);
$selection=self::resolveValue($model,$attribute);
if($model->hasErrors($attribute))
self::addErrorCss($htmlOptions);
$name=$htmlOptions['name'];
unset($htmlOptions['name']);
if(array_key_exists('uncheckValue',$htmlOptions))
{
$uncheck=$htmlOptions['uncheckValue'];
unset($htmlOptions['uncheckValue']);
}
else
$uncheck='';
$hiddenOptions=isset($htmlOptions['id']) ? array('id'=>self::ID_PREFIX.$htmlOptions['id']) : array('id'=>false);
if(!empty($htmlOptions['disabled']))
$hiddenOptions['disabled']=$htmlOptions['disabled'];
$hidden=$uncheck!==null ? self::hiddenField($name,$uncheck,$hiddenOptions) : '';
return $hidden . self::radioButtonList($name,$selection,$data,$htmlOptions);
}
public static function errorSummary($model,$header=null,$footer=null,$htmlOptions=array())
{
$content='';
if(!is_array($model))
$model=array($model);
if(isset($htmlOptions['firstError']))
{
$firstError=$htmlOptions['firstError'];
unset($htmlOptions['firstError']);
}
else
$firstError=false;
foreach($model as $m)
{
foreach($m->getErrors() as $errors)
{
foreach($errors as $error)
{
if($error!='')
{
if (!isset($htmlOptions['encode']) || $htmlOptions['encode'])
$error=self::encode($error);
$content.= ''.$error."\n";
}
if($firstError)
break;
}
}
}
if($content!=='')
{
if($header===null)
$header=''.Yii::t('yii','Please fix the following input errors:').'
';
if(!isset($htmlOptions['class']))
$htmlOptions['class']=self::$errorSummaryCss;
return self::tag('div',$htmlOptions,$header."\n".$footer);
}
else
return '';
}
public static function error($model,$attribute,$htmlOptions=array())
{
self::resolveName($model,$attribute); // turn [a][b]attr into attr
$error=$model->getError($attribute);
if (!isset($htmlOptions['encode']) || $htmlOptions['encode'])
$error=self::encode($error);
if($error!='')
{
if(!isset($htmlOptions['class']))
$htmlOptions['class']=self::$errorMessageCss;
return self::tag(self::$errorContainerTag,$htmlOptions,$error);
}
else
return '';
}
public static function listData($models,$valueField,$textField,$groupField='')
{
$listData=array();
if($groupField==='')
{
foreach($models as $model)
{
$value=self::value($model,$valueField);
$text=self::value($model,$textField);
$listData[$value]=$text;
}
}
else
{
foreach($models as $model)
{
$group=self::value($model,$groupField);
$value=self::value($model,$valueField);
$text=self::value($model,$textField);
if($group===null)
$listData[$value]=$text;
else
$listData[$group][$value]=$text;
}
}
return $listData;
}
public static function value($model,$attribute,$defaultValue=null)
{
if(is_scalar($attribute) || $attribute===null)
foreach(explode('.',$attribute) as $name)
{
if(is_object($model))
{
if ((version_compare(PHP_VERSION, '7.2.0', '>=')
&& is_numeric($name))
|| !isset($model->$name)
)
{
return $defaultValue;
}
else
{
$model=$model->$name;
}
}
elseif(is_array($model) && isset($model[$name]))
$model=$model[$name];
else
return $defaultValue;
}
else
return call_user_func($attribute,$model);
return $model;
}
public static function getIdByName($name)
{
return str_replace(array('[]','][','[',']',' '),array('','_','_','','_'),$name);
}
public static function activeId($model,$attribute)
{
return self::getIdByName(self::activeName($model,$attribute));
}
public static function modelName($model)
{
if(is_callable(self::$_modelNameConverter))
return call_user_func(self::$_modelNameConverter,$model);
$className=is_object($model) ? get_class($model) : (string)$model;
return trim(str_replace('\\','_',$className),'_');
}
public static function setModelNameConverter($converter)
{
if(is_callable($converter))
self::$_modelNameConverter=$converter;
elseif($converter===null)
self::$_modelNameConverter=null;
else
throw new CException(Yii::t('yii','The $converter argument must be a valid callback or null.'));
}
public static function activeName($model,$attribute)
{
$a=$attribute; // because the attribute name may be changed by resolveName
return self::resolveName($model,$a);
}
protected static function activeInputField($type,$model,$attribute,$htmlOptions)
{
$htmlOptions['type']=$type;
if($type==='text'||$type==='password'||$type==='color'||$type==='date'||$type==='datetime'||
$type==='datetime-local'||$type==='email'||$type==='month'||$type==='number'||$type==='range'||
$type==='search'||$type==='tel'||$type==='time'||$type==='url'||$type==='week')
{
if(!isset($htmlOptions['maxlength']))
{
foreach($model->getValidators($attribute) as $validator)
{
if($validator instanceof CStringValidator && $validator->max!==null)
{
$htmlOptions['maxlength']=$validator->max;
break;
}
}
}
elseif($htmlOptions['maxlength']===false)
unset($htmlOptions['maxlength']);
}
if($type==='file')
unset($htmlOptions['value']);
elseif(!isset($htmlOptions['value']))
$htmlOptions['value']=self::resolveValue($model,$attribute);
if($model->hasErrors($attribute))
self::addErrorCss($htmlOptions);
return self::tag('input',$htmlOptions);
}
public static function listOptions($selection,$listData,&$htmlOptions)
{
$raw=isset($htmlOptions['encode']) && !$htmlOptions['encode'];
$content='';
if(isset($htmlOptions['prompt']))
{
$content.='\n";
unset($htmlOptions['prompt']);
}
if(isset($htmlOptions['empty']))
{
if(!is_array($htmlOptions['empty']))
$htmlOptions['empty']=array(''=>$htmlOptions['empty']);
foreach($htmlOptions['empty'] as $value=>$label)
$content.='\n";
unset($htmlOptions['empty']);
}
if(isset($htmlOptions['options']))
{
$options=$htmlOptions['options'];
unset($htmlOptions['options']);
}
else
$options=array();
$key=isset($htmlOptions['key']) ? $htmlOptions['key'] : 'primaryKey';
if(is_array($selection))
{
foreach($selection as $i=>$item)
{
if(is_object($item))
$selection[$i]=$item->$key;
}
}
elseif(is_object($selection))
$selection=$selection->$key;
foreach($listData as $key=>$value)
{
if(is_array($value))
{
$content.=''."\n";
}
else
{
$attributes=array('value'=>(string)$key,'encode'=>!$raw);
if(!is_array($selection) && !strcmp($key,$selection) || is_array($selection) && in_array($key,$selection))
$attributes['selected']='selected';
if(isset($options[$key]))
$attributes=array_merge($attributes,$options[$key]);
$content.=self::tag('option',$attributes,$raw?(string)$value : self::encode((string)$value))."\n";
}
}
unset($htmlOptions['key']);
return $content;
}
protected static function clientChange($event,&$htmlOptions)
{
if(!isset($htmlOptions['submit']) && !isset($htmlOptions['confirm']) && !isset($htmlOptions['ajax']))
return;
if(isset($htmlOptions['live']))
{
$live=$htmlOptions['live'];
unset($htmlOptions['live']);
}
else
$live = self::$liveEvents;
if(isset($htmlOptions['return']) && $htmlOptions['return'])
$return='return true';
else
$return='return false';
if(isset($htmlOptions['on'.$event]))
{
$handler=trim($htmlOptions['on'.$event],';').';';
unset($htmlOptions['on'.$event]);
}
else
$handler='';
if(isset($htmlOptions['id']))
$id=$htmlOptions['id'];
else
$id=$htmlOptions['id']=isset($htmlOptions['name'])?$htmlOptions['name']:self::ID_PREFIX.self::$count++;
$cs=Yii::app()->getClientScript();
$cs->registerCoreScript('jquery');
if(isset($htmlOptions['submit']))
{
$cs->registerCoreScript('yii');
$request=Yii::app()->getRequest();
if($request->enableCsrfValidation && isset($htmlOptions['csrf']) && $htmlOptions['csrf'])
$htmlOptions['params'][$request->csrfTokenName]=$request->getCsrfToken();
if(isset($htmlOptions['params']))
$params=CJavaScript::encode($htmlOptions['params']);
else
$params='{}';
if($htmlOptions['submit']!=='')
$url=CJavaScript::quote(self::normalizeUrl($htmlOptions['submit']));
else
$url='';
$handler.="jQuery.yii.submitForm(this,'$url',$params);{$return};";
}
if(isset($htmlOptions['ajax']))
$handler.=self::ajax($htmlOptions['ajax'])."{$return};";
if(isset($htmlOptions['confirm']))
{
$confirm='confirm(\''.CJavaScript::quote($htmlOptions['confirm']).'\')';
if($handler!=='')
$handler="if($confirm) {".$handler."} else return false;";
else
$handler="return $confirm;";
}
if($live)
$cs->registerScript('Yii.CHtml.#' . $id,"jQuery('body').on('$event','#$id',function(){{$handler}});");
else
$cs->registerScript('Yii.CHtml.#' . $id,"jQuery('#$id').on('$event', function(){{$handler}});");
unset($htmlOptions['params'],$htmlOptions['submit'],$htmlOptions['ajax'],$htmlOptions['confirm'],$htmlOptions['return'],$htmlOptions['csrf']);
}
public static function resolveNameID($model,&$attribute,&$htmlOptions)
{
if(!isset($htmlOptions['name']))
$htmlOptions['name']=self::resolveName($model,$attribute);
if(!isset($htmlOptions['id']))
$htmlOptions['id']=self::getIdByName($htmlOptions['name']);
elseif($htmlOptions['id']===false)
unset($htmlOptions['id']);
}
public static function resolveName($model,&$attribute)
{
$modelName=self::modelName($model);
if(($pos=strpos($attribute,'['))!==false)
{
if($pos!==0) // e.g. name[a][b]
return $modelName.'['.substr($attribute,0,$pos).']'.substr($attribute,$pos);
if(($pos=strrpos($attribute,']'))!==false && $pos!==strlen($attribute)-1) // e.g. [a][b]name
{
$sub=substr($attribute,0,$pos+1);
$attribute=substr($attribute,$pos+1);
return $modelName.$sub.'['.$attribute.']';
}
if(preg_match('/\](\w+\[.*)$/',$attribute,$matches))
{
$name=$modelName.'['.str_replace(']','][',trim(strtr($attribute,array(']['=>']','['=>']')),']')).']';
$attribute=$matches[1];
return $name;
}
}
return $modelName.'['.$attribute.']';
}
public static function resolveValue($model,$attribute)
{
if(($pos=strpos($attribute,'['))!==false)
{
if($pos===0) // [a]name[b][c], should ignore [a]
{
if(preg_match('/\](\w+(\[.+)?)/',$attribute,$matches))
$attribute=$matches[1]; // we get: name[b][c]
if(($pos=strpos($attribute,'['))===false)
return $model->$attribute;
}
$name=substr($attribute,0,$pos);
$value=$model->$name;
foreach(explode('][',rtrim(substr($attribute,$pos+1),']')) as $id)
{
if((is_array($value) || $value instanceof ArrayAccess) && isset($value[$id]))
$value=$value[$id];
else
return null;
}
return $value;
}
else
return $model->$attribute;
}
protected static function addErrorCss(&$htmlOptions)
{
if(empty(self::$errorCss))
return;
if(isset($htmlOptions['class']))
$htmlOptions['class'].=' '.self::$errorCss;
else
$htmlOptions['class']=self::$errorCss;
}
public static function renderAttributes($htmlOptions)
{
static $specialAttributes=array(
'autofocus'=>1,
'autoplay'=>1,
'async'=>1,
'checked'=>1,
'controls'=>1,
'declare'=>1,
'default'=>1,
'defer'=>1,
'disabled'=>1,
'formnovalidate'=>1,
'hidden'=>1,
'ismap'=>1,
'itemscope'=>1,
'loop'=>1,
'multiple'=>1,
'muted'=>1,
'nohref'=>1,
'noresize'=>1,
'novalidate'=>1,
'open'=>1,
'readonly'=>1,
'required'=>1,
'reversed'=>1,
'scoped'=>1,
'seamless'=>1,
'selected'=>1,
'typemustmatch'=>1,
);
if($htmlOptions===array())
return '';
$html='';
if(isset($htmlOptions['encode']))
{
$raw=!$htmlOptions['encode'];
unset($htmlOptions['encode']);
}
else
$raw=false;
foreach($htmlOptions as $name=>$value)
{
if(isset($specialAttributes[$name]))
{
if($value===false && $name==='async') {
$html .= ' ' . $name.'="false"';
}
elseif($value)
{
$html .= ' ' . $name;
if(self::$renderSpecialAttributesValue)
$html .= '="' . $name . '"';
}
}
elseif($value!==null)
$html .= ' ' . $name . '="' . ($raw ? $value : self::encode($value)) . '"';
}
return $html;
}
}
class CWidgetFactory extends CApplicationComponent implements IWidgetFactory
{
public $enableSkin=false;
public $widgets=array();
public $skinnableWidgets;
public $skinPath;
private $_skins=array(); // class name, skin name, property name => value
public function init()
{
parent::init();
if($this->enableSkin && $this->skinPath===null)
$this->skinPath=Yii::app()->getViewPath().DIRECTORY_SEPARATOR.'skins';
}
public function createWidget($owner,$className,$properties=array())
{
$className=Yii::import($className,true);
$widget=new $className($owner);
if(isset($this->widgets[$className]))
$properties=$properties===array() ? $this->widgets[$className] : CMap::mergeArray($this->widgets[$className],$properties);
if($this->enableSkin)
{
if($this->skinnableWidgets===null || in_array($className,$this->skinnableWidgets))
{
$skinName=isset($properties['skin']) ? $properties['skin'] : 'default';
if($skinName!==false && ($skin=$this->getSkin($className,$skinName))!==array())
$properties=$properties===array() ? $skin : CMap::mergeArray($skin,$properties);
}
}
foreach($properties as $name=>$value)
$widget->$name=$value;
return $widget;
}
protected function getSkin($className,$skinName)
{
if(!isset($this->_skins[$className][$skinName]))
{
$skinFile=$this->skinPath.DIRECTORY_SEPARATOR.$className.'.php';
if(is_file($skinFile))
$this->_skins[$className]=require($skinFile);
else
$this->_skins[$className]=array();
if(($theme=Yii::app()->getTheme())!==null)
{
$skinFile=$theme->getSkinPath().DIRECTORY_SEPARATOR.$className.'.php';
if(is_file($skinFile))
{
$skins=require($skinFile);
foreach($skins as $name=>$skin)
$this->_skins[$className][$name]=$skin;
}
}
if(!isset($this->_skins[$className][$skinName]))
$this->_skins[$className][$skinName]=array();
}
return $this->_skins[$className][$skinName];
}
}
class CWidget extends CBaseController
{
public $actionPrefix;
public $skin='default';
private static $_viewPaths;
private static $_counter=0;
private $_id;
private $_owner;
public static function actions()
{
return array();
}
public function __construct($owner=null)
{
$this->_owner=$owner===null?Yii::app()->getController():$owner;
}
public function getOwner()
{
return $this->_owner;
}
public function getId($autoGenerate=true)
{
if($this->_id!==null)
return $this->_id;
elseif($autoGenerate)
return $this->_id='yw'.self::$_counter++;
}
public function setId($value)
{
$this->_id=$value;
}
public function getController()
{
if($this->_owner instanceof CController)
return $this->_owner;
else
return Yii::app()->getController();
}
public function init()
{
}
public function run()
{
}
public function getViewPath($checkTheme=false)
{
$className=get_class($this);
$scope=$checkTheme?'theme':'local';
if(isset(self::$_viewPaths[$className][$scope]))
return self::$_viewPaths[$className][$scope];
else
{
if($checkTheme && ($theme=Yii::app()->getTheme())!==null)
{
$path=$theme->getViewPath().DIRECTORY_SEPARATOR;
if(strpos($className,'\\')!==false) // namespaced class
$path.=str_replace('\\','_',ltrim($className,'\\'));
else
$path.=$className;
if(is_dir($path))
return self::$_viewPaths[$className]['theme']=$path;
}
$class=new ReflectionClass($className);
return self::$_viewPaths[$className]['local']=dirname($class->getFileName()).DIRECTORY_SEPARATOR.'views';
}
}
public function getViewFile($viewName)
{
if(($renderer=Yii::app()->getViewRenderer())!==null)
$extension=$renderer->fileExtension;
else
$extension='.php';
if(strpos($viewName,'.')) // a path alias
$viewFile=Yii::getPathOfAlias($viewName);
else
{
$viewFile=$this->getViewPath(true).DIRECTORY_SEPARATOR.$viewName;
if(is_file($viewFile.$extension))
return Yii::app()->findLocalizedFile($viewFile.$extension);
elseif($extension!=='.php' && is_file($viewFile.'.php'))
return Yii::app()->findLocalizedFile($viewFile.'.php');
$viewFile=$this->getViewPath(false).DIRECTORY_SEPARATOR.$viewName;
}
if(is_file($viewFile.$extension))
return Yii::app()->findLocalizedFile($viewFile.$extension);
elseif($extension!=='.php' && is_file($viewFile.'.php'))
return Yii::app()->findLocalizedFile($viewFile.'.php');
else
return false;
}
public function render($view,$data=null,$return=false)
{
if(($viewFile=$this->getViewFile($view))!==false)
return $this->renderFile($viewFile,$data,$return);
else
throw new CException(Yii::t('yii','{widget} cannot find the view "{view}".',
array('{widget}'=>get_class($this), '{view}'=>$view)));
}
}
class CClientScript extends CApplicationComponent
{
const POS_HEAD=0;
const POS_BEGIN=1;
const POS_END=2;
const POS_LOAD=3;
const POS_READY=4;
public $enableJavaScript=true;
public $scriptMap=array();
public $packages=array();
public $corePackages;
public $scripts=array();
protected $cssFiles=array();
protected $scriptFiles=array();
protected $metaTags=array();
protected $linkTags=array();
protected $css=array();
protected $hasScripts=false;
protected $coreScripts=array();
public $coreScriptPosition=self::POS_HEAD;
public $defaultScriptFilePosition=self::POS_HEAD;
public $defaultScriptPosition=self::POS_READY;
private $_baseUrl;
public function reset()
{
$this->hasScripts=false;
$this->coreScripts=array();
$this->cssFiles=array();
$this->css=array();
$this->scriptFiles=array();
$this->scripts=array();
$this->metaTags=array();
$this->linkTags=array();
$this->recordCachingAction('clientScript','reset',array());
}
public function render(&$output)
{
if(!$this->hasScripts)
return;
$this->renderCoreScripts();
if(!empty($this->scriptMap))
$this->remapScripts();
$this->unifyScripts();
$this->renderHead($output);
if($this->enableJavaScript)
{
$this->renderBodyBegin($output);
$this->renderBodyEnd($output);
}
}
protected function unifyScripts()
{
if(!$this->enableJavaScript)
return;
$map=array();
if(isset($this->scriptFiles[self::POS_HEAD]))
$map=$this->scriptFiles[self::POS_HEAD];
if(isset($this->scriptFiles[self::POS_BEGIN]))
{
foreach($this->scriptFiles[self::POS_BEGIN] as $scriptFile=>$scriptFileValue)
{
if(isset($map[$scriptFile]))
unset($this->scriptFiles[self::POS_BEGIN][$scriptFile]);
else
$map[$scriptFile]=true;
}
}
if(isset($this->scriptFiles[self::POS_END]))
{
foreach($this->scriptFiles[self::POS_END] as $key=>$scriptFile)
{
if(isset($map[$key]))
unset($this->scriptFiles[self::POS_END][$key]);
}
}
}
protected function remapScripts()
{
$cssFiles=array();
foreach($this->cssFiles as $url=>$media)
{
$name=basename($url);
if(isset($this->scriptMap[$name]))
{
if($this->scriptMap[$name]!==false)
$cssFiles[$this->scriptMap[$name]]=$media;
}
elseif(isset($this->scriptMap['*.css']))
{
if($this->scriptMap['*.css']!==false)
$cssFiles[$this->scriptMap['*.css']]=$media;
}
else
$cssFiles[$url]=$media;
}
$this->cssFiles=$cssFiles;
$jsFiles=array();
foreach($this->scriptFiles as $position=>$scriptFiles)
{
$jsFiles[$position]=array();
foreach($scriptFiles as $scriptFile=>$scriptFileValue)
{
$name=basename($scriptFile);
if(isset($this->scriptMap[$name]))
{
if($this->scriptMap[$name]!==false)
$jsFiles[$position][$this->scriptMap[$name]]=$this->scriptMap[$name];
}
elseif(isset($this->scriptMap['*.js']))
{
if($this->scriptMap['*.js']!==false)
$jsFiles[$position][$this->scriptMap['*.js']]=$this->scriptMap['*.js'];
}
else
$jsFiles[$position][$scriptFile]=$scriptFileValue;
}
}
$this->scriptFiles=$jsFiles;
}
protected function renderScriptBatch(array $scripts)
{
$html = '';
$scriptBatches = array();
foreach($scripts as $scriptValue)
{
if(is_array($scriptValue))
{
$scriptContent = $scriptValue['content'];
unset($scriptValue['content']);
$scriptHtmlOptions = $scriptValue;
ksort($scriptHtmlOptions);
}
else
{
$scriptContent = $scriptValue;
$scriptHtmlOptions = array();
}
$key=serialize($scriptHtmlOptions);
$scriptBatches[$key]['htmlOptions']=$scriptHtmlOptions;
$scriptBatches[$key]['scripts'][]=$scriptContent;
}
foreach($scriptBatches as $scriptBatch)
if(!empty($scriptBatch['scripts']))
$html.=CHtml::script(implode("\n",$scriptBatch['scripts']),$scriptBatch['htmlOptions'])."\n";
return $html;
}
public function renderCoreScripts()
{
if($this->coreScripts===null)
return;
$cssFiles=array();
$jsFiles=array();
foreach($this->coreScripts as $name=>$package)
{
$baseUrl=$this->getPackageBaseUrl($name);
if(!empty($package['js']))
{
foreach($package['js'] as $js)
$jsFiles[$baseUrl.'/'.$js]=$baseUrl.'/'.$js;
}
if(!empty($package['css']))
{
foreach($package['css'] as $css)
$cssFiles[$baseUrl.'/'.$css]='';
}
}
// merge in place
if($cssFiles!==array())
{
foreach($this->cssFiles as $cssFile=>$media)
$cssFiles[$cssFile]=$media;
$this->cssFiles=$cssFiles;
}
if($jsFiles!==array())
{
if(isset($this->scriptFiles[$this->coreScriptPosition]))
{
foreach($this->scriptFiles[$this->coreScriptPosition] as $url => $value)
$jsFiles[$url]=$value;
}
$this->scriptFiles[$this->coreScriptPosition]=$jsFiles;
}
}
public function renderHead(&$output)
{
$html='';
foreach($this->metaTags as $meta)
$html.=CHtml::metaTag($meta['content'],null,null,$meta)."\n";
foreach($this->linkTags as $link)
$html.=CHtml::linkTag(null,null,null,null,$link)."\n";
foreach($this->cssFiles as $url=>$media)
$html.=CHtml::cssFile($url,$media)."\n";
foreach($this->css as $css)
$html.=CHtml::css($css[0],$css[1])."\n";
if($this->enableJavaScript)
{
if(isset($this->scriptFiles[self::POS_HEAD]))
{
foreach($this->scriptFiles[self::POS_HEAD] as $scriptFileValueUrl=>$scriptFileValue)
{
if(is_array($scriptFileValue))
$html.=CHtml::scriptFile($scriptFileValueUrl,$scriptFileValue)."\n";
else
$html.=CHtml::scriptFile($scriptFileValueUrl)."\n";
}
}
if(isset($this->scripts[self::POS_HEAD]))
$html.=$this->renderScriptBatch($this->scripts[self::POS_HEAD]);
}
if($html!=='')
{
$count=0;
$output=preg_replace('/(]*>|<\\/head\s*>)/is','<###head###>$1',$output,1,$count);
if($count)
$output=str_replace('<###head###>',$html,$output);
else
$output=$html.$output;
}
}
public function renderBodyBegin(&$output)
{
$html='';
if(isset($this->scriptFiles[self::POS_BEGIN]))
{
foreach($this->scriptFiles[self::POS_BEGIN] as $scriptFileUrl=>$scriptFileValue)
{
if(is_array($scriptFileValue))
$html.=CHtml::scriptFile($scriptFileUrl,$scriptFileValue)."\n";
else
$html.=CHtml::scriptFile($scriptFileUrl)."\n";
}
}
if(isset($this->scripts[self::POS_BEGIN]))
$html.=$this->renderScriptBatch($this->scripts[self::POS_BEGIN]);
if($html!=='')
{
$count=0;
$output=preg_replace('/(]*>)/is','$1<###begin###>',$output,1,$count);
if($count)
$output=str_replace('<###begin###>',$html,$output);
else
$output=$html.$output;
}
}
public function renderBodyEnd(&$output)
{
if(!isset($this->scriptFiles[self::POS_END]) && !isset($this->scripts[self::POS_END])
&& !isset($this->scripts[self::POS_READY]) && !isset($this->scripts[self::POS_LOAD]))
return;
$fullPage=0;
$output=preg_replace('/(<\\/body\s*>)/is','<###end###>$1',$output,1,$fullPage);
$html='';
if(isset($this->scriptFiles[self::POS_END]))
{
foreach($this->scriptFiles[self::POS_END] as $scriptFileUrl=>$scriptFileValue)
{
if(is_array($scriptFileValue))
$html.=CHtml::scriptFile($scriptFileUrl,$scriptFileValue)."\n";
else
$html.=CHtml::scriptFile($scriptFileUrl)."\n";
}
}
$scripts=isset($this->scripts[self::POS_END]) ? $this->scripts[self::POS_END] : array();
if(isset($this->scripts[self::POS_READY]))
{
if($fullPage)
$scripts[]="jQuery(function($) {\n".implode("\n",$this->scripts[self::POS_READY])."\n});";
else
$scripts[]=implode("\n",$this->scripts[self::POS_READY]);
}
if(isset($this->scripts[self::POS_LOAD]))
{
if($fullPage)
$scripts[]="jQuery(window).on('load',function() {\n".implode("\n",$this->scripts[self::POS_LOAD])."\n});";
else
$scripts[]=implode("\n",$this->scripts[self::POS_LOAD]);
}
if(!empty($scripts))
$html.=$this->renderScriptBatch($scripts);
if($fullPage)
$output=str_replace('<###end###>',$html,$output);
else
$output=$output.$html;
}
public function getCoreScriptUrl()
{
if($this->_baseUrl!==null)
return $this->_baseUrl;
else
return $this->_baseUrl=Yii::app()->getAssetManager()->publish(YII_PATH.'/web/js/source');
}
public function setCoreScriptUrl($value)
{
$this->_baseUrl=$value;
}
public function getPackageBaseUrl($name)
{
if(!isset($this->coreScripts[$name]))
return false;
$package=$this->coreScripts[$name];
if(isset($package['baseUrl']))
{
$baseUrl=$package['baseUrl'];
if($baseUrl==='' || $baseUrl[0]!=='/' && strpos($baseUrl,'://')===false)
$baseUrl=Yii::app()->getRequest()->getBaseUrl().'/'.$baseUrl;
$baseUrl=rtrim($baseUrl,'/');
}
elseif(isset($package['basePath']))
$baseUrl=Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias($package['basePath']));
else
$baseUrl=$this->getCoreScriptUrl();
return $this->coreScripts[$name]['baseUrl']=$baseUrl;
}
public function hasPackage($name)
{
if(isset($this->coreScripts[$name]))
return true;
if(isset($this->packages[$name]))
return true;
else
{
if($this->corePackages===null)
$this->corePackages=require(YII_PATH.'/web/js/packages.php');
if(isset($this->corePackages[$name]))
return true;
}
return false;
}
public function registerPackage($name)
{
return $this->registerCoreScript($name);
}
public function registerCoreScript($name)
{
if(isset($this->coreScripts[$name]))
return $this;
if(isset($this->packages[$name]))
$package=$this->packages[$name];
else
{
if($this->corePackages===null)
$this->corePackages=require(YII_PATH.'/web/js/packages.php');
if(isset($this->corePackages[$name]))
$package=$this->corePackages[$name];
}
if(isset($package))
{
if(!empty($package['depends']))
{
foreach($package['depends'] as $p)
$this->registerCoreScript($p);
}
$this->coreScripts[$name]=$package;
$this->hasScripts=true;
$params=func_get_args();
$this->recordCachingAction('clientScript','registerCoreScript',$params);
}
elseif(YII_DEBUG)
throw new CException('There is no CClientScript package: '.$name);
else
Yii::log('There is no CClientScript package: '.$name,CLogger::LEVEL_WARNING,'system.web.CClientScript');
return $this;
}
public function registerCssFile($url,$media='')
{
$this->hasScripts=true;
$this->cssFiles[$url]=$media;
$params=func_get_args();
$this->recordCachingAction('clientScript','registerCssFile',$params);
return $this;
}
public function registerCss($id,$css,$media='')
{
$this->hasScripts=true;
$this->css[$id]=array($css,$media);
$params=func_get_args();
$this->recordCachingAction('clientScript','registerCss',$params);
return $this;
}
public function registerScriptFile($url,$position=null,array $htmlOptions=array())
{
$params=func_get_args();
if($position===null)
$position=$this->defaultScriptFilePosition;
$this->hasScripts=true;
if(empty($htmlOptions))
$value=$url;
else
{
$value=$htmlOptions;
$value['src']=$url;
}
$this->scriptFiles[$position][$url]=$value;
$this->recordCachingAction('clientScript','registerScriptFile',$params);
return $this;
}
public function registerScript($id,$script,$position=null,array $htmlOptions=array())
{
$params=func_get_args();
if($position===null)
$position=$this->defaultScriptPosition;
$this->hasScripts=true;
if(empty($htmlOptions))
$scriptValue=$script;
else
{
if($position==self::POS_LOAD || $position==self::POS_READY)
throw new CException(Yii::t('yii','Script HTML options are not allowed for "CClientScript::POS_LOAD" and "CClientScript::POS_READY".'));
$scriptValue=$htmlOptions;
$scriptValue['content']=$script;
}
$this->scripts[$position][$id]=$scriptValue;
if($position===self::POS_READY || $position===self::POS_LOAD)
$this->registerCoreScript('jquery');
$this->recordCachingAction('clientScript','registerScript',$params);
return $this;
}
public function registerMetaTag($content,$name=null,$httpEquiv=null,$options=array(),$id=null)
{
$params=func_get_args();
$this->hasScripts=true;
if($name!==null)
$options['name']=$name;
if($httpEquiv!==null)
$options['http-equiv']=$httpEquiv;
$options['content']=$content;
$this->metaTags[null===$id?count($this->metaTags):$id]=$options;
$this->recordCachingAction('clientScript','registerMetaTag',$params);
return $this;
}
public function registerLinkTag($relation=null,$type=null,$href=null,$media=null,$options=array())
{
$params=func_get_args();
$this->hasScripts=true;
if($relation!==null)
$options['rel']=$relation;
if($type!==null)
$options['type']=$type;
if($href!==null)
$options['href']=$href;
if($media!==null)
$options['media']=$media;
$this->linkTags[serialize($options)]=$options;
$this->recordCachingAction('clientScript','registerLinkTag',$params);
return $this;
}
public function isCssFileRegistered($url)
{
return isset($this->cssFiles[$url]);
}
public function isCssRegistered($id)
{
return isset($this->css[$id]);
}
public function isScriptFileRegistered($url,$position=self::POS_HEAD)
{
return isset($this->scriptFiles[$position][$url]);
}
public function isScriptRegistered($id,$position=self::POS_READY)
{
return isset($this->scripts[$position][$id]);
}
protected function recordCachingAction($context,$method,$params)
{
if(($controller=Yii::app()->getController())!==null)
$controller->recordCachingAction($context,$method,$params);
}
public function addPackage($name,$definition)
{
$this->packages[$name]=$definition;
return $this;
}
}
class CList extends CComponent implements IteratorAggregate,ArrayAccess,Countable
{
private $_d=array();
private $_c=0;
private $_r=false;
public function __construct($data=null,$readOnly=false)
{
if($data!==null)
$this->copyFrom($data);
$this->setReadOnly($readOnly);
}
public function getReadOnly()
{
return $this->_r;
}
protected function setReadOnly($value)
{
$this->_r=$value;
}
public function getIterator()
{
return new CListIterator($this->_d);
}
public function count()
{
return $this->getCount();
}
public function getCount()
{
return $this->_c;
}
public function itemAt($index)
{
if(isset($this->_d[$index]))
return $this->_d[$index];
elseif($index>=0 && $index<$this->_c) // in case the value is null
return $this->_d[$index];
else
throw new CException(Yii::t('yii','List index "{index}" is out of bound.',
array('{index}'=>$index)));
}
public function add($item)
{
$this->insertAt($this->_c,$item);
return $this->_c-1;
}
public function insertAt($index,$item)
{
if(!$this->_r)
{
if($index===$this->_c)
$this->_d[$this->_c++]=$item;
elseif($index>=0 && $index<$this->_c)
{
array_splice($this->_d,$index,0,array($item));
$this->_c++;
}
else
throw new CException(Yii::t('yii','List index "{index}" is out of bound.',
array('{index}'=>$index)));
}
else
throw new CException(Yii::t('yii','The list is read only.'));
}
public function remove($item)
{
if(($index=$this->indexOf($item))>=0)
{
$this->removeAt($index);
return $index;
}
else
return false;
}
public function removeAt($index)
{
if(!$this->_r)
{
if($index>=0 && $index<$this->_c)
{
$this->_c--;
if($index===$this->_c)
return array_pop($this->_d);
else
{
$item=$this->_d[$index];
array_splice($this->_d,$index,1);
return $item;
}
}
else
throw new CException(Yii::t('yii','List index "{index}" is out of bound.',
array('{index}'=>$index)));
}
else
throw new CException(Yii::t('yii','The list is read only.'));
}
public function clear()
{
for($i=$this->_c-1;$i>=0;--$i)
$this->removeAt($i);
}
public function contains($item)
{
return $this->indexOf($item)>=0;
}
public function indexOf($item)
{
if(($index=array_search($item,$this->_d,true))!==false)
return $index;
else
return -1;
}
public function toArray()
{
return $this->_d;
}
public function copyFrom($data)
{
if(is_array($data) || ($data instanceof Traversable))
{
if($this->_c>0)
$this->clear();
if($data instanceof CList)
$data=$data->_d;
foreach($data as $item)
$this->add($item);
}
elseif($data!==null)
throw new CException(Yii::t('yii','List data must be an array or an object implementing Traversable.'));
}
public function mergeWith($data)
{
if(is_array($data) || ($data instanceof Traversable))
{
if($data instanceof CList)
$data=$data->_d;
foreach($data as $item)
$this->add($item);
}
elseif($data!==null)
throw new CException(Yii::t('yii','List data must be an array or an object implementing Traversable.'));
}
public function offsetExists($offset)
{
return ($offset>=0 && $offset<$this->_c);
}
public function offsetGet($offset)
{
return $this->itemAt($offset);
}
public function offsetSet($offset,$item)
{
if($offset===null || $offset===$this->_c)
$this->insertAt($this->_c,$item);
else
{
$this->removeAt($offset);
$this->insertAt($offset,$item);
}
}
public function offsetUnset($offset)
{
$this->removeAt($offset);
}
}
class CFilterChain extends CList
{
public $controller;
public $action;
public $filterIndex=0;
public function __construct($controller,$action)
{
$this->controller=$controller;
$this->action=$action;
}
public static function create($controller,$action,$filters)
{
$chain=new CFilterChain($controller,$action);
$actionID=$action->getId();
foreach($filters as $filter)
{
if(is_string($filter)) // filterName [+|- action1 action2]
{
if(($pos=strpos($filter,'+'))!==false || ($pos=strpos($filter,'-'))!==false)
{
$matched=preg_match("/\b{$actionID}\b/i",substr($filter,$pos+1))>0;
if(($filter[$pos]==='+')===$matched)
$filter=CInlineFilter::create($controller,trim(substr($filter,0,$pos)));
}
else
$filter=CInlineFilter::create($controller,$filter);
}
elseif(is_array($filter)) // array('path.to.class [+|- action1, action2]','param1'=>'value1',...)
{
if(!isset($filter[0]))
throw new CException(Yii::t('yii','The first element in a filter configuration must be the filter class.'));
$filterClass=$filter[0];
unset($filter[0]);
if(($pos=strpos($filterClass,'+'))!==false || ($pos=strpos($filterClass,'-'))!==false)
{
$matched=preg_match("/\b{$actionID}\b/i",substr($filterClass,$pos+1))>0;
if(($filterClass[$pos]==='+')===$matched)
$filterClass=trim(substr($filterClass,0,$pos));
else
continue;
}
$filter['class']=$filterClass;
$filter=Yii::createComponent($filter);
}
if(is_object($filter))
{
$filter->init();
$chain->add($filter);
}
}
return $chain;
}
public function insertAt($index,$item)
{
if($item instanceof IFilter)
parent::insertAt($index,$item);
else
throw new CException(Yii::t('yii','CFilterChain can only take objects implementing the IFilter interface.'));
}
public function run()
{
if($this->offsetExists($this->filterIndex))
{
$filter=$this->itemAt($this->filterIndex++);
$filter->filter($this);
}
else
$this->controller->runAction($this->action);
}
}
class CFilter extends CComponent implements IFilter
{
public function filter($filterChain)
{
if($this->preFilter($filterChain))
{
$filterChain->run();
$this->postFilter($filterChain);
}
}
public function init()
{
}
protected function preFilter($filterChain)
{
return true;
}
protected function postFilter($filterChain)
{
}
}
class CInlineFilter extends CFilter
{
public $name;
public static function create($controller,$filterName)
{
if(method_exists($controller,'filter'.$filterName))
{
$filter=new CInlineFilter;
$filter->name=$filterName;
return $filter;
}
else
throw new CException(Yii::t('yii','Filter "{filter}" is invalid. Controller "{class}" does not have the filter method "filter{filter}".',
array('{filter}'=>$filterName, '{class}'=>get_class($controller))));
}
public function filter($filterChain)
{
$method='filter'.$this->name;
$filterChain->controller->$method($filterChain);
}
}
class CAccessControlFilter extends CFilter
{
public $message;
private $_rules=array();
public function getRules()
{
return $this->_rules;
}
public function setRules($rules)
{
foreach($rules as $rule)
{
if(is_array($rule) && isset($rule[0]))
{
$r=new CAccessRule;
$r->allow=$rule[0]==='allow';
foreach(array_slice($rule,1) as $name=>$value)
{
if($name==='expression' || $name==='roles' || $name==='message' || $name==='deniedCallback')
$r->$name=$value;
else
$r->$name=array_map('strtolower',$value);
}
$this->_rules[]=$r;
}
}
}
protected function preFilter($filterChain)
{
$app=Yii::app();
$request=$app->getRequest();
$user=$app->getUser();
$verb=$request->getRequestType();
$ip=$request->getUserHostAddress();
foreach($this->getRules() as $rule)
{
if(($allow=$rule->isUserAllowed($user,$filterChain->controller,$filterChain->action,$ip,$verb))>0) // allowed
break;
elseif($allow<0) // denied
{
if(isset($rule->deniedCallback))
call_user_func($rule->deniedCallback, $rule);
else
$this->accessDenied($user,$this->resolveErrorMessage($rule));
return false;
}
}
return true;
}
protected function resolveErrorMessage($rule)
{
if($rule->message!==null)
return $rule->message;
elseif($this->message!==null)
return $this->message;
else
return Yii::t('yii','You are not authorized to perform this action.');
}
protected function accessDenied($user,$message)
{
if($user->getIsGuest())
$user->loginRequired();
else
throw new CHttpException(403,$message);
}
}
class CAccessRule extends CComponent
{
public $allow;
public $actions;
public $controllers;
public $users;
public $roles;
public $ips;
public $verbs;
public $expression;
public $message;
public $deniedCallback;
public function isUserAllowed($user,$controller,$action,$ip,$verb)
{
if($this->isActionMatched($action)
&& $this->isUserMatched($user)
&& $this->isRoleMatched($user)
&& $this->isIpMatched($ip)
&& $this->isVerbMatched($verb)
&& $this->isControllerMatched($controller)
&& $this->isExpressionMatched($user))
return $this->allow ? 1 : -1;
else
return 0;
}
protected function isActionMatched($action)
{
return empty($this->actions) || in_array(strtolower($action->getId()),$this->actions);
}
protected function isControllerMatched($controller)
{
return empty($this->controllers) || in_array(strtolower($controller->getUniqueId()),$this->controllers);
}
protected function isUserMatched($user)
{
if(empty($this->users))
return true;
foreach($this->users as $u)
{
if($u==='*')
return true;
elseif($u==='?' && $user->getIsGuest())
return true;
elseif($u==='@' && !$user->getIsGuest())
return true;
elseif(!strcasecmp($u,$user->getName()))
return true;
}
return false;
}
protected function isRoleMatched($user)
{
if(empty($this->roles))
return true;
foreach($this->roles as $key=>$role)
{
if(is_numeric($key))
{
if($user->checkAccess($role))
return true;
}
else
{
if($user->checkAccess($key,$role))
return true;
}
}
return false;
}
protected function isIpMatched($ip)
{
if(empty($this->ips))
return true;
foreach($this->ips as $rule)
{
if($rule==='*' || $rule===$ip || (($pos=strpos($rule,'*'))!==false && !strncmp($ip,$rule,$pos)))
return true;
}
return false;
}
protected function isVerbMatched($verb)
{
return empty($this->verbs) || in_array(strtolower($verb),$this->verbs);
}
protected function isExpressionMatched($user)
{
if($this->expression===null)
return true;
else
return $this->evaluateExpression($this->expression, array('user'=>$user));
}
}
abstract class CModel extends CComponent implements IteratorAggregate, ArrayAccess
{
private $_errors=array(); // attribute name => array of errors
private $_validators; // validators
private $_scenario=''; // scenario
abstract public function attributeNames();
public function rules()
{
return array();
}
public function behaviors()
{
return array();
}
public function attributeLabels()
{
return array();
}
public function validate($attributes=null, $clearErrors=true)
{
if($clearErrors)
$this->clearErrors();
if($this->beforeValidate())
{
foreach($this->getValidators() as $validator)
$validator->validate($this,$attributes);
$this->afterValidate();
return !$this->hasErrors();
}
else
return false;
}
protected function afterConstruct()
{
if($this->hasEventHandler('onAfterConstruct'))
$this->onAfterConstruct(new CEvent($this));
}
protected function beforeValidate()
{
$event=new CModelEvent($this);
$this->onBeforeValidate($event);
return $event->isValid;
}
protected function afterValidate()
{
$this->onAfterValidate(new CEvent($this));
}
public function onAfterConstruct($event)
{
$this->raiseEvent('onAfterConstruct',$event);
}
public function onBeforeValidate($event)
{
$this->raiseEvent('onBeforeValidate',$event);
}
public function onAfterValidate($event)
{
$this->raiseEvent('onAfterValidate',$event);
}
public function getValidatorList()
{
if($this->_validators===null)
$this->_validators=$this->createValidators();
return $this->_validators;
}
public function getValidators($attribute=null)
{
if($this->_validators===null)
$this->_validators=$this->createValidators();
$validators=array();
$scenario=$this->getScenario();
foreach($this->_validators as $validator)
{
if($validator->applyTo($scenario))
{
if($attribute===null || in_array($attribute,$validator->attributes,true))
$validators[]=$validator;
}
}
return $validators;
}
public function createValidators()
{
$validators=new CList;
foreach($this->rules() as $rule)
{
if(isset($rule[0],$rule[1])) // attributes, validator name
$validators->add(CValidator::createValidator($rule[1],$this,$rule[0],array_slice($rule,2)));
else
throw new CException(Yii::t('yii','{class} has an invalid validation rule. The rule must specify attributes to be validated and the validator name.',
array('{class}'=>get_class($this))));
}
return $validators;
}
public function isAttributeRequired($attribute)
{
foreach($this->getValidators($attribute) as $validator)
{
if($validator instanceof CRequiredValidator)
return true;
}
return false;
}
public function isAttributeSafe($attribute)
{
$attributes=$this->getSafeAttributeNames();
return in_array($attribute,$attributes);
}
public function getAttributeLabel($attribute)
{
$labels=$this->attributeLabels();
if(isset($labels[$attribute]))
return $labels[$attribute];
else
return $this->generateAttributeLabel($attribute);
}
public function hasErrors($attribute=null)
{
if($attribute===null)
return $this->_errors!==array();
else
return isset($this->_errors[$attribute]);
}
public function getErrors($attribute=null)
{
if($attribute===null)
return $this->_errors;
else
return isset($this->_errors[$attribute]) ? $this->_errors[$attribute] : array();
}
public function getError($attribute)
{
return isset($this->_errors[$attribute]) ? reset($this->_errors[$attribute]) : null;
}
public function addError($attribute,$error)
{
$this->_errors[$attribute][]=$error;
}
public function addErrors($errors)
{
foreach($errors as $attribute=>$error)
{
if(is_array($error))
{
foreach($error as $e)
$this->addError($attribute, $e);
}
else
$this->addError($attribute, $error);
}
}
public function clearErrors($attribute=null)
{
if($attribute===null)
$this->_errors=array();
else
unset($this->_errors[$attribute]);
}
public function generateAttributeLabel($name)
{
return ucwords(trim(strtolower(str_replace(array('-','_','.'),' ',preg_replace('/(?attributeNames() as $name)
$values[$name]=$this->$name;
if(is_array($names))
{
$values2=array();
foreach($names as $name)
$values2[$name]=isset($values[$name]) ? $values[$name] : null;
return $values2;
}
else
return $values;
}
public function setAttributes($values,$safeOnly=true)
{
if(!is_array($values))
return;
$attributes=array_flip($safeOnly ? $this->getSafeAttributeNames() : $this->attributeNames());
foreach($values as $name=>$value)
{
if(isset($attributes[$name]))
$this->$name=$value;
elseif($safeOnly)
$this->onUnsafeAttribute($name,$value);
}
}
public function unsetAttributes($names=null)
{
if($names===null)
$names=$this->attributeNames();
foreach($names as $name)
$this->$name=null;
}
public function onUnsafeAttribute($name,$value)
{
if(YII_DEBUG)
Yii::log(Yii::t('yii','Failed to set unsafe attribute "{attribute}" of "{class}".',array('{attribute}'=>$name, '{class}'=>get_class($this))),CLogger::LEVEL_WARNING);
}
public function getScenario()
{
return $this->_scenario;
}
public function setScenario($value)
{
$this->_scenario=$value;
}
public function getSafeAttributeNames()
{
$attributes=array();
$unsafe=array();
foreach($this->getValidators() as $validator)
{
if(!$validator->safe)
{
foreach($validator->attributes as $name)
$unsafe[]=$name;
}
else
{
foreach($validator->attributes as $name)
$attributes[$name]=true;
}
}
foreach($unsafe as $name)
unset($attributes[$name]);
return array_keys($attributes);
}
public function getIterator()
{
$attributes=$this->getAttributes();
return new CMapIterator($attributes);
}
public function offsetExists($offset)
{
return property_exists($this,$offset);
}
public function offsetGet($offset)
{
return $this->$offset;
}
public function offsetSet($offset,$item)
{
$this->$offset=$item;
}
public function offsetUnset($offset)
{
unset($this->$offset);
}
}
abstract class CActiveRecord extends CModel
{
const BELONGS_TO='CBelongsToRelation';
const HAS_ONE='CHasOneRelation';
const HAS_MANY='CHasManyRelation';
const MANY_MANY='CManyManyRelation';
const STAT='CStatRelation';
public static $db;
private static $_models=array(); // class name => model
private static $_md=array(); // class name => meta data
private $_new=false; // whether this instance is new or not
private $_attributes=array(); // attribute name => attribute value
private $_related=array(); // attribute name => related objects
private $_c; // query criteria (used by finder only)
private $_pk; // old primary key value
private $_alias='t'; // the table alias being used for query
public function __construct($scenario='insert')
{
if($scenario===null) // internally used by populateRecord() and model()
return;
$this->setScenario($scenario);
$this->setIsNewRecord(true);
$this->_attributes=$this->getMetaData()->attributeDefaults;
$this->init();
$this->attachBehaviors($this->behaviors());
$this->afterConstruct();
}
public function init()
{
}
public function cache($duration, $dependency=null, $queryCount=1)
{
$this->getDbConnection()->cache($duration, $dependency, $queryCount);
return $this;
}
public function __sleep()
{
return array_keys((array)$this);
}
public function __get($name)
{
if(isset($this->_attributes[$name]))
return $this->_attributes[$name];
elseif(isset($this->getMetaData()->columns[$name]))
return null;
elseif(isset($this->_related[$name]))
return $this->_related[$name];
elseif(isset($this->getMetaData()->relations[$name]))
return $this->getRelated($name);
else
return parent::__get($name);
}
public function __set($name,$value)
{
if($this->setAttribute($name,$value)===false)
{
if(isset($this->getMetaData()->relations[$name]))
$this->_related[$name]=$value;
else
parent::__set($name,$value);
}
}
public function __isset($name)
{
if(isset($this->_attributes[$name]))
return true;
elseif(isset($this->getMetaData()->columns[$name]))
return false;
elseif(isset($this->_related[$name]))
return true;
elseif(isset($this->getMetaData()->relations[$name]))
return $this->getRelated($name)!==null;
else
return parent::__isset($name);
}
public function __unset($name)
{
if(isset($this->getMetaData()->columns[$name]))
unset($this->_attributes[$name]);
elseif(isset($this->getMetaData()->relations[$name]))
unset($this->_related[$name]);
else
parent::__unset($name);
}
public function __call($name,$parameters)
{
if(isset($this->getMetaData()->relations[$name]))
{
if(empty($parameters))
return $this->getRelated($name,false);
else
return $this->getRelated($name,false,$parameters[0]);
}
$scopes=$this->scopes();
if(isset($scopes[$name]))
{
$this->getDbCriteria()->mergeWith($scopes[$name]);
return $this;
}
return parent::__call($name,$parameters);
}
public function getRelated($name,$refresh=false,$params=array())
{
if(!$refresh && $params===array() && (isset($this->_related[$name]) || array_key_exists($name,$this->_related)))
return $this->_related[$name];
$md=$this->getMetaData();
if(!isset($md->relations[$name]))
throw new CDbException(Yii::t('yii','{class} does not have relation "{name}".',
array('{class}'=>get_class($this), '{name}'=>$name)));
$relation=$md->relations[$name];
if($this->getIsNewRecord() && !$refresh && ($relation instanceof CHasOneRelation || $relation instanceof CHasManyRelation))
return $relation instanceof CHasOneRelation ? null : array();
if($params!==array()) // dynamic query
{
$exists=isset($this->_related[$name]) || array_key_exists($name,$this->_related);
if($exists)
$save=$this->_related[$name];
if($params instanceof CDbCriteria)
$params = $params->toArray();
$r=array($name=>$params);
}
else
$r=$name;
unset($this->_related[$name]);
$finder=$this->getActiveFinder($r);
$finder->lazyFind($this);
if(!isset($this->_related[$name]))
{
if($relation instanceof CHasManyRelation)
$this->_related[$name]=array();
elseif($relation instanceof CStatRelation)
$this->_related[$name]=$relation->defaultValue;
else
$this->_related[$name]=null;
}
if($params!==array())
{
$results=$this->_related[$name];
if($exists)
$this->_related[$name]=$save;
else
unset($this->_related[$name]);
return $results;
}
else
return $this->_related[$name];
}
public function hasRelated($name)
{
return isset($this->_related[$name]) || array_key_exists($name,$this->_related);
}
public function getDbCriteria($createIfNull=true)
{
if($this->_c===null)
{
if(($c=$this->defaultScope())!==array() || $createIfNull)
$this->_c=new CDbCriteria($c);
}
return $this->_c;
}
public function setDbCriteria($criteria)
{
$this->_c=$criteria;
}
public function defaultScope()
{
return array();
}
public function resetScope($resetDefault=true)
{
if($resetDefault)
$this->_c=new CDbCriteria();
else
$this->_c=null;
return $this;
}
public static function model($className=__CLASS__)
{
if(isset(self::$_models[$className]))
return self::$_models[$className];
else
{
$model=self::$_models[$className]=new $className(null);
$model->attachBehaviors($model->behaviors());
return $model;
}
}
public function getMetaData()
{
$className=get_class($this);
if(!array_key_exists($className,self::$_md))
{
self::$_md[$className]=null; // preventing recursive invokes of {@link getMetaData()} via {@link __get()}
self::$_md[$className]=new CActiveRecordMetaData($this);
}
return self::$_md[$className];
}
public function refreshMetaData()
{
$className=get_class($this);
if(array_key_exists($className,self::$_md))
unset(self::$_md[$className]);
}
public function tableName()
{
$tableName = get_class($this);
if(($pos=strrpos($tableName,'\\')) !== false)
return substr($tableName,$pos+1);
return $tableName;
}
public function primaryKey()
{
}
public function relations()
{
return array();
}
public function scopes()
{
return array();
}
public function attributeNames()
{
return array_keys($this->getMetaData()->columns);
}
public function getAttributeLabel($attribute)
{
$labels=$this->attributeLabels();
if(isset($labels[$attribute]))
return $labels[$attribute];
elseif(strpos($attribute,'.')!==false)
{
$segs=explode('.',$attribute);
$name=array_pop($segs);
$model=$this;
foreach($segs as $seg)
{
$relations=$model->getMetaData()->relations;
if(isset($relations[$seg]))
$model=CActiveRecord::model($relations[$seg]->className);
else
break;
}
return $model->getAttributeLabel($name);
}
else
return $this->generateAttributeLabel($attribute);
}
public function getDbConnection()
{
if(self::$db!==null)
return self::$db;
else
{
self::$db=Yii::app()->getDb();
if(self::$db instanceof CDbConnection)
return self::$db;
else
throw new CDbException(Yii::t('yii','Active Record requires a "db" CDbConnection application component.'));
}
}
public function getActiveRelation($name)
{
return isset($this->getMetaData()->relations[$name]) ? $this->getMetaData()->relations[$name] : null;
}
public function getTableSchema()
{
return $this->getMetaData()->tableSchema;
}
public function getCommandBuilder()
{
return $this->getDbConnection()->getSchema()->getCommandBuilder();
}
public function hasAttribute($name)
{
return isset($this->getMetaData()->columns[$name]);
}
public function getAttribute($name)
{
if(property_exists($this,$name))
return $this->$name;
elseif(isset($this->_attributes[$name]))
return $this->_attributes[$name];
}
public function setAttribute($name,$value)
{
if(property_exists($this,$name))
$this->$name=$value;
elseif(isset($this->getMetaData()->columns[$name]))
$this->_attributes[$name]=$value;
else
return false;
return true;
}
public function addRelatedRecord($name,$record,$index)
{
if($index!==false)
{
if(!isset($this->_related[$name]))
$this->_related[$name]=array();
if($record instanceof CActiveRecord)
{
if($index===true)
$this->_related[$name][]=$record;
else
$this->_related[$name][$index]=$record;
}
}
elseif(!isset($this->_related[$name]))
$this->_related[$name]=$record;
}
public function getAttributes($names=true)
{
$attributes=$this->_attributes;
foreach($this->getMetaData()->columns as $name=>$column)
{
if(property_exists($this,$name))
$attributes[$name]=$this->$name;
elseif($names===true && !isset($attributes[$name]))
$attributes[$name]=null;
}
if(is_array($names))
{
$attrs=array();
foreach($names as $name)
{
if(property_exists($this,$name))
$attrs[$name]=$this->$name;
else
$attrs[$name]=isset($attributes[$name])?$attributes[$name]:null;
}
return $attrs;
}
else
return $attributes;
}
public function save($runValidation=true,$attributes=null)
{
if(!$runValidation || $this->validate($attributes))
return $this->getIsNewRecord() ? $this->insert($attributes) : $this->update($attributes);
else
return false;
}
public function getIsNewRecord()
{
return $this->_new;
}
public function setIsNewRecord($value)
{
$this->_new=$value;
}
public function onBeforeSave($event)
{
$this->raiseEvent('onBeforeSave',$event);
}
public function onAfterSave($event)
{
$this->raiseEvent('onAfterSave',$event);
}
public function onBeforeDelete($event)
{
$this->raiseEvent('onBeforeDelete',$event);
}
public function onAfterDelete($event)
{
$this->raiseEvent('onAfterDelete',$event);
}
public function onBeforeFind($event)
{
$this->raiseEvent('onBeforeFind',$event);
}
public function onAfterFind($event)
{
$this->raiseEvent('onAfterFind',$event);
}
public function getActiveFinder($with)
{
return new CActiveFinder($this,$with);
}
public function onBeforeCount($event)
{
$this->raiseEvent('onBeforeCount',$event);
}
protected function beforeSave()
{
if($this->hasEventHandler('onBeforeSave'))
{
$event=new CModelEvent($this);
$this->onBeforeSave($event);
return $event->isValid;
}
else
return true;
}
protected function afterSave()
{
if($this->hasEventHandler('onAfterSave'))
$this->onAfterSave(new CEvent($this));
}
protected function beforeDelete()
{
if($this->hasEventHandler('onBeforeDelete'))
{
$event=new CModelEvent($this);
$this->onBeforeDelete($event);
return $event->isValid;
}
else
return true;
}
protected function afterDelete()
{
if($this->hasEventHandler('onAfterDelete'))
$this->onAfterDelete(new CEvent($this));
}
protected function beforeFind()
{
if($this->hasEventHandler('onBeforeFind'))
{
$event=new CModelEvent($this);
$this->onBeforeFind($event);
}
}
protected function beforeCount()
{
if($this->hasEventHandler('onBeforeCount'))
$this->onBeforeCount(new CEvent($this));
}
protected function afterFind()
{
if($this->hasEventHandler('onAfterFind'))
$this->onAfterFind(new CEvent($this));
}
public function beforeFindInternal()
{
$this->beforeFind();
}
public function afterFindInternal()
{
$this->afterFind();
}
public function insert($attributes=null)
{
if(!$this->getIsNewRecord())
throw new CDbException(Yii::t('yii','The active record cannot be inserted to database because it is not new.'));
if($this->beforeSave())
{
$builder=$this->getCommandBuilder();
$table=$this->getTableSchema();
$command=$builder->createInsertCommand($table,$this->getAttributes($attributes));
if($command->execute())
{
$primaryKey=$table->primaryKey;
if($table->sequenceName!==null)
{
if(is_string($primaryKey) && $this->$primaryKey===null)
$this->$primaryKey=$builder->getLastInsertID($table);
elseif(is_array($primaryKey))
{
foreach($primaryKey as $pk)
{
if($this->$pk===null)
{
$this->$pk=$builder->getLastInsertID($table);
break;
}
}
}
}
$this->_pk=$this->getPrimaryKey();
$this->afterSave();
$this->setIsNewRecord(false);
$this->setScenario('update');
return true;
}
}
return false;
}
public function update($attributes=null)
{
if($this->getIsNewRecord())
throw new CDbException(Yii::t('yii','The active record cannot be updated because it is new.'));
if($this->beforeSave())
{
if($this->_pk===null)
$this->_pk=$this->getPrimaryKey();
$this->updateByPk($this->getOldPrimaryKey(),$this->getAttributes($attributes));
$this->_pk=$this->getPrimaryKey();
$this->afterSave();
return true;
}
else
return false;
}
public function saveAttributes($attributes)
{
if(!$this->getIsNewRecord())
{
$values=array();
foreach($attributes as $name=>$value)
{
if(is_integer($name))
$values[$value]=$this->$value;
else
$values[$name]=$this->$name=$value;
}
if($this->_pk===null)
$this->_pk=$this->getPrimaryKey();
if($this->updateByPk($this->getOldPrimaryKey(),$values)>0)
{
$this->_pk=$this->getPrimaryKey();
return true;
}
else
return false;
}
else
throw new CDbException(Yii::t('yii','The active record cannot be updated because it is new.'));
}
public function saveCounters($counters)
{
$builder=$this->getCommandBuilder();
$table=$this->getTableSchema();
$criteria=$builder->createPkCriteria($table,$this->getOldPrimaryKey());
$command=$builder->createUpdateCounterCommand($this->getTableSchema(),$counters,$criteria);
if($command->execute())
{
foreach($counters as $name=>$value)
$this->$name=$this->$name+$value;
return true;
}
else
return false;
}
public function delete()
{
if(!$this->getIsNewRecord())
{
if($this->beforeDelete())
{
$result=$this->deleteByPk($this->getPrimaryKey())>0;
$this->afterDelete();
return $result;
}
else
return false;
}
else
throw new CDbException(Yii::t('yii','The active record cannot be deleted because it is new.'));
}
public function refresh()
{
if(($record=$this->findByPk($this->getPrimaryKey()))!==null)
{
$this->_attributes=array();
$this->_related=array();
foreach($this->getMetaData()->columns as $name=>$column)
{
if(property_exists($this,$name))
$this->$name=$record->$name;
else
$this->_attributes[$name]=$record->$name;
}
return true;
}
else
return false;
}
public function equals($record)
{
return $this->tableName()===$record->tableName() && $this->getPrimaryKey()===$record->getPrimaryKey();
}
public function getPrimaryKey()
{
$table=$this->getTableSchema();
if(is_string($table->primaryKey))
return $this->{$table->primaryKey};
elseif(is_array($table->primaryKey))
{
$values=array();
foreach($table->primaryKey as $name)
$values[$name]=$this->$name;
return $values;
}
else
return null;
}
public function setPrimaryKey($value)
{
$this->_pk=$this->getPrimaryKey();
$table=$this->getTableSchema();
if(is_string($table->primaryKey))
$this->{$table->primaryKey}=$value;
elseif(is_array($table->primaryKey))
{
foreach($table->primaryKey as $name)
$this->$name=$value[$name];
}
}
public function getOldPrimaryKey()
{
return $this->_pk;
}
public function setOldPrimaryKey($value)
{
$this->_pk=$value;
}
protected function query($criteria,$all=false)
{
$this->beforeFind();
$this->applyScopes($criteria);
if(empty($criteria->with))
{
if(!$all)
$criteria->limit=1;
$command=$this->getCommandBuilder()->createFindCommand($this->getTableSchema(),$criteria);
return $all ? $this->populateRecords($command->queryAll(), true, $criteria->index) : $this->populateRecord($command->queryRow());
}
else
{
$finder=$this->getActiveFinder($criteria->with);
return $finder->query($criteria,$all);
}
}
public function applyScopes(&$criteria)
{
if(!empty($criteria->scopes))
{
$scs=$this->scopes();
$c=$this->getDbCriteria();
foreach((array)$criteria->scopes as $k=>$v)
{
if(is_integer($k))
{
if(is_string($v))
{
if(isset($scs[$v]))
{
$c->mergeWith($scs[$v],true);
continue;
}
$scope=$v;
$params=array();
}
elseif(is_array($v))
{
$scope=key($v);
$params=current($v);
}
}
elseif(is_string($k))
{
$scope=$k;
$params=$v;
}
call_user_func_array(array($this,$scope),(array)$params);
}
}
if(isset($c) || ($c=$this->getDbCriteria(false))!==null)
{
$c->mergeWith($criteria);
$criteria=$c;
$this->resetScope(false);
}
}
public function getTableAlias($quote=false, $checkScopes=true)
{
if($checkScopes && ($criteria=$this->getDbCriteria(false))!==null && $criteria->alias!='')
$alias=$criteria->alias;
else
$alias=$this->_alias;
return $quote ? $this->getDbConnection()->getSchema()->quoteTableName($alias) : $alias;
}
public function setTableAlias($alias)
{
$this->_alias=$alias;
}
public function find($condition='',$params=array())
{
$criteria=$this->getCommandBuilder()->createCriteria($condition,$params);
return $this->query($criteria);
}
public function findAll($condition='',$params=array())
{
$criteria=$this->getCommandBuilder()->createCriteria($condition,$params);
return $this->query($criteria,true);
}
public function findByPk($pk,$condition='',$params=array())
{
$prefix=$this->getTableAlias(true).'.';
$criteria=$this->getCommandBuilder()->createPkCriteria($this->getTableSchema(),$pk,$condition,$params,$prefix);
return $this->query($criteria);
}
public function findAllByPk($pk,$condition='',$params=array())
{
$prefix=$this->getTableAlias(true).'.';
$criteria=$this->getCommandBuilder()->createPkCriteria($this->getTableSchema(),$pk,$condition,$params,$prefix);
return $this->query($criteria,true);
}
public function findByAttributes($attributes,$condition='',$params=array())
{
$prefix=$this->getTableAlias(true).'.';
$criteria=$this->getCommandBuilder()->createColumnCriteria($this->getTableSchema(),$attributes,$condition,$params,$prefix);
return $this->query($criteria);
}
public function findAllByAttributes($attributes,$condition='',$params=array())
{
$prefix=$this->getTableAlias(true).'.';
$criteria=$this->getCommandBuilder()->createColumnCriteria($this->getTableSchema(),$attributes,$condition,$params,$prefix);
return $this->query($criteria,true);
}
public function findBySql($sql,$params=array())
{
$this->beforeFind();
if(($criteria=$this->getDbCriteria(false))!==null && !empty($criteria->with))
{
$this->resetScope(false);
$finder=$this->getActiveFinder($criteria->with);
return $finder->findBySql($sql,$params);
}
else
{
$command=$this->getCommandBuilder()->createSqlCommand($sql,$params);
return $this->populateRecord($command->queryRow());
}
}
public function findAllBySql($sql,$params=array())
{
$this->beforeFind();
if(($criteria=$this->getDbCriteria(false))!==null && !empty($criteria->with))
{
$this->resetScope(false);
$finder=$this->getActiveFinder($criteria->with);
return $finder->findAllBySql($sql,$params);
}
else
{
$command=$this->getCommandBuilder()->createSqlCommand($sql,$params);
return $this->populateRecords($command->queryAll());
}
}
public function count($condition='',$params=array())
{
$this->beforeCount();
$builder=$this->getCommandBuilder();
$criteria=$builder->createCriteria($condition,$params);
$this->applyScopes($criteria);
if(empty($criteria->with))
return $builder->createCountCommand($this->getTableSchema(),$criteria)->queryScalar();
else
{
$finder=$this->getActiveFinder($criteria->with);
return $finder->count($criteria);
}
}
public function countByAttributes($attributes,$condition='',$params=array())
{
$prefix=$this->getTableAlias(true).'.';
$builder=$this->getCommandBuilder();
$this->beforeCount();
$criteria=$builder->createColumnCriteria($this->getTableSchema(),$attributes,$condition,$params,$prefix);
$this->applyScopes($criteria);
if(empty($criteria->with))
return $builder->createCountCommand($this->getTableSchema(),$criteria)->queryScalar();
else
{
$finder=$this->getActiveFinder($criteria->with);
return $finder->count($criteria);
}
}
public function countBySql($sql,$params=array())
{
$this->beforeCount();
return $this->getCommandBuilder()->createSqlCommand($sql,$params)->queryScalar();
}
public function exists($condition='',$params=array())
{
$builder=$this->getCommandBuilder();
$criteria=$builder->createCriteria($condition,$params);
$table=$this->getTableSchema();
$criteria->select='1';
$criteria->limit=1;
$this->applyScopes($criteria);
if(empty($criteria->with))
return $builder->createFindCommand($table,$criteria,$this->getTableAlias(false, false))->queryRow()!==false;
else
{
$criteria->select='*';
$finder=$this->getActiveFinder($criteria->with);
return $finder->count($criteria)>0;
}
}
public function with()
{
if(func_num_args()>0)
{
$with=func_get_args();
if(is_array($with[0])) // the parameter is given as an array
$with=$with[0];
if(!empty($with))
$this->getDbCriteria()->mergeWith(array('with'=>$with));
}
return $this;
}
public function together()
{
$this->getDbCriteria()->together=true;
return $this;
}
public function updateByPk($pk,$attributes,$condition='',$params=array())
{
$builder=$this->getCommandBuilder();
$table=$this->getTableSchema();
$criteria=$builder->createPkCriteria($table,$pk,$condition,$params);
$command=$builder->createUpdateCommand($table,$attributes,$criteria);
return $command->execute();
}
public function updateAll($attributes,$condition='',$params=array())
{
$builder=$this->getCommandBuilder();
$criteria=$builder->createCriteria($condition,$params);
$command=$builder->createUpdateCommand($this->getTableSchema(),$attributes,$criteria);
return $command->execute();
}
public function updateCounters($counters,$condition='',$params=array())
{
$builder=$this->getCommandBuilder();
$criteria=$builder->createCriteria($condition,$params);
$command=$builder->createUpdateCounterCommand($this->getTableSchema(),$counters,$criteria);
return $command->execute();
}
public function deleteByPk($pk,$condition='',$params=array())
{
$builder=$this->getCommandBuilder();
$criteria=$builder->createPkCriteria($this->getTableSchema(),$pk,$condition,$params);
$command=$builder->createDeleteCommand($this->getTableSchema(),$criteria);
return $command->execute();
}
public function deleteAll($condition='',$params=array())
{
$builder=$this->getCommandBuilder();
$criteria=$builder->createCriteria($condition,$params);
$command=$builder->createDeleteCommand($this->getTableSchema(),$criteria);
return $command->execute();
}
public function deleteAllByAttributes($attributes,$condition='',$params=array())
{
$builder=$this->getCommandBuilder();
$table=$this->getTableSchema();
$criteria=$builder->createColumnCriteria($table,$attributes,$condition,$params);
$command=$builder->createDeleteCommand($table,$criteria);
return $command->execute();
}
public function populateRecord($attributes,$callAfterFind=true)
{
if($attributes!==false)
{
$record=$this->instantiate($attributes);
$record->setScenario('update');
$record->init();
$md=$record->getMetaData();
foreach($attributes as $name=>$value)
{
if(property_exists($record,$name))
$record->$name=$value;
elseif(isset($md->columns[$name]))
$record->_attributes[$name]=$value;
}
$record->_pk=$record->getPrimaryKey();
$record->attachBehaviors($record->behaviors());
if($callAfterFind)
$record->afterFind();
return $record;
}
else
return null;
}
public function populateRecords($data,$callAfterFind=true,$index=null)
{
$records=array();
foreach($data as $attributes)
{
if(($record=$this->populateRecord($attributes,$callAfterFind))!==null)
{
if($index===null)
$records[]=$record;
else
$records[$record->$index]=$record;
}
}
return $records;
}
protected function instantiate($attributes)
{
$class=get_class($this);
$model=new $class(null);
return $model;
}
public function offsetExists($offset)
{
return $this->__isset($offset);
}
}
class CBaseActiveRelation extends CComponent
{
public $name;
public $className;
public $foreignKey;
public $select='*';
public $condition='';
public $params=array();
public $group='';
public $join='';
public $joinOptions='';
public $having='';
public $order='';
public function __construct($name,$className,$foreignKey,$options=array())
{
$this->name=$name;
$this->className=$className;
$this->foreignKey=$foreignKey;
foreach($options as $name=>$value)
$this->$name=$value;
}
public function mergeWith($criteria,$fromScope=false)
{
if($criteria instanceof CDbCriteria)
$criteria=$criteria->toArray();
if(isset($criteria['select']) && $this->select!==$criteria['select'])
{
if($this->select==='*'||$this->select===false)
$this->select=$criteria['select'];
elseif($criteria['select']===false)
$this->select=false;
elseif($criteria['select']!=='*')
{
$select1=is_string($this->select)?preg_split('/\s*,\s*/',trim($this->select),-1,PREG_SPLIT_NO_EMPTY):$this->select;
$select2=is_string($criteria['select'])?preg_split('/\s*,\s*/',trim($criteria['select']),-1,PREG_SPLIT_NO_EMPTY):$criteria['select'];
$this->select=array_merge($select1,array_diff($select2,$select1));
}
}
if(isset($criteria['condition']) && $this->condition!==$criteria['condition'])
{
if($this->condition==='')
$this->condition=$criteria['condition'];
elseif($criteria['condition']!=='')
$this->condition="({$this->condition}) AND ({$criteria['condition']})";
}
if(isset($criteria['params']) && $this->params!==$criteria['params'])
$this->params=array_merge($this->params,$criteria['params']);
if(isset($criteria['order']) && $this->order!==$criteria['order'])
{
if($this->order==='')
$this->order=$criteria['order'];
elseif($criteria['order']!=='')
$this->order=$criteria['order'].', '.$this->order;
}
if(isset($criteria['group']) && $this->group!==$criteria['group'])
{
if($this->group==='')
$this->group=$criteria['group'];
elseif($criteria['group']!=='')
$this->group.=', '.$criteria['group'];
}
if(isset($criteria['join']) && $this->join!==$criteria['join'])
{
if($this->join==='')
$this->join=$criteria['join'];
elseif($criteria['join']!=='')
$this->join.=' '.$criteria['join'];
}
if(isset($criteria['having']) && $this->having!==$criteria['having'])
{
if($this->having==='')
$this->having=$criteria['having'];
elseif($criteria['having']!=='')
$this->having="({$this->having}) AND ({$criteria['having']})";
}
}
}
class CStatRelation extends CBaseActiveRelation
{
public $select='COUNT(*)';
public $defaultValue=0;
public $scopes;
public function mergeWith($criteria,$fromScope=false)
{
if($criteria instanceof CDbCriteria)
$criteria=$criteria->toArray();
parent::mergeWith($criteria,$fromScope);
if(isset($criteria['defaultValue']))
$this->defaultValue=$criteria['defaultValue'];
}
}
class CActiveRelation extends CBaseActiveRelation
{
public $joinType='LEFT OUTER JOIN';
public $on='';
public $alias;
public $with=array();
public $together;
public $scopes;
public $through;
public function mergeWith($criteria,$fromScope=false)
{
if($criteria instanceof CDbCriteria)
$criteria=$criteria->toArray();
if($fromScope)
{
if(isset($criteria['condition']) && $this->on!==$criteria['condition'])
{
if($this->on==='')
$this->on=$criteria['condition'];
elseif($criteria['condition']!=='')
$this->on="({$this->on}) AND ({$criteria['condition']})";
}
unset($criteria['condition']);
}
parent::mergeWith($criteria);
if(isset($criteria['joinType']))
$this->joinType=$criteria['joinType'];
if(isset($criteria['on']) && $this->on!==$criteria['on'])
{
if($this->on==='')
$this->on=$criteria['on'];
elseif($criteria['on']!=='')
$this->on="({$this->on}) AND ({$criteria['on']})";
}
if(isset($criteria['with']))
$this->with=$criteria['with'];
if(isset($criteria['alias']))
$this->alias=$criteria['alias'];
if(isset($criteria['together']))
$this->together=$criteria['together'];
}
}
class CBelongsToRelation extends CActiveRelation
{
}
class CHasOneRelation extends CActiveRelation
{
}
class CHasManyRelation extends CActiveRelation
{
public $limit=-1;
public $offset=-1;
public $index;
public function mergeWith($criteria,$fromScope=false)
{
if($criteria instanceof CDbCriteria)
$criteria=$criteria->toArray();
parent::mergeWith($criteria,$fromScope);
if(isset($criteria['limit']) && $criteria['limit']>0)
$this->limit=$criteria['limit'];
if(isset($criteria['offset']) && $criteria['offset']>=0)
$this->offset=$criteria['offset'];
if(isset($criteria['index']))
$this->index=$criteria['index'];
}
}
class CManyManyRelation extends CHasManyRelation
{
private $_junctionTableName=null;
private $_junctionForeignKeys=null;
public function getJunctionTableName()
{
if ($this->_junctionTableName===null)
$this->initJunctionData();
return $this->_junctionTableName;
}
public function getJunctionForeignKeys()
{
if ($this->_junctionForeignKeys===null)
$this->initJunctionData();
return $this->_junctionForeignKeys;
}
private function initJunctionData()
{
if(!preg_match('/^\s*(.*?)\((.*)\)\s*$/',$this->foreignKey,$matches))
throw new CDbException(Yii::t('yii','The relation "{relation}" in active record class "{class}" is specified with an invalid foreign key. The format of the foreign key must be "joinTable(fk1,fk2,...)".',
array('{class}'=>$this->className,'{relation}'=>$this->name)));
$this->_junctionTableName=$matches[1];
$this->_junctionForeignKeys=preg_split('/\s*,\s*/',$matches[2],-1,PREG_SPLIT_NO_EMPTY);
}
}
class CActiveRecordMetaData
{
public $tableSchema;
public $columns;
public $relations=array();
public $attributeDefaults=array();
private $_modelClassName;
public function __construct($model)
{
$this->_modelClassName=get_class($model);
$tableName=$model->tableName();
if(($table=$model->getDbConnection()->getSchema()->getTable($tableName))===null)
throw new CDbException(Yii::t('yii','The table "{table}" for active record class "{class}" cannot be found in the database.',
array('{class}'=>$this->_modelClassName,'{table}'=>$tableName)));
if(($modelPk=$model->primaryKey())!==null || $table->primaryKey===null)
{
$table->primaryKey=$modelPk;
if(is_string($table->primaryKey) && isset($table->columns[$table->primaryKey]))
$table->columns[$table->primaryKey]->isPrimaryKey=true;
elseif(is_array($table->primaryKey))
{
foreach($table->primaryKey as $name)
{
if(isset($table->columns[$name]))
$table->columns[$name]->isPrimaryKey=true;
}
}
}
$this->tableSchema=$table;
$this->columns=$table->columns;
foreach($table->columns as $name=>$column)
{
if(!$column->isPrimaryKey && $column->defaultValue!==null)
$this->attributeDefaults[$name]=$column->defaultValue;
}
foreach($model->relations() as $name=>$config)
{
$this->addRelation($name,$config);
}
}
public function addRelation($name,$config)
{
if(isset($config[0],$config[1],$config[2])) // relation class, AR class, FK
$this->relations[$name]=new $config[0]($name,$config[1],$config[2],array_slice($config,3));
else
throw new CDbException(Yii::t('yii','Active record "{class}" has an invalid configuration for relation "{relation}". It must specify the relation type, the related active record class and the foreign key.', array('{class}'=>$this->_modelClassName,'{relation}'=>$name)));
}
public function hasRelation($name)
{
return isset($this->relations[$name]);
}
public function removeRelation($name)
{
unset($this->relations[$name]);
}
}
class CDbConnection extends CApplicationComponent
{
public $connectionString;
public $username='';
public $password='';
public $schemaCachingDuration=0;
public $schemaCachingExclude=array();
public $schemaCacheID='cache';
public $queryCachingDuration=0;
public $queryCachingDependency;
public $queryCachingCount=0;
public $queryCacheID='cache';
public $autoConnect=true;
public $charset;
public $emulatePrepare;
public $enableParamLogging=false;
public $enableProfiling=false;
public $tablePrefix;
public $initSQLs;
public $driverMap=array(
'cubrid'=>'CCubridSchema', // CUBRID
'pgsql'=>'CPgsqlSchema', // PostgreSQL
'mysqli'=>'CMysqlSchema', // MySQL
'mysql'=>'CMysqlSchema', // MySQL,MariaDB
'sqlite'=>'CSqliteSchema', // sqlite 3
'sqlite2'=>'CSqliteSchema', // sqlite 2
'mssql'=>'CMssqlSchema', // Mssql driver on windows hosts
'dblib'=>'CMssqlSchema', // dblib drivers on linux (and maybe others os) hosts
'sqlsrv'=>'CMssqlSchema', // Mssql
'oci'=>'COciSchema', // Oracle driver
);
public $pdoClass = 'PDO';
private $_driverName;
private $_attributes=array();
private $_active=false;
private $_pdo;
private $_transaction;
private $_schema;
public function __construct($dsn='',$username='',$password='')
{
$this->connectionString=$dsn;
$this->username=$username;
$this->password=$password;
}
public function __sleep()
{
$this->close();
return array_keys(get_object_vars($this));
}
public static function getAvailableDrivers()
{
return PDO::getAvailableDrivers();
}
public function init()
{
parent::init();
if($this->autoConnect)
$this->setActive(true);
}
public function getActive()
{
return $this->_active;
}
public function setActive($value)
{
if($value!=$this->_active)
{
if($value)
$this->open();
else
$this->close();
}
}
public function cache($duration, $dependency=null, $queryCount=1)
{
$this->queryCachingDuration=$duration;
$this->queryCachingDependency=$dependency;
$this->queryCachingCount=$queryCount;
return $this;
}
protected function open()
{
if($this->_pdo===null)
{
if(empty($this->connectionString))
throw new CDbException('CDbConnection.connectionString cannot be empty.');
try
{
$this->_pdo=$this->createPdoInstance();
$this->initConnection($this->_pdo);
$this->_active=true;
}
catch(PDOException $e)
{
if(YII_DEBUG)
{
throw new CDbException('CDbConnection failed to open the DB connection: '.
$e->getMessage(),(int)$e->getCode(),$e->errorInfo);
}
else
{
Yii::log($e->getMessage(),CLogger::LEVEL_ERROR,'exception.CDbException');
throw new CDbException('CDbConnection failed to open the DB connection.',(int)$e->getCode(),$e->errorInfo);
}
}
}
}
protected function close()
{
$this->_pdo=null;
$this->_active=false;
$this->_schema=null;
}
protected function createPdoInstance()
{
$pdoClass=$this->pdoClass;
if(($driver=$this->getDriverName())!==null)
{
if($driver==='mssql' || $driver==='dblib')
$pdoClass='CMssqlPdoAdapter';
elseif($driver==='sqlsrv')
$pdoClass='CMssqlSqlsrvPdoAdapter';
}
if(!class_exists($pdoClass))
throw new CDbException(Yii::t('yii','CDbConnection is unable to find PDO class "{className}". Make sure PDO is installed correctly.',
array('{className}'=>$pdoClass)));
@$instance=new $pdoClass($this->connectionString,$this->username,$this->password,$this->_attributes);
if(!$instance)
throw new CDbException(Yii::t('yii','CDbConnection failed to open the DB connection.'));
return $instance;
}
protected function initConnection($pdo)
{
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if($this->emulatePrepare!==null && constant('PDO::ATTR_EMULATE_PREPARES'))
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,$this->emulatePrepare);
if($this->charset!==null)
{
$driver=strtolower($pdo->getAttribute(PDO::ATTR_DRIVER_NAME));
if(in_array($driver,array('pgsql','mysql','mysqli')))
$pdo->exec('SET NAMES '.$pdo->quote($this->charset));
}
if($this->initSQLs!==null)
{
foreach($this->initSQLs as $sql)
$pdo->exec($sql);
}
}
public function getPdoInstance()
{
return $this->_pdo;
}
public function createCommand($query=null)
{
$this->setActive(true);
return new CDbCommand($this,$query);
}
public function getCurrentTransaction()
{
if($this->_transaction!==null)
{
if($this->_transaction->getActive())
return $this->_transaction;
}
return null;
}
public function beginTransaction()
{
$this->setActive(true);
$this->_pdo->beginTransaction();
return $this->_transaction=new CDbTransaction($this);
}
public function getSchema()
{
if($this->_schema!==null)
return $this->_schema;
else
{
$driver=$this->getDriverName();
if(isset($this->driverMap[$driver]))
return $this->_schema=Yii::createComponent($this->driverMap[$driver], $this);
else
throw new CDbException(Yii::t('yii','CDbConnection does not support reading schema for {driver} database.',
array('{driver}'=>$driver)));
}
}
public function getCommandBuilder()
{
return $this->getSchema()->getCommandBuilder();
}
public function getLastInsertID($sequenceName='')
{
$this->setActive(true);
return $this->_pdo->lastInsertId($sequenceName);
}
public function quoteValue($str)
{
if(is_int($str) || is_float($str))
return $str;
$this->setActive(true);
return $this->quoteValueInternal($str, PDO::PARAM_STR);
}
public function quoteValueWithType($value, $type)
{
$this->setActive(true);
return $this->quoteValueInternal($value, $type);
}
private function quoteValueInternal($value, $type)
{
if(mb_stripos($this->connectionString, 'odbc:')===false)
{
if(($quoted=$this->_pdo->quote($value, $type))!==false)
return $quoted;
}
// fallback for drivers that don't support quote (e.g. oci and odbc)
return "'" . addcslashes(str_replace("'", "''", $value), "\000\n\r\\\032") . "'";
}
public function quoteTableName($name)
{
return $this->getSchema()->quoteTableName($name);
}
public function quoteColumnName($name)
{
return $this->getSchema()->quoteColumnName($name);
}
public function getPdoType($type)
{
static $map=array
(
'boolean'=>PDO::PARAM_BOOL,
'integer'=>PDO::PARAM_INT,
'string'=>PDO::PARAM_STR,
'resource'=>PDO::PARAM_LOB,
'NULL'=>PDO::PARAM_NULL,
);
return isset($map[$type]) ? $map[$type] : PDO::PARAM_STR;
}
public function getColumnCase()
{
return $this->getAttribute(PDO::ATTR_CASE);
}
public function setColumnCase($value)
{
$this->setAttribute(PDO::ATTR_CASE,$value);
}
public function getNullConversion()
{
return $this->getAttribute(PDO::ATTR_ORACLE_NULLS);
}
public function setNullConversion($value)
{
$this->setAttribute(PDO::ATTR_ORACLE_NULLS,$value);
}
public function getAutoCommit()
{
return $this->getAttribute(PDO::ATTR_AUTOCOMMIT);
}
public function setAutoCommit($value)
{
$this->setAttribute(PDO::ATTR_AUTOCOMMIT,$value);
}
public function getPersistent()
{
return $this->getAttribute(PDO::ATTR_PERSISTENT);
}
public function setPersistent($value)
{
return $this->setAttribute(PDO::ATTR_PERSISTENT,$value);
}
public function getDriverName()
{
if($this->_driverName!==null)
return $this->_driverName;
elseif(($pos=strpos($this->connectionString,':'))!==false)
return $this->_driverName=strtolower(substr($this->connectionString,0,$pos));
//return $this->getAttribute(PDO::ATTR_DRIVER_NAME);
}
public function setDriverName($driverName)
{
$this->_driverName=strtolower($driverName);
}
public function getClientVersion()
{
return $this->getAttribute(PDO::ATTR_CLIENT_VERSION);
}
public function getConnectionStatus()
{
return $this->getAttribute(PDO::ATTR_CONNECTION_STATUS);
}
public function getPrefetch()
{
return $this->getAttribute(PDO::ATTR_PREFETCH);
}
public function getServerInfo()
{
return $this->getAttribute(PDO::ATTR_SERVER_INFO);
}
public function getServerVersion()
{
return $this->getAttribute(PDO::ATTR_SERVER_VERSION);
}
public function getTimeout()
{
return $this->getAttribute(PDO::ATTR_TIMEOUT);
}
public function getAttribute($name)
{
$this->setActive(true);
return $this->_pdo->getAttribute($name);
}
public function setAttribute($name,$value)
{
if($this->_pdo instanceof PDO)
$this->_pdo->setAttribute($name,$value);
else
$this->_attributes[$name]=$value;
}
public function getAttributes()
{
return $this->_attributes;
}
public function setAttributes($values)
{
foreach($values as $name=>$value)
$this->_attributes[$name]=$value;
}
public function getStats()
{
$logger=Yii::getLogger();
$timings=$logger->getProfilingResults(null,'system.db.CDbCommand.query');
$count=count($timings);
$time=array_sum($timings);
$timings=$logger->getProfilingResults(null,'system.db.CDbCommand.execute');
$count+=count($timings);
$time+=array_sum($timings);
return array($count,$time);
}
}
abstract class CDbSchema extends CComponent
{
public $columnTypes=array();
private $_tableNames=array();
private $_tables=array();
private $_connection;
private $_builder;
private $_cacheExclude=array();
abstract protected function loadTable($name);
public function __construct($conn)
{
$this->_connection=$conn;
foreach($conn->schemaCachingExclude as $name)
$this->_cacheExclude[$name]=true;
}
public function getDbConnection()
{
return $this->_connection;
}
public function getTable($name,$refresh=false)
{
if($refresh===false && isset($this->_tables[$name]))
return $this->_tables[$name];
else
{
if($this->_connection->tablePrefix!==null && strpos($name,'{{')!==false)
$realName=preg_replace('/\{\{(.*?)\}\}/',$this->_connection->tablePrefix.'$1',$name);
else
$realName=$name;
// temporarily disable query caching
if($this->_connection->queryCachingDuration>0)
{
$qcDuration=$this->_connection->queryCachingDuration;
$this->_connection->queryCachingDuration=0;
}
if(!isset($this->_cacheExclude[$name]) && ($duration=$this->_connection->schemaCachingDuration)>0 && $this->_connection->schemaCacheID!==false && ($cache=Yii::app()->getComponent($this->_connection->schemaCacheID))!==null)
{
$key='yii:dbschema'.$this->_connection->connectionString.':'.$this->_connection->username.':'.$name;
$table=$cache->get($key);
if($refresh===true || $table===false)
{
$table=$this->loadTable($realName);
if($table!==null)
$cache->set($key,$table,$duration);
}
$this->_tables[$name]=$table;
}
else
$this->_tables[$name]=$table=$this->loadTable($realName);
if(isset($qcDuration)) // re-enable query caching
$this->_connection->queryCachingDuration=$qcDuration;
return $table;
}
}
public function getTables($schema='')
{
$tables=array();
foreach($this->getTableNames($schema) as $name)
{
if(($table=$this->getTable($name))!==null)
$tables[$name]=$table;
}
return $tables;
}
public function getTableNames($schema='')
{
if(!isset($this->_tableNames[$schema]))
$this->_tableNames[$schema]=$this->findTableNames($schema);
return $this->_tableNames[$schema];
}
public function getCommandBuilder()
{
if($this->_builder!==null)
return $this->_builder;
else
return $this->_builder=$this->createCommandBuilder();
}
public function refresh()
{
if(($duration=$this->_connection->schemaCachingDuration)>0 && $this->_connection->schemaCacheID!==false && ($cache=Yii::app()->getComponent($this->_connection->schemaCacheID))!==null)
{
foreach(array_keys($this->_tables) as $name)
{
if(!isset($this->_cacheExclude[$name]))
{
$key='yii:dbschema'.$this->_connection->connectionString.':'.$this->_connection->username.':'.$name;
$cache->delete($key);
}
}
}
$this->_tables=array();
$this->_tableNames=array();
$this->_builder=null;
}
public function quoteTableName($name)
{
if(strpos($name,'.')===false)
return $this->quoteSimpleTableName($name);
$parts=explode('.',$name);
foreach($parts as $i=>$part)
$parts[$i]=$this->quoteSimpleTableName($part);
return implode('.',$parts);
}
public function quoteSimpleTableName($name)
{
return "'".$name."'";
}
public function quoteColumnName($name)
{
if(($pos=strrpos($name,'.'))!==false)
{
$prefix=$this->quoteTableName(substr($name,0,$pos)).'.';
$name=substr($name,$pos+1);
}
else
$prefix='';
return $prefix . ($name==='*' ? $name : $this->quoteSimpleColumnName($name));
}
public function quoteSimpleColumnName($name)
{
return '"'.$name.'"';
}
public function compareTableNames($name1,$name2)
{
$name1=str_replace(array('"','`',"'"),'',$name1);
$name2=str_replace(array('"','`',"'"),'',$name2);
if(($pos=strrpos($name1,'.'))!==false)
$name1=substr($name1,$pos+1);
if(($pos=strrpos($name2,'.'))!==false)
$name2=substr($name2,$pos+1);
if($this->_connection->tablePrefix!==null)
{
if(strpos($name1,'{')!==false)
$name1=$this->_connection->tablePrefix.str_replace(array('{','}'),'',$name1);
if(strpos($name2,'{')!==false)
$name2=$this->_connection->tablePrefix.str_replace(array('{','}'),'',$name2);
}
return $name1===$name2;
}
public function resetSequence($table,$value=null)
{
}
public function checkIntegrity($check=true,$schema='')
{
}
protected function createCommandBuilder()
{
return new CDbCommandBuilder($this);
}
protected function findTableNames($schema='')
{
throw new CDbException(Yii::t('yii','{class} does not support fetching all table names.',
array('{class}'=>get_class($this))));
}
public function getColumnType($type)
{
if(isset($this->columnTypes[$type]))
return $this->columnTypes[$type];
elseif(($pos=strpos($type,' '))!==false)
{
$t=substr($type,0,$pos);
return (isset($this->columnTypes[$t]) ? $this->columnTypes[$t] : $t).substr($type,$pos);
}
else
return $type;
}
public function createTable($table,$columns,$options=null)
{
$cols=array();
foreach($columns as $name=>$type)
{
if(is_string($name))
$cols[]="\t".$this->quoteColumnName($name).' '.$this->getColumnType($type);
else
$cols[]="\t".$type;
}
$sql="CREATE TABLE ".$this->quoteTableName($table)." (\n".implode(",\n",$cols)."\n)";
return $options===null ? $sql : $sql.' '.$options;
}
public function renameTable($table,$newName)
{
return 'RENAME TABLE ' . $this->quoteTableName($table) . ' TO ' . $this->quoteTableName($newName);
}
public function dropTable($table)
{
return "DROP TABLE ".$this->quoteTableName($table);
}
public function truncateTable($table)
{
return "TRUNCATE TABLE ".$this->quoteTableName($table);
}
public function addColumn($table,$column,$type)
{
return 'ALTER TABLE ' . $this->quoteTableName($table)
. ' ADD ' . $this->quoteColumnName($column) . ' '
. $this->getColumnType($type);
}
public function dropColumn($table,$column)
{
return "ALTER TABLE ".$this->quoteTableName($table)
." DROP COLUMN ".$this->quoteColumnName($column);
}
public function renameColumn($table,$name,$newName)
{
return "ALTER TABLE ".$this->quoteTableName($table)
. " RENAME COLUMN ".$this->quoteColumnName($name)
. " TO ".$this->quoteColumnName($newName);
}
public function alterColumn($table,$column,$type)
{
return 'ALTER TABLE ' . $this->quoteTableName($table) . ' CHANGE '
. $this->quoteColumnName($column) . ' '
. $this->quoteColumnName($column) . ' '
. $this->getColumnType($type);
}
public function addForeignKey($name,$table,$columns,$refTable,$refColumns,$delete=null,$update=null)
{
if(is_string($columns))
$columns=preg_split('/\s*,\s*/',$columns,-1,PREG_SPLIT_NO_EMPTY);
foreach($columns as $i=>$col)
$columns[$i]=$this->quoteColumnName($col);
if(is_string($refColumns))
$refColumns=preg_split('/\s*,\s*/',$refColumns,-1,PREG_SPLIT_NO_EMPTY);
foreach($refColumns as $i=>$col)
$refColumns[$i]=$this->quoteColumnName($col);
$sql='ALTER TABLE '.$this->quoteTableName($table)
.' ADD CONSTRAINT '.$this->quoteColumnName($name)
.' FOREIGN KEY ('.implode(', ',$columns).')'
.' REFERENCES '.$this->quoteTableName($refTable)
.' ('.implode(', ',$refColumns).')';
if($delete!==null)
$sql.=' ON DELETE '.$delete;
if($update!==null)
$sql.=' ON UPDATE '.$update;
return $sql;
}
public function dropForeignKey($name,$table)
{
return 'ALTER TABLE '.$this->quoteTableName($table)
.' DROP CONSTRAINT '.$this->quoteColumnName($name);
}
public function createIndex($name,$table,$columns,$unique=false)
{
$cols=array();
if(is_string($columns))
$columns=preg_split('/\s*,\s*/',$columns,-1,PREG_SPLIT_NO_EMPTY);
foreach($columns as $col)
{
if(strpos($col,'(')!==false)
$cols[]=$col;
else
$cols[]=$this->quoteColumnName($col);
}
return ($unique ? 'CREATE UNIQUE INDEX ' : 'CREATE INDEX ')
. $this->quoteTableName($name).' ON '
. $this->quoteTableName($table).' ('.implode(', ',$cols).')';
}
public function dropIndex($name,$table)
{
return 'DROP INDEX '.$this->quoteTableName($name).' ON '.$this->quoteTableName($table);
}
public function addPrimaryKey($name,$table,$columns)
{
if(is_string($columns))
$columns=preg_split('/\s*,\s*/',$columns,-1,PREG_SPLIT_NO_EMPTY);
foreach($columns as $i=>$col)
$columns[$i]=$this->quoteColumnName($col);
return 'ALTER TABLE ' . $this->quoteTableName($table) . ' ADD CONSTRAINT '
. $this->quoteColumnName($name) . ' PRIMARY KEY ('
. implode(', ',$columns). ' )';
}
public function dropPrimaryKey($name,$table)
{
return 'ALTER TABLE ' . $this->quoteTableName($table) . ' DROP CONSTRAINT '
. $this->quoteColumnName($name);
}
}
class CSqliteSchema extends CDbSchema
{
public $columnTypes=array(
'pk' => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
'bigpk' => 'integer PRIMARY KEY AUTOINCREMENT NOT NULL',
'string' => 'varchar(255)',
'text' => 'text',
'integer' => 'integer',
'bigint' => 'integer',
'float' => 'float',
'decimal' => 'decimal',
'datetime' => 'datetime',
'timestamp' => 'timestamp',
'time' => 'time',
'date' => 'date',
'binary' => 'blob',
'boolean' => 'tinyint(1)',
'money' => 'decimal(19,4)',
);
public function resetSequence($table,$value=null)
{
if($table->sequenceName===null)
return;
if($value!==null)
$value=(int)($value)-1;
else
$value=(int)$this->getDbConnection()
->createCommand("SELECT MAX(`{$table->primaryKey}`) FROM {$table->rawName}")
->queryScalar();
try
{
// it's possible that 'sqlite_sequence' does not exist
$this->getDbConnection()
->createCommand("UPDATE sqlite_sequence SET seq='$value' WHERE name='{$table->name}'")
->execute();
}
catch(Exception $e)
{
}
}
public function checkIntegrity($check=true,$schema='')
{
$this->getDbConnection()->createCommand('PRAGMA foreign_keys='.(int)$check)->execute();
}
protected function findTableNames($schema='')
{
$sql="SELECT DISTINCT tbl_name FROM sqlite_master WHERE tbl_name<>'sqlite_sequence'";
return $this->getDbConnection()->createCommand($sql)->queryColumn();
}
protected function createCommandBuilder()
{
return new CSqliteCommandBuilder($this);
}
protected function loadTable($name)
{
$table=new CDbTableSchema;
$table->name=$name;
$table->rawName=$this->quoteTableName($name);
if($this->findColumns($table))
{
$this->findConstraints($table);
return $table;
}
else
return null;
}
protected function findColumns($table)
{
$sql="PRAGMA table_info({$table->rawName})";
$columns=$this->getDbConnection()->createCommand($sql)->queryAll();
if(empty($columns))
return false;
foreach($columns as $column)
{
$c=$this->createColumn($column);
$table->columns[$c->name]=$c;
if($c->isPrimaryKey)
{
if($table->primaryKey===null)
$table->primaryKey=$c->name;
elseif(is_string($table->primaryKey))
$table->primaryKey=array($table->primaryKey,$c->name);
else
$table->primaryKey[]=$c->name;
}
}
if(is_string($table->primaryKey) && !strncasecmp($table->columns[$table->primaryKey]->dbType,'int',3))
{
$table->sequenceName='';
$table->columns[$table->primaryKey]->autoIncrement=true;
}
return true;
}
protected function findConstraints($table)
{
$foreignKeys=array();
$sql="PRAGMA foreign_key_list({$table->rawName})";
$keys=$this->getDbConnection()->createCommand($sql)->queryAll();
foreach($keys as $key)
{
$column=$table->columns[$key['from']];
$column->isForeignKey=true;
$foreignKeys[$key['from']]=array($key['table'],$key['to']);
}
$table->foreignKeys=$foreignKeys;
}
protected function createColumn($column)
{
$c=new CSqliteColumnSchema;
$c->name=$column['name'];
$c->rawName=$this->quoteColumnName($c->name);
$c->allowNull=!$column['notnull'];
$c->isPrimaryKey=$column['pk']!=0;
$c->isForeignKey=false;
$c->comment=null; // SQLite does not support column comments at all
$c->init(strtolower($column['type']),$column['dflt_value']);
return $c;
}
public function renameTable($table, $newName)
{
return 'ALTER TABLE ' . $this->quoteTableName($table) . ' RENAME TO ' . $this->quoteTableName($newName);
}
public function truncateTable($table)
{
return "DELETE FROM ".$this->quoteTableName($table);
}
public function dropColumn($table, $column)
{
throw new CDbException(Yii::t('yii', 'Dropping DB column is not supported by SQLite.'));
}
public function renameColumn($table, $name, $newName)
{
throw new CDbException(Yii::t('yii', 'Renaming a DB column is not supported by SQLite.'));
}
public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete=null, $update=null)
{
throw new CDbException(Yii::t('yii', 'Adding a foreign key constraint to an existing table is not supported by SQLite.'));
}
public function dropForeignKey($name, $table)
{
throw new CDbException(Yii::t('yii', 'Dropping a foreign key constraint is not supported by SQLite.'));
}
public function alterColumn($table, $column, $type)
{
throw new CDbException(Yii::t('yii', 'Altering a DB column is not supported by SQLite.'));
}
public function dropIndex($name, $table)
{
return 'DROP INDEX '.$this->quoteTableName($name);
}
public function addPrimaryKey($name,$table,$columns)
{
throw new CDbException(Yii::t('yii', 'Adding a primary key after table has been created is not supported by SQLite.'));
}
public function dropPrimaryKey($name,$table)
{
throw new CDbException(Yii::t('yii', 'Removing a primary key after table has been created is not supported by SQLite.'));
}
}
class CDbTableSchema extends CComponent
{
public $name;
public $rawName;
public $primaryKey;
public $sequenceName;
public $foreignKeys=array();
public $columns=array();
public function getColumn($name)
{
return isset($this->columns[$name]) ? $this->columns[$name] : null;
}
public function getColumnNames()
{
return array_keys($this->columns);
}
}
class CDbCommand extends CComponent
{
public $params=array();
private $_connection;
private $_text;
private $_statement;
private $_paramLog=array();
private $_query;
private $_fetchMode = array(PDO::FETCH_ASSOC);
public function __construct(CDbConnection $connection,$query=null)
{
$this->_connection=$connection;
if(is_array($query))
{
foreach($query as $name=>$value)
$this->$name=$value;
}
else
$this->setText($query);
}
public function __sleep()
{
$this->_statement=null;
return array_keys(get_object_vars($this));
}
public function setFetchMode($mode)
{
$params=func_get_args();
$this->_fetchMode = $params;
return $this;
}
public function reset()
{
$this->_text=null;
$this->_query=null;
$this->_statement=null;
$this->_paramLog=array();
$this->params=array();
return $this;
}
public function getText()
{
if($this->_text=='' && !empty($this->_query))
$this->setText($this->buildQuery($this->_query));
return $this->_text;
}
public function setText($value)
{
if($this->_connection->tablePrefix!==null && $value!='')
$this->_text=preg_replace('/{{(.*?)}}/',$this->_connection->tablePrefix.'\1',$value);
else
$this->_text=$value;
$this->cancel();
return $this;
}
public function getConnection()
{
return $this->_connection;
}
public function getPdoStatement()
{
return $this->_statement;
}
public function prepare()
{
if($this->_statement==null)
{
try
{
$this->_statement=$this->getConnection()->getPdoInstance()->prepare($this->getText());
$this->_paramLog=array();
}
catch(Exception $e)
{
Yii::log('Error in preparing SQL: '.$this->getText(),CLogger::LEVEL_ERROR,'system.db.CDbCommand');
$errorInfo=$e instanceof PDOException ? $e->errorInfo : null;
throw new CDbException(Yii::t('yii','CDbCommand failed to prepare the SQL statement: {error}',
array('{error}'=>$e->getMessage())),(int)$e->getCode(),$errorInfo);
}
}
}
public function cancel()
{
$this->_statement=null;
}
public function bindParam($name, &$value, $dataType=null, $length=null, $driverOptions=null)
{
$this->prepare();
if($dataType===null)
$this->_statement->bindParam($name,$value,$this->_connection->getPdoType(gettype($value)));
elseif($length===null)
$this->_statement->bindParam($name,$value,$dataType);
elseif($driverOptions===null)
$this->_statement->bindParam($name,$value,$dataType,$length);
else
$this->_statement->bindParam($name,$value,$dataType,$length,$driverOptions);
$this->_paramLog[$name]=&$value;
return $this;
}
public function bindValue($name, $value, $dataType=null)
{
$this->prepare();
if($dataType===null)
$this->_statement->bindValue($name,$value,$this->_connection->getPdoType(gettype($value)));
else
$this->_statement->bindValue($name,$value,$dataType);
$this->_paramLog[$name]=$value;
return $this;
}
public function bindValues($values)
{
$this->prepare();
foreach($values as $name=>$value)
{
$this->_statement->bindValue($name,$value,$this->_connection->getPdoType(gettype($value)));
$this->_paramLog[$name]=$value;
}
return $this;
}
public function execute($params=array())
{
if($this->_connection->enableParamLogging && ($pars=array_merge($this->_paramLog,$params))!==array())
{
$p=array();
foreach($pars as $name=>$value)
$p[$name]=$name.'='.var_export($value,true);
$par='. Bound with ' .implode(', ',$p);
}
else
$par='';
try
{
if($this->_connection->enableProfiling)
Yii::beginProfile('system.db.CDbCommand.execute('.$this->getText().$par.')','system.db.CDbCommand.execute');
$this->prepare();
if($params===array())
$this->_statement->execute();
else
$this->_statement->execute($params);
$n=$this->_statement->rowCount();
if($this->_connection->enableProfiling)
Yii::endProfile('system.db.CDbCommand.execute('.$this->getText().$par.')','system.db.CDbCommand.execute');
return $n;
}
catch(Exception $e)
{
if($this->_connection->enableProfiling)
Yii::endProfile('system.db.CDbCommand.execute('.$this->getText().$par.')','system.db.CDbCommand.execute');
$errorInfo=$e instanceof PDOException ? $e->errorInfo : null;
$message=$e->getMessage();
Yii::log(Yii::t('yii','CDbCommand::execute() failed: {error}. The SQL statement executed was: {sql}.',
array('{error}'=>$message, '{sql}'=>$this->getText().$par)),CLogger::LEVEL_ERROR,'system.db.CDbCommand');
if(YII_DEBUG)
$message.='. The SQL statement executed was: '.$this->getText().$par;
throw new CDbException(Yii::t('yii','CDbCommand failed to execute the SQL statement: {error}',
array('{error}'=>$message)),(int)$e->getCode(),$errorInfo);
}
}
public function query($params=array())
{
return $this->queryInternal('',0,$params);
}
public function queryAll($fetchAssociative=true,$params=array())
{
return $this->queryInternal('fetchAll',$fetchAssociative ? $this->_fetchMode : PDO::FETCH_NUM, $params);
}
public function queryRow($fetchAssociative=true,$params=array())
{
return $this->queryInternal('fetch',$fetchAssociative ? $this->_fetchMode : PDO::FETCH_NUM, $params);
}
public function queryScalar($params=array())
{
$result=$this->queryInternal('fetchColumn',0,$params);
if(is_resource($result) && get_resource_type($result)==='stream')
return stream_get_contents($result);
else
return $result;
}
public function queryColumn($params=array())
{
return $this->queryInternal('fetchAll',array(PDO::FETCH_COLUMN, 0),$params);
}
private function queryInternal($method,$mode,$params=array())
{
$params=array_merge($this->params,$params);
if($this->_connection->enableParamLogging && ($pars=array_merge($this->_paramLog,$params))!==array())
{
$p=array();
foreach($pars as $name=>$value)
$p[$name]=$name.'='.var_export($value,true);
$par='. Bound with '.implode(', ',$p);
}
else
$par='';
if($this->_connection->queryCachingCount>0 && $method!==''
&& $this->_connection->queryCachingDuration>0
&& $this->_connection->queryCacheID!==false
&& ($cache=Yii::app()->getComponent($this->_connection->queryCacheID))!==null)
{
$this->_connection->queryCachingCount--;
$cacheKey='yii:dbquery'.':'.$method.':'.$this->_connection->connectionString.':'.$this->_connection->username;
$cacheKey.=':'.$this->getText().':'.serialize(array_merge($this->_paramLog,$params));
if(($result=$cache->get($cacheKey))!==false)
{
return $result[0];
}
}
try
{
if($this->_connection->enableProfiling)
Yii::beginProfile('system.db.CDbCommand.query('.$this->getText().$par.')','system.db.CDbCommand.query');
$this->prepare();
if($params===array())
$this->_statement->execute();
else
$this->_statement->execute($params);
if($method==='')
$result=new CDbDataReader($this);
else
{
$mode=(array)$mode;
call_user_func_array(array($this->_statement, 'setFetchMode'), $mode);
$result=$this->_statement->$method();
$this->_statement->closeCursor();
}
if($this->_connection->enableProfiling)
Yii::endProfile('system.db.CDbCommand.query('.$this->getText().$par.')','system.db.CDbCommand.query');
if(isset($cache,$cacheKey))
$cache->set($cacheKey, array($result), $this->_connection->queryCachingDuration, $this->_connection->queryCachingDependency);
return $result;
}
catch(Exception $e)
{
if($this->_connection->enableProfiling)
Yii::endProfile('system.db.CDbCommand.query('.$this->getText().$par.')','system.db.CDbCommand.query');
$errorInfo=$e instanceof PDOException ? $e->errorInfo : null;
$message=$e->getMessage();
Yii::log(Yii::t('yii','CDbCommand::{method}() failed: {error}. The SQL statement executed was: {sql}.',
array('{method}'=>$method, '{error}'=>$message, '{sql}'=>$this->getText().$par)),CLogger::LEVEL_ERROR,'system.db.CDbCommand');
if(YII_DEBUG)
$message.='. The SQL statement executed was: '.$this->getText().$par;
throw new CDbException(Yii::t('yii','CDbCommand failed to execute the SQL statement: {error}',
array('{error}'=>$message)),(int)$e->getCode(),$errorInfo);
}
}
public function buildQuery($query)
{
$sql=!empty($query['distinct']) ? 'SELECT DISTINCT' : 'SELECT';
$sql.=' '.(!empty($query['select']) ? $query['select'] : '*');
if(!empty($query['from']))
$sql.="\nFROM ".$query['from'];
if(!empty($query['join']))
$sql.="\n".(is_array($query['join']) ? implode("\n",$query['join']) : $query['join']);
if(!empty($query['where']))
$sql.="\nWHERE ".$query['where'];
if(!empty($query['group']))
$sql.="\nGROUP BY ".$query['group'];
if(!empty($query['having']))
$sql.="\nHAVING ".$query['having'];
if(!empty($query['union']))
$sql.="\nUNION (\n".(is_array($query['union']) ? implode("\n) UNION (\n",$query['union']) : $query['union']) . ')';
if(!empty($query['order']))
$sql.="\nORDER BY ".$query['order'];
$limit=isset($query['limit']) ? (int)$query['limit'] : -1;
$offset=isset($query['offset']) ? (int)$query['offset'] : -1;
if($limit>=0 || $offset>0)
$sql=$this->_connection->getCommandBuilder()->applyLimit($sql,$limit,$offset);
return $sql;
}
public function select($columns='*', $option='')
{
if(is_string($columns) && strpos($columns,'(')!==false)
$this->_query['select']=$columns;
else
{
if(!is_array($columns))
$columns=preg_split('/\s*,\s*/',trim($columns),-1,PREG_SPLIT_NO_EMPTY);
foreach($columns as $i=>$column)
{
if(is_object($column))
$columns[$i]=(string)$column;
elseif(strpos($column,'(')===false)
{
if(preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/',$column,$matches))
$columns[$i]=$this->_connection->quoteColumnName($matches[1]).' AS '.$this->_connection->quoteColumnName($matches[2]);
else
$columns[$i]=$this->_connection->quoteColumnName($column);
}
}
$this->_query['select']=implode(', ',$columns);
}
if($option!='')
$this->_query['select']=$option.' '.$this->_query['select'];
return $this;
}
public function getSelect()
{
return isset($this->_query['select']) ? $this->_query['select'] : '';
}
public function setSelect($value)
{
$this->select($value);
}
public function selectDistinct($columns='*')
{
$this->_query['distinct']=true;
return $this->select($columns);
}
public function getDistinct()
{
return isset($this->_query['distinct']) ? $this->_query['distinct'] : false;
}
public function setDistinct($value)
{
$this->_query['distinct']=$value;
}
public function from($tables)
{
if(is_string($tables) && strpos($tables,'(')!==false)
$this->_query['from']=$tables;
else
{
if(!is_array($tables))
$tables=preg_split('/\s*,\s*/',trim($tables),-1,PREG_SPLIT_NO_EMPTY);
foreach($tables as $i=>$table)
{
if(strpos($table,'(')===false)
{
if(preg_match('/^(.*?)(?i:\s+as|)\s+([^ ]+)$/',$table,$matches)) // with alias
$tables[$i]=$this->_connection->quoteTableName($matches[1]).' '.$this->_connection->quoteTableName($matches[2]);
else
$tables[$i]=$this->_connection->quoteTableName($table);
}
}
$this->_query['from']=implode(', ',$tables);
}
return $this;
}
public function getFrom()
{
return isset($this->_query['from']) ? $this->_query['from'] : '';
}
public function setFrom($value)
{
$this->from($value);
}
public function where($conditions, $params=array())
{
$this->_query['where']=$this->processConditions($conditions);
foreach($params as $name=>$value)
$this->params[$name]=$value;
return $this;
}
public function andWhere($conditions,$params=array())
{
if(isset($this->_query['where']))
$this->_query['where']=$this->processConditions(array('AND',$this->_query['where'],$conditions));
else
$this->_query['where']=$this->processConditions($conditions);
foreach($params as $name=>$value)
$this->params[$name]=$value;
return $this;
}
public function orWhere($conditions,$params=array())
{
if(isset($this->_query['where']))
$this->_query['where']=$this->processConditions(array('OR',$this->_query['where'],$conditions));
else
$this->_query['where']=$this->processConditions($conditions);
foreach($params as $name=>$value)
$this->params[$name]=$value;
return $this;
}
public function getWhere()
{
return isset($this->_query['where']) ? $this->_query['where'] : '';
}
public function setWhere($value)
{
$this->where($value);
}
public function join($table, $conditions, $params=array())
{
return $this->joinInternal('join', $table, $conditions, $params);
}
public function getJoin()
{
return isset($this->_query['join']) ? $this->_query['join'] : '';
}
public function setJoin($value)
{
$this->_query['join']=$value;
}
public function leftJoin($table, $conditions, $params=array())
{
return $this->joinInternal('left join', $table, $conditions, $params);
}
public function rightJoin($table, $conditions, $params=array())
{
return $this->joinInternal('right join', $table, $conditions, $params);
}
public function crossJoin($table)
{
return $this->joinInternal('cross join', $table);
}
public function naturalJoin($table)
{
return $this->joinInternal('natural join', $table);
}
public function naturalLeftJoin($table)
{
return $this->joinInternal('natural left join', $table);
}
public function naturalRightJoin($table)
{
return $this->joinInternal('natural right join', $table);
}
public function group($columns)
{
if(is_string($columns) && strpos($columns,'(')!==false)
$this->_query['group']=$columns;
else
{
if(!is_array($columns))
$columns=preg_split('/\s*,\s*/',trim($columns),-1,PREG_SPLIT_NO_EMPTY);
foreach($columns as $i=>$column)
{
if(is_object($column))
$columns[$i]=(string)$column;
elseif(strpos($column,'(')===false)
$columns[$i]=$this->_connection->quoteColumnName($column);
}
$this->_query['group']=implode(', ',$columns);
}
return $this;
}
public function getGroup()
{
return isset($this->_query['group']) ? $this->_query['group'] : '';
}
public function setGroup($value)
{
$this->group($value);
}
public function having($conditions, $params=array())
{
$this->_query['having']=$this->processConditions($conditions);
foreach($params as $name=>$value)
$this->params[$name]=$value;
return $this;
}
public function getHaving()
{
return isset($this->_query['having']) ? $this->_query['having'] : '';
}
public function setHaving($value)
{
$this->having($value);
}
public function order($columns)
{
if(is_string($columns) && strpos($columns,'(')!==false)
$this->_query['order']=$columns;
else
{
if(!is_array($columns))
$columns=preg_split('/\s*,\s*/',trim($columns),-1,PREG_SPLIT_NO_EMPTY);
foreach($columns as $i=>$column)
{
if(is_object($column))
$columns[$i]=(string)$column;
elseif(strpos($column,'(')===false)
{
if(preg_match('/^(.*?)\s+(asc|desc)$/i',$column,$matches))
$columns[$i]=$this->_connection->quoteColumnName($matches[1]).' '.strtoupper($matches[2]);
else
$columns[$i]=$this->_connection->quoteColumnName($column);
}
}
$this->_query['order']=implode(', ',$columns);
}
return $this;
}
public function getOrder()
{
return isset($this->_query['order']) ? $this->_query['order'] : '';
}
public function setOrder($value)
{
$this->order($value);
}
public function limit($limit, $offset=null)
{
$this->_query['limit']=(int)$limit;
if($offset!==null)
$this->offset($offset);
return $this;
}
public function getLimit()
{
return isset($this->_query['limit']) ? $this->_query['limit'] : -1;
}
public function setLimit($value)
{
$this->limit($value);
}
public function offset($offset)
{
$this->_query['offset']=(int)$offset;
return $this;
}
public function getOffset()
{
return isset($this->_query['offset']) ? $this->_query['offset'] : -1;
}
public function setOffset($value)
{
$this->offset($value);
}
public function union($sql)
{
if(isset($this->_query['union']) && is_string($this->_query['union']))
$this->_query['union']=array($this->_query['union']);
$this->_query['union'][]=$sql;
return $this;
}
public function getUnion()
{
return isset($this->_query['union']) ? $this->_query['union'] : '';
}
public function setUnion($value)
{
$this->_query['union']=$value;
}
public function insert($table, $columns)
{
$params=array();
$names=array();
$placeholders=array();
foreach($columns as $name=>$value)
{
$names[]=$this->_connection->quoteColumnName($name);
if($value instanceof CDbExpression)
{
$placeholders[] = $value->expression;
foreach($value->params as $n => $v)
$params[$n] = $v;
}
else
{
$placeholders[] = ':' . $name;
$params[':' . $name] = $value;
}
}
$sql='INSERT INTO ' . $this->_connection->quoteTableName($table)
. ' (' . implode(', ',$names) . ') VALUES ('
. implode(', ', $placeholders) . ')';
return $this->setText($sql)->execute($params);
}
public function update($table, $columns, $conditions='', $params=array())
{
$lines=array();
foreach($columns as $name=>$value)
{
if($value instanceof CDbExpression)
{
$lines[]=$this->_connection->quoteColumnName($name) . '=' . $value->expression;
foreach($value->params as $n => $v)
$params[$n] = $v;
}
else
{
$lines[]=$this->_connection->quoteColumnName($name) . '=:' . $name;
$params[':' . $name]=$value;
}
}
$sql='UPDATE ' . $this->_connection->quoteTableName($table) . ' SET ' . implode(', ', $lines);
if(($where=$this->processConditions($conditions))!='')
$sql.=' WHERE '.$where;
return $this->setText($sql)->execute($params);
}
public function delete($table, $conditions='', $params=array())
{
$sql='DELETE FROM ' . $this->_connection->quoteTableName($table);
if(($where=$this->processConditions($conditions))!='')
$sql.=' WHERE '.$where;
return $this->setText($sql)->execute($params);
}
public function createTable($table, $columns, $options=null)
{
return $this->setText($this->getConnection()->getSchema()->createTable($table, $columns, $options))->execute();
}
public function renameTable($table, $newName)
{
return $this->setText($this->getConnection()->getSchema()->renameTable($table, $newName))->execute();
}
public function dropTable($table)
{
return $this->setText($this->getConnection()->getSchema()->dropTable($table))->execute();
}
public function truncateTable($table)
{
$schema=$this->getConnection()->getSchema();
$n=$this->setText($schema->truncateTable($table))->execute();
if(strncasecmp($this->getConnection()->getDriverName(),'sqlite',6)===0)
$schema->resetSequence($schema->getTable($table));
return $n;
}
public function addColumn($table, $column, $type)
{
return $this->setText($this->getConnection()->getSchema()->addColumn($table, $column, $type))->execute();
}
public function dropColumn($table, $column)
{
return $this->setText($this->getConnection()->getSchema()->dropColumn($table, $column))->execute();
}
public function renameColumn($table, $name, $newName)
{
return $this->setText($this->getConnection()->getSchema()->renameColumn($table, $name, $newName))->execute();
}
public function alterColumn($table, $column, $type)
{
return $this->setText($this->getConnection()->getSchema()->alterColumn($table, $column, $type))->execute();
}
public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete=null, $update=null)
{
return $this->setText($this->getConnection()->getSchema()->addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete, $update))->execute();
}
public function dropForeignKey($name, $table)
{
return $this->setText($this->getConnection()->getSchema()->dropForeignKey($name, $table))->execute();
}
public function createIndex($name, $table, $columns, $unique=false)
{
return $this->setText($this->getConnection()->getSchema()->createIndex($name, $table, $columns, $unique))->execute();
}
public function dropIndex($name, $table)
{
return $this->setText($this->getConnection()->getSchema()->dropIndex($name, $table))->execute();
}
private function processConditions($conditions)
{
if(!is_array($conditions))
return $conditions;
elseif($conditions===array())
return '';
$n=count($conditions);
$operator=strtoupper($conditions[0]);
if($operator==='OR' || $operator==='AND')
{
$parts=array();
for($i=1;$i<$n;++$i)
{
$condition=$this->processConditions($conditions[$i]);
if($condition!=='')
$parts[]='('.$condition.')';
}
return $parts===array() ? '' : implode(' '.$operator.' ', $parts);
}
if(!isset($conditions[1],$conditions[2]))
return '';
$column=$conditions[1];
if(strpos($column,'(')===false)
$column=$this->_connection->quoteColumnName($column);
$values=$conditions[2];
if(!is_array($values))
$values=array($values);
if($operator==='IN' || $operator==='NOT IN')
{
if($values===array())
return $operator==='IN' ? '0=1' : '';
foreach($values as $i=>$value)
{
if(is_string($value))
$values[$i]=$this->_connection->quoteValue($value);
else
$values[$i]=(string)$value;
}
return $column.' '.$operator.' ('.implode(', ',$values).')';
}
if($operator==='LIKE' || $operator==='NOT LIKE' || $operator==='OR LIKE' || $operator==='OR NOT LIKE')
{
if($values===array())
return $operator==='LIKE' || $operator==='OR LIKE' ? '0=1' : '';
if($operator==='LIKE' || $operator==='NOT LIKE')
$andor=' AND ';
else
{
$andor=' OR ';
$operator=$operator==='OR LIKE' ? 'LIKE' : 'NOT LIKE';
}
$expressions=array();
foreach($values as $value)
$expressions[]=$column.' '.$operator.' '.$this->_connection->quoteValue($value);
return implode($andor,$expressions);
}
throw new CDbException(Yii::t('yii', 'Unknown operator "{operator}".', array('{operator}'=>$operator)));
}
private function joinInternal($type, $table, $conditions='', $params=array())
{
if(strpos($table,'(')===false)
{
if(preg_match('/^(.*?)(?i:\s+as|)\s+([^ ]+)$/',$table,$matches)) // with alias
$table=$this->_connection->quoteTableName($matches[1]).' '.$this->_connection->quoteTableName($matches[2]);
else
$table=$this->_connection->quoteTableName($table);
}
$conditions=$this->processConditions($conditions);
if($conditions!='')
$conditions=' ON '.$conditions;
if(isset($this->_query['join']) && is_string($this->_query['join']))
$this->_query['join']=array($this->_query['join']);
$this->_query['join'][]=strtoupper($type) . ' ' . $table . $conditions;
foreach($params as $name=>$value)
$this->params[$name]=$value;
return $this;
}
public function addPrimaryKey($name,$table,$columns)
{
return $this->setText($this->getConnection()->getSchema()->addPrimaryKey($name,$table,$columns))->execute();
}
public function dropPrimaryKey($name,$table)
{
return $this->setText($this->getConnection()->getSchema()->dropPrimaryKey($name,$table))->execute();
}
}
class CDbColumnSchema extends CComponent
{
public $name;
public $rawName;
public $allowNull;
public $dbType;
public $type;
public $defaultValue;
public $size;
public $precision;
public $scale;
public $isPrimaryKey;
public $isForeignKey;
public $autoIncrement=false;
public $comment='';
public function init($dbType, $defaultValue)
{
$this->dbType=$dbType;
$this->extractType($dbType);
$this->extractLimit($dbType);
if($defaultValue!==null)
$this->extractDefault($defaultValue);
}
protected function extractType($dbType)
{
if(stripos($dbType,'int')!==false && stripos($dbType,'unsigned int')===false)
$this->type='integer';
elseif(stripos($dbType,'bool')!==false)
$this->type='boolean';
elseif(preg_match('/(real|floa|doub)/i',$dbType))
$this->type='double';
else
$this->type='string';
}
protected function extractLimit($dbType)
{
if(strpos($dbType,'(') && preg_match('/\((.*)\)/',$dbType,$matches))
{
$values=explode(',',$matches[1]);
$this->size=$this->precision=(int)$values[0];
if(isset($values[1]))
$this->scale=(int)$values[1];
}
}
protected function extractDefault($defaultValue)
{
$this->defaultValue=$this->typecast($defaultValue);
}
public function typecast($value)
{
if(gettype($value)===$this->type || $value===null || $value instanceof CDbExpression)
return $value;
if($value==='' && $this->allowNull)
return $this->type==='string' ? '' : null;
switch($this->type)
{
case 'string': return (string)$value;
case 'integer': return (integer)$value;
case 'boolean': return (boolean)$value;
case 'double':
default: return $value;
}
}
}
class CSqliteColumnSchema extends CDbColumnSchema
{
protected function extractDefault($defaultValue)
{
if($this->dbType==='timestamp' && $defaultValue==='CURRENT_TIMESTAMP')
$this->defaultValue=null;
else
$this->defaultValue=$this->typecast(strcasecmp($defaultValue,'null') ? $defaultValue : null);
if($this->type==='string' && $this->defaultValue!==null) // PHP 5.2.6 adds single quotes while 5.2.0 doesn't
$this->defaultValue=trim($this->defaultValue,"'\"");
}
}
abstract class CValidator extends CComponent
{
public static $builtInValidators=array(
'required'=>'CRequiredValidator',
'filter'=>'CFilterValidator',
'match'=>'CRegularExpressionValidator',
'email'=>'CEmailValidator',
'url'=>'CUrlValidator',
'unique'=>'CUniqueValidator',
'compare'=>'CCompareValidator',
'length'=>'CStringValidator',
'in'=>'CRangeValidator',
'numerical'=>'CNumberValidator',
'captcha'=>'CCaptchaValidator',
'type'=>'CTypeValidator',
'file'=>'CFileValidator',
'default'=>'CDefaultValueValidator',
'exist'=>'CExistValidator',
'boolean'=>'CBooleanValidator',
'safe'=>'CSafeValidator',
'unsafe'=>'CUnsafeValidator',
'date'=>'CDateValidator',
);
public $attributes;
public $message;
public $skipOnError=false;
public $on;
public $except;
public $safe=true;
public $enableClientValidation=true;
abstract protected function validateAttribute($object,$attribute);
public static function createValidator($name,$object,$attributes,$params=array())
{
if(is_string($attributes))
$attributes=preg_split('/\s*,\s*/',trim($attributes, " \t\n\r\0\x0B,"),-1,PREG_SPLIT_NO_EMPTY);
if(isset($params['on']))
{
if(is_array($params['on']))
$on=$params['on'];
else
$on=preg_split('/[\s,]+/',$params['on'],-1,PREG_SPLIT_NO_EMPTY);
}
else
$on=array();
if(isset($params['except']))
{
if(is_array($params['except']))
$except=$params['except'];
else
$except=preg_split('/[\s,]+/',$params['except'],-1,PREG_SPLIT_NO_EMPTY);
}
else
$except=array();
if(method_exists($object,$name))
{
$validator=new CInlineValidator;
$validator->attributes=$attributes;
$validator->method=$name;
if(isset($params['clientValidate']))
{
$validator->clientValidate=$params['clientValidate'];
unset($params['clientValidate']);
}
$validator->params=$params;
if(isset($params['skipOnError']))
$validator->skipOnError=$params['skipOnError'];
}
else
{
$params['attributes']=$attributes;
if(isset(self::$builtInValidators[$name]))
$className=Yii::import(self::$builtInValidators[$name],true);
else
$className=Yii::import($name,true);
$validator=new $className;
foreach($params as $name=>$value)
$validator->$name=$value;
}
$validator->on=empty($on) ? array() : array_combine($on,$on);
$validator->except=empty($except) ? array() : array_combine($except,$except);
return $validator;
}
public function validate($object,$attributes=null)
{
if(is_array($attributes))
$attributes=array_intersect($this->attributes,$attributes);
else
$attributes=$this->attributes;
foreach($attributes as $attribute)
{
if(!$this->skipOnError || !$object->hasErrors($attribute))
$this->validateAttribute($object,$attribute);
}
}
public function clientValidateAttribute($object,$attribute)
{
}
public function applyTo($scenario)
{
if(isset($this->except[$scenario]))
return false;
return empty($this->on) || isset($this->on[$scenario]);
}
protected function addError($object,$attribute,$message,$params=array())
{
$params['{attribute}']=$object->getAttributeLabel($attribute);
$object->addError($attribute,strtr($message,$params));
}
protected function isEmpty($value,$trim=false)
{
return $value===null || $value===array() || $value==='' || $trim && is_scalar($value) && trim($value)==='';
}
}
class CStringValidator extends CValidator
{
public $max;
public $min;
public $is;
public $tooShort;
public $tooLong;
public $allowEmpty=true;
public $encoding;
protected function validateAttribute($object,$attribute)
{
$value=$object->$attribute;
if($this->allowEmpty && $this->isEmpty($value))
return;
if(is_array($value))
{
// https://github.com/yiisoft/yii/issues/1955
$this->addError($object,$attribute,Yii::t('yii','{attribute} is invalid.'));
return;
}
if(function_exists('mb_strlen') && $this->encoding!==false)
$length=mb_strlen($value, $this->encoding ? $this->encoding : Yii::app()->charset);
else
$length=strlen($value);
if($this->min!==null && $length<$this->min)
{
$message=$this->tooShort!==null?$this->tooShort:Yii::t('yii','{attribute} is too short (minimum is {min} characters).');
$this->addError($object,$attribute,$message,array('{min}'=>$this->min));
}
if($this->max!==null && $length>$this->max)
{
$message=$this->tooLong!==null?$this->tooLong:Yii::t('yii','{attribute} is too long (maximum is {max} characters).');
$this->addError($object,$attribute,$message,array('{max}'=>$this->max));
}
if($this->is!==null && $length!==$this->is)
{
$message=$this->message!==null?$this->message:Yii::t('yii','{attribute} is of the wrong length (should be {length} characters).');
$this->addError($object,$attribute,$message,array('{length}'=>$this->is));
}
}
public function clientValidateAttribute($object,$attribute)
{
$label=$object->getAttributeLabel($attribute);
if(($message=$this->message)===null)
$message=Yii::t('yii','{attribute} is of the wrong length (should be {length} characters).');
$message=strtr($message, array(
'{attribute}'=>$label,
'{length}'=>$this->is,
));
if(($tooShort=$this->tooShort)===null)
$tooShort=Yii::t('yii','{attribute} is too short (minimum is {min} characters).');
$tooShort=strtr($tooShort, array(
'{attribute}'=>$label,
'{min}'=>$this->min,
));
if(($tooLong=$this->tooLong)===null)
$tooLong=Yii::t('yii','{attribute} is too long (maximum is {max} characters).');
$tooLong=strtr($tooLong, array(
'{attribute}'=>$label,
'{max}'=>$this->max,
));
$js='';
if($this->min!==null)
{
$js.="
if(value.length<{$this->min}) {
messages.push(".CJSON::encode($tooShort).");
}
";
}
if($this->max!==null)
{
$js.="
if(value.length>{$this->max}) {
messages.push(".CJSON::encode($tooLong).");
}
";
}
if($this->is!==null)
{
$js.="
if(value.length!={$this->is}) {
messages.push(".CJSON::encode($message).");
}
";
}
if($this->allowEmpty)
{
$js="
if(jQuery.trim(value)!='') {
$js
}
";
}
return $js;
}
}
class CRequiredValidator extends CValidator
{
public $requiredValue;
public $strict=false;
public $trim=true;
protected function validateAttribute($object,$attribute)
{
$value=$object->$attribute;
if($this->requiredValue!==null)
{
if(!$this->strict && $value!=$this->requiredValue || $this->strict && $value!==$this->requiredValue)
{
$message=$this->message!==null?$this->message:Yii::t('yii','{attribute} must be {value}.',
array('{value}'=>$this->requiredValue));
$this->addError($object,$attribute,$message);
}
}
elseif($this->isEmpty($value,$this->trim))
{
$message=$this->message!==null?$this->message:Yii::t('yii','{attribute} cannot be blank.');
$this->addError($object,$attribute,$message);
}
}
public function clientValidateAttribute($object,$attribute)
{
$message=$this->message;
if($this->requiredValue!==null)
{
if($message===null)
$message=Yii::t('yii','{attribute} must be {value}.');
$message=strtr($message, array(
'{value}'=>$this->requiredValue,
'{attribute}'=>$object->getAttributeLabel($attribute),
));
return "
if(value!=" . CJSON::encode($this->requiredValue) . ") {
messages.push(".CJSON::encode($message).");
}
";
}
else
{
if($message===null)
$message=Yii::t('yii','{attribute} cannot be blank.');
$message=strtr($message, array(
'{attribute}'=>$object->getAttributeLabel($attribute),
));
if($this->trim)
$emptyCondition = "jQuery.trim(value)==''";
else
$emptyCondition = "value==''";
return "
if({$emptyCondition}) {
messages.push(".CJSON::encode($message).");
}
";
}
}
}
class CNumberValidator extends CValidator
{
public $integerOnly=false;
public $allowEmpty=true;
public $max;
public $min;
public $tooBig;
public $tooSmall;
public $integerPattern='/^\s*[+-]?\d+\s*$/';
public $numberPattern='/^\s*[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\s*$/';
protected function validateAttribute($object,$attribute)
{
$value=$object->$attribute;
if($this->allowEmpty && $this->isEmpty($value))
return;
if(!is_numeric($value))
{
// https://github.com/yiisoft/yii/issues/1955
// https://github.com/yiisoft/yii/issues/1669
$message=$this->message!==null?$this->message:Yii::t('yii','{attribute} must be a number.');
$this->addError($object,$attribute,$message);
return;
}
if($this->integerOnly)
{
if(!preg_match($this->integerPattern,"$value"))
{
$message=$this->message!==null?$this->message:Yii::t('yii','{attribute} must be an integer.');
$this->addError($object,$attribute,$message);
}
}
else
{
if(!preg_match($this->numberPattern,"$value"))
{
$message=$this->message!==null?$this->message:Yii::t('yii','{attribute} must be a number.');
$this->addError($object,$attribute,$message);
}
}
if($this->min!==null && $value<$this->min)
{
$message=$this->tooSmall!==null?$this->tooSmall:Yii::t('yii','{attribute} is too small (minimum is {min}).');
$this->addError($object,$attribute,$message,array('{min}'=>$this->min));
}
if($this->max!==null && $value>$this->max)
{
$message=$this->tooBig!==null?$this->tooBig:Yii::t('yii','{attribute} is too big (maximum is {max}).');
$this->addError($object,$attribute,$message,array('{max}'=>$this->max));
}
}
public function clientValidateAttribute($object,$attribute)
{
$label=$object->getAttributeLabel($attribute);
if(($message=$this->message)===null)
$message=$this->integerOnly ? Yii::t('yii','{attribute} must be an integer.') : Yii::t('yii','{attribute} must be a number.');
$message=strtr($message, array(
'{attribute}'=>$label,
));
if(($tooBig=$this->tooBig)===null)
$tooBig=Yii::t('yii','{attribute} is too big (maximum is {max}).');
$tooBig=strtr($tooBig, array(
'{attribute}'=>$label,
'{max}'=>$this->max,
));
if(($tooSmall=$this->tooSmall)===null)
$tooSmall=Yii::t('yii','{attribute} is too small (minimum is {min}).');
$tooSmall=strtr($tooSmall, array(
'{attribute}'=>$label,
'{min}'=>$this->min,
));
$pattern=$this->integerOnly ? $this->integerPattern : $this->numberPattern;
$js="
if(!value.match($pattern)) {
messages.push(".CJSON::encode($message).");
}
";
if($this->min!==null)
{
$js.="
if(value<{$this->min}) {
messages.push(".CJSON::encode($tooSmall).");
}
";
}
if($this->max!==null)
{
$js.="
if(value>{$this->max}) {
messages.push(".CJSON::encode($tooBig).");
}
";
}
if($this->allowEmpty)
{
$js="
if(jQuery.trim(value)!='') {
$js
}
";
}
return $js;
}
}
class CListIterator implements Iterator
{
private $_d;
private $_i;
public function __construct(&$data)
{
$this->_d=&$data;
$this->_i=0;
}
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_d);
}
}
interface IApplicationComponent
{
public function init();
public function getIsInitialized();
}
interface ICache
{
public function get($id);
public function mget($ids);
public function set($id,$value,$expire=0,$dependency=null);
public function add($id,$value,$expire=0,$dependency=null);
public function delete($id);
public function flush();
}
interface ICacheDependency
{
public function evaluateDependency();
public function getHasChanged();
}
interface IStatePersister
{
public function load();
public function save($state);
}
interface IFilter
{
public function filter($filterChain);
}
interface IAction
{
public function getId();
public function getController();
}
interface IWebServiceProvider
{
public function beforeWebMethod($service);
public function afterWebMethod($service);
}
interface IViewRenderer
{
public function renderFile($context,$file,$data,$return);
}
interface IUserIdentity
{
public function authenticate();
public function getIsAuthenticated();
public function getId();
public function getName();
public function getPersistentStates();
}
interface IWebUser
{
public function getId();
public function getName();
public function getIsGuest();
public function checkAccess($operation,$params=array());
public function loginRequired();
}
interface IAuthManager
{
public function checkAccess($itemName,$userId,$params=array());
public function createAuthItem($name,$type,$description='',$bizRule=null,$data=null);
public function removeAuthItem($name);
public function getAuthItems($type=null,$userId=null);
public function getAuthItem($name);
public function saveAuthItem($item,$oldName=null);
public function addItemChild($itemName,$childName);
public function removeItemChild($itemName,$childName);
public function hasItemChild($itemName,$childName);
public function getItemChildren($itemName);
public function assign($itemName,$userId,$bizRule=null,$data=null);
public function revoke($itemName,$userId);
public function isAssigned($itemName,$userId);
public function getAuthAssignment($itemName,$userId);
public function getAuthAssignments($userId);
public function saveAuthAssignment($assignment);
public function clearAll();
public function clearAuthAssignments();
public function save();
public function executeBizRule($bizRule,$params,$data);
}
interface IBehavior
{
public function attach($component);
public function detach($component);
public function getEnabled();
public function setEnabled($value);
}
interface IWidgetFactory
{
public function createWidget($owner,$className,$properties=array());
}
interface IDataProvider
{
public function getId();
public function getItemCount($refresh=false);
public function getTotalItemCount($refresh=false);
public function getData($refresh=false);
public function getKeys($refresh=false);
public function getSort();
public function getPagination();
}
interface ILogFilter
{
public function filter(&$logs);
}
?>