]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Utils/Fieldmapper.pm
new protofields
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Utils / Fieldmapper.pm
1 package Fieldmapper;
2 use JSON;
3 use Data::Dumper;
4 use base 'OpenSRF::Application';
5
6 use OpenSRF::Utils::Logger;
7 my $log = 'OpenSRF::Utils::Logger';
8
9 use OpenILS::Application::Storage::CDBI;
10 use OpenILS::Application::Storage::CDBI::actor;
11 use OpenILS::Application::Storage::CDBI::biblio;
12 use OpenILS::Application::Storage::CDBI::config;
13 use OpenILS::Application::Storage::CDBI::metabib;
14
15 use vars qw/$fieldmap $VERSION/;
16
17 _init();
18
19 sub publish_fieldmapper {
20         my ($self,$client,$class) = @_;
21
22         return $fieldmap unless (defined $class);
23         return undef unless (exists($$fieldmap{$class}));
24         return {$class => $$fieldmap{$class}};
25 }
26 __PACKAGE__->register_method(
27         api_name        => 'opensrf.open-ils.system.fieldmapper',
28         api_level       => 1,
29         method          => 'publish_fieldmapper',
30 );
31
32 #
33 # To dump the Javascript version of the fieldmapper struct use the command:
34 #
35 #       PERL5LIB=~/cvs/ILS/OpenSRF/src/perlmods/:~/cvs/ILS/Open-ILS/src/perlmods/ GEN_JS=1 perl -MOpenILS::Utils::Fieldmapper -e 'print "\n";'
36 #
37 # ... adjusted for your CVS sandbox, of course.
38 #
39
40 sub classes {
41         return () unless (defined $fieldmap);
42         return keys %$fieldmap;
43 }
44
45 sub _init {
46         return if (defined $fieldmap);
47
48         $fieldmap = 
49         {
50                 'Fieldmapper::actor::user'                      => { hint => 'au'   },
51                 'Fieldmapper::actor::org_unit'                  => { hint               => 'aou',
52                                                                      proto_fields       => { children => 1 } },
53                 'Fieldmapper::actor::org_unit_type'             => { hint               => 'aout',
54                                                                      proto_fields       => { children => 1 } },
55                 
56                 'Fieldmapper::biblio::record_node'              => { hint               => 'brn',
57                                                                      proto_fields       => { children => 1 } },
58                 'Fieldmapper::biblio::record_entry'             => { hint               => 'bre',
59                                                                      proto_fields       => { call_numbers => 1 } },
60                 'Fieldmapper::biblio::record_mods'              => { hint => 'brm'  },
61                 'Fieldmapper::biblio::record_marc'              => { hint => 'brx'  },
62
63                 'Fieldmapper::config::bib_source'               => { hint => 'cbs'  },
64                 'Fieldmapper::config::metabib_field'            => { hint => 'cmf'  },
65
66                 'Fieldmapper::metabib::metarecord'              => { hint => 'mmr'  },
67                 'Fieldmapper::metabib::title_field_entry'       => { hint => 'mtfe' },
68                 'Fieldmapper::metabib::author_field_entry'      => { hint => 'mafe' },
69                 'Fieldmapper::metabib::subject_field_entry'     => { hint => 'msfe' },
70                 'Fieldmapper::metabib::keyword_field_entry'     => { hint => 'mkfe' },
71                 'Fieldmapper::metabib::full_rec'                => { hint => 'mfr'  },
72
73                 'Fieldmapper::asset::copy'                      => { hint => 'acp'  },
74                 'Fieldmapper::asset::copy_note'                 => { hint => 'acpn' },
75                 'Fieldmapper::asset::call_number'               => { hint               => 'acn',
76                                                                      proto_fields       => { copies => 1 } },
77                 'Fieldmapper::asset::call_number_note'          => { hint => 'acnn' },
78         };
79
80         #-------------------------------------------------------------------------------
81         # Now comes the evil!  Generate classes
82
83         for my $pkg ( keys %$fieldmap ) {
84                 (my $cdbi = $pkg) =~ s/^Fieldmapper:://o;
85
86                 eval <<"                PERL";
87                         package $pkg;
88                         use base 'Fieldmapper';
89                 PERL
90
91                 $$fieldmap{$pkg}{cdbi} = $cdbi;
92
93                 my $pos = 0;
94                 for my $vfield ( qw/isnew ischanged isdeleted/ ) {
95                         $$fieldmap{$pkg}{fields}{$vfield} = { position => $pos, virtual => 1 };
96                         $pos++;
97                 }
98
99                 if (exists $$fieldmap{$pkg}{proto_fields}) {
100                         for my $pfield ( keys %{ $$fieldmap{$pkg}{proto_fields} } ) {
101                                 $$fieldmap{$pkg}{fields}{$pfield} = { position => $pos, virtual => $$fieldmap{$pkg}{proto_fields}{$pfield} };
102                                 $pos++;
103                         }
104                 }
105
106                 for my $col ( $cdbi->columns('All') ) {
107                         $$fieldmap{$pkg}{fields}{$col} = { position => $pos, virtual => 0 };
108                         $pos++;
109                 }
110
111                 JSON->register_class_hint(
112                         hint => $pkg->json_hint,
113                         name => $pkg,
114                         type => 'array',
115                 );
116
117         }
118
119         print Fieldmapper->javascript() if ($ENV{GEN_JS});
120 }
121
122 sub new {
123         my $self = shift;
124         my $value = shift;
125         $value = [] unless (defined $value);
126         return bless $value => $self->class_name;
127 }
128
129 sub javascript {
130         my $class_name = shift;
131         return 'var fieldmap = ' . JSON->perl2JSON($fieldmap) . ';'
132 }
133
134 sub DESTROY {}
135
136 sub AUTOLOAD {
137         my $obj = shift;
138         my $value = shift;
139         (my $field = $AUTOLOAD) =~ s/^.*://o;
140         my $class_name = $obj->class_name;
141
142
143         if ($field =~ /^clear_/o) {
144                 {       no strict 'subs';
145                         *{$obj->class_name."::$field"} = sub {
146                                 my $self = shift;
147                                 $self->[$pos] = undef;
148                                 return 1;
149                         };
150                 }
151                 return $obj->$field();
152         }
153
154         die "No field by the name $field in $class_name!"
155                 unless (exists $$fieldmap{$class_name}{fields}{$field});
156
157         my $pos = $$fieldmap{$class_name}{fields}{$field}{position};
158
159         {       no strict 'subs';
160                 *{$obj->class_name."::$field"} = sub {
161                         my $self = shift;
162                         my $new_val = shift;
163                         $self->[$pos] = $new_val if (defined $new_val);
164                         return $self->[$pos];
165                 };
166         }
167         return $obj->$field($value);
168 }
169
170 sub class_name {
171         my $class_name = shift;
172         return ref($class_name) || $class_name;
173 }
174
175 sub real_fields {
176         my $self = shift;
177         my $class_name = $self->class_name;
178         my $fields = $$fieldmap{$class_name}{fields};
179
180         my @f = grep {
181                         !$$fields{$_}{virtual}
182                 } sort {$$fields{$a}{position} <=> $$fields{$b}{position}} keys %$fields;
183
184         return @f;
185 }
186
187 sub api_level {
188         my $self = shift;
189         return $fieldmap->{$self->class_name}->{api_level};
190 }
191
192 sub json_hint {
193         my $self = shift;
194         return $fieldmap->{$self->class_name}->{hint};
195 }
196
197
198 1;