day21(から4日遅れ)の今日は、DoctrineやEloquentでレコードを保存するときに、作成日時・更新日時を自動保存する方法を見ていきます。
Doctrine
Entity/Book.php
<?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: 'books')]
#[ORM\HasLifecycleCallbacks]
class Book
{
#[ORM\Id]
#[ORM\Column(type: 'integer')]
#[ORM\GeneratedValue(strategy: 'AUTO')]
private int $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;
#[ORM\Column(type: 'text', nullable: true)]
private ?string $description;
#[ORM\OneToMany(mappedBy: 'book', targetEntity: Reaction::class, cascade: ['persist'], orphanRemoval: true)]
private Collection $reactions;
#[ORM\Column(name: 'created_at', type: 'datetime_immutable')]
private \DateTimeImmutable $createdAt;
#[ORM\Column(name: 'updated_at', type: 'datetime_immutable')]
private \DateTimeImmutable $updatedAt;
public function __construct()
{
$this->reactions = new ArrayCollection();
}
public function getId(): int
{
return $this->id;
}
public function setId(int $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;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): void
{
$this->description = $description;
}
/**
* @return Collection<Reaction>
*/
public function getReactions(): Collection
{
return $this->reactions;
}
public function setReactions(Collection $reactions): void
{
$this->reactions = $reactions;
}
public function addReaction(Reaction $reaction): void
{
if (!$this->reactions->contains($reaction)) {
$reaction->setBook($this);
$this->reactions->add($reaction);
}
}
public function removeReaction(Reaction $reaction): void
{
$reaction->setBook(null);
$this->reactions->removeElement($reaction);
}
#[ORM\PrePersist]
public function prePersist(): void
{
$this->createdAt = new \DateTimeImmutable();
$this->updatedAt = new \DateTimeImmutable();
}
#[ORM\PreUpdate]
public function preUpdate(): void
{
$this->updatedAt = new \DateTimeImmutable();
}
public function getCreatedAt(): \DateTimeImmutable
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeImmutable $createdAt): void
{
$this->createdAt = $createdAt;
}
public function getUpdatedAt(): \DateTimeImmutable
{
return $this->updatedAt;
}
public function setUpdatedAt(\DateTimeImmutable $updatedAt): void
{
$this->updatedAt = $updatedAt;
}
}
<?php
declare(strict_types=1);
use App\Entity\Author;
use App\Entity\Book;
use Doctrine\ORM\EntityManagerInterface;
require __DIR__.'/../vendor/autoload.php';
/** @var EntityManagerInterface $entityManager */
$entityManager = require __DIR__.'/bootstrap.php';
$author = new Author();
$author->setName('tanakahisateru');
$newBook = new Book();
$newBook->setTitle('ちょうぜつソフトウェア設計入門');
$newBook->setPrice(3080);
$newBook->setDescription('かわいい絵柄で釣ってオブジェクト指向をガッツリ解説する本');
$newBook->setAuthor($author);
/** @var EntityManagerInterface $entityManager */
$entityManager = require __DIR__.'/bootstrap.php';
$entityManager->persist($author);
$entityManager->persist($newBook);
$entityManager->flush();
$newBook->getCreatedAt(); // 登録日時
$newBook->getUpdatedAt(); // 更新日時
- DoctrineのLifecycleCallbackを設定することで実現できます。カラムや保存処理は自分で書く必要があります。
- 全部のエンティティにupdatedAt, createdAtを設定したい場合など、全エンティティに設定するのが面倒な場合はDoctrineExtensions https://github.com/doctrine-extensions/DoctrineExtensions の
Timestampable
を使うと楽に設定できます。
Eloquent
Models/Book.php
<?php
declare(strict_types=1);
namespace App\Models;
use Carbon\CarbonInterface;
use Illuminate\Database\Eloquent\Model;
/**
* App\Models\Book
*
* @property int $id
* @property string $title
* @property int $price
* @property Author $author
* @property string|null $description
* @property CarbonInterface $created_at
* @property CarbonInterface $updated_at
*/
class Book extends Model
{
public $fillable = [
'title',
'price',
'author_id',
'description',
];
public $timestamps = true;
public function author()
{
return $this->belongsTo(Author::class);
}
public function likes()
{
return $this->morphMany(Like::class, 'likable');
}
}
<?php
declare(strict_types=1);
use App\Models\Author;
use App\Models\Book;
require __DIR__.'/../vendor/autoload.php';
require __DIR__.'/bootstrap.php';
$author = new Author();
$author->name = 'tanakahisateru';
$author->save();
$newBook = new Book();
$newBook->title = 'ちょうぜつソフトウェア設計入門';
$newBook->price = 3080;
$newBook->description = 'かわいい絵柄で釣ってオブジェクト指向をガッツリ解説する本';
$newBook->author_id = $author->id;
$newBook->save();
$newBook->created_at; // 登録日時がセットされている
$newBook->updated_at; // 更新日時がセットされている
- Modelの
$timestamps
プロパティをtrueにセットするだけです。細かいオプション(カラム名を標準から変える等)はすべてModelの所定のプロパティを使って設定します。