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

4 comentarios:

  1. Excelente!!! me sirvio como no imaginas, gracias, colocaré en mi blog de informatica un link para que vean tu explicación los que andan aprendiendo symfony como yo. Sigue asi.

    ResponderEliminar
  2. Amigo ante todo disculpa por hacer este comentario a modo de pregunta...yo se que para eso existen los blogs...y esas cosas pero ya he pedido ayuda donde quiera y no me han podido ayudar..pero bueno..este es mi problema

    Trabajo con MySQL y Symfony 1.4.9 + Doctrine...
    Tengo tres tablas.....

    CesIngreso:
    actAs: { Timestampable: ~ }
    columns:
    nombre: { type: string(7), notnull: true, unique: true }
    - En la cual almaceno dos datos, que son los ingresos (Entrada, Salida)

    CesSecciones:
    columns:
    secciones: { type: string(50), notnull: true}
    start: { type: time }
    end: { type: time }
    - Almaceno tres datos mas las horas de inicio y fin de cada Seccion ,Sesiones (Mañana, Tarde, Extraordinaria)

    CesUser:
    columns:
    foto: { type: string(255) }
    user: { type: string(30), notnull: true}
    nombre: { type: string(50), notnull: true}
    apeuno: { type: string(50), notnull: true}
    apedos: { type: string(50), notnull: true}
    fecha: { type: date, notnull: true}
    - Almaceno los datos de los Usuarios ( n cantidad de usuarios)

    Necesito crear un formulario de Registro de Asistencia...para
    registrar la asistencia de los usuarios que esten registrados en el systema...pero lo más importante es
    que necesito que los usuarios cuando vayan a registrar su
    asistencia.....solamente me puedan registrar 1 Entrada y 1 Salida(CesIngreso) para cada seccion (Mañana, Tarde, Extraordinaria)diariamente...
    Amigo yo he tratado de hacerlo de diferentes formas, pero no logro hacer que un usuario solamente pueda guardar 1 Entrada y 1 Salida para cada sesion de trabajo en el día.....
    El formulario solo debe de llevar....Usuarios, Sección, Ingreso....y lo que deseo hacer es que por ejemplo el usuario Pepe...cuando se vaya a registrar su asistencia en la Sección (Mañana, Tarde, Extra), si ya ha registrado una entrada en la Mañana solamente me pueda registrar la salida y así para cada seccion...
    Espero me haya sabido explicar....y muchas gracias de
    antemano....cualquier ayuda o idea será bienvenida...y disculpa si no debía preguntarte aquí...saludos

    ResponderEliminar
    Respuestas
    1. en la tabla CesIngreso solo tienes el campo nombre?? deberias tener el id del usuario y el id de la seccion.. luego como garantizar q el usuario X pueda hacer ingreso y egreso? facil.. validando si el usuario tiene ingreso antes de hacer un egreso.. antes de mostrar el formulario haces esa validacion con una consulta simple a la bd.. no es tan complicado lo q debes hacer..

      Eliminar
  3. Hola amigos, yo tengo un problema también con las relación de muchos a muchos y es que tengo una tabla Trabajador y otra tabla Cargo, en las que un trabajador puede tener varios cargos y un cargo le perteneces a muchos trabajadores, pero en la tabla Trabajador_Cargo exite un campo fecha el cual me sirve para saber en que fecha estuvo en ese cargo el trabajador y no se como hacer para que el formulario de esta tabla ( Trabajador_Cargo ) me permita seleccionar el trabajador y el cargo...

    Espero que me puedan ayudar

    Este es mi correo: jsalas@sc.uci.cu

    ResponderEliminar