fixup for stringify that can be false in find_or_create_related
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Relationship / Base.pm
CommitLineData
55e2d745 1package DBIx::Class::Relationship::Base;
2
3use strict;
4use warnings;
5
1edd1722 6use base qw/DBIx::Class/;
55e2d745 7
75d07914 8=head1 NAME
55e2d745 9
8918977e 10DBIx::Class::Relationship::Base - Inter-table relationships
55e2d745 11
12=head1 SYNOPSIS
13
14=head1 DESCRIPTION
15
30236e47 16This class provides methods to describe the relationships between the
17tables in your database model. These are the "bare bones" relationships
75d07914 18methods, for predefined ones, look in L<DBIx::Class::Relationship>.
55e2d745 19
20=head1 METHODS
21
8091aa91 22=head2 add_relationship
503536d5 23
27f01d1f 24=over 4
25
ebc77b53 26=item Arguments: 'relname', 'Foreign::Class', $cond, $attrs
27f01d1f 27
28=back
30236e47 29
503536d5 30 __PACKAGE__->add_relationship('relname', 'Foreign::Class', $cond, $attrs);
31
5271499d 32The condition needs to be an L<SQL::Abstract>-style representation of the
33join between the tables. When resolving the condition for use in a C<JOIN>,
34keys using the pseudo-table C<foreign> are resolved to mean "the Table on the
35other side of the relationship", and values using the pseudo-table C<self>
30236e47 36are resolved to mean "the Table this class is representing". Other
37restrictions, such as by value, sub-select and other tables, may also be
5271499d 38used. Please check your database for C<JOIN> parameter support.
30236e47 39
5271499d 40For example, if you're creating a relationship from C<Author> to C<Book>, where
41the C<Book> table has a column C<author_id> containing the ID of the C<Author>
42row:
503536d5 43
30236e47 44 { 'foreign.author_id' => 'self.id' }
503536d5 45
5271499d 46will result in the C<JOIN> clause
503536d5 47
5271499d 48 author me JOIN book book ON book.author_id = me.id
503536d5 49
5271499d 50For multi-column foreign keys, you will need to specify a C<foreign>-to-C<self>
51mapping for each column in the key. For example, if you're creating a
52relationship from C<Book> to C<Edition>, where the C<Edition> table refers to a
53publisher and a type (e.g. "paperback"):
54
55 {
781102cd 56 'foreign.publisher_id' => 'self.publisher_id',
5271499d 57 'foreign.type_id' => 'self.type_id',
58 }
59
60This will result in the C<JOIN> clause:
61
62 book me JOIN edition edition ON edition.publisher_id = me.publisher_id
63 AND edition.type_id = me.type_id
64
65Each key-value pair provided in a hashref will be used as C<AND>ed conditions.
66To add an C<OR>ed condition, use an arrayref of hashrefs. See the
67L<SQL::Abstract> documentation for more details.
8091aa91 68
69Valid attributes are as follows:
70
71=over 4
72
73=item join_type
74
75Explicitly specifies the type of join to use in the relationship. Any SQL
76join type is valid, e.g. C<LEFT> or C<RIGHT>. It will be placed in the SQL
77command immediately before C<JOIN>.
78
79=item proxy
80
30236e47 81An arrayref containing a list of accessors in the foreign class to create in
8091aa91 82the main class. If, for example, you do the following:
83
27f01d1f 84 MyDB::Schema::CD->might_have(liner_notes => 'MyDB::Schema::LinerNotes',
85 undef, {
86 proxy => [ qw/notes/ ],
87 });
8091aa91 88
30236e47 89Then, assuming MyDB::Schema::LinerNotes has an accessor named notes, you can do:
8091aa91 90
30236e47 91 my $cd = MyDB::Schema::CD->find(1);
92 $cd->notes('Notes go here'); # set notes -- LinerNotes object is
93 # created if it doesn't exist
8091aa91 94
95=item accessor
96
97Specifies the type of accessor that should be created for the relationship.
98Valid values are C<single> (for when there is only a single related object),
99C<multi> (when there can be many), and C<filter> (for when there is a single
100related object, but you also want the relationship accessor to double as
101a column accessor). For C<multi> accessors, an add_to_* method is also
102created, which calls C<create_related> for the relationship.
103
104=back
105
87c4e602 106=head2 register_relationship
107
27f01d1f 108=over 4
109
ebc77b53 110=item Arguments: $relname, $rel_info
27f01d1f 111
112=back
71e65b39 113
30236e47 114Registers a relationship on the class. This is called internally by
71f9df37 115DBIx::Class::ResultSourceProxy to set up Accessors and Proxies.
71e65b39 116
55e2d745 117=cut
118
71e65b39 119sub register_relationship { }
120
27f01d1f 121=head2 related_resultset
122
123=over 4
124
ebc77b53 125=item Arguments: $relationship_name
27f01d1f 126
d601dc88 127=item Return Value: $related_resultset
27f01d1f 128
129=back
30236e47 130
27f01d1f 131 $rs = $cd->related_resultset('artist');
30236e47 132
27f01d1f 133Returns a L<DBIx::Class::ResultSet> for the relationship named
134$relationship_name.
30236e47 135
136=cut
137
138sub related_resultset {
139 my $self = shift;
bc0c9800 140 $self->throw_exception("Can't call *_related as class methods")
141 unless ref $self;
30236e47 142 my $rel = shift;
143 my $rel_obj = $self->relationship_info($rel);
bc0c9800 144 $self->throw_exception( "No such relationship ${rel}" )
145 unless $rel_obj;
30236e47 146
147 return $self->{related_resultsets}{$rel} ||= do {
148 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
149 $attrs = { %{$rel_obj->{attrs} || {}}, %$attrs };
150
bc0c9800 151 $self->throw_exception( "Invalid query: @_" )
152 if (@_ > 1 && (@_ % 2 == 1));
30236e47 153 my $query = ((@_ > 1) ? {@_} : shift);
154
bc0c9800 155 my $cond = $self->result_source->resolve_condition(
156 $rel_obj->{cond}, $rel, $self
157 );
30236e47 158 if (ref $cond eq 'ARRAY') {
159 $cond = [ map { my $hash;
160 foreach my $key (keys %$_) {
161 my $newkey = $key =~ /\./ ? "me.$key" : $key;
162 $hash->{$newkey} = $_->{$key};
163 }; $hash } @$cond ];
164 } else {
165 foreach my $key (grep { ! /\./ } keys %$cond) {
166 $cond->{"me.$key"} = delete $cond->{$key};
167 }
168 }
169 $query = ($query ? { '-and' => [ $cond, $query ] } : $cond);
bc0c9800 170 $self->result_source->related_source($rel)->resultset->search(
171 $query, $attrs
172 );
30236e47 173 };
174}
175
8091aa91 176=head2 search_related
503536d5 177
30236e47 178 $rs->search_related('relname', $cond, $attrs);
179
180Run a search on a related resultset. The search will be restricted to the
181item or items represented by the L<DBIx::Class::ResultSet> it was called
182upon. This method can be called on a ResultSet, a Row or a ResultSource class.
503536d5 183
184=cut
185
55e2d745 186sub search_related {
ff7bb7a1 187 return shift->related_resultset(shift)->search(@_);
b52e9bf8 188}
189
190=head2 count_related
191
7be93b07 192 $obj->count_related('relname', $cond, $attrs);
b52e9bf8 193
bc0c9800 194Returns the count of all the items in the related resultset, restricted by the
195current item or where conditions. Can be called on a
27f01d1f 196L<DBIx::Class::Manual::Glossary/"ResultSet"> or a
bc0c9800 197L<DBIx::Class::Manual::Glossary/"Row"> object.
30236e47 198
b52e9bf8 199=cut
200
201sub count_related {
202 my $self = shift;
203 return $self->search_related(@_)->count;
55e2d745 204}
205
30236e47 206=head2 new_related
207
208 my $new_obj = $obj->new_related('relname', \%col_data);
209
210Create a new item of the related foreign class. If called on a
27f01d1f 211L<DBIx::Class::Manual::Glossary/"Row"> object, it will magically set any
212primary key values into foreign key columns for you. The newly created item
213will not be saved into your storage until you call L<DBIx::Class::Row/insert>
30236e47 214on it.
215
216=cut
217
218sub new_related {
219 my ($self, $rel, $values, $attrs) = @_;
220 return $self->search_related($rel)->new($values, $attrs);
221}
222
8091aa91 223=head2 create_related
503536d5 224
30236e47 225 my $new_obj = $obj->create_related('relname', \%col_data);
226
227Creates a new item, similarly to new_related, and also inserts the item's data
228into your storage medium. See the distinction between C<create> and C<new>
229in L<DBIx::Class::ResultSet> for details.
503536d5 230
231=cut
232
55e2d745 233sub create_related {
3842b955 234 my $self = shift;
fea3d045 235 my $rel = shift;
64acc2bc 236 my $obj = $self->search_related($rel)->create(@_);
237 delete $self->{related_resultsets}->{$rel};
238 return $obj;
55e2d745 239}
240
8091aa91 241=head2 find_related
503536d5 242
30236e47 243 my $found_item = $obj->find_related('relname', @pri_vals | \%pri_vals);
244
245Attempt to find a related object using its primary key or unique constraints.
27f01d1f 246See L<DBIx::Class::ResultSet/find> for details.
503536d5 247
248=cut
249
1a14aa3f 250sub find_related {
251 my $self = shift;
252 my $rel = shift;
716b3d29 253 return $self->search_related($rel)->find(@_);
1a14aa3f 254}
255
8091aa91 256=head2 find_or_create_related
503536d5 257
30236e47 258 my $new_obj = $obj->find_or_create_related('relname', \%col_data);
259
27f01d1f 260Find or create an item of a related class. See
261L<DBIx::Class::ResultSet/"find_or_create"> for details.
503536d5 262
263=cut
264
55e2d745 265sub find_or_create_related {
266 my $self = shift;
9c2c91ea 267 my $obj = $self->find_related(@_);
268 return (defined($obj) ? $obj : $self->create_related(@_));
55e2d745 269}
270
8091aa91 271=head2 set_from_related
503536d5 272
30236e47 273 $book->set_from_related('author', $author_obj);
274
275Set column values on the current object, using related values from the given
276related object. This is used to associate previously separate objects, for
277example, to set the correct author for a book, find the Author object, then
278call set_from_related on the book.
279
27f01d1f 280The columns are only set in the local copy of the object, call L</update> to
281set them in the storage.
503536d5 282
283=cut
284
55e2d745 285sub set_from_related {
286 my ($self, $rel, $f_obj) = @_;
4685e006 287 my $rel_obj = $self->relationship_info($rel);
701da8c4 288 $self->throw_exception( "No such relationship ${rel}" ) unless $rel_obj;
55e2d745 289 my $cond = $rel_obj->{cond};
bc0c9800 290 $self->throw_exception(
291 "set_from_related can only handle a hash condition; the ".
292 "condition for $rel is of type ".
293 (ref $cond ? ref $cond : 'plain scalar')
294 ) unless ref $cond eq 'HASH';
2c037e6b 295 if (defined $f_obj) {
296 my $f_class = $self->result_source->schema->class($rel_obj->{class});
297 $self->throw_exception( "Object $f_obj isn't a ".$f_class )
298 unless $f_obj->isa($f_class);
299 }
fde6e28e 300 $self->set_columns(
301 $self->result_source->resolve_condition(
302 $rel_obj->{cond}, $f_obj, $rel));
55e2d745 303 return 1;
304}
305
8091aa91 306=head2 update_from_related
503536d5 307
30236e47 308 $book->update_from_related('author', $author_obj);
309
27f01d1f 310The same as L</"set_from_related">, but the changes are immediately updated
311in storage.
503536d5 312
313=cut
314
55e2d745 315sub update_from_related {
316 my $self = shift;
317 $self->set_from_related(@_);
318 $self->update;
319}
320
8091aa91 321=head2 delete_related
503536d5 322
30236e47 323 $obj->delete_related('relname', $cond, $attrs);
324
325Delete any related item subject to the given conditions.
503536d5 326
327=cut
328
55e2d745 329sub delete_related {
330 my $self = shift;
64acc2bc 331 my $obj = $self->search_related(@_)->delete;
332 delete $self->{related_resultsets}->{$_[0]};
333 return $obj;
55e2d745 334}
335
3361;
337
55e2d745 338=head1 AUTHORS
339
daec44b8 340Matt S. Trout <mst@shadowcatsystems.co.uk>
55e2d745 341
342=head1 LICENSE
343
344You may distribute this code under the same terms as Perl itself.
345
346=cut
347