GitHubBehaviours¶はじめに¶モデルの中で似た内容を持つクラスを見つけることはよくあります。これらの内容はコンポーネント自身のスキーマ(リレーション、カラムの定義、インデックスの定義など)に関連することがあります。このコードをリファクタリングする明らかな方法は基底クラスとそれを継承するクラスを用意することです。継承はこれらの一部しか解決しません。次のセクションで``Doctrine_Template``が継承よりもはるかに強力で柔軟であることを示します。``Doctrine_Template``はクラステンプレートシステムです。基本的にテンプレートはRecordクラスがロードできるすぐ使える小さなコンポーネントです。テンプレートがロードされるとき``setTableDefinition()``と``setUp()``メソッドが起動されこれらの内部でメソッドが呼び出され渦中のクラスに導かれます。この章ではDoctrineで利用できる様々なビヘイビアの使い方を説明します。独自ビヘイビアの作り方も説明します。この章のコンセプトを掴むために``Doctrine_Template``と``Doctrine_Record_Generator``の背景にある理論に慣れなければなりません。これらのクラスがどんなものであるのか手短に説明します。ビヘイビアを言及するときテンプレート、ジェネレータとリスナーを広範囲に渡って使用するクラスパッケージを意味します。この章で紹介されるすべてのコンポーネントは``core``ビヘイビアとしてみなされています。これはDoctrineのメインリポジトリに保管されていることを意味します。通常ビヘイビアはテンプレートクラス(``Doctrine_Template``を継承するクラス)でジェネレータを使用します。共通のワークフローは次の通りです:新しいテンプレートが初期化されるテンプレートはジェネレータを作成し``initialize()``メソッドを呼び出すテンプレートはクラスに添付されるご存知かもしれませんがテンプレートは共通の定義とオプションをレコードクラスに追加するために使われます。ジェネレータの目的はとても複雑です。通常これらはジェネリックレコードクラスを動的に作成するために使われます。これらのジェネリッククラスの定義はオーナーのクラスによります。クラスをバージョニングする``AuditLog``カラムの定義はすべてのsequenceとautoincrementの定義が削除された親クラスのカラムです。次の例において``TimestampBehavior``と呼ばれるテンプレートを定義します。基本的にテンプレートの目的はこのテンプレートをロードするレコードクラスに日付カラムの’created’と’updated’を追加することです。加えてこのテンプレートはレコードのアクションに基づいてこれらのカラムを更新するTimestampリスナーを使用します。TimestampListener());}}タイムスタンプの機能を必要とする``BlogPost``クラスを考えてみましょう。行う必要があるのはクラスの定義に``actAs()``の呼び出しを追加することです。$this->actAs('TimestampBehavior');}}YAMLフォーマットでの例は次の通りです。上記で説明した機能は既にお話した``Timestampable``ビヘイビアを通して利用できます。:name]セクションに戻って詳細内容を読むことができます。以前の章よりも状況は複雑になりがちです。他のモデルクラスへのリレーションを持つクラスがあり任意のクラスを格調されたクラスで置き換えたいことがあります。);}}YAMLフォーマットでの例は次の通りです。User:``User``と``Email``クラスを拡張し、例えば``ExtendedUser``と``ExtendedEmail``クラスを作る場合、``ExtendedUser``は``Email``クラスへのリレーションを保存しますが``ExtendedEmail``クラスへのリレーションは保存しません。``User``クラスの``setUp()``メソッドをオーバーライドして``ExtendedEmail``クラスへのリレーションを定義することはできますが、継承の本質を失います。injection)の方法でエレガントに解決します。次の例では2つのテンプレート、``UserTemplate``と``EmailTemplate``を``User``と``Email``クラスが持つほぼ理想的な定義で定義します。);}}リレーションの設定方法に注目してください。Record具象クラスを指し示すのではなく、テンプレートへのリレーションを設定しています。これはDoctrineにこれらのテンプレート用のRecord具象クラスを探すように伝えています。}YAMLフォーマットでの例は次の通りです。[EmailTemplate]次のコードスニペットを考えてみましょう。テンプレート用の具象実装を設定していないのでこのコードスニペットは動きません。exception次のバージョンが動作します。)))Tipテンプレート用の実装はマネージャー、接続とテーブルレベルでも設定できます。デリゲートメソッド¶フルテーブル定義のデリゲートシステムとして振る舞うことに加えて、Doctrine\_Template``はメソッドの呼び出しのデリゲートを可能にします。これはロードされたテンプレート内のすべてのメソッドはテンプレートをロードしたレコードの中で利用できることを意味します。この機能を実現するために内部では__call()``と呼ばれるマジックメソッドが使用されます。}``Doctrine_Table``クラスにメソッドをデリゲートすることも簡単にできます。名前衝突を避けるために、テーブルクラス用のメソッドはメソッド名の最後に追加される``TableProxy``の文字列を持たなければなりません。$userTable->findUsersWithEmail();Tipそれぞれのクラスは複数のテンプレートから構成されます。前のものを常にオーバーライドします。ビヘイビアを作成する¶この節では独自ビヘイビア作成用の方法を説明します。一対多のEメールが必要な様々なRecordクラスを考えてみましょう。Emailクラスを即座に作成する一般的なビヘイビアを作成することでこの機能を実現します。``EmailBehavior``と呼ばれるビヘイビアを``setTableDefinition()``メソッドで作成することからこのタスクを始めます。``setTableDefinition()``メソッドの内部では動的なレコードの定義に様々なヘルパーメソッドが使われます。);}}コアビヘイビア¶コアビヘイビアを使う次のいくつかの例のために以前の章で作成したテスト環境から既存のスキーマとモデルをすべて削除しましょう。–Doctrineにはモデルにそのまま使える機能を提供するテンプレートが搭載されています。モデルでこれらのテンプレートを簡単に有効にできます。``Doctrine_Records``で直接行うもしくはYAMLでモデルを管理しているのであればこれらをYAMLスキーマで指定できます。次の例ではDoctrineに搭載されているビヘイビアの一部を実演します。);}}YAMLフォーマットでの例は次の通りです。``auditLog``オプションはauditのログ履歴を無効にするために使われます。これはバージョン番号を維持したいがそれぞれのバージョンでのデータを維持したくない場合に使います。予期していなかったであろう2の追加ステートメントがあることに注目してください。ビヘイビアは自動的に``blog_post_version``テーブルを作成しこれを``blog_post``に関連付けます。``BlogPost``を挿入もしくは更新するときバージョンテーブルは古いバージョンのレコードをすべて保存していつでも差し戻しできるようにします。最初に``NewsItem``をインスタンス化するとき内部で起きていることは次の通りです:``BlogPostVersion``という名前のクラスが即座に作成される。レコードが指し示すテーブルは``blog_post_version``である``BlogPost``オブジェクトが削除/更新されるたびに以前のバージョンは``blog_post_version``に保存される``BlogPost``オブジェクトが更新されるたびにバージョン番号が増える。``version``カラムの値が``2``であることに注目してください。2つのバージョンの``BlogPost``モデルを保存したからです。ビヘイビアが格納する``revert()``メソッドを使用することで別のバージョンに差し戻すことができます。``version``カラムの値が1に設定され``title``は``BlogPost``を作成するときに設定されたオリジナルの値に戻ります。Timestampable¶Timestampableビヘイビアは``created_at``と``updated_at``カラムを追加しレコードが挿入と更新されたときに値を自動的に設定します。日付を知ることは共通のニーズなので``BlogPost``モデルを展開してこれらの日付を自動的に設定するために``Timestampable``ビヘイビアを追加します。$this->actAs('Timestampable');}}YAMLフォーマットでの例は次の通りです。...``updated_at``フィールドではなく``created_at``タイムスタンプといったカラムの1つだけを使うことに興味があるのであれば、下記の例のようにフィールドのどちらかに対して``disabled``をtrueに設定します。timestampカラム型を使いたくない場合のタイムスタンプのフォーマット。||Sluggable¶``Sluggable``ビヘイビアは素晴らしい機能の1つでタイトル、題目などのカラムから作成できる人間が読解できるユニークな識別子を保存するためにモデルにカラムを自動的に追加します。これらの値は検索エンジンにフレンドリーなURLに使うことができます。);}}YAMLフォーマットでの例は次の通りです。...新しい投稿を作成する際に何が起きるのか見てみましょう。``title``カラムの値に基づいて``slug``カラムの値が自動的に設定されることに注目してください。スラッグが作成されるとき、デフォルトでは``urlized``が使われます。これはURLにフレンドリーではない文字は削除されホワイトスペースはハイフン(-)に置き換えられます。uniqueフラグは作成されたスラッグがユニークであることを強制します。incrementな整数がスラッグに自動的に追加されます。``canUpdate``フラグはurlフレンドリーなスラッグを生成する際にユーザーが使用するスラッグを自動的に設定することを許可します。||I18n¶``Doctrine_I18n``パッケージはレコードクラス用の国際化サポートを提供するビヘイビアです。次の例では``title``と``content``の2つのフィールドを持つ``NewsItem``クラスがあります。異なる言語サポートを持つ``title``フィールドを用意したい場合を考えます。);}}YAMLフォーマットでの例は次の通りです。``title``フィールドが``news_item``テーブルに存在しないことに注目してください。翻訳テーブルにあるとメインテーブルで同じフィールドが存在してリソースの無駄遣いになるからです。基本的にDoctrineは常にメインテーブルから翻訳されたフィールドをすべて削除します。structure)に変換できます。ツリー構造全体を1つのクエリで効率的に読み取ることができます。このビヘイビアはツリーのデータを操作するための素晴らしいインターフェイスも提供します。例として``Category``モデルを考えてみましょう。);}}YAMLフォーマットでの例は次の通りです。root_id、lft、``rgt``と``level``カラムが自動的に追加されることに注目してください。これらのカラムはツリー構造を編成して内部の自動処理に使われます。ここでは``NestedSet``ビヘイビアの100%を検討しません。専用の章]があります。Searchable¶``Searchable``ビヘイビアは全文インデックス作成と検索機能を提供します。データベースとファイルの両方のインデックスと検索に使われます。);}}YAMLフォーマットでの例は次の通りです。``job_index``テーブルおよび``job``と``job_index``の間の外部キーが自動的に生成されることに注目してください。:name]の章で見つかります。下記のコードはデモのみです。Geographicalビヘイビアは2つのレコードの間のマイルもしくはキロメータの数値を決定するためのレコードデータで使うことができます。$this->actAs('Geographical');}}YAMLフォーマットでの例は次の通りです。Geographicalビヘイビアが2つのレコードの距離を算出するために使われるレコードに``latitude``と``longitude``カラムを自動的に追加することに注目してください。使い方の例は下記の通りです。``getDistance()``メソッドの2番目の引数はキロメーターで距離を返すかどうかです。デフォルトはfalseです。上記のSQLクエリが書かなかったSQLの束を含んでいることに注目してください。これはレコードの間のマイル数を計算するためにビヘイビアによって自動的に追加されます。}SoftDelete¶``SoftDelete``ビヘイビアは``delete()``機能をオーバーライドし``deleted``カラムを追加するとてもシンプルだが大いにおすすめできるモデルビヘイビアです。``delete()``が呼び出されるとき、データベースからレコードを削除する代わりに、削除フラグを1にセットします。下記のコードは``SoftDelete``ビヘイビアでモデルを作る方法です。$this->actAs('SoftDelete');}}YAMLフォーマットでの例は次の通りです。INNODBビヘイビアを動かしてみましょう。すべての実行されるクエリのためにDQLコールバックを有功にする必要があります。``SoftDelete``ビヘイビアにおいて追加のWHERE条件で``deleted_at``フラグが設定されているすべてのレコードを除外するSELECT文をフィルタリングするために使われます。削除されていないレコードだけを返すためにwhere条件が自動的に追加されたことに注目してください。$count;上記のコード0をechoします。deleteフラグが設定されたので保存されたレコードが除外されます。入れ子のビヘイビア¶versionable、searchable、sluggable、と完全なI18nである完全なwikiデータベースを与える複数のビヘイビアの例です。$this->actAs('Timestampable');}}YAMLフォーマットでの例は次の通りです。stringNote現在上記の入れ子のビヘイビアは壊れています。開発者は後方互換性を修正するために懸命に取り組んでいます。修正ができたときにアナウンスを行いドキュメントを更新します。ファイルを生成する¶デフォルトではビヘイビアによって生成されるクラスは実行時に評価されクラスを格納するファイルはディスクに書き込まれません。これは設定オプションで変更できます。下記のコードは実行時にクラスを評価する代わりにクラスを生成してファイルに書き込むためのI18nビヘイビアを設定する方法の例です。);}}YAMLフォーマットでの例は次の通りです。eval()]``を使用する代わりにこれでビヘイビアはファイルを生成します。自動生成モデルをクエリしたい場合添付されたモデルを持つモデルがロードされ初期化されることを確認する必要があります。``Doctrine_Core::initializeModels()``スタティックメソッドを使用することでこれをできます。$q->execute();Noteモデルが最初にインスタンス化されるまでビヘイビアはインスタンス化されないのでこれは必須です。上記の``initializeModels()``メソッドは渡されたモデルをインスタンス化して情報がロードされたモデルの配列に適切にロードされることを確認します。===Doctrineビヘイビアについて多くのことを学びます。Doctrineに搭載されている素晴らしいビヘイビアの使い方と同じようにモデル用の独自ビヘイビアの書き方を学びます。Searchable]ビヘイビアを詳しく検討するために移動する準備ができています。これは大きなトピックなので専門の章が用意されています。