Pongamonos en situación, tenemos un listado generado por el AdminGenerator. Decidimos añadir una nueva columna a la lista, algo tremendamente fácil con sólo añadir un nuevo getter al objeto del modelo pero …. (siempre hay un pero) no podemos ordenar por ese nuevo campo,
.
Bueno, esa situación era hasta hoy, ya que intentaré exponer lo tremendamente sencillo que es conseguir ordenar por una columna virtual.
En primer lugar, y para trabajar sobre un ejemplo “real” consideremos el archi-conocido caso en el que tenemos un modelo de datos formado por usuarios (sfGuardUser) y sus correspondientes perfiles (Profile) guardando una relación de 1:1 y teniendo la tabla Profile la siguiente estructura:
Profile:
columns:
full_name: { type: string(255) }
email: { type: string(255) }
Cómo era la situación hasta hoy
Consideremos el caso hipotético de que para el desarrollo de una aplicación tenemos que mostrar un listado con todos los usuarios con las siguientes columnas: nombre de usuario, nombre real y email. Hasta hoy, el proceso a seguir era,
1) creamos dos nuevos getter en el objeto sfGuardUser para las dos nuevas columnas virtuales:
// lib/model/sfGuardUser.class.php
<?
class sfGuardUser extends BasesfGuardUser{
public function getFullName()
{
$this->Profile->full_name;
}
public function getEmail()
{
$this->Profile->email;
}
?>
Te podías haber ahorrado definir estos getters si en lugar de esto hubieses creado directamente un proxy del objeto Profile, aunque eso es otra historia
2) Modificamos el archivo generator.yml para que muestre estos dos nuevas columnas virtuales:
list:
title: Listado de Usuarios
display: [=username, full_name, email]
3) El

pero no podríamos ordenar ni por full_name ni email … hasta hoy! Vamos allá!
Desvirtualizando los campos virtuales
Lo primero que debemos hacer es desvirtualizar los campos que eran virtuales, para ello cambiamos el método que utiliza el AdminGenerator para recoger el listado de elementos:
list:
title: Listado de Usuarios
display: [=username, full_name, email]
table_method: doSelectAdmin
debiendo de crear este método en el objeto de la tabla correspondiente
// lib/model/sfGuardUserTable.class.php
<?php
class sfGuardUserTable extends Doctrine_Table{
public static function doSelectAdmin()
{
return Doctrine_Query::create()
->select('u.username as username, p.full_name as full_name, p.email as email')
->from('sfGuardUser u')
->leftJoin('u.Profile p');
}
}
?>
Notemos que el nombre de los campos de la sentencia select coincide con el nombre de los campos en list.display.
Después de esto tendríamos el mismo resultado que en el caso anterior, sin poder seguir ordenando por estas dos nuevas columnas.
Ya no es virtual, ahora es real
Para que symfony sustituya el texto de la cabecera de la tabla por un enlace debemos de indicarle de manera explícita que estos campos son reales y no virtuales. Esto se lo indicamos en el generator.yml:
#generator.yml
fields:
full_name: { is_real: true }
email: { is_real: true }
Resulta curioso que este parámetro no venga en ningún sitio en la documentación de symfony (o al menos, yo no lo he sabido encontrar).
Con esto conseguiremos que el texto de la cabecera (i.e: “Email”, “Nombre”) sea ahora un enlace, aunque si haces click verás que no ocurre nada, esto se debe a que symfony pone una traba más que hay que sortear.
Sí, mis campos son reales y además son “ordenables”
Finalmente hay que indicarle a symfony que sí que queremos poder ordenar por esa columna, por lo que será necesario reescribir un método:
<?php
// /modules/sfGuardUser/actions/actions.class.php
class sfGuardUserActions extendes autosfGuardUserActions{
protected function isValidSortColumn($column)
{
return in_array($column, array('username', 'full_name', 'email');
}
}
?>