Orm

Orm 是 物件關聯對映(Object Relational Mapper) 的简寫,它做兩件事:
對應你資料庫裡的資料列到物件, 并能让你在这些物件之間建立關係。
它緊隨 活动記錄模式( Active Record Pattern),但也受到其他系统的影響。

CRUD:建立、讀取、更新和刪除

一旦你配置好你的模型,是時候開始在你的資料庫中建立、讀取、 更新和刪除條目。

建立(Create)

// 選項 1
$new = new Model_Example();
$new->property = 'something';
$new->save();

// 選項 2,使用 forge 代替 new
$new = Model_Example::forge();
$new->property = 'something';
$new->save();

save() 之後,模型已经被儲存到資料庫, 而且如果你正在使用一个 auto_increment 主鍵,在成功儲存後, 它将自动地被設定在實例。

你也可以在模型設定一个特性的陣列:

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

// 使用 "new"
$new = new Model_Example($props);
$new->save();

// 選項 2,使用 forge 代替 new
$new = Model_Example::forge($props);
$new->save();

讀取(Read)

或實際上是 find()。find 方法可用於三種方式:選找一个特定 ID(主鍵)、 尋找第一个/最後一个或帶條件的所有條目。 所有可能的選擇方法(where、or_where、order_by、等)可在頁面底部找到。

Find by ID

// 你知道有一个主題是 ID=2
$entry = Model_Article::find(2);

// ……或當使用複合主鍵
$entry = Model_Article::find(array(2, 'foo'));

在这个範例中它将回傳一个 Model_Article 的實例或 null 當 ID 找不到時。

Find first/last

// 尋找第一个條目
$entry = Model_Article::find('first');

// 尋找最後一个條目添加日期排序
$entry = Model_Article::find('last', array('order_by' => 'date'));

在这个範例中它将回傳一个 Model_Article 的實例或 null 當 ID 找不到時。

Find all

// 尋找所有主題
$entry = Model_Article::find('all');

// 從 category 1 降序排列日期尋找所有主題
$entry = Model_Article::find('all', array(
	'where' => array(
		array('category_id', 1),
	),
	'order_by' => array('date' => 'desc'),
));

// 從 category 1 或 catergory 2 尋找所有主題
$entry = Model_Article::find('all', array(
	'where' => array(
		array('category_id', 1),
		'or' => array(
			array('catergory_id', 2),
		),
	),
));

在这个範例中它将始終回傳一个 Model_Article 實例的陣列。

Find 使用鍊結方法

你不能沒帶屬性呼叫 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');

// 取回一个 Article
$newest_article = $query->get_one();

// 我們重複使用但添加一个回傳限制到上一个查詢,來取回多个主題
$all_articles = $query->limit(15)->get();

这些方法全部都一樣有效,其他四个 find 方法實際上一樣使用 Query 物件, 但不回傳。

部分行選擇

預設情況下,所有 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();

更新(Update)

$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();

刪除(Delete)

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

再一次,沒有更多了:尋找并刪除。

在上一个例子中,$entry 變数及其物件仍然存在。 但主鍵設为 null 而且該物件本身被認为是一个新的實例。 如果你在刪除之後儲存,它会重新被輸入到資料庫并被賦予一个新的主鍵, 在 auto_increment 被開啟時。

使用 find 時所有的選擇方法

方法 參数 範例
select 字串 $column, [字串 $more_columns,] | 陣列 $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 字串|陣列 $relation, [陣列 $conditions]
// 在 find 中包含關聯模型
Model_Article::query()->related(array('author', 'comments'));
Model_Article::find('all', array('related' => array('author', 'comments')));

//=============================
// 在關聯包含一个或更多條件(只支援鍊結)
//=============================

// 第一種方法 - 使用一个陣列
//----------------------------
// 单一條件
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'))));

// 第二種方法 - 使用句點表示法
//----------------------------
// 单一條件
Model_Article::query()
	->related('author')
	->where('author.active', 1);

// 多个條件
Model_Article::query()
	->related('author')
	->where('author.active', 1);
	->where('author.status', 1);
use_view 字串 $viewname
// 使用 view 來檢索資料
Model_Article::query()->use_view('with_comments');
Model_Article::find('all', array('use_view' => 'with_comments'));
where 字串 $column, [字串 $operator,] 混合 $value
// 单一 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 字串 $column, [字串 $direction]
// 单一 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 布林$cache
// 在此查詢停用 ORM 物件快取
Model_Article::query()->from_cache(false);
Model_Article::find('all', array('from_cache' => false));
limit 整数 $limit
// 帶有關聯一致的 limit
Model_Article::query()->limit(10);
Model_Article::find('all', array('limit' => 10));
rows_limit 整数 $limit
// 沒有關聯一致的 limit
Model_Article::query()->rows_limit(10);
Model_Article::find('all', array('rows_limit' => 10));
offset 整数 $offset
// 帶有關聯一致的 offset
Model_Article::query()->offset(10);
Model_Article::find('all', array('offset' => 10));
rows_offset 整数 $offset
// 沒有關聯一致的 offset
Model_Article::query()->rows_offset(10);
Model_Article::find('all', array('rows_offset' => 10));

不要把 limit/offset 兩種类型搞混了!limitrows_offset 的組合(或其他方式), 将導致意想不到的結果!

在此情境中,關聯一致意指預設情況下,當你查詢包含關聯模型時, ORM 将確保關聯結果是一致的。这意味著你的結果并非總是准確的被限制。 例如,如果第一个 parent 在結果有 12 个 children,你的結果集将包含 12 筆紀錄, 即使你已经使用 limit(10)。當你使用 rows_limit(10),該結果集将只包含 10 筆資料, 但将缺少 2 筆關聯紀錄,而且稍候不能被檢索,因为該結果将被快取, 而且快取处理程序并不知道該結果是不完整的!

複雜的 where 子句

使用鍊結你可以建立更複雜的 where 子句,使用 and、or 及巢狀

// 複雜的 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() 函式