2007年5月アーカイブ

Catalyst::Plugin::FillInForm::ForceUTF8 をアップデートしました。そのうちインデックスされると思います。


0.02 Wed May 23 2007
- implemented finalize method

そう。どこでソースが入れ替わったのか知りませんが、finalizeを実装してないのをあげちゃったのでデフォルトでFormValidatorがエラーを返してもfillformしてなかったんですね。てへ。

自分の環境では常に明示的にfillformしてるので、同僚のAさんに言われるまで気づかなかったです。

てか、Catalystのプラグインのテスト書くのすんごい面倒なのでテストを書いてないのばればれです。この辺のBP欲しかったりする。

[% WHILE %] の中のこと その後 (日々のこと)
と、思っていたら、多対多のときには _rs ではできないね。

そうそう。忘れてました。many-to-manyではできないんですね。
これはドキュメントにもちゃんと書いてあって

DBIx::Class::Relationship - Inter-table relationships - search.cpan.org
Many_to_many is not strictly a relationship in its own right. Instead, it is a bridge between two resultsets which provide the same kind of convenience accessors as true relationships provide. Although the accessor will return a resultset or collection of objects just like has_many does, you cannot call $related_resultset and similar methods which operate on true relationships.

つまりhas_manyと同じようにアクセサを使えるけど、$related_resultsetなメソッドは使えないので下の例だとentries_rsなんてメソッドは使えないと。

package MT::Schema::Category;

use strict;

__PACKAGE__->has_many(
    placement => 'MT::Schema::Placement',
    'placement_category_id',
);
__PACKAGE__->many_to_many(
    entries => 'placement',
    'entry',
);

1;

ちなみに

$category->search_related('entries', {})

とか*_related関連メソッドも、そんなリレーション知らんと、怒られます。

なので、面倒だけど僕はmany-to-manyな関係を持つテーブルには

sub entries_rs { 
    my $rs = shift->entries->count
    return $rs;
}

なんてメソッドくっつけてます。

またはDBIx::Class::Relationship::ManyToManyをhackして

*{"${class}::${meth}_rs"} = sub {
  my $self = shift;

  my $rs = $self->${meth}(@_);
  return $rs;
};

ってメソッドをつけるのもありかもですね。

よくわからない表題ですが要は・・・

MyApp::Schema::TopicsとMyApp::Schema::Commentsが1:nの関係にあるとして

package MyApp::Schema::Topics;

use strict;

__PACKAGE__->has_many('comments' => 'MyApp::Schema::Comments');

1;

こんなアクションで

sub list : Local {
	my ( $self, $c ) = @_;

	my $topics = $c->model('Topics')->search({});
    $c->stash->{topics} = $topics;
    $c->stash->{template} = 'list.tt';
}

TTで素でやる場合

<html>
<body>
<ul>
[% WHILE (topic = topics.next) %]
    <li>
	[% topic.title %]
	: comments([% topic.comments.size ? topic.comments.size : 0 %])
    </li>
[% END %]
</ul>
</body>
</html>

とかするのかなぁと。

何を言いたいかというと、TTでhas_manyで定義した子オブジェクトの結果一覧を取得するメソッド(ここではcomments)にアクセスするとイテレーターではなく配列のリファレンスとして扱われるので大変面倒。

で、こうするといい感じ。

<html>
<body>
<ul>
[% WHILE (topic = topics.next) %]
    <li>
	[% topic.title %]
	: comments([% topic.comments_rs.count %])
    </li>
[% END %]
</ul>
</body>
</html>

search_rs同様、_rsをつけるだけで強制的にイテレーター(ResultSet)を返すことができる。
ぶっちゃけしらんかったです。

発行されるSQLもこんなに親切
SELECT COUNT( * ) FROM comments me WHERE ( me.topic_id = ? )

しかも、こんなこともできちゃう。

<html>
<body>
<ul>
[% WHILE (topic = topics.next) %]
    <li>[% topic.title %]</li>
	: comments([% topic.comments_rs.count %])
    <ul>
    [% SET comments = topic.comments_rs.search_rs({}{rows => 5}) %]
    [% WHILE (comment = comments.next) %]
    <li> [% comment.title %]</li>
    [% END %]
    </ul>
[% END %]
</ul>
</body>
</html>

とっても便利・・・かな。

事件は先週の中ごろに起こりました。

