Hi. This is related so I thought I would ask it here. I'm trying to generate a select box with options that have a value of "profile_id" and a name of "name_first name_last" … Am I only able to ask for one column for the name?
<?php
private static function prepareField($model,$field,$textConcatenator = ', ')
{
if (is_array($field)) $myfields = $field; // If the field is an array all is ok,
else $myfields = array($field); // else, make it part of an array.
$preparedField = ''; // Initialize
foreach ($myfields as $f):
$semiPreparedField = $model; //initialization.
if (!(strpos($f,'.') === FALSE))
{
$parts = split('[.]',$f);
// Added, separate in $parts. Now I can pass things like $groupField = 'type.name';
// Note that in the example 'type' is the name of a relation, and name is an atribute of the related AR.
foreach ($parts as $part):
if(is_object($model)) $semiPreparedField = $semiPreparedField->$part; // if an objet, the part is treated as a property
else $semiPreparedField = $semiPreparedField[$part]; // if not, then the part is treated as an element af the array.
endforeach;
}
else
{
if(is_object($model)) $semiPreparedField = $semiPreparedField->$f; // if an objet, the part is treated as a property
else $semiPreparedField = $semiPreparedField[$f]; // if not, then the part is treated as an element af the array.
}
empty($preparedField)? $preparedField = $semiPreparedField : $preparedField.= $textConcatenator.$semiPreparedField;
endforeach;
return $preparedField;
}
public static function listData($models,$valueField,$textField,$groupField='',$textConcatenator = ', ')
{
$listData=array();
foreach ($models as $model):
$preparedTextField = self::prepareField($model, $textField,$textConcatenator);
$preparedValueField= self::prepareField($model, $valueField,$textConcatenator);
if ($groupField==='')
{
$listData[$preparedValueField] = $preparedTextField;
}
else
{
$preparedGroupField = self::prepareField($model, $groupField,$textConcatenator);
$listData[$preparedGroupField][$preparedValueField] = $preparedTextField;
}
endforeach;
return $listData;
}
Now you can use listData in the following ways:
1. As ever
2. Passing a dot notation to work with related AR as shown in the previous posts.
3. Passing an array of one, two or more columns names, (these also can be with dot notation for related AR)
Qiang: This corresponds to the issue #268. Some thing can be better I know, but, can you check it and if is good enough make it part of the framework? Please PM me whatever thing you need…
Could I only use customized method in model instead of findBy()? Because I already has a customized SQL.
I also tried another case, my Tag model has a perend_id field for the parent tag. I can use above code to generate the dropDownList with group. But the problem is parent tag will show twice. I think if I have solution for 1st question, then I can fix this question by a SQL. (The SQL may be "where parent_id is not null")
Yes, the following are the code (I removed rules and attributeLabels). Most code is generated by Yii directly.
<?php
class Tag extends CActiveRecord
{
/**
* Returns the static model of the specified AR class.
* @return CActiveRecord the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* @return string the associated database table name
*/
public function tableName()
{
return 'tag';
}
/**
* @return array relational rules.
*/
public function relations()
{
return array(
'parent'=>array(self::BELONGS_TO, 'Tag', 'parent_id'),
);
}
public function getNames() {
$opts = array();
Yii::log('=== getNames ===', info, 'Tag.php');
Yii::log('user_name='.Yii::app()->user->name, info, 'Tag.php');
$sql='select t.id, t.name from ...';
$list=$this->findAllBySql($sql);
foreach($list as $n) {
$opts[$n->id] = $n->name;
}
return $opts;
}
}