Foros del Web » Programando para Internet » PHP » Frameworks y PHP orientado a objetos »

Relaciones con Doctrine 2

Estas en el tema de Relaciones con Doctrine 2 en el foro de Frameworks y PHP orientado a objetos en Foros del Web. Hola, como estan todos, la idea es que tengo en mi base una tabla usuarios y otra perfiles. Donde un usuario puede tener solo un ...
  #1 (permalink)  
Antiguo 13/10/2012, 12:09
Avatar de portalmana  
Fecha de Ingreso: septiembre-2007
Ubicación: Montevideo-Uruguay
Mensajes: 633
Antigüedad: 17 años, 1 mes
Puntos: 80
Relaciones con Doctrine 2

Hola, como estan todos, la idea es que tengo en mi base una tabla usuarios y otra perfiles.
Donde un usuario puede tener solo un perfil.
Pero un perfil puede tener muchos Usuarios asociados.
USUARIOS
Código SQL:
Ver original
  1. CREATE TABLE `usuarios` (
  2.     `usuario` VARCHAR(30) NOT NULL DEFAULT '',
  3.     `correo` VARCHAR(210) NOT NULL,
  4.     `nombre_usuario` VARCHAR(50) NOT NULL,
  5.     `clave` VARCHAR(50) NOT NULL,
  6.     `id_perfil` INT(50) NOT NULL,
  7.     PRIMARY KEY (`usuario`),
  8.     INDEX `FK_usuarios_perfiles` (`id_perfil`),
  9.     CONSTRAINT `FK_usuarios_perfiles` FOREIGN KEY (`id_perfil`) REFERENCES `perfiles` (`id_perfil`) ON UPDATE CASCADE
  10. )
  11. COMMENT='Modulo Autenticacion'
  12. COLLATE='utf8_general_ci'
  13. ENGINE=InnoDB;
PERFILES
Código SQL:
Ver original
  1. CREATE TABLE `perfiles` (
  2.     `id_perfil` INT(10) NOT NULL AUTO_INCREMENT,
  3.     `perfil` VARCHAR(50) NOT NULL,
  4.     PRIMARY KEY (`id_perfil`),
  5.     UNIQUE INDEX `perfil` (`perfil`)
  6. )
  7. COMMENT='Modulo Autenticacion\r\n'
  8. COLLATE='utf8_general_ci'
  9. ENGINE=InnoDB

