Orm

ORM はオブジェクト 関係マッピングの略です。 これは、2 つのことを行います: オブジェクトにデータベースのテーブルの行をマップし、 それはあなたがそれらのオブジェクト間の関係を確立することができます。
それは Active Record パターンに従いますが、他のシステムに影響も受けます。

CRUD: 作成、読み取り、更新、削除

一度あなたのモデルを設定したそれは、作成、読み取り、更新、 およびデータベース内のエントリを行います。

作成

// オプション 1
$new = new Model_Example();
$new->property = 'something';
$new->save();

// オプション 2, forge メソッドでインスタンスを作成して使用する。
$new = Model_Example::forge();
$new->property = 'something';
$new->save();

save() した後、 model がデータベースに保存されていて、 主キーに auto_increment を使用している場合は、保存後に自動的にインスタンスに設定されます。

配列からモデルのプロパティを設定することができます:

$props = array('property' => 'something');

// "new" を使用する。
$new = new Model_Example($props);
$new->save();

// オプション 2, forge メソッドでインスタンスを作成して使用する。
$new = Model_Example::forge($props);
$new->save();

読み取り

使うのは find() メソッドです。指定した ID (主キー)、最初/最後、条件を満たすもの全部、の 3 通りの方法があります。 可能な選択方法 (where, or_where, order_by 等) はこのページの下で説明します。

IDから検索する

// ID=2 の記事を検索する
$entry = Model_Article::find(2);

// 複合主キーを使用している場合
$entry = Model_Article::find(array(2, 'foo'));

この例では、ID が見つからなかったときは Model_Article インスタンスまたは null を返します。

最初と最後を検索する

// 最初のエントリーを検索する
$entry = Model_Article::find('first');

// date カラムで並び替えて最新のエントリーを検索する
$entry = Model_Article::find('last', array('order_by' => 'date'));

この例では、ID が見つからなかったときは Model_Article のインスタンスまたは null を返します。

すべてを検索する

// すべての記事を検索する。
$entry = Model_Article::find('all');

// category_id カラムの値が 1 の記事を検索し、 date カラムを降順に並び替える。
$entry = Model_Article::find('all', array(
	'where' => array(
		array('category_id', 1),
	),
	'order_by' => array('date' => 'desc'),
));

// category_id カラムの値が 1 か 2 の記事を検索する。
$entry = Model_Article::find('all', array(
	'where' => array(
		array('category_id', 1),
		'or' => array(
			array('category_id', 2),
		),
	),
));

この例では、それは常に Model_Article のインスタンスの配列を返します。

メソッドチェーンを使用して見つける

find() メソッドをプロパティ無し、あるいは null プロパティ、あるいはパラメータに null が含まれる変数、で呼び出すことはできません。 もし、そうした場合、null が返ります。メソッドチェーンを使用したい場合、 query() メソッドを使用してください。

$query = Model_Article::query()->where('category_id', 1)->order_by('date', 'desc');

// ページネーションのための記事の総数を知りたい場合。
$number_of_articles = $query->count();

// 最大の ID の値を知りたい場合。
$number_of_articles = $query->max('id');

// 一番最初に投稿された記事の日付を知りたい場合。
$number_of_articles = $query->min('date');

// 1 件だけ取得した場合。
$newest_article = $query->get_one();

// 以前のクエリに取得したい件数の制限を加えて、複数の記事を取得する場合。
$all_articles = $query->limit(15)->get();

これらのメソッドは等しく有効です。その他の 4 メソッドも Query オブジェクトを使いますが、 オブジェクトを返しません。

配列に変換する

to_array() メソッドを使うことで、単一のクエリ結果を配列に変換できます。


// using the chaining method. select one row and convert it to an array
$entry = Model_Article::query()->where('id', '=', 8)->get_one()->to_array();

// select one row, convert it to an array, include custom data and also run recursivly
$entry = Model_Article::query()->where('id', '=', 8)->get_one()->to_array(true, true);

// select one row and convert it to an array, include custom data, run recursivly and get eav relations
$entry = Model_Article::query()->where('id', '=', 8)->get_one()->to_array(true, true, true);

カラムを指定して部分的に取得

デフォルトではすべての ORM の find メソッドはテーブルのすべてのカラムを取得します。 select 配列 エントリを使うか、 select() メソッドを使うことでこの挙動を変更することができます。

// 配列を使う方法。 'name' と 'date' のカラムのみを取得します
$entry = Model_Article::find('last', array('select' => array('name', 'date')));

// 上記と同じですがメソッドチェーンを使っています
$entry = Model_Article::query()->select('name', 'date')->get();

// 配列を使う方法。'date' カラム以外のすべてのカラムを選択します
$entry = Model_Article::find('all', array('select' => array(array('date' => false))));

// 上記と同じですがメソッドチェーンを使っています
$entry = Model_Article::query()->select(array('date' => false))->get();

更新

$entry = Model_Article::find(4);
$entry->title = 'My first edit';
$entry->author = 'Total n00b';
$entry->save();

これだけです。特別なことはありません。検索して、プロパティを変更して、保存すれば良いのです。

モデルのプロパティは、配列で設定することもできます。

$entry = Model_Article::find(4);
$entry->set(array(
	'title'  => 'My first edit',
	'author' => 'Total n00b'
));

$entry->save();

削除

$entry = Model_Article::find(4);
$entry->delete();

ここもこれだけです。検索して、削除すれば良いのです。

直前の例では、 $entry 変数とそのオブジェクトは存在しています。 主キーは null にセットされており、オブジェクト自身はあたらしいインスタンスとみなされます。 削除した後に保存した場合、データベースに再挿入され、 auto_increment が on の場合は新しい主キーが割り当てられます。

