伊藤清徳の垂直落下式ムーンサルトプレス

PerlとかPHPとかMySQLとか...がんばっても8割だ。

Category: CodeIgniter

Inter-MediatorをCodeigniterから使ってみる

INTER-MediatorというPHPアプリケーションフレームワークがあります。
かなり前から存在は知っていたものの、今回はじめて使ってみました。
普通に使うには、私個人としてメリットがなかったので使って来なかったのですが、
他のフレームワークと一緒に使うと便利なんじゃね?
ってことで、Codeigniterで使ってみることに。
 
え?なんでかって?seezoo cmsのコミッターだからさ!
 


そもそも、INTER-Mediatorってなによ?

 
そもそも、INTER-Mediatorってなによ?ってことなんですが、
従来のPHPやPHPフレームワークでは、
SQLやORMをつかってデータベースのレコードを呼んできて、
 

<table>
<?php foreach( $rows as $row ): ?>
<tr> <td><?php $row['field']; ?></td> </tr> <?php endforeach; ?>
</table>

 
のようなコードを書かなくてはなりませんでした。
(PHPTALをつかうともっとスッキリHTMLのポリシーに近くなりますが)
 
Inter-Mediatorの場合、PHPファイルに規定の書き方で、
呼び出すテーブル・1ページあたりのレコード数などを書き入れ、
そのファイルをjavascriptファイルとして、HTMLから呼び出すだけで、
 

<table>
<tr>
<td class="IM[テーブル名@フィールド名"></td>
</tr>
</table>

 
こんなHTMLを書けば、Javascript制御でclassで指定された
テーブル名/フィールド名のデータを表示してくれます。
また、複数レコードを呼ぶ設定にしている場合は、
テーブルの行数もレコード数分追加してくれます。


定義ファイルの中身

INTER-Mediatorの定義ファイルは
 

<?php
require_once ('INTER-Mediator/INTER-Mediator.php');
IM_Entry(
	//呼び出すレコードの定義
	array(
		array(
			'records' => 1,
			'name' => 'person',
			'key' => 'id',
		),
	),
	//オプション設定
	null,
	//DBへの接続設定
	array('db-class' => 'PDO'),
	//デバッグレベルの設定
	false
);

こんな感じです。詳しくは公式サイトのドキュメントをご覧下さい。
IM_Entry();が、HTMLのクラスセレクタを解析して、
DBのレコード/フィールドを差し込むJavascriptコードを出力してくれる
そんな仕組みになっているようです。
 


Codeignireから使うには?

 
上記の様に、INTER-Mediatorの定義ファイルは実に単純なしくみです。
この定義ファイルを出力するコントローラーをつくれば、
ページの出力がかなり簡単になるのでは?
と思ったわけです。
 
気をつけるポイントとして、
INTER-Mediatorでは、PDOでMySQLなどへの接続を行なっているので、
CodeigniterのDBドライバインスタンスをINTER-Mediatorで使うことはできません。
ただ、CodeigniterでつかっているDBの設定はそのまま引き継ぎたい。
そんなわけで、以下のようなコントローラーを作ってみました。
 

<?php
class im_require extends CI_Controller
{
	public function index()
	{
		//IMをrequire
		require FCPATH.'INTER-Mediator/INTER-Mediator.php';
		
		//データベース設定を呼び出す
		require APPPATH . 'config/database.php';
		$dsn = $db[$active_group];
		
		//第三引数
		$dbset = array();
		$dbset['db-class'] = 'PDO';
		$dbset['dsn'] = 'mysql:dbname=' . $dsn['database'] . ';host=' . $dsn['hostname'];
		$dbset['user'] = $dsn['username'];
		$dbset['password'] = $dsn['password'];
		
		
		IM_Entry(
			array(
					array(
						'records' => 1,
						'paging' => true,
						'name' => 'person'
					)
			),
			null,
			$dbset,
			0
		);
	}
}

 
DB設定ファイルを呼び出して、今アクティブなDB設定を
INTER-MediatorのPDO設定に入れているという簡単なしくみです。
 
