« 最近買ったHouse remixなCDS | Home | ナイトミュージアム »

[Catalyst]   Catalystでマルチバイトを取り扱うときのまとめ

#前に社内wikiに書いておいたのを公開してみるテスト。

Catalystでマルチバイトを扱う機会があるのは主に
  • ユーザーがフォームで入力する値 ($c->req->param())
  • データベースからの入出力 (DBIx::Class)
  • それ以外の文字列の評価
  • View::TTによる出力の生成
  • FillInFormによるフォームの埋め込み
  • HTTPレスポンス
です。 ここでは以下の条件でまとめてみました。
  • 文字コードはUTF8に統一
  • データベースにはmysqlを使用

下準備

テンプレート、perlのコードは全てUTF8で書きます。

mysqlの文字コードの指定は/etc/my.cnfに

[mysqld]
default-character-set = utf8
skip-character-set-client-handshake
[mysql]
default-character-set = utf8
[mysqldump]
default-character-set = utf8

を書いてから起動して、create databaseします。

ユーザーがフォームで入力する値 ($c->req->param())

Catalyst::Plugin::Unicodeを使う。 prepare_parameters時に$c->req->paramsの値にutf8フラグを立ててfinalize時に$c->res->bodyからutf8フラグを落としてくれる。

ただしfinalizeメソッドをオーバーライドしているのでFillInFormなどを使う場合には

use Catalyst qw/
	...
	FillInForm
	...
	Unicode
/;

とかして最後にロードするようにする。
(via http://unknownplace.org/memo/2006/03/09#e004)

データベースからの入出力 (DBIx::Class)

DBIx::Class::UTF8Columnsを使う。 $row->get_column/get_columnsでutf8フラグを立てて返す。
__PACKAGE__->load_components(qw/UTF8Columns Core/);
__PACKAGE__->utf8_columns(qw/name description/);

とかするとutf8_columnsで指定した$row->nameや$row->descriptionにutf8フラグが立つ。
指定していないものにはutf8フラグは立っていないのでマルチバイトコードを扱いそうなカラムは全部指定した方が良いかも。

それ以外の文字列の評価

常にutf8フラグを立てて評価する。
utf8::decode($str);

View::TTによる出力の生成

Catalyst::View::TT::ForceUTF8を使う。 テンプレートをutf8フラグを立てて処理する。
script/create.pl view TT TT::ForceUTF8

でViewクラスを作るか

すでにあるMyApp::View::TTを

use base 'Catalyst::View::TT::ForceUTF8';

として継承関係を変ればOK。

FillInFormによるフォームの埋め込み

通常は上記のことだけでOKなのですが、まれに
$c->req->param->{name} = 'ほげ';

というような処理をする場合、当然この文字列にはutf8フラグが立っていないのにView::TT::ForceUTF8でレンダリングされたutf8フラグ付きの文字列にfillformしようとするため文字化けします。

対処方法としては、"・それ以外の文字列の評価"で説明したとおり、常にutf8フラグを立てて取り扱えばいいのですが、面倒なときもあるのでHTML::FillInForm::ForceUTF8を使ったCatalyst::Plugin::FillInForm::ForceUTF8ってのを作りました。これだとfillform時に全てutf8フラグを立てるので文字化けは起こらなくなります。
ついでにFV::Sとか使ってると勝手にfillinするおせっかいな処理を抑制するオプション付き。

MyApp->config->(
    fillinform->{
        auto => 0
    }
);

HTTPレスポンス

HTTPレスポンスのcontent-typeはCatalystではデフォルトでutf8が設定されるけど、明示的に指定したい場合はMyApp::Controller::Rootで
sub render : ActionClass('RenderView'){}

sub end : Private{
	my ($self, $c) = @_;

	$c->forward('render');
	$c->res->content_type("text/html; charset=utf8");
}

とかしておけばOK。

Trackbacks:

このエントリーのトラックバックURL:

この一覧は、次のエントリーを参照しています: Catalystでマルチバイトを取り扱うときのまとめ:

Perl/Catalyst/日本語 from PukiWiki/TrackBack 0.2
Perl/Catalyst 概要 入力部分 ユーザーがフォームで入力する値 ($c->req->param()) デー...

コメントを投稿