🤖
FuelPHPのORMが使いづらいから少しだけ便利にするtrait
前提
- Rails(ActiveRecord)に慣れている
- なんらかの深遠なる理由でFuelPHPを使う事になった
という感じの人間にとっては頭の整理&少し便利になると思われるtips。
FuelPHPのORM
ActiveRecordと比較して書いてみる
User.where(name: 'hoge').first
User::find('first', ['where' => [['name', 'hoge']]]);
User.where(enabled: true).all
User::find('all', ['where' => [['enabled', 1]]]);
※ 正確には User.where(enabled: true).all.index_by(&:id)
で得られるハッシュのような形になっている
User.where(enabled: true).limit(10).offset(30).all
User::find('all', ['where' => [['enabled', 1]], 'limit' => 10, 'offset' => 30]);
使いづらいと思った点
-
find
のオプションとして渡す配列が読みにくい - ORMのキャッシュが悪さする事が多くデフォルトで使いたくない
と言うわけで、ここを改善するメソッドを生やす。
<?php
trait OrmFindMethods
{
public static function find_by($conditions)
{
$options = static::build_options($conditions);
return static::find('first', $options);
}
public static function find_all($conditions = [], $limit = null, $offset = null)
{
$options = static::build_options($conditions, $limit, $offset);
return static::find('all', $options);
}
protected static function build_options($conditions, $limit = null, $offset = null)
{
$where = [];
foreach ($conditions as $key => $value) {
if (is_array($value)) {
$where[] = [$key, 'IN', $value];
} else {
$where[] = [$key, $value];
}
}
$options = [
'where' => $where,
'from_cache' => false,
];
if (isset($limit) && is_numeric($limit) && $limit > 0) {
$options['limit'] = (int)$limit;
}
if (isset($offset) && is_numeric($offset) && $offset >= 0) {
$options['offset'] = (int)$offset;
}
return $options;
}
}
というtraitを用意して
<?php
class User extends \Orm\Model {
use OrmFindMethods;
…
}
とかやってやる。
このtraitを使うと
User::find_by(['name' => 'hoge']);
User::find_all(['enabled' => 1])
User::find_all(['enabled' => 1], 10, 30);
という感じになる。
ついでに、Railsだと
User.where(id: [1, 2, 3]).all
と書いていた奴は
User::find_all('id' => [1, 2, 3])
と書けるようになる。
おまけ
trait OrmFindMethods
{
…
public static function find_or_initialize_by($conditions)
{
$obj = static::find_by($conditions);
if (!static::is_present($obj)) {
return $obj;
}
$obj = new static();
foreach ($conditions as $key => $value) {
$obj->$key = $value;
}
return $obj;
}
public static function find_or_create_by($conditions, \Closure $block = null)
{
$obj = static::find_by($conditions);
if (!static::is_present($obj)) {
return $obj;
}
$obj = new static();
foreach ($conditions as $key => $value) {
$obj->$key = $value;
}
if (isset($block)) {
$obj->tap($block);
}
$obj->save();
return $obj;
}
public static function is_present($obj)
{
return isset($obj) && !empty($obj);
}
public function tap(\Closure $block)
{
$block($this);
return $this;
}
…
}
までお膳立てするとさらに便利。
Discussion