あとは、どのテーブルを呼び出すかなどを、
GET/POSTのパラメータなどから呼び出せるようにしたり、
YAMLなどで定義できるようにしておけば、
1つのコントローラーで、複数のINTER-Mediatorの定義を作ることができるようになります。
 


INTER-Mediatorの改造

 
さて、定義ファイルを作成するコントローラーができたわけですが、
これだけでは、ちょっとまずいところがありますので、
INTER-Mediator自体の改造が少し必要です。
GenerateJSCode.phpを改造します。
68行目付近に
 

$pathToMySelf = (isset($scriptPathPrefix) ? $scriptPathPrefix : '')
. $_SERVER['SCRIPT_NAME'] . (isset($scriptPathSufix) ? $scriptPathSufix : '');

 
があります。
この状態ですと、定義ファイルの物理的なパスをJavascript中でXHRのURLとして利用してしまうので、
URIルーティングがあるCodeigniterでは、index.phpが呼ばれてしまい、
正しく動作してくれません。
 

$pathToMySelf = (isset($scriptPathPrefix) ? $scriptPathPrefix : '')

			. $_SERVER['SCRIPT_NAME'] . (isset($scriptPathSufix) ? $scriptPathSufix : '');

if(function_exists('get_instance'))
{
	$ci = get_instance();
	$pathToMySelf = (isset($scriptPathPrefix) ? $scriptPathPrefix : '')
		. '/index.php/' . $ci->uri->uri_string()
		. (isset($scriptPathSufix) ? $scriptPathSufix : '');
}

このように書き換えています。
Codeigniterからの呼び出しでない場合も踏まえて、
コントローラーインスタンスが呼べるかどうかで、振り分けをしています。
 
上記のコードでは、GETパラメーターへの考慮がされていないので、
実務レベルで使うには、そのあたりも考慮した改造が更に必要でしょう。
 


viewファイルの記述は?

viewファイルのへの記述は特に気にするような点はなく、
ここまでで作った定義作成コントローラーをjavascriptとして呼び出して、
bodyにonload="INTERMediator.construct(true);"をつければOKです。
 

<script type="text/javascript" src="http://localhost/index.php/im_require"></script>

  

<body onload="INTERMediator.construct(true);">

 
こんな感じですね。
 


seezoo cmsに入れる?

 
seezoo cmsはCodeigniterベースにできているので、
ここまでで書いたコントローラーを突っ込めばうごいてくれますし、
seezoo cmsには管理者/会員承認機能がそろっているので、
このへんもからめると面白いものができそうです。
 
また、Codeigniter自身のModel(DB)機能を使えば、
Inter-Mediartorではカバーできない複雑な処理も行うこともできますから、
「とても便利系」なライブラリやフレームワークにありがちな、
「あーここまではできないかーorz」という手詰まり感も回避することができます。
 


将来展望

実は、私今年のはじめからseezoo cmsベースで似たようなものを作ろうとしていたのですが、
仕様の練り直しなどで進んでいなかったところがあり、
一気に解決した感じです。
 
CodeigniterにはDB構造を操作するメソッドも揃っているので、
テーブル作成やインデックスの付与などを管理画面からできるようにすれば、
オンライン版FileMakerのようなものができるのでは!?
と思っています。
 
もう少しいじってみよう!
 


P.S.

INTER-Mediatorのコードを覗くと、
プロパティが

var $var = '';

のような、ちょっと古い書き方がされているところがあるようです。
この辺りは改善してもらえるとうれしいなー。

CodeIgniterのいいとこ色々

先日CodeIgniterが2.0にバージョンアップしたり、
はてぶ界隈で
http://h2o-space.com/blog_ver2/diary/195
こちらの記事が話題となっているようですので、
CodeIgniterを使い始めて3ヶ月の私がちょっと反応してみます。
 


 私がCIを利用しはじめた理由は、

  • コーディング規約がゆるゆる
  • インストールにコマンドがいらない
  • 拡張がらくちん
  • 比較的広いPHPのバージョンに対応
  • モデルの扱いがゆるい

