Add search_rs to ResultSet and a new {$rel}_rs accessor to has_many.
[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
5b89a768 178 @objects = $rs->search_related('relname', $cond, $attrs);
179 $objects_rs = $rs->search_related('relname', $cond, $attrs);
30236e47 180
181Run a search on a related resultset. The search will be restricted to the
182item or items represented by the L<DBIx::Class::ResultSet> it was called
183upon. This method can be called on a ResultSet, a Row or a ResultSource class.
503536d5 184
185=cut
186
55e2d745 187sub search_related {
ff7bb7a1 188 return shift->related_resultset(shift)->search(@_);
b52e9bf8 189}
190
5b89a768 191=head2 search_related_rs
192
193 ( $objects_rs ) = $rs->search_related_rs('relname', $cond, $attrs);
194
195This method works exactly the same as search_related_rs, except that
196it garauntees that it will return a restultset even in list context.
197
198=cut
199
200sub search_related_rs {
201 return shift->related_resultset(shift)->search_rs(@_);
202}
203
b52e9bf8 204=head2 count_related
205
7be93b07 206 $obj->count_related('relname', $cond, $attrs);
b52e9bf8 207
bc0c9800 208Returns the count of all the items in the related resultset, restricted by the
209current item or where conditions. Can be called on a
27f01d1f 210L<DBIx::Class::Manual::Glossary/"ResultSet"> or a
bc0c9800 211L<DBIx::Class::Manual::Glossary/"Row"> object.
30236e47 212
b52e9bf8 213=cut
214
215sub count_related {
216 my $self = shift;
217 return $self->search_related(@_)->count;
55e2d745 218}
219
30236e47 220=head2 new_related
221
222 my $new_obj = $obj->new_related('relname', \%col_data);
223
224Create a new item of the related foreign class. If called on a
27f01d1f 225L<DBIx::Class::Manual::Glossary/"Row"> object, it will magically set any
226primary key values into foreign key columns for you. The newly created item
227will not be saved into your storage until you call L<DBIx::Class::Row/insert>
30236e47 228on it.
229
230=cut
231
232sub new_related {
233 my ($self, $rel, $values, $attrs) = @_;
234 return $self->search_related($rel)->new($values, $attrs);
235}
236
8091aa91 237=head2 create_related
503536d5 238
30236e47 239 my $new_obj = $obj->create_related('relname', \%col_data);
240
241Creates a new item, similarly to new_related, and also inserts the item's data
242into your storage medium. See the distinction between C<create> and C<new>
243in L<DBIx::Class::ResultSet> for details.
503536d5 244
245=cut
246
55e2d745 247sub create_related {
3842b955 248 my $self = shift;
fea3d045 249 my $rel = shift;
64acc2bc 250 my $obj = $self->search_related($rel)->create(@_);
251 delete $self->{related_resultsets}->{$rel};
252 return $obj;
55e2d745 253}
254
8091aa91 255=head2 find_related
503536d5 256
30236e47 257 my $found_item = $obj->find_related('relname', @pri_vals | \%pri_vals);
258
259Attempt to find a related object using its primary key or unique constraints.
27f01d1f 260See L<DBIx::Class::ResultSet/find> for details.
503536d5 261
262=cut
263
1a14aa3f 264sub find_related {
265 my $self = shift;
266 my $rel = shift;
716b3d29 267 return $self->search_related($rel)->find(@_);
1a14aa3f 268}
269
b3e1f1f5 270=head2 find_or_new_related
271
272 my $new_obj = $obj->find_or_new_related('relname', \%col_data);
273
274Find an item of a related class. If none exists, instantiate a new item of the
275related class. The object will not be saved into your storage until you call
276L<DBIx::Class::Row/insert> on it.
277
278=cut
279
280sub find_or_new_related {
281 my $self = shift;
282 return $self->find_related(@_) || $self->new_related(@_);
283}
284
8091aa91 285=head2 find_or_create_related
503536d5 286
30236e47 287 my $new_obj = $obj->find_or_create_related('relname', \%col_data);
288
27f01d1f 289Find or create an item of a related class. See
b3e1f1f5 290L<DBIx::Class::ResultSet/find_or_create> for details.
503536d5 291
292=cut
293
55e2d745 294sub find_or_create_related {
295 my $self = shift;
1a14aa3f 296 return $self->find_related(@_) || $self->create_related(@_);
55e2d745 297}
298
045120e6 299=head2 update_or_create_related
300
301 my $updated_item = $obj->update_or_create_related('relname', \%col_data, \%attrs?);
302
303Update or create an item of a related class. See
f7e1846f 304L<DBIx::Class::ResultSet/update_or_create> for details.
045120e6 305
306=cut
307
308sub update_or_create_related {
309 my $self = shift;
310 my $rel = shift;
311 return $self->related_resultset($rel)->update_or_create(@_);
312}
313
8091aa91 314=head2 set_from_related
503536d5 315
30236e47 316 $book->set_from_related('author', $author_obj);
317
318Set column values on the current object, using related values from the given
319related object. This is used to associate previously separate objects, for
320example, to set the correct author for a book, find the Author object, then
321call set_from_related on the book.
322
27f01d1f 323The columns are only set in the local copy of the object, call L</update> to
324set them in the storage.
503536d5 325
326=cut
327
55e2d745 328sub set_from_related {
329 my ($self, $rel, $f_obj) = @_;
4685e006 330 my $rel_obj = $self->relationship_info($rel);
701da8c4 331 $self->throw_exception( "No such relationship ${rel}" ) unless $rel_obj;
55e2d745 332 my $cond = $rel_obj->{cond};
bc0c9800 333 $self->throw_exception(
334 "set_from_related can only handle a hash condition; the ".
335 "condition for $rel is of type ".
336 (ref $cond ? ref $cond : 'plain scalar')
337 ) unless ref $cond eq 'HASH';
2c037e6b 338 if (defined $f_obj) {
339 my $f_class = $self->result_source->schema->class($rel_obj->{class});
340 $self->throw_exception( "Object $f_obj isn't a ".$f_class )
341 unless $f_obj->isa($f_class);
342 }
fde6e28e 343 $self->set_columns(
344 $self->result_source->resolve_condition(
345 $rel_obj->{cond}, $f_obj, $rel));
55e2d745 346 return 1;
347}
348
8091aa91 349=head2 update_from_related
503536d5 350
30236e47 351 $book->update_from_related('author', $author_obj);
352
27f01d1f 353The same as L</"set_from_related">, but the changes are immediately updated
354in storage.
503536d5 355
356=cut
357
55e2d745 358sub update_from_related {
359 my $self = shift;
360 $self->set_from_related(@_);
361 $self->update;
362}
363
8091aa91 364=head2 delete_related
503536d5 365
30236e47 366 $obj->delete_related('relname', $cond, $attrs);
367
368Delete any related item subject to the given conditions.
503536d5 369
370=cut
371
55e2d745 372sub delete_related {
373 my $self = shift;
64acc2bc 374 my $obj = $self->search_related(@_)->delete;
375 delete $self->{related_resultsets}->{$_[0]};
376 return $obj;
55e2d745 377}
378
3791;
380
55e2d745 381=head1 AUTHORS
382
daec44b8 383Matt S. Trout <mst@shadowcatsystems.co.uk>
55e2d745 384
385=head1 LICENSE
386
387You may distribute this code under the same terms as Perl itself.
388
389=cut
390