あっぽログ
← 記事一覧に戻る

SymfonyのDoctrine ORM入門:エンティティ・リポジトリ・マイグレーションを使いこなす

Doctrine ORMとは?

Doctrine ORMは、PHPのオブジェクトとデータベースのテーブルをマッピングするライブラリです。SQLを直接書かなくても、PHPのクラス(エンティティ)を通じてデータベース操作ができます。

SymfonyはDoctrine ORMと非常に密接に統合されており、Symfonyプロジェクトでは標準的なデータベースアクセス手段として利用されています。

この記事では以下の流れで解説します。

  • エンティティの作成
  • マイグレーションの実行
  • リポジトリを使ったCRUD操作

セットアップ

まずDoctrineをインストールします。

composer require symfony/orm-pack
composer require --dev symfony/maker-bundle

次に.envファイルでデータベース接続情報を設定します。

DATABASE_URL="mysql://root:password@127.0.0.1:3306/symfony_demo?serverVersion=8.0"

データベースを作成します。

php bin/console doctrine:database:create

エンティティを作成する

エンティティとは、データベースのテーブルに対応するPHPクラスです。Makerバンドルを使うと対話形式で簡単に生成できます。

php bin/console make:entity Article

コマンドを実行すると、フィールド名や型を対話的に入力できます。以下のようなArticleエンティティが生成されます。

// src/Entity/Article.php
namespace App\Entity;

use App\Repository\ArticleRepository;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: ArticleRepository::class)]
class Article
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private ?string $title = null;

    #[ORM\Column(type: 'text')]
    private ?string $body = null;

    #[ORM\Column]
    private ?\DateTimeImmutable $createdAt = null;

    // getterとsetter(省略)
    public function getId(): ?int { return $this->id; }

    public function getTitle(): ?string { return $this->title; }
    public function setTitle(string $title): static
    {
        $this->title = $title;
        return $this;
    }

    public function getBody(): ?string { return $this->body; }
    public function setBody(string $body): static
    {
        $this->body = $body;
        return $this;
    }

    public function getCreatedAt(): ?\DateTimeImmutable { return $this->createdAt; }
    public function setCreatedAt(\DateTimeImmutable $createdAt): static
    {
        $this->createdAt = $createdAt;
        return $this;
    }
}

#[ORM\Column]などのPHP 8のアトリビュート(Attribute)でカラムの定義を行います。


マイグレーションを実行する

エンティティを作成したら、その内容をデータベースに反映します。

# マイグレーションファイルを生成
php bin/console make:migration

# マイグレーションを実行
php bin/console doctrine:migrations:migrate

生成されたマイグレーションファイルはmigrations/ディレクトリに保存されます。中身はこのようなSQLを含むPHPファイルです。

public function up(Schema $schema): void
{
    $this->addSql('CREATE TABLE article (
        id INT AUTO_INCREMENT NOT NULL,
        title VARCHAR(255) NOT NULL,
        body LONGTEXT NOT NULL,
        created_at DATETIME NOT NULL COMMENT "(DC2Type:datetime_immutable)",
        PRIMARY KEY(id)
    ) DEFAULT CHARACTER SET utf8mb4');
}

マイグレーションを使うことでデータベースの変更履歴が管理でき、チーム開発や本番環境への適用がスムーズになります。


リポジトリでCRUD操作を行う

リポジトリはデータベースへのクエリをまとめるクラスです。エンティティを作成するとArticleRepositoryも自動生成されます。

データの保存(Create)

// src/Controller/ArticleController.php
use App\Entity\Article;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class ArticleController extends AbstractController
{
    #[Route('/article/new', name: 'article_new')]
    public function new(EntityManagerInterface $em): Response
    {
        $article = new Article();
        $article->setTitle('はじめての記事');
        $article->setBody('Doctrine ORMは便利です!');
        $article->setCreatedAt(new \DateTimeImmutable());

        $em->persist($article); // 保存対象として登録
        $em->flush();           // 実際にINSERTを発行

        return new Response('記事ID: ' . $article->getId());
    }
}

データの取得(Read)

#[Route('/article/{id}', name: 'article_show')]
public function show(int $id, ArticleRepository $repo): Response
{
    // プライマリキーで1件取得
    $article = $repo->find($id);

    if (!$article) {
        throw $this->createNotFoundException('記事が見つかりません');
    }

    return new Response($article->getTitle());
}

リポジトリには便利なメソッドが標準で用意されています。

// 全件取得
$articles = $repo->findAll();

// 条件で検索
$articles = $repo->findBy(['title' => 'テスト'], ['createdAt' => 'DESC']);

// 1件だけ条件で検索
$article = $repo->findOneBy(['title' => 'はじめての記事']);

カスタムクエリ(QueryBuilder)

より複雑な検索はリポジトリにメソッドを追加します。

// src/Repository/ArticleRepository.php
public function findRecent(int $limit = 5): array
{
    return $this->createQueryBuilder('a')
        ->orderBy('a.createdAt', 'DESC')
        ->setMaxResults($limit)
        ->getQuery()
        ->getResult();
}

データの更新(Update)と削除(Delete)

// Update
$article = $repo->find(1);
$article->setTitle('タイトルを変更しました');
$em->flush(); // flushするだけでUPDATEが発行される

// Delete
$article = $repo->find(1);
$em->remove($article);
$em->flush();

まとめ

この記事では、Symfony + Doctrine ORMの基本的な使い方を解説しました。

操作メソッド
保存persist() + flush()
取得find() / findBy()
更新プロパティ変更 + flush()
削除remove() + flush()

Doctrine ORMを使うことで、SQLを直接書かずに安全・簡潔にデータベース操作ができます。次のステップとして、エンティティ間のリレーション(OneToMany・ManyToManyなど)を学ぶとさらに表現力が広がります。ぜひ試してみてください!

← 記事一覧に戻る