===== GridView ===== Este widget permite mostrar datos en forma de tabla, con posibilidad de filtrar y ordenar por cualquier columna. La propiedad "columns" especifica la lista de columnas del Grid, que pueden ser: - SerialColumn: contador secuencial de filas - Atributo: cualquier atributo del modelo - Raw: Código HTMl - ActionColumn: Botones de acciones, con enlaces Para especificar atributos, se puede hacer de las siguientes formas: GridView::widget([ 'dataProvider' => $dataProvider, 'filterModel' => $searchModel, 'columns' => [ 'fecha', 'usuario.nombre', 'aprobada', ['attribute'=>'categorias_id', 'value'=>function($data){ return $data->categoria->nombre; }, ], ['class' => 'yii\grid\ActionColumn'], ], Cuando en una columna queremos incluir código HTML para formatear la entrada, poner colores, incluir imágenes o lo que sea, añadiremos 'format'=>'raw' en la especificación de la columna: ['attribute'=>'aprobada', 'format'=>'raw', 'value'=>function($data){ return "$data->aprobadaText"; }, ], ==== 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 cuando el número de objetos a mostrar no es grande, también podemos utilizar un ArrayDataProvider, creado a partir de array de objetos ActiveRecord (de una relación HAS_MANY o mediante un find()). Ejemplo: si tenemos un usuario con una relación a los roles que tiene asignados, en la vista view podemos mostrar ...DetailView de datos del usuario

Roles del usuario

new ArrayDataProvider($model->roles), .... ]);
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** También se puede crear un ActiveDataProvider a partir de una relación asociada a un modelo, o a partir de un ActiveQuery: ...DetailView de datos de un titulo

Comentarios

