Tags: 技術日記

技術日記
Zend Framework 1.5対応作業Edit

久しぶりにtrunk(Zend Framework 1.5相当)にupしてみたら、ViewRenderer連動時にアクションからビュースクリプト名に変換する際に、自動的にCamelCaseを小文字ハイフン区切りに変換するようになっていた(デフォルトのままのInflectorを利用した場合)。

「FooController::CamelCaseAction」が「foo/camel-case.phtml」になる。従来は単に小文字変換される(foo/camelcase.phtml)だけだったんで、その頃に作ったビュースクリプトファイル名を全部リネームしないと。

新しい仕様の方がわかりやすくていいけど、さらに古いバージョンの頃はfoo/CamelCase.phtmlでいけたから、これで3度目の仕様変更(リネーム作業)だなー。そろそろフィックスしてほしい。

そういえばZend_Layoutが追加されていたんで、自前の(ActionController::postDispatch()を利用した)レイアウト実装から、Zend_Layoutを使ったレイアウト実装への切り替えも行った。こちらは単純なレイアウト以上の高機能なものになっているっぽいけど、ひとまずは最低限のレイアウト機能のみを利用。

それ以外は特に変更しなくても、だいたい動いているっぽいかな。

Published At2008-02-04 00:00Updated At2019-12-30 23:56

技術日記
Zend_Mailで日本語ヘッダ要素を登録Edit

mb_encode_mimeheader()してから、setSubject()とかしただけだと、"\r"とか"\n"とかが"?"に変換されてしまうんで、

