Home > 技術・開発ツール Archive

技術・開発ツール Archive

PHP用IDEの○と× その3 – NetBeans(6.7.1)

EclipseとNetBeansを比較した情報はすでに多くあるが、「PHP用の統合開発環境」という視点で簡潔にまとめる。

NetBeansの◯

  • マルチプラットフォーム(Win, LInux, Mac)
  • 日本語関数名が使える(PHPUnitでテストケースを記述できる)(http://studiokdf.com/blog/2009/07/283.html)
  • UIが初めから日本語化されてる。Eclipseのように自力で日本語化する必要なし。
  • SubversionとMercurialが標準で使える。
  • インストーラが付属しており親切。6.5.1をインストールしている状態で6.7をインストールしたときには設定を自動で引き継いでくれる。
  • 設定項目が少なく、シンプル。

NetBeansの×

  • php5.3未対応
  • プロジェクトペインにファイルを直接ドラッグ&ドロップできない
    • これはEclipseになれている人が一番戸惑う部分ではなかろうか?
  • プラグインの数が少ない
    • 自分にとって一番残念なのはBTS/ITSと接続するプラグインが提供されていないことである。(6.5.1用にはある。)
  • Eclipseに比べてマイナーなので情報・Tipsが少ない。
  • 対応しているデバッガはXdebugのみ。
    • といってもXdebugが使えればそれで十分ではあるが。

まとめ

  • 設定が簡単な分、テキストエディタを使ってPHPの開発していた人が初めてIDEを使用する際にはNetBeansの方が適していると思う。一方Eclipseに慣れている人にとっては今のところ移行するメリットがあまり感じられない。拡張性が劣る分むしろ物足りなさを感じるだろう。ただしNetBeansの「関数名に日本語を使用して記述しても正しく認識される」という特徴はEclipse系IDE(PDT, ZendStudio, PHPEclipse)にはないので少々心惹かれる。

PHP用IDEの○と× その2 – Zend Studio(7.0)

Zend StudioはEclipse PDTをベースにしたその上位版という位置づけである。

Zend Studio の◯

  • マルチプラットフォーム(Win, LInux, Mac)
  • php5.3対応
  • 他のZend製品との連携機能(Zend Server, Zend Debugger, Zend Guard)
  • リファクタリング支援機能(自分の知る限り、この機能を持つPHP用IDEはZend Studioだけである。

090803 0001 300x262 PHP用IDEの○と× その2    Zend Studio(7.0)

  • ポップアップウィンドウからZend_Toolのzfコマンドが使える

zendstudio7 300x180 PHP用IDEの○と× その2    Zend Studio(7.0)

  • 日本語版を購入すればUI、ドキュメントが日本語となる。
  • DB接続、SVNとの接続、PHPUnit, phpdocumentorなどが最初からプラグインとして含まれている。
  • トンネリングによるリモートデバッグをサポート。

090710 0002 300x208 PHP用IDEの○と× その2    Zend Studio(7.0)

  • フォーマッターの振る舞いを細かく制御できる。

090710 0001 300x228 PHP用IDEの○と× その2    Zend Studio(7.0)

Zend Studio の×

  • 約4万円で1年間のアップグレード権&ユーザサポート。少々高い?
  • PDT同様、日本語の関数名をつけると怒られる。
  • デバッガの選択肢としてZendDebuggerしか選べない(ただしXdebugを有効にする方法はある。(How to enable the Xdebug debugger in Zend Studio for Eclipse – Blog of Max Horvath )だがこの設定をするとせっかくのZend ServerやZend Debuggerとの連携はできなくなってしまう。)
  • 日本語版のリリースの遅さ。

まとめ

  • リファクタリング機能とコードのフォーマッティング機能は大きな魅力である。
  • 日本語版のリリースは本家英語版に比べて数ヶ月〜1年ほど遅いので注意。エンジニアたるものどうせ英語とは縁を切ることはできないのだから、買うとしたら英語版で良いと思う。

PHP用IDEの○と× その1 – PDT(Eclipse)

対象としたのはPDT2.1(Eclipse 3.5ベース)である。

PDTの◯

  • 無償
  • マルチプラットフォーム(Win, Linux, Mac)
  • 豊富なプラグインで自在に拡張
  • php5.3に対応
  • 日本語の情報やTipsが豊富

PDTの×

  • 関数名に日本語を使うとsyntaxエラーになってしまう。

これはPHPUnitを使ってテストケースを書く場合に問題となる。PHPUnitの場合

/**
*@test
*/

とメソッドのコメントに書けばメソッド名を”test”で始めなくてもテスト用メソッドと認識されるという機能を持つ。テスト用のメソッドの名前はどうしても長くなるので便利である。(NetBeans 6.7 Beta で PHPUnit – 逃走航路@hatena)P残念ながら今のところPDT(と上位版のZendStudio)では日本語のメソッド名をIDEが受け付けないのでこの機能が使えないということになる。

NetBeansの場合は下のようにエディタ中で日本語を入れても正しくIDE側で正しく認識してくれる。

 NetBeans IDE 6.7-1

NetBeans IDE 6.7-2

  • デバッガとしてZend Debuggerを選んだ場合はプロファイリングやコードカバレッジの機能は使えない。有償の上位版であるZend Studioを使う必要がある。(Zend Debugger, Xdebug, DBGを比較する ) この機能を使いたい場合はXdebugを使う。
  • 設定項目が非常に多くて複雑。エディタを使って開発していた人がPDTに移行する場合この部分でつまずいてしまうのでは。

その他

  • デバッガはXdebug,またはZendDebuggerが使用できる。かつてXdebug使用時には変数の中身の日本語が化けていたが現在は問題無し。(ここを参照。)
  • 数年前まではEclipseベースのPHP用IDEといえばPHPEclipseだったが、PDTがEclipseの公式プロジェクトになったことでその 立場は逆転したようだ。Web上の情報から判断するに、PHPのIDEとしては日本で恐らく最も広く使われていると思う。
  • PDT2.1はEclipse3.5ベースなのだが、矩形選択などの新機能は使えない。マークオカレンスなどEclipse3.4で追加された機能はPDT2.1でやっと使えるようになった。PDTの場合、機能の進化がEclipse本体の進化よりも1年遅れというのが残念。

※PDTについてはここが詳しい。

Zend Debugger, Xdebug, DBGを比較する

Zend Debugger

Index of /pdt/server-debugger

  • PDT または Zend Studio(6.0以上)と一緒に使用できる
  • Zend Serverには組込み済み
  • Zend Studioと併用すれば統合されたプロファイリング機能やコードカバレッジ機能が使える。
  • 現在公開されている最新バージョンは2008年9月リリースの5.2.15だがZend Serverにもこれと同じバージョンが入っているのかどうかが不明。(ちなみに最新のZend Studio 7.0.0betaに組み込まれているZend Debuggerのバージョンを見たら5.2.26となっていたので開発は進んでいるようだ。おそらくこれはPHP5.3に対応したバージョンだろう。)

Xdebug

Xdebug – Debugger and Profiler Tool for PHP

  • サードーパーティのオープンソース製品。非常に優れたツールとして広く使用されている。
  • なんとすでにPHP 5.3に対応済み(2.0.4以降)
  • エラーの内容をわかりやすく整形して出力してくれる。(ここを参照。) コードカバレッジ機能とプロファイリング機能を標準で備えている。
  • phing, PHPUnit, phpDocumentorとの連携で自動テスト&レポート作成ができる。
  • PDT(2.0以上)およびNetbeans(6.5以上)と組み合わせて快適に使える。
  • Zend製品との組み合わせに難あり
    • Zend Studio – EclipseベースのはずなのにZend Debuggerしか選べない。(※注)
    • Zend Server – 相性が悪い

DBG

  • オープンソースの無償版と有償版がある。
  • 無償版はPHPEclipse VS.Php などでサポート。
  • 有償版は商用IDEのNuSphere PhpED と共に提供される。
  • 最新版がリリースされたの2007年の5月と少々古い。
  • PHP5.2まで対応。
  • 今となっては多少マイナーな存在か。Xdebugが先に進みすぎているだけかも。

まとめ:

Zend DebuggerはZend Studioと一緒に使わないとコードカバレッジやプロファイリング機能を使えないのが辛い。ZendとしてはユーザにZend製品で統一してもらいたいのだろうが、無償で利用できるXdebugと比較した場合その価格に見合った価値を提供できているかというと正直”?”である。今後の開発でさらに優れた製品になることを期待。

(※ 注) 実はZend Studio使用時にXdebugを有効にする方法がある。How to enable the Xdebug debugger in Zend Studio for Eclipse – Blog of Max Horvath

PHP開発を行うための統合AMP環境まとめ

「IDEとデバッガを使用して開発作業を行う」という前提でメジャーな統合AMPをまとめる。

Zend Server

特徴:

  • Windows版、Linux版, Mac OSX版あり
  • デバッガ(Zend Debugger)組込み済み。
  • 他のZend製品との連携機能あり。
  • GUIによる管理画面がとても充実している。
  • ウェブサーバとしてApacheだけでなくIISも選べる(Windows版のみ)

コメント:

  • Xdebugとの相性が良くないのでデバッガはZend Debuggerをそのまま使うのが賢明だ。(参考:Zend ServerでCLI – noopな日々)ということは、プロファイリングやコードカバレッジ機能は有償のZend Studioを使わないと実現できないということになる。
  • Mac版の場合、 以前にも書いたが実運用重視のためパラメータやパーミッションの設定が厳しめ。このあたりのことをできるだけ気にせずに開発作業をしたい人はMAMPのほうがいい。
  • 有償版に限った話だがページキャッシュ、アプリケーション監視、自動アップグレード&パッチ適用機能などがある。これは実運用には役立つだろう。

MAMP

特徴:

  • Mac 専用
  • UIがシンプルで扱いやすい
  • デバッガは自分で組み込む必要あり

コメント:

  • 製品のリリース間隔が長いのが不安。現在のver.1.7.2は約1年前にでたもので、PHPのバージョンは5.2.6でApacheは2.0系、 MySQLも5.0系。
  • Zend Serverに比べてセキュリティ設定が甘いのであれこれといじりやすい。
  • MAMP Proという実運用向けの製品もある。

XAMPP

特徴:

  • Windows版 Mac版 Linux版 Solaris版あり
  • デバッガは自分で組み込む必要あり
  • Windows版についてはメールサーバやFTPサーバも付属。
  • 開発が活発ゆえパッケージ内の各アプリが新しめ。
  • Mac版については起動・停止にコマンドラインを使う必要あり。

コメント:

VertrigoServ

特徴:

  • Windows版のみ
  • XAMPPよりもGUI管理画面がわりと充実、ただしZendServerほどではない
  • 開発が遅いので現バージョンに含まれるPHPは5.2.6のまま

コメント:

  • もっと開発のスピードを速くしないとXAMPPにとってかわることはできそうにない。

次エントリではデバッガの比較をしたいと思う。


2009/7/7  はてブ経由でBitnamiを知ったので以下追記。

Bitnami

特徴:

  • Windows版, Mac版, Linux版, Solaris版あり
  • インストーラで簡単インストール
  • コントロールパネルのUIは必要最低限かつシンプルでわかりやすい
  • PHPのバージョンは5.2.8。Apacheは2.2系、MySQLは5.1系
  • デバッガは自分で組み込む。
  • MAMP同様中身をいじりやすい。

コメント:

  • インストーラが良くできている。
  • XAMPPやMAMPよりもこちらの方が優れているか。

Zend DebuggerとXdebug – どちらを使えばよいのか

  • XdebugをPDTで使ってデバッグすると変数に含まれる日本語を正しく表示できない、だからPDTとの組み合わせではZend Debuggerを使うべき
  • Zend Debuggerはmod_rewriteには対応していないのでCakePHPをデバッグできない。XdebugならOK。

という主旨の情報がWeb上にいくつか見られるので試してみた。特に後者の問題については他の人の報告を鵜呑みにしているだけのようなエントリが見受けられるので自分で確かめたかった。

動作させた環境

- Mac OS X 10.5.7

- Zend Server Community Edition 4.0.3 + Zend Debugger(Zend ServeにはZend Debuggerが最初から入っている。組込み済みZend Debuggerの正確なバージョンを知る方法が自分にはわからないので断言はできないが、Zend Debugger 5.2.15が2008年の9月に公開されているので少なくともこれより後のバージョンのはずだ)

- MAMP 1.7.2 + Xdebug 2.0.4

- PDT 1.0.3

- PDT 2.0

- PDT 2.1

1. Xdebug + PDTは文字化けするのか?

PDT1.0.3では確かにデバッグ内容が文字化けする。だが2009年1月にリリースされたPDT 2.0およびつい最近リリースされたPDT 2.1では大丈夫だ。(もちろんPDT側で文字コード関連の設定を正しく行う必要はある。)

2. Zend Debugger + mod_rewrite + CakePHPは正しく動かないのか?

これは耳にした時から腑に落ちなかった。同じくmod_rewriteを使用するZend Framework + Zend Debuggerの組み合わせで自分は問題に遭遇したことがないからだ。CakePHP固有の問題なのかもしれないのでCakePHP(1.2.3.8166)をセットアップし、サンプルをPDT2.0でデバッグしてみたのだが何の問題もなくデバッグできた。

この問題に言及しているウェブ上の情報が1年前以上のものということで少々古いし、書き手の環境等の具体的なデータが載っていないのが気になる。もしかして以前はこの組み合わせではだめだったのかもしれない。ただ自分も今回さらりと使っただけなので「現在のバージョンでは問題なし」と断言できるほど十分使い込んだとは言えない。なのでこの辺はCakePHPに詳しい人に会ったときにぜひ聞いてみたい。

まとめ

  • 最近のPDT(2.0以上)はXdebugとZend Debuggerのどちらと組み合わせてもちゃんと日本語を扱える。
  • Zend Debugger + mod_rewrite + CakePHP の組み合わせに問題があるのかどうかについては保留(個人的な感触としては2009年7月現在の最新バージョンを使えば問題なさそう)

※PDT以外のIDE以外の場合については別エントリで書きたいと思う。

EclipseからPhingを使う

phingのタスクををantとしてラッピングしてみた。なんでそんなことをする必要があるのかと言えば、Eclipse(PDT / Zend Studio for Eclipse)からphingを使うためである。そしてなぜphingを使いたいかというと、Zend Frameworkを使用したプロジェクトの環境変数(production環境 or development環境)という情報を.htaccessやiniファイルにハードコーディングするのに違和感があるからである。こういう値はアプリケーション本体の上に位置するレイヤーで設定・コントロールするべきものだ。
phingをEclipseから使うためには外部ツールとしての登録などいくつか方法があるとは思うが、せっかく親戚のantが標準で入っているのだからそれを使わせていただく。phingのタスクをantのタスクでラッピングしてEclipse側からはantとして実行するわけである。ラッピングしているだけなので、Eclipseを使わずにコマンドラインから直接phingを実行することもできる。

事前準備:

-  phingをインストールする。(詳細は省略。)
- Zend Studio  for Eclipse(6.1系 or 7.0.0beta)を使用している場合、デフォルトではなぜかantがオフになっているのでちょっとした設定が必要。(PDTの場合は不要。)

設定方法:

1. メニューからNew(新規作成) => Other…(その他)を選ぶ。

090630 0009 150x150 EclipseからPhingを使う
2. Show All Wizardsにチェックを入れてから、Java => Java Project from Existing Ant Bundleを選びNext。

windows xp home edition 150x150 EclipseからPhingを使う
3. するとダイアログボックスが「Ant Developmentを有効にするか?」と聞いてくるのでOKを押す。新規作成そのものはキャンセル。これでAntが使えるようになる。

処理対象ファイル

application.php.distというファイルに環境関連の設定記述があるものとする。このファイルに対してphingで処理を行う。

application.php.dist
<?php
$paths = array(
    get_include_path(),
     '../library'
);
set_include_path(implode(PATH_SEPARATOR, $paths));
defined('APPLICATION_PATH')
    or define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

	defined('APPLICATION_ENV')
		or define('APPLICATION_ENV', '@ENVIRONMENT@');

				以下略

タスクの定義

1. phingの定義ファイルbuild.xml)を作成

build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="testphing" default="setappenv" >
    <property name="basedir" value="../" />
        <target name="setappenv">
		    <property file="ant.properties" />
		    <copy file="${basedir}/application/application.php.dist"
			tofile="${basedir}/application/application.php" overwrite="true">
			    <filterchain>
				<replacetokens begintoken="@" endtoken="@">
					<token key="ENVIRONMENT" value="${environment}" />
				</replacetokens>
			</filterchain>
		   </copy>
	  </target>
</project>

2. プロパティファイルを設定

ant.properties
phing=/Path/to/phing
environment=development

3. ラッパーであるantファイル(ant-build.xml)を作成

ant-build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="phing-wrapper" default="setappenv">
	<target name="setappenv" description="Set application environment from property file">
		<property file="ant.properties" />
		<exec dir="" executable="${phing}">
			<arg line="setappenv" />
		</exec>
	</target>
</project>

4. ant-build.xmlをAnt Editorで開き、antビューかoutlineビューにてタスクを選択し、 Run as => Ant buildと実行。

090630 0007 150x150 EclipseからPhingを使う

phingを実行するとapplication.php.distの中の@ENVIRONMENT@の部分が”development”に置換され、新たにapplication.phpとして作成される。アプリケーションはpublic/index.phpなどでapplication.phpをインクルードして以後の処理を行うことになる。

まとめ

たかが一個の変数を設定するためにphingを使うのはいかにも大げさだが、タスクを追加設定していけばテンポラリディレクトリの掃除/データのリロード / ユニットテスト実行 / ドキュメント生成 / 配布用アーカイブ作成 といった定型作業を自動で実行できるようになるので正確で迅速なリリースの助けになるだろう。

参考サイト
Zend Framework 1.8: Building MVC Web Applications
How to enable the Ant plugin in Zend Studio for Eclipse – Blog of Max Horvath
PHPUnit3で始めるユニットテスト:第5回 PHPUnitの便利な機能とPhingとの連携|gihyo.jp … 技術評論社

Zend Framework のViewにPHPTALを使う

(少なくとも日本においては)PHPのテンプレートエンジンと言えばSmartyが知名度・普及度共に圧倒的だが、Smartyで定義されたテンプレートファイルはプレビューしたときにデザインが崩れるという欠点がある。これはSmartyを知らないデザイナーさんとの協業をする場合に大きな問題になるし、自分でデザインをするとしてもロジック側が完成しないと出来上がりのイメージを目で見ることができないのがつらい。

ところで最近のPHP製フレームワークはViewとして素のPHPファイルを使うのがモダンスタイルということになっている。確かにテンプレートエンジンを使わずとも記述を工夫すればテンプレート風に書くことはできるしなによりその方が速度の面で有利だ。 そこで目を付けたのがPHPTALだ。日本語のマニュアルも整備されている。 以下のエントリを見ると PHPテンプレートベンチマーク —- PHPTALに注目 – なんたらノート 第二期 速度的にはSmartyとそん色ない。 なによりも大きな特徴はこのエントリが述べているように

* タグ構造を維持したまま、属性に制御コードを書く(デザイナフレンドリ)

* 元ページのDOMノードをラップするマクロを定義できる

という二点だ。2番目の特徴はさておき最初の部分だけでもPHPTALを使う価値が十分にあると思う。

PHPTALとZend Frameworkとの組み合わせについては次の情報が有力と思われる。 TAAT — Zend Framework Tutorial Step 2

※著者はポーランド人のようである。Zend Framework関連の海外情報を見ているとポーランド人が発信した情報が多いのに気づく。

今回PHPTALの調査を兼ねてこのソースをダウンロードして動かしてみた。なお、著者の説明によると

${structure helper:layout().content}

のような記述でビューに変数を書けるとあるのだが、これではPHPTALの美点が失われてしまうのでいただけない。PHPTAL本来の記述を試してみることにする。 コントローラ側で

$this->view->name = 'name';
$this->view->defaulttext = 'hoge@example.com';
$this->view->attributes = array('id'=>'anotherID','size'=>22);

と書きビュー側で

<li tal:content="structure helper:formText(name, defaulttext, attributes)">この部分は置き換えられる</li>

としたところ出力されるHTML が

 <li><input type="text" name="name" id="anotherID" value="hoge@example.com" size="22" /></li>

だったのでこのPHPTAL式記述で問題ないようだ。 なお、PHPTALの仕様として

tal:content=”$value”

と書いた場合に$valueは第2引数にENT_QUOTESを、第3引数に文字エンコーディング(デフォルト値はUTF8)を伴ったhtmlspecialchars関数で自動的にエスケープされる。セキュリティの観点から見てこれらのパラメータは指定する必要があるので、PHPTALのこの仕様は正しい。(参照:htmlspecialchars/htmlentitiesの正しい使い方 )もしエスケープさせたくない場合は

tal:content=”structure $value”

と”structure”を付加すれば良い。

さてまずレイアウトを定義したファイルだが

application/modules/default/views/layouts/main.tpl.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
		<title>Main layout</title>
	</head>

	<body id="index">
		<div id="page-container">
		<h1 id="title">Main layout</h1>

			<?php echo $this->layout()->content ?>      ⇐1

			${structure helper:layout().content}           ⇐ 2

		    <span tal:content="structure helper:layout().content">contents</span>    ⇐ 3

		</div>
	</body>
</html>

1. がZF標準の書き方、2.が変数の中身だけを書く方法、3.がPHPTALの美点を生かした書き方である。3つのうちどれを使っても全く同じHTMLを吐き出す。(ZFSyntax.phpというプレフィルターがあるので1.のように書いてもちゃんとPHPTALが理解できるように内部で書き換えてくれるのだ。)ここではもちろん3.を採用する。 レイアウトの中に含めるビューは

application/modules/default/views/templates/index/index.tpl.html
<div >
 <ul>
    <li tal:content="structure helper:formatCurrency(price1)">price1(JPY)</li>
    <li tal:content="price2">price(with no helper)</li>
    <li tal:content="structure helper:formatCurrency(price2, '&euro;')">price2(EURO)</li>
    <li tal:content="structure helper:formText(name, defaulttext, array('size'=>35, 'id'=>'myID'))">this is email</li>
    <li tal:content="structure helper:formText(name, defaulttext, attributes)">this is email</li>
    <li tal:content="name">this is email</li>
  </ul>
</div>

コントローラではテスト用に意地悪な値をセットする。

application/modules/default/controllers/IndexControllers.php
<?php
class IndexController extends Zend_Controller_Action
{
    public function indexAction ()
    {
        $this->view->price1 = 'ABC';
        $this->view->price2 = '12800';
        $this->view->name = "'&<>";
        $this->view->defaulttext = "hoge@example.com'&<>";
        $this->view->attributes = array('size'=>22, 'id'=>'"anotherID"');

    }
}

通貨表示用のフォーマットを行うビューヘルパーを作る。

application/modules/default/views/helpers/FormatCurrency.php
<?php

class My_View_Helper_FormatCurrency extends Zend_View_Helper_Abstract {

    public function formatCurrency($value, $symbol='&yen;')
    {
        $output = $value;
        $value = trim($value);
        if (is_numeric($value)) {
            if ($value >= 0) {
                $output = $symbol . number_format($value, 2);
            } else {
                $output = '-' . $symbol . number_format(abs($value), 2);
            }
        } else {
        		$output = '###値が無効です###';

        }
        return $output;
    }
}

表示結果は

090624 0001 300x187 Zend Framework のViewにPHPTALを使う

となる。はきだされたHTMLソースを見ると

Main layout
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
		<title>Main layout</title>
	</head>

	<body id="index">
		<div id="page-container">
		<h1 id="title">Main layout</h1>

		    <span><div>

  <ul>

    <li>###値が無効です###</li>
    <li>12800</li>
    <li>&euro;12,800.00</li>
    <li><input type="text" name="'&amp;&lt;&gt;" id="myID" value="hoge@example.com'&amp;&lt;&gt;" size="35" /></li>
    <li><input type="text" name="'&amp;&lt;&gt;" id="&quot;anotherID&quot;" value="hoge@example.com'&amp;&lt;&gt;" size="22" /></li>
    <li>&#039;&amp;&lt;&gt;</li>

  </ul>
</div></span>

		</div>
	</body>
</html>

である。formTextに入れた値のシングルクォートがエスケープされていない。

調べてみると

<li tal:content="name">this is email</li>

というPHPTALの記述はコンパイルされて

<li><?php echo phptal_escape($ctx->name, ENT_QUOTES, 'UTF-8') ?></li>

と展開され、

<li tal:content="structure helper:formText(name, defaulttext, attributes)">this is email</li>

<li><?php echo $ctx->this->formText($ctx->name, $ctx->defaulttext, $ctx->attributes) ?></li>

となっていた。formTextはZF純正のビューヘルパーで、エスケープ処理には内部的にhtmlspecialcharsを使っているのだが、第2と第3パラメータは明示的に指定する必要があるのである。そこで

library/My/PHPTAL/Escape.php
<?php

class My_PHPTAL_Escape {

    public static function safeEscape ($var) {
        return htmlspecialchars($var, ENT_QUOTES, mb_internal_encoding());

    }

}

というクラスを作り、ZFでのエスケープ処理の際は常にこれを呼ぶようにする。

library/My/Controller/Plugin/ViewSetup.php
           ~~~
$view = new My_PHPTAL_ZFView();
//set 2nd and 3rd parameters to escape method
 $view->setEscape(array('My_PHPTAL_Escape', 'safeEscape'));    // <== Added
          ~~~
$phptal = new PHPTAL;
 $view->setEngine($phptal);
 $phptal->setPhpCodeDestination($root . '/temp')
 ->setEncoding(mb_internal_encoding())        // <== Added
 ->setForceReparse(true)
 ->setPreFilter(new My_PHPTAL_Filter_ZFSyntax());

改めて出力してみると

    <li>###値が無効です###</li>
    <li>12800</li>
    <li>&euro;12,800.00</li>
    <li><input type="text" name="&#039;&amp;&lt;&gt;" id="myID" value="hoge@example.com&#039;&amp;&lt;&gt;" size="35" /></li>
    <li><input type="text" name="&#039;&amp;&lt;&gt;" id="&quot;anotherID&quot;" value="hoge@example.com&#039;&amp;&lt;&gt;" size="22" /></li>
    <li>&#039;&amp;&lt;&gt;</li>

となりinput中のシングルクォートもエスケープされるようになった。 ということでPHPTALの機能のごく一部を触っただけだがこれはなかなかいけそうな雰囲気である。PHPアプリケーション構築でテンプレートエンジンを利用してデザイン部分を分離する必要がある場合、PHPTALはSmartyに代わる有力な候補になるのではないだろうか。

Zend Framework Quick StartにDoctrineを適用してみる – その2

前回のエントリのコードはDoctrine関連の記述が煩雑だった。せっかくZend_Applicationが出てきたのだからそれを利用したスマートな記述ができるのではと思っていたら、すでに先人がいた。

Doctrine ORM and Zend Framework « Danceric

多忙のため更新が滞っている元ネタの作者に代わりZF1.8を適用した形で書き直したというエントリである。内容はコードを見てもらえばわかるとして、doctrine-cliの中の

$application->bootstrap('doctrine')

$application->getBootstrap()->bootstrap('doctrine');

の間違いだと思う。(前者だとBootstrapの中の_init*メソッドがすべて実行されてしまうので。)

それから同じくdoctrine-cliの中で

define('APPLICATION_ENV', 'development');

とあるが、この値は外部に出してindex.phpとdoctrine-cliとで共用すべきだろう。preparation.phpの中にまとめてあるのでそれをインクルードするようにした。

doctrine-cli
#!/usr/bin/env php

<?php
/**
 * Doctrine CLI script
 */
//Preparation
require_once '../library/preparation.php';

//Doctrine Bootstrap
$application->getBootstrap()->bootstrap('doctrine');

$cli = new Doctrine_Cli($application->getOption('doctrine'));
$cli->run($_SERVER['argv']);

Zend Framework Quick StartにDoctrineを適用してみる

前回のエントリに基づき、ZF本家のクイックスタートにあるチュートリアルのコードをDoctrineを使って書き直してみた。Zend_Dbを使う場合に一番面倒なモデルのコードの記述が簡単なYAMLファイルを一つ書くだけで済み、コントローラの修正も最低限で済んだ。

新旧の概要を比較を見てみると

オリジナルのディレクトリ構造

zf_original

Doctrine適用後のディレクトリ構造

zf_modified

  • モデルの生成をDoctrinに任せた結果、チュートリアル中の”Create a Model and Database Table”に関わる部分は不要になる。つまりオリジナルの”models/”以下のコードはまるまるDoctrineが生成するコードで置き換わる。
  • MySQLを使用するのでdata/に入っていたSQLiteのテーブルを削除。代わりにDoctrineを使用する際に必要になる4つのディレクトリを置く。schema.sqlはDoctrineが生成したものである。
  • library/の配下にDoctrine本体(1.1.1)と自分でカスタマイズしたプログラムを入れる。本来はプラグインとして定義すればスマートなのだろうが今回は省略。また環境設定関連の情報はWebアプリとDoctrineのコマンドラインツールの両方から参照される必要があるので、preparation.phpとして外に出しここに配置。
  • scripts/の配下はDoctrineのコマンドラインツールを動かすためのdoctrine-cli.phpに置き換える。
  • あらかじめZendFrameworkにパスが通っていることが前提。もちろんlibrary/の下にZFを置いてもいい。自分が使用したバージョンは1.8.2。
  • 余談だが、library/の下に複数のライブラリを置く場合にどうやって配置するかという問題を感じた。正攻法で行けば各ライブラリごとにサブディレクトリを切ってその中に配置することで明示的に分けるべきだろう。ただしそうなると新たにライブラリを追加するたびにinclude_pathのメンテも行わなければならなくなり面倒だ。一方フラットに配置したとするとlibrary/にさえパスが通っていればあとはAutoloader任せでOKということになる。ただしファイル名の衝突が生じたときにやっかいなことになるだろう。

public/index.phpとscripts/doctrine-cli.phpの両方から呼び出されるpreparation.phpの内容はこんな感じだ。

preparation.php
<?php

// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

// Set include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../library'),
    realpath(APPLICATION_PATH . '/../library/doctrine'),
    realpath(APPLICATION_PATH . '/models'),
    realpath(APPLICATION_PATH . '/models/generated'),
    get_include_path()
)));

