Catalyst でのモデルとロジック

分けたほうがいいよー!という話を最近よく聞く(読む)ので、分けるようにした。
とりあえず Catalyst での config やら model はそのまま使いたいけれど、CLI とかではどうするの?って話になるので、その辺もくそかっこわるいけどなんとかできるように。

具体的には、Catalyst::Model::DynamicAdaptor をほんのちょっと拡張して、Catalyst::Model::DynamicAdaptor::Lazy というものを作った。
実際に使う場合には、それをベースクラスに持つ MyApp::Model::Logic なんてのをこさえて、MyApp::Logic::Hoge やら MyApp::Logic::Fuga なんてものを坦々と作ると。
で、Catalyst で動作している場合は、DynamicAdaptor そのまんまに $c->model('Logic::Hoge') 出来るし、Catalyst じゃない場合は、MyApp::Model::Logic のカスタムコンストラクタに config と schema を渡せばいいと。具体的にはこんな感じに使えるように。

my $config = LoadFile(file($Bin, '..', 'myapp.yml')); # とりあえず YAML 使ってるので
my $schema = MyApp::Model::DBIC->new;
my $l      = MyApp::Model::Logic->new_with_nocatalyst('MyApp::Logic', $config, $schema);
print $l->logic('Hoge')->say;

安直で、素晴らしくかっこわるい。正直このまま実用する気はない。

SQL を DBIC でうまく使う

DBIC Custom ResultSource for Arbitrary SQL

So you haven't figured out how to write a complex query in DBIC yet? No worries, DBIC will allow you to write that query in SQL. To do so one:

  • Defines a custom ResultSource based on an existing one.
  • Pass the new ResultSource's name method the raw SQL.
  • Register the new ResultSource with your Schema.

こんな方法は知らなかった。あとでやってみる。

Cookbook にも載ってた。

Catalyst::Plugin::Session の flash ではまった

Store::DBIC を使ってるのだけど、flash が使えなくてはまった。
そのとき出たログは、sessions テーブル の row が見つからないから update できないよーってもの。
row が見つからないっていうから id の照合順序とかそのへんを疑ったりしても何も変わらず。
で、もう一度 Manual とかを見直したら、sessions テーブルの構造がちょっとだけ違ってた。
俺が作った sessions テーブルは

CREATE TABLE `sessions` (
  `id` char(72) NOT NULL,
  `session_data` text NOT NULL,
  `expires` int(10) unsigned NOT NULL default '0',
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

こんなんで、正しくは、

CREATE TABLE `sessions` (
  `id` char(72) NOT NULL,
  `session_data` text,
  `expires` int(11) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

こう。phpMyAdmin で出力してるから余計な情報がくっついちゃってるけれども。
で、最初の例でも通常のセッション管理だけなら問題ない(多分。使えてたし)。けれど、flash を使う時に問題が発生する。
なぜなら flash データを保持するときは、expires に値を入力しないから。
で、expires に値が無いため、デフォルト値の 0 が設定される。すると、$c->delete_expired_sessions を実行した場合に期限切れとして flash データが削除されてしまうのだ。これが正しいほうの例であれば、expires には 0 ではなく null が設定され、その場合は delete_expired_sessions の対象ではなくなる。そういうことみたい。

ということで、つまらないミスのせいではまったけど、繰り返さないようにメモしとこう。

Google Chrome の使い道

今のところ、メインのブラウザとしてではなく、ショートカットをいくつか作って、単体アプリケーションみたいな感じで使ってる。
たとえばこんなショートカット。

  • 社内グループウェア
    • タイムカード的な機能を使ってるので、Firefox だと起動が遅くてめんどくさい。
  • 社内用 Google Calendar
    • 個人でいくつか Gmail アカウントを持ってるため、いちいちログアウトして会社用の Gmail アカウントでログインして・・・とかがめんどくさい。

こうやって限定的なサイトのショートカットを作っていけるのは便利だしとってもうれしい。
で、自作のコマンドラインランチャーでそれぞれを簡単に起動できるようにすれば完成。