php - Symfony Doctrine: How to get Relation data with additional attributes through getters
Get the solution ↓↓↓i want to develop a doctrine-powered database application which should portray the following schema.
There are users, companies and relation-roles which describes the relation between a user to a company like[USER X] is [ROLE X] in [COMPANY X]
.
I'm using thesymfony maker-bundle
to create the entities I need. I'll attach every code at the end of this post.
To test the code, I persisted a company, a user, a role and a relation between them to the database. I expected that I could get all related users with their roles using aCompany-Entity-Object
with the generated gettergetRelatedUsers()
but I get an emptyArrayCollection
.
This is how I tested to fetch the data in aTestController
#[Route('/test', name: 'test_page')]
public function index(CompanyRepository $companyRepository): Response
{
$companies = $companyRepository->findAll();
dd($companies[0]->getRelatedUsers());
}
Thanks for your help!
User.php
<?php
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=UserRepository::class)
* @ORM\Table(name="`user`")
*/
class User
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $fullName;
/**
* @ORM\OneToMany(targetEntity=UserCompanyRelation::class, mappedBy="user")
*/
private $relatedCompanies;
public function __construct()
{
$this->relatedCompanies = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getFullName(): ?string
{
return $this->fullName;
}
public function setFullName(string $fullName): self
{
$this->fullName = $fullName;
return $this;
}
/**
* @return Collection|UserCompanyRelation[]
*/
public function getRelatedCompanies(): Collection
{
return $this->relatedCompanies;
}
public function addRelatedCompany(UserCompanyRelation $relatedCompany): self
{
if (!$this->relatedCompanies->contains($relatedCompany)) {
$this->relatedCompanies[] = $relatedCompany;
$relatedCompany->setUser($this);
}
return $this;
}
public function removeRelatedCompany(UserCompanyRelation $relatedCompany): self
{
if ($this->relatedCompanies->removeElement($relatedCompany)) {
// set the owning side to null (unless already changed)
if ($relatedCompany->getUser() === $this) {
$relatedCompany->setUser(null);
}
}
return $this;
}
}
Company.php
<?php
namespace App\Entity;
use App\Repository\CompanyRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=CompanyRepository::class)
*/
class Company
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/**
* @ORM\OneToMany(targetEntity=UserCompanyRelation::class, mappedBy="company")
*/
private $relatedUsers;
public function __construct()
{
$this->relatedUsers = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
/**
* @return Collection|UserCompanyRelation[]
*/
public function getRelatedUsers(): Collection
{
return $this->relatedUsers;
}
public function addRelatedUser(UserCompanyRelation $relatedUser): self
{
if (!$this->relatedUsers->contains($relatedUser)) {
$this->relatedUsers[] = $relatedUser;
$relatedUser->setCompany($this);
}
return $this;
}
public function removeRelatedUser(UserCompanyRelation $relatedUser): self
{
if ($this->relatedUsers->removeElement($relatedUser)) {
// set the owning side to null (unless already changed)
if ($relatedUser->getCompany() === $this) {
$relatedUser->setCompany(null);
}
}
return $this;
}
}
UserCompanyRelation.php
<?php
namespace App\Entity;
use App\Repository\UserCompanyRelationRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=UserCompanyRelationRepository::class)
*/
class UserCompanyRelation
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity=UserCompanyRelationRole::class, inversedBy="userCompanyRelations")
* @ORM\JoinColumn(nullable=false)
*/
private $role;
/**
* @ORM\ManyToOne(targetEntity=Company::class, inversedBy="relatedUsers")
* @ORM\JoinColumn(nullable=false)
*/
private $company;
/**
* @ORM\ManyToOne(targetEntity=User::class, inversedBy="relatedCompanies")
* @ORM\JoinColumn(nullable=false)
*/
private $user;
public function __construct()
{
}
public function getId(): ?int
{
return $this->id;
}
public function getRole(): ?UserCompanyRelationRole
{
return $this->role;
}
public function setRole(?UserCompanyRelationRole $role): self
{
$this->role = $role;
return $this;
}
public function getCompany(): ?Company
{
return $this->company;
}
public function setCompany(?Company $company): self
{
$this->company = $company;
return $this;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
}
UserCompanyRelationRole.php
<?php
namespace App\Entity;
use App\Repository\UserCompanyRelationRoleRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=UserCompanyRelationRoleRepository::class)
*/
class UserCompanyRelationRole
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/**
* @ORM\OneToMany(targetEntity=UserCompanyRelation::class, mappedBy="role")
*/
private $userCompanyRelations;
public function __construct()
{
$this->userCompanyRelations = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
/**
* @return Collection|UserCompanyRelation[]
*/
public function getUserCompanyRelations(): Collection
{
return $this->userCompanyRelations;
}
public function addUserCompanyRelation(UserCompanyRelation $userCompanyRelation): self
{
if (!$this->userCompanyRelations->contains($userCompanyRelation)) {
$this->userCompanyRelations[] = $userCompanyRelation;
$userCompanyRelation->setRole($this);
}
return $this;
}
public function removeUserCompanyRelation(UserCompanyRelation $userCompanyRelation): self
{
if ($this->userCompanyRelations->removeElement($userCompanyRelation)) {
// set the owning side to null (unless already changed)
if ($userCompanyRelation->getRole() === $this) {
$userCompanyRelation->setRole(null);
}
}
return $this;
}
}
Answer
Solution:
I found an solution. I had to modify the fetch-strategy toEAGER
in a annotation attribute. I modified therelatedUsers
annotation property incompany.php
<?php
namespace App\Entity;
use App\Repository\CompanyRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=CompanyRepository::class)
*/
class Company
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/**
* @ORM\OneToMany(targetEntity=UserCompanyRelation::class, mappedBy="company", fetch="EAGER")
*/
private $relatedUsers;
public function __construct()
{
$this->relatedUsers = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
/**
* @return Collection|UserCompanyRelation[]
*/
public function getRelatedUsers(): Collection
{
return $this->relatedUsers;
}
public function addRelatedUser(UserCompanyRelation $relatedUser): self
{
if (!$this->relatedUsers->contains($relatedUser)) {
$this->relatedUsers[] = $relatedUser;
$relatedUser->setCompany($this);
}
return $this;
}
public function removeRelatedUser(UserCompanyRelation $relatedUser): self
{
if ($this->relatedUsers->removeElement($relatedUser)) {
// set the owning side to null (unless already changed)
if ($relatedUser->getCompany() === $this) {
$relatedUser->setCompany(null);
}
}
return $this;
}
}
Answer
Solution:
You should use inversed by for bidirectional mapping between entities. See: https://www.doctrine-project.org/projects/doctrine-orm/en/2.9/reference/association-mapping.html#many-to-many-bidirectional
Share solution ↓
Additional Information:
Link To Answer People are also looking for solutions of the problem: xml parsing error: no root element found
Didn't find the answer?
Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Similar questions
Find the answer in similar questions on our website.
Write quick answer
Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.