独自のリレーション処理を行うにはどーすんの

MoFedge::Data::DBIC::Schema::Loaderみたいな処理をCatalystから扱えるようにするにはどうしたらよいか悩んでます。

例としてMoFedge::Data::DBIC::Schema::Loaderをちょっと書き換えたHoge::DBIC::Schema::Loaderを用意します。

package Hoge::DBIC::Schema::Loader;
use strict;
use warnings;
use base qw/DBIx::Class::Schema::Loader/;

use UNIVERSAL::require;
use Switch;
use Lingua::EN::Inflect;

sub setup_source {
    my $class = shift;

    for my $source_moniker ($class->sources) {

        my $source = $class->class($source_moniker);

        my @ordered_sources = $class->_ordered_sources;
        for my $column ( $source->columns ) {

            # 本来は独自リレーション処理をここに書く

        }
    }
}

sub _auto_relationship {
    my ($class, $ordered_sources, $source, $column, $column_head) = @_;

    for my $foreign_source (@$ordered_sources) {
        if ($column_head =~ $foreign_source->table) {

            $source->belongs_to($column, $foreign_source);

            # $self->user_id => $self->user
            no strict 'refs'; ## no critic
            *{"$source\::$column_head"} = *{"$source\::$column"};

            $foreign_source->has_many(Lingua::EN::Inflect::PL($source->table), $source, $column);

            last;
        }
    }
}

# sort sources order by table name length.
sub _ordered_sources {
    my $class = shift;

    return          map  { $_->[0] }
            reverse sort { $a->[1] <=> $b->[1] }
                    map  { [ $_, length($_->table)] }
                    map  { $class->class($_) }
                         $class->sources;
}

1;

# ↑ほぼ完全にMoFedge::Data::DBIC::Schema::Loaderのコピペだけど例ということで

setup_sourceメソッドでやってる処理ってコネクトした後に行うものなんだけどそれをどうやってCatalystから呼ばせるかがちょっとわかんないす。

実際にコネクトされるのはCatalyst::Model::DBIC::Schemaのnew内なのでそれが終わったあとにsetup_sourceが呼ばれるようにすればOKなんだけど、外側から制御できないっぽいので派生した独自のCatalyst::Modelを作らないといけないのかな?

package Hoge::Catalyst::Model::DBIC::Schema;

use strict;
use warnings;

use base qw/Catalyst::Model::DBIC::Schema/;

sub new {
    my $self = shift->NEXT::new(@_);

    $self->schema->setup_source(); # コネクト終わってるはずなので呼ぶ
}

1;

MyAppクラスの設定は以下

package MyApp::Schema;

use strict;
use base qw/Hoge::DBIC::Schema::Loader/;

__PACKAGE__->loader_options(
    #relationships => 1,
    #debug => 1,
);
package MyApp::Model::DBIC;

use strict;
use base 'Hoge::Catalyst::Model::DBIC::Schema'; # Hogeの方を使うようにする

__PACKAGE__->config(
    schema_class => 'MyApp::Schema',
    connect_info => [
        'dbi:mysql:dbname=testdb',
        'user',
        'pass',
        
    ],
);

コレで実行・・・。

うごかねぇ・・・orz

resultsetが見つからんとかエラーになる。

ってことで別のやり方を模索。

最終的にはconnectionメソッドが呼ばれるんだからオーバーライドしちゃえばどう?と。

ってことでMyApp::Schemaでconnectionをオーバーライドする。

package MyApp::Schema;

use strict;
use base qw/Hoge::DBIC::Schema::Loader/;

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

our $SETUP_SOURCE_FLAG = 0;

sub connection {
    my $proto = shift;
    $proto->next::method(@_);
    if ( !$SETUP_SOURCE_FLAG ) { # 念のため一度しか呼ばれないようにする。
        $proto->setup_source;
        $SETUP_SOURCE_FLAG = 1;
    }
}

コレで実行するとうまくいった。

けど・・・・。

こんなんでいいのか・・・?