多対多のリレーションシップ
Propelはデータベースレベルで取り扱われるリレーションシップの方法への直接のリレーションシップマップをサポートするので、Propelでの多対多のリレーションシップに関しては魔法のようなサポートはありません -- 例えば、(Javaの Hibernateのような)より抽象化を含んだORMレイヤによって提供されたサポートなどです。 このことが意味することはPropelで多対多のリレーションシップを取り組むことはルックアップ/クロスリファレンステーブルを参照することが要求されます。自動的にこれを行う常に独自のメソッドを作成してスタブクラスに設置することが出来ます。将来'テーブルがクロスリファレンステーブルであることをPropelに示す方法が存在するかもしれません -- そしてPropelはこの一部を自動化することが出来るかもしれません。しかし現在はまだそうではありません。
例
例を見てみましょう、本とそれらを読む人々を関連づける必要があるとします -- 多くの人は一つの本を読み、一人が多くの本を読みます:
<table name="book_reader_ref">
<column name="book_id" type="INTEGER" required="true" primaryKey="true"/>
<column name="reader_id" type="INTEGER" required="true" primaryKey="true"/>
<foreign-key foreignTable="book">
<reference
local="book_id"
foreign="book_id"/>
</foreign-key>
<foreign-key foreignTable="reader">
<reference
local="reader_id"
foreign="reader_id"/>
</foreign-key>
</table>
PHPスクリプトで関連したエンティティを取得するための"仲介を通した"(middleman)クロスリファレンステーブルを利用する必要があるとします:
<?php $books = BookPeer::doSelect(new Criteria()); // 本のためにすべての読者を取得します foreach($books as $book) { $readerRefs = $book->getBookReaderRefsJoinReader(); foreach($readerRefs as $ref) { $reader = $ref->getReader(); // <-- これは追加クエリではありません // 上記でJoinメソッドを使用したので } }
上記のコードは1+n文を実行します。nは返されたbooks列の数です:
- SELECT * FROM book
- n x SELECT * FROM book_reader_ref INNER JOIN reader ON reader.reader_id = book_reader_ref.reader_id WHERE book_reader_ref.book_id = $book->getBookId()
このメソッドは過剰な無駄遣いではありませんけれど -- 多対多のjoinされた結果を取得するために単独のselectを実行することは通常意味をなしません -- しかしながら、単独のメソッドコールよりもあまりエレガントではありません。クロスリファレンステーブルの明示的なリファレンスを要求することはPropelによって採用されたとてもリテラルなデータモデリングアプローチを使用するための欠点です(Torqueから継承されました)。
提案: カスタムのスタブメソッドを作成する
人生を楽にするために、Bookと/もしくはReaderクラスのスタブメソッドを作成したいと思います。例えば、getReaders()メソッドを上記のロジックをカプセル化するBookクラスに追加することが出来ます。
Book.phpスタブクラスを編集して次のメソッドを追加して下さい:
<?php class Book extends BaseBook { /** * Convenience method to fetch all related Reader objects. * @param Criteria $c An [optional] Criteria to limit results * @return array Reader[] */ public function getReaders($c = null) { $readers = array(); foreach($book->getBookReaderRefsJoinReader($c) as $ref) { $readers[] = $ref->getReader(); } return $readers; } }