1ヶ月くらい前に今週の日曜日に行くつもりだった対横浜の阪神のチケットを取っていたので、確認しようと引っ張り出してきたところ

2007052001.jpg

・・・?

2007052002.jpg

甲子園?
三塁側アルプススタンド?

そうです。
横浜球場と思い込んで何も考えずにゲットしたのが甲子園のチケットだったのです。
横浜にはアルプススタンドないわな・・・

というわけで、急遽日曜日に周りからの罵倒と嘲笑をうけつつ行ってまいりました。
聖地巡礼弾丸ツアー。

2007052003.jpg

で、30年ぶりくらいに甲子園到着。

2007052004.jpg

阪神百貨店で買った、おニューのユニフォームで聖地参上。
横浜だと思いこんでいたので当然3塁側です。
でも、そこは甲子園。関係ありません。
360度見渡す限り阪神ファン。

2007052005.jpg

おっと。
青い人たちが警備員に守られながら閉じ込められていました。

2007052006.jpg

で、試合のほうは横浜銀行のお財布が大分ゆるくなってきたおかげか、土曜日の杉山の完封に続き完封勝利で三連勝。

2007052007.jpg

この日のヒーローは同級生の投打のヒーロー、「リン君」と「ヤッサン」。

林は果敢に突っ込んだライトライナーを後逸して迎えた大ピンチの汚名を晴らした先制決勝タイムリー。
これで12試合連続安打。完全に低位置をつかんでいますが、これで夏場を乗り越えれば将来は安泰です。

そしてとにかく素晴らしかったのが中村泰。
6回4被安打無失点9奪三振の素晴らしい成績。
初回、三回は三者連続三振。圧巻でした。
最近負け試合やJFKの前に投げるのを見てても内容がよかったのでやるかな、とは思ってたけど期待以上でした。

2007052008.jpg

中村は6回でお役ごめんでしたが789はJFKできっちり締めて、久々にBGM付の六甲おろしを熱唱。

時間的にも金銭的にもかなりハードでしたが、久々の甲子園に大満足でした。
またここに帰って来たいと思います。

DBICでTwitterのユーザー関係を表してみるってので、どえらい勘違いをしてました。

2007051801.gif

もごもごは
片想い: A
想われ: B
両想い: C
であってるのですが

Twitterでは
friends: A + C
followers: B + C

ですね。

なのでこのコードだと

もごもごの片想い: $user->favorite_users
もごもごの想われ: $user->follower_users
もごもごの両想い: $user->friend_users
Twitterのfriends: $user->link_users
Twitterのfollowers: $user->linked_users

で取得することになります。
単純なTwitter cloneを作る場合は普通にmany-to-manyでいけるってことです。

追記:
勘違いしてたので別エントリーで補足

Twitterで言うところのfavorites、followers、friends。
もごもごで言うところの片想い、想われ、両想いの関係をDBICで表してみました。

まず関係の定義から。

2007051601.gif

favorite(片想い):
 AがBをお気に入りに入れるとAから見てBはfavoriteな関係(片方向)
follower(想われ):
 Bから見てAはfollowerな関係(片方向)
friend(両想い):
 Aのお気に入りに入ってるBがAをお気に入りに入れると両方から見てfriendな関係(双方向)

で、テーブル設計ですが、それぞれをテーブルとして持ってもいいのですが、関係を追加するごとにあちこちのテーブルを見なきゃならんので、一個のテーブルで済ましてみました。

2007051602.gif

要は
user_linksテーブルを使ってusersを自己結合なmany-to-manyの関係にする。
user_links.user_idにはお気に入りに入れるusers.id
user_links.link_user_idにはお気に入りに入れられるusers.id

で、これをDBICのリレーションで表すと

MyApp/Schema.pm
package MyApp::Schema;

use strict;
use warnings;

use base qw/DBIx::Class::Schema::Loader/;

__PACKAGE__->loader_options(
    relationships => 1,
    debug         => 1,
);

1;
MyApp/Schema/UserLinks.pm
package MyApp::Schema::UserLinks;

use strict;

__PACKAGE__->belongs_to(
    'user' => 'MyApp::Schema::Users',
    'user_id'
);
__PACKAGE__->belongs_to(
    'link_user' => 'MyApp::Schema::Users',
    'link_user_id'
);

1;
MyApp/Schema/Users.pm
package MyApp::Schema::Users;

use strict;