というところでした。
 
モデルのあたりは、前述の話題サイトにも書かれていますね。


実際に使い始めて特にいいなと思ったのが、
ユーザーガイドのページの使いやすさ・読みやすさです。
PHPさえちゃんとできれば、
ユーザーガイドのページを見ながら開発をラクに進められます。
書籍などはいらないと言ってよいです。
学習コストが異常なほど低いです。
 


そして、コントローラーの頭の良さに驚きを隠せないです。
一度ルーティングが成功してしまえば、
どこからでも、コントローラーインスタンスを呼び出すことができるので、
値をシステム内で縦断させて、参照/変更がかなり簡単にできます。
 
また、ローダーと呼ばれる、
ライブラリや設定ビューを呼び出す機能も、頭が良いです。
 
私はCodeIgniterを使う前、自作のフレームワークを利用していたのですが、
こちらのFWに使っていたライブラリ類の移植が、
コントローラーとローダーの頭の良さで、
非常に簡単に移植できました。
 
またCI自身のコアの拡張も分かりやすく、簡単にできます。
 


で、何が一番驚きって、とにかく高速。
ぶっちゃけ、普通のサイト作ったり、
モデルパターンの少ないWEBサービスだったら、
DBのクエリの速度以外は気にしないでいいレベルです。
 


常々私はEC専業のPGだと嘘ぶいていますが、
ECはページの魅せ方を色々変える必要があったり、
決済などの問題で、色んな拡張の必要性に迫られるケースが多々あるのですが、
そのへんでCIはパワーを発揮してくれます。
 
たとえばCakePHPは、良く言えば機能満載で、
痒いところに手が届いてサイト作りをラクにしてくれますが、
悪く言えばおせっかい機能満載で、
サイトの性質や、サイト作りの方針によっては足かせになります。
 
私のECサイト構築の立場では後者の立場だったのでCIはそのへんを解決してくれました。
 


 
とは言え、CIいいところばかりでは有りません。
 
前述の通りモデルやDB周りの実装がゆるゆるで、
ぶっちゃけモデルなんかナシでどうにかできちゃいますが、
ActiveRecordの機能は有しているものの、
Cakeよりは、ずっと「DBを操作している感」のある使い方になると思います。
また、DB操作が多いサイト作りの場合、
モデルファイルが大量になるかもしれません。
 
そして、CIを使ううえでPHPerが一番戸惑うのが、セッションでしょうね。
CIのセッションは、PHPのセッションは使わず独自実装です。
cookieに全てのデータを突っ込むcookieセッションか、
DBへデータを保存するDBセッションの2パターンが用意されていますが、
やっぱりファイルを使ったセッションもほしいところ。
ファイルセッションを利用する場合は、
自作でライブラリを作るか、別に配布されているライブラリを利用擦る必要があります。
(ただ、前述のとおりライブラリづくりは比較的簡単です。)
 
デフォルトで$_GETを破棄するという豪快な仕様になっているので、
そのへんを扱うのを最初戸惑うかもしれません。
(設定さえ覚えれば、すぐに慣れますが)
私の場合は、$_REQUESTを取り回す自作ライブラリで対応しています。
@kenji_sさんから

デフォルトで$_GETを破棄するのは CodeIgniter 1.x の仕様で 2.0.0 (Reactor) からはデフォルトで$_GETが使えるように変更されています

とご指摘いただきました。ありがとうございます。ちょっと不勉強でした。
 
あと、これは良いと言う人と悪いという人がいますが、
CIのviewは基本的に生PHPです。
私の場合は、生PHPは「うーん」な人なので、Smarty拡張しました。
(ただし、Smartyも「うーん」ですwwPHPTALにしようかなとか考えています)
 


というわけで、とにかくCIは頭がイイんだぜ!って話になっちゃいましたが、
よくないところを吸収するには、それなりのPHPの知識も必要というわけです。
以前書いたPHPのフレームワーク選択の記事でも書きましたが、
CIは、良くも悪くもちゃんとPHPが使えているということが前提条件であるFWでしょう。 