new ActiveDataProvider(['query'=>$model->getComentarios()->orderBy('fecha desc')], .... ]);
==== Cambiar el número de filas que se visualizan ==== El tamaño de página se define en el [[..clases:dataprovider]] mediante pageSize de la propiedad pagination.: $dataProvider->pagination=array('pageSize'=>30); o en el momento de la creación: $dataProvider=new ActiveDataProvider(['query'=>...,'pagination'=>['pageSize'=>30]], .... ==== Convertir cada fila en un enlace a una acción ==== 'rowOptions' => function ($model, $key, $index, $grid) { return [ 'style' => "cursor: pointer", 'onclick' => 'location.href="' . Yii::$app->urlManager->createUrl(['usuarios/update','id'=>$key]).'"' ]; ==== Personalizar los botones de acciones ==== Con la propiedad **template** de ActionColumn definimos los botones que queremos mostrar: Para mostrar únicamente las acciones view y update: ... ['class'=>'yii\grid\ActionColumn', 'template'=>'{view} {update}' ], Podemos añadir acciones nuevas, definiéndolas en la propiedad buttons: ... 'columns'=>[ ... ['class'=>'yii\grid\ActionColumn', 'template'=>'{view} {update} {email}', 'buttons'=>[ 'email'=>function ($url, $model) { if($model->estado=='B') return ''; //No se muestra el botón $url=Url::toRoute(['mail','id'=>$model->id]); return Html::a('', $url); }, ]] ], Para cada botón definido en buttons, el closure devuelve el código HTML del botón, incluyendo enlace, texto o icono. Si el botón ha de ocultarse dependiendo de alguna condición, basta con devolver "" en ese caso. === Cambiar el controlador destino === El controlador al que apuntan las acciones del GridView es el mismo de la acción actual. En una vista donde el GridView muestra datos relacionados con el modelo principal (comentarios de un titulo, por ejemplo), nos llevaría a hacer enlaces incorrectos, por lo que hay cambiar la propiedad 'controller' del Grid al que deseemos: ['class' => 'yii\grid\ActionColumn', ... 'controller'=>'comentarios' Si queremos todavía más flexibilidad para crear las URL a las que apuntan los botones, podemos utilizar la propiedad urlCReator de ActionColumn: ['class' => 'yii\grid\ActionColumn', ... 'urlCreator'=>function ($action,$model, $key, $index) { return Url::toRoute(['comentarios/'.$action,'id'=>$model->id]); } ... ==== Mostrar fechas ==== Si hemos configurado el componente formatter en config/main.php correctamente, los atributos date o datetime se pueden presentar en un grid, utilizando la opción "format": GridView::widget([ 'model' => $model, 'attributes' => [ ... ['attribute'=>'fecha_alta','format'=>'date'], ], ]); ==== Referenciar a datos relacionados ==== Utilizaremos la sintáxis: //relación.dato// 'columns'=>[ ... 'usuario.nombre', //Escribe el nombre del usuario, si usuario es una relación hasOne del modelo 'categoria.descripcion', ] Si queremos personalizar la etiqueta de la cabecera para estas columnas relacionadas, lo haremos de la forma [['attribute'=>'categoria.descripcion','label'=>'Categoría']] Si queremos filtrar por los valores posibles de categoría, podemos definir un método lookup() en Categorias (Ver Crear y configurar modelos) y utilizarlo aquí: 'columns'=>[ ... ['attribute'=>'categorias_id', 'filter'=>Categorias::lookup(), 'value'=>function($data) { return $data->categoria->descripcion; } ], ... ] ==== Incluir casillas de selección múltiple para ejecutar una acción ==== Incluiremos en el grid una columna de tipo CheckBoxColumn: 'columns'=>[ .... ['class' => CheckboxColumn::className(),'name'=>'idselec', 'checkboxOptions' => function ($model, $key, $index, $column) { return ['value' => $model->id]; }], ... Si el grid lo incluimos dentro de una form, cuando se envíe ésta, el controlador recibirá en $_POST['idselec'] un array con las id de las filas seleccionadas. Desde la vista podemos acceder fácilmente al array de filas seleccionadas mediante ** var keys = $('#grid').yiiGridView('getSelectedRows'); **, donde #grid es la id del grid deseado.
'Aceptadas','R'=>'Rechazadas'], // o mejor: Entradas::$estadoOptions, si está definida ['class'=>'form-control','prompt'=>'Selecciona...'])?>
'btn btn-info',]);?>
echo GridView::widget(....) .... ));
Fijate que al abrir el form, especificamos la acción que queremos ejecutar, que será distinta de la actual (index normalmente, si es un grid) En el controlador, procesaremos las filas seleccionadas mediante find: /** Cambia de estado un conjunto de entradas * * @param char $estado POST * @param array $idselec POST */ public function actionEstado(){ $estado=Yii::$app->request->post('accion'); $idselec=(array)Yii::$app->request->post('idselec'); foreach(Entradas::findAll($idselec) as $entrada){ $entrada->estado=$estado; if(!$entrada->save()) { //Tratar el error, añadiendo mensajes a una lista, o lo que se desee } } $this->redirect(['index']); } ==== Filtro de datos ==== Para que aparezca una línea con campos para poder filtrar datos en el Grid, debemos asignar la propiedad filterModel del Grid, asignándole un modelo de tipo Search (lo genera gii). Por otra parte, cuando hay atributos para filtrar que 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: En el controlador: public function actionIndex(){ $usuariosSearch = new app\models\UsuariosSearch(); // Podemos añadir filtros: $usuariosSearch->estado="A"; $provider = $usuariosSearch->search(Yii::$app->request->queryParams); return $this->render('index',['usuariosSearch'=>$usuariosSearch,'provider'=>$provider]); } En la vista echo GridView::widget([ 'dataProvider' => $provider, 'filterModel'=>$usuariosSearch, //Habilita la linea de filtros 'columns' => [ ['attribute'=>'estado', 'value'=>function ($model,$attribute) { return $model->estadoText; }, 'filter'=>app\models\Usuarios::$estadoOptions //Array de valor=>descri ], estadoText y estadoOptions son dos propiedades definidas en el modelo, que me devuelven la descripción como texto del dato estado, y el array de valores posibles de estado. (Ver Crear y configurar Modelos) En el caso de que el atributo esté relacionado con otro modelo, podemos utilizar el método lookup() para los valores de filter (ver [[cursos:yii2:modelos|]]) ['attribute'=>'categorias_id', 'value'=>function ($model,$attribute) { return $model->categoria->descripcion; }, 'filter'=>Categorias::lookup() ], **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. En ese caso, se ha de utilizar un autocomplete === Filtrar y ordenar por un dato de un modelo relacionado === Es muy habitual que mostremos en el grid datos que no pertenecen al modelo, sino a uno relacionado. Por ejemplo, en los comentarios de un título podemos mostrar el nombre del usuario que ha hecho el comentario. En este caso, ya no se muestra la opción de ordenar ni filtrar por este dato, ya que no pertenece al modelo. La forma de solucionarlo es incluir el dato por el que filtramos (nombre del usuario) en ComentariosSearch, forzar a que el acceso SQL haga un join con Usuarios, y aplicar el filtro del nombre a la consulta: En ComentariosSearch.php class ComentariosSearch extends Comentarios { public $usuario_nombre; //Se podría llamar simplemente 'nombre', pero así evitamos posibles ambigüedades public function rules(){ ... [['xxx', 'usuario_nombre'], 'safe'], //Lo incluimos en rules-safe para que lo asigne desde el formulario } public function search($params) { $query = Comentarios::find()->innerJoinWith('usuario', true); //usuario es el nombre de la relación $dataProvider->sort->attributes['usuario_nombre'] = [ 'asc' => ['usuarios.nombre' => SORT_ASC], 'desc' => ['usuarios.nombre' => SORT_DESC], ]; ...resto del código //Añadimos el filtro por nombre de usuario: $query->andFilterWhere( ['like','usuarios.nombre',$this->usuario_nombre]); return $dataProvider; } En la vista: echo GridView::widget([ ... 'columns' => [ ['attribute' => 'usuario_nombre', 'label' => 'Usuario', 'format' => 'raw', 'value' => function ($data){ return $data->usuario->nombre; } ], ... ]);