DBIx::Skinny::Row の値を JSON で出力したい!
から始まった、Row クラスをちょっと変わった方法で拡張するお話。
すごく特異なケースだと思いますが。。。
JSON に書き出すときに、できれば Row クラスから直接
my $itr = $model->search('table_name1'); while (my $row = $itr->next) { my $json = $row->to_json; # JSON にする }
って感じで書けるといい、よね?
そんなわけで、Skinny の "Row クラスの拡張" 機能を利用してみます。
詳しい説明は去年の Advent Calendar で!
で、書いてみたのがこんな Row クラス。
package MyApp::Model::Row::TableName1; use strict; use warnings; use base qw/ DBIx::Skinny::Row /; use JSON ( ); sub to_json { return JSON->new->utf8->encode(shift->get_columns); } 1;
これで、目的を達成することができました。
Skinny べんり!かんたん!わーい!
い?
って、あれ?Row クラスってテーブル固有のものだから、すべてのテーブルで to_json を利用したい場合、テーブル数分の Row クラスを用意しなきゃダメなのかな?
テーブルが全部で 20個くらいあるんだけど、どうしよう。。。
こんなときのために、すべてのテーブルで共通して使える Row クラスを定義できるといいなー。
さてさて、どうしよう。。。
といっても Skinny の構造は PHP に移植する過程でだいたい理解しているつもりなので、なんとなく目星をつけて、"Row クラスの拡張" を実現している部分に手を加えてみることにしました。
本来 Skinny では MyApp::Model::Row::TableName みたいな特定のテーブル専用のクラスを、自動で use してみて、成功すればそのクラスを返し、失敗した場合には anon row class と呼ばれている(?) "MyApp::Model::Row::Cdb3ee45d06b8098ef489e14b9bbb801741e549c8" のような Row クラスを返します。
そこで、今回はこの部分に手を加えて
- テーブル専用 Row クラスの use を試みる
- 失敗したらテーブル共通 Row クラスの use を試みる
- 失敗したら anon row class を返す
となるようにしてみました。
といっても、Skinny に直接手を加えるのもアレなので、MyApp::Model クラスの方で、Row クラスを作っているメソッド (_mk_row_class) を再定義してあげました。
こんな感じ。
共通で利用する Row Class のクラス名が、テーブル専用の Row Class とかぶってしまうと、とてもマズイので、Camelize された後に絶対出てこないクラス名 *1 にしてみました。
"共通で" って言っているんだし "COMMON_ROW" とかの方がよかったのかな。。。
これで、テーブル数分の Row クラスを用意するのではなく、以下のような Row クラスを1つ作るだけで、すべての Row クラスに "to_json" メソッドを生やすことができるようになりました。
package MyApp::Model::Row::BASE_ROW; use base qw/ DBIx::Skinny::Row /; use JSON::XS ( ); sub to_json { return JSON->new->utf8->encode(shift->get_columns); } 1;
テーブル専用の Row クラスも欲しい場合には ↑ を継承して作ればオッケーっぽいよね。
さてさて、目的はひとまず達成したように思いますが、こんなやり方は正しいのかな?
ひとまず、わーい。
*1:テーブル専用の Row Class は必ず Camelize されるため