Doctrine入門 まず最初にすること

Doctrineって?

データベース操作って素でやるととっても面倒ですよね。
SQLゴリゴリ書いて、ごにょごにょやって、汚く長ったらしいコードの出来上がり。

もう少し簡潔に、OOPっぽく書きたいなーって時に使うといい感じに手抜きさせてくれるライブラリ、ORM(O/R マッパー)というものがあります。

ORMはPHPに限らずJavaや.NET等いろんな界隈でいろんな種類の物があります。
PHPではEloquentDoctrineなどいろんなORMライブラリがあります。

個人的にはDoctrine使っていこうかということでDoctrineのメモになります。

Doctrineはエンティティが特定の実装に依存しないピュアな設計なのと(POJOとかPOCOでググってください、PHPだとPOPOかも)、
エンティティの一意性をいい感じに保障してくれるとか、.NETのEntity Frameworkのように使えそうなのでこっちを選びました。

大まかな機能。

ざっくりコードでイメージしてください。
例えばデータベースに製品に関する情報を作成したいとします。
データベース(MySQL想定)では

CREATE TABLE Product(
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(124) NOT NULL
    ...
)

といったテーブルを定義すると思います。
ORMを使うと、

class Product
{
    private int $id;
    private string $name;

    ...
}

こういったクラスを作成すれば、クラスから自動的にテーブルを作成してくれます。
さらにデータベースからデータをとってくるときは通常次のようなSQLを投げますが、

SELECT * FROM Product;

ORMを使うとSQLを書く必要もなく次のようなPHPコードでProduct型の配列で取得できるようになります。

// Productにマップされたテーブルからデータを引っ張ってきて、Productクラスの配列で返す。
$products = $em->getRepository(Product::class)->findAll();

つまりクラスを作成すれば、それに基づいてテーブル操作やCRUDやってくれる便利なやつです。

インストール

まずはPHPがインストールされていること、Composerが使えることが前提です。

