0

I have 2 entities. The simple logic is that a user has many delivery address, so in the future they will be able to choose one of them for their deliveries.

First entity, Direccion (address).

<?php 

use Doctrine\ORM\Mapping as ORM;

/**
 * Direccion
 *
 * @ORM\Table(name="direccion", indexes={@ORM\Index(name="id_usuario", 
columns={"id_usuario"})})
 * @ORM\Entity
 */
class Direccion
{
    /**
     * @var string
     *
     * @ORM\Column(name="Calle", type="string", length=100, nullable=false)
     */
    private $calle;        

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var \Usuario
     *
     * @ORM\ManyToOne(targetEntity="Usuario", inversedBy="direcciones",  fetch="EAGER")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="id_usuario", referencedColumnName="id" )
     * })
     */
    private $idUsuario;


    /**
     * Set calle
     *
     * @param string $calle
     * @return Direccion
     */
    public function setCalle($calle)
    {
        $this->calle = $calle;

        return $this;
    }

    /**
     * Get calle
     *
     * @return string 
     */
    public function getCalle()
    {
        return $this->calle;
    }

    
    /**
     * Set idUsuario
     *
     * @param \Usuario $idUsuario
     * @return Direccion
     */
    public function setIdUsuario(\Usuario $idUsuario = null)
    {
        $this->idUsuario = $idUsuario;

        return $this;
    }

    /**
     * Get idUsuario
     *
     * @return \Usuario 
     */
    public function getIdUsuario()
    {
        return $this->idUsuario;
    }

}

and the second entity is, Usuario (User)

<?php



use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
 * Usuario
 *
 * @ORM\Table(name="usuario")
 * @ORM\Entity
 */
class Usuario
{


    /**
     * @var string
     *
     * @ORM\Column(name="nombre", type="string", length=255, nullable=true)
     */
    private $nombre;


    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;


    /**
     * @ORM\OneToMany(targetEntity="Direccion", mappedBy="id_usuario", cascade={"persist"})
     */
    private $direcciones;


    public function __construct()
    {
        $this->direcciones = new \Doctrine\Common\Collections\ArrayCollection();
    }

    

    /**
     * Set nombre
     *
     * @param string $nombre
     * @return Usuario
     */
    public function setNombre($nombre)
    {
        $this->nombre = $nombre;

        return $this;
    }

    /**
     * Get nombre
     *
     * @return string 
     */
    public function getNombre()
    {
        return $this->nombre;
    }

    

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }


    public function getDirecciones()
    {
        return $this->direcciones;
    }

    public function setDirecciones($direcciones)
    {
        $this->direcciones = $direcciones;

        return $this;
    }



}

I have already read many blogs and similar questions, but I can't get the property $direcciones hydrated or filled with the associated data, when I try to achieve that on the inverse side of the relation (OneToMany), with $usuario->getDirecciones();

I'm working in with this code in a non MVC architecture, to this point everything works like charm in getting creating and updating through a DAO which uses the Doctrine sentences, so I know that in the ending points (updating, creating, persist and flush, retrieving data with find, findBy, etc.), everything works fine.

When I try to fill the ArrayCollection calling from the Service layer where I use both classes (Usuario-InverseSide and Direccion-OwnerSide), nothing happens, the $direcciones arrayCollection property on Usuario instance, doesn't fetch anything, even when I tried establishing fetch="EAGER"on the annotations.

for the rest of the data or properties, everything works fine, all the other attributes of the user get filled just fine.

For some reason, the annotations are not being considered, don´t know why. I've spent a few days trying to figure out how to accomplish this way of accessing the associated data, didn't wanted to use DQL, but at this point I think I will take that road.

I tried something hard-coded to test and, the result is the same, $direcciones doesn't get his data.Obvious are already discarded, that exact ID for a Usuario(user) has his related direcciones(address) setted.

$usuario = $this->usuarioDAO->find(20);
        $direcciones = $usuario->getDirecciones();
        var_dump($direcciones);
        return $usuario;

the relation was only defined with a FK called id_usuario on Direccion on a MySQL InnoDb table.

don't know if I should be setting something else on the Usuario table. or if there is something wrong in the way I store the entities on my project.

please help me, any recommendation will be appreciated.

doctrine 2, how do get data from the inverse side (many to one)

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
  • Try changing mappedBy="id_usuario" to mappedBy="idUsuario" – Jannes Botis Dec 14 '17 at 12:30
  • thanks for your answer, i already tried that, knowing that the property on the Direccion entity is called idUsuario, and it is still not working right with that change done. i will try changing the name of the column on the DB table. – Sebastian Quevedo Dec 14 '17 at 15:38
  • Try to iterate through your collection foreach ($direcciones as $dir) { var_dump($dir); } – Jannes Botis Dec 14 '17 at 17:35
  • if i only var dump the user the result is, ( i'll resume to 2 or 3 properties for post.length issue) {}object(Usuario)#109 (13) { ["rut":"Usuario":private]=> string(10) "17738715-0" ["nombre":"Usuario":private]=> NULL ["perfil":"Usuario":private]=> string(7) "usuario" ["telefono":"Usuario":private]=> string(7) "7346534" ["id":"Usuario":private]=> int(20) ["direcciones":"Usuario":private]=> NULL } so, the user already finded doesn´'t get his $direcciones filled, for some reason the relation is not being listened or considered by doctrine. – Sebastian Quevedo Dec 14 '17 at 18:31
  • so for more detail and less time watching ["direcciones":"Usuario":private]=> NULL } when i try to iterate, appears this warning, that happens when you dont.pass an array or in this case a pretty well defined ArrayCollection ($direcciones is initialized that way on its entity). Warning: Invalid argument supplied for foreach() in C:\Apache24\htdocs\doctrine2tutorial\src\service\usuarioService.php on line 119
    – Sebastian Quevedo Dec 14 '17 at 18:33

2 Answers2

0

Provided that your bidirectional mapping between Direccion and Usuaro is correct, you need to use setter methods on both sides.

And the other thing, when using ArrayCollection, an easier (perhaps the only way) is to add elements one by one.

Therefore, instead of setDirecciones() you add this method to Usuario class:

public function addDireccion(Direccion $direccion) {
    $direccion->setIdUsuario($this);
    $this->direcciones->add($direccion);
}

Hope that helps.

And, it would be better to name it $usuario and setUsuario instead od setIdUsuario because you work with objects and PHP should not be concerned about actual database field names (to put it that way).

Đuro Mandinić
  • 693
  • 1
  • 8
  • 26
  • thanks , this will be usefull now that i've achieved making it bring the correct data. happens that for some reason, the php annotations were not being actually readed, or on a different way to say it, it was listening to the XML annotations first, so i put the xml sentence on the inverse side of the relation (usuario) inside the tags and it worked, now i got polish the data result of the consult so i can send a cleaner/clearer object to the front-end. – Sebastian Quevedo Dec 15 '17 at 12:03
0

i resolved it.

happens that for some reason, the php annotations were not being actually readed, or on a different way to say it, it was listening to the XML annotations first, so i put the xml sentence on the inverse side of the relation (usuario) inside the tags

<one-to-many field="direcciones" target-entity="Direccion" mapped-by="idUsuario" />

and it worked, now i got polish the data result of the consult so i can send a cleaner/clearer object to the front-end.