拡張性の高いプログラムを作る プログラム演習6

プログラム演習4ではヤフーのウエブ検索APIを利用して簡単なウエブ検索サイトを作りました。次にこのサイトを以下の仕様で拡張することを考えてみます

【拡張仕様】

  • 検索キーワード入力窓と検索ボタンの間に web, image, both の3種が選択できる選択プルダウンを設置する
  • webが選択された場合は演習4の結果と同様の動きをする
  • imageが選択された場合はヤフー画像検索APIからキーワードに関連する画像を検索してサムネイル画像を表示する
  • bothが選択された場合は、ウエブ検索、画像検索の両方を行い、上下に疎の結果を表示する

という仕様とします。たとえば「紅葉」というキーワードでbothが選択された場合の出力は以下のような画面が期待されます。

【演習】
MVCや再利用を意識しないで、単純に演習4の延長で上の機能を実現するサイトを開発してみましょう。

おそらく、webが検索できるプログラムを基本として拡張する場合、最終的な出来上がりは同じようなロジックが点在する形になるでしょう。それを改善するために共通の処理を関数化したりとすれば、1つ機能が増えるごとのコードのステップ数(行数)はある程度押さえることがかのうです。では、「そのサイトにさらにブログ検索結果を...」という要求がきた場合、どの程度の修正量が必要かを考えてみましょう。 MVC的な発想でプログラムを開発すると、関数化でのアプローチとは異なる形での開発となります。
次に紹介するプログラムは一般的なMVCのモデルとは若干外れていますが、筆者自身が普段簡易なサイトを開発する際に使っている自己流のフレームワークを紹介します。
今回はプログラム一式から紹介します。以下から閲覧可能です
http://trac.assembla.com/cX0noKTPir3A7Oab7jnrAJ/browser/prog6
ファイル構造は以下のようになります

|-- ACTION  (動作処理の定義)
|   |-- Action_Base.class.inc     <--- あらゆる処理の基本となる動きを定義しています
|   |-- Action_both.class.inc     <--- both が選択しされたときの動きを定義しています
|   |-- Action_image.class.inc   <--- imageが選択されたときの動きを定義しています
|   |-- Action_main.class.inc     <---初めの画面の処理を定義しています
|   `-- Action_web.class.inc      <---webが選択されたときの動きを定義しています
|-- COMMON  (汎用的に使える機能)
|   |-- Config.inc    <--- 色々な設定値などを記入しておきます
|   |-- HttpApiRequest.class.inc    <--- HTTPでAPIからXMLを取得する機能を提供します
|   |-- Logs.class.inc     <--- error_logに必要な情報を書き込む処理を受け持ちます
|   `-- RequestManager.class.inc    <---クライアントからのURL引数を取得したりする機能を提供します
|-- MODEL (データを取得する部分)
|   |-- YahooImageSearch.class.inc   <--- ウエブ検索結果の取得&管理します  
|   `-- YahooWebSearch.class.inc  <---画像検索結果の取得&管理します
|-- VIEW  (テンプレート)
|   |-- ViewManager.class.inc   <--- Smartyでの画面描画を管理します
|   |-- cache  <--- Smartyのcacheディレクトリ
|   |-- footer.tpl  <--- ページフッタテンプレート
|   |-- header.tpl   <---ページヘッダテンプレート
|   `-- main.tpl   <---メインテンプレート
`-- index.php <---エントリーファイル

このサイトのURLは queryとactionの2種類のみの引数を受付ます(Config.incのline6で定義)

/prog6/index.php?query=[キーワード]&action=[web, image, bothのいずれか]

という仕様で動きます.
index.phpの処理が重要なのでその部分は以下に解説します。

<?php
    require_once('COMMON/Config.inc');
    require_once('VIEW/ViewManager.class.inc');

    $request = new RequestManager($ACCEPT_URL_ARGS);

    $actionClassName = 'Action_'.$request->get('action');
    if(!include_once("./ACTION/{$actionClassName}.class.inc")) {
        $actionClassName = "Action_main";
        include_once("./ACTION/{$actionClassName}.class.inc");
    }
    $action = new $actionClassName($request);
    $action->execute();

    ViewManager::viewSmarty($action->template, $action->templParams);

    exit;
?>

処理を順を追って解説すると

  1. RequestManagerというURL引数を管理するクラスにユーザからのリクエストを解析させます。
  2. 処理を決定するactionという引数をもとに、動作を行うクラス名を動的に決定させます ($actionClassName)
  3. 動作を行う処理が記述された(クラス)ファイルを読み込みます. (無い場合actionが空など. はAction_mainというクラスファイルを選択します)
  4. ACTIONクラスを生成(インスタンス化)します. 各クラスはAction_Base.class.incを継承させているのでexecuteメソッドは実装されてることを保証します
  5. ececuteを実行します。当然Actionのクラスごとに処理内容は異なります。
  6. 最後にSmartyで描画します

という処理をこのindex.phpで行っています。処理の解説のなかで、ウエブ検索や画像とかという記述はありません。よって基本的に、機能の拡張に対してこのファイルを修正する必要はないように作られています。
各ActionクラスのexecuteメソッドをAction毎に実装することになります。executeが終了した段階で

$action->template にこのActionの場合どのテンプレートを利用するか。今回は全部main.tpl
$action->templParams にテンプレートに渡したい変数(郡)をセット

するように実装します
Viewでは指定のテンプレートをSmarty書式で渡された変数を用いて画面をつくります。
データを取得する部分はMODELとしてACTIONとは別に定義しています。こうすることによって、データの処理をActionに依存することなく保守性,再利用性が向上します(bothの処理を参照)
このような形でプログラムすることで、たとえば、「ブログ検索結果の追加」という要求がきた場合はAction_blog.class.inc と MODELにブログ検索を取得するclassを追加すればすぐに拡張できます。

一般的に提供されているフレームワークを用いると、さらに汎用的なデザインパターンで開発することができますが、フレームワーク自体の利用の理解が必要になったりと敷居が高く感じられる方も多いと思います。そのような方は多少MVCとはいえない部分もありますが、上で紹介したような自己流フレームワークを一つ武器として持っておくと良いと思います。

番外: バージョン管理(ソース管理)システム

今回のプログラムコードは以下のURLで紹介しました。
http://trac.assembla.com/cX0noKTPir3A7Oab7jnrAJ/browser/prog6
これはSubversionと呼ばれるオープンソースバージョン管理システムです。バージョン管理システムを利用すると、プログラムはリポジトリと呼ばれるDBのような場所に一括管理され、ファイル毎の更新情報(世代管理)などが可能になります。リポジトリへの操作(追加,更新,ダウンロード)は専用のコマンドを利用して行います。バージョン管理システムSubversionの他に,CVSと呼ばれるものがあります。最近はtrucと呼ばれるプロジェクト管理とバグ管理も含めたツールに組み合わせて使うことができるSubversionが人気があるようです。
自分のPCにSubversionリポジトリを構築して管理することもできます。企業などでは専用の管理サーバに対して複数の開発者が利用する形態がおおいです。また、リポジトリの構築は多少の手間がかかるので無料で使えるオンラインサービス版のSubversionもあります。無料オンライン版は

などがあります。今回は assemblaを利用しました(unfuddleは管理したものをシェアすることが無料ではできないので)。オンライン版を利用するとsubversionのコマンド(svn)が利用できる環境を構築すれば、それを使えるのでプログラム開発する場合はあわせてこのようなシステムを利用することを検討すると良いでしょう。(公開設定すると、あらゆる誰にでもその情報の閲覧機会を与えてしまうので、無料オンラインのものを利用する場合はその登録内容に注意しましょう(個人情報など))
PHP開発におけるSubversionを用いたバージョン管理
意外と使われていない「個人用trac」活用のすすめ