{
    "require": {
        "symfony/cache": "^6.0",
        "doctrine/orm": "^2.11",
        "doctrine/annotations": "^1.13"
    },

    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

必要なもの

doctrine/orm 一番必要なもの。

symfony/cache、あるいは最新のdoctrine/cacheではなくver1.11をインストールします。
無いとクラス定義からテーブルを作成する時にエラーになります。

doctrine/annotationsも必要なようです。
環境によってはこれが無いとエラーが出る場合があります。

Uncaught Error: Class "Doctrine\Common\Annotations\AnnotationRegistry" not found in
/doctrine-migration-test/vendor/doctrine/orm/lib/Doctrine/ORM/Configuration.php:165
"App\\": "src/"

autoloadもエンティティを使用する時必要になります。
この設定は、プロジェクトのsrcディレクトリ以降に置いたクラスが名前空間Appから始まるようにしてます。
例えば、my-projectがプロジェクトのルートで次のようにItem.phpを配置したら

/my-project/src/Entities/Item.php

namespaceやuseで使用する名前空間はこのようになります。

App\Entities\Item

エンティティの定義

まずテーブルとマップするクラスを作成します。
一般的にはクラスにアノテーションを付与します。
規則があるので注意してください。

早速Itemというクラスを定義します。
特に用途を考えず適当にメンバ変数を定義しました。

ファイルを/my-project/src/Entities/Item.phpに作成したとして。

namespace App\Entities;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Item
{

    /**
     * @ORM\Id
     * @ORM\Column
     * @ORM\GeneratedValue
     */
    private int $id;

    /**
     * @ORM\Column
     */
    private string $name;

    /**
     * @ORM\Column
     */
    private int $power;

    public function __construct(string $name, int $power)
    {
        $this->name = $name;
        $this->power = $power;
    }

    public function getId(): int
    {
        return $this->id;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name): void
    {
        $this->name = $name;
    }

    public function getPower(): int
    {
        return $this->power;
    }

    public function setPower(int $power): void
    {
        $this->power = $power;
    }

}

アノテーションは次の名前空間を使います。

use Doctrine\ORM\Mapping as ORM;

以下アノテーションの説明です。

 @ORM\Entity

クラスにこのアノテーションを付けると、このクラスはエンティティだぜ!ってこになります。
測定ではデータベースにはクラス名と同じProductテーブルが作成されるようになります。

@ORM\Column

メンバー変数に付けると、これはカラムですよってことになります。

@ORM\Id

メンバー変数に付けると、これはカラムでも主キーになりますって意味です。

@ORM\GeneratedValue

メンバー変数に付けると、これは自動インクリメントですって意味です。

クラス名はデータベースのテーブル名に、メンバ変数はそのままテーブルのカラム名になります。
もし名前を任意のものにしたければ

テーブル名を変更したければクラスに以下の属性を追加(productsになる)

@ORM\Table(name="products")

カラム名を変更したければメンバ変数を次のようにします。

@ORM\Column(name="onamae")

コマンドの用意。

エンティティを定義しただけでは何も置きません。
ターミナルからコマンドを実行することでテーブルの作成、削除などを行います。

そのための設定ファイル等が必要です。
プロジェクトディレクトリに以下のファイルを書きます。

今回作成するのは、接続情報、EntityManagerのインスタンス, CLIの設定ファイルの三つです。

  • 接続情報は、DBの接続に必要なパスワードとか一式
  • EntityManagerはDoctrineの中核的なクラスで多用する
  • CLIの設定ファイルはコマンドラインからテーブル作成などの操作するために必要な設定ファイル

です。

接続情報

ファイル名は適当にconnection-settings.phpとでもします。
MySQLを使う場合は、

return [
    'dbname' => 'doctrinetest',
    'user' => 'root',
    'password' => 'wwwwwwwwwwwwwwwwww',
    'host' => 'localhost',
    'driver' => 'pdo_mysql'
];

で、キーを見ると大体意味分かると思います。
使いやすく留守ため、単に連想配列を返すだけのPHPファイルを作りました。

EntityManagerのインスタンス作成

ファイル名は適当にcreateManager.phpにします。

require 'vendor/autoload.php';

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Setup;

// エンティティの置き場、今回は一つだけ/my-project/src/Entitiesに用意。
$path = __DIR__ . '/src/Entities';

// Doctrineの設定情報
$config = Setup::createAnnotationMetadataConfiguration(
    [$path],
    true,
    null,
    null,
    false
);

// 接続情報
$conn = require 'connection-settings.php';

// EntityManagerを作成して返す
return EntityManager::create($conn, $config);

EntityManagerのインスタンスを作成するPHPファイルを用意しました。
これを使用する時は次のようにして作成することが出来るようになります。

$em = require 'createManager.php';

CLIの設定

プロジェクトディレクトリにcli-config.phpを作成します。
この名前は固定です。

$manager = require 'createManager.php';

return \Doctrine\ORM\Tools\Console\ConsoleRunner::createHelperSet($manager);

これでコマンドラインからテーブル操作が出来るようになります。

これまでのディレクトリ

これまで作成してきたファイルのディレクトリ構造。

[プロジェクトルート]
  composer.json
  src
    Entities
      Item.php
  connection-config.php
  createManager.php
  cli-config.php

エンティティを増やす場合はsrc/Entitiesにどんどん追加していきます。

コマンドの実行

とりあえず作成、削除のコマンドです。

テーブル作成のコマンド

まずはいきなりテーブルを作成せず、テーブル作成のSQLを吐き出します。

vendor/bin/doctrine orm:schema-tool:create --dump-sql

ターミナルからコマンドを実行すると

CREATE TABLE Item (
    id INT AUTO_INCREMENT NOT NULL,
    name VARCHAR(255) NOT NULL,
    power INT NOT NULL,
    PRIMARY KEY(id)
)
DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB;

SQLが吐き出されます。これは接続情報がMySQLの場合です。
src/Entitiesからエンティティを片っ端から拾った(今回はItem.phpだけ)SQLです。
もし複数合ったりリレーションがある場合はそれに応じたSQLが吐き出されます。

今度はSQL出力ではなく実際にテーブルを作成するコマンドです。

vendor/bin/doctrine orm:schema-tool:create

ちょっと警告されますが無視です。

[CAUTION] This operation should not be executed in a production environment!


成功したらデータベースに反映されているはずです。

テーブル削除のコマンド

vendor/bin/doctrine orm:schema-tool:drop --force

これで作成されたテーブルは無くなります。

あと、エンティティの定義を編集したばあい

vendor/bin/doctrine orm:schema-tool:update --force

もあります。

最後に

今回はエンティティを定義して、それからテーブルを作成、削除するための一連の流れを解説しました。
次からは実際にCRUDやっていきます。

certificate Docker Gutenberg Hyper-V openssl PHP React ReduxToolkit REST ubuntu WordPress オレオレ認証局 フレームワーク