require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->setFallbackAutoloader(true);

// Create application
$application = new Zend_Application(
    APPLICATION_ENV,
    APPLICATION_PATH . '/configs/application.ini'
);

$application_ini = new Zend_Config_Ini(APPLICATION_PATH . '/configs/application.ini', null);
Zend_Registry::set('application_ini', $application_ini);

$connection = My_Db_Doctrine::connect($application_ini );

Zend_Registry::set('doctrine_config', array(
    'data_fixtures_path'  =>  APPLICATION_PATH . '/../data/fixtures/',
    'migrations_path'     =>  APPLICATION_PATH . '/../data/migrations/',
    'sql_path'            =>  APPLICATION_PATH . '/../data/sql/',
    'yaml_schema_path'    =>  APPLICATION_PATH . '/../data/schema/',
    'models_path'         =>  APPLICATION_PATH . '/models/'
    ));

Doctrineとの接続を行うクラスであるMy_Db_Doctrineも定義する

library/My/Db/Doctrine.php
<?php

class My_Db_Doctrine
{

    public static function connect($application_ini){

        $data = $application_ini->con_database;

        $dsn = sprintf(
                '%s://%s:%s@%s/%s',
                strtolower($data->type),
                $data->username,
                $data->password,
                $data->host,
                $data->dbname
        );

        $db =  Doctrine_Manager::connection($dsn);

        return $db;
    }

}

