ZendFrameworkで携帯 文字化け対応

ZendFrameWorkで携帯対応してみた。その1

※動作保証しません。

ソースの文字コードがURF-8をShit-JISに変換して表示したかったが、ごにょごにょした所、いくつかはまったポイントがはったので備忘録として残しておく。
一番最初にためしたのは、Viewのフィルターでの変換
下記のようなフィルターを作成して、View->setFilter()で設定

1
2
3
4
5
6
7
8
class ConvertToSJIS implements Zend_Filter_Interface {
public function filter($value) {
// ここには半角カナ変換とか、改行・タブの除去などなど
// 処理が入ってます。
// 文字コードは直接指定ではないのですが、そのあたりは割愛
return mb_convert_encoding($value, 'SJIS-win', 'UTF-8');
}
}

View単体だと問題なかったのですが、Zend_Layoutを絡めるとバケラッタ!!
今回は、Zend_Layoutをバリバリに使いたかったので、ZendFrameWorkのソースコードを調査しました。

  • Zend_Layout内でrenderメソッドが呼び出された時に結局は、Zend_Viewのrenderが呼び出されている。
  • Zend_Layoutで呼び出されるViewは特に指定しなければ、ViewRenderに登録されたViewが使用される。
  • 今回は、Viewは特に指定していない
    結果として、こんな感じ
  1. ビューにフィルターを設定
  2. レイアウト内のビューを描画 → 描画したビューをフィルタリング
  3. レイアウトを描画 → 描画したビューを含んだレイアウトに対してフィルタリング
  4. の所で、すでに描画(文字コード変換済みのやつ)したビューに対しても再度、文字コード変換処理が実行されているっぽい
    で、さらに調査したところ、Zend_LayoutをMVCで利用した際に、最終的に呼び出されている
    Zend_Layout_Controller_Plugin_LayoutのpostDispatchメソッドで最終的な描画結果の
    書き出しをしていることを発見!!
    ここを拡張すればいけるのではという淡い期待のもと
    Zend_Layout_Controller_Plugin_Layoutの拡張クラスを作成
1
2
3
4
5
6
7
8
9
10
11
12
require_once 'Zend/Layout/Controller/Plugin/Layout.php';
class My_Layout extends Zend_Layout_Controller_Plugin_Layout {
// 親クラスのpostDispatchを継承
public function postDispatch(Zend_Controller_Request_Abstract $request) {
// 親クラスのpostDispatchを呼び出す
parent::postDispatch($request);
// 親クラスのpostDispatchで出力されたコンテンツを変換
require_once 'ConvertToSJIS.php';
$filter = new ConvertToSJIS ();
$this->getResponse()->setBody($filter->filter($this->getResponse()->getBody()));
}
}

そのあと、Zend_Layoutの初期設定している個所を以下のように修正

1
2
3
4
5
6
7
$layout_options = array(
'layoutPath' => 'レイアウトパス'
, 'layout' => 'デフォルトのレイアウトファイル'
, 'pluginClass' => 'My_Layout' // ここに拡張したクラスを設定
);
// レイアウトの開始
$layout = Zend_Layout::startMvc($layout_options);

‘2010.10.29追記’ ヘッダーの設定を忘れると文字化けするので忘れずに。

1
$this->getResponse()->setHeader('Content-Type', 'application/xhtml+xml; charset=Shift_JIS');

最初からShift_JISで作れという声も聞こえてこないこともないですが、ひとまず、UTF-8からShift_JISへの変換はうまくいったので良しとしています。
もっと楽な方法があれば、教えてほしいところです。