Centralize all user-side rsrc calls to go through result_source()
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Relationship / BelongsTo.pm
1 package # hide from PAUSE
2     DBIx::Class::Relationship::BelongsTo;
3
4 # Documentation for these methods can be found in
5 # DBIx::Class::Relationship
6
7 use strict;
8 use warnings;
9 use Try::Tiny;
10 use DBIx::Class::_Util 'dbic_internal_try';
11 use namespace::clean;
12
13 our %_pod_inherit_config =
14   (
15    class_map => { 'DBIx::Class::Relationship::BelongsTo' => 'DBIx::Class::Relationship' }
16   );
17
18 sub belongs_to {
19   my ($class, $rel, $f_class, $cond, $attrs) = @_;
20
21   # assume a foreign key constraint unless defined otherwise
22   $attrs->{is_foreign_key_constraint} = 1
23     if not exists $attrs->{is_foreign_key_constraint};
24   $attrs->{undef_on_null_fk} = 1
25     if not exists $attrs->{undef_on_null_fk};
26
27   # no join condition or just a column name
28   if (!ref $cond) {
29
30     my ($f_key, $guess);
31     if (defined $cond and length $cond) {
32       $f_key = $cond;
33       $guess = "caller specified foreign key '$f_key'";
34     }
35     else {
36       $f_key = $rel;
37       $guess = "using given relationship name '$rel' as foreign key column name";
38     }
39
40     $class->throw_exception(
41       "No such column '$f_key' declared yet on ${class} ($guess)"
42     )  unless $class->result_source->has_column($f_key);
43
44     $class->ensure_class_loaded($f_class);
45     my $f_rsrc = dbic_internal_try {
46       $f_class->result_source;
47     }
48     catch {
49       $class->throw_exception(
50         "Foreign class '$f_class' does not seem to be a Result class "
51       . "(or it simply did not load entirely due to a circular relation chain): $_"
52       );
53     };
54
55     my $pri = $f_rsrc->_single_pri_col_or_die;
56
57     $cond = { "foreign.${pri}" => "self.${f_key}" };
58
59   }
60   # explicit join condition
61   else {
62     if (ref $cond eq 'HASH') { # ARRAY is also valid
63       my $cond_rel;
64       # FIXME This loop is ridiculously incomplete and dangerous
65       # staving off changes until implmentation of the swindon consensus
66       for (keys %$cond) {
67         if (m/\./) { # Explicit join condition
68           $cond_rel = $cond;
69           last;
70         }
71         $cond_rel->{"foreign.$_"} = "self.".$cond->{$_};
72       }
73       $cond = $cond_rel;
74     }
75   }
76
77   my $acc_type = (
78     ref $cond eq 'HASH'
79       and
80     keys %$cond == 1
81       and
82     (keys %$cond)[0] =~ /^foreign\./
83       and
84     $class->result_source->has_column($rel)
85   ) ? 'filter' : 'single';
86
87   my $fk_columns = ($acc_type eq 'single' and ref $cond eq 'HASH')
88     ? { map { $_ =~ /^self\.(.+)/ ? ( $1 => 1 ) : () } (values %$cond ) }
89     : undef
90   ;
91
92   $class->add_relationship($rel, $f_class,
93     $cond,
94     {
95       is_depends_on => 1,
96       accessor => $acc_type,
97       $fk_columns ? ( fk_columns => $fk_columns ) : (),
98       %{$attrs || {}}
99     }
100   );
101
102   return 1;
103 }
104
105 1;