今回モデル関連で作成する必要のある唯一のファイルがschema.ymlである。

schema.yml
---
Guestbook:
  tableName: guestbook
  columns:
    id:
      primary: true
      autoincrement: true
      type: integer(10)
    email:
      type: string(32)
      notnull: true
      email: true
    comment: string(255)
    created: timestamp

オリジナルのスキーマにはemailフィールドにデフォルト値を定義しているが今回は省略。また初期データの投入のしかけもスキップした。

今回はSQLiteではなくMySQLを使用するのでapplication.iniファイルに以下のセクションを追記する。

[con_database]
name      = "db"
type      = "mysql"
dbname    = "zfdev"
host      = "localhost"
username  = "zfdev"
password  = "zfdev"
charset   = "utf8"

scripts/doctrine-cli.phpは実行スクリプトではなくただのphpファイルにした。こうすればWindowsからも使えるはずだ。

doctrine-cli.php
<?php

//Preparation
require_once '../library/preparation.php';

$cli = new Doctrine_Cli(Zend_Registry::get('doctrine_config'));

if (isset($_GET['cmd'])) {
    $_SERVER['argv'] = array('doctrine-cli.php', $_GET['cmd']);
}

$cli->run($_SERVER['argv']);

scripts/の中から

php doctrine-cli.php