Luego tengo las Entidades
Código PHP:
Ver original
  1. /**
  2.  * @Entity
  3.  * @Table(name="perfiles")
  4.  **/
  5. class Perfil
  6. {
  7.     /**
  8.      * @Id
  9.      * @GeneratedValue (strategy="AUTO")
  10.      * @Column(type="integer", name="id_perfil")
  11.      **/
  12.     protected $id;
  13.    
  14.     /** @Column(type="string", length=50) **/
  15.     protected $perfil;
  16.    
  17.     /**
  18.      * @OneToMany(targetEntity="Usuario", mappedBy="perfil", cascade={"persist"})
  19.      */
  20.     protected $usuarios;
  21.  
  22.     public function __construct()
  23.     {
  24.         $this->usuarios = new \Doctrine\Common\Collections\ArrayCollection();
  25.     }
  26.    
  27.     /**
  28.      * Agrego un Usuario al Perfil.
  29.      * @param \modulos\acceso\models\Usuario $usuario
  30.      */
  31.     public function addUsuario(Usuario $usuario)
  32.     {
  33.         $this->usuarios[] = $usuario;
  34.     }
Código PHP:
Ver original
  1. /**
  2.  * @Entity
  3.  * @Table(name="usuarios")
  4.  **/
  5. class Usuario
  6. {
  7.     /**
  8.      * @Id
  9.      * @Column(type="string", length=30)
  10.      **/
  11.     protected $usuario;
  12.    
  13.     /**
  14.      * @Column(type="string", length=210)
  15.      **/
  16.     protected $correo;
  17.    
  18.     /**
  19.      * @Column(type="string", length=50, name="nombre_usuario")
  20.      **/
  21.     protected $nombre;
  22.    
  23.     /**
  24.      * @Column(type="string", length=50)
  25.      **/
  26.     protected $clave;
  27.    
  28.     /**
  29.      * @OneToOne(targetEntity="Perfil", inversedBy="usuarios", fetch="EAGER")
  30.      * @JoinColumn(name="id_perfil", referencedColumnName="id_perfil")
  31.      */
  32.     protected $perfil;
  33.    
  34.     public function __construct()
  35.     {
  36.        $this->perfil = New \Doctrine\Common\Collections\ArrayCollection();
  37.     }
Cada clase con sus setters y getters.

La situacion es que Eliminar y Crear un nuevo Usuario lo realiza bien, el problema es cuando tengo que actualizar un nuevo usuario, me da el siguiente error:

Código PHP:
Ver original
  1. Mensaje : A new entity was found through the relationship 'modulos\acceso\models\Usuario#perfil' that was not configured to cascade persist operations for entity: modulos\acceso\models\Perfil@00000000404b9edd000000004c14202d. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist  this association in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'modulos\acceso\models\Perfil#__toString()' to get a clue.
Se supone que es un error en el mapeo de las entidades, pero he probado varias posibilidades y nada.

La pregunta es como seria el codigo correcto para actualizar con Doctrine o si, es solo error de mapeo.

Gracias
__________________
"La imaginación es más importante que el conocimiento. El conocimiento es limitado, mientras que la imaginación no" -- A.Einstein
objetivophp.com,twitter.com/objetivophp
  #2 (permalink)  
Antiguo 13/10/2012, 12:25
Avatar de masterpuppet
Software Craftsman
 
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 3.550
Antigüedad: 16 años, 9 meses
Puntos: 845
Respuesta: Relaciones con Doctrine 2

Comprueba la metadata, de un lado estas haciendo onetomany y del otro onetoone cuando debería ser manytoone, setea correctamente la relación y nos comentas.
__________________
http://es.phptherightway.com/
thats us riders :)
  #3 (permalink)  
Antiguo 13/10/2012, 12:36
Avatar de portalmana  
Fecha de Ingreso: septiembre-2007
Ubicación: Montevideo-Uruguay
Mensajes: 633
Antigüedad: 17 años, 1 mes
Puntos: 80
Respuesta: Relaciones con Doctrine 2

Si eso ya lo habia probado es que estaba dando manotazos de ahogado pero igual no funciona cambiando la relacion.
Lo que funciona es Nuevo usuario y Borrar el Usuario. El actualizar no lo hace.

Gracias
__________________
"La imaginación es más importante que el conocimiento. El conocimiento es limitado, mientras que la imaginación no" -- A.Einstein
objetivophp.com,twitter.com/objetivophp
  #4 (permalink)  
Antiguo 13/10/2012, 13:26
Avatar de masterpuppet
Software Craftsman
 
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 3.550
Antigüedad: 16 años, 9 meses
Puntos: 845
Respuesta: Relaciones con Doctrine 2

En la entidad Usuario perfil no es una colección sino uno asociación con la entidad Perfil, como estas seteando el perfil a un usuario ?
__________________
http://es.phptherightway.com/
thats us riders :)
  #5 (permalink)  
Antiguo 13/10/2012, 13:42
Avatar de portalmana  
Fecha de Ingreso: septiembre-2007
Ubicación: Montevideo-Uruguay
Mensajes: 633
Antigüedad: 17 años, 1 mes
Puntos: 80
Respuesta: Relaciones con Doctrine 2

Exacto porque un usuario solo puede tener un perfil (administrador, moderador, leector, invitado etc)

Código PHP:
Ver original
  1. /**
  2.      * @OneToMany(targetEntity="Usuario", mappedBy="perfil", cascade={"persist"})
  3.      */
  4.     protected $usuarios;
  5.  
  6.     public function __construct()
  7.     {
  8.         $this->usuarios = new \Doctrine\Common\Collections\ArrayCollection();
  9.     }
  10.    
  11.     /**
  12.      * Agrego un Usuario al Perfil.
  13.      * @param \modulos\acceso\models\Usuario $usuario
  14.      */
  15.     public function addUsuario(Usuario $usuario)
  16.     {
  17.         $this->usuarios[] = $usuario;
  18.     }

se que tiene que ver con la cascada o no defino bien el propietario de la relacion.
La idea basica es que un usuario tiene un perfil pero el perfil puede estar en muchos usuarios. Entonces en Perfil tengo una coleccion de usuarios.

Saludos
__________________
"La imaginación es más importante que el conocimiento. El conocimiento es limitado, mientras que la imaginación no" -- A.Einstein
objetivophp.com,twitter.com/objetivophp
  #6 (permalink)  
Antiguo 13/10/2012, 14:07
Avatar de masterpuppet
Software Craftsman
 
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 3.550
Antigüedad: 16 años, 9 meses
Puntos: 845
Respuesta: Relaciones con Doctrine 2