function encode_mimeheader_for_zendmail($str)
{
return strtr(mb_encode_mimeheader($str, 'iso-2022-jp'), array("\r" => '', "\n" => '');
}

みたいなものをかましておくのが正解か*1

っつーか"?"がZend_Mail内で変換されていたことになかなか気づかなかったよ。てっきりメールサーバーの問題だと思ってしまっていた。

*1 strtr($str, "\r\n", "")だとうまく動かなかったんでstrtr($str, array("\r" => "", "\n" => ""))に変更

Published At2007-12-25 00:00Updated At2019-12-30 23:56

技術日記
Zend_DateのW3C形式対応Edit

現状では、タイムゾーンでZを指定したパターンと、小数秒には対応していないんだね。例外になるんで注意。

Published At2007-12-06 00:00Updated At2019-12-30 23:56

技術日記
YUIのRich Text EditorEdit

いつの間にかYUIにもRich Text Editorってのが増えていたんだね(て、もしかして存在に気づいていなかっただけだったりして)。

JavaScript HTMLエディタも最近ではたくさんあって、何を使うのが一番いいのか選ぶのが難しい状態だったら、YUIにあるならそれが一番いいかなと思って使ってみたんだけど、まだベータ版だからなのか、あるいは根本的な方向性が俺が求めているものとは違うのか、ちょっと試してみたけれども現状では(今作っているアプリには)うまく使えなかった。しばらく様子を見ることにしよう。

ところで、YUIのRich Text Editorを試してみて思ったんだけど、これって、Editorで編集した内容をポストする時に、textareaに自動反映させようと、handleSubmitオプションをtrueにしておくと、form.onSubmit時にイベントハンドラ内でEvent.stopしてから、JavaScriptコードでsubmitし直しているせいで、input type="submit"な値をチェックして、どのsubmitボタンが押されたかを識別している(サーバーサイドの)コードが動かなくなるんだけど、こういう仕様って困る人多くないのかなー。

Published At2007-12-03 00:00Updated At2019-12-30 23:56

技術日記
無効なルーティングでIndex/Indexを呼ばせないEdit

Zend Framework(trunk)でRewriteRouterを使っていて、無効な(設定したルートいずれにもマッチしない)ルーティングの場合はエラーが出てほしいんだけど、なぜかIndex/Indexにルーティングされてしまう。

フロントコントローラ(もしくはディスパッチャ)のuseDefaultControllerAlways設定の問題かなーと思ったんだけど、それもデフォルトのままでOKのはずだし、おかしいなーと思いつつも、あまり重要度が高くない問題だったんでしばらく放置していた。

けど、やっぱり気色悪いなーとソースを追いかけてみたところ、なんだかZend_Controller_Dispatcher_Standard::isDispatchable()の、

         if (!$className) {
return true;
}

         if (!$className) {
return false;
}

なんじゃないかという気がしてきたんだけど、まさかバージョン1.0.0が発表されてずいぶん経つし(もう1.0.1も発表されてるし)、こんなところにこんなバグが残っているはずがない気もするし、Zend FrameworkのJIRA(バグ管理ツール)もまた落ちているみたいだし(っつーか、最近Zend FrameworkのWikiにつながったことないんだけど、その辺のサーバーって生きてるの?)、ひとまずここでさらしてみる。

直った

やっぱりバグだったのか。1.0.2(ZF-1727)で修正されていた。っつーか、1.0.2が出るまでずっとJIRAが死んでなかった? そんなにまめにチェックしていたわけじゃないけど、もしかしてZFの開発はすでに収束に向かっているのかと疑ってしまったよ。

Published At2007-09-20 00:00Updated At2019-12-30 23:57

技術日記
RC以降で仕様変更するなよ その2Edit

もう一個あった。Zend_Db_Table::createRow()したときに、primary keyカラムの値をnullにするのではなく、カラム自体へのアクセスができないようにしてある。こっちはまあテンプレートファイル名強制小文字化なんかと比べれば、仕様変更の内容自体には文句はない(より安全になったし)んだけど。っつーか、RC3からreleaseバージョンに変更しただけで、こんなにあちこち動かなくなるなんて思ってなかったよ。

Published At2007-07-04 00:00Updated At2019-12-31 00:00

技術日記
RC以降で仕様変更するなよEdit

なんか知らんが、Zend Framework 1.0.0 RC3から1.0.0への間に、viewRendererで解決されるテンプレートスクリプト名が、強制的にstrtolowerされるように仕様変更されたらしい。なにそれ。そんな仕様変更、RC以降でするべきことかよ。つーか俺は、テンプレートファイル名を全部リネームしなきゃならないんですか。そうですか。

Published At2007-07-03 00:00Updated At2019-12-31 00:00

技術日記
起動ファイルのコードのスコープEdit

どうでもいいけど、ちょっと気になること。

Zend Frameworkでは、起動ファイルにいろいろ初期化コードを書いていくけど、そこで使った変数はグローバル変数になってしまうことになる。たとえば、

$config = new Zend_Config_Xml('/path/to/config.xml');
Zend_Registry::set('config', $config);

とかして読み込んだconfigオブジェクトは、普通はZend_Registryにセットしておいて、必要に応じてZend_Registry::get('config')して使うけれども、実際はアクションコントローラの中とかで、

global $config;

とかすればアクセスできてしまう。かといって、わざわざ、

$config = new Zend_Config_Xml('/path/to/config.xml');
Zend_Registry::set('config', $config);
unset($config);

とまでは書かないよね。

じゃあグローバルスコープじゃないようにしようかと、起動ファイルの中身を、

function main()
{
// 各種初期化処理
}
main();

とかmain()関数でくくって書けばいいかなーと思ったりしたんだけど、それもいまいちぱっとしない気がする。どうせなら、

class Application
{
public function __construct()
{
$this->_init();
$this->_run();
}
protected function _init()
{
//初期化コード
}
protected function _run()
{
//実行
}
}
new Application();

までやっちゃった方が融通が利くか(staticメソッドのみで書いて、インスタンス化させずに動かした方がきれいか)。

っつーか、起動ファイルの中身をグローバルスコープでフラットに書いていると、可読性が悪くて嫌になってこない?

Published At2007-06-06 00:00Updated At2019-12-30 23:52

技術日記
Zend_Aclのresourceの解決Edit

Zend_Aclで、roleの方はスキーマ定義の段階でだいたい決まることが多いだろうし、それを解決するタイミングもユーザー識別の段階でほぼ確定だろうけど、resourceの方はどうやって解決するのが妥当だろう?

ドキュメントにある例では、resourceを指定せず(すべてのresourceに対して)roleごとに操作権限を設定するようになっているけど、よく使われるのは(すべてのresourceに対する)操作権限を管理するパターンではなく、どのresourceにアクセスできるかを管理するパターンだろう。たとえば、管理ツールには管理者のみがアクセスできる、とか。

そう言う場合、やっぱりmodule=resourceと考えて、Zend_Auth_Plugin_Abstract::preDispatch()あたりで、認証結果から確定したrole+リクエストから抜き出したmodule=resourceとして、$acl->isAllowed()するのが常道かな。module単位よりも細かい単位でアクセス制御したい場合は、function getResourceName($request)みたいなメソッドを用意して、requestから対応するresourceを解決するようにするとか。

ただ、SNSみたいにresourceとroleの関係を動的に解決しなければならないことが多いアプリケーションの場合、Zend_Aclをどう使うのがいいのかはまだ未解決。プラグインとかの共通層では対応が難しそうだから、roleとresourceの関係は抽象化した形で登録しておいて、アクションコントローラの末端でgetResource()とgetRole()を実装して突き合わせるしかないかな。それとも末端でローカルなZend_Aclオブジェクトを生成(=resourceもroleもローカルな定義を作り直す)した方がいいんだろうか。

ちなみに、ようやくZend_Session、Zend_Auth、Zend_Aclを実践的に使ってみているけど、思ったよりもだいぶ使いやすくなっていた。Zend_AuthとZend_Auth_Adapterの関係がちょっとわかりにくかったけど。

Published At2007-06-06 00:00Updated At2019-12-30 23:51

技術日記
ようやくViewの初期化手順が分かったEdit

標準設定状態でのView周りの初期化処理の流れがようやく理解できた。

  • Zend_Controller_Front::__construct()で、viewRendererがZend_Controller_Action_HelperBroker::addHelper()される
  • Zend_Controller_Front::dispatch()内で、Zend_Controller_Dispatcher::dispatch()される
  • Zend_Controller_Action::__construct()が実行され、その中でZend_Controller_Action_HelperBroker::__construct()が実行される
  • Zend_Controller_Action_HelperBroker::__construct()内で、viewRenderer::init()が実行される
  • viewRenderer::init()内で、viewRenderer::initView()が実行される
  • 初回のviewRenderer::initView()でのみ、Zend_Viewオブジェクトが生成され、2回目以降は作成済みのZend_Viewオブジェクトを使い回す
  • viewRenderer::initView()内では、Zend_Viewオブジェクトの生成以外のViewの設定(現在のリクエストに対応したパスの解決など)は、毎回(_forward()されるたびに)行われる
  • viewRenderer::initView()内で、Zend_Controller_Action::$viewにviewRendererの持つViewオブジェクトをセットする
  • これで、アクションコントローラ内のメソッドでは、$this->viewで、viewRendererと共通のViewオブジェクトを利用することができる

なのね。てっきりZend_Controller_Action::initView()の方がメインだと思って、それが呼ばれる場所を探していたよ。Zend_Controller_Action::initView()の方は、viewRendererがない場合用のZend_View生成場所なのね。

ただ、viewRendererの有無を意識したくなければ、アクションコントローラ内では直接$this->viewを使わず、$this->initView()経由でViewオブジェクトを扱うようにした方がいいのかな?

あと、こういう仕組みならば、viewRendererを利用している場合に限り、カスタムView(たとえばZend_View_Smarty)をあらかじめviewRenderer::setView()しておくことで、アクションコントローラ内で$this->viewとか$this->initView()とかして使うことができそうだ。viewRendererを使わない場合は、Zend_Controller_Action::initView()とかを書き直したアクションコントローラを使う必要が出てくるんだろう。

Published At2007-06-05 00:00Updated At2019-12-30 23:52