__PACKAGE__->has_many(
    'user_link_users' => 'MyApp::Schema::UserLinks',
    'user_id'
);
__PACKAGE__->many_to_many(
    'link_users' => 'user_link_users',
    'link_user'
);
__PACKAGE__->has_many(
    'user_linked_users' => 'MyApp::Schema::UserLinks',
    'link_user_id'
);
__PACKAGE__->many_to_many(
    'linked_users' => 'user_linked_users',
    'user'
);

sub favorite_users {
    my ( $self, $cond, $attrs ) = @_;

    my $id = $self->id;
    my $sub_sql
        = "NOT IN (SELECT user_id FROM user_links WHERE link_user_id = $id)";

    return $self->link_users(
        {   'link_user_id' => \$sub_sql,
            %{ $cond || {} },
        },
        $attrs
    );
}

sub follower_users {
    my ( $self, $cond, $attrs ) = @_;

    my $id = $self->id;
    my $sub_sql
        = "NOT IN (SELECT link_user_id FROM user_links WHERE user_id = $id)";

    return $self->linked_users(
        {   'user_id' => \$sub_sql,
            %{ $cond || {} },
        },
        $attrs
    );
}

sub friend_users {
    my ( $self, $cond, $attrs ) = @_;

    my $id = $self->id;
    my $sub_sql
        = "IN (SELECT user_id FROM user_links WHERE link_user_id = $id)";

    return $self->link_users(
        {   'link_user_id' => \$sub_sql,
            %{ $cond || {} },
        },
        $attrs
    );
}

1;

重要なのはUsersクラスでメソッドは

$user->link_users
 自分がお気に入りに入れているユーザー全てを取得

$user->linked_users
 自分をお気に入りに入れているユーザー全て取得

これだけだとfriendな関係のユーザーも入ってしまうので別にメソッドを追加します。

$user->favorite_users
 link_usersで自分をお気に入りに入れていないユーザー

$user->follower_users
 linked_usersで自分がお気に入りに入れていないユーザー

$user->friend_users
 link_usersで自分をお気に入りに入れているユーザー

many-to-manyなリレーションを作ると
$user->add_to_link_users($user)
$user->add_to_linked_users($user)
のメソッドが自動的に作成されるので関係の追加にはこれを使うといいかも。

で、実際に使うにはこんな感じ

use strict;
use warnings;

use MyApp::Schema;

# userを3人作成
my $schema = MyApp::Schema->connect('dbi:SQLite:db/myapp.db');
for ( 0 .. 2 ) {
    $schema->resultset('Users')->create( { username => "user$_", } );
}

my @users = $schema->resultset('Users')->search( {} );
# user0とuser1はfriend
$users[0]->add_to_link_users( $users[1] );
$users[1]->add_to_link_users( $users[0] );
# user2はuser0のfavorite
# user0はuser2のfollower
$users[0]->add_to_link_users( $users[2] );

# 結果を表示
foreach  my $user ( @users ) {
    print $user->username;

    my $favorites = $user->favorite_users();
    print "\tfavarites:\n";
    while ( my $favorite = $favorites->next ) {
        print "\t\t" . $favorite->username . "\n";
    }

    my $followers = $user->follower_users;
    print "\tfollowers:\n";
    while ( my $follower = $followers->next ) {
        print "\t\t" . $follower->username . "\n";
    }

    my $friends = $user->friend_users;
    print "\tfriends:\n";
    while ( my $friend = $friends->next ) {
        print "\t\t" . $friend->username . "\n";
    }
}
結果はこんな感じ。
user0   favarites:
                user2
        followers:
        friends:
                user1
user1   favarites:
        followers:
        friends:
                user0
user2   favarites:
        followers:
                user0
        friends:

サブクエリを使うのが何ですが、結構お手軽かなと。

というわけで、日曜日も神宮球場に行ってきました。
金曜日の試合の帰りに球場で買ったチケットだったのですが、前から4列目でブルペンの投球練習が目の前というなかなかいい席。前売りでは3塁側は売り切れだったのにチケット販売ってどういう仕組みなんですかねぇ。

2007051301.jpg

この日の先発はジャンでしたが、1回に4点もらったものの3回でKO。
この調子だと2軍落ちかもしれないけど、代わりの先発はいるんだろうか・・・
全然関係ないけどジャン、ブルペンから汗かきすぎ。とても夏場を越えれるとは思えないです。