Lo que estas mostrando es el perfil yo te pregunto por el Usuario, en el primer post Usuario::perfil lo tienes como ArrayCollection o al menos eso parece por el constructor, cuando debería ser del tipo Perfil(en la entidad Usuario getPerfil, setPerfil) por eso te pregunto como lo estas haciendo, como le asignas un perfil a un usuario.
__________________
http://es.phptherightway.com/
thats us riders :)
  #7 (permalink)  
Antiguo 13/10/2012, 14:27
Avatar de portalmana  
Fecha de Ingreso: septiembre-2007
Ubicación: Montevideo-Uruguay
Mensajes: 633
Antigüedad: 17 años, 1 mes
Puntos: 80
Respuesta: Relaciones con Doctrine 2

si es un arrayCollection.
Pero voy a terminar haciéndolo con dql esa parte que es mas fácil.

Saludos y Muchas Gracias
__________________
"La imaginación es más importante que el conocimiento. El conocimiento es limitado, mientras que la imaginación no" -- A.Einstein
objetivophp.com,twitter.com/objetivophp
  #8 (permalink)  
Antiguo 13/10/2012, 14:52
Avatar de masterpuppet
Software Craftsman
 
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 3.550
Antigüedad: 16 años, 9 meses
Puntos: 845
Respuesta: Relaciones con Doctrine 2

Utilizar DQL no va a cambiar el hecho de que esta mal definida la relación, no es una solución sino un parche que te puede(seguramente lo haga) traer dolores de cabeza después, fuera de que lo lógico seria comprender como funciona la herramienta que estas utilizando, pero bueno, esto último va en cada uno, de cualquier manera te dejo un ejemplo de como podría ser:

Código PHP:
Ver original
  1. class User
  2. {
  3.     /**
  4.      * @var Profile $profile    
  5.      * @ORM\ManyToOne(targetEntity="Profile", inversedBy="users", cascade={"persist"})      
  6.      */
  7.     private $profile;
  8.     public function setProfile(Profile $p)
  9.     {
  10.         $p->addUser($this);
  11.         $this->profile = $p;
  12.     }
  13.     public function getProfile()
  14.     {
  15.         return $this->profile;
  16.     }
  17. }
  18.  
  19. class Profile
  20. {
  21.     /**    
  22.      * @var ArrayCollection
  23.      * @ORM\OneToMany(targetEntity="User", mappedBy="profile", cascade={"persist"})
  24.      */
  25.     private $users;
  26.     public function addUser(User)
  27.     {
  28.         $this->users[] = $user;
  29.     }    
  30.     public function getUsers()
  31.     {
  32.         return $this->users;
  33.     }
  34. }

suerte,

Saludos.
__________________
http://es.phptherightway.com/
thats us riders :)
  #9 (permalink)  
Antiguo 13/10/2012, 15:33
Avatar de portalmana  
Fecha de Ingreso: septiembre-2007
Ubicación: Montevideo-Uruguay
Mensajes: 633
Antigüedad: 17 años, 1 mes
Puntos: 80
Respuesta: Relaciones con Doctrine 2

La idea es esa, conocer un poco de Doctrine. Es para un proyecto personal. El problema es que ya he probado de todas las formas posibles y siempre me hace lo mismo. Inserta y Borra bien pero no actualiza.

En la base de datos las tablas son Inodb y esta restringido que el perfil sea único. Si yo saco eso me actualiza pero me genera un nuevo perfil.
Es decir lo que me hace es actualiza el usuario y me inserta un perfil nuevo.

Intente de actualizar solo desde la entidad usuario, y tambien lo hice desde perfil pero no logro el comportamiento deseado.

Gracias...
__________________
"La imaginación es más importante que el conocimiento. El conocimiento es limitado, mientras que la imaginación no" -- A.Einstein
objetivophp.com,twitter.com/objetivophp
  #10 (permalink)  
Antiguo 13/10/2012, 16:07
Avatar de masterpuppet
Software Craftsman
 
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 3.550
Antigüedad: 16 años, 9 meses
Puntos: 845
Respuesta: Relaciones con Doctrine 2

Te animas a postear el código completo de las entidades y el cual estés utilizando procesarlas ?
__________________
http://es.phptherightway.com/
thats us riders :)
  #11 (permalink)  
Antiguo 13/10/2012, 16:19
Avatar de portalmana  
Fecha de Ingreso: septiembre-2007
Ubicación: Montevideo-Uruguay
Mensajes: 633
Antigüedad: 17 años, 1 mes
Puntos: 80
Respuesta: Relaciones con Doctrine 2

