Hace tiempo hicimos una introducción sobre Yii Framework. Comentamos que una de sus características es que viene integrado con jQuery y con una serie de widgets Ajax que el desarrollador puede ampliar a su gusto para mejorar la usabilidad y la experiencia del usuario.

Hoy hablaremos de uno de los widgets más usados, CGridView.

Con este widget se muestra la información en forma de tabla, donde las filas representan los elementos y las columnas los atributos de éstos. Soporta paginación y ordenamiento, es totalmente personalizable y permite el filtrado de los elementos por múltiples campos.

El CGridView lo usamos fundamentalmente en los CRUD que generamos para los medelos, y lo usamos conjuntamente con un data provider, preferiblemente un CActiveDataProvider.

El siguiente código genera un CGridView con la información de todos los elementos del modelo especificado. Puesto que no se ha personalizado de ninguna manera, la tabla se mostrará con todas las columnas posibles, una por cada atributo del modelo:

 $dataProvider=new CActiveDataProvider('nombre_modelo');

 $this->widget('zii.widgets.grid.CGridView', array(
    'dataProvider'=>$dataProvider,
 ));

Para configurar el widget con las columnas deseadas añadimos la propiedad ‘columns’ que será un array con los atributos del modelo que queremos mostrar:

 $this->widget('zii.widgets.grid.CGridView', array(
    'dataProvider'=>$dataProvider,
    'columns'=>array(
        'titulo', // muestra el atributo "titulo"
        'categoria.nombre', // muestra el atributo 'nombre' de la relación 'categoria' declararada en el modelo
        array( // muestra el atributo 'fecha_creacion' usando una expresión para procesar el valor de éste
            'name'=>'fecha_creacion',
            'value'=>'date("M j, Y", $data->fecha_creacion)',
        ),
        array(  // muestra una columna con los botones "view", "update" y "delete"
            'class'=>'CButtonColumn',
        ),
    ),
 ));

Para personalizar los botones o añadir uno nuevo editaremos y añadiremos propiedades al array correspondiente, cuya clase es ‘CButtonColumn’:

 $this->widget('zii.widgets.grid.CGridView', array(
    'id' =>'nombre-grid', // id del grid que usamos después para actualizarlo tras borrar un registro
    'dataProvider'=>$dataProvider,
    'columns'=>array(
        'titulo',
         ...resto de atributos...
         array(
            'class' => 'CButtonColumn',
            'template'=>'{delete}{update}{accion_nueva}', // botones a mostrar
            'updateButtonUrl'=>'Yii::app()->createUrl("/nombre_modelo/update?id=$data->id" )', // url de la acción 'update'
            'deleteButtonUrl'=>'Yii::app()->createUrl("/nombre_modelo/delete?id=$data->id" )', // url de la acción 'delete'
            'deleteConfirmation'=>'Seguro que quiere eliminar el elemento?', // mensaje de confirmación de borrado
            'afterDelete'=>'$.fn.yiiGridView.update("nombre-grid");', // actualiza el grid después de borrar
            'buttons'=>array(
		'accion_nueva' => array( //botón para la acción nueva
		    'label'=>'descripción accion_nueva', // titulo del enlace del botón nuevo
		    'imageUrl'=>Yii::app()->request->baseUrl.'/ruta_carpeta/nombre_foto', //ruta icono para el botón
		    'url'=>'Yii::app()->createUrl("/nombre_modelo/accion_nueva?id=$data->id" )', //url de la acción nueva
		    ),
		),
          ),
      ),
 ));

Si queremos que los elementos de la tabla se puedan ordenar y filtrar hay que hacer lo siguiente:

Suponemos que ‘Usuario’ es el nombre de la clase del modelo con el que estamos tratando.
Vamos a usar en todo momento la variable $modelo, como si todo el código estuviera escrito de manera secuencial. Aunque poniendo el código así, todo junto por ejemplo en la vista, funcionaría, es recomendable no hacerlo. Lo codificamos de está manera a continuación para que se entienda mejor el orden de los pasos, pero indicaremos la ubicación en la que debería estar cada bloque.

-MODELO-
Antes de nada, lo que hay que hacer para poder filtrar por los atributos deseados es declarar en la función ‘rules()’ del modelo una regla que indique que en el escenario ‘search’ (se podría definir con otro nombre) los valores de los atributos pasados (por $_POST o $_GET) son seguros y se deben tener en cuenta cuando se asignen al objeto.

 array('id, nombre, apellidos', 'safe', 'on'=>'search'),

-CONTROLADOR-
Creamos un Objeto de la clase ‘Usuario’ en el escenario ‘search’ para que se tenga en cuenta la reglada declarada anteriormente en el modelo. Y recibimos, en caso de existir, los atributos que nos lleguen por GET (esto sucederá en caso de que se esté filtrando en el Grid).
El código correspondiente a esto se debería ubicar en el controlador dentro del Action en el que estemos.

 $model = new Usuario('search'); //crea  usuario en escenario 'search'
 $model->unsetAttributes();  // limpia valores por defecto

 //recibimos datos cuando se esté filtrando en el Grid y modificamos el usuario
 if(isset($_GET['Usuario']))
	$model->attributes=$_GET['Usuario']; //asociamos a los atributos del modelo los valores que nos llegan del filtro

