You are viewing revision #4 of this wiki article.
This version may not be up to date with the latest version.
You may want to view the differences to the latest version.
It is difficult to perform user dependent theming through a general configuration in 'main.php'. This article proposes a method to do so through a Factory that dynamically generates classes to allow delayed resolution of actual user values. This means that you can refer to values that are stored in the database through the CActiveRecord before Yii is actually loaded. The values will be fetched from the database when actually used for the first time, which is after Yii is loaded. Actually, you can use pretty much any method that relies on Yii with this method.
Why you may need this ¶
Personnally, I wanted the theme directory and the jquery ui theme to be dependent on the user's context.
How it works ¶
It works by assigning a "property object" to a configuration field. This "property object" will return a string value when used in a string context. (I also had to make it delegate calls to a child object in order to be compatible with theming.)
When you read/use the code below, you have to know that my User class has some properties providing the User's theme, jquery-ui theme, and other properties that may influence some application component behaviors.
Side effects ¶
When passed in CJavaScript::encode(), the object is encoded as an object, not as a string. Making it a CJavaScriptExpression would not be ok either. So one needs to make sure the expression is used a string in certain locations by quoting the parameter ("$value") or concatenating the parameter ("".$value or $anothervalue.$value).
Example code and UserProperty class ¶
It allows you to have a 'main.php' configuration like this:
require(__DIR__.'/../components/UserProperty.php');
$juitheme=UserProperty::getProperty('juitheme','"myjuitheme"');
$juitheme = array(
'themeUrl' => $themeurl.'/css/jqueryui',
'theme' => $juitheme,
'htmlOptions'=>array('class' => $juitheme),
);
return array(
'theme'=>UserProperty::getProperty('themeobject','Yii::app()->getThemeManager()->getTheme("mytheme")'),
'components'=>array(
'widgetFactory' => array(
'widgets' => array(
'CJuiAutoComplete' =>$juitheme,
'CJuiDialog' => $juitheme,
//...
),
),
)
);
The above sets the juitheme and general theme path from the User properties by using the class below (located in the components directory in my case).
/**
* User Property factory.
*
* Generates an instance for a User Property that is computed when the value is first used.
* This class allows setting up Yii configuration with User properties that are known only when
* Yii is actually set up.
*
* Example for configuration array:
* $juitheme=UserProperty::getProperty('juitheme','"myjuitheme"');
* $juitheme = array(
* 'themeUrl' => $themeurl.'/css/jqueryui',
* 'theme' => $juitheme,
* 'htmlOptions'=>array('class' => $juitheme),
* );
*
* return array(
* 'theme'=>UserProperty::getProperty('themeobject','Yii::app()->getThemeManager()->getTheme("mytheme")'),
* 'components'=>array(
* 'widgetFactory' => array(
* 'widgets' => array(
* 'CJuiAutoComplete' =>$juitheme,
* 'CJuiDialog' => $juitheme,
* //...
* ),
* ),
* )
* );
*
* @license MIT
*/
class UserProperty {
/**
* Object pool of instances.
* @var Object[]
*/
static public $inst;
/**
* Provides an instance providing a user property when called.
*
* @param string $property Same as second parameter in CHtml::value
* @param string $default Default value (inside string, so null must be written as "null").
* @param string $template If provided '{val}' in the template is replaced with the User property.
* @return mixed Property returned by User model or default if null or empty string.
*/
public static function getProperty($property,$default=null,$template=null) {
$propertyclass= "_User_".$property.base_convert(crc32(" ".$default.$template),10,36);
if(!isset(self::$inst[$propertyclass])) {
if($default) {
// Test for object - if value is an object, do not handle it as a string//do not use default value.
$defaultexpression='if(!is_object($this->val) && "{$this->val}"==="") $this->val='.$default.';';
} else {
$defaultexpression='';
}
$val="CHtml::value(Yii::app()->user,'$property')";
if($template!==null) {
$val="strtr('$template',array('{val}'=>$val))";
}
$code="class $propertyclass {
private \$val;
private function _val() {
if(!isset(\$this->val)) {
\$this->val=$val;
$defaultexpression
}
return \$this->val;
}
public function __toString() {
\$r=\$this->_val();
return \$r;
}
public function __call(\$name,\$parameters) {
return call_user_func_array(array(\$this->_val(),\$name),\$parameters); }
public function __get(\$name) {
return \$this->_val()->\$name;
}
}";
//print strtr($code,array("\n"=>'<br />'));
eval($code);
self::$inst[$propertyclass]=new $propertyclass;
}
return self::$inst[$propertyclass];
}
}
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.