Hace unos días, expliqué en un artículo anterior, cómo agregar atributos virtuales (que no están en la BD) a un modelo ActiveRecord en Yii2, Pero al mostrar el listado de registros generado por GridView, los nuevos campos (virtuales) no aparecen con las opciones de ordenar o filtrar la lista por ellos, como en el siguiente ejemplo:
Para solucionarlo hay que modificar el modelo de búsquedas respectivo, que normalmente lleva el mismo nombre de la clase principal, pero con el sufijo Search. En este ejemplo dicho modelo es: ClienteSearch.php
y explicaré por separado cómo agregar las características de filtrado y de ordenamiento.
Filtrado
Lo primero será agregar los campos virtuales (nombre_completo
y edad
) a la lista de campos «safe» del método rules()
:
public function rules() { return [ [['id'], 'integer'], [['nombre', 'apellido', 'fecha_nacimiento', 'email', 'nombre_completo', 'edad'], 'safe'], ]; }
A continuación hay que agregar las condiciones respectivas para cada campo virtual, al método search()
:
public function search($params) { $query = Cliente::find(); ... ... $query->andFilterWhere(['like', 'CONCAT(nombre, " ", apellido)', $this->nombre_completo]); $query->andFilterWhere(['(YEAR(CURRENT_DATE) - YEAR(fecha_nacimiento) - (RIGHT(CURRENT_DATE, 5) < RIGHT(fecha_nacimiento, 5)))' => $this->edad]); ... ... }
Nótese que las condiciones de filtro generadas incluyen algo de «inteligencia» del lado del motor de BD, dado que ninguno de los dos campos existe tal cual en la tabla:
- Se compara el campo virtual
nombre_completo
con el nombre y apellido concatenados - Se compara el campo virtual
edad
con una operación que calcula la edad en base a la fecha de nacimiento en la BD
Ordenamiento
Para lograr ordenar el listado con los campos virtuales, hay que agregar las condiciones de ordenamiento al método search()
:
public function search($params) { $query = Cliente::find(); ... ... $dataProvider->sort->attributes['nombre_completo'] = [ 'asc' => ['CONCAT(nombre, " ", apellido)' => SORT_ASC], 'desc' => ['CONCAT(nombre, " ", apellido)' => SORT_DESC], ]; $dataProvider->sort->attributes['edad'] = [ 'asc' => ['(YEAR(CURRENT_DATE) - YEAR(fecha_nacimiento) - (RIGHT(CURRENT_DATE, 5) < RIGHT(fecha_nacimiento, 5)))' => SORT_ASC], 'desc' => ['(YEAR(CURRENT_DATE) - YEAR(fecha_nacimiento) - (RIGHT(CURRENT_DATE, 5) < RIGHT(fecha_nacimiento, 5)))' => SORT_DESC], ]; ... ... }
Con lo cual ya disponemos de las opciones de filtrado y ordenamiento por los campos virtuales en el listado del GridView: