Win2Kのシェア2007年09月06日 02時00分07秒

ΣΣ(゚Д゚;)

OSシェア、LinuxとWindows 98が並ぶ - @IT (via: あるSEのつぶやき: OSシェアで、LinuxとWindows 98が並んだらしい

タイトルにあるLinuxと98のシェアはかなりどうでもよくて、これにちとショックを受けた。

2位のWindows 2000は3.94%で0.12ポイントの下落だった。3位のMac OS Xも3.66%から3.73%にシェアを上げた。

がぼーん。もうじきマコスXに負けちゃうじゃん > Win2K。

いや、そりゃ現役OSじゃないのはわかってますがね。。。

ZendFramework入門・その3 フォームを取り扱う・その12007年09月09日 04時21分20秒

ちょっと予定を変更

前回の終わりに書いた予告では、「複数のアクションコントローラを使用する例」をやるつもりだったのですが、よく考えてみたらこれって特に技術的に注意点があるわけじゃないので今回は見送ることにしました。

その代わり、でもないんですが、今回はフォームを触ってみることにします。

フォルダツリーの構築

今回はまた新しいアプリケーションということにします。名前は「zf2」にしておきましょう。

お決まりのように、まずは以下のフォルダ構成を作ってください。

  • htdocs/
    • zf2/
      • application/
        • controllers/
          • IndexController.php
        • views/
          • scripts/
            • index/
              • index.phtml
              • dump.phtml
      • index.php
      • .htaccess
index.php は前回のものをそのまま流用してください。

IIS + ISAPI-Rewriteの環境の方は、httpd.iniにzf2向けの設定を追加することを忘れないでください。以下のようになります。

RewriteRule ^/zf2/[\w/\%]*(?:\.(?!(?:js|ico|gif|jpg|png|css)$)[\w\%]*$)? /zf2/index.php [I]

まずは、以下のようなきわめてシンプルな形で作成してみます。

  • 入力フォームを表示するアクション(→ indexAction)
  • indexActionの送信ターゲットで、入力フォームの内容をダンプするアクション(→ dumpAction
ということで、application以下には「IndexController.php」と「index.phtml」「dump.phtml」を作成することになります。

IndexController - 入力フォームの作成

さっそくIndexController.phpを作成してみましょう。まずはindexActionのみの実装です。

<?php
require_once 'Zend/Controller/Action.php';

class IndexController extends Zend_Controller_Action {
	// 初期化処理
	public function init() {
		// BASE要素向けのベースURL
		$this->view->assign( 'baseUrl', getApplicationUrl( $this->getRequest() ) );
	}
	
	// indexアクション
	public function indexAction() {
	}
}
IndexController.php
...はい、indexActionでは特にすることがありません(^^;

対応するindex.phtmlです。これまたなんのひねりもありませんね。

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
    <base href="<?php echo $this->baseUrl; ?>/"></base>
    <title>フォーム テスト</title>
  </head>
  <body>
    <h3>入力フォーム</h3>
    <form action="index/dump" method="post">
      <ul>
        <li>
          <label for="name">名前</label>
          <input type="text" name="name" id="name" size="20">
        
        <li>
          <label for="sex">性別</label>
          <select name="sex" id="sex">
            <option value="1">男性
            <option value="2">女性
          </select>
      </ul>
      <input type="submit" value="送信">
    </form>
  </body>
</html>
index.phtml
なんてことはない、dumpActionに向けてnameとsexというフィールドをpostするだけです。

フォームの入力内容を受け取る

あたりまえなのですが、indexActionから送信されたを受け取る必要があります。$_GETや$_POSTなどのスーパーグローバルを使ってはいけないということはないのですが、Zend Frameworkで用意されている機能を使うようにしましょう。

勘の良い方は、前回index.phpに追加した「getApplicationUrl」のコードからピンとくるかも知れませんが、Zend Framework(というよりZend_Controllerか)でリクエスト情報にアクセスするにはZend_Controller_Requestを使用します。

Zend_Controller_Requestの細かい説明は後回しにして、とりあえず入力内容を受け取って表示するだけのdumbActionを実装してみましょう。以下のような感じです。

<?php
require_once 'Zend/Controller/Action.php';

class IndexController extends Zend_Controller_Action {
	// 初期化処理
	public function init() {
		// BASE要素向けのベースURL
		$this->view->assign(
			'baseUrl',
			getApplicationUrl( $this->getRequest() )
		);
	}
	
	// indexアクション
	public function indexAction() {
	}
	
	// dumpアクション
	public function dumpAction() {
		$this->view->assign(
			'postData',
			$this->getRequest()->getParams()
		);
	}
}
「dumpAction」を追加したIndexController.php

そして、対応するdump.phtmlは以下のような感じです。

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
    <meta http-equiv="Content-Style-Type" content="text/css">
    <base href="<?php echo $this->baseUrl; ?>/"></base>
    <title>フォーム テスト - 送信内容</title>
    <style>
    .dump {
      border: solid 2px silver;
      overflow: auto;
      height: 250px;
    }
    </style>
  </head>
  <body>
    <h3>送信内容</h3>
    <pre class="dump"><?php var_dump( $this->postData ); ?></pre>
    <hr>
    <a href="index/index">戻る</a>
  </body>
</html>
dump.phtml

実行結果と解説

ここまでのコードを実行してみましょう。まずは「http://<host名>/zf2/」にアクセスすると、以下のようなフォームが表示されます。

入力フォーム

index/index
名前に「dara-j」、性別を「男性」にして送信すると、index/dumpで以下のように表示されます。

送信内容

array(5) {
  ["controller"]=>
  string(5) "index"
  ["action"]=>
  string(4) "dump"
  ["module"]=>
  string(7) "default"
  ["name"]=>
  string(6) "dara-j"
  ["sex"]=>
  string(1) "1"
}

戻る
index/dump

さて、dumpActionとdump.phtmlの解説です。 まず、dumpAction内の「$this->getRequest()->getParams()」ですが、「$this->getRequest()」でリクエストオブジェクトであるZend_Controller_Request_Httpのインスタンスを取得します。getApplicationUrlに渡している部分と同じですね。 そして、取得したリクエストオブジェクトの「getParams()」メソッドを実行した結果を'postData'としてviewにassignしています。

Zend_Controller_RequestのgetParamsメソッドは、getパラメータやpostパラメータなどの、クライアントから要求されたパラメータすべてを格納した連想配列を取得するメソッドです。(※ 実際にはsetParam/setParamsによって、コントローラ処理中に任意に設定されたパラメータも含まれますが、ここではそういった使い方には触れていません)

そして、dump.phtmlでは、'postData'としてassignされた連想配列をダンプしています。

getParams()の中身とその他のアクセスメソッド

出力された連想配列をみて「あれ?」と思いませんでしたか?キー「controller」が「index」、「action」が「dump」...そうです。どのコントローラのどのアクションが指定されたか、の情報もリクエストオブジェクトに含まれるのです。

ここではgetParams()でいっさいがっさいを取得しましたが、リクエストオブジェクトに対してgetControllerName()やgetActionName()といったメソッドでこれらの情報を取得することもできます。

リクエストオブジェクトZend_Controller_Request_Httpの主なアクセスメソッドには以下のようなものがあります。

  • mixed getParams() → ユーザパラメータやGETパラメータ、POSTパラメータを格納した連想配列を取得する
  • mixed getParam(string $key, [mixed $default=null]) → キー$keyに関連付けられたパラメータ値を取得する。$defaultを指定した場合、$keyが指定されていない場合のデフォルト値にできる
  • mixed getPost([string $key=null], [mixed $default=null]) → POSTパラメータを取得する。$keyを指定した場合は$keyに対応する値のみ、省略した場合は$_POSTそのものが返る。$defaultはgetParam()と同じ。
  • mixed getQuery([string $key=null], [mixed $default=null]) → getPost()のGET版
その他のメソッドやメンバはAPIリファレンスで調べてみてください。

今回のまとめ

今回のポイントは以下のとおりです。

  • フォームの入力値を取得するには、Zend_Controller_Request_Httpを使用して、getParams()メソッドを使用する
  • getParams()で取得できる連想配列にはコントローラやアクションの情報も含まれる
  • Zend_Controller_Request_Httpには、他にもgetParam()、getPost()などの情報へのアクセスメソッドがある
まとめてみると、また薄い内容でしたね...

今回の反省&次回予告

本当はこのあとに「受け取った入力値をもう一度フォームにまわす」ようなサンプルを載せるつもりだったのですが、思ったより記事が長くなったので今回はここまでにしました。単純に受け取った値をフォームに当てはめて表示させるだけなら今回の記事から簡単に作れるでしょうから、皆さん試してみてください。

さて、次回は今回のフォーム入力をベースに、他のアクションへ処理を委譲する方法とマジックメソッド、関連して(ようやく)基本的な例外処理方法について書こうと考えていますのでお楽しみに。

なさけなや...2007年09月10日 01時35分15秒

日中はあまり気乗りがしてなかったため見てなかったが、今全取り組みをみた。白鵬、横綱の負け方じゃないな。安馬がよかったのは確かだが、よりによって首投げかよ。

白鵬はどうもメンタルが脆い。まだ幼いのかもしらんが。

ZendFramework入門・その4 フォームを取り扱う・その22007年09月10日 04時18分44秒

未実装のアクションを呼び出す

さて、今回は例外処理からはじめたいと思います。とはいってもそう難しいことをやるわけではなく、Zend_Controllerが標準的に用意している仕組みの導入方法を説明するだけですが。

まずは例外を発生させるところからはじめましょう。やりかたは至極簡単、前回作成した「zf2」アプリケーションで、存在しないアクションを呼び出すだけです。 前回までの実装では、IndexControllerに実装したアクションメソッドは「index」アクションと「dump」アクションの2つのみでした。この実装状況のままで、存在しないアクションメソッド、そうたとえば「hoge」を呼び出してみましょう。

http://<host名>/zf2/index/hoge/ へアクセスしてみてください。いきなり「Fatal error」が表示されるはずです(表示されない場合はdisplay_errorsがfalseになっていると思われるので、PHP.iniを見直すか、index.phpでini_setを行うようにしてください)。

エラーハンドラを作成する

次にこの例外をキャッチして、エラーの内容を表示するようにしてみます。やり方は簡単、専用のアクションコントローラ「ErrorController」にアクションメソッド「errorAction()」を実装し、対応するビュースクリプト「error.phtml」をviews/scripts/error/に設置するだけです。

まずはErrorControllerを作成しましょう。内容は以下のように、結構シンプルなものになります。

<?php
require_once 'Zend/Controller/Action.php';

class ErrorController extends Zend_Controller_Action {
	public function errorAction() {
		// レスポンスオブジェクトから取得した
		// 例外情報をビューへassignする
		$this->view->assign(
			'errors',
			$this->getResponse()->getException()
		);
	}
}
ErrorController.php
「$this->getResponse()」はレスポンスオブジェクト「Zend_Controller_Response_Abstract」を取得するメソッドです。Zend_Controllerを使用している場合、処理中に発生したエラーはレスポンスオブジェクトに格納されるため、レスポンスオブジェクトを取得し、そのあとにgetException()メソッドで例外を取得します。そしてそれをビューへassignしています。

エラーの内容を表示する

このエラーアクションを表示するerror.phtmlは以下のようにしてみましょう。

<html>
  <head>
  	<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
  	<base href="<?php echo $this->baseUrl; ?>/"></base>
  	<title>フォーム テスト - エラー</title>
  </head>
  <body>
  	<h3>以下のエラーが発生しました</h3>
  	<ul>
  	<?php
  	foreach($this->errors as $error) {
  		echo '<li>' . $error->getMessage() . '</li>';
  	}
  	?>
  	</ul>
  </body>
</html>
error.phtml
errorAction内でassignされた「errros」を処理しているのですが、Zend_Controller_Response::getException()が例外の配列を返すためforeachで処理しています。配列の内容は例外クラス「Exception」およびその派生の例外クラスですので、getMessage()メソッドでエラーメッセージを取得することができます。Exceptionの詳細はPHPのマニュアルの「第20章 例外(exceptions)」を参照してください。

エラー処理を追加したフォルダツリー

ここまででフォルダツリーは以下のようになります。

  • htdocs/
    • zf2/
      • application/
        • controllers/
          • IndexController.php
          • ErrorController.php
        • views/
          • scripts/
            • index/
              • index.phtml
              • dump.phtml
            • error/
              • error.phtml
      • index.php
      • .htaccess

この状態でもう一度 http://<host名>/zf2/index/hoge/ へアクセスすると、今度は以下のような表示になるはずです。

以下のエラーが発生しました

  • IndexController::hogeAction() does not exist and was not trapped in __call()
index/hoge
「hogeActionが存在しない」旨のメッセージが表示されたはずです。

このように、発生したエラーはErrorController::errorActionで処理させるのがZend_Controllerの標準的な例外処理になります。この仕組みは、Zend Frameworkに標準で添付されている「エラーハンドラ」コントロールプラグインの機能により提供されています。詳細はリファレンスガイドの「7.12. MVC での例外」や「7.10.5. 標準の配布パッケージに含まれるプラグイン」を参照してください。

未実装のアクションをデフォルトアクションに振り分ける

さて、上の例では、未実装のアクションを呼び出すことで例外を発生させましたが、場合によっては未実装のアクションを例外にせず、他の動作に付け替えたい場合もでてくるかもしれません。

このような場合は、PHP5の標準的な機能である「__call」マジックメソッドを利用できます。__callは、未定義のメソッドが呼び出された場合にオーバーロードとして呼び出されるメソッドです。(「オーバーロード」の意味合いが、たとえばC#のようなほかのプログラミング言語と違う点に注意してください)

__callメソッドのシグニチャは以下のように定義されています。

mixed __call ( string $name, array $arguments )
第一引数の「$name」は呼び出された(存在しない)メソッドの名前、第二引数は呼び出しに使用された引数のリストになります。

ここでは、「未定義のアクションが呼び出されたら、デフォルトアクション(=indexAction)を代わりに実行する」ようにしてみます。追加するコードはシンプルです。

<?php
require_once 'Zend/Controller/Action.php';

class IndexController extends Zend_Controller_Action {
	// 初期化処理
	public function init() {
		// BASE要素向けのベースURL
		$this->view->assign(
			'baseUrl',
			getApplicationUrl( $this->getRequest() )
		);
	}
	
	// indexアクション
	public function indexAction() {
	}
	
	// dumpアクション
	public function dumpAction() {
		$this->view->assign(
			'postData',
			$this->getRequest()->getPost()
		);
	}
	
	// __callオーバーロード
	public function __call($name, $args) {
		// indexアクションへ処理を委譲
		$this->_forward( 'index' );
	}
}

IndexController.php(__callを追加)
上記の__callをIndexControllerに追加してhttp://<host名>/zf2/index/hoge/ へアクセスすると、先ほどはエラーが表示されていたのが、今度はindex/indexにアクセスした場合と同じ表示になります。つまりindex/hoge の呼び出しを index/index に付け替えたということです。

_forward プロテクトメソッド

アクションコントローラ内で、あるメソッドから他のアクションメソッドへ処理を委譲する場合は「_forward」メソッドを使用します。「_forward」メソッドはZend_Controller_Actionに実装されたプロテクトメソッドで、シグニチャは以下のようになっています。

final protected function _forward($action, $controller = null, $module = null, array $params = null)

第二引数でコントローラ名も指定できるのですが、通常は同じコントローラ内のほかのアクションメソッドを呼び出すと思われるためたいていは第一引数にターゲットのアクション名を指定するだけです。

ここで注意が必要なのは、_forwardの呼び出し実行時は、呼び出されるアクションコントローラが再度初期化される点です。 たとえば

public function hogeAction() {
	// 自身のhogeParamプロパティに値を設定
	$this->hogeParam = 'ほげほげ';
	// fugaアクションへ_forward
	$this->_forward( 'fuga' );
}
とした場合、その後呼び出されたfugaAction()内で「$this->hogeParam」を参照してもhogeAction内で設定した値は格納されていません。このあたりはZend_Controllerの内部における「ディスパッチ」処理の動作によるもので、いずれ解説をしたいと思いますが、ここでは「_forwardはメソッド呼び出しではなく、次のアクションの予約を入れている」ようなもの、と認識してください。

まとめ

今回の要点は以下のとおりです。

  • ErrorController::errorActionが定義されている場合、それが標準のエラーハンドラになる
  • エラー情報の取得はZend_Controller_Response::getException()で行う。戻り値はExceptionの配列である
  • __callメソッドで未定義のアクション呼び出しをカバーできる
  • Zend_Controller_Action::_forwardメソッドで他のアクションメソッドへ処理を委譲できる

あとがき&次回予告

またも予想より記事が長くなってしまったので、今回はフォーム処理周りに触れられませんでした(タイトルに偽りあり、ですね^^;)。次回こそは前回のフォームを拡張し、入力内容によって処理を分岐させるようなサンプルを行いたいと思います。また今回でてきた「_forward」の親戚筋にあたる「_redirect」についても解説してみたいと思います。

トラックバックスパムが増えてる2007年09月10日 23時19分58秒

先週くらいから、結構トラックバックスパムが増えてる。

googleに引っかかりづらい(8月に入ってからまたも嫌われてるらしいのだ)こんなしょぼブログでも、多い日は1日50件くらいのスパムがやってくる。

ほとんどがしょーもないアダルト系でとりあげるまでもないのだが、この週末からなぜか海外からのトラックバックが増えてきた。

今日なぞはnew mexico radioだのindiana weatherだの、何を意図しているのかさっぱりわからんのがやってくる。

機械処理なんだろうけど、効果あるのかな?