きまブログ

2022-12から再開しました。

自動コード生成のための補習 - Model編

手書きからコード自動生成へ - Model編

Modelは、コード自動生成しようとすると、データベースとの連携を考慮したファイルを生成します。

$ oil generate model testtable2 name:text
Creating model: /home/kima/test_app/fuel/app/classes/model/testtable2.php
Creating migration: /home/kima/test_app/fuel/app/migrations/001_create_testtable2s.php

2つのファイルが生成されました。


testtable2.php は、モデルです。内容は、あとで解析しますw


001_create_testtable2.php は、
マイグレーションという、データベースを操作するためのファイルです。
ここでは、ファイルができるだけで、データベースの操作は、別途手動で実施します。
このファイルの中身は、見なかったことにしますw

FuelPHPの準備 - パッケージの有効化&マイグレーション

/fuel/core/config/config.php
packages配列にormを追加します。(たぶん)コメントを外すだけです。


上で生成したマイグレーションを実行します。

$ oil refine migrate

これで、新しいテーブル testtable2ができているはずです。
phpMyAdminでご確認を。。

実行結果

いままでテストで作ってきたコントローラーのメソッドに、
こんな感じでデータベースのテーブル testtable2 の全レコードを読み込むようにして、
結果の配列をvar_dump()で全部出力するようにしてみると。。

  public function action_ormtest()
  {
    $query = Model_Testtable2::find('all');
    var_dump($query);
  }

前と同じ様に、できました。

自動生成されたModelファイルの解析

$_propertyには、テーブルカラムが代入されてるんだろうな。。
$_table_nameには、テーブル名が代入されてるんだろうな。。
とすんなり、腑に落ちますが。。

なんや、$_observersって。。

/fuel/app/classes/model$ cat testtable2.php 
<?php

class Model_Testtable2 extends \Orm\Model
{
	protected static $_properties = array(
		'id',
		'name',
		'created_at',
		'updated_at',
	);

	protected static $_observers = array(
		'Orm\Observer_CreatedAt' => array(
			'events' => array('before_insert'),
			'mysql_timestamp' => false,
		),
		'Orm\Observer_UpdatedAt' => array(
			'events' => array('before_update'),
			'mysql_timestamp' => false,
		),
	);

	protected static $_table_name = 'testtable2s';

}

そう、これこそGoF - 23のデザインパターンのひとつ「オブザーバー」パターン。
きました。GoFですw たぶん。。ちょっと違うかな。。


テストのため、先ほどと同じように、
適当なコントローラーに、こんな感じでメソッドを書いておき、実行すると、
データベースに1件レコードが追加されます。

  public function action_dbinsert()
  {
    $data = array('name'=>'db insert test');
    $testtable2 = new Model_Testtable2($data);
    $testtable2->save();
  }

この処理の流れは。。こうなっているみたい。Orm/Observer_CreateAtの処理です。。

1.ORM/Modelのsave()メソッドで、配列$dataに代入した値を、
  データベースに書き込む処理(挿入処理)の前に。。
  save()の中で、insert()メソッドが呼ばれ、
  その中で、observe(‘before_insert’)メソッドが呼ばれます。


2.observe()で、ナゾの$_observers配列をforeachし、
  イベント ‘before_insert’にマッチした要素で指定されたクラス
  (CreatedAtクラス)を動作させる。 (__construct()が動く。)
  (イベント before_insert が、オブザーバーCreateAtへ伝わった!)


3.主目的であるデータベースへの挿入処理(Insert)をする。


4.observe(‘after_insert’)が呼ばれ、同じ感じで、
  マッチしたオブザーバーが動作する。

結果として、レコードをinsertするbeforeに、CreatedAtを動かすこと(通知)ができます。


こんな感じ。


これを「オブザーバー (Observer:観測者?) パターン」といい、いわゆるGoFの23あるデザインパターンのひとつです。たぶん。。


ミソなのは、

通知して欲しい時(Event)と、その時に動かしてほしいクラスを配列$_observersへ登録しておいて、
何かイベントが発生したら、問答無用で「オブザーバー!!イベントだー」といえば、observe()メソッドで、$_observersをぐるぐるforeachして、
そのイベントを受信したいクラスを探して、動かしてくれる。

というところでしょう。


だから、イベントの受け手(オブザーバー)がないと、何も起きないし、たくさんいても大丈夫!


イベントを通知する側は、どのクラスを呼べばいいか知らなくていいし、
通知を受信する側は、どのクラスから呼ばれるか知らなくていい。


いわゆる疎結合になる。ことなのでしょう。。たぶん。。

オブジェクト指向における再利用のためのデザインパターン

オブジェクト指向における再利用のためのデザインパターン