Trabajando con filtros en Symfony (I)

Esta es una entrada bastante rápida, pero que busca mostrar la forma básica en que se pueden usar los formularios de filtros en Symfony (versión 1.2) para facilitar a los usuarios la clasificación y consulta de información.  El manejo de formularios de filtros es muy similar a los formularios que se usan para el ingreso y/o edición de información,  con algunas variaciones. Hago claridad que las pruebas que he realizado han sido usando Propel como ORM.

Bien, empecemos por saber que en Symfony existe una tarea que nos permite construir en forma automática los formularios de filtros, de la siguiente forma:

$ php symfony propel:build-filters

Después de la ejecución de esta tarea, en el directorio lib/filters de nuestro proyecto, se habrán creado (de acuerdo a nuestro modelo) un conjunto de clases cuyo nombre sigue la siguiente nomenclatura:

ClaseFormFilter.class.php

y al igual que con el modelo y los formularios, tendremos unas clases Base y unas clases que extenderán de esas clases base, las cuales podemos adaptar según nuestras necesidades. Una vez creadas nuestras clases de formularios de filtros, ya podemos usarlas dentro de nuestras acciones. Tomaré como ejemplo, que tenemos un modulo llamado clientes que permite trabajar con el CRUD normal y que cada cliente tiene un nombre, telefono y una ciudad, de modo que nuestra clase base de formulario de filtro lucirá así:

class BaseClienteFormFilter extends BaseFormFilterPropel
{
  public function setup()
 
  {
     $this->setWidgets(array(
      'nombre'    => new sfWidgetFormFilterInput(),
      'telefono'  => new sfWidgetFormFilterInput(),
      'ciudad_id' => new sfWidgetFormPropelChoice(array(
            'model' => 'Ciudad', 'add_empty' => true))
       ));
 
   $this->setValidators(array(
    'nombre'    => new sfValidatorPass(array('required' => false)),
    'telefono'  => new sfValidatorPass(array('required' => false)),
    'ciudad_id' => new sfValidatorPropelChoice(array('required' => false,
                                 'model' => 'Ciudad', 'column' => 'id')),
   ));
 
   $this->widgetSchema->setNameFormat('cliente_filters[%s]');
   $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
   parent::setup();
  }
 
  public function getModelName()
  {
    return 'Cliente';
  }
 
  public function getFields()
  {
    return array(
     'id'        => 'Number',
     'nombre'    => 'Text',
     'telefono'  => 'Text',
     'ciudad_id' => 'ForeignKey',
   );
  }
}

Tengamos en cuenta que esta clase es generada automáticamente y podemos hacer las modificaciones necesarias en la clase ClienteFormFilter, como se hace con los formularios.  Ahora bien, vamos a utilizar este formulario de filtro en nuestra acción index de nuestro módulo de clientes, de la siguiente forma:

class clientesActions extends sfActions
{
  public function executeIndex(sfWebRequest $request)
  {
     // creamos el filtro ....
     $this->filtro = new ClienteFormFilter();
     // .....
     // más código ....
     // Típica consulta  ....
     $this->clientes = CientePeer::doSelect(new Criteria());
  }
}

En nuestra plantilla: (indexSuccess.php)

<form action="&lt;?php echo url_for('clientes/filtrar'); ?&gt;" method="post">
 
<table>
<tbody></tbody>
</table>
 
<input name="filtrar" type="submit" value="Filtrar" />
</form>
 
// otro codigo html ....

Bien, hasta aquí nada nuevo, simplemente un formulario más, que aparecerá en nuestra acción index de nuestro módulo de clientes, pero con la diferencia que será procesado por la acción filtrar (o como decida llamarse). En este punto es importante mencionar, que para la ejecución del filtrado, se empleará el método buildCriteria, el cuál recibe como parámetro un arreglo (los campos por  los  cuales se desea hacer el filtro) y se encarga de construir las consultas:

public function executeFiltrar(sfWebRequest $request)
{
  $this-&gt;filtro = new ClienteFormFilter();
  // Construye un objeto criteria con el valor de los filtros
  $criteria = $this-&gt;filtro-&gt;buildCriteria($request-&gt;getParameter('cliente_filters'));
  $this-&gt;clientes = ClientePeer::doSelect($criteria);
  $this-&gt;setTemplate('index');
}

El método buildCriteria es el encargado de construir la consulta según el valor de los filtros (revise la clase sfFormFilterPropel y los métodos addXXXCriteria() de la misma clase). Posteriormente pasamos ese objeto criteria a el método doSelect para devolver la consulta filtrada usando la plantilla de la acción index.  Sencillo, no ??

