Skip to content

Instantly share code, notes, and snippets.

@marcelomx
Last active July 15, 2021 12:48
Show Gist options
  • Save marcelomx/330cf7365514c14a0a083e80ec9c2685 to your computer and use it in GitHub Desktop.
Save marcelomx/330cf7365514c14a0a083e80ec9c2685 to your computer and use it in GitHub Desktop.
Doctrine HasOneThrough relation example (based on Laravel Eloquent HasOneThrough)
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\OneToOne;
#[Entity()]
class Car
{
#[Id(), GeneratedValue()]
private int $id;
#[Column(name: 'name', type: 'string')]
private string $name;
#[OneToOne(inversedBy: 'car', targetEntity: Mechanic::class)]
#[JoinColumn(name: 'mechanic_id', referencedColumnName: 'id')]
private Mechanic $mechanic;
/** Magic to Mechanic#HasOneThrough */
#[OneToOne(mappedBy: 'car', targetEntity: Owner::class)]
private Owner $owner;
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;
}
public function getMechanic(): Mechanic
{
return $this->mechanic;
}
public function setMechanic(Mechanic $mechanic): self
{
$this->mechanic = $mechanic;
return $this;
}
public function getOwner(): Owner
{
return $this->owner;
}
}
<?php
namespace App\Repository;
use App\Entity\Mechanic;
use Doctrine\ORM\EntityRepository;
class CarRepository extends EntityRepository
{
/**
* @return Mechanic[]
* @throws \InvalidArgumentException
* @throws \RuntimeException
* @throws \Doctrine\ORM\ORMException
*/
public function getAllMechanics()
{
return $this->createQueryBuilder('m')
->from(Mechanic::class, 'm')
->getQuery()
->getResult();
}
}
<?php
use App\Entity\Car;
use App\Repository\CarRepository;
use Doctrine\ORM\EntityManager;
/** @var EntityManager $m */
$em;
/** @var CarRepository $carRepository */
$carRepository = $em->getRepository(Car::class);
// Get all mechanics and car `Owner` through virtual relation `Car`
$allMechanics = $carRepository->getAllMechanics();
foreach ($allMechanics as $mechanic) {
$carOwner = $mechanic->getCarOwner();
echo $carOwner->getName() . PHP_EOL;
}
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\OneToOne;
#[Entity()]
class Mechanic
{
#[Id(), GeneratedValue()]
private int $id;
#[Column(name: 'name', type: 'string')]
private string $name;
/** Magic to Mechanic#HasOneThrough */
#[OneToOne(mappedBy: 'mechanic', targetEntity: Car::class)]
private Car $car;
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;
}
public function getCar(): Car
{
return $this->car;
}
/**
* Where the magic happens
* HasOneThrough
*/
public function getCarOwner(): Owner
{
return $this->car->getOwner();
}
}
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\OneToOne;
#[Entity()]
class Owner
{
#[Id(), GeneratedValue()]
private int $id;
#[Column(name: 'name', type: 'string')]
private string $name;
#[OneToOne(inversedBy: 'owner', targetEntity: Car::class)]
#[JoinColumn(name: 'car_id', referencedColumnName: 'id')]
private Car $car;
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;
}
public function getCar(): Car
{
return $this->car;
}
public function setCar(Car $car): self
{
$this->car = $car;
return $this;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment