Orm
ORM はオブジェクト
関係マッピングの略です。 これは、 2 つのことを行います: オブジェクトにデータベースのテーブルの行をマップし、
それはあなたがそれらのオブジェクト間のリレーションを確立することができます。
それは
Active Record パターンに従いますが、 他のシステムに影響も受けます。
Relations: はじめに
設定
基本的な設定
protected static $_has_many = array('comments');
例えば、 Model_Article で指定した場合、
comments のインスタンスを通して主キーにマッチしている article_id フィールドを持つ多数の
Model_Comment オブジェクトとして取得する事を可能にします。
完全な設定
protected static $_has_many = array('comments' => array(
'model_to' => 'Model_Fancy_Comment',
'key_from' => 'article_id',
'key_to' => 'parent_article_id',
'cascade_save' => true,
'cascade_delete' => false,
// 特定のリレーションタイプのために、もう少しオプションがあります
));
基本的な例として、 Orm はモデル名とフィールドのマッピングを自動的に行います。この例では、明示的にターゲットモデルのクラス名を指定しており、
フィールドはそれらを関連付けることや、現在のオブジェクト上で行なわれた動作をターゲットに
カスケードする必要があるかどうかで利用されます。
comment の parent_article_id フィールドが現在のオブジェクトの article_id に対応する
Model_Fancy_Comment オブジェクトの配列を返します。 オブジェクトに操作を保持する時、
その操作は、そのロードしたリレーションに関しても実行されます。削除することはデフォルトではカスケードされませんが、
あなたがこのスイッチを ON にするならば、可能です。
リレーションを取得し、それらの出力を制限するときの制限: あなたは、メインオブジェクトのステートメントを
複合して使うことができません。 それは where_open() を使った
ネスト状態の括弧を使っている問合わせです。問合わせがあることができる標準 (非ネスト) は、問題なく適用できます。
技術的に、それはこのように働きます : 出力を制限するために、ベース・モデルのテーブルの上の問合わせは、
実は制限をそれの上に置くサブクエリです。ネストになったそれらのどの状況でも、
サブクエリとさらに加わられたリレーションの結果に関して適用されます。
構成オプション
最も一般的な命名規則を使用する場合の構成はすべてオプションです。
model_to |
別名から算出 |
指定された場合は、対象モデルの完全なクラス名を必要とします (例えば Model_Comment)。
デフォルトでは、この値はエイリアスの単数形に "Model_"を付加することによって形成されます
(例えば 'comments' は 'Model_Comment' となる) 。モデルが別の名前空間にある場合、 PHP
は文字列内での相対的な名前空間をサポートしいないため、先頭のバックスラッシュを除いた、
完全な名前空間を指定する必要があります (例えば 'Admin\Model_User') 。 |
key_from |
現在のモデルでのリレーションのために使用するキー (通常は id) |
ターゲットモデルを現在のモデルのテーブルの任意のフィールドにマップすることを許可します。 |
key_to |
現在のモデル名から算出 |
デフォルトでは、 Model_Article から多くの Model_Comment へのリレーションは、
comments テーブルの article_id フィールドを使用します |
cascade_save |
bool true |
カスケードすることは、モデルの活動がそのリレーションに関して繰り返されることを意味します。 このように、
保存をカスケードすることは同様にリレーションを保持し、削除をカスケードすることは、
同様にリレーションも削除します。 カスケード削除について特に注意をしてください!
あなたは、元のモデルの delete() もしくは save() を呼び出すときに、
最初の引数に true を渡すことで、実行時にこれらのオプションを無効にすることができます。 |
cascade_delete |
bool false |
conditions |
array() |
'where' と 'order_by' キーを受け取ります。これらは、通常の使用よりも制限されます:
where は array(field, compare, value) を含む配列の配列でなければなりません。
order_by はフィールドの配列や連想の field => direction
が含まれています。
Note: これらは常に使用され、オフにすることはできません。 |
使い方
ORM はリレーションの一括読み込みと遅延読み込みの両方を可能にします。一括読み込みは、
一部 (またはすべて) のリレーションは、元の照会でフェッチされていることを意味します。 遅延読み込みは、
あなたがそれらを要求するまでリレーションがフェッチされないことを意味します。
// 一括読み込み。join が使われます:
$post = Model_Post::find('all', array('related' => array('comments')));
// もしくは
$post = Model_Post::query()->related('comments')->get();
// これで $post->comments が使用可能です。これ以上のクエリは発生しません。
// もしくは、遅延読み込みを使用。joinは使われず、一度でも要求したときに改めてクエリが発生します。
// まず "post" を取得。join 無しの 1 クエリ。
$post = Model_Post::find('first');
// ここで (まだロードされていない) コメントを要求すると、 join 無しの別のクエリが自動的に実行されます。
$comments = $post->comments;
// あるいは、get() を使用すれば条件を追加できます:
$comments = $post->get('comments', array('where' => array(array('field', '=', $value))));
where/order_by 条件と使い方
ORM でフェッチするときにも条件を追加することができます。 それはまたデータ検索で
それらをフェッチしている時のみ条件が有効なことに注意してください。
遅延ロードでも任意のデフォルト条件 (上記の設定の表を参照) は当然ながら使用されますが、
追加の条件は一括読み込みでのみ可能です。
// クエリ配列を使用
$post = Model_Post::find('first', array(
'related' => array(
'articles' => array(
'order_by' => array('id' => 'desc'),
'where' => array(
array('publish_date', '>', time()),
array('published', '=', 1),
),
),
),
));
// メソッドチェーンを使用して
$post = Model_Post::query()->related('articles', array(
'order_by' => array('id' => 'desc'),
'where' => array(
array('publish_date', '>', time()),
array('published', 1), // 使用時に '=' は省略することができる
),
)->get_one();
// しかし、同じことがまたカラムにリレーション名を付けることによって行うことができます:
$post = Model_Post::query()->related('articles')
->order_by('articles.id', 'desc')
->where('articles.publish_date', '>', time())
->where('articles.published', 1)
->get_one();
入れ子になったリレーションシップと使い方
それは (あまりにも多くの結合が必要なためクエリの作成に注意が必要ですが)
深さに制限無くリレーションのリレーションを取得することも可能です。これらのすべて、または一部は、以下に例示されている場所と
order_by を条件と組み合わせることができます。
リレーションのリレーションを取得したい場合は、そのリレーションの前に "parent"
のリレーションをロードする必要があるため、順番がここで問題になることに注意してください。そうでない場合は例外が投げられます。
// クエリ配列を使用
$post = Model_Post::find('first', array(
'related' => array(
'articles' => array(
'related' => array(
'user' => array(
'related' => array('profile'),
'where' => array('active', 1),
),
),
'order_by' => array(
'published' => 'desc',
),
),
),
));
// 唯一のメソッドチェーンを使用して
$post = Model_Post::query()
->related('articles')
->related('articles.user')
->related('articles.user.profile')
->where('articles.user.active', '=', 1)
->order_by('articles.published', 'desc')
->get_one();
// または配列とメソッドチェーンを組み合わせる
$post = Model_Post::query()
->related('articles', array(
'related' => array('user' => array(
'where' => array('active' => 1),
)),
'order_by' => array('published', 'desc'),
))
->related('articles.user.profile')
->get_one();
結合の種類
デフォルトでは、ORM は 'left' join を使用してリレーションを結合します。異なるリレーションを指定するには、'join_type' 条件を使用します:
$post = Model_Post::find('first', array(
'related' => array(
'articles' => array(
'join_type' => 'inner',
'where' => array(
array('publish_date', '>', DB::expr(time())),
array('published', '=', DB::expr(1)),
),
'order_by' => array('id' => 'desc'),
),
),
));
where 句は join 前に実行されるため、 where 句が含まれている場合は OUTER JOIN にはならず、
where 句の条件は結合前フィルタのように動作します。
JOIN の条件を定義するためには以下のようにします:
$post = Model_Post::find('all', array(
'related' => array(
'articles' => array(
'join_type' => 'left outer',
'join_on' => array(
array('publish_date', '>', DB::expr(time())),
array('published', '=', DB::expr(1)),
),
'order_by' => array('id' => 'desc'),
),
),
));
これは、 WHERE 句の条件の代わりに、 ON 句の検索条件として追加します。
結合時にリテラル値を渡したい場合は、カラム名としてエスケープされるのを避けるために DB::expr() でカプセル化しなければならないことに注意してください。
リレーションタイプ
ORM はネイティブに次のリレーションのタイプをサポートしています。
- Belongs To
そのテーブルにリレーションを保持する主キーを持つ、 1 つの関連オブジェクトに属します。
- Has One
別のテーブル (これに属する) のいずれかの他の行に保存され、その主キーは、
1 つの関連オブジェクトを持っています。
- Has Many
別のテーブル (このいずれかに属している) 他の多くの行に保存され、
その主キーに関連する多くのオブジェクトを持っています。
- Many to Many
それらの主キーは、両方のテーブルから主キーのペアを保持し、間にテーブルに保存されています。
持っていると多くのオブジェクトに属します。