ORM Observer
FuelPHPのORMパッケージに含まれるオブザーバがとても便利。
イベントベースになっていて、特定のイベント発生時に処理を行うことが出来る。
たとえば、before_insert, before_save, after_loadなどのタイミング。
標準でいくつかのオブザーバが付属していて、自前で作ることもできる。
付属オブザーバ
- Observer_Self
- 任意のイベント発生時に、モデルに含まれる任意の関数を実行する
- Observer_CreatedAt
- レコードが挿入されたときにcreated_atを設定
- Observer_UpdatedAt
- レコードが更新されたときにupdated_atを設定
- Observer_Validation
- レコードの挿入・更新前にカラムのデータをバリデーションする
- Observer_Typing
- カラムのデータをキャストする
- Observer_Slug
- URLのスラグを生成する
試してみる
テストデータ
とりあえず説明用にMySQLに適当なテーブルを追加してテストデータを投入。
CREATE TABLE `students` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`blood_type` varchar(10) DEFAULT '',
`favorite_things` text NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime DEFAULT NULL,
`deleted_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Model_Studentを作成
このような感じで、カラム名や論理削除フラグ、主要な4つのオブザーバを設定。
class Model_Student extends Orm\Model_Soft
{
protected static $_primary_key = array('id');
protected static $_soft_delete = array(
'mysql_timestamp' => true,
);
protected static $_properties = array(
'id',
'blood_type' => array(
'data_type' => 'var_char',
'validation' => array(
'match_pattern' => array('@\A(A|B|O|AB)\z@'),
),
),
'name' => array(
'data_type' => 'varchar',
),
'favorite_things' => array(
'data_type' => 'json',
),
'created_at' => array(
'data_type' => 'time_mysql',
),
'updated_at' => array(
'data_type' => 'time_mysql',
),
'deleted_at' => array(
'data_type' => 'time_mysql',
)
);
protected static $_observers = array(
'Orm\Observer_Typing' => array(
'events' => array('before_save', 'after_save', 'after_load')
),
'Orm\Observer_Validation' => array(
'events' => array('before_insert', 'before_save'),
),
'Orm\Observer_UpdatedAt' => array(
'events' => array('before_save'),
'mysql_timestamp' => true,
),
'Orm\Observer_CreatedAt' => array(
'events' => array('before_insert'),
'mysql_timestamp' => true,
),
);
}
TypingでJSONもデコード
モデルをfindして取得するだけで、以下のようにキャストされる。
$student = \Model_Student::find(1);
/*
array (
'blood_type' => 'O',
'name' => 'Ichigo Hoshimiya',
'favorite_things' =>
stdClass::__set_state(array(
'color' => 'pink',
'genre' => 'cute',
'brand' => 'Angely Sugar',
)),
'created_at' =>
Fuel\Core\Date::__set_state(array(
'timestamp' => 1349659654,
'timezone' => 'Asia/Tokyo',
)),
'updated_at' =>
Fuel\Core\Date::__set_state(array(
'timestamp' => 1401273534,
'timezone' => 'Asia/Tokyo',
)),
'deleted_at' => NULL,
'id' => '1',
)
*/
ここにはないけど、int型やfloat型も、もちろんキャストされる。
tinyint(1)のカラムに、data_typeでboolを設定しておくとtrue/falseになったり。とっても便利。
Validationでバリデーション
$student = \Model_Student::find(1);
try
{
$student->blood_type = 'AC';
$student->save();
}
catch (\Orm\ValidationFailed $e)
{
echo $e->getMessage();
// The field blood_type must match the pattern @\A(A|B|O|AB)\z@.
}
blood_typeに「AC」を入れてsaveしようとしても、match_patternで「A, B, O, AB」のどれかに制限されているのでエラーになる。
CreatedAt, UpdatedAt
もちろんupdateしてsaveすれば、updated_atが更新される。
$student = \Model_Student::find(1);
$student->favorite_things->lucky_charm = 'おしゃもじ';
$student->save();
Typingマジ便利
JSONの他にもserializeとかも使えるので、こういうケースだと使い勝手がすごくいい。
細かい部分でスキーマレスなデータを取り扱いたくなるとき、ラララ〜って感じで小さく書ける。