CodeIgniter2.0でSmarty

CodeIgniterが2011年1月28日付で2.0にバージョンアップされました。

ちょうど今日スタートの案件で、CodeIgniterを使おうと思って、
ダウンロードしにいったら2.0になっててびっくり。
 
社内で Perl→Template::Toolkit PHP→Smarty という刷り込みを行ってきたので、
オープンソースのFWを採用してもSmartyを使いたい。
ということで、こちらのような方策をとったのですが、
果たして、2.0ではどうでしょう?
 
とりあえず、前回の記事のように処理したら、
コンパイル済みテンプレートファイルの格納ディレクトリがないと警告。
 
CIの1.x系では、システムディレクトリの中にアプリケーションディレクトリがあるという構造でしたが、2.xからこれらが分離して、すこしディレクトリ構造が変わったのが原因でした。
 
前回の記事からのリンク先の説明にある、
config/smarty_parser.phpの

$config['compile_dir'] = BASEPATH.'cache/';

$config['compile_dir'] = APPPATH.'cache/';

にすれば動きました。
 
一安心。
 
CodeIgniteゆるゆるで素晴らしいよ!

CodeIgniterでSQLiteに接続。

今から作るアプリケーションでSQLiteを使わなくてはならなくなりました。
 
というわけで、CodeIgniterでSQLiteを使うにはどうしたらよいか。
 
system/application/config/database.phpの接続設定を

$db['default']['hostname'] = "";
$db['default']['username'] = "";
$db['default']['password'] = "";
$db['default']['database'] = "データベースファイル";
$db['default']['dbdriver'] = "sqlite";
$db['default']['dbprefix'] = "";
$db['default']['pconnect'] = TRUE;
$db['default']['db_debug'] = TRUE;
$db['default']['cache_on'] = FALSE;
$db['default']['cachedir'] = "";
$db['default']['char_set'] = "utf8";
$db['default']['dbcollat'] = "utf8_general_ci";

ドライバに「sqlite」にして、
dbnameはデータベースファイルへのパスを指定します。
データベースファイルへのパスは相対パスも場合、
index.phpからの相対パスです。
APPPATHとかで、絶対パスを指定したほうがいいかもです。
 


この方法で使えるSQLiteは「SQLite2」ですのでご注意ください。
SQLite3を使いたい場合は、
http://codeigniter.com/wiki/PDO_SQLite3/
こちらを参考に。
配布アプリの場合は権限とか設定とかの問題があるので、
あまりやらないほうがいいかな。。。

CodeIgniterに同梱のSQLite用ドライバは、
バグがあるようです。
http://zidane27.blog119.fc2.com/blog-entry-11.html
このへんを参考に。これ以外情報がないので、バグにぶつかったら自分で直すしかなさそう…。

まぁいろいろアレだけど、SELECTとかINSERTとか基本的なとこは問題なさそう。

CodeIgniterをWEBとCLIハイブリッドにする

案件の事情により、CodeIgniterをCLIからもWEBからも利用しなければならないという問題にぶち当たる。

CodeIgniterでは、
system/libraries/Router.php
で実行するコントローラとメソッドを指定しているので、これを拡張してやれば、行ける気がする。

今回のコマンドは、

index.php "ディレクトリ" "クラス" "実行するメソッド"

と指定することにした。

まず、Router.phpの拡張を作る。
system/application/libraries/MY_Router.php
を作成し、そのなかに以下のようなクラスを作成する。

<?php
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class EB_Router extends CI_Router{
 
//ここに後述のメソッドを書く。
 
}
?>

「//ここに後述のメソッドを書く。」の部分に後述のメソッドを書きます。


続いて、コマンドライン引数からコントローラーなどを指定するメソッドを拡張します。
system/libraries/Router.php
の「_validate_request」メソッドを、
system/application/libraries/MY_Router.php
へコピーします。

そして、このメソッドの冒頭へ、
CLIでの起動だった場合に、コマンドラインからコントローラーを指定するコードを書きます。
 

