INTER-MediatorというPHPアプリケーションフレームワークがあります。
HTMLからのDBカラム指定でデータが呼び出せたり、
Javascriptの制御でDB操作ができたりなど、なかなか重宝するフレームワークです。

が、必ずしも万能というわけではないのかなというところがあり、
私はSymfonyなどに代表されるMVCフレームワークにINTER-MEdiator(以下、IMと略す)を統合して、
利用しています。

以前はCodeigniterにIMを統合するという記事を書きましたが、今回はYiiに統合をしてみます。


Yii?

PHPのフレームワークといえば?というところで最初にあがってくるようなフレームワークではないですが、柔軟で高速で、かつ、スカッフォールディングなどベースの生成が頭がいいので、気に入って利用しています。他方CakePHPほどの「なんでも感」はないので、PHPerとしての「地力」が試されるフレームワークであると思っています。


早速やってみましょう

これよりさきはMySQLへの接続を前提としてお話をすすめます。

IMのファイルは、yiiのアプリケーションディレクトリ(通常であればprotected)に配置します。

/protected/Inter-Mediator/...

のような感じですね。
特に何かコマンドを打つ必要はありません。


設定ファイルの書き換え

データベースへの接続設定をIMでも使いまわせるようにするために、
初期値ではメイン設定に閉じ込められているデータベース設定を、
別ファイルに移します。

/protected/config/main.phpの

'db'=> array(
			'connectionString' => 'mysql:host=localhost;dbname=dbname',
			'emulatePrepare' => true,
			'username' => 'user',
			'password' => 'pass',
			'charset' => 'utf8',
		), 

の値の部分をカットして、

'db'=> require dirname(__FILE__) . '/database.php'

とします。新規に/protected/config/database.phpを作成して、その中を

<??php
return array(
			'connectionString' => 'mysql:host=localhost;dbname=dbname',
			'emulatePrepare' => true,
			'username' => 'user',
			'password' => 'password',
			'charset' => 'utf8',
		);

とします。
さらに、main.phpのほうには、Yiiのセッション機能を使えるようにするために、加筆をします。
(IMの設定情報をセッションで保持することで柔軟に利用できるようにします)

//DBを外に
		'db'=> require dirname(__FILE__) . '/database.php',
		
		
		//セッションを追加
		'session'=>array(//追加
				'class'=>'CDbHttpSession',//追加
				'sessionTableName'=>'sessions',//追加
				'connectionID'=>'db',//追加
		),

先ほどのDBの設定の部分の下に、セッションを利用可能にしておきます。
そして、下記に説明するヘルパを自動読み込みさせるために、サードパーティーライブラリのフォルダを自動ロードするように設定します。

	'import'=>array(
		'application.models.*',
		'application.components.*',
	),

とします。

	'import'=>array(
		'application.models.*',
		'application.components.*',
		'application.vendor.*',
	),

に書き換えます。
設定ファイルの書き換えは以上。


ヘルパファイルの作成

続いて、IMの設定をラクにするヘルパファイルを作ります。
/protected/vendor/ImHelper.php
を作成し、

<??php
YiiBase::import('application.Inter-Mediator.*');
class ImHelper
{
	//デバッグ
	private static $debug = FALSE;
	
	// ----------------------------------------------------
	
	/**
	 * IMコードのセット
	 */
	public static function setImCode( $im1, $im2 = array(), $im3 = array() )
	{
		//データベース設定をロードしてIMの引数に設定
		$database = require YiiBase::getPathOfAlias('application.config') . '/database.php';
		$im3['db-class'] = 'PDO';
		$im3['dsn'] = $database['connectionString'];
		$im3['user'] = $database['username'];
		$im3['password'] = $database['password'];
		
		
		//一時コードの発行
		$code = sha1( uniqid( '', true ) );
		$data = array(
			'im1' => $im1,
			'im2' => $im2,
			'im3' => $im3,
			'debug' => self::$debug
		);
		Yii::app()->session['im_temporary_code_' . $code] = $data;
		
		return $code;
	}
	
	// ----------------------------------------------------
	
	/**
	 * IMコードの取得
	 * @param type $im 
	 */
	
	public static function getImCode( $code )
	{
		global $callURL;
		$callURL = Yii::app()->createAbsoluteUrl( 'im/get', array('code'=>$code) );
		require_once 'INTER-Mediator.php';
		$params = Yii::app()->session['im_temporary_code_' . $code];
		//echo 'var test = ' . json_encode($params) . ';';
		IM_Entry( $params['im1'], $params['im2'],  $params['im3'], $params['debug'] );
	}
	
