1 package DBIx::Class::Schema::Loader::RelBuilder;
5 use Carp::Clan qw/^DBIx::Class/;
6 use Lingua::EN::Inflect::Number ();
8 our $VERSION = '0.03999_01';
12 DBIx::Class::Schema::Loader::RelBuilder - Builds relationships for DBIx::Class::Schema::Loader
16 See L<DBIx::Class::Schema::Loader>
20 This class builds relationships for L<DBIx::Class::Schema::Loader>. This
21 is module is not (yet) for external use.
27 Arguments: schema_class (scalar), inflect_plural, inflect_singular
29 C<$schema_class> should be a schema class name, where the source
30 classes have already been set up and registered. Column info, primary
31 key, and unique constraints will be drawn from this schema for all
32 of the existing source monikers.
34 Options inflect_plural and inflect_singular are optional, and are better documented
35 in L<DBIx::Class::Schema::Loader::Base>.
39 Arguments: local_moniker (scalar), fk_info (arrayref)
41 This generates the code for the relationships of a given table.
43 C<local_moniker> is the moniker name of the table which had the REFERENCES
44 statements. The fk_info arrayref's contents should take the form:
48 local_columns => [ 'col2', 'col3' ],
49 remote_columns => [ 'col5', 'col7' ],
50 remote_moniker => 'AnotherTableMoniker',
53 local_columns => [ 'col1', 'col4' ],
54 remote_columns => [ 'col1', 'col2' ],
55 remote_moniker => 'YetAnotherTableMoniker',
60 This method will return the generated relationships as a hashref keyed on the
61 class names. The values are arrayrefs of hashes containing method name and
65 'Some::Source::Class' => [
66 { method => 'belongs_to', arguments => [ 'col1', 'AnotherTableMoniker' ],
67 { method => 'has_many', arguments => [ 'anothers', 'AnotherTableMoniker', 'col15' ],
69 'Another::Source::Class' => [
78 my ( $class, $schema, $inflect_pl, $inflect_singular ) = @_;
82 inflect_plural => $inflect_pl,
83 inflect_singular => $inflect_singular,
86 bless $self => $class;
92 # pluralize a relationship name
94 my ($self, $relname) = @_;
96 if( ref $self->{inflect_plural} eq 'HASH' ) {
97 return $self->{inflect_plural}->{$relname}
98 if exists $self->{inflect_plural}->{$relname};
100 elsif( ref $self->{inflect_plural} eq 'CODE' ) {
101 my $inflected = $self->{inflect_plural}->($relname);
102 return $inflected if $inflected;
105 return Lingua::EN::Inflect::Number::to_PL($relname);
108 # Singularize a relationship name
109 sub _inflect_singular {
110 my ($self, $relname) = @_;
112 if( ref $self->{inflect_singular} eq 'HASH' ) {
113 return $self->{inflect_singular}->{$relname}
114 if exists $self->{inflect_singular}->{$relname};
116 elsif( ref $self->{inflect_singular} eq 'CODE' ) {
117 my $inflected = $self->{inflect_singular}->($relname);
118 return $inflected if $inflected;
121 return Lingua::EN::Inflect::Number::to_S($relname);
125 my ($self, $local_moniker, $rels) = @_;
129 my $local_table = $self->{schema}->source($local_moniker)->from;
130 my $local_class = $self->{schema}->class($local_moniker);
133 foreach my $rel (@$rels) {
134 next if !$rel->{remote_source};
135 $counters{$rel->{remote_source}}++;
138 foreach my $rel (@$rels) {
139 next if !$rel->{remote_source};
140 my $local_cols = $rel->{local_columns};
141 my $remote_cols = $rel->{remote_columns};
142 my $remote_moniker = $rel->{remote_source};
143 my $remote_obj = $self->{schema}->source($remote_moniker);
144 my $remote_class = $self->{schema}->class($remote_moniker);
145 my $remote_table = $remote_obj->from;
146 $remote_cols ||= [ $remote_obj->primary_columns ];
148 if($#$local_cols != $#$remote_cols) {
149 croak "Column count mismatch: $local_moniker (@$local_cols) "
150 . "$remote_moniker (@$remote_cols)";
154 foreach my $i (0 .. $#$local_cols) {
155 $cond{$remote_cols->[$i]} = $local_cols->[$i];
158 # If more than one rel between this pair of tables, use the
159 # local col name(s) as the relname in the foreign source, instead
160 # of the local table name.
162 if($counters{$remote_moniker} > 1) {
163 $local_relname = $self->_inflect_plural(
164 lc($local_table) . q{_} . join(q{_}, @$local_cols)
167 $local_relname = $self->_inflect_plural(lc $local_table);
170 # for single-column case, set the relname to the column name,
171 # to make filter accessors work
173 if(scalar keys %cond == 1) {
174 my ($col) = keys %cond;
175 $remote_relname = $self->_inflect_singular($cond{$col});
178 $remote_relname = $self->_inflect_singular(lc $remote_table);
181 my %rev_cond = reverse %cond;
183 for (keys %rev_cond) {
184 $rev_cond{"foreign.$_"} = "self.".$rev_cond{$_};
185 delete $rev_cond{$_};
188 push(@{$all_code->{$local_class}},
189 { method => 'belongs_to',
190 args => [ $remote_relname,
197 push(@{$all_code->{$remote_class}},
198 { method => 'has_many',
199 args => [ $local_relname,