CButtonColumn: Use special variable $data for the 'id' in the 'options' of a button

The problem

In an application I had a CGridView with a CButtonColumn and for an Ajax-Request I needed to make sure that the IDs of the buttons would not change when the GridView was updated so in effect I wanted to link them to the $data->id. So I tried:

array(	'class'=>'CButtonColumn',
	'template'=>'{myButton}',
	'buttons'=>array(
		'myButton'=>array(
			'label'=>'My Button',
			'url'=>'Yii::app()->createUrl("site/doStuff", array("id"=>$data->id))',
			'options'=>array(
				'id'=>'\'button_for_id_\'.$data->id',
			),
		),
	),
),

Which did not work as the 'id' is simply not evaluated using CButtonColumn.

The solution

I found this article which does a similar thing for a normal CDataColumn: CGridView: Use special variable $data in the htmlOptions of a column (i.e. evaluate htmlOptions attribute)

Inspired by it I extended the CButtonColumn class like this:

/**
 * ButtonColumn class file.
 * Extends {@link CButtonColumn}
 * 
 * Allows additional evaluation of ID in options.
 * 
 * @version $Id$
 * 
 */
class ButtonColumn extends CButtonColumn
{
	/**
	 * @var boolean whether the ID in the button options should be evaluated.
	 */
	public $evaluateID = false;

	/**
	 * Renders the button cell content.
	 * This method renders the view, update and delete buttons in the data cell.
	 * Overrides the method 'renderDataCellContent()' of the class CButtonColumn
	 * @param integer $row the row number (zero-based)
	 * @param mixed $data the data associated with the row
	 */
	public function renderDataCellContent($row, $data)
	{
		$tr=array();
		ob_start();
		foreach($this->buttons as $id=>$button)
		{
			if($this->evaluateID and isset($button['options']['id'])) 
			{
				$button['options']['id'] = $this->evaluateExpression($button['options']['id'], array('row'=>$row,'data'=>$data));
			}
			
			$this->renderButton($id,$button,$row,$data);
			$tr['{'.$id.'}']=ob_get_contents();
			ob_clean();
		}
		ob_end_clean();
		echo strtr($this->template,$tr);
	}
}

Basically I'm first checking if the ID should be evaluated which is indicated by a new boolean variable $evaluateID and whether the ID is actually set. Then we try to evaluate it and replace the original with the result which later on gets placed into the HTML-tag.

I can now use this class instead, set the $evaluateID to true and my button IDs will be evaluated correctly. This is how the button gets used now:

array(	'class'=>'ButtonColumn',
	'template'=>'{myButton}',
	'evaluateID'=>true,
	'buttons'=>array(
		'myButton'=>array(
			'label'=>'My Button',
			'url'=>'Yii::app()->createUrl("site/doStuff", array("id"=>$data->id))',
			'options'=>array(
				'id'=>'\'button_for_id_\'.$data->id',
			),
		),
	),
),

The resulting HTML then looks like this:

[html]
<td>
	<a id="button_for_id_4711" href="/MyApp/index.php?r=site/doStuff&id=4711"></a>
</td>