	// ----------------------------------------------------
	
	/**
	 * URL作成
	 */
	public static function getUrl( $im1, $im2 = array(), $im3 = array() )
	{
		$code = self::setImCode($im1, $im2, $im3);
		return Yii::app()->createAbsoluteUrl( 'im/get', array('code'=>$code) );
	}
	
	// ----------------------------------------------------
}

と書いて起きます。

YiiBase::import('application.Inter-Mediator.*');

で、IMのフォルダ内をオートロードの対象にしておきます。


IM自体の改造

IM自体の改造が必要です。

まず、INTER-Mediator.phpを改造します。

if (!class_exists('Crypt_RSA')) {
    require_once($currentDir . 'phpseclib' . DIRECTORY_SEPARATOR . 'Crypt' . DIRECTORY_SEPARATOR . 'RSA.php');
}
if (!class_exists('Crypt_Hash')) {
    require_once($currentDir . 'phpseclib' . DIRECTORY_SEPARATOR . 'Crypt' . DIRECTORY_SEPARATOR . 'Hash.php');
}
if (!class_exists('Math_BigInteger')) {
    require_once($currentDir . 'phpseclib' . DIRECTORY_SEPARATOR . 'Math' . DIRECTORY_SEPARATOR . 'BigInteger.php');
}

//Yiiのオートローダーを一旦解除
spl_autoload_unregister(array('YiiBase', 'autoload'));


if (!class_exists('Crypt_RSA')) {
    require_once($currentDir . 'phpseclib' . DIRECTORY_SEPARATOR . 'Crypt' . DIRECTORY_SEPARATOR . 'RSA.php');
}
if (!class_exists('Crypt_Hash')) {
    require_once($currentDir . 'phpseclib' . DIRECTORY_SEPARATOR . 'Crypt' . DIRECTORY_SEPARATOR . 'Hash.php');
}
if (!class_exists('Math_BigInteger')) {
    require_once($currentDir . 'phpseclib' . DIRECTORY_SEPARATOR . 'Math' . DIRECTORY_SEPARATOR . 'BigInteger.php');
}

//Yiiの再登録
spl_autoload_register(array('YiiBase', 'autoload'));

とします。これは、先のImHerlper.phpでIMのディレクトリ内をオートロードの対象にしたわけですが、PHP拡張である「Crypt_RSA」などのクラスの存在拡張をチェックすると、自動的にファイルを探しに知ってしまうのを回避しています。

続いて、GenerateJSCode.phpを改造します。

public function generateInitialJSCode($datasource, $options, $dbspecification, $debug)
{
	$q = '"';

public function generateInitialJSCode($datasource, $options, $dbspecification, $debug)
{
	global $callURL;
	$q = '"';

としておきます。IMのコードを見ると、$callURLがセットされていれば、このURLを優先して利用する仕組みになっているようですので、globalにして、先のImHelper.php内でコールするURLを指定できるように改造しています。

もしかすると、

if (isset($callURL)) {

if ( $callURL != '' ){

にしておいたほうが賢明かもしれません。


IM処理用コントローラーの設置

次にIMの処理を担うコントローラーファイルを設置します。
/protected/controllers/ImController.php
を作成し

<??php
class ImController extends CController
{
	
	// ----------------------------------------------------
	
	/**
	 * アクセスルール
	 */
	public function accessRules()
	{
		return array(
				'actions'=>array(  ),
				'users'=>array('@'),
			),
		);
	}
	
	// ----------------------------------------------------
	
	/**
	 * IM用コード出力
	 */
	public function actionGet( $code )
	{
		echo ImHelper::getImCode($code);
	}
	
	// ----------------------------------------------------
}

と保存しておきます。アクセス状況によってはアクセスルールを適切に設定したほうがよいでしょう。


準備完了

準備ができました。
あとは任意のコントローラーアクション内で、

$ds = array(
			array(
				'name' => 'categories',
				'records' => 20,
				'paging' => true,
			),
		);
		$def = array();
		$ds2 = array();
		
		$url = ImHelper::getUrl(
				$ds,
				$def,
				$ds2
		);

とすれば、$urlにIMの設定を呼び出すための一時URLが発行されるため、
viewの中で表示するなり、clientScriptクラスに登録するなりすればOK

ImHelper::getUrl()の引数は
IM_Entry()の引数に引き当てられます。
DBへの接続設定はImHelperで自動的に割り当てられるので、不要です。


これで、開発高速化!

現場からは以上です。