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?
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