En una próxima entrada se explicará lo referente al manejo de formularios de filtro y el mantenimiento de los resultados obtenidos por el filtro entre páginas.

Tags: ,

13 De respuestas a “Trabajando con filtros en Symfony (I)”

  1. Juan Carlos Romero 14 septiembre, 2009 en 7:04 AM #

    Hola, muy buen post, espero con impaciencia el segundo, para pasar los parametros de los filtros entre paginas.
    Saludos

  2. Camilo Nova 14 septiembre, 2009 en 8:29 AM #

    Muy fácil, es interesante que se puedan automatizar estas tareas que se repiten proyecto tras proyecto así el desarrollador se concentra en los detalles mas importantes.

    También espero ver la otra entrega de filtros.

  3. Juan Pablo Romero Bernal 14 septiembre, 2009 en 10:04 AM #

    Muchas gracias por los comentarios. En breve, espero publicar la segunda parte del manejo de formularios de filtro.

  4. Moises 17 septiembre, 2009 en 12:12 AM #

    Oye muy interesante el post, sobre todo porque la documentacion de los filtros es escasa. Seria posible que mostraras como realizar ese mismo ejemplo con doctrine? porque la ultima parte ($this->clientes = ClientePeer::doSelect($criteria)) no supe como hacerla en doctrine, muchas gracias

  5. Maria Torres 17 septiembre, 2009 en 12:12 AM #

    Concuerdo en que lo has explicado de una manera fácil y que el tema es muy interesante :) . Felicitaciones por tu post!. Por otro lado quisiera preguntarte cómo se haria esto en doctrine. Lo que no tengo idea es como transformar estas dos instrucciones de propel a doctrine:

    $criteria = $this->filtro->buildCriteria($request->getParameter(‘cliente_filters’));

    $this->clientes = ClientePeer::doSelect($criteria);

    Si alguien pudiese explicarme se lo agradeceria muchisimo. Soy nueva en Symfony, asi que disculpen si pregunto algo que quizas para los que tienen más tiempo es obvio :(

  6. Juan Pablo Romero Bernal 17 septiembre, 2009 en 2:52 PM #

    Moises y María, muchas gracias por sus comentarios y sugerencias. Espero tener lo más pronto documentación del uso de filtros con Doctrine.

  7. Camilo Nova 20 septiembre, 2009 en 7:07 PM #

    Ya tenemos una segunda entrega, la pueden ver en http://axiacore.com/blog/2009/09/trabajando-con-filtros-en-symfony-ii/

  8. Jorge Chávez 10 marzo, 2010 en 2:25 PM #

    Excelente post! Sin duda los filtros son un problema con la falta de documentación oficial, pero en lo bueno es que comparten similitudes con los forms.
    Tu ejemplo me ha ayudado mucho a comprender y además es mucho más sencillo que analizar el código creado automáticamente por el admin generator :)

  9. Alcides Rausseo 9 abril, 2010 en 4:18 PM #

    Muy Buen post! me ha servido de mucho espero el siguiente post donde se mantiene el filtrado al navegar por las paginas pasando los parametros del filtro

  10. Maria 18 mayo, 2010 en 7:31 PM #

    Saludos!

    Estoy tratando de hacer los filtro con propel, pero tengo un campo created_at y me da un error: Array to string conversion … ¿? me estoy perdiendo de algo?

    Gracias

  11. Supialo 4 agosto, 2010 en 5:45 AM #

    Hola,
    Estoy haciendo un proyecto Symfony 1.4 + Propel y necesito usar los filtros en el frontend, asi que estaba contento de haber encontrado este tutorial…
    He seguido todos los pasos del tutorial y me da este error:

    Catchable fatal error: Argument 1 passed to sfFormFilterPropel::buildCriteria() must be an array

    Como es obvio no le paso bien el parametro a la accion Filtrar, no le paso un array. Alguien me puede explicar como se hace? No entiendo bien de donde sale el cliente_filters en “getParameter(‘cliente_filters’)” y donde tengo que declararlo.

    Muchas gracias!!!
    Supialo
    PD: espero que alguien lea esto pronto…

  12. Manu 25 noviembre, 2010 en 2:46 AM #

    muchas gracias por darte el tiempo de explicar algo muy poco documentado.
    saludos desde chile.

  13. martias 5 marzo, 2011 en 11:41 AM #

    you must define a “add_csrfTokenColumnCriteria” method to be able to filter with the “_csrf_token” field.

Deja una respuesta