2007-06-04 [長年日記]
_ ZF1.0RCのZend_Viewでlayout機能
もうlayout機能がないビューは使いたくないんだけど、Zend Framework 1.0RCになっても、Zend_Viewには標準でlayout機能が搭載されていないらしい。昔layout機能のproposalが出ていた記憶があるけど、あれってどうなってるのかな? Zend Frameworkの開発Wikiにつながらないから、状況がわからん。
前はZend_Viewのラッパーを書いてlayout機能を追加していたけど、1.0RCのZend_Viewはもはやラッパーを書くのは無理っぽいな。テンプレートエンジン差し替えとかコントローラとの連携とかまで考えたラッパーはとても書けそうにない。一発こっきりだったら書けるかもしれないけど、とてもバージョンアップ対応できそうにないし。
しょうがないんで、Zend_Viewをラップする以外の方法でlayout機能を実現しようと思ったんだけど、今のところ思いついたのはアクションコントローラのpostDispatch()でlayout処理を実現するアプローチ。
class FooController extends Zend_Controller_Action
{
public function postDispatch()
{
$response = $this->getResponse();
$view = $this->initView();
$view->contents_for_layout = $respoinse->getBody();
$response->setBody($view->render('path/to/layout.phtml');
}
}
<!-- ヘッダとかごちゃごちゃ --> <?php echo $this->contents_for_layout; ?> <!-- フッタとかごちゃごちゃ -->
みたいな感じね。
これはこれで一応動きそうではあるけど、Zend Framework 1.0RCでlayoutしたい場合は、こんな感じでやる派が多数派でしょうか?
2007-06-05 [長年日記]
_ ようやくViewの初期化手順が分かった
標準設定状態での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()とかを書き直したアクションコントローラを使う必要が出てくるんだろう。
2007-06-06 [長年日記]
_ 起動ファイルのコードのスコープ
どうでもいいけど、ちょっと気になること。
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メソッドのみで書いて、インスタンス化させずに動かした方がきれいか)。
っつーか、起動ファイルの中身をグローバルスコープでフラットに書いていると、可読性が悪くて嫌になってこない?
_ Zend_Aclのresourceの解決
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の関係がちょっとわかりにくかったけど。
_ しょうもないバグを見つけた
Zend_Logでmaskとorしているのを見つけたとき以来のしょーもないバグ。まだこんなのが残っているのか。
ちなみになんでこれを見つけたのかというと、ErrorControllerの中で、
$this->getResponse->setHttpResponseCode(403);
をした場合に、なぜかviewRendererでデフォルトのテンプレートがレンダリングされないという症状にはまったから。「Zend_Controller_Response_Abstract::setHttpResponseCode(403)でisRedirect()がtrueにセットされる」→「Zend_Controller_Action_Helper_ViewRenderer::postDispatch()で、render()するかどうかの条件に!$this->getResponse()->isRedirect()を見ている」という原因ね。
2007-06-12 [長年日記]
_ 「TrackBackはもうなかったことにしてはどうか?」とは? - Ogawa::Memoranda
URL間のlinkageを提供する外部サービスを実現して、ブログからは適当なAPIを用いてそのlinkage情報を利用するようにする
ってのは、blogmapの頃からトライしているネタなんだよなー。ちなみに今は亡きblogmapとは、RSSフィードからエントリーごとに含まれるリンク(URL/Amazon商品)情報を解析し、サイトやエントリーごとのリンク/被リンク情報を提供するサービスだった。海外には地図系のblogmapサービスがあるけど、それとは別(それより古かった)。
ただ、blog黎明期(もともとはWeb日記リンク集時代からHTML解析ベースでやっていた)のデータ量が少ない頃はよかったけど、blog時代になってデータ量が爆発的に増えると、どんどん必要なサーバーリソースが増え続けてしまい、さらには大量のspam blogによって耐spam機能を持っていなかったblogmapのシステムは破綻してしまった。
そこで、MM/Memo(ソーシャルブックマーク)を使って、自動的に収集されたデータ(URL)に対して、人力の重み付けを行ったりすることで、耐spam用の情報を得ようと思ったりもしたんだけど、自動収集されたデータとソーシャルブックマークに登録されるデータではその量が圧倒的に違いすぎて、そういう用途では使えなかった。
しょうがないんで、blogmapのシステムを捨て去り、新しく1470.netリニューアル版を作った。blogmapではupdate pingで更新情報が送られてくるサイトのデータを収集していたんだけど、そういうやり方だとspam系データがあまりにも多くなりすぎるんで、1470.netでは情報収集先に人力フィルターを通すようにした。
具体的には、ユーザーは自分がチェックしたいサイトのフィード群を登録し、そのサイト群内での情報の解析(ランキング/新着) をみられるようにした。
たとえば俺の場合は、 これらのサイトのフィード を解析対象として登録しておき、それによって、
という解析情報を得られるようにしている。
この登録フィードは基本的にはRSSリーダーに登録しているものほぼそのまま(OPMLでインポートした)んだけど、RSSリーダーでいちいち全部見ている暇がない場合は、ひとまずこういう解析情報をチェックしておくと、流行りものの状況がなんとなくわかるようになる。
で、こういう風に自分が情報をチェックしたいサイトのフィードを登録してもらうことで、spamサイトではないサイトのフィードを選別し、それによってspamの少ない優良なサイトのフィード群から収集したデータを元にした解析を行おうというアプローチ。
ただ、このアプローチだと基本的に収集するデータ量が少なくなりすぎる。spamが少ないのはいいんだけど、spamじゃないデータも少なくて、元々の目的だったリンク/被リンク情報の解析情報としては、あまりにも物足りないものになってしまう。
たとえばここの場合、 http://1470.net/site/tdiary.ishinao.net なんてURLで、サイト単位の被リンク情報が閲覧できるけど、ここで被リンク情報を見ても、ほとんど有用な情報がとれていない。複数の被リンク情報があるかと思ったら、ソーシャルブックマークサービスとかの新着情報経由だったりするのがほとんど。
ちなみに1470.netの場合は、ドメインのみではなく、 http://1470.net/site/tdiary.ishinao.net/2007 みたいに、パスの前方一致で絞り込むこともできるんで、ディレクトリ単位での言及チェックにも対応できる。エントリー(URL)単位での言及チェックは、http://1470.net/uri/http://tdiary.ishinao.net/20070606.html%23p01 みたいな感じね。というのはここでは本題ではないんだけど。
で、何が言いたいかというと、たくさんのnot spamなフィード情報を1470.netに登録していただけると、データ収集先が増えてもっと有用な情報が得られるようになるかもしれないんで、よろしくお願いします。1470.netにユーザー登録(はてなかTypeKeyのアカウントが使えます)してから、RSSリーダーとかからエクスポートしたOPMLをインポートをするだけで登録できますんで。ちなみにBloglinesはよく壊れたOPMLファイルをエクスポートするので注意してください。
2007-06-26 [長年日記]
_ MM/Memoのドメインを変更しました
MM/Memoのドメインを、http://1470.net/mm/からhttp://mmmemo.1470.net/mm/に変更しました(1470.netリニューアル版の方の負荷対策のためです)。自動的にリダイレクトするようにしていますので、今まで通り利用できるはずですが、修正漏れ等による不具合等ありましたらおしらせください。



_ (o) [元記事はエントリー間の参照関係の通知をend-to-endのメッセージングに依らない方法で実現することが趣旨なのでb..]
_ ishinao [元記事の話は、 http://1470.net/uri/http://as-is.net/blog/archi..]