]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Utils/Fieldmapper.pm
allow circ.reshelving_complete.interval ou setting to override the default reshelving...
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Utils / Fieldmapper.pm
1 package Fieldmapper;
2 use OpenSRF::Utils::JSON;
3 use Data::Dumper;
4 use base 'OpenSRF::Application';
5 use OpenSRF::Utils::Logger;
6 use OpenSRF::Utils::SettingsClient;
7 use OpenSRF::System;
8 use XML::Simple;
9
10 my $log = 'OpenSRF::Utils::Logger';
11
12 use vars qw/$fieldmap $VERSION/;
13
14 sub publish_fieldmapper {
15         my ($self,$client,$class) = @_;
16
17         return $fieldmap unless (defined $class);
18         return undef unless (exists($$fieldmap{$class}));
19         return {$class => $$fieldmap{$class}};
20 }
21 __PACKAGE__->register_method(
22         api_name        => 'opensrf.open-ils.system.fieldmapper',
23         api_level       => 1,
24         method          => 'publish_fieldmapper',
25 );
26
27 #
28 # To dump the Javascript version of the fieldmapper struct use the command:
29 #
30 #       PERL5LIB=~/cvs/ILS/OpenSRF/src/perlmods/:~/cvs/ILS/Open-ILS/src/perlmods/ GEN_JS=1 perl -MOpenILS::Utils::Fieldmapper -e 'print "\n";'
31 #
32 # ... adjusted for your CVS sandbox, of course.
33 #
34
35 sub classes {
36         return () unless (defined $fieldmap);
37         return keys %$fieldmap;
38 }
39
40 import();
41 sub import {
42         my $class = shift;
43         my %args = @_;
44
45         return if (keys %$fieldmap);
46         return if (!OpenSRF::System->connected && !$args{IDL});
47
48         # parse the IDL ...
49         my $file = $args{IDL} || OpenSRF::Utils::SettingsClient->new->config_value( 'IDL' );
50         my $idl = XMLin( $file, ForceArray => 0, KeyAttr => ['name', 'id'], ValueAttr => {link =>'key'} )->{class};
51         for my $c ( keys %$idl ) {
52                 next unless ($idl->{$c}{'oils_obj:fieldmapper'});
53                 my $n = 'Fieldmapper::'.$idl->{$c}{'oils_obj:fieldmapper'};
54
55                 $log->debug("Building Fieldmapper class for [$n] from IDL");
56
57                 $$fieldmap{$n}{hint} = $c;
58                 $$fieldmap{$n}{virtual} = ($idl->{$c}{'oils_persist:virtual'} eq 'true') ? 1 : 0;
59                 $$fieldmap{$n}{table} = $idl->{$c}{'oils_persist:tablename'};
60                 $$fieldmap{$n}{sequence} = $idl->{$c}{fields}{'oils_persist:sequence'};
61                 $$fieldmap{$n}{identity} = $idl->{$c}{fields}{'oils_persist:primary'};
62
63                 for my $f ( keys %{ $idl->{$c}{fields}{field} } ) {
64                         $$fieldmap{$n}{fields}{$f} =
65                                 { virtual => ($idl->{$c}{fields}{field}{$f}{'oils_persist:virtual'} eq 'true') ? 1 : 0,
66                                   position => $idl->{$c}{fields}{field}{$f}{'oils_obj:array_position'},
67                                 };
68
69                         if ($idl->{$c}{fields}{field}{$f}{'reporter:selector'}) {
70                                 $$fieldmap{$n}{selector} = $idl->{$c}{fields}{field}{$f}{'reporter:selector'};
71                         }
72                 }
73         }
74
75
76         #-------------------------------------------------------------------------------
77         # Now comes the evil!  Generate classes
78
79         for my $pkg ( __PACKAGE__->classes ) {
80                 (my $cdbi = $pkg) =~ s/^Fieldmapper:://o;
81
82                 eval <<"                PERL";
83                         package $pkg;
84                         use base 'Fieldmapper';
85                 PERL
86
87                 my $pos = 0;
88                 for my $vfield ( qw/isnew ischanged isdeleted/ ) {
89                         $$fieldmap{$pkg}{fields}{$vfield} = { position => $pos, virtual => 1 };
90                         $pos++;
91                 }
92
93                 if (exists $$fieldmap{$pkg}{proto_fields}) {
94                         for my $pfield ( sort keys %{ $$fieldmap{$pkg}{proto_fields} } ) {
95                                 $$fieldmap{$pkg}{fields}{$pfield} = { position => $pos, virtual => $$fieldmap{$pkg}{proto_fields}{$pfield} };
96                                 $pos++;
97                         }
98                 }
99
100                 OpenSRF::Utils::JSON->register_class_hint(
101                         hint => $pkg->json_hint,
102                         name => $pkg,
103                         type => 'array',
104                 );
105
106         }
107 }
108
109 sub new {
110         my $self = shift;
111         my $value = shift;
112         $value = [] unless (defined $value);
113         return bless $value => $self->class_name;
114 }
115
116 sub decast {
117         my $self = shift;
118         return [ @$self ];
119 }
120
121 sub DESTROY {}
122
123 sub AUTOLOAD {
124         my $obj = shift;
125         my $value = shift;
126         (my $field = $AUTOLOAD) =~ s/^.*://o;
127         my $class_name = $obj->class_name;
128
129         my $fpos = $field;
130         $fpos  =~ s/^clear_//og ;
131
132         my $pos = $$fieldmap{$class_name}{fields}{$fpos}{position};
133
134         if ($field =~ /^clear_/o) {
135                 {       no strict 'subs';
136                         *{$obj->class_name."::$field"} = sub {
137                                 my $self = shift;
138                                 $self->[$pos] = undef;
139                                 return 1;
140                         };
141                 }
142                 return $obj->$field();
143         }
144
145         die "No field by the name $field in $class_name!"
146                 unless (exists $$fieldmap{$class_name}{fields}{$field} && defined($pos));
147
148
149         {       no strict 'subs';
150                 *{$obj->class_name."::$field"} = sub {
151                         my $self = shift;
152                         my $new_val = shift;
153                         $self->[$pos] = $new_val if (defined $new_val);
154                         return $self->[$pos];
155                 };
156         }
157         return $obj->$field($value);
158 }
159
160 sub Selector {
161         my $self = shift;
162         return $$fieldmap{$self->class_name}{selector};
163 }
164
165 sub Identity {
166         my $self = shift;
167         return $$fieldmap{$self->class_name}{identity};
168 }
169
170 sub Sequence {
171         my $self = shift;
172         return $$fieldmap{$self->class_name}{sequence};
173 }
174
175 sub Table {
176         my $self = shift;
177         return $$fieldmap{$self->class_name}{table};
178 }
179
180 sub class_name {
181         my $class_name = shift;
182         return ref($class_name) || $class_name;
183 }
184
185 sub real_fields {
186         my $self = shift;
187         my $class_name = $self->class_name;
188         my $fields = $$fieldmap{$class_name}{fields};
189
190         my @f = grep {
191                         !$$fields{$_}{virtual}
192                 } sort {$$fields{$a}{position} <=> $$fields{$b}{position}} keys %$fields;
193
194         return @f;
195 }
196
197 sub has_field {
198         my $self = shift;
199         my $field = shift;
200         my $class_name = $self->class_name;
201         return 1 if grep { $_ eq $field } keys %{$$fieldmap{$class_name}{fields}};
202         return 0;
203 }
204
205 sub properties {
206         my $self = shift;
207         my $class_name = $self->class_name;
208         return keys %{$$fieldmap{$class_name}{fields}};
209 }
210
211 sub to_bare_hash {
212         my $self = shift;
213
214         my %hash = ();
215         for my $f ($self->properties) {
216                 my $val = $self->$f;
217                 $hash{$f} = $val;
218         }
219
220         return \%hash;
221 }
222
223 sub clone {
224         my $self = shift;
225         return $self->new( [@$self] );
226 }
227
228 sub api_level {
229         my $self = shift;
230         return $fieldmap->{$self->class_name}->{api_level};
231 }
232
233 sub cdbi {
234         my $self = shift;
235         return $fieldmap->{$self->class_name}->{cdbi};
236 }
237
238 sub is_virtual {
239         my $self = shift;
240         my $field = shift;
241         return $fieldmap->{$self->class_name}->{proto_fields}->{$field} if ($field);
242         return $fieldmap->{$self->class_name}->{virtual};
243 }
244
245 sub is_readonly {
246         my $self = shift;
247         my $field = shift;
248         return $fieldmap->{$self->class_name}->{readonly};
249 }
250
251 sub json_hint {
252         my $self = shift;
253         return $fieldmap->{$self->class_name}->{hint};
254 }
255
256
257 1;