Herramientas de usuario

Herramientas del sitio


cursos:yii:views:grid

CgridView

Mostrar un array de objetos ActiveRecord en lugar de un ActiveDataProvider

Habitualmente el origen de datos de un Grid es un ActiveDataProvider, que gestiona el paginado, filtrado y ordenación de datos, pero también podemos utilizar un array de objetos ActiveRecord (de una relación HAS_MANY o mediante un findAll()). Ejemplo: si tenemos una entrada de blog con comentarios, en la vista view podemos mostrar

<?php $this->widget('zii.widgets.CDetailView', array(
	'data'=>$model,
	'attributes'=>array(
		'titulo',
		'fecha',
		'texto'
	),
)); 
 
$this->widget('zii.widgets.grid.CGridView', array(
  'dataProvider'=>new CArrayDataProvider($model->comentarios),
  'columns'=>array(
		'titulo',
                'fecha_alta::Fecha'
		'texto_comentario::Texto'
             )
....
));

En este caso, las etiquetas de los atributos no se heredan del modelo, por lo que se deben especificar en columns con la sintáxis atributo::etiqueta

Cambiar el número de filas que se visualizan

El tamaño de página se define en el CdataProvider mediante pageSize:

$dataProvider->pagination=array('pageSize'=>30);

Personalizar los botones de acciones

Con la propiedad template de CbuttonColumn definimos los botones que queremos: Para mostrar únicamente las acciones view y update:

  ...
  array(
	'class'=>'CButtonColumn',
	'template'=>'{view} {update}'
  ),

Podemos añadir acciones nuevas, definiéndolas en la propiedad buttons:

  ...
  array(
	'class'=>'CButtonColumn',
	'template'=>'{view} {update} {imprimir}',
	'buttons'=>array(
		'imprimir'=>array(
			//Si no hay icono: 'label'=>'Imprimir',
			'imageUrl'=>Yii::app()->request->baseUrl.'/images/print.png',
			'url'=>'Yii::app()->controller->createUrl("imprimir", array("id"=>$data->id))',
 
		),
		'delete'=>array(
			'visible'=>'$data->estado="A"',
 
		),
 
 
	)
  ),

Para cada botón definido en buttons, podemos definir las siguientes propiedades

  • label: texto a mostrar como botón
  • imageUrl: Si queremos mostrar un icono en lugar de un texto, utilizaremos esta propiedad, en lugar de label. Para referenciar a la carpeta images de nuestra aplicación, podemos utilizar la sintáxis del ejemplo anterior
  • class: Clase css a aplicarle
  • url: Url con la que enlaza. Es una expresión entre comillas, ya que ha de evaluarse para cada fila del grid (con eval), en la que podemos hacer referencia a los datos de la fila mediante $data
  • visible: Expresión (entre comillas, igual que la de imageUrl), que se evalua en cada fila. Si devuelve true, el botón se muestra. Si devuelve false, no.

Referenciar a datos relacionados

Utilizaremos la sintáxis: relación.dato

'columns'=>array(
	'id',
	'descripcion',
	'usuario.nombre',  //Escribe el nombre del usuario
  	'categoria.descripcion::Categoría',
  )

Si queremos personalizar la etiqueta de la cabecera para estas columnas relacionadas, lo haremos de la forma relacion.dato::Etiqueta

Incluir casillas de selección múltiple para ejecutar una acción

Incluiremos en el grid una columna de tipo CCheckBoxColumn:

   'columns'=>array(
      ....
	array('class'=>'CCheckBoxColumn',
           'value'=>'$data->id',  //valor que se tomará para almacenar en la variable del formulario
           'id'=>'idchk', //'name' de la variable de formulario
           'selectableRows'=>999
        ),
     ...

Si el grid lo incluimos dentro de una form, cuando se envíe ésta el controlador recibirá en $_REQUEST['idchk'] un array con las id de las filas seleccionadas

$form=$this->beginWidget('CActiveForm', array(
	'id'=>'entradas-form',
	'enableAjaxValidation'=>false,
        'action'=>array('entradas/aceptar'), //Definimos la acción a ejecutar
)); 
...
$this->widget('zii.widgets.grid.CGridView', array(
....
));
 
echo CHtml::submitButton('Aceptar los seleccionados');
$this->endWidget();

Fijate que al abrir el form, especificamos la acción que queremos ejecutar, que será distinta de la actual (admin, normalmente, si es un grid)

En el controlador, procesaremos las filas seleccionadas mediante findAllByPk:

/** Acepta un conjunto de entradas
 * 
 * @param type $idchk
 */
public function actionAceptar(){
	$idchk=$_POST['idchk'];
 
	foreach(Entradas::model()->findAllByPk($idchk) as $entrada){
		$entrada->aceptado=1;
		if(!$entrada->save()) {
                        $errores=json_encode($entrada->getErrors();
			Yii::app()->user->setFlash('error','Error en entrada '.$entrada->id.' '. $errores ));
		} 		
	}
	Yii::app()->user->setFlash('success','Entrada/s Aceptada/s');
	$this->redirect(array('admin'));
}

Filtrar con datos de un desplegable

Cuando el atributo a filtrar tiene valores concretos (ej: estado: 'P'⇒'Pend Aceptar','A'⇒'Aceptado'), o está relacionado con otro modelo (categoría, por ejemplo), podemos hacer que el grid muestre un filtro con desplegable:

$this->widget('zii.widgets.grid.CGridView', array(
	'id'=>'entradas-grid',
	'dataProvider'=>$model->search(),
	'filter'=>$model, //Para que aparezca el filtro
	'columns'=>array(
		...
		array(
   		   'name'=>'aceptado',
		   'value'=>'$data->aceptadoText',
		   'filter'=>$model->aceptadoOptions,
		   'header'=>'Aceptado'
		),

aceptadoText y aceptadoOptions son dos propiedas definidas en el modelo, que me devuelven la descripción como texto del dato aceptado, y el array de valores posibles de aceptado

$this->widget('zii.widgets.grid.CGridView', array(
	'id'=>'entradas-grid',
	'dataProvider'=>$model->search(),
	'filter'=>$model, //Para que aparezca el filtro
	'columns'=>array(
		...
		array(
			'name'=>'categorias_id',
			'value'=>'$data->categoria->descripcion',
		       'filter'=>CHtml::listData(Categorias::model()->findAll(),'id','descripcion')
		),

CUIDADO: No se debe utilizar este sistema si el modelo relacionado puede tener muchos valores, ya que se cargarían todos en el desplegable y es poco óptimo.