Hina-Mode

とある呑んだくれエンジニアの気が向いた時に書く戯言

【FuelPHP】ORMパッケージのObserver機能を使ってユーザ作成時にIPを自動付与する

FuelPHP Advent Calendar 2015 の12日目を担当します @hinashiki です。よろしくお願いします。
普段は少人数で自社サイト運営をしながら呑んだくれたりマンガ読んだりアニメ観たりしております。

今回は掲題にあるとおり、DBへのレコード挿入時にObserver使えば便利だよ、という事を簡単に紹介します。

そもそもObserverってなんぞや?

ざっくりと説明しますと、DBへのINSERT, UPDATE時に何かしらのフックをいれることが出来る機能のことです


はじめに - Obervers - Orm パッケージ - FuelPHP ドキュメント

イベントベースのシステムは、特定のイベントに動作を追加できるようにします。 イベントが観測されると ORM は自動的にそれらを行うためには何があるのかどうかを確認するために追加されたすべてのオブザーバを呼び出します

と書いてありますが、要するに

  • INSERTの前後
  • UPDATEの前後

に特定動作を追加できるよーってことです。

では具体的にどんな感じで使うのか

上記の機能を使うためにはORMパッケージを入れる必要があるので、configファイルから設定を追加しましょう。

'always_load' => array(
    'packages' => array(
        'orm',
    ),
),


さて、では実際にコード記述に入ります。
試しに「usersテーブルにINSERTをしたら作成日時が自動的に保存される」という部分を作ってみます。

Modelの用意

fuel/app/classes/model/user.php を用意します。

class Model_User extends \Orm\Model
{
	protected static $_observers = array(
		'Orm\\Observer_CreatedAt' => array( // 実行内容が記述されているクラス名
			'events' => array('before_insert'), // INSERTの前に実行する
			'mysql_timestamp' => true, // php側の時刻ではなくmysql側の時刻を参照する
			'property' => 'created_at', // 保存するテーブルのカラム名
		),
	);

	protected static $_table_name = 'users'; // 保存するテーブル名
}

Orm\ModelクラスをextendsしたModelクラスを用意し、usersテーブルにはcreated_atカラムを用意します。

実行

あとはこのModelを使ってINSERTをすればOKです。

# Modelを使ってINSERT
$new = new \Model_User();
$new->property = 'something';
$new->save();

# DBクラスを使ってINSERTするとcreated_atには何も入りません。注意。
$query = DB::insert('users');

もう一歩進んで、本題

本題に戻りまして、IPアドレスの自動挿入についてご説明しましょう。
先ほどの「timestampを突っ込む」という本処理を実行していたのはOrmパッケージが持つObserver_CreateAtクラスでした。
では今度は「ip_addressを取得する」という本処理を自分で書いて持ってみましょう。

Observer_IpAddressの用意

fuel/app/classes/observer/ipaddress.php を用意します。

class Observer_IpAddress extends Orm\Observer
{
	public static $property = 'ip_address'; // デフォルトのカラム名
	protected $_property; // カラム名保持用プロパティ

	/**
	 * プロパティ名の変更があったらここで出来るよ的な処理
	 */
	public function __construct($class)
	{
		$props = $class::observers(get_class($this));
		$this->_property = isset($props['property']) ? $props['property'] : static::$property; 
	}


	/**
	 * 各イベント名機能。ここではINSERT前に取得したいのでbefore_insert()としてます
	 */
	public function before_insert(Orm\Model $Model)
	{
		if(is_null($Model->{$this->_property}))
		{
			$Model->set($this->_property, \Input::real_ip()); // IPアドレス入れ込む本処理
		}
	}
}
Modelへの記述追加

Observerを作成したら、先ほどのModel_Userの$_observersにObserver_IpAddressを追加してあげます。

	protected static $_observers = array(
		'Orm\\Observer_CreatedAt' => array(
			'events' => array('before_insert'),
			'mysql_timestamp' => true,
			'property' => 'created_at',
		),
		// 追加
		'Observer_IpAddress' => array( // 実行内容が記述されているクラス名
			'events' => array('before_insert'), // INSERTの前に実行する
			'property' => 'ip_address', // 保存するテーブルのカラム名
		),
	);

これで準備は完了です。
あとはModel_Userを通じてsaveを実行してあげれば、IPアドレスがusers.ip_addressに追加されます。

まとめ

いかがでしたでしょうか。Observerは他にも

  • 直前にValidationを実行する
  • 投稿された座標情報を自動取得して保存しておく
  • 論理削除用にとりあえずdeleted = 0を仕込んでおく

など、色々な使い方が出来ます。覚えておくと便利な機能だと思いますので是非活用してみてください。




この投稿は FuelPHP Advent Calendar 2015 の 12日目の記事です。