と実行するとDoctrineのオプション一覧が出てくる。

doctrine cli execution 150x150 Zend Framework Quick StartにDoctrineを適用してみる

正しくコマンドラインツールが動いているのが確認できたので今度は

php doctrine-cli.php build-all

を実行。DoctrineがMySQL内にテーブルを作り、同時にapplication/modelsの配下にモデルが生成される。DDL文は別途

php doctrine-cli.php generate-sql

とすることでdata/sqlの配下に生成されるがアプリの動作そのものには必須ではない。

コントローラについて修正が必要なのはapplication/controllers/GuestbookController.phpだけだ。

application/controllers/GuestbookController.php
<?php

class GuestbookController extends Zend_Controller_Action
{

    public function init()
    {

    }

    public function indexAction()
    {
        $guestbook = Doctrine_Query::create()
                        -> from('Guestbook g')
                        -> orderBy('g.created DESC')
                        -> execute();

        $this->view->entries = $guestbook;
    }

     public function signAction()
    {
        $request = $this->getRequest();
        $form    = new Default_Form_Guestbook();

        if ($this->getRequest()->isPost()) {
            if ($form->isValid($request->getPost())) {
            	$guestbook = new Guestbook();
                $guestbook->fromArray($form->getValues(true));
                $guestbook->created = new Doctrine_Expression('now()');
                $guestbook->save();

                return $this->_helper->redirector('index');
            }
        }
    	$this->view->form = $form;
    }

}

元のコードは、indexAction()が

    public function indexAction()
    {
        $guestbook = new Default_Model_Guestbook();
        $this->view->entries = $guestbook->fetchAll();
    }

で、signAction()が

   public function signAction()
     {
        $request = $this->getRequest();
        $form    = new Default_Form_Guestbook();

        if ($this->getRequest()->isPost()) {

            if ($form->isValid($request->getPost())) {

                $model = new Default_Model_Guestbook($form->getValues());
                $model->save();

                return $this->_helper->redirector('index');
            }
        }

である。非常に単純なアプリケーションとはいえ拍子抜けするほど簡単に変更できた。(当然ながらビューはまったく変更していない。)

Doctrineを使うと参照整合性制約やモデル同士の一対一/一対多/多対多といった関係、さらにモデル同士の継承でさえも簡単に定義できてしまうという。 もちろんDoctrineという一種のフレームワークを覚えなければならないからその分のコストはかかるしDoctrine独自の制約といった難し さもあるのだろうが、それらを補ってあまりある恩恵が得られると思う。これはトライする価値ありだ。

Home > 技術・開発ツール Archive

アーカイブ

Return to page top