2007051302.jpg

打線は1回に今岡のタイムリーとアンディの久々のアーチで4点先制まではよかったけど、後はグライシンガーに抑えられて沈黙。中押しができないのが今の阪神打線。この辺どうにかしてもらいたいものです。

この日良かったのは、中継ぎの中村と橋本。特に橋本は金曜日も球が走ってるなぁと思ってたら、3者連続三振を含める完璧な内容。一時期はどうしてくれようかと思ってたけど、これだったら競った試合でも安心して見れます。

2007051303.jpg

試合は同点で迎えた9回に満塁から関本の決勝打、野口の走者一掃追加点が飛び出して最後は久保田がなんとかかんとか締めて4連勝。

2007051304.jpg

9連敗の借金返済にはまだまだですが、なんとかがんばって欲しいものです。

それにしても、去年から神宮で負け試合見てません。
そもそも今年は横浜銀行が渋いけど東京ヤクルト銀行は大盤振る舞い。
後半戦も是非見に行こう。

9連敗とか万年最下位のころを思い出させるような、とても懐かしい気分にさせてくれたタイガースです。
36年もファンをやってるので、むしろ久々に愚痴らせてもらって感謝したいくらいです。

・・・と強がってみるテスト。

今年は横浜銀行の財布の紐がとても硬いのですが、東京ヤクルト銀行がたくさん融資してくれそうです。
というわけで、金曜日に今年二回目の神宮球場に行ってまいりました。

2007051101.jpg

席はmixiの阪神コミュの方に譲ってもらったバックネット裏2階席1列目というなかなか良い席でした。
ただ、この日は風が強かったので猛烈に寒かったです。

2007051102.jpg

試合のほうは今岡の先制タイムリー、林の2ラン、続く金本の二者連続アーチ、最後はJFKで締めるというとても理想的な勝ち方でした。ま、5回に先発のボーグルソンが崩れるあたりも阪神らしかったですが。

2007051103.jpg

印象的だったのがヒーローインタビューの林が猛烈に日本語がうまかったこと。まぁ、高校から日本にいるので当たり前といえば当たり前なんですが、妙に感動しました。ついでに是非帰化していただきたい。

2007051104.jpg

で、試合終了後日曜日のチケットが販売されていたので、勢いで買ってしまいました。
今日も勝ったしこれから地道に借金返済に努めていただきたい次第です。

今さらですが今年のゴールデンウィークの記録。

3日はさいたまスタジアムにレッズ戦観戦。

4日は奥多摩の境渓谷にバーベキュー。

2007050401.jpg

2007050402.jpg

5日は横浜に散歩。

2007050501.jpg

2007050502.jpg

6日は渋谷でレコード買って、新宿でスパイダーマン3鑑賞。

全て近場だけど、かつてない充実ぶりに超満足でしたとさ。

2007050301.jpg

第7節のホームゲームでホーム25試合連続無敗記録がストップして以来のホームゲームだった浦和ですが、今日もいまいちでした。

前半、啓太の素晴らしい突破からワシントンがあわせて先制したのに、後半退場者を出して10人になった千葉に同点にされそのまま逃げ切られる始末。

とにかくシュートが少なかったです。後半の最後の方にようやく山田が遠目から打ったり、アーリークロスを入れるようになったけど、それ以外の時間はペナルティエリアの外で回してるだけでした。決定機にもボールが枠にいかなかったり、かなり深刻な決定力不足のようです。

2007050302.jpg

攻めの形がないのかなんだか知りませんが、相手が10人になったとたんにアタフタしてました。リアクションサッカーしかできないのか・・・って感じでした。

一方の千葉は水野が良かったです。基本的に坪井が左サイドで一人で対応していたのですが、スピードでは完全に負けていました。とにかく速いし、足元もうまいし、遠目から打ってくる積極性も素晴らしかったです。

試合終了後にはサポーターからブーイングを食らってましたが、あれはしょうがないかなと。

今後過密日程が続くこともあって、ちょっと不安になる内容でした。

しかも、かわいい女子二人!

この子と
2007050201.jpg

この子
2007050202.jpg

GWの間、予定がないので来週まで預かってるんですが、この二人性格が正反対でしかもあまり仲がよろしくないので、もう大変です。
2007050203.jpg

プロフィール

このアーカイブについて

このページには、2007年5月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2007年4月です。

次のアーカイブは2007年6月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。