PHP 開発者にとって、この PHP というプログラミング言語に潜む根本的な問題を見つけるのに、それほど時間はかかりません。その問題とは、大規模なプロジェクトとなると扱いにくくなることです。
これは必ずしも PHP の落ち度というわけではありません。実際、機能豊富なこの言語には、プログラマーそれぞれの作業を区別できるだけの PHP 特有の柔軟な表現形式があります。この点に関して PHP は Perl に似ていて、それがこの言語の人気の理由になっています (それと同時に、嫌われる理由にもなっています)。レガシー PHP プロジェクトを検討したことのある経験豊富な PHP 開発者であれば、誰でも簡単にプロジェクトの各フェーズでのさまざまな開発者の作業を見抜くことができます。これはまるで、考古学者が地下深くの墓所を掘り起こし、それぞれの時代の文化の歩みを証明するようなものです。
PHP プロジェクトが数千行を超えると、どのスタイルが関係しているか、あるいはどの手法が使用されているかに関わらず、瞬く間に扱いにくくなってくる傾向があります。その理由は主に、構造が統一されていないためです。なかにはクラスを作成して自分たちの作業を整理しているプログラマーもいますが、クラスの作成の仕方について同じ考えを持つプログラマーは二人としていません。また、関数を集めた膨大なインクルード・ファイルを作成するプログラマーもいれば、依然として PEAR のような巨大な一体構造のライブラリーを使用するプログラマーもいます。
ほんの数年前まで、PHP には優れた機能的な MVC (Model-View-Controller) フレームワークがありませんでした。MVC フレームワークでは、プログラマーが自分たちのコードを以下の明確な 3 つの機能領域に分類した構成にします。
- モデル (Model) には、データベースやその他のデータ構造に関連するあらゆるコードが含まれます。例えば pages というテーブルがあるとすると、このテーブルに対応するモデルがあり、そのモデルに、テーブル内のレコードを選択、作製、更新、削除するなどの操作を行う関数が含まれることになります。
- ビュー (View) には、表示および UI 要素すべてが含まれます。例えば、JavaScript コード、CSS (Cascading Style Sheets)、HTML、さらには PHP も、ビューに含まれる要素に該当します。
- コントローラー (Controller) はすべてを 1 つに組み立てます。コントローラーに含まれる関数は、それぞれが 1 つの宛先またはルートを表します。例えば /about という宛先がある場合、コントローラーには
about()という関数が含まれることになります。
これまで MVC フレームワークを操作した経験がなければ、上記の 3 つの要点を読んでも、このような構成にすることの威力を察することはできないでしょう。しかし、MVC の点から考えるようになれば、PHP開発についての見方や取り組み方はがらりと変わってきます。
例えば、データベース・クエリーのコードをプロジェクトの至るところに押し込む代わりに、すべてをモデル内に整理します。そしてデータベース・テーブルからページを選択するには、この pages モデルに含まれる関数を使用します。
これと同じく、特定のページのルック・アンド・フィールを更新しなければならない場合にはビューを操作します。この場合、コントローラーをいじることはしません。コントローラーに追加するのは、アプリケーションの宛先やその他の制御コードです。これらのものは、モデルにも配置しません。
MVC フレームワークを操作して 1 日も経たないいうちに、このシステムが覚えやすく、必要に応じて簡単に拡張できることを実感するはずです。顧客が翌週に変更を必要としているとしても、問題なく対応することができます。さらに、その要求に来年対応するとしても同じことが言えます。
Convention-over-Configuration による MVC
MVC フレームワークのなかでも最もよく知られているのは、Ruby on Rails です。数年前、Ruby on Rails は Web 開発の世界に嵐を巻き起こし、人々は Ruby on Rails を使ったさまざまな可能性に思いを巡らせました。これは単なる MVC フレームワークではなく、「Convention-over-Configuration (設定より規約)」の原則に従った MVC フレームワークです。
Rails での Convention over Configuration は、重要な構成項目 (データベースのロケーション、特定のユーザー名とパスなど) をいくつか設定し、残りの項目についてはよく考慮されているデフォルトを使って操作することを意味します。デフォルトは後で調整することもあれば、調整しないこともあります。
その結果もたらされるのは整然と編成されたコードだけではなく、驚くほど快適に動作する、使いやすい Web 開発環境です。これはまさに、PHP 世界の開発者たちが切望していた素晴らしいツールでした。その後 1 年から 2 年の間には、おびただしい数の Rails 同様のツールが登場しました。そこには CakePHP、Symfony などが含まれます。
そしていよいよ EllisLab の善良な人々がリリースしたのが、CodeIgniter です。有効なあらゆる PHP MVC フレームワークを使って実験した多くの企業では、CodeIgniter が最終的に選ばれています。その理由は主に、このフレームワークは動的な編成が可能なため十分な自由度があり、迅速な開発が可能になるためです。
CodeIgniter での自由度とは、データベース・テーブルに特定の方法で名前を付ける必要も、モデルの名前をテーブル名にちなんだ名前にする必要もないということです。そのため、あらゆる類の突飛な構造を移植しなければならないようなレガシー PHP アプリケーションのリファクタリングを行うには、CodeIgniter が最適な選択となります。
CodeIgniter のコードには大きなフットプリントは不要です (1.6.2 リリースはわずか 2.8 MB で、そのうち 1.3 MB はユーザー・マニュアルなので削除しても構いません)。PEAR などの大きなライブラリーを組み込む必要もありません。PHP 4 と PHP 5 とで同じく有効に機能するため、移植性に優れたアプリケーションを作成することができます。さらに、ビューの作成にはテンプレート・エンジンを使用しなくても、昔ながらの HTML と PHP で十分対応できます。
入門用の資料は十分にあるので、ここからは単純なプロジェクトを作成して、このフレームワークを実際に確かめてもらうことにします。
新しい CodeIgniter プロジェクトで決まって最初のステップとなるのは、最新のパッケージをダウンロードすることです (この記事を執筆している時点での最新バージョンは 1.6.2 です。「参考文献」セクションを参照してください)。圧縮された (.zip) アーカイブをダウンロードして解凍すると、codeigniter_<version_number> フォルダーが作成されます。このフォルダーに、プロジェクトに取り掛かるのに必要なすべてのものが含まれています。
プロジェクト開始にあたって必要な、最小限の構成変更を行う前に、このセクションでは状況を理解できるように CodeIgniter について簡単に説明しておきます。
CodeIgniter フォルダーを開くと、system という名前のフォルダーがあります。ここに、CodeIgniter のすべてのコードが置かれます。このフォルダーのなかには複数のフォルダーがありますが、そのうちの 1 つに application というフォルダーがあります。作業するファイルのうちの 99.999% はこのフォルダーに含まれることになります。このフォルダーにこのような名前が付けられているわけは、ここに、アプリケーションとそのアプリケーションを構成するすべてのものが含まれるからです。system フォルダーの残りの部分には、CodeIgniter コア・コードやライブラリーなど、いじってはならないその他のファイルが含まれます。
application フォルダーは様々なフォルダーに分かれています (図 1 を参照)。そのほとんどは簡単に理解することができます。例えば、モデルは models フォルダーに、ビューは views フォルダーに、そしてコントローラーは controllers フォルダーに置かれるといった具合です。また、ローカル拡張機能を CodeIgniter ヘルパーおよびライブラリーに保管するためのフォルダーもありますが、この記事ではこれらのフォルダーについては取り上げません。
図 1. CodeIgniter のフォルダー構造
この時点で最も重要な system/application フォルダー内のフォルダーは config です。config フォルダーのなかには、早速対処しなければならない 2 つのファイル、config.php および database.php があります。
config.php ファイルの内容は、CodeIgniter をセットアップするための基本パラメーターと引数です。もう一方の database.php ファイルには、データベースに接続するための基本パラメーターと引数が含まれます。
現時点で config.php ファイルで必要となる作業は、base_url パラメーターを設定することだけです。このパラメーターは http://127.0.0.1/CodeIgniter/ に設定されているはずですが、この値を、使用しているサーバーのアドレスと一致するように変更してください。
$config['base_url'] = "http://www.example.com/"; |
Always add a trailing slash, even if you're setting up your CodeIgniter application in a subdirectory.
Next, open the database.php file, and set the connection parameters for your database server:
$db['default']['hostname'] = "your-db-host"; $db['default']['username'] = "your-username"; $db['default']['password'] = "your-password"; $db['default']['database'] = "your-db-name"; $db['default']['dbdriver'] = "mysql"; |
末尾には必ずスラッシュを追加する必要があります。末尾のスラッシュは、サブディレクトリーで CodeIgniter アプリケーションをセットアップしているとしても必要です。
次に database.php ファイルを開いて、使用しているデータベース・サーバーに応じた接続パラメーターを設定します。
必要な作業はこれだけです。他にもできることはありますが (自動ロードのプリファレンスや特別なルートを設定するなど)、CodeIgniter が場所を認識して基礎となるデータベースに接続できる限り、コーディングを開始することができます。
CodeIgniter のインストールと構成は完了したので、いよいよプロジェクトの作成を開始します。作成にかかる時間は長くても 1 時間程度です。
ここでは Hello World アプリケーションを作成する代わりに、CodeIgniter を使って単純な Web サイトを作成します。このサイトのホーム・ページには、販促用のコピーと、データベース・テーブルに送信されるフォームが表示されます。ルック・アンド・フィールについては心配する必要はありません。アプリケーションの観点から当然と思える部分だけに専念してください。つまり、見映えに関してはその道の専門家に任せて、アプリケーションが正しく機能し、素早く動作を完了することだけを確実にします。
CodeIgniter では、これらの要件を以下のような言葉で表現します。
- ほんの少数の関数のみが含まれる 1 つのコントローラー (デフォルトの Welcome コントローラーを使用可)
- 連絡先情報を保管するための 1 つのモデル (データベース・テーブルを設定)
- 1 つのマスター・ビューといくつかのサポート・インクルード
モデルから手を付けることで、機能と UI を重ねる前の基礎となるデータベース・テーブルを理解しやすくなります。そもそもテーブルに保持される内容がわからなければ、テーブルとやりとりするフォームを設計するのは難しい話です。
このサンプル・アプリケーションの場合、フォームから保管する必要があるのは連絡先情報です。どのような連絡先情報を要求するかについては、いろいろ意見があると思いますが、とりあえずは基本的な情報として、名前、E メール・アドレス、そしてちょっとしたメモを入力するようにします。バックエンドでは、タイムスタンプと IP アドレスも保管します。
CREATE TABLE `contacts` ( `id` int(11) NOT NULL auto_increment, `name` varchar(128) NOT NULL, `email` varchar(255) NOT NULL, `notes` text NOT NULL, `stamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, `ipaddress` varchar(32) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM; |
MySQL テーブルは、以下のようになります。
テーブルが用意できたので、今度は初めてのモデルを作成します。system/application/models フォルダーに、mcontacts.php という名前のファイルを作成してください。なぜ mcontacts という名前にするかと言うと、これがモデルの省略表現だからです。ファイル名を構成するモデル名の前に m を付ければ、model_ などといった長い接頭辞や接尾辞を使う必要がなくなり、整理がしやすくなります。
すべてのモデルは同じように構成されます。
class MContacts extends Model{
function MContacts(){
parent::Model();
}
}
|
クラス名がファイル名と一致すること、そしてクラスにはコンストラクターが必要なことに注意してください。つまり、モデルは PHP クラスです。したがって、モデルに含まれるすべての関数は、そのクラスのメソッドということになります。
この点を理解すれば、必要となるのは連絡先データベース・テーブルにデータを安全に挿入する関数である、という結論に至るまでの道のりは遠くありません。そのための関数は以下のとおりです。
function addContact(){
$now = date("Y-m-d H:i:s");
$data = array(
'name' => $this->input->xss_clean($this->input->post('name')),
'email' => $this->input->xss_clean($this->input->post('email')),
'notes' => $this->input->xss_clean($this->input->post('notes')),
'ipaddress' => $this->input->ip_address(),
'stamp' => $now
);
$this->db->insert('contacts', $data);
}
|
上記で重要な点は、POST に含まれるデータを格納している配列から入力を取得し、その入力をクリーンアップしてから contacts という名前のデータベース・テーブルに挿入していることです。この過程では、さまざまなヘルパーを使用してタスクを単純化しています。
例えば、$this->input->xss_clean() はフォーム・フィールドからのデータをクリーンアップし、$this->input->post() がフォーム・フィールドへのアクセスを単純化します。また、$this->input->ip_address() がユーザーのブラウザーから IP アドレスを取得して、$this->db->insert() が新しいレコードをデータベース・テーブルに追加します。
このコンテキストでは、$this->input->xss_clean() の使用が不可欠です。ここでは Web 上でのユーザー入力を扱っており、そこにはどんな内容でも入力できるからです。xss_clean() 関数を使用すると、より入念に安全性が保証できるため、最低限この関数を使用する必要があります。順番から言うと、次は入力フィールドを一定のサイズに制限する機能を加えるところですが、とりあえず xss_clean() ルーチンによって安全性は十分確保されています。
このようにほんの数分で、連絡先情報をデータベースに保管するために再利用可能な関数を作成できました。次は、コントローラーの作業に移ります。
CodeIgniter では、コントローラーがプロジェクトを編成する場所となります。それぞれの関数は、サイトやアプリケーションのそれぞれのページや宛先であると考えてください。例えばホーム・ページがあれば、index() 関数が必要となります。About Us ページがある場合には、URL をどのように構成するかによって、about() または about_us() 関数が必要です。
それぞれのコントローラーをフォルダー別に編成し、階層構造を作ることもできます。例えば、system/application/controllers フォルダーのなかに admin フォルダーを配置して、このフォルダーのなかに、管理ツールの主要なパーツごとのコントローラーを配置することができます。その場合、これらのコントローラー (および関数) には、http://www.example.com/admin/controller-name/function-name/ などでアクセスすることになります。
とりあえず今は、デフォルト・コントローラーで作業します。この Welcome という名前のデフォルト・コントローラーは、system/application/controllers/ フォルダーに welcome.php として保管されています。このファイルを開くと、以下のような内容になっています。
class Welcome extends Controller {
function Welcome(){
parent::Controller();
}
function index(){
$this->load->view('welcome_message');
}
}
|
ご覧のように、クラスの名前はファイル名を反映しています。また、CodeIgniter コア深くにある親 Controller クラスを呼び出すコンストラクターもあります。ここまでは何も問題ありません。
今度は起動関数、index() に目を向けてください。この関数は、welcome_message というビューをロードします。この関数を削除して独自の関数を作成する前に、重要な点として、アプリケーションのエンド・サーバーに情報を表示する上で必要最低限の作業は、このプロトタイプ index() 関数がほとんど行うということを理解しておいてください。
この点を指摘したところで、作業を進めて新しい index() 関数を作成します。まず始めに必要なことは、非常に有用な Form Helper をロードすることです。このヘルパーが、連絡先フォームを作成するという厄介なタスクを容易にします。
続いて、ビュー内部で使用できる複数の変数を設定します。変数を設定することによって、アプリケーションを整然とした状態に維持できるからです。例えば、コントローラーにタイトルとヘッドラインを設定する場合、この 2 つそれぞれに対応する変数をビューにロードします。ロードする変数の 1 つは、組み込みビューの名前です。このようにすれば、ルック・アンド・フィールのすべてを保持するマスター・ビューと併せて、コンテンツが含まれるさまざまなインクルードをセットアップすることができます。
function index(){
$this->load->helper('form');
$data['title'] = "Welcome to our Site";
$data['headline'] = "Welcome!";
$data['include'] = 'home';
$this->load->vars($data);
$this->load->view('template');
}
|
$data 配列は template というビュー (次のステップで作成します) に渡されます。この配列に含まれる情報にはキー名でアクセスします。つまり、ヘッドラインを出力する場合には、$headline を使ってその情報にアクセスします。
次のステップでは、template ビューと home ビュー (後者は単なるインクルード) を作成し、コントローラーを仕上げます。
最初に作成するのは、極めて単純な template というビューです。ビューに備わった優れた柔軟性を説明するために、このビューは簡潔なままにしておきます。template ビューは system/application/views に template.php として保管します。このビューは、最初は以下のようになっています。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
</body>
</html>
|
ここで、この template ビューに 3 つの変数を渡していたことを思い出してください。具体的には、$title、$headline、そして $include 内のインクルードの名前です。この内容を追加した template ビューを、追加部分を太字で示して以下に記載します。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title><?php echo $title;?></title>
<style>label { display:block;}</style>
</head>
<body>
<h1><?php echo $headline;?></h1>
<?php $this->load->view($include);?>
</body>
</html>
|
最初の 2 つの追加では、$data['title'] と $data['headline'] で検出したデータをそれぞれエコー出力します。次に $data['include'] の値を使用して 2 つ目のビューをロードします。この例の場合、ロードするのは home というビューです (多少の CSS を追加していることにも注目してください。これは後で、他の部分を単純化するためです)。
このビューを呼び出すとしたら、まずはビューを作成するのが賢明です。以下に、サイトの訪問者から情報を収集するためのテキスト・ブロックとフォームが含まれる単純なビューを記載します。
<p>This is random text for the CodeIgniter article.
There's nothing to see here folks, just move along!</p>
<h2>Contact Us</h2>
<?php
echo form_open('welcome/contactus');
echo form_label('your name','name');
$ndata = array('name' => 'name', 'id' => 'id', 'size' => '25');
echo form_input($ndata);
echo form_label('your email','email');
$edata = array('name' => 'email', 'id' => 'email', 'size' => '25');
echo form_input($edata);
echo form_label('how can you help you?','notes');
$cdata = array('name' => 'notes', 'id' => 'notes', 'cols' => '40', 'rows' => '5');
echo form_textarea($cdata);
echo form_submit('submit','send us a note');
echo form_close();
?>
|
このビューをブラウザーでロードすると、図 2 の画面が表示されます。
図 2. フォームを表示する単純なビュー
ここでもやはり、非常に有用な一連の CodeIgniter のショートカットを使用します。今回使用するのは、コントローラーにロードした Form Helper です。form_open() 関数によってフォームを開きます。この関数に必要な引数は、フォームの送信先だけです。この後、コントローラーに戻って contact() 関数を追加し、フォームの送信データを処理できるようにします。
このフォーム全体を説明すると、form_label() でユーザー補助ラベルを作成し、form_input() と form_textarea() でフォーム・フィールドとテキスト域を作成し、form_submit() で入力ボタンを作成します。注目する点として、form_input() および form_textarea() では (その他多くのフォーム関数と同じく)、フィールドの名前、ID、サイズなどの情報を追跡できるように情報の配列を渡すことができます。
最後に form_close() によってフォームを閉じます。
それではコントローラーに戻って仕上げの作業に取り掛かります。
この時点で、2 つのビューが準備できています。ここで必要となるのは、コントローラーに戻って 2 つの関数を追加することです。最初に追加する関数はご存知のとおり、contactus() です。この関数で、ホーム・ページのフォームから送られてくる POST を処理します。もう 1 つの関数は、最終的なフォームの確認ページとして機能する thankyou() です。
contactus() は単純な関数で、MContacts モデルをロードし、このモデル内部で addContact() 関数を実行した後、ユーザーをサンキュー・ページにリダイレクトします。そのための redirect() 関数を使用するには、URL Helper をロードしなければならないことに注意してください。
このコードは以下のとおりです。
function contactus(){
$this->load->helper('url');
$this->load->model('MContacts','',TRUE);
$this->MContacts->addContact();
redirect('welcome/thankyou','refresh');
}
|
thankyou() は以下のとおりです。
function thankyou(){
$data['title'] = "Thank You!";
$data['headline'] = "Thanks!";
$data['include'] = 'thanks';
$this->load->vars($data);
$this->load->view('template');
}
|
そして、thanks ビューは以下のように至って簡単なものです。
<p>Thanks so much for contacting us. Someone will be in contact with you soon.</p> |
読者の中には、どうしてこのような小さなビューで時間を無駄にしなければならないのか、なぜコントローラーに変数を設定して実行するという方法を使わないのか疑問に思うかもしれません。もちろんそのようにすることもできますが、機能コンポーネントは常に独立させておくのが最善策です。機能コンポーネントを分けておくことで、問題が発生するリスクがなくなるからです。
最後にもう 1 つ、やらなければならない作業が残っています。Welcome コントローラーの contactus() 関数では、データベース内に複数のブランク・レコードを作成してしまう危険があります。つまり、ユーザーが継続的に、あるいはある種のプログラムによって連絡先情報の宛先をユーザーのブラウザーにロードすると、このような事態が起こります。
この事態を防ぐのに最も簡単な方法は、コントローラーに簡単な検証を追加することです。POST データがある場合には MContacts モデルをロードし、addContact() 関数を実行した後、サンキュー・ページにリダイレクトしますが、POST データが含まれていない場合にはそのままホーム・ページにリダイレクトします。書き換えた関数は以下のようになります。
function contact(){
$this->load->helper('url');
if ($this->input->post('email')){
$this->load->model('MContacts','',TRUE);
$this->MContacts->addContact();
redirect('welcome/thankyou','refresh');
}else{
redirect('welcome/index','refresh');
}
}
|
1 時間足らずのうちに、CodeIgniter をインストールして構成し、ホーム・ページ、データベースに情報を追加するためのフォーム、そしてサンキュー・ページからなる Web サイトを作成することができました。
もちろん、学ぶべきことはまだまだたくさんあります。例えば、モデルと併せて必要なヘルパーやライブラリーを自動ロードしたり、アプリケーションに応じてキャッシュおよびパフォーマンスを調整したりすることもできます。さらに、CSS の他の長所をビューに加えたり、データベースへの挿入完了時に E メール通知が送信されるようにしたりすることも可能です。
現段階で、CodeIgniter を使い始めるために必要なすべての知識は身に付いています。
学ぶために
- developerWorks technical events and webcasts で最新情報を入手してください。
- developerWorks Web development ゾーンの Web 技術を専門とした記事やトライアルで、Web 開発者としての腕を磨いてください。
製品や技術を入手するために
- CodeIgniter プロジェクトの最新パッケージ (現時点では 1.6.2) をダウンロードしてください。
- CodeIgniter のオンラインのドキュメントを読んでください。
- CodeIgniter フォーラムにアクセスしてください。
- CodeIgniter ウィキにアクセスしてください。
議論するために
- developerWorks blogs から developerWorks コミュニティーに加わってください。
Thomas Myer は、技術書の著者、コンサルタント、そして Web 開発者です。彼が 2001年にテキサス州オースチンに創立した Triple Dog Dare Media は、企業がコンテンツ・マネージメント、ポータル、e-コマース・システムなどのアプリケーションを CodeIgniter ベースで作成する際の支援を提供する会社です。彼の著書には、『No Nonsense XML Web Development with PHP』(Sitepoint、2004年)、『Lead Generation on the Web』(O'Reilly、2007年) があります。2008年7月には彼の新しい著書、『Professional CodeIgniter』(WROX) も売り出されました。その他、IBM developerWorks、Amazon Web Services、AOL、Darwin Magazine などにも技術記事やビジネス記事を書いています。