1 package FS::o2m_Common;
4 use vars qw( $DEBUG $me );
6 use FS::Schema qw( dbdef );
7 use FS::Record qw( qsearch qsearchs dbh );
11 $me = '[FS::o2m_Common]';
15 FS::o2m_Common - Mixin class for tables with a related table
21 @ISA = qw( FS::o2m_Common FS::Record );
25 FS::o2m_Common is intended as a mixin class for classes which have a
32 =item process_o2m OPTION => VALUE, ...
36 table (required) - Table into which the records are inserted.
38 fields (required) - Arrayref of the field names in the "many" table.
40 params (required) - Hashref of keys and values, often passed as
41 C<scalar($cgi->Vars)> from a form. This will be scanned for keys of the form
42 "pkeyNN" (where pkey is the primary key column name, and NN is an integer).
43 Each of these designates one record in the "many" table. The contents of
44 that record will be taken from other parameters with the names
45 "pkeyNN_myfield" (where myfield is one of the fields in the 'fields'
48 num_col (optional) - Name of the foreign key column in the "many" table, which
49 links to the primary key of the base table. If not specified, it is assumed
50 this has the same name as in the base table.
54 #a little more false laziness w/m2m_Common.pm than m2_name_Common.pm
55 # still, far from the worse of it. at least we're a reuable mixin!
57 my( $self, %opt ) = @_;
59 my $self_pkey = $self->dbdef_table->primary_key;
60 my $link_sourcekey = $opt{'num_col'} || $self_pkey;
62 my $hashref = {}; #$opt{'hashref'} || {};
63 $hashref->{$link_sourcekey} = $self->$self_pkey();
65 my $table = $self->_load_table($opt{'table'});
66 my $table_pkey = dbdef->table($table)->primary_key;
68 # my $link_static = $opt{'link_static'} || {};
70 warn "$me processing o2m from ". $self->table. ".$link_sourcekey".
74 #if ( ref($opt{'params'}) eq 'ARRAY' ) {
75 # $opt{'params'} = { map { $_=>1 } @{$opt{'params'}} };
78 local $SIG{HUP} = 'IGNORE';
79 local $SIG{INT} = 'IGNORE';
80 local $SIG{QUIT} = 'IGNORE';
81 local $SIG{TERM} = 'IGNORE';
82 local $SIG{TSTP} = 'IGNORE';
83 local $SIG{PIPE} = 'IGNORE';
85 my $oldAutoCommit = $FS::UID::AutoCommit;
86 local $FS::UID::AutoCommit = 0;
89 my @fields = grep { /^$table_pkey\d+$/ }
90 keys %{ $opt{'params'} };
92 my %edits = map { $opt{'params'}->{$_} => $_ }
93 grep { $opt{'params'}->{$_} }
97 grep { ! $edits{$_->$table_pkey()} }
98 $self->process_o2m_qsearch( $table, $hashref )
100 my $error = $del_obj->delete;
102 $dbh->rollback if $oldAutoCommit;
107 foreach my $pkey_value ( keys %edits ) {
108 my $old_obj = $self->process_o2m_qsearchs( $table, { %$hashref, $table_pkey => $pkey_value } );
109 my $add_param = $edits{$pkey_value};
110 my %hash = ( $table_pkey => $pkey_value,
111 map { $_ => $opt{'params'}->{$add_param."_$_"} }
114 &{ $opt{'hash_callback'} }( \%hash ) if $opt{'hash_callback'};
115 #next unless grep { $_ =~ /\S/ } values %hash;
117 my $new_obj = "FS::$table"->new( { %$hashref, %hash } );
118 my $error = $new_obj->replace($old_obj);
120 $dbh->rollback if $oldAutoCommit;
125 foreach my $add_param ( grep { ! $opt{'params'}->{$_} } @fields ) {
127 my %hash = map { $_ => $opt{'params'}->{$add_param."_$_"} }
129 &{ $opt{'hash_callback'} }( \%hash ) if $opt{'hash_callback'};
130 next unless grep { $_ =~ /\S/ } values %hash;
132 my $add_obj = "FS::$table"->new( { %$hashref, %hash } );
133 my $error = $add_obj->insert;
135 $dbh->rollback if $oldAutoCommit;
140 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
144 sub process_o2m_qsearch { my $self = shift; qsearch( @_ ); }
145 sub process_o2m_qsearchs { my $self = shift; qsearchs( @_ ); }
148 my( $self, $table ) = @_;
149 eval "use FS::$table";