allow add_fk_index param to be specified in rel def
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Relationship / Base.pm
1 package DBIx::Class::Relationship::Base;
2
3 use strict;
4 use warnings;
5
6 use Scalar::Util ();
7 use base qw/DBIx::Class/;
8
9 =head1 NAME
10
11 DBIx::Class::Relationship::Base - Inter-table relationships
12
13 =head1 SYNOPSIS
14
15 =head1 DESCRIPTION
16
17 This class provides methods to describe the relationships between the
18 tables in your database model. These are the "bare bones" relationships
19 methods, for predefined ones, look in L<DBIx::Class::Relationship>.
20
21 =head1 METHODS
22
23 =head2 add_relationship
24
25 =over 4
26
27 =item Arguments: 'relname', 'Foreign::Class', $cond, $attrs
28
29 =back
30
31   __PACKAGE__->add_relationship('relname', 'Foreign::Class', $cond, $attrs);
32
33 The condition needs to be an L<SQL::Abstract>-style representation of the
34 join between the tables. When resolving the condition for use in a C<JOIN>,
35 keys using the pseudo-table C<foreign> are resolved to mean "the Table on the
36 other side of the relationship", and values using the pseudo-table C<self>
37 are resolved to mean "the Table this class is representing". Other
38 restrictions, such as by value, sub-select and other tables, may also be
39 used. Please check your database for C<JOIN> parameter support.
40
41 For example, if you're creating a relationship from C<Author> to C<Book>, where
42 the C<Book> table has a column C<author_id> containing the ID of the C<Author>
43 row:
44
45   { 'foreign.author_id' => 'self.id' }
46
47 will result in the C<JOIN> clause
48
49   author me JOIN book book ON book.author_id = me.id
50
51 For multi-column foreign keys, you will need to specify a C<foreign>-to-C<self>
52 mapping for each column in the key. For example, if you're creating a
53 relationship from C<Book> to C<Edition>, where the C<Edition> table refers to a
54 publisher and a type (e.g. "paperback"):
55
56   {
57     'foreign.publisher_id' => 'self.publisher_id',
58     'foreign.type_id'      => 'self.type_id',
59   }
60
61 This will result in the C<JOIN> clause:
62
63   book me JOIN edition edition ON edition.publisher_id = me.publisher_id
64     AND edition.type_id = me.type_id
65
66 Each key-value pair provided in a hashref will be used as C<AND>ed conditions.
67 To add an C<OR>ed condition, use an arrayref of hashrefs. See the
68 L<SQL::Abstract> documentation for more details.
69
70 In addition to standard result set attributes, the following attributes are also valid:
71
72 =over 4
73
74 =item join_type
75
76 Explicitly specifies the type of join to use in the relationship. Any SQL
77 join type is valid, e.g. C<LEFT> or C<RIGHT>. It will be placed in the SQL
78 command immediately before C<JOIN>.
79
80 =item proxy
81
82 An arrayref containing a list of accessors in the foreign class to create in
83 the main class. If, for example, you do the following:
84   
85   MyDB::Schema::CD->might_have(liner_notes => 'MyDB::Schema::LinerNotes',
86     undef, {
87       proxy => [ qw/notes/ ],
88     });
89   
90 Then, assuming MyDB::Schema::LinerNotes has an accessor named notes, you can do:
91
92   my $cd = MyDB::Schema::CD->find(1);
93   $cd->notes('Notes go here'); # set notes -- LinerNotes object is
94                                # created if it doesn't exist
95   
96 =item accessor
97
98 Specifies the type of accessor that should be created for the relationship.
99 Valid values are C<single> (for when there is only a single related object),
100 C<multi> (when there can be many), and C<filter> (for when there is a single
101 related object, but you also want the relationship accessor to double as
102 a column accessor). For C<multi> accessors, an add_to_* method is also
103 created, which calls C<create_related> for the relationship.
104
105 =item is_foreign_key_constraint
106
107 If you are using L<SQL::Translator> to create SQL for you and you find that it
108 is creating constraints where it shouldn't, or not creating them where it 
109 should, set this attribute to a true or false value to override the detection
110 of when to create constraints.
111
112 =item is_deferrable
113
114 Tells L<SQL::Translator> that the foreign key constraint it creates should be
115 deferrable. In other words, the user may request that the constraint be ignored
116 until the end of the transaction. Currently, only the PostgreSQL producer
117 actually supports this.
118
119 =item add_fk_index
120
121 Tells L<SQL::Translator> to add an index for this constraint. Can also be
122 specified globally in the args to L<DBIx::Class::Schema/deploy> or
123 L<DBIx::Class::Schema/create_ddl_dir>. Default is on, set to 0 to disable.
124
125 =back
126
127 =head2 register_relationship
128
129 =over 4
130
131 =item Arguments: $relname, $rel_info
132
133 =back
134
135 Registers a relationship on the class. This is called internally by
136 DBIx::Class::ResultSourceProxy to set up Accessors and Proxies.
137
138 =cut
139
140 sub register_relationship { }
141
142 =head2 related_resultset
143
144 =over 4
145
146 =item Arguments: $relationship_name
147
148 =item Return Value: $related_resultset
149
150 =back
151
152   $rs = $cd->related_resultset('artist');
153
154 Returns a L<DBIx::Class::ResultSet> for the relationship named
155 $relationship_name.
156
157 =cut
158
159 sub related_resultset {
160   my $self = shift;
161   $self->throw_exception("Can't call *_related as class methods")
162     unless ref $self;
163   my $rel = shift;
164   my $rel_obj = $self->relationship_info($rel);
165   $self->throw_exception( "No such relationship ${rel}" )
166     unless $rel_obj;
167   
168   return $self->{related_resultsets}{$rel} ||= do {
169     my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
170     $attrs = { %{$rel_obj->{attrs} || {}}, %$attrs };
171
172     $self->throw_exception( "Invalid query: @_" )
173       if (@_ > 1 && (@_ % 2 == 1));
174     my $query = ((@_ > 1) ? {@_} : shift);
175
176     my $cond = $self->result_source->resolve_condition(
177       $rel_obj->{cond}, $rel, $self
178     );
179     if (ref $cond eq 'ARRAY') {
180       $cond = [ map { my $hash;
181         foreach my $key (keys %$_) {
182           my $newkey = $key =~ /\./ ? "me.$key" : $key;
183           $hash->{$newkey} = $_->{$key};
184         }; $hash } @$cond ];
185     } else {
186       foreach my $key (grep { ! /\./ } keys %$cond) {
187         $cond->{"me.$key"} = delete $cond->{$key};
188       }
189     }
190     $query = ($query ? { '-and' => [ $cond, $query ] } : $cond);
191     $self->result_source->related_source($rel)->resultset->search(
192       $query, $attrs
193     );
194   };
195 }
196
197 =head2 search_related
198
199   @objects = $rs->search_related('relname', $cond, $attrs);
200   $objects_rs = $rs->search_related('relname', $cond, $attrs);
201
202 Run a search on a related resultset. The search will be restricted to the
203 item or items represented by the L<DBIx::Class::ResultSet> it was called
204 upon. This method can be called on a ResultSet, a Row or a ResultSource class.
205
206 =cut
207
208 sub search_related {
209   return shift->related_resultset(shift)->search(@_);
210 }
211
212 =head2 search_related_rs
213
214   ( $objects_rs ) = $rs->search_related_rs('relname', $cond, $attrs);
215
216 This method works exactly the same as search_related, except that 
217 it guarantees a restultset, even in list context.
218
219 =cut
220
221 sub search_related_rs {
222   return shift->related_resultset(shift)->search_rs(@_);
223 }
224
225 =head2 count_related
226
227   $obj->count_related('relname', $cond, $attrs);
228
229 Returns the count of all the items in the related resultset, restricted by the
230 current item or where conditions. Can be called on a
231 L<DBIx::Class::Manual::Glossary/"ResultSet"> or a
232 L<DBIx::Class::Manual::Glossary/"Row"> object.
233
234 =cut
235
236 sub count_related {
237   my $self = shift;
238   return $self->search_related(@_)->count;
239 }
240
241 =head2 new_related
242
243   my $new_obj = $obj->new_related('relname', \%col_data);
244
245 Create a new item of the related foreign class. If called on a
246 L<Row|DBIx::Class::Manual::Glossary/"Row"> object, it will magically 
247 set any foreign key columns of the new object to the related primary 
248 key columns of the source object for you.  The newly created item will 
249 not be saved into your storage until you call L<DBIx::Class::Row/insert>
250 on it.
251
252 =cut
253
254 sub new_related {
255   my ($self, $rel, $values, $attrs) = @_;
256   return $self->search_related($rel)->new($values, $attrs);
257 }
258
259 =head2 create_related
260
261   my $new_obj = $obj->create_related('relname', \%col_data);
262
263 Creates a new item, similarly to new_related, and also inserts the item's data
264 into your storage medium. See the distinction between C<create> and C<new>
265 in L<DBIx::Class::ResultSet> for details.
266
267 =cut
268
269 sub create_related {
270   my $self = shift;
271   my $rel = shift;
272   my $obj = $self->search_related($rel)->create(@_);
273   delete $self->{related_resultsets}->{$rel};
274   return $obj;
275 }
276
277 =head2 find_related
278
279   my $found_item = $obj->find_related('relname', @pri_vals | \%pri_vals);
280
281 Attempt to find a related object using its primary key or unique constraints.
282 See L<DBIx::Class::ResultSet/find> for details.
283
284 =cut
285
286 sub find_related {
287   my $self = shift;
288   my $rel = shift;
289   return $self->search_related($rel)->find(@_);
290 }
291
292 =head2 find_or_new_related
293
294   my $new_obj = $obj->find_or_new_related('relname', \%col_data);
295
296 Find an item of a related class. If none exists, instantiate a new item of the
297 related class. The object will not be saved into your storage until you call
298 L<DBIx::Class::Row/insert> on it.
299
300 =cut
301
302 sub find_or_new_related {
303   my $self = shift;
304   my $obj = $self->find_related(@_);
305   return defined $obj ? $obj : $self->new_related(@_);
306 }
307
308 =head2 find_or_create_related
309
310   my $new_obj = $obj->find_or_create_related('relname', \%col_data);
311
312 Find or create an item of a related class. See
313 L<DBIx::Class::ResultSet/find_or_create> for details.
314
315 =cut
316
317 sub find_or_create_related {
318   my $self = shift;
319   my $obj = $self->find_related(@_);
320   return (defined($obj) ? $obj : $self->create_related(@_));
321 }
322
323 =head2 update_or_create_related
324
325   my $updated_item = $obj->update_or_create_related('relname', \%col_data, \%attrs?);
326
327 Update or create an item of a related class. See
328 L<DBIx::Class::ResultSet/update_or_create> for details.
329
330 =cut
331
332 sub update_or_create_related {
333   my $self = shift;
334   my $rel = shift;
335   return $self->related_resultset($rel)->update_or_create(@_);
336 }
337
338 =head2 set_from_related
339
340   $book->set_from_related('author', $author_obj);
341   $book->author($author_obj);                      ## same thing
342
343 Set column values on the current object, using related values from the given
344 related object. This is used to associate previously separate objects, for
345 example, to set the correct author for a book, find the Author object, then
346 call set_from_related on the book.
347
348 This is called internally when you pass existing objects as values to
349 L<DBIx::Class::ResultSet/create>, or pass an object to a belongs_to acessor.
350
351 The columns are only set in the local copy of the object, call L</update> to
352 set them in the storage.
353
354 =cut
355
356 sub set_from_related {
357   my ($self, $rel, $f_obj) = @_;
358   my $rel_obj = $self->relationship_info($rel);
359   $self->throw_exception( "No such relationship ${rel}" ) unless $rel_obj;
360   my $cond = $rel_obj->{cond};
361   $self->throw_exception(
362     "set_from_related can only handle a hash condition; the ".
363     "condition for $rel is of type ".
364     (ref $cond ? ref $cond : 'plain scalar')
365   ) unless ref $cond eq 'HASH';
366   if (defined $f_obj) {
367     my $f_class = $self->result_source->schema->class($rel_obj->{class});
368     $self->throw_exception( "Object $f_obj isn't a ".$f_class )
369       unless Scalar::Util::blessed($f_obj) and $f_obj->isa($f_class);
370   }
371   $self->set_columns(
372     $self->result_source->resolve_condition(
373        $rel_obj->{cond}, $f_obj, $rel));
374   return 1;
375 }
376
377 =head2 update_from_related
378
379   $book->update_from_related('author', $author_obj);
380
381 The same as L</"set_from_related">, but the changes are immediately updated
382 in storage.
383
384 =cut
385
386 sub update_from_related {
387   my $self = shift;
388   $self->set_from_related(@_);
389   $self->update;
390 }
391
392 =head2 delete_related
393
394   $obj->delete_related('relname', $cond, $attrs);
395
396 Delete any related item subject to the given conditions.
397
398 =cut
399
400 sub delete_related {
401   my $self = shift;
402   my $obj = $self->search_related(@_)->delete;
403   delete $self->{related_resultsets}->{$_[0]};
404   return $obj;
405 }
406
407 =head2 add_to_$rel
408
409 B<Currently only available for C<has_many>, C<many-to-many> and 'multi' type
410 relationships.>
411
412 =over 4
413
414 =item Arguments: ($foreign_vals | $obj), $link_vals?
415
416 =back
417
418   my $role = $schema->resultset('Role')->find(1);
419   $actor->add_to_roles($role);
420       # creates a My::DBIC::Schema::ActorRoles linking table row object
421
422   $actor->add_to_roles({ name => 'lead' }, { salary => 15_000_000 });
423       # creates a new My::DBIC::Schema::Role row object and the linking table
424       # object with an extra column in the link
425
426 Adds a linking table object for C<$obj> or C<$foreign_vals>. If the first
427 argument is a hash reference, the related object is created first with the
428 column values in the hash. If an object reference is given, just the linking
429 table object is created. In either case, any additional column values for the
430 linking table object can be specified in C<$link_vals>.
431
432 =head2 set_$rel
433
434 B<Currently only available for C<many-to-many> relationships.>
435
436 =over 4
437
438 =item Arguments: (\@hashrefs | \@objs)
439
440 =back
441
442   my $actor = $schema->resultset('Actor')->find(1);
443   my @roles = $schema->resultset('Role')->search({ role => 
444      { '-in' => ['Fred', 'Barney'] } } );
445
446   $actor->set_roles(\@roles);
447      # Replaces all of $actor's previous roles with the two named
448
449 Replace all the related objects with the given reference to a list of
450 objects. This does a C<delete> B<on the link table resultset> to remove the
451 association between the current object and all related objects, then calls
452 C<add_to_$rel> repeatedly to link all the new objects.
453
454 Note that this means that this method will B<not> delete any objects in the
455 table on the right side of the relation, merely that it will delete the link
456 between them.
457
458 Due to a mistake in the original implementation of this method, it will also
459 accept a list of objects or hash references. This is B<deprecated> and will be
460 removed in a future version.
461
462 =head2 remove_from_$rel
463
464 B<Currently only available for C<many-to-many> relationships.>
465
466 =over 4
467
468 =item Arguments: $obj
469
470 =back
471
472   my $role = $schema->resultset('Role')->find(1);
473   $actor->remove_from_roles($role);
474       # removes $role's My::DBIC::Schema::ActorRoles linking table row object
475
476 Removes the link between the current object and the related object. Note that
477 the related object itself won't be deleted unless you call ->delete() on
478 it. This method just removes the link between the two objects.
479
480 =head1 AUTHORS
481
482 Matt S. Trout <mst@shadowcatsystems.co.uk>
483
484 =head1 LICENSE
485
486 You may distribute this code under the same terms as Perl itself.
487
488 =cut
489
490 1;