Código PHP:
Ver original
  1. <?php
  2. namespace modulos\acceso\models;
  3.  
  4. /**
  5.  * @Entity
  6.  * @Table(name="usuarios")
  7.  **/
  8. class Usuario
  9. {
  10.     /**
  11.      * @Id
  12.      * @Column(type="string", length=30)
  13.      **/
  14.     protected $usuario;
  15.    
  16.     /**
  17.      * @Column(type="string", length=210)
  18.      **/
  19.     protected $correo;
  20.    
  21.     /**
  22.      * @Column(type="string", length=50, name="nombre_usuario")
  23.      **/
  24.     protected $nombre;
  25.    
  26.     /**
  27.      * @Column(type="string", length=50)
  28.      **/
  29.     protected $clave;
  30.    
  31.     /**
  32.      * @ManyToOne(targetEntity="Perfil", inversedBy="usuarios", cascade={"persist"}, fetch="EAGER")
  33.      * @JoinColumn(name="id_perfil", referencedColumnName="id_perfil")
  34.      */
  35.     protected $perfil;
  36.    
  37.     public function __construct()
  38.     {
  39.        $this->perfil = new Perfil();
  40.     }
  41.    
  42.     /** GETERS */
  43.     public function getUsuario()    { return $this->usuario; }
  44.     public function getCorreo()     { return $this->correo; }
  45.     public function getNombre()     { return $this->nombre; }
  46.     public function getClave()      { return $this->clave; }
  47.     public function getPerfil()     { return $this->perfil; }
  48.    
  49.     /** SETERS */
  50.     public function setUsuario($usuario)    { $this->usuario    = $usuario; }
  51.     public function setCorreo($correo)      { $this->correo     = $correo; }
  52.     public function setNombre($nombre)      { $this->nombre     = $nombre; }
  53.     public function setClave($clave)        { $this->clave      = $clave; }
  54.    
  55.     public function setPerfil(Perfil $perfil)
  56.     {
  57.         $perfil         ->addUsuario($this);
  58.         $this->perfil   = $perfil;
  59.     }
  60.  
  61. }
Código PHP:
Ver original
  1. <?php
  2. namespace modulos\acceso\models;
  3.  
  4. /**
  5.  * @Entity
  6.  * @Table(name="perfiles")
  7.  **/
  8. class Perfil
  9. {
  10.     /**
  11.      * @Id
  12.      * @GeneratedValue (strategy="AUTO")
  13.      * @Column(type="integer", name="id_perfil")
  14.      **/
  15.     protected $id;
  16.    
  17.     /** @Column(type="string", length=50) **/
  18.     protected $perfil;
  19.    
  20.     /**
  21.      * @OneToMany(targetEntity="Usuario", mappedBy="perfil", cascade={"persist"})
  22.      */
  23.     protected $usuarios;
  24.  
  25.     public function __construct()
  26.     {
  27.         $this->usuarios = new \Doctrine\Common\Collections\ArrayCollection();
  28.     }
  29.    
  30.     /**
  31.      * Agrego un Usuario al Perfil.
  32.      * @param \modulos\acceso\models\Usuario $usuario
  33.      */
  34.     public function addUsuario(Usuario $usuario)
  35.     {
  36.         $this->usuarios[] = $usuario;
  37.     }
  38.    
  39.    
  40.     /** GETERS */
  41.     public function getId()         { return $this->id; }
  42.     public function getPerfil()     { return $this->perfil; }
  43.     public function getUsuario()    { return $this->usuario; }
  44.    
  45.     /** SETERS */
  46.     public function setId($id)              { $this->id         = $id; }
  47.     public function setPerfil($perfil)      { $this->perfil     = $perfil; }
  48.     public function setUsuarios($usuario)   { $this->usuario    = $usuario; }  
  49.    
  50.     /** Funciones Especiales */
  51.     public function toArray()
  52.     {
  53.         return get_object_vars($this);
  54.     }
  55.  
  56. }

Estas son las entidades
Estas es una de las formas que intente para guardar.
Generar un objeto Perfil agregarle el Usuario y luego persistirlo
Código PHP:
Ver original
  1. // Traigo un Usuario
  2. $usuario =  $this->_ormManager->find('\modulos\acceso\models\Usuario',$id);
  3.                $usuario->setCorreo($valores['correo']);
  4.                $usuario->setNombre($valores['nombre']);
  5.                $usuario->setClave($valores['clave']);
  6.                $usuario->setPerfil($perfiles->getPerfilById($valores['idPerfil']));
  7.                
  8.                $perfil = $this->_ormManager->find('\modulos\acceso\models\Perfil',$id);
  9.                $perfil->addUsuario($usuario);
  10.                $this->_ormManager->persist($perfil);
  11.               $this->_ormManager->flush();

