2010年9月8日水曜日

zend frameworkでZend_Filterを設定かつZend_Layoutを使うと文字化け

どうも、俺@仕事中です。

タイトルの通り、zend framework(v1.10.8)でZend_Filterを使ってviewにフィルタをかけて(実際は絵文字変換)、さらにZend_Layoutを利用すると文字化けが発生してしまいました。

Zend_Filterはこんな感じ(省略してます)
<?php
class My_View_Filter implements Zend_Filter_Interface {
public function filter($output) {
return mb_convert_encoding($output, "SJIS-win", "UTF-8");
}
}

で、コントローラのinit()メソッドで
public function init() {
$this->view->setFilterPath("My/View", "My_View_")->addFilter("Filter");
}
としてフィルタをセットしています。
レイアウトはapplication.iniの設定で
resources.layout.layout = "layout"
resources.layout.layoutPath = APPLICATION_PATH "/views/layouts"
としてレイアウトを有効にしています。

これだと、どうやらそれぞれのviewスクリプトに対しフィルタがかかり、さらに全てのviewスクリプトを含んだlayout.phtmlでさらにフィルタがかかるという2重フィルタ処理で文字化けが起こっているようです。

※このブログでも言及されていました。骨折り損のくたびれ儲け::ZendFrameworkで携帯 文字化け対応

上記のブログと同じ現象なのでこれで解決かな?と思ったのですが、なぜかうまくいきません。
1)独自のZend_Layout_Controller_Plugin_Layoutを拡張したクラスを作成
<?php
class My_Layout_Controller_Plugin_Layout extends Zend_Layout_Controller_Plugin_layout {
plubic function postDispatch(Zend_Controller_Request_Abstract $request) {
parent::postDispatch($request);
$filter = new My_View_Filter();
$this->getResponse()->setBody($filter->filter($this->getResponse()->getBody()));
}
}

2)application.iniに追記
resources.layout.pluginClass = "My_Layout_Controller_Plugin_Layout"


やり方が間違っているのか、、でも上のpostDispatch()メソッドで親クラスのを一度呼び出してるから文字化けするんじゃ??とも思うのですが、、
正しい方法があれば教えてください><

で、解決方法ですが、↑で作ったクラスなどはそのままにしておいてZend_View_Abstractクラスのrender()メソッドをちょこっと変更すればできます。
public function render($name) {
-- 中略 --
// return $this->_filter(ob_get_clean());
return ob_get_clean();
}


Zend_View_Abstractクラスを拡張しても良いかもしれませんね。

以上でぇぇす。

-- 2010.09.08 追記 --
Zend_Viewクラスを拡張したバージョンを作りました。
まず拡張クラスを作ります。
<?php
class My_View extends Zend_View {
private $_file = null;
// 一応
private $_useViewStream = false;
private $_useViewStreamWrapper = false;

public function render($name) {
$this->_file = $this->_script($name);
unset($name);

ob_start();
$this->_run($this->_file);
return ob_get_clean(); // ここは親クラスと違う
}
}

次はこの拡張Viewクラスを使うようindex.phpか、またはBootstrapに(※この例ではBootstrapを利用)
<?php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
protected function _initView() {
$view = new My_View(array()); // コンストラクタの引数はViewに渡すオプション配列、またはZend_Config
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper("ViewRenderer");
$viewRenderer->setView($view);
}
}

以上でーす。

0 件のコメント: