Symfony Doctrine: How to get Relation data with additional attributes through getters

Viewed 132

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 the symfony 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 a Company-Entity-Object with the generated getter getRelatedUsers() but I get an empty ArrayCollection.

This is how I tested to fetch the data in a TestController

#[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;
    }
}
2 Answers

I found an solution. I had to modify the fetch-strategy to EAGER in a annotation attribute. I modified the relatedUsers annotation property in 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", 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;
    }

}
Related