2008年06月11日
Zend FrameworkでDocTest

Zend Frameworkをベースに開発している新しいカートのユニットテストを効率的に行おうと色々考えていて、前から気になっていたDocTestを試してみることにしました。
ということで、Mapleのkunitさん作のDocTestをZend Frameworkのプロジェクトで使うための覚書。
といっても、割とすんなりいきました。
Zend Frameworkにて、MVCの形のプロジェクトを既に用意できている段階であれば、パスの通ったところに、DocTestのalpha2を解凍して、srcディレクトリの中のファイルをコピー。
TestControllerを作成して、その中で、DocTestを呼び出すようにする。
<?php
class TestController extends My_Controller_Action
{
public function init()
{
parent::init();
}
public function preDispatch()
{
parent::preDispatch();
}
public function indexAction()
{
$this->_helper->viewRenderer->setNoRender();
$params = array('compileDir' => './var/tests_c');
$testDir = './lib/My';
$options = array('prefix' => 'My');
echo '<pre>';
Maple_DocTest::singleton($params)->run($testDir, $options);
echo '</pre>';
}
}
こんな感じ。
テスト対象を指定するところで、当初ライブラリ関係を収めているディレクトリ(./lib)を指定していたため、Zend Framework自体や、Smartyなんかもテスト対象とされてしまって美しくなかったんですが、ソースを読んでprefixの指定でうまく解決できました。
あとは、テストから除外したいディレクトリを設定するために、DocTestにちょっと手を加えたのと、テストに関する情報を抜き出す正規表現をちょっと変更しました。
DocTest.phpのgetTestDataメソッドの853行目
- if (preg_match_all('|(#test (.*?))?<code>(.*?)</code>|s', $str, $matches, PREG_SET_ORDER)) {
+ if (preg_match_all('|#test((.*?))<code>(.*?)</code>|s', $str, $matches, PREG_SET_ORDER)) {
どうも、元のままだと、#testから始まっていない(DocTest用ではない)Docコメントでも、<code></code>で囲まれた記述があると抜き出してしまう問題があるようでした。
Zend Frameworkのコードの中にそのような箇所があって、当初エラーを吐いていたので修正。
ということで、いざ動いてくれるとすごく楽ちんです。感動ものです。
投稿者 田中@グリニッジ : 17:50 | コメント (0) | トラックバック
2008年01月11日
Zend_Viewでescapeを勝手にやるための試行錯誤

Zend_View を使っていて、ビュースクリプトで都度都度 $this->escape($this->hoge) みたいな事をやるのがいやなので、試行錯誤。Zend_View_Abstractを継承したMy_Viewを作ってみました。
<?php
class My_View extends Zend_View_Abstract { public $autoEscape = true;
protected function _run() { $varBackup = null; if($this->autoEscape) { $vars = $this->getVars(); $varBackup = $vars;
foreach($vars as $k => $v) { if (is_string($v)) { $this->assign($k . '_raw', $v); $this->$k = $this->escape($v); } elseif (is_array($v)) { $this->$k = $this->_arrayEscape($v); $this->{$k . '_raw'} = $v; } } }
include func_get_arg(0);
if($varBackup !== null) { $this->clearVars(); $this->assign($varBackup); } }
private function _arrayEscape($vs) { foreach($vs as $k => $v) { if (is_string($v)) { $vs[$k] = $this->escape($v); } elseif (is_array($v)) { $vs[$k] = $this->_arrayEscape($v); } } return $vs; } }
こんな感じです。
使い方は、
// setup view $view = new My_View(); $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view); Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
みたいな感じで(ViewRendererは使わなくてもいいけど)、あとはアクションの中などで、
// 変数
$this->view->hoge = 'ほげ<br />ほげ';
// 配列
$tmp = array('aaa', 'bbb<br />bbb');
$this->view->hoge_array = $tmp;
とセットする。
ビュースクリプトの中では、エスケープ済みのものと、エスケープしないものがそれぞれ、
<!-- エスケープ済み変数 --> <?php echo $this->hoge; ?>
<!-- エスケープなし変数 --> <?php echo $this->hoge_raw; ?>
<!-- エスケープ済み配列 --> <?php echo $this->hoge_array[0]; ?> <?php echo $this->hoge_array[1]; ?>
<!-- エスケープなし配列 --> <?php echo $this->hoge_array_raw[0]; ?> <?php echo $this->hoge_array_raw[1]; ?>
みたいな感じ。多重配列も同じような感じ。
単純な用途の場合はこれはこれでいいのだけれど、いろいろとZend Frameworkのソースやドキュメントを追っていくと、自動でエスケープすると、却ってフォーム関係のView_Helperが使いづらくなりそうだったり、毎回別名の変数や配列を生成したりして、どうなのと思うところもあり。何か良いアイデア合ったら教えてください。
ビュースクリプト側でエスケープを書きたくないというのは、もちろん、不注意からXSSを生み出してしまわないためなのですが、そのためにややこしくなるのもいやなので、Viewにセットする段階で、フィルターかましてエスケープしてあげるほうがいいのかなぁとも思っています。
なるべくZend Frameworkの素のままで使ってみようと思ってましたが、やはりSmartyと、Smartyのプラグインを使ってViewまわりを固めたほうが早いかなと思って、現在そっち方面で検討中。
ViewRendererとかは結構便利なので、Zend Frameworkの良い所を生かしつつ。
ということで、Smartyを使ったViewの話は次回にします。
