I have just started to use the new CSqlDataProvider class to do a more complicated query to prepare data for a CGridView. There is an issue with doing it this way. The normal way you code for a CGridView is to say something like the following:
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
'columns'=>array(
array(
'name'=>'Field',
'value'=>'$data->field',
),
Typically, when using the CActiveDataProvider, the $data variable comes through as an Object. But when you use CSqlDataProvider, the $data variable is simply an Array.
What are we supposed to do here? Should we change the way our CGridView operates to accommodate whatever dataProvider type we are using? Or should there be some mechanism to always treat things the same way in the View?
My coworker came up with a solution in the Yii Framework/base/CComponent.php class.
The function evaluateExpression($expression,$data=array())
//CComponent.php ~ line 611
public function evaluateExpression($_expression_,$_data_=array())
{
if(is_string($_expression_))
{
extract($_data_);
return eval('return '.$_expression_.';');
}
else
{
$_data_[]=$this;
return call_user_func_array($_expression_, $_data_);
}
}
If you check to see what the expression is expecting, you can typecast $data to Object. See our change below:
//CComponent.php ~ line 611
public function evaluateExpression($_expression_,$_data_=array())
{
if(is_string($_expression_))
{
extract($_data_);
/*
HERE'S OUR ADD:
THIS WILL CAST TO OBJECT IF THE EXPRESSION SHOWS WE INTEND TO TREAT IT AS SUCH
*/
if(strpos($_expression_,'->')){
$data = (object) $data;
}
return eval('return '.$_expression_.';');
}
else
{
$_data_[]=$this;
return call_user_func_array($_expression_, $_data_);
}
}
Now, we can make sure $data is always an Object this way. Or we can change the way we do our CGridView such that the expression is:
‘value’=>’$data[“field”]’ instead of ‘value’=>’$data->field’
But I don’t think it makes sense to have to change CGridView this way. I think it should have one standard way of behaving so that no matter what dataProvider we throw at it, the code should work.
What do you guys think about this?
-Jaz