find を使用するときの全ての選択メソッド

メソッド パラメータ
select string $column, [string $more_columns,] | array $filter
// いくつかのカラムだけを取得します。
Model_Article::query()->select('id', 'name');
Model_Article::find('all', array('select' => array('id', 'name')));

// 'name' を除く全てのカラムを取得します。
Model_Article::query()->select(array('name' => false));
Model_Article::find('all', array('select' => array(array('name' => false))));
related string|array $relation, [array $conditions]
// find に 関係するモデルを含めます。
Model_Article::query()->related(array('author', 'comments'));
Model_Article::find('all', array('related' => array('author', 'comments')));

//=============================
// リレーションにおいて、1 つ、または、複数の条件を含みます。 (メソッドチェーンでのみサーポートされています)
//=============================

// 1 つ目の方法 - array を使用
//----------------------------
// 条件が 1 つの場合
Model_Article::query()
    ->related('author', array('where' => array(array('active', '=', 1))));

// 条件が複数の場合
Model_Article::query()
    ->related('author', array('where' => array(array('active', '=', 1), array('status', '=', 'X'))));

// 2 つ目の方法 - ドット表記を使用
//----------------------------
// 条件が 1 つの場合
Model_Article::query()
	->related('author')
	->where('author.active', 1);

// 条件が複数の場合
Model_Article::query()
	->related('author')
	->where('author.active', 1);
	->where('author.status', 1);
use_view string $viewname
// データ取得のためにビューを使用
Model_Article::query()->use_view('with_comments');
Model_Article::find('all', array('use_view' => 'with_comments'));
where string $column, [string $operator,] mixed $value
// 1 つの where 
Model_Article::query()->where('id', 4);
Model_Article::find('all', array('where' => array('category_id' => 5)));

// 複数の where の使用例
Model_Article::query()->where('id', 4)->where('category_id', '>', 1);
Model_Article::query()->where(array('id' => 4, 'category_id' => 6));
Model_Article::find('all', array('where' => array(array('category_id', '=', 5), array('publish', '<', time()))));

// or where を使用する。
Model_Article::query()->where('id', 4)->or_where('id', 5);
order_by string $column, [string $direction]
// 1 つの order_by
Model_Article::query()->order_by('name', 'desc');
Model_Article::find('all', array('order_by' => array('name' => 'desc')));

// 複数の order_by の使用例
Model_Article::query()->order_by('name', 'desc')->order_by('category_id', 'asc');
Model_Article::query()->order_by(array('name' => 'desc', 'category_id' => 'asc'));
Model_Article::find('all', array('order_by' => array(array('name' => 'desc', 'category_id' => 'asc'))));
from_cache bool$cache
// このクエリでは ORM オブジェクトのキャッシュを行わなくする
Model_Article::query()->from_cache(false);
Model_Article::find('all', array('from_cache' => false));
limit int $limit
// 関係一貫性のある件数制限
Model_Article::query()->limit(10);
Model_Article::find('all', array('limit' => 10));
rows_limit int $limit
// 関係一貫性ののない件数制限
Model_Article::query()->rows_limit(10);
Model_Article::find('all', array('rows_limit' => 10));
offset int $offset
// 関係一貫性のあるオフセット
Model_Article::query()->offset(10);
Model_Article::find('all', array('offset' => 10));
rows_offset int $offset
// 関係一貫性のないオフセット
Model_Article::query()->rows_offset(10);
Model_Article::find('all', array('rows_offset' => 10));

2つの limit/offset タイプを混在させないでください! limitrows_offset (もしくはその逆) の組み合わせは 予期せぬ結果につながるでしょう!

この文脈において、関係モデルを含んだクエリを実行するとき、デフォルトでは、 ORM は関係する結果が一致することを確認する、ということを関係一貫性は意味しています。 これは検索結果がいつも正確に 件数制限されているわけではないことを意味します。例えば、検索結果において最初の親が 12 件の子を持っている場合、たとえ limit(10) を使ったとしても 結果セットは 12 レコード含みます。 rows_limit(10) を使うと、結果セットは 10 レコードだけ含みますが、関係のある 2 レコードは失われ、後に取得することはできません。 この理由は、結果がキャッシュされ、キャッシュハンドラは結果が不完全であることを知らないためです!

複雑な where 句

and、or、そしてネストを使ったチェーンにより、さらに複雑な where 句を作ることができます。

// 複雑な where 句
Model_Article::query()
  ->where('author', '=', 16)
  ->and_where_open()
      ->where('date', '<', time())
      ->or_where('draft', '=', 1)
  ->and_where_close();

// WHERE `author` = 16 AND (`date` < 1348404127 OR `draft` = 1) が生成されます。

ネストされた OR を作るには or_where_open()or_where_close() を使ってください。 必ず open メソッドと close メソッドが一致するように気をつけてください。

サブクエリ

別々のクエリオブジェクトを構築し、パースするために get_query() を使うことによって、サブクエリを作ることができます。

$subQuery = Model_Article::query()
        ->select('author')
        ->where('date', '<', time())
        ->where('draft', '=', 1);

Model_Article::query()
        ->where('author', '=', 16)
        ->or_where('author', $subQuery->get_query(true))
        ->get();

カスタム SQL

カスタム SQL 文を実行し、 ORM モデル (または、モデルのリスト) として結果を得ることも可能です。これは ORM 自体の一部ではありませんが、知っておくと便利です。 詳細は DB::query() 関数を見てください。

DB::query('SELECT * FROM `articles` WHERE `id` = 1')->as_object('Model_Article')->execute();

可能であれば、 query() 関数を使うことが推奨されています。