function _validate_request($segments){

/**********************************************************/
if( PHP_SAPI == 'cli' )
{
    
    //ここでコントローラーなどを指定。
    $this->set_directory($_SERVER['argv'][1]);
    $this->set_class($_SERVER['argv'][2]);
    $this->set_method($_SERVER['argv'][3]);
    
    //カレントディレクトリを変更しておく
    chdir( FCPATH );
    
    return array();
}
/**********************************************************/

// Does the requested controller exist in the root folder?
if (file_exists(APPPATH.'controllers/'.$segments[0].EXT))
{
    return $segments;
}

// Is the controller in a sub-folder?
if(is_dir(APPPATH.'controllers/'.$segments[0]))
{ 
    
    // Set the directory and remove it from the segment array
    $this->set_directory($segments[0]);
    $segments = array_slice($segments, 1);
    
    if (count($segments) > 0)
    {
        // Does the requested controller exist in the sub-folder?
        if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].EXT))
        {
            show_404($this->fetch_directory().$segments[0]);
        }
    }
    else
    {
        $this->set_class($this->default_controller);
        $this->set_method('index');
        
        // Does the default controller exist in the sub-folder?
        if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT))
        {
            $this->directory = '';
            return array();
        }
    }
    return $segments;
}

// Can't find the requested controller...
show_404($segments[0]);
}

/**********************************************************/
で囲まれた部分が追加した部分です。

これで、コマンドからコントローラーやメソッドを指定できます。

定義済み定数の「PHP_SAPI」に「cli」が指定されたとき以外は、
通常のルーティングが行われるので、
CLIとWEBでハイブリッドな使い方ができそうです。


注意点としては、
上記のコードは、コマンドから渡された、
ディレクトリやらコントローラーやらメソッドが、
確実に存在するという前提で書いています。
実際に使う場合は、このへんのエラートラップもしておいたほうがいいでしょう。

拡張のヒントとしては、上記のコードでは、第4引数以降はと特になにもしていないですが、
ここも拾って、実行メソッドの引数として渡せると楽しいかもです。

何かの参考になればー。

CodeIgniterにSmartyを導入

前の記事でCodeIgniterを使うことを決めたと書きましたが、
ダメな所ももちろんたくさんあります。
 
http://oddwit.com/blog/2007/coming-to-hate-code-igniter 
 
こんな記事もありますし。
 
私は個人的にテンプレートが生PHPなのがうーん。だったのが、最初躊躇した理由です。
PHP自体がテンプレートエンジンのオーバーテクノロジー(だと、PHP開発陣ですら公言している)なので仕方ないですが。
とはいえ、phpタグをHTMLコーディングする人に書いてもらうのはどうしてもいやだ。
 
という理由で、EthnaかSoyCMSのフレームワークかで悩んだのですが、
 

@kiyotchi CodeIgniterの事であれば僭越ながら色々お話できるかもです。SeezooもCodeIgniterで作ってるので、プラグイン作り放題ですよーwあと、Smartyプラグインは http://bit.ly/eWYqAC とかを参考にドゾー。less than a minute ago via web


 
という情報をいただく。
 
ただ、Cakeとかも一応Smartyつかえるけど、かなりCakeの良さをそぎ落として使うことになるのは、よく知られたはなし。CodeIgniterではどうかな?と思って、寝ずにやってみた。
 
うん。かなりいい感じ。無理なく使えるって感じです。各ライブラリの独立性が高いのと、コントローラーが柔軟なおかげですね。
 


 
上記のTipsだと、CIのライブラリフォルダにsmartyを突っ込みましょうとかいてありますが、
CI → Apache/BSD
Smarty→LGPL
と、真っ向からぶつかる訳ではないですが、
やっぱりライセンス的に切り分けておきたいので、
SmartyはSmartyのみで、PEARディレクトリか、include_pathの通っているパスへインストールして使うことに。
 
その場合、CodeIgniter/system/libraries/Smarty_parser.php の
 

require "smarty/Smarty.class.php";

