Sobes.tech
Middle+

Kaip įgyvendinti 'has many through' ryšį Doctrine?

sobes.tech AI

Atsakymas iš AI

Doctrine2 santykyje "has many through" realizuojamas per aiškiai sukurtą tarpinę entitetą (join entity), kuri sujungia dvi kitas entites Many-to-One santykiais.

  1. Sukuriami trys entitetų klasės: šaltinio, tikslo ir tarpinė (JoinEntity).

  2. Tarpinė entitetas (pavyzdžiui, UserGroup "User has many Group through UserGroup") turi du laukus, kurie yra Many-to-One santykiai su Šaltinio (User) ir Tikslo (Group) entitetais.

  3. Šaltinio ir Tikslo entitetai turi One-to-Many santykį su Tarpine entitetu.

  4. Patogumui pasiekti Tikslo entitetus per Šaltinio (pavyzdžiui, gauti visas GroupUser) galima pridėti metodą Šaltinio entitete, kuris filtruos Tarpines entites.

Struktūros pavyzdys:

// User.php
<?php

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class User
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\OneToMany(targetEntity: UserGroup::class, mappedBy: 'user')]
    private Collection $userGroups; // Santykis su tarpine entitete

    public function __construct()
    {
        $this->userGroups = new ArrayCollection();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    /**
     * Gauti naudotojo grupes per tarpinę entitetą.
     * Tai yra "has many through" atitikmuo.
     * Pastaba: priklausomai nuo poreikių, galite efektyviai gauti šią kolekciją.
     */
    public function getGroups(): Collection
    {
        return $this->userGroups->map(fn(UserGroup $userGroup) => $userGroup->getGroup());
    }

    public function getUserGroups(): Collection
    {
        return $this->userGroups;
    }

    public function addUserGroup(UserGroup $userGroup): static
    {
        if (!$this->userGroups->contains($userGroup)) {
            $this->userGroups->add($userGroup);
            $userGroup->setUser($this);
        }

        return $this;
    }

    public function removeUserGroup(UserGroup $userGroup): static
    {
        if ($this->userGroups->removeElement($userGroup)) {
            if ($userGroup->getUser() === $this) {
                $userGroup->setUser(null);
            }
        }

        return $this;
    }
}
// Group.php
<?php

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class Group
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\OneToMany(targetEntity: UserGroup::class, mappedBy: 'group')]
    private Collection $userGroups; // Santykis su tarpine entitete

    public function __construct()
    {
        $this->userGroups = new ArrayCollection();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getUserGroups(): Collection
    {
        return $this->userGroups;
    }

    public function addUserGroup(UserGroup $userGroup): static
    {
        if (!$this->userGroups->contains($userGroup)) {
            $this->userGroups->add($userGroup);
            $userGroup->setGroup($this);
        }

        return $this;
    }

    public function removeUserGroup(UserGroup $userGroup): static
    {
        if ($this->userGroups->removeElement($userGroup)) {
            if ($userGroup->getGroup() === $this) {
                $userGroup->setGroup(null);
            }
        }

        return $this;
    }
}
// UserGroup.php
<?php

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ORM\Table(name: 'user_user_group')] // Pavyzdinis lentelės pavadinimas
class UserGroup
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'userGroups')]
    #[ORM\JoinColumn(nullable: false)]
    private ?User $user = null; // Many-to-One prie User

    #[ORM\ManyToOne(targetEntity: Group::class, inversedBy: 'userGroups')]
    #[ORM\JoinColumn(nullable: false)]
    private ?Group $group = null; // Many-to-One prie Group

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getUser(): ?User
    {
        return $this->user;
    }

    public function setUser(?User $user): static
    {
        $this->user = $user;

        return $this;
    }

    public function getGroup(): ?Group
    {
        return $this->group;
    }

    public function setGroup(?Group $group): static
    {
        $this->group = $group;

        return $this;
    }
}

Šis požiūris, nors ir reikalauja papildomos entitetos sukūrimo, suteikia pilną kontrolę nad ryšių duomenimis ir leidžia lengvai pridėti papildomų laukų tarpinėje lentelėje (pavyzdžiui, naudotojo prisijungimo datą prie grupės).