-MODELO-
Cuando decidimos por qué atributos queremos permitir filtrar se configura la propiedad ‘criteria’ del CActiveDataProvider. La propiedad ‘criteria’ sirve para especificar diferentes opciones de la consulta .
Con la propiedad ‘sort’ indicaremos el orden por defecto que queremos que tengan los elementos de la tabla.
Para el grid del admin del CRUD que se puede generar automáticamente a partir de una tabla de una base de datos el código correspondiente a esto se ubica en la función search().

 /*se realizan las comparaciones de los atributos aquí indicados (id, nombre, apellidos)
 con los valores de los mismos atributos del modelo $model que se ha modificado por el GET anteriormente en el controlador */
 $criteria=new CDbCriteria;
 $criteria->compare('id',$model->id);
 $criteria->compare('nombre',$model->nombre,true);
 $criteria->compare('apellidos',$model->apellidos,true);

 $dataProvider = new CActiveDataProvider($model, array(
    'criteria'=>$criteria,
    'sort'=>array('defaultOrder'=>'nombre ASC'), // orden por defecto según el atributo nombre
    'pagination'=>array('pageSize'=>4), // personalizamos la paginación

  ));

-VISTA-
En el widget, para que se muestren los campos de filtrado en las columnas correspondientes hay que añadir la propiedad ‘filter’. Y el dataProvider será el generado anteriormente con la propiedad ‘criteria’. Si el código anterior estuviera ubicado en la función search() del controlador, en lugar de asignarle la variable $dataProvider se le asignaría $model->search() que es lo que por defecto viene en los CRUD generados automáticamente.

 $this->widget('zii.widgets.grid.CGridView', array(
   'dataProvider'=>$dataProvider,
   'filter'=>$model,
    'columns'=>array(
        'id',
        'nombre',
        'apellidos',
         array(
             'name' => 'direccion',
             'filter' => false, // para que no se muestre el campo de filtrar para el atributo direccion
             ),
         array(
            'class' => 'CButtonColumn',
         ),
      ),
 ));

El grid resultante se vería de la siguiente manera:

22 Replies to “CGridView, uno de los widgets más usados del framework Yii”
  1. Genial el post, estoy tratando de mostrar en un cgridview los datos obtenidos de una consulta que relaciona varios modelos. Cómo tendría que programar el search()?. Podrían ayudarme??

  2. Hola necesito saber como puedo mostrar una tabla en una vista utilizando yii como framework

    • Hola Yarita, precisamente en este post se explica cómo crear un CGridView. Puedes ver la manera de mostrarlo en una vista en la parte final de la explicación.

  3. No abre el link que le enviaste a osbel, tmb tengo la misma duda. Gracias buen post.

  4. Como podria filtrar datos del grid estando dentro de un modal?
    Desde ya gracias por tu respuesta y que buen post.

  5. hola, muy bueno el tutorial, me gustaria saber si es posible que el crud generado tenga un scroll horiontal, ya que mi tabla tiene muchos atributos y al mostrarlos todos por pantalla se ve desordenado. Gracias

  6. Hola, buen post, me gustaría saber como puedo imprimir un enlace (ejm. un texto que diga “ver” y me linkee a una dirección dada), hago esta pregunta xq de las maneras q e intentado (Yii::app:createUrl, CHtml::link) terminan mostrandome el código html como texto, es decir en el casillero se muestra “…”

  7. Pues tienes que colocar dentro de la columna la propiedad “type”=>”raw”, o “type”=>”html”

  8. Buenas, muchas gracias por el post, varias cosas me sirvieron, sin embargo hay algo que pareciera ser de poca importancia pero no puedo encontrar el como cambiar el idioma ya sea del paginado y la cantidad de resultados que se muestran, bueno gracias por el post!

    • Hola, si lo que quieres es customizar lo que te sale justo antes y después del grid, puedes hacerlo añadiendo lo siguiente en el widget:

      – Texto sobre el número de resultados presentados:

      ‘summaryText’ => “Mostrando {start} – {end} de {count} resultados”,

      – Paginación:

      ‘pager’=>array(
      ‘header’ => ‘Ir a la pagina:’,
      ‘firstPageLabel’ => ‘< <', 'prevPageLabel' => ‘Anterior’,
      ‘nextPageLabel’ => ‘Siguiente’,
      ‘lastPageLabel’ => ‘>>;’,
      ),

    • Para cambiar el idioma , ingresa a protected/config/main.php y escribe ” ‘language’=>’es’, ” como se muestra en el siguiente ejemplo:
      return array(
      ‘basePath’=>dirname(__FILE__).DIRECTORY_SEPARATOR.’..’,
      ‘name’=>’Mi proyecto’,
      ‘language’=>’es’,

      De esta manera los mensajes de error, el paginado,etc. Se mostraran en español, espero les sirva

  9. quisiera hacer una dos filtros con listData pero uno dependiente del otro (departamentos-ciudades)en el cual ciudades depende de la elección del departamento

  10. hola nencesito pasar valores de un m modelo a otro esto con la finalidad de crear un boton y al darle click me mande los valores de ese mismo modelo a otro qya tengo creado como puedo realizarlo??

  11. Hola, tengo dos campos en la base de datos, nombre y apellido y quiero concatenarlos y en el momento de filtrar me busque.

  12. Hola, buenisima la expliación…. tienes alguna idea de como quitar uno de los botones que trae por defecto el cgrid view, específicamente la x, para no dejar q el usuario borre registros?

  13. Hola muy bueno el tuotial una consulta quisiera hacer una dos filtros con listData pero uno dependiente del otro (departamentos-ciudades)en el cual ciudades depende de la elección del departamento
    Saludos

  14. Buenas, estoy mostrando un TbGridView por ajax, muestra la primera pagina correctamente pero cuando selecciono otra pagina, se recarga la pagina entera.
    Sabes cual puede ser el problema

    Gracias de antemano

Deja un comentario

*