new package def editor
[freeside.git] / FS / FS / m2m_Common.pm
1 package FS::m2m_Common;
2
3 use strict;
4 use vars qw( @ISA $DEBUG );
5 use FS::Schema qw( dbdef );
6 use FS::Record qw( qsearch qsearchs dbh );
7
8 #hmm.  well.  we seem to be used as a mixin.
9 #@ISA = qw( FS::Record );
10
11 $DEBUG = 0;
12
13 =head1 NAME
14
15 FS::m2m_Common - Mixin class for classes in a many-to-many relationship
16
17 =head1 SYNOPSIS
18
19 use FS::m2m_Common;
20
21 @ISA = qw( FS::m2m_Common FS::Record );
22
23 =head1 DESCRIPTION
24
25 FS::m2m_Common is intended as a mixin class for classes which have a
26 many-to-many relationship with another table (via a linking table).
27
28 It is currently assumed that the link table contains two fields named the same
29 as the primary keys of the base and target tables, but you can ovverride this
30 assumption if your table is different.
31
32 =head1 METHODS
33
34 =over 4
35
36 =item process_m2m OPTION => VALUE, ...
37
38 Available options:
39
40 =over 4
41
42 =item link_table (required)
43
44 =item target_table (required)
45
46 =item params (required)
47
48 hashref; keys are primary key values in target_table (values are boolean).  For convenience, keys may optionally be prefixed with the name
49 of the primary key, as in "agentnum54" instead of "54", or passed as an arrayref
50 of values.
51
52 =item base_field (optional)
53
54 base field, defaults to primary key of this base table
55
56 =item target_field (optional)
57
58 target field, defaults to the primary key of the target table
59
60 =item hashref (optional)
61
62 static hashref further qualifying the m2m fields
63
64 =cut
65
66 sub process_m2m {
67   my( $self, %opt ) = @_;
68
69   my $self_pkey = $self->dbdef_table->primary_key;
70   my $base_field = $opt{'base_field'} || $self_pkey;
71   my %hash = $opt{'hashref'} || {};
72   $hash{$base_field} = $self->$self_pkey();
73
74   my $link_table = $self->_load_table($opt{'link_table'});
75
76   my $target_table = $self->_load_table($opt{'target_table'});
77   my $target_field = $opt{'target_field'}
78                      || dbdef->table($target_table)->primary_key;
79
80   if ( ref($opt{'params'}) eq 'ARRAY' ) {
81     $opt{'params'} = { map { $_=>1 } @{$opt{'params'}} };
82   }
83
84   local $SIG{HUP} = 'IGNORE';
85   local $SIG{INT} = 'IGNORE';
86   local $SIG{QUIT} = 'IGNORE';
87   local $SIG{TERM} = 'IGNORE';
88   local $SIG{TSTP} = 'IGNORE';
89   local $SIG{PIPE} = 'IGNORE';
90
91   my $oldAutoCommit = $FS::UID::AutoCommit;
92   local $FS::UID::AutoCommit = 0;
93   my $dbh = dbh;
94
95   foreach my $del_obj (
96     grep { 
97            my $targetnum = $_->$target_field();
98            (    ! $opt{'params'}->{$targetnum}
99              && ! $opt{'params'}->{"$target_field$targetnum"}
100            );
101          }
102          qsearch( $link_table, \%hash )
103   ) {
104     my $error = $del_obj->delete;
105     if ( $error ) {
106       $dbh->rollback if $oldAutoCommit;
107       return $error;
108     }
109   }
110
111   foreach my $add_targetnum (
112     grep { ! qsearchs( $link_table, { %hash, $target_field => $_ } ) }
113     map  { /^($target_field)?(\d+)$/; $2; }
114     grep { /^($target_field)?(\d+)$/ }
115     grep { $opt{'params'}->{$_} }
116     keys %{ $opt{'params'} }
117   ) {
118
119     my $add_obj = "FS::$link_table"->new( {
120       %hash, 
121       $target_field => $add_targetnum,
122     });
123     my $error = $add_obj->insert;
124     if ( $error ) {
125       $dbh->rollback if $oldAutoCommit;
126       return $error;
127     }
128   }
129
130   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
131   '';
132 }
133
134 sub _load_table {
135   my( $self, $table ) = @_;
136   eval "use FS::$table";
137   die $@ if $@;
138   $table;
139 }
140
141 #=item target_table
142 #
143 #=cut
144 #
145 #sub target_table {
146 #  my $self = shift;
147 #  my $target_table = $self->_target_table;
148 #  eval "use FS::$target_table";
149 #  die $@ if $@;
150 #  $target_table;
151 #}
152
153 =back
154
155 =head1 BUGS
156
157 =head1 SEE ALSO
158
159 L<FS::Record>
160
161 =cut
162
163 1;
164