Πώς υλοποιείται η σχέση 'has many through' στο Doctrine;
sobes.tech AI
Απάντηση από AI
Στο Doctrine2, η σχέση "has many through" υλοποιείται μέσω της ρητής δημιουργίας μιας ενδιάμεσης οντότητας (join entity), η οποία συνδέει δύο άλλες οντότητες με σχέσεις Many-to-One.
-
Δημιουργούνται τρεις κλάσεις οντοτήτων: Πηγή, Στόχος και Ενδιάμεση (JoinEntity).
-
Η ενδιάμεση οντότητα (π.χ.,
UserGroupγια το "User έχει πολλές Groups μέσω UserGroup") περιέχει δύο πεδία που είναι σχέσεις Many-to-One με τις οντότητες Πηγή (User) και Στόχο (Group). -
Οι οντότητες Πηγή και Στόχος έχουν σχέση One-to-Many με την ενδιάμεση οντότητα.
-
Για εύκολη πρόσβαση στις οντότητες Στόχο μέσω της Πηγής (π.χ., όλες οι
Groupγια ένανUser), μπορεί να προστεθεί μια μέθοδος στην οντότητα Πηγή που φιλτράρει τις ενδιάμεσες οντότητες.
Παραδείγματα δομής:
// 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; // Σχέση με την ενδιάμεση οντότητα
public function __construct()
{
$this->userGroups = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
/**
* Λήψη ομάδων του χρήστη μέσω της ενδιάμεσης οντότητας.
* Αυτό είναι το ισοδύναμο του "has many through".
* Σημείωση: Μπορεί να θέλετε να φορτώσετε αυτή τη συλλογή αποτελεσματικά ανάλογα με τις ανάγκες σας.
*/
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; // Σχέση με την ενδιάμεση οντότητα
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')] // Παράδειγμα ονόματος πίνακα
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 προς User
#[ORM\ManyToOne(targetEntity: Group::class, inversedBy: 'userGroups')]
#[ORM\JoinColumn(nullable: false)]
private ?Group $group = null; // Many-to-One προς 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;
}
}
Αυτή η προσέγγιση, αν και απαιτεί τη δημιουργία επιπλέον οντότητας, παρέχει πλήρη έλεγχο στις σχέσεις και επιτρέπει εύκολα την προσθήκη επιπλέον πεδίων στον ενδιάμεσο πίνακα (π.χ., ημερομηνία ένταξης χρήστη σε ομάδα).