Search code examples
symfonydoctrinemany-to-many

Doctrine many-to-many relationship: failed to get data automatically from database


In my Symfony code I've used Doctrine. In an Entity ( AppBundle\Entity\Core\User ) I defined a column foodTypes, which is associated with another Entity (AppBundle\Entity\FoodRecording\FoodType). I've defined an Many-to-Many relationship between User and FoodType, with a linking table foodrecording_user, joining User.username and FoodType.foodtype_code. The code is shown below.

// Entity\Core\User
namespace AppBundle\Entity\Core;
......
class User implements AdvancedUserInterface, \Serializable {
......
/**
 * @ORM\ManyToMany(targetEntity="AppBundle\Entity\FoodRecording\FoodType")
 * @ORM\JoinTable(name="foodrecording_user",
 *      joinColumns={@ORM\JoinColumn(name="username", referencedColumnName="username", onDelete="CASCADE")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="foodtype_code", referencedColumnName="code", onDelete="CASCADE")}
 *      )
 */
private $foodTypes;

public function getFoodTypes()
{
    $this->foodTypes = new \Doctrine\Common\Collections\ArrayCollection();

    return $this->foodTypes;
}

However, as I wanted to get directly all the food types of a certain user, using

$userFoodTypes = $this->get('security.token_storage')->getToken()->getUser()->getFoodTypes();

then I got

$userFoodTypes =====> array[]

I expected that as I've created the M-M relationship, Doctrine would automatically fetch the data I need, but it is not the case!

Therefore, I have to write my own code to retrieve the data from the DB / table like following:

public function fetchUserFoodTypes()
{
    global $kernel;
    $container = $kernel->getContainer();
    $em = $container->get('doctrine.orm.entity_manager');
    $conn = $em->getConnection();

    $sql = 'SELECT * FROM foodrecording_user where username = :username';
    $stmt = $conn->prepare($sql);
        $stmt->execute([
            'username' => $this->getUsername(),
        ]);

    $data = $stmt->fetchAll();

    $res = [];
    foreach ($data as $item) {

        $foodtype = $em->getRepository('AppBundle\Entity\FoodRecording\FoodType')->findByCode($item['foodtype_code']);
        $res[] = $foodtype;
    }

    return $res;
}

public function getFoodTypes()
{
    $this->foodTypes = $this->fetchUserFoodTypes();
    //$this->foodTypes = new \Doctrine\Common\Collections\ArrayCollection();

    return $this->foodTypes;
}

Only in this way I am able to get the food types associated with a user.

Could anyone explain to me, why I can't simply use the M-M definition and let doctrine do all the thing automatically for me? Why should I explicitly write my own function to retrieve data from DB? Is Doctrine not smart enough?


Solution

  • This part: $this->foodTypes = new \Doctrine\Common\Collections\ArrayCollection(); Belongs to the __construct method, not getter.. You see, like this, every time you call your getter, you reset the property foodTypes to an empty instance of an ArrayCollection