avoid eval() on CGridView columns' values

I’ll have to deploy a Yii application on a server where eval() is disabled (for security reasons). And I can’t make my application avoid using eval() without major changes. For instance it seems that CGridView depends on eval().

Here a short extract of my code:




$this->widget(

    'zii.widgets.grid.CGridView',

    array(

        'columns' => array(

            array(

                'name' => 'word',

                'type' => 'raw',

                'value' => 'CHtml::link($data->keyword, array("keyword/view", "id" => $data->id),'

                    .' array("title" => $data->notes, "class" => "keyword"))',

            ),



Apart from the ugliness of putting code in a string (hard not to forget a parenthesis), my problem is this code relies on eval(). Looking in the doc, I saw I coud probably define columns by extending CDataColumn, but this class still expects a "value" attribute that gets evaled. Is there a way to use a function that would receive $data as parameter? Something like:




class MyColumn extends CDataColumn

{

    function getValue($data) // would be used instead of $this->value

    {

        return CHtml::link(

            $data->keyword,

            array("keyword/view", "id" => $data->id),

            array("title" => $data->notes, "class" => "keyword")

        );

    }



I know someone posted on “eval() is evil” last month, especially thinking of HipHop, but contrary to this, I don’t want to delete the eval() uses from the Yii code, I’m just looking for a way to avoid it in my application.

If anyone has the same problem, it’s just that the documentation isn’t very clear. It says that the attributes “value” will be evaled. But Yii doesn’t use eval() but CComponent::evaluateExpression(). If given an array, it will behave like call_user_func_array().

So I replaced:




                'value' => 'CHtml::link($data->keyword, array("keyword/view", "id" => $data->id),'

                    .' array("title" => $data->notes, "class" => "keyword"))',



with:




                'value' => array($model, 'htmlColumn'), // calls $model->htmlColumn($data)



I couldn’t find a way to pass a parameter, but at least I avoided eval().

One way to avoid eval() would be to use anonymous functions (PHP 5.3).

http://php.net/manual/en/functions.anonymous.php

First of all - try to check CComponent.evaluateExpression:


	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 provide an array - argument called as function!

I didn’t either find a way to pass parameters to call_user_func_array() called by CComponent->evaluateExpression(). Is there a way for doing this?

I’ve been looking for the same solution. I am now thinking to override the evaluateExpression() method unless the staff provide an advice.

regards,

bettor

oh, guys!

try to provide:


'value'=>array($this,'myDataRender'),

and add your model in current context and parametrize it


public function myDataRender($data,$row,$grid){

 $this->myCurrentModel->setSomeDataProperty($data->property);

 return $this->myCurrentModel->renderSomeText($data->someProperty);

}

I don’t see how this could work with e.g. an accessRules() ‘expression’.

It would be nice if I could use an expression like this:




'expression'=>array(array(Yii::app()->user, 'checkAccess'), array('viewUser')),




'value'=>array($this,'checkAccess'),


public function checkAccess($data){

  return call_user_func_array(array(Yii::app()->user,'checkAccess'),array('viewUser',$data));

}

or no?

I’m not sure I understand what you mean, could you explain a bit?

Thanks for your help. Yii cannot find the third argument for myDataRender: Missing argument 3 for MyController::myDataRender();

Can you please suggest how I can obtain the value of one of the CGrudView columns in myDataRender() according to which I would like to calculate which css class to display?

Thank you in advance.

Regards,

bettor