Shuffle delete tests, and sanify the delete related ones
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Relationship / ManyToMany.pm
CommitLineData
75d07914 1package # hide from PAUSE
c0e7b4e5 2 DBIx::Class::Relationship::ManyToMany;
8973b6f1 3
4use strict;
5use warnings;
b234e9d9 6
7use Carp::Clan qw/^DBIx::Class/;
ddc0a6c8 8use Sub::Name ();
8973b6f1 9
10sub many_to_many {
78af1010 11 my ($class, $meth, $rel, $f_rel, $rel_attrs) = @_;
d0ed3b55 12
13 $class->throw_exception(
14 "missing relation in many-to-many"
15 ) unless $rel;
16
17 $class->throw_exception(
18 "missing foreign relation in many-to-many"
19 ) unless $f_rel;
20
8973b6f1 21 {
22 no strict 'refs';
23 no warnings 'redefine';
4b3ab474 24
b3f358b5 25 my $add_meth = "add_to_${meth}";
26 my $remove_meth = "remove_from_${meth}";
27 my $set_meth = "set_${meth}";
18788bf2 28 my $rs_meth = "${meth}_rs";
303cf522 29
35210a5d 30 for ($add_meth, $remove_meth, $set_meth, $rs_meth) {
d81b2771 31 if ( $class->can ($_) ) {
b234e9d9 32 carp (<<"EOW") unless $ENV{DBIC_METHOD_CLOBBER_OK};
33
35678f0b 34***************************************************************************
b234e9d9 35The many-to-many relationship '$meth' is trying to create a utility method
36called $_.
37This will completely overwrite one such already existing method on class
38$class.
d81b2771 39
b234e9d9 40You almost certainly want to rename your method or the many-to-many
41relationship, as the functionality of the original method will not be
42accessible anymore.
d81b2771 43
b234e9d9 44To disable this warning set the environment variable DBIC_METHOD_CLOBBER_OK
45to a true value
35678f0b 46
35678f0b 47***************************************************************************
48EOW
d81b2771 49 }
35210a5d 50 }
51
7141bdfc 52 $rel_attrs->{alias} ||= $f_rel;
53
ddc0a6c8 54 my $rs_meth_name = join '::', $class, $rs_meth;
55 *$rs_meth_name = Sub::Name::subname $rs_meth_name, sub {
0f6ac8bb 56 my $self = shift;
57 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {};
78060df8 58 my @args = ($f_rel, @_ > 0 ? @_ : undef, { %{$rel_attrs||{}}, %$attrs });
18788bf2 59 my $rs = $self->search_related($rel)->search_related(
3a868fb2 60 $f_rel, @_ > 0 ? @_ : undef, { %{$rel_attrs||{}}, %$attrs }
61 );
18788bf2 62 return $rs;
78af1010 63 };
4b3ab474 64
ddc0a6c8 65 my $meth_name = join '::', $class, $meth;
66 *$meth_name = Sub::Name::subname $meth_name, sub {
18788bf2 67 my $self = shift;
68 my $rs = $self->$rs_meth( @_ );
69 return (wantarray ? $rs->all : $rs);
70 };
71
ddc0a6c8 72 my $add_meth_name = join '::', $class, $add_meth;
73 *$add_meth_name = Sub::Name::subname $add_meth_name, sub {
303cf522 74 my $self = shift;
75 @_ > 0 or $self->throw_exception(
b3f358b5 76 "${add_meth} needs an object or hashref"
303cf522 77 );
78 my $source = $self->result_source;
79 my $schema = $source->schema;
80 my $rel_source_name = $source->relationship_info($rel)->{source};
81 my $rel_source = $schema->resultset($rel_source_name)->result_source;
82 my $f_rel_source_name = $rel_source->relationship_info($f_rel)->{source};
78060df8 83 my $f_rel_rs = $schema->resultset($f_rel_source_name)->search({}, $rel_attrs||{});
84
85 my $obj;
86 if (ref $_[0]) {
87 if (ref $_[0] eq 'HASH') {
88 $obj = $f_rel_rs->create($_[0]);
89 } else {
90 $obj = $_[0];
91 }
92 } else {
93 $obj = $f_rel_rs->create({@_});
94 }
95
3bd6e3e0 96 my $link_vals = @_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {};
6cc5b382 97 my $link = $self->search_related($rel)->new_result($link_vals);
303cf522 98 $link->set_from_related($f_rel, $obj);
99 $link->insert();
716c16a0 100 return $obj;
4b3ab474 101 };
102
ddc0a6c8 103 my $set_meth_name = join '::', $class, $set_meth;
104 *$set_meth_name = Sub::Name::subname $set_meth_name, sub {
b3f358b5 105 my $self = shift;
106 @_ > 0 or $self->throw_exception(
107 "{$set_meth} needs a list of objects or hashrefs"
108 );
f72f9361 109 my @to_set = (ref($_[0]) eq 'ARRAY' ? @{ $_[0] } : @_);
b3f358b5 110 $self->search_related($rel, {})->delete;
ac36a402 111 $self->$add_meth($_, ref($_[1]) ? $_[1] : {}) for (@to_set);
b3f358b5 112 };
113
ddc0a6c8 114 my $remove_meth_name = join '::', $class, $remove_meth;
115 *$remove_meth_name = Sub::Name::subname $remove_meth_name, sub {
303cf522 116 my $self = shift;
117 @_ > 0 && ref $_[0] ne 'HASH'
b3f358b5 118 or $self->throw_exception("${remove_meth} needs an object");
303cf522 119 my $obj = shift;
120 my $rel_source = $self->search_related($rel)->result_source;
121 my $cond = $rel_source->relationship_info($f_rel)->{cond};
122 my $link_cond = $rel_source->resolve_condition(
123 $cond, $obj, $f_rel
124 );
125 $self->search_related($rel, $link_cond)->delete;
4b3ab474 126 };
127
8973b6f1 128 }
129}
130
1311;