line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Class::DBI::Relationship::IsA; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Class::DBI::Relationship::IsA - A Class::DBI module for 'Is A' relationships |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 DESCRIPTION |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
Class::DBI::Relationship::IsA Provides an Is A relationship between Class::DBI classes/tables. |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
By using this module you can emulate some features of inheritance both within your database and classes through the Class::DBI API. |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
NOTE: This module is still experimental, several very nasty bugs have been found (and fixed) others may still be lurking - see CAVEATS AND BUGS below. |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
Warning Will Robinson! |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 SYNOPSIS |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
In your database (assuming mysql): |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
create table person ( |
22
|
|
|
|
|
|
|
personid int primary key auto_increment, |
23
|
|
|
|
|
|
|
firstname varchar(32), |
24
|
|
|
|
|
|
|
initials varchar(16), |
25
|
|
|
|
|
|
|
surname varchar(64), |
26
|
|
|
|
|
|
|
date_of_birth datetime |
27
|
|
|
|
|
|
|
); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
create table artist ( |
30
|
|
|
|
|
|
|
artistid int primary key auto_increment, |
31
|
|
|
|
|
|
|
alias varchar(128), |
32
|
|
|
|
|
|
|
person int |
33
|
|
|
|
|
|
|
); |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
In your classes: |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
package Music::DBI; |
39
|
|
|
|
|
|
|
use base 'Class::DBI'; |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
Music::DBI->connection('dbi:mysql:dbname', 'username', 'password'); |
42
|
|
|
|
|
|
|
__PACKAGE__->add_relationship_type(is_a => 'Class::DBI::Relationship::IsA'); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
Superclass: |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
package Music::Person; |
47
|
|
|
|
|
|
|
use base 'Music::DBI'; |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
Music::Person->table('person'); |
50
|
|
|
|
|
|
|
Music::Person->columns(All => qw/personid firstname initials surname date_of_birth/); |
51
|
|
|
|
|
|
|
Music::Person->columns(Primary => qw/personid/); # Good practice, less likely to break IsA |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
Child class: |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
package Music::Artist; |
56
|
|
|
|
|
|
|
use base 'Music::DBI'; |
57
|
|
|
|
|
|
|
use Music::Person; # required for access to Music::Person methods |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
Music::Artist->table('artist'); |
60
|
|
|
|
|
|
|
Music::Artist->columns(All => qw/artistid alias/); |
61
|
|
|
|
|
|
|
Music::Person->columns(Primary => qw/personid/); # Good practice, less likely to break IsA |
62
|
|
|
|
|
|
|
Music::Artist->has_many(cds => 'Music::CD'); |
63
|
|
|
|
|
|
|
Music::Artist->is_a(person => 'Person'); # Music::Artist inherits accessors from Music::Person |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
... elsewhere ... |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
use Music::Artist; |
68
|
|
|
|
|
|
|
my $artist = Music::Artist->create( {firstname=>'Sarah', surname=>'Geller', alias=>'Buffy'}); |
69
|
|
|
|
|
|
|
$artist->initials('M'); |
70
|
|
|
|
|
|
|
$artist->update(); |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=cut |
73
|
|
|
|
|
|
|
|
74
|
1
|
|
|
1
|
|
942
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
53
|
|
75
|
|
|
|
|
|
|
our $VERSION = '0.05'; |
76
|
|
|
|
|
|
|
|
77
|
1
|
|
|
1
|
|
7
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
36
|
|
78
|
1
|
|
|
1
|
|
16
|
use base qw( Class::DBI::Relationship ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1146
|
|
79
|
1
|
|
|
1
|
|
7092
|
use Class::DBI::AbstractSearch; |
|
1
|
|
|
|
|
27322
|
|
|
1
|
|
|
|
|
77
|
|
80
|
|
|
|
|
|
|
|
81
|
1
|
|
|
1
|
|
1275
|
use Data::Dumper; |
|
1
|
|
|
|
|
7132
|
|
|
1
|
|
|
|
|
830
|
|
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub remap_arguments { |
84
|
0
|
|
|
0
|
1
|
|
my $proto = shift; |
85
|
0
|
|
|
|
|
|
my $class = shift; |
86
|
0
|
0
|
|
|
|
|
$class->_invalid_object_method('is_a()') if ref $class; |
87
|
0
|
0
|
|
|
|
|
my $column = $class->find_column(shift) |
88
|
|
|
|
|
|
|
or return $class->_croak("is_a needs a valid column"); |
89
|
0
|
0
|
|
|
|
|
my $f_class = shift |
90
|
|
|
|
|
|
|
or $class->_croak("$class $column needs an associated class"); |
91
|
0
|
|
|
|
|
|
my %meths = @_; |
92
|
0
|
|
|
|
|
|
my @f_cols; |
93
|
0
|
|
|
|
|
|
foreach my $f_col ($f_class->all_columns) { |
94
|
0
|
0
|
|
|
|
|
push @f_cols, $f_col |
95
|
|
|
|
|
|
|
unless $f_col eq $f_class->primary_column; |
96
|
|
|
|
|
|
|
} |
97
|
0
|
|
|
|
|
|
$class->__grouper->add_group(TEMP => map { $_->name } @f_cols); |
|
0
|
|
|
|
|
|
|
98
|
0
|
|
|
|
|
|
$class->__grouper->add_group(__INHERITED => map { $_->name } @f_cols); |
|
0
|
|
|
|
|
|
|
99
|
0
|
|
|
|
|
|
$class->mk_classdata('__isa_rels'); |
100
|
0
|
|
|
|
|
|
$class->__isa_rels({ }); |
101
|
0
|
|
|
|
|
|
return ($class, $column, $f_class, \%meths); |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub triggers { |
105
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
106
|
0
|
|
|
|
|
|
$self->class->_require_class($self->foreign_class); |
107
|
0
|
|
|
|
|
|
my $column = $self->accessor; |
108
|
|
|
|
|
|
|
return ( |
109
|
|
|
|
|
|
|
select => $self->_inflator, |
110
|
|
|
|
|
|
|
before_create => $self->_creator, |
111
|
|
|
|
|
|
|
before_update => sub { |
112
|
0
|
0
|
|
0
|
|
|
if (my $f_obj = $_[0]->$column()) { $f_obj->update } |
|
0
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
}, |
114
|
|
|
|
|
|
|
|
115
|
0
|
|
|
|
|
|
); |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub methods { |
119
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
120
|
0
|
|
|
|
|
|
$self->class->_require_class($self->foreign_class); |
121
|
|
|
|
|
|
|
|
122
|
0
|
|
|
|
|
|
my $foreign_class = $self->foreign_class; |
123
|
0
|
|
|
|
|
|
my $class = $self->class; |
124
|
0
|
|
|
|
|
|
warn "foreign class : $foreign_class\n"; |
125
|
|
|
|
|
|
|
|
126
|
0
|
|
|
|
|
|
warn "getting relationships..\n"; |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
|
129
|
0
|
|
|
|
|
|
my $parent_relation_fields = $self->_inject_inherited_relationships(class=>$class, foreign=>$foreign_class); |
130
|
|
|
|
|
|
|
|
131
|
0
|
|
|
|
|
|
my $forbidden_fields = "(id|${class}_?u?id"; |
132
|
0
|
0
|
|
|
|
|
$forbidden_fields .= ($foreign_class->columns('Primary')) ? '|' . $foreign_class->columns('Primary') .')' : ')' ; |
133
|
0
|
|
|
|
|
|
warn "forbidden_fields : $forbidden_fields\n"; |
134
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
my %methods; |
136
|
0
|
|
|
|
|
|
my $acc_name = $self->accessor->name; |
137
|
0
|
|
|
|
|
|
foreach my $f_col ($self->foreign_class->all_columns) { |
138
|
0
|
|
|
|
|
|
warn "f_col : $f_col, acc_name : $acc_name\n"; |
139
|
0
|
0
|
0
|
|
|
|
next if ($f_col eq $acc_name or $f_col =~ /$forbidden_fields/i or $parent_relation_fields->{$f_col}); |
|
|
|
0
|
|
|
|
|
140
|
0
|
0
|
|
|
|
|
if ($class->can('pure_accessor_name')) { |
141
|
|
|
|
|
|
|
# provide seperate read/write accessor, read only accessor and write only mutator |
142
|
0
|
|
|
|
|
|
$methods{ucfirst($class->pure_accessor_name($f_col))} |
143
|
|
|
|
|
|
|
= $methods{$class->pure_accessor_name($f_col)} = $self->_get_methods($acc_name, $f_col,'ro'); |
144
|
0
|
|
|
|
|
|
$methods{ucfirst($class->mutator_name($f_col))} |
145
|
|
|
|
|
|
|
= $methods{$class->mutator_name($f_col)} = $self->_get_methods($acc_name, $f_col,'wo'); |
146
|
0
|
|
|
|
|
|
$methods{ucfirst($class->accessor_name($f_col))} |
147
|
|
|
|
|
|
|
= $methods{$class->accessor_name($f_col)} = $self->_get_methods($acc_name, $f_col,'rw'); |
148
|
|
|
|
|
|
|
} else { |
149
|
0
|
0
|
|
|
|
|
if ( $class->mutator_name($f_col) eq $class->accessor_name($f_col) ) { |
150
|
|
|
|
|
|
|
# provide read/write accessor |
151
|
0
|
|
|
|
|
|
$methods{ucfirst($class->accessor_name($f_col))} |
152
|
|
|
|
|
|
|
= $methods{$class->accessor_name($f_col)} = $self->_get_methods($acc_name, $f_col,'rw'); |
153
|
|
|
|
|
|
|
} else { |
154
|
|
|
|
|
|
|
# provide seperate read only accessor and write only mutator |
155
|
0
|
|
|
|
|
|
$methods{ucfirst($class->accessor_name($f_col))} |
156
|
|
|
|
|
|
|
= $methods{$class->accessor_name($f_col)} = $self->_get_methods($acc_name, $f_col,'ro'); |
157
|
0
|
|
|
|
|
|
$methods{ucfirst($class->mutator_name($f_col))} |
158
|
|
|
|
|
|
|
= $methods{$class->mutator_name($f_col)} = $self->_get_methods($acc_name, $f_col,'wo'); |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
0
|
0
|
|
|
|
|
$methods{search_where} = $self->search_where if $self->class->can('search_where'); |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
return( |
166
|
0
|
|
|
|
|
|
%methods, |
167
|
|
|
|
|
|
|
search => $self->search, |
168
|
|
|
|
|
|
|
search_like => $self->search_like, |
169
|
|
|
|
|
|
|
all_columns => $self->all_columns, |
170
|
|
|
|
|
|
|
); |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub search { |
174
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
175
|
0
|
|
|
|
|
|
my $SUPER = $self->foreign_class; |
176
|
0
|
|
|
|
|
|
my $col = $self->accessor; |
177
|
|
|
|
|
|
|
{ |
178
|
1
|
|
|
1
|
|
10
|
no strict "refs"; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
228
|
|
|
0
|
|
|
|
|
|
|
179
|
0
|
|
|
|
|
|
*{$self->class."::orig_search"} = \&{"Class::DBI::search"}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
return sub { |
182
|
0
|
|
|
0
|
|
|
my ($self, %args) = (@_); |
183
|
0
|
|
|
|
|
|
my (%child, %parent); |
184
|
0
|
|
|
|
|
|
foreach my $key (keys %args) { |
185
|
0
|
0
|
|
|
|
|
$child{$key} = $args{$key} if $self->has_real_column($key); |
186
|
0
|
0
|
|
|
|
|
$parent{$key} = $args{$key} if $SUPER->has_real_column($key); |
187
|
|
|
|
|
|
|
} |
188
|
0
|
0
|
|
|
|
|
if(%parent) { |
189
|
0
|
|
|
|
|
|
return map { $self->orig_search($col => $_->id, %child) |
|
0
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
} $SUPER->search(%parent); |
191
|
|
|
|
|
|
|
} else { |
192
|
0
|
|
|
|
|
|
return $self->orig_search(%child); |
193
|
|
|
|
|
|
|
} |
194
|
0
|
|
|
|
|
|
}; |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
sub search_like { |
198
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
199
|
0
|
|
|
|
|
|
my $SUPER = $self->foreign_class; |
200
|
0
|
|
|
|
|
|
my $col = $self->accessor; |
201
|
|
|
|
|
|
|
{ |
202
|
1
|
|
|
1
|
|
4
|
no strict "refs"; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
225
|
|
|
0
|
|
|
|
|
|
|
203
|
0
|
|
|
|
|
|
*{$self->class."::orig_search_like"} = \&{"Class::DBI::search_like"}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
return sub { |
206
|
0
|
|
|
0
|
|
|
my ($self, %args) = (@_); |
207
|
0
|
|
|
|
|
|
my (%child, %parent); |
208
|
0
|
|
|
|
|
|
foreach my $key (keys %args) { |
209
|
0
|
0
|
|
|
|
|
$child{$key} = $args{$key} if $self->has_real_column($key); |
210
|
0
|
0
|
|
|
|
|
$parent{$key} = $args{$key} if $SUPER->has_real_column($key); |
211
|
|
|
|
|
|
|
} |
212
|
0
|
0
|
|
|
|
|
if(%parent) { |
213
|
0
|
|
|
|
|
|
return map { $self->orig_search_like($col => $_->id, %child) |
|
0
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
} $SUPER->search_like(%parent); |
215
|
|
|
|
|
|
|
} else { |
216
|
0
|
|
|
|
|
|
return $self->orig_search_like(%child); |
217
|
|
|
|
|
|
|
} |
218
|
0
|
|
|
|
|
|
}; |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
sub search_where { |
222
|
0
|
|
|
0
|
|
|
my $self = shift; |
223
|
0
|
|
|
|
|
|
my $SUPER = $self->foreign_class; |
224
|
0
|
|
|
|
|
|
my $col = $self->accessor; |
225
|
|
|
|
|
|
|
{ |
226
|
1
|
|
|
1
|
|
5
|
no strict "refs"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
407
|
|
|
0
|
|
|
|
|
|
|
227
|
0
|
|
|
|
|
|
*{$self->class."::orig_search_where"} = \&{"Class::DBI::AbstractSearch::search_where"}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
return sub { |
231
|
0
|
|
|
0
|
|
|
my ($self, %args) = (@_); |
232
|
0
|
|
|
|
|
|
my (%child, %parent); |
233
|
0
|
|
|
|
|
|
foreach my $key (keys %args) { |
234
|
0
|
0
|
|
|
|
|
$child{$key} = $args{$key} if $self->has_real_column($key); |
235
|
0
|
0
|
|
|
|
|
$parent{$key} = $args{$key} if $SUPER->has_real_column($key); |
236
|
|
|
|
|
|
|
} |
237
|
0
|
0
|
|
|
|
|
if(%parent) { |
238
|
0
|
|
|
|
|
|
return map { $self->orig_search_where($col->name => $_->id, %child) |
|
0
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
} $SUPER->search_where(%parent); |
240
|
|
|
|
|
|
|
} else { |
241
|
0
|
|
|
|
|
|
return $self->orig_search_where(%child); |
242
|
|
|
|
|
|
|
} |
243
|
0
|
|
|
|
|
|
}; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub all_columns { |
247
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
248
|
0
|
|
|
|
|
|
my $SUPER = $self->foreign_class; |
249
|
0
|
|
|
|
|
|
my $col = $self->accessor; |
250
|
|
|
|
|
|
|
{ |
251
|
1
|
|
|
1
|
|
7
|
no strict "refs"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
466
|
|
|
0
|
|
|
|
|
|
|
252
|
0
|
|
|
|
|
|
*{$self->class."::orig_all_columns"} = \&{"Class::DBI::all_columns"}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
return sub { |
255
|
0
|
|
|
0
|
|
|
my $self = shift; |
256
|
0
|
|
|
|
|
|
return ($self->orig_all_columns, $self->columns('TEMP')); |
257
|
0
|
|
|
|
|
|
}; |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
################################################################################ |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
sub _inject_inherited_relationships { |
264
|
0
|
|
|
0
|
|
|
my ($self,%params) = @_; |
265
|
0
|
|
|
|
|
|
my $class = $params{class}; |
266
|
0
|
|
|
|
|
|
my $foreign_class = $params{foreign}; |
267
|
0
|
|
|
|
|
|
my $fields = {}; |
268
|
|
|
|
|
|
|
|
269
|
0
|
|
|
|
|
|
my %current_relationships = (); |
270
|
|
|
|
|
|
|
|
271
|
0
|
0
|
|
|
|
|
if ($class->can('meta_info')) { |
272
|
0
|
|
|
|
|
|
warn "class has meta_info "; |
273
|
|
|
|
|
|
|
# warn Dumper($class->meta_info); |
274
|
0
|
|
|
|
|
|
my $meta_info = $class->meta_info; |
275
|
0
|
|
|
|
|
|
foreach my $relation_type ( keys %$meta_info ) { |
276
|
0
|
0
|
|
|
|
|
next if ($relation_type eq 'is_a'); |
277
|
0
|
|
|
|
|
|
foreach my $relname (keys %{$meta_info->{$relation_type}}) { |
|
0
|
|
|
|
|
|
|
278
|
0
|
|
|
|
|
|
$current_relationships{$relname} = 1; |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
0
|
0
|
|
|
|
|
if ($foreign_class->can('meta_info')) { |
284
|
0
|
|
|
|
|
|
warn "foreign class has meta_info "; |
285
|
|
|
|
|
|
|
# warn Dumper($class->meta_info); |
286
|
0
|
|
|
|
|
|
my $meta_info = $foreign_class->meta_info; |
287
|
0
|
|
|
|
|
|
foreach my $relation_type ( keys %$meta_info ) { |
288
|
0
|
0
|
|
|
|
|
next if ($relation_type eq 'is_a'); |
289
|
0
|
|
|
|
|
|
foreach my $relname (keys %{$meta_info->{$relation_type}}) { |
|
0
|
|
|
|
|
|
|
290
|
0
|
|
|
|
|
|
warn "adding new relationship : $relname \n"; |
291
|
0
|
|
|
|
|
|
$fields->{$relname} = 1; |
292
|
0
|
|
|
|
|
|
$self->_inject_inherited_method($class, $relname); |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
} |
295
|
|
|
|
|
|
|
} |
296
|
0
|
|
|
|
|
|
return $fields; |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
sub _inject_inherited_method { |
300
|
0
|
|
|
0
|
|
|
my ($self,$class,$accessor_name) = @_; |
301
|
0
|
|
|
|
|
|
my $parent_accessor = $self->accessor; |
302
|
|
|
|
|
|
|
my $method = sub { |
303
|
0
|
|
|
0
|
|
|
warn "injected method $accessor_name , calling $accessor_name on parent via $parent_accessor \n"; |
304
|
0
|
|
|
|
|
|
warn "..called with args ", join(', ',@_), "\n"; |
305
|
0
|
|
|
|
|
|
my ($self, @args) = @_; |
306
|
0
|
|
|
|
|
|
$self->$parent_accessor->$accessor_name(@args); |
307
|
0
|
|
|
|
|
|
}; |
308
|
|
|
|
|
|
|
{ |
309
|
1
|
|
|
1
|
|
5
|
no strict "refs"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
909
|
|
|
0
|
|
|
|
|
|
|
310
|
0
|
|
|
|
|
|
*{"${class}::${accessor_name}"} = $method; |
|
0
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
sub _creator { |
315
|
0
|
|
|
0
|
|
|
my $proto = shift; |
316
|
0
|
|
|
|
|
|
my $col = $proto->accessor; |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
return sub { |
319
|
0
|
|
|
0
|
|
|
my $self = shift; |
320
|
0
|
|
|
|
|
|
my $meta = $self->meta_info(is_a => $col); |
321
|
0
|
|
|
|
|
|
my $f_class = $meta->foreign_class; |
322
|
|
|
|
|
|
|
|
323
|
0
|
|
|
|
|
|
my $hash = { }; |
324
|
|
|
|
|
|
|
|
325
|
0
|
|
|
|
|
|
foreach ($self->__grouper->group_cols('TEMP')) { |
326
|
0
|
0
|
|
|
|
|
next unless defined($self->_attrs($_)); |
327
|
0
|
|
|
|
|
|
$hash->{$_} = $self->_attrs($_); |
328
|
|
|
|
|
|
|
} |
329
|
0
|
|
|
|
|
|
my $f_pk = $f_class->primary_column; |
330
|
0
|
0
|
|
|
|
|
if ($self->_attrs($f_pk)) { |
331
|
0
|
|
|
|
|
|
$hash->{$f_pk} = $self->_attrs($f_pk); |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
0
|
|
|
|
|
|
my $f_obj = $f_class->create($hash); |
335
|
0
|
|
|
|
|
|
$proto->_import_column_values($self, $f_class, $f_obj); |
336
|
|
|
|
|
|
|
|
337
|
0
|
|
|
|
|
|
return $self->_attribute_store($col => $f_obj->id); |
338
|
0
|
|
|
|
|
|
}; |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
sub _inflator { |
342
|
0
|
|
|
0
|
|
|
my $proto = shift; |
343
|
0
|
|
|
|
|
|
my $col = $proto->accessor; |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
return sub { |
346
|
0
|
|
|
0
|
|
|
my $self = shift; |
347
|
0
|
|
|
|
|
|
my $value = $self->$col; |
348
|
0
|
|
|
|
|
|
my $meta = $self->meta_info(is_a => $col); |
349
|
0
|
|
|
|
|
|
my $f_class = $meta->foreign_class; |
350
|
|
|
|
|
|
|
|
351
|
0
|
0
|
0
|
|
|
|
return if ref($value) and $value->isa($f_class); |
352
|
|
|
|
|
|
|
|
353
|
0
|
|
|
|
|
|
$value = $f_class->_simple_bless($value); |
354
|
0
|
|
|
|
|
|
$proto->_import_column_values($self, $f_class, $value); |
355
|
|
|
|
|
|
|
|
356
|
0
|
|
|
|
|
|
return $self->_attribute_store($col => $value); |
357
|
0
|
|
|
|
|
|
}; |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
sub _import_column_values { |
361
|
0
|
|
|
0
|
|
|
my ($self, $class, $f_class, $f_obj) = (@_); |
362
|
0
|
|
|
|
|
|
foreach ($f_class->all_columns) { |
363
|
0
|
0
|
|
|
|
|
$class->_attribute_store($_, $f_obj->$_) |
364
|
|
|
|
|
|
|
unless $_->name eq $class->primary_column->name; |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
} |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
sub _set_up_class_data { |
369
|
0
|
|
|
0
|
|
|
my $self = shift; |
370
|
0
|
|
|
|
|
|
$self->class->_extend_class_data(__isa_rels => $self->accessor => |
371
|
0
|
|
|
|
|
|
[ $self->foreign_class, %{ $self->args } ]); |
372
|
0
|
|
|
|
|
|
$self->SUPER::_set_up_class_data; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
sub _get_methods { |
377
|
0
|
|
|
0
|
|
|
my ($self, $acc_name, $f_col, $mode) = @_; |
378
|
0
|
|
|
|
|
|
warn "_get_methods $acc_name, $f_col, $mode \n"; |
379
|
0
|
|
|
|
|
|
warn join(', ',caller()); |
380
|
0
|
|
|
|
|
|
my $method; |
381
|
|
|
|
|
|
|
MODE: { |
382
|
0
|
0
|
|
|
|
|
if ($mode eq 'rw') { |
|
0
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
$method = sub { |
384
|
0
|
|
|
0
|
|
|
warn "artificial method $acc_name/$f_col called with args ", join(', ',@_), "\n"; |
385
|
0
|
|
|
|
|
|
my ($self, @args) = @_; |
386
|
0
|
0
|
|
|
|
|
if(@args) { |
387
|
0
|
|
|
|
|
|
$self->$acc_name->$f_col(@args); |
388
|
0
|
|
|
|
|
|
return; |
389
|
|
|
|
|
|
|
} else { |
390
|
0
|
|
|
|
|
|
return $self->$acc_name->$f_col; |
391
|
|
|
|
|
|
|
} |
392
|
0
|
|
|
|
|
|
}; |
393
|
0
|
|
|
|
|
|
last MODE; |
394
|
|
|
|
|
|
|
} |
395
|
0
|
0
|
|
|
|
|
if ($mode eq 'ro') { |
396
|
|
|
|
|
|
|
$method = sub { |
397
|
0
|
|
|
0
|
|
|
my $self = shift; |
398
|
0
|
|
|
|
|
|
return $self->$acc_name->$f_col; |
399
|
0
|
|
|
|
|
|
}; |
400
|
0
|
|
|
|
|
|
last MODE; |
401
|
|
|
|
|
|
|
} |
402
|
0
|
0
|
|
|
|
|
if ($mode eq 'wo') { |
403
|
|
|
|
|
|
|
$method = sub { |
404
|
0
|
|
|
0
|
|
|
my $self = shift; |
405
|
0
|
|
|
|
|
|
$self->$acc_name->$f_col(@_); |
406
|
0
|
|
|
|
|
|
return; |
407
|
0
|
|
|
|
|
|
}; |
408
|
0
|
|
|
|
|
|
last MODE; |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
else { |
412
|
0
|
|
|
|
|
|
die "can't get method for mode :$mode\n"; |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
} # end of MODE |
415
|
0
|
|
|
|
|
|
return $method; |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
################################################################################ |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
=head1 BUGS AND CAVEATS |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
* Multiple inheritance is not supported, this is unlikely to change for the forseable future |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
* is_a must be called after all other cdbi relationship methods otherwise inherited methods and |
425
|
|
|
|
|
|
|
accessors may be over-ridden or clash unexpectedly |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
* non Class::DBI attributes and methods are not inherited via this module |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
* The update method is called on the inherited object when the inhertiting object has update called |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
* Always specify the primary key using columns(Primary => qw/../) if you don't bad things could happen, think of the movies 'Tremors', 'Poltergeist' and 'Evil Dead' all rolled into one but without any heros. |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
* Very Bad Things can and may occur when using this module even if you use good practice and are cautious -- this includes but is not limited to infinite loops, memory leaks and data corruption. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=head1 DEPENDANCIES |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
L |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
=head1 SEE ALSO |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
L |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
L |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
L |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=head1 AUTHOR |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
Richard Hundt, Erichard@webtk.org.ukE |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=head1 MAINTAINER |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
Aaron Trevena Eaaron.trevena@droogs.orgE |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
=head1 COPYRIGHT |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
Licensed for use, modification and distribution under the Artistic |
458
|
|
|
|
|
|
|
and GNU GPL licenses. |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
Copyright (C) 2004 by Richard Hundt and Aaron Trevena |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
463
|
|
|
|
|
|
|
it under the same terms as Perl itself, either Perl version 5.8.1 or, |
464
|
|
|
|
|
|
|
at your option, any later version of Perl 5 you may have available. |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=cut |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
################################################################################ |
470
|
|
|
|
|
|
|
################################################################################ |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
1; |
473
|
|
|
|
|
|
|
|