は、インストールの仕方で、パス指定が変わるので注意。

今後のPHP開発にCodeIgniterを採用。

来春からひとり立ちをして生きて行くことになったわけですが、
それに伴い、高速開発というのも視野にいれて行動しなくてはいけなくなりました。
 
かなりECに特化したフレームワーク(Perl|PHP)を自作して使っているのですが、
自作フレームワークだとそれ自体をUPGRADEする時間も必要になって大変だ。
 
というわけで、PHPのものだけ、オープンのものをさがすことに。
有名どころから
 


 
・CakePHP http://cakephp.jp/
RoRをお手本にしたフレームワーク。
PEARなどの既存ライブラリに依存せず、かなり広汎なサイト構築に対応。
「なんでも屋」な印象。
既存ライブラリに依存してないのはいいけど、
ちょっとカッチリしすぎていて、自分の設計思想には合わず。
 


 
・Symfony http://www.symfony-project.org/
こちらもきれいなMVCパターン。
かなり堅牢なアプリケーションが開発できる。
規模という意味ではおそらく、一番広く対応できる。
こちらもかっちりしすぎていて、自分の設計思想には合わず。
 


 
・Ethna http://ethna.jp/
GREEが自社開発用のためにつくったフレームワーク。
MVCながら、緩い制約。コマンドラインがちょっと面倒。
全体的に好みなんだが、DB接続のデフォルトがPEAR_DBなので、ちょっと困った。
日本製っていうのが大きいし、稼動実績は目に見えてわかる。
PEAR_MDB2採用なら飛びつく。そこだけが惜しい。
 


 
・ZendFramework http://framework.zend.com/
PHPの言語エンジンの開発元謹製のフレームワーク。
かなり色んなライブラリが揃ってるのが魅力。言わば第二のPEARみたいな。
各機能はそこだけ切りだして使えるのもPHPっぽくて良い。
が、、、PHP5.2.4以上なのが困った。まだ5.1系沢山抱えているので。。。
 


 
・ちいたんhttp://php.cheetan.net/
cakeに影響をうけながら、フレームワークとしての機能はMVCの分離にとどまっているのが、
いいなぁと思って、1年くらい前からチェックはしていた。
でも、まぁよくも悪くも、何もなさすぎて、、、
 


 
・SoyCMSのフレームワークhttp://www.soycms.net/
フレームワークとして、独立しているわけではないのですが、
SOY CMSはベースに独自フレームワークを使っています。
CMSなのでテンプレートエンジンが素晴らしいとこがいいです。
が、ドキュメントが少なくて、断念。
 


 
・CodeIgniter http://codeigniter.jp/
周りに使っている人が少なくて、いまいちマイナーな感じをうけていたので、
後回しになっていました。
コマンドライン操作がいらない。コーディング規約がゆるい。
MVC分離にはなっているが、ぶっちゃけモデルいらない。
セッションを全てcookieに保存するところがうーん。
これまでの資産が活かしやすい。
 
  


 
ほかに、MapleやMojaviなどもありますね。
 
PHPは言語じゃなくて、ツールやフレームワークだよと思っているので、
その上にガチガチのフレームワークを乗っけるのは好きではない。
これまでの資産が活かしたい。
コマンドラインを叩かず、ぶち込めば基本的に動くものがほしい。
 
という個人的なわがままを一番満たしてくれたのが、CodeIgniterなので、
これを採用することにしました。
 


 
早速、これまでの資産をCodeIgniterに移植する作業をしていますが、
ちょっとの書き換えで済むので、すごくラクです。
良くも悪くもPHPを知ってないと、使いこなせないのかなという印象もありますが。
とりあえず、なんか一個作ります。
 


 
自作フレームワークも並行してさらにEC専用になるように磨いていきます!
 
ちなみに、自作フレームワークは、
・説明書が書けないレベルになっとる。
・あまりにもEC専用で、私の仕事の手の内を見せることになる。
・フレームワークの名前に元カノの名前が付いとる。
ということで、公開はしません。絶対にww。