コードの例

CAUTION この本のテキストはたくさんのPHPコードの例を含みます。本の分量を減らすためにPHPの開始と終了タグはすべて取り除かれています。サンプルをコピー&ペーストするときは必ずPHPタグを含めてください。

Doctrineって何?

DoctrineはPHP5.2.3以降用のオブジェクトリレーショナルマッパー(ORM - Object Relational Mapper)で強力なデータベース抽象化レイヤー(DBAL - DataBase Abstraction Layer)のに。主要な機能の1つはDoctrine Query Language (DQL)と呼ばれるプロプリエタリなオブジェクト指向のSQL方言でデータベースクエリを書くオプションがあることです。HibernateのHQLにインスパイアされ、これは開発者に柔軟性を維持し不要なコードの重複がないSQLの強力な代替機能を提供します。

ORMって何?

オブジェクトリレーショナルマッピング(Object Relational Mapping)はプログラミング言語のテクニックです。リレーショナルデータベースで互換性のないデータ型を翻訳するためにデータベースで対処するとき、これによってプログラミング言語から利用できる”バーチャルなオブジェクトデータベース”を用意できます。これを可能にするたくさんの無料と商用パッケージが存在しますが時には開発者が独自のORMを作成する選択肢もあります。

何が問題なの?

ウェブアプリケーションを構築するときに多くの問題に直面します。ここでオブジェクトリレーショナルマッパーのすべてを説明するよりもWikipediaの説明を見るのがベストです。