Esta es la mas rebuscada.
La otra es ir solo contra Usuario

Gracias
__________________
"La imaginación es más importante que el conocimiento. El conocimiento es limitado, mientras que la imaginación no" -- A.Einstein
objetivophp.com,twitter.com/objetivophp
  #12 (permalink)  
Antiguo 13/10/2012, 17:30
Avatar de masterpuppet
Software Craftsman
 
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 3.550
Antigüedad: 16 años, 9 meses
Puntos: 845
Respuesta: Relaciones con Doctrine 2

Tal cual esta a mi me funciona correctamente tanto para editar como crear usuarios nuevos, el único problema que veo tal cual lo tienes es que si no seteas un perfil te va a lanzar una excepcion porque estas creando en el constructor un nuevo perfil sin nombre.

Lo teste con el siguiente código:

Código PHP:
Ver original
  1. $usuario =  new Usuario;       
  2. //$usuario = $em->find('Usuario', '5079f24a36791');    
  3. $usuario->setCorreo('correo');
  4. $usuario->setNombre('nombre');
  5. $usuario->setClave('clave');
  6.  
  7. $perfil = $em->find('Perfil', 1);
  8. if(null === $perfil){
  9.     $perfil = new Perfil;
  10.     $perfil->setPerfil('guest'.rand());
  11. }
  12. $usuario->setPerfil($perfil);            
  13. $em->persist($usuario);
  14. $em->flush();
__________________
http://es.phptherightway.com/
thats us riders :)
  #13 (permalink)  
Antiguo 14/10/2012, 08:16
Avatar de portalmana  
Fecha de Ingreso: septiembre-2007
Ubicación: Montevideo-Uruguay
Mensajes: 633
Antigüedad: 17 años, 1 mes
Puntos: 80
Respuesta: Relaciones con Doctrine 2

Disculpa la demora es que ayer me tuve que ir y regrese ahora con esto.

Si efectivamente así Funciona...
Código PHP:
Ver original
  1. $usuario = $em->find('Usuario', $idUsuario);
  2. $perfil     = $em->find('Perfil', $idPerfil);
  3.  
  4. $usuario->setCorreo($valores['correo']);
  5. $usuario->setNombre($valores['nombre']);
  6. $usuario->setClave($valores['clave']);
  7. $usuario->setPerfil($perfil);
  8.  
  9. $em->persist($usuario);
  10. $em->flush();

Muchisimas gracias por la Ayuda.
Y hasta la próxima, que en Doctrine estoy muy Verde un par de días llevamos.

Saludos
__________________
"La imaginación es más importante que el conocimiento. El conocimiento es limitado, mientras que la imaginación no" -- A.Einstein
objetivophp.com,twitter.com/objetivophp
  #14 (permalink)  
Antiguo 14/10/2012, 08:27
Avatar de masterpuppet
Software Craftsman
 
Fecha de Ingreso: enero-2008
Ubicación: Montevideo, Uruguay
Mensajes: 3.550
Antigüedad: 16 años, 9 meses
Puntos: 845
Respuesta: Relaciones con Doctrine 2

Genial, de todas formas de comento algo interesante, cuando tienes el identificador de la entidad a relacionar(en este caso idPerfil) se suele utilizar Reference Proxy ;)

Saludos.
__________________
http://es.phptherightway.com/
thats us riders :)
  #15 (permalink)  
Antiguo 14/10/2012, 08:40
Avatar de portalmana  
Fecha de Ingreso: septiembre-2007
Ubicación: Montevideo-Uruguay
Mensajes: 633
Antigüedad: 17 años, 1 mes
Puntos: 80
Respuesta: Relaciones con Doctrine 2

Cita:
Iniciado por masterpuppet Ver Mensaje
Genial, de todas formas de comento algo interesante, cuando tienes el identificador de la entidad a relacionar(en este caso idPerfil) se suele utilizar Reference Proxy ;)

Saludos.
Ya lo cambie y funciona perfecto. Por lo que leí mejora el rendimiento.
Muchas gracias por tus aportes.

Saludos
__________________
"La imaginación es más importante que el conocimiento. El conocimiento es limitado, mientras que la imaginación no" -- A.Einstein
objetivophp.com,twitter.com/objetivophp

Etiquetas: doctrine, relaciones, tabla, usuarios
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta

SíEste tema le ha gustado a 1 personas




La zona horaria es GMT -6. Ahora son las 04:39.