Doctrineを利用してconcrete5のオブジェクトを作る(1)
Posted by admin at 9:17 日時 2015/04/23
concrete5もバージョン5.7からデータベースとのアクセスにDoctrineを使うようになりました。Doctrineにはデータベース抽象化レイヤー(DBAL)とO/Rマッパー(ORM)の2つの機能があります。
DBALは特定のデータベース製品に依存しないデータベースへのアクセス手段を提供します。Doctrineへの完全な置き換えが終われば、concrete5をMySQL以外で動作させることも期待できるでしょう。
ORMは、オブジェクト指向プログラミングの中心となるオブジェクトと、データベースとのやりとりを抽象化してくれるしくみです。ググるとインピーダンスミスマッチの解消とか解説には出てきますが、個人的にはクラスにSQLを書かないしくみだと理解するとシンプルかなと思います。
現時点でのconcrete5では、5.6以前の時代の古いコードとの互換性が残されていますので、5.6の頃のようにSQLがコードに混じるような書き方も可能ですが、コアの中の既存のコードも、どんどんDoctrineを使ったコードに書き換えられています。今後concrete5で機能開発する際は、新しくスタンダードな方法を使いましょう!
ということで本連載記事では、テキストフィールドが1カラムだけある超シンプルなデータベースを持った、オリジナルのオブジェクトを設計し、concrete5の管理画面から操作するまでの入門編を解説していきます。
concrete5では、データベーススキーマはXMLで定義します。この形式で作成した db.xml をパッケージのルートドキュメントに配置しておくだけで、このXMLに基づいてデータベースにテーブルが自動で作られます。
XMLの形式は、バージョン5.7.3時点ではADOdb XML Schemaという形式を採用しています。ADOdbはconcrete5のバージョン5.6まで使われていたDBALです。ADOdbは廃止されDoctrineに移行しましたが、XML形式としてまだ生きている状態です。Doctrineの表現方法と互換性がある新しいXML定義の策定が現在進められています。
2015年5月10日追記:Doctrineのエンティティに対応したクラスがパッケージのsrcディレクトリに存在していれば、自動的にデータベースが作成されます。その際、db.xmlの内容は使われません。
次に、このデータベーステーブルと対応するオブジェクトのクラスを示します。サンプルとして作りましたので、ゲッター/セッター以外の機能がありませんが、作ってはいけないという意味ではありません。このオブジェクトの振る舞いを示すメソッドはどんどん足して構いません。
<?php namespace Concrete\Package\EntityExample\Src\Entity; use Database; /** * @Entity * @Table(name="ExampleEntities") */ class Entity { /** * @Id @Column(type="integer") * @GeneratedValue(strategy="AUTO") */ protected $eID; /** * @Column(type="string") */ protected $name; public function getID() { return $this->eID; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } public static function getByID($eID) { $em = Database::get()->getEntityManager(); return $em->getRepository('\Concrete\Package\EntityExample\Src\Entity\Entity') ->find($eID); } public function save() { $em = Database::get()->getEntityManager(); $em->persist($this); $em->flush(); } public function delete() { $em = Database::get()->getEntityManager(); $em->remove($this); $em->flush(); } }
クラス自体とプロパティーに「@」で始まったコメントがありますが、これらをアノテーションと言い、Doctrineにデータベースのカラムとクラスのプロパティとの関係性を伝えるために使われる特殊なコメントです。Doctrineのアノテーションのドキュメントはこちらです。アノテーションを使って、このクラスがどのデータベーステーブルに対応しているか、またどのプロパティがどのカラムと対応しているかを指示します。
ゲッター(getID()
, getName()
)とセッター(setName($name)
)を使ってこのクラスから情報を引き出したり、制御できます。ここには特筆すべきことはありません。
ポイントとなるのはsave()
とdelete()
メソッドでしょう。save()
メソッドを使うと、このオブジェクトのインスタンスをデータベースに保存することができます。これを永続化(persistence)とも言います。オブジェクトのインスタンスはメモリ上に存在するものですので、すぐに消えてしまいます。これを、再び取り出せるように固定するというイメージです。固定する場所はデータベースですが、データベースをDoctrineがEntityManagerとして抽象化しています。逆にdelete()
メソッドを使うとデータベースから取り除く(remove)ことができます。SQLは全く記述していません。
データベースから保存済のオブジェクトを取り出すためには、getByID($eID)
メソッドを使います。こちらもSQLは記述する必要がありません。EntityManagerにオブジェクトのクラスを指定して、IDをキーに探してくださいと指示しているだけ、です。
このクラスを作成しただけで、次のコードで「Foo」という名前がついた新しいエントリーをデータベースに保存することができます。
use Concrete\Package\EntityExample\Src\Entity\Entity; $e = new Entity(); $e->setName('Foo'); $e->save();
また、IDが1のエントリーの名前を「Bar」に変更したり、
use Concrete\Package\EntityExample\Src\Entity\Entity; $e = Entity::getByID(1); $e->setName('Bar'); $e->save();
IDが1のエントリーを削除するのもかんたんです。
use Concrete\Package\EntityExample\Src\Entity\Entity; $e = Entity::getByID(1); $e->delete();
それでは、このクラスの新規作成画面、編集画面、一覧画面をconcrete5の管理画面に作っていきましょう。そのためには、まず一覧画面用の別のクラスを作成する必要があります。第2回「Doctrine ORMを利用したItemListクラスを作成する」に続きます。
この連載記事のサンプルをGitHubにアップしました。
https://github.com/hissy/c5_example_entity
また、concrete5開発者のMainioさんが公開しているサンプルはより実践的で参考になります。
https://github.com/mainio/c5_entities_example
※ 本記事はconcrete5バージョン5.7.3時点で執筆しています。また、concrete5からのDoctrineの使い方については、公式ドキュメントがまだ公開されていません。将来的に変更になる可能性もありますのでご注意ください。