[http://en.wikipedia.org/wiki/Object-relational_mapping Wikipedia]からの引用:

通常、オブジェクト指向のプログラミングにおけるデータ管理のタスクは、大抵の場合スカラーではない値であるオブジェクトの操作によって実装されます。例えば、ゼロ以上の電話番号とゼロ以上のアドレスに沿って個人を表すアドレスブックのエントリを考えてみましょう。これはオブジェクト指向の実装でモデル化できます。例えばエントリ: 個人の名前、電話番号のリスト(もしくは配列)、とアドレスのリストより構成されるデータを保有する”スロット”を持つ”個人オブジェクト”です。電話番号のリスト自身は”電話番号オブジェクト”などを含みます。アドレスブックのエントリはプログラミング言語による単独の変数として扱われます(例えば、単独の変数で参照される)。さまざまなメソッドはオブジェクト、望む電話番号、ホームアドレスなどを返すメソッドなどで関連付けできます。

しかしながら、SQLを生み出す多くのデータベースはテーブルの範囲内で編成されたスカラーの値、整数と文字列のようなものしか保存と操作ができません。

データベースに保存するためにプログラマはオブジェクトの値をよりシンプルな値に変換する(そしてこれらを読み取り用に変換する)、もしくはプログラムの範囲内でシンプルなスカラーの値のみを使用しなければなりません。オブジェクトリレーショナルマッピングは最初のアプローチを実装するために使われます。

より高度な問題は、永続的なオブジェクトのプロパティとリレーションが維持しながら、これらのオブジェクトがデータを読み取りやすくするためにデータベースに保存可能なフォームに翻訳することです、

最小要件

DoctrineはPHP5.2.3以降を必要とし、外部ライブラリは必要ありません。 データベース関数の呼び出しを抽象化するために、DoctrineはPDOを利用します。PDOはwww.php.netから入手できるPHPの公式リリースに搭載されています。

NOTE Windows用のUniform Server、MAMPもしくはその他の非公式パッケージを利用する場合、追加設定が必要な場合があります。

基本的な概要

DoctrineはPHP製のオブジェクトリレーショナルマッピング用のツールです。DoctrineはPDOを利用し2つの主要なレイヤー、DBALとORMに分割されます。下記の図はDoctrineのそれぞれのレイヤーが連携する様子を示しています。

[http://www.doctrine-project.org/images/doctrine-layers.jpg Doctrineレイヤー]

DBAL(Database Abstraction Layer)は基本的なデータベースのPDOによって既に提供される抽象化/独立性を完成および拡張します。PDOの元で強力なデータベース抽象化レイヤーを使いたいだけなら、DBALライブラリはスタンドアロンで利用可能です。ORMレイヤーはDBALに依存するので、ORMパッケージをロードするときDBALは既にインクルードされています。

Doctrineの説明

次のセクションではDoctrineがいるORMツールの世界を説明することにします。Doctrine ORMは主に [http://www.martinfowler.com/eaaCatalog/activeRecord.html Active Record]、[http://www.martinfowler.com/eaaCatalog/dataMapper.html Data Mapper]と [http://www.martinfowler.com/eaaCatalog/metadataMapping.html Meta Data Mapping]パターンでビルドされています。

Doctrine\_Record``という名前の特定の基底クラスを継承することで、すべての子クラスは典型的なActiveRecordインターフェイス(save/delete/etc.)を取得するのでDoctrineはレコードのライフサイクルの扱いとモニタリングを簡単にできます。しかしながら、大抵の場合実際の作業は``Doctrine_Table``クラスのような他のコンポーネントに向けられます。このクラスの典型例はData Mapperインターフェイス、``createQuery()find(id)findAll()findBy*()``findOneBy*()``などです。ですのでActiveRecordの基底クラスによってマッピングのフットワークがどこか他のところで行われる一方でDoctrineはレコードを管理して典型的なActiveRecordインターフェイスを提供できます。

ActiveRecordのアプローチには典型的な制限がついてまわります。もっとも明らかなことは永続的であるために特定の基底クラスを継承することが強制されることです(Doctrine_Record)。一般的に、ドメインモデルのデザインはリレーショナルモデルのデザインによってほとんど制限されます。しかし例外があります。継承構造を扱うとき、Doctrineによって洗練されたマッピング戦略が提供されるのでドメインモデルはリレーショナルモデルから少し分離されもう少し自由が得られます。

Doctrineは継続的な開発プロセスにありドメインのモデリングにより多くの自由を提供する新しい機能の追加を常に試みています。しかしながら、DoctrineがActiveRecordアプローチにとどまる限り、(強制された)これら2つのモデルのとても大きな類似性が常に存在するようになります。

現在の状況は次の図で記述されます。

[http://www.doctrine-project.org/relational-bounds.jpg リレーショナルモデルの範囲]

この図でわかるように、ドメインモデルはリレーショナルモデルの範囲から遠く離れることはできません。

これらの欠点を述べた後で、ActiveRecordのアプローチの利点を述べましょう。(ごくわずかな)シンプルなプログラミングモデルは別として、リレーショナルモデルとオブジェクト指向ドメインモデルの強い類似性も利点を持つことがわかります: これによって既存のリレーショナルスキーマから基本的なドメインモデルを作成できる強力な生成ツールを比較的簡単に提供できます。さらに、上記の理由のためドメインモデルはリレーショナルモデルから遠くに離れることができないので、生成と同期ツールなどは開発プロセスを通して簡単に使えます。このようなツールがDoctrineの強みの一つです。

大多数のウェブアプリケーションに対してActiveRecordのアプローチの制限はそれほど大きな問題ではないと筆者は考えます。多くの場合ビジネスドメインの複雑性が適度ですが、多すぎる制限が押しつけられドメインモデルに影響がありすぎるので、ActiveRecordのアプローチは複雑なビジネスロジック複雑なビジネスロジック(ドメイン駆動のデザインを利用してよく取り組まれる)には必ずしも適していないことも筆者は認めます。

Doctrineはシンプルもしくはほどほどの複雑性を持つドメインモデル``(1)``の一貫性を推し進めるための素晴らしいツールです。ドメインモデルをデータベース中心にすることと独自のものへのすべてのマッピングを実装することの間のトレードオフを考慮する場合、複雑なドメインモデルに対してよい選択肢ではないことがわかるかもしれません(執筆時点で筆者はActiveRecordアプローチに基づいたPHP製の強力なORMツールは知らないからです)。

NOTE (1) 複雑性は規模ではないことに注意してください。ドメインモデルは複雑性を伴わずにとても大きくなることがありますし逆もしかりです。もちろん、ドメインモデルが大きいほど複雑性である可能性は高くなります。

これでDoctrineができることとできないことがわかりました。すぐに始めたいのであれば、次の章の”Getting Started”に直行してください。

キーコンセプト

Doctrine Query Language(DQL)はオブジェクトクエリ言語です。ドメインモデル: クラスの名前、フィールドの名前、クラスの間のリレーション、などの用語を使い単独のオブジェクトもしくは完全なオブジェクトグラフ用のクエリを表現します。リレーショナルモデル(テーブルの名前、カラムの名前、など)からのドメインモデル(フィールドの名前、クラスの名前、など)の分離を壊さずにオブジェクトを読み取るもしくは操作するためにこれは強力なツールです。DQLはSQLにとてもよく似ており、またSQLを理解している人がわかりやすいようにそうなるように意図しています。しかしながら、ごくわずかですが、常に念頭においておく必要のある重要な違いがあります:

DQLクエリの例をあげます:

FROM User u LEFT JOIN u.Phonenumbers where u.level > 1

このクエリからわかることは次の通りです:

  • **テーブル**ではなく**クラス**をselectします。``User``クラス/モデルからselectしています。

  • アソシエーション (u.Phonenumbers)に従ってjoinします

  • フィールド (u.level)を参照できます

  • joinの条件(ON x.y = y.x)はありません。クラスの間のアソシエーションとデータベースで表現する方法はDoctrineに知らされます(もちろん、Doctrineにこのマッピングを知らせる必要があります。このやり方は[doc defining-models :name]の章で説明されます)。

    NOTE ドメインモデル (クラス、属性、他のクラスへのリレーションなど)の観点からDQLはクエリを表現します

クラス、フィールドとクラスの間のアソシエーションはそれほど重要ではありません。``User``はテーブル/テーブルの名前**ではありません**。``User``クラスにマッピングされるデータベーステーブルの名前は本当に``User``ですが専門用語の違いにはこだわります。あら探しに聞こえるかもしれませんが、ActiveRecordのアプローチのため、リレーショナルモデルはドメインモデルによく似ていますが実際にはとても重要です。カラムの名前はフィールドの名前と同じであることがまれ であり継承が関わると同時に、ドメインモデルから分岐するためにリレーショナルモデルが始まります。データベースの複数のテーブルに実際にマッピングされる``User``クラスを用意できます。この点で”``User``テーブルから選択する”を語るのは単に間違っていることは明らかです。Doctrineの開発は継続されるので2つのモデルより分岐できるようにする機能が追加されてゆきます。

さらなる読み物

オブジェクトリレーショナルマッピングと(object-oriented)ドメインモデルを知らない方には次の読み物をお勧めします:

[http://www.martinfowler.com/books.html Martin Fowlerの本]はたくさんのORMの基本用語、ビジネスロジックと関連パターンのモデリングの異なるアプローチをカバーします。

別の良い読み物は[http://domaindrivendesign.org/books/#DDD Domain Driven Design]です。現在Doctrineで本格的なドメイン駆動のデザインは利用できませんが、これはドメインモデリング用の優れたリソースで、とりわけ複雑なビジネスドメインにおいて、今日広く使われるようになったドメインモデル周辺の用語が詳しく説明されています(Entity、Value Object、Repositoryなど)。

まとめ

Doctrineの背景にある方法論と原則に関する教育上の読み物を少し提供しました。これでDoctrineのすべてに取り組む準備ができています。[doc getting-started :name]の章でDoctrineのセットアップに突入しましょう。

Fork me on GitHub