day7の今日は、テーブル間に外部キーによるリレーションがある場合にDoctrine, Eloquentそれぞれでどうやって表すか見ていきます。
SQL的にはauthorsテーブルとbooksテーブルへのauthor_idカラム(authors.idに対する外部キーつき)を追加しています。 https://github.com/77web/doctrine-vs-eloquent/blob/7f98ff21e16a1223e0ad5936e72e8be60c381ba0/sql/book.sql
Doctrine
author_idを追加したbooksテーブルを表すBookエンティティにはauthor_idプロパティでなくauthorプロパティを追加します。
<?php
declare(strict_types=1);
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[ORM\Table(name: 'books')]
class Book
{
#[ORM\Id]
#[ORM\Column(type: 'integer')]
#[ORM\GeneratedValue(strategy: 'AUTO')]
private string $id;
#[ORM\Column(type: 'string', length: 255, nullable: false)]
private string $title;
#[ORM\Column(type: 'integer')]
private int $price;
#[ORM\ManyToOne(targetEntity: Author::class)]
#[ORM\JoinColumn(onDelete: 'CASCADE')]
private Author $author;
public function getId(): string
{
return $this->id;
}
public function setId(string $id): void
{
$this->id = $id;
}
public function getTitle(): string
{
return $this->title;
}
public function setTitle(string $title): void
{
$this->title = $title;
}
public function getPrice(): int
{
return $this->price;
}
public function setPrice(int $price): void
{
$this->price = $price;
}
public function getAuthor(): Author
{
return $this->author;
}
public function setAuthor(Author $author): void
{
$this->author = $author;
}
}
一方、所有側であるAuthorにもOneToManyリレーションを定義することで、author_idに自らのIDが設定されているBookエンティティのリストを取得することができます。
<?php
declare(strict_types=1);
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
#[ORM\Table(name: 'authors')]
class Author
{
#[ORM\Id]
#[ORM\Column(type: 'integer')]
#[ORM\GeneratedValue(strategy: 'AUTO')]
private string $id;
#[ORM\Column(type: 'string', length: 255)]
private string $name;
#[ORM\OneToMany(targetEntity: Book::class)]
private Collection $books;
public function __construct()
{
$this->books = new ArrayCollection();
}
public function getId(): string
{
return $this->id;
}
public function setId(string $id): void
{
$this->id = $id;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): void
{
$this->name = $name;
}
public function getBooks(): Collection
{
return $this->books;
}
public function addBook(Book $book): void
{
if (!$this->books->contains($book)) {
$book->setAuthor($this);
$this->books->add($book);
}
}
}
-
Book::$author
のManyToOne
アトリビュートによりBookがAuthorに対するinverse-sideであることを示します。 -
Author::$books
のOneToMany
アトリビュートによりAuthorがBookに対するowning-sideであることを示します。
Eloquent
author_idを追加したbooksテーブルを表すBookモデルには author()
メソッドを追加します。
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
* App\Models\Book
*
* @property int $id
* @property string $title
* @property int $price
* @property Author $author
*/
class Book extends Model
{
public $fillable = [
'title',
'price',
'author_id',
];
public function author()
{
return $this->belongsTo(Author::class);
}
}
一方、所有側であるAuthorにも books()
メソッドを定義することで、author_idに自らのIDが設定されているBookモデルのリストを取得することができます。
<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
/**
* App\Models\Author
*
* @property int $id
* @property string $name
* @property Collection<Book> $books
*/
class Author extends Model
{
public $fillable = [
'name',
];
public function books()
{
return $this->hasMany(Book::class);
}
}