4b1577c4f5eb257f77b12f6e0f50ffc547c48f39
[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 namespace::clean;
11
12 our %_pod_inherit_config =
13   (
14    class_map => { 'DBIx::Class::Relationship::BelongsTo' => 'DBIx::Class::Relationship' }
15   );
16
17 sub belongs_to {
18   my ($class, $rel, $f_class, $cond, $attrs) = @_;
19
20   # assume a foreign key constraint unless defined otherwise
21   $attrs->{is_foreign_key_constraint} = 1
22     if not exists $attrs->{is_foreign_key_constraint};
23   $attrs->{undef_on_null_fk} = 1
24     if not exists $attrs->{undef_on_null_fk};
25
26   # no join condition or just a column name
27   if (!ref $cond) {
28
29     my ($f_key, $guess);
30     if (defined $cond and length $cond) {
31       $f_key = $cond;
32       $guess = "caller specified foreign key '$f_key'";
33     }
34     else {
35       $f_key = $rel;
36       $guess = "using given relationship name '$rel' as foreign key column name";
37     }
38
39     $class->throw_exception(
40       "No such column '$f_key' declared yet on ${class} ($guess)"
41     )  unless $class->has_column($f_key);
42
43     $class->ensure_class_loaded($f_class);
44     my $f_rsrc = try {
45       $f_class->result_source_instance;
46     }
47     catch {
48       $class->throw_exception(
49         "Foreign class '$f_class' does not seem to be a Result class "
50       . "(or it simply did not load entirely due to a circular relation chain)"
51       );
52     };
53
54     my $pri = $f_rsrc->_single_pri_col_or_die;
55
56     $cond = { "foreign.${pri}" => "self.${f_key}" };
57
58   }
59   # explicit join condition
60   else {
61     if (ref $cond eq 'HASH') { # ARRAY is also valid
62       my $cond_rel;
63       for (keys %$cond) {
64         if (m/\./) { # Explicit join condition
65           $cond_rel = $cond;
66           last;
67         }
68         $cond_rel->{"foreign.$_"} = "self.".$cond->{$_};
69       }
70       $cond = $cond_rel;
71     }
72   }
73
74   my $acc_type = (
75     ref $cond eq 'HASH'
76       and
77     keys %$cond == 1
78       and
79     (keys %$cond)[0] =~ /^foreign\./
80       and
81     $class->has_column($rel)
82   ) ? 'filter' : 'single';
83
84   my $fk_columns = ($acc_type eq 'single' and ref $cond eq 'HASH')
85     ? { map { $_ =~ /^self\.(.+)/ ? ( $1 => 1 ) : () } (values %$cond ) }
86     : undef
87   ;
88
89   $class->add_relationship($rel, $f_class,
90     $cond,
91     {
92       is_depends_on => 1,
93       accessor => $acc_type,
94       $fk_columns ? ( fk_columns => $fk_columns ) : (),
95       %{$attrs || {}}
96     }
97   );
98
99   return 1;
100 }
101
102 # Attempt to remove the POD so it (maybe) falls off the indexer
103
104 #=head1 AUTHORS
105 #
106 #Alexander Hartmaier <Alexander.Hartmaier@t-systems.at>
107 #
108 #Matt S. Trout <mst@shadowcatsystems.co.uk>
109 #
110 #=cut
111
112 1;