jueves, 3 de marzo de 2011

Relaciones Muchos a Muchos (M:N) en symfony 1.4 y Doctrine

Este es mi primer post de Symfony, mas adelante publicare muchos mas tips relacionados a este excelente framework de desarrollo en PHP.

Probando algunas cosas en symfony necesite hacer relaciones M:N en sf 1.4 con doctrine.. propel en la verison df 1.2 resolvia el asunto el solo, aparentemente 1.4 no lo hace asi... bien, supongamos que necesitamos realizar este tipo de relacion en nuestro projecto M:N, autor y libro, un autor tieme muchos libros y un libro tiene muchos autores necesariamente necesitamos una tabla intermedia parar representar este tipo de relacion..
En la vista de autor o de libro necesitamos tener un listado de libros o autores dependiendo del caso, una lista multiple, o un listado con checkboxes,

para realizar este ejemplo necesitamos la estructura (PostgreSQL):

CREATE TABLE autor
(
  id serial NOT NULL,
  descripcion text NOT NULL,
  CONSTRAINT autor_pkey PRIMARY KEY (id)
);

CREATE TABLE libro
(
  id serial NOT NULL,
  descripcion text NOT NULL,
  CONSTRAINT libro_pkey PRIMARY KEY (id)
);

CREATE TABLE autor_libro
(
  autor_id integer NOT NULL,
  libro_id integer NOT NULL,
  CONSTRAINT autor_libro_pkey PRIMARY KEY (autor_id, libro_id),
  CONSTRAINT autor_libro_autor_id_fkey FOREIGN KEY (autor_id)
      REFERENCES autor (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT autor_libro_libro_id_fkey FOREIGN KEY (libro_id)
      REFERENCES libro (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
);
creamos nuestro proyecto, aplicacion, realizamos la conexion a BD y generamos el modelo, filtros y formularios, notamos que efectivamente en la vista de autor y de libro no existe referencia a la tabla intermedia...
symfony generate:project proy
symfony generate:app app
symfony configure:database "pgsql:host=localhost;dbname=proy_db" u_test 123456
symfony doctrine:build-schema
symfony doctrine:build --model
symfony doctrine:build --filters
symfony doctrine:build --forms
symfony doctrine:generate-module --with-show  app libro Libro
symfony doctrine:generate-module --with-show  app autor Autor
symfony cc
como solucionamos esto.. bien.. el schema original de la primera corrida es algo asi...

lo q tenemos q mejorar es lo referente a la relacion que representa el schema de la siguiente manera...
Autor:
  connection: doctrine
  tableName: autor
  columns:
    id:
      ....
    descripcion:
      ....
  relations:
    AutorLibro:
      local: id
      foreign: autor_id
      type: many

si lo que queremos es que en la vista de autor nos muestre un listado de libros para hacer una seleccion multiple tenemos que modificar la parte de la relacion de la tabla autor.
ahora quedara asi
Autor:
  connection: doctrine
  tableName: autor
  columns:
    id:
      ....
    descripcion:
      ....
  relations:
    Libro:
      class: Libro
      refClass: AutorLibro
      local: autor_id
      foreign: libro_id

posterior a esto lo q debemos hacer es ejecutar modelo, filtros, formulario y regenerar el modulo autor
symfony doctrine:build --model
symfony doctrine:build --filters
symfony doctrine:build --forms
symfony doctrine:generate-module --with-show  app autor Autor
symfony cc
Chequea nuevamente la vista y observamos una lista multiple donde se listaran todos los libros..
OJO, si modificas la estructura de datos y necesitas generar nuevamente el schema se perderan los cambios realizados en la tabla autor... algo malo a mi parecer.. debe haber algun plugin que realice algo de esto.. pero bueee...

si necesitas cambiar esa lista multiple solo deberas cambiar el widget y listo...

si tienes el plugin sfFormExtraPlugin instalado, solo agrega en /lib/form/doctrine/AutorForm.class.php:
$this->widgetSchema['libro_list']->setOption('renderer_class', 'sfWidgetFormSelectDoubleList');

tambien puedes cambiar lo que muestra en la lista agregando algunas validaciones de la consulta o mostrar checkboxes.. pero eso lo veremos luego en otro articulo..
la referencia de todo esto q explico lo puedes conseguir Aqui