File Coverage

blib/lib/DBIx/BabelKit.pm
Criterion Covered Total %
statement 15 327 4.5
branch 0 156 0.0
condition 0 63 0.0
subroutine 5 30 16.6
pod 2 19 10.5
total 22 595 3.7


line stmt bran cond sub pod time code
1             package DBIx::BabelKit;
2              
3 1     1   36063 use strict;
  1         2  
  1         36  
4 1     1   6 use warnings;
  1         2  
  1         29  
5 1     1   5 use Carp;
  1         6  
  1         60  
6              
7 1     1   4 use vars qw( $VERSION );
  1         2  
  1         3303  
8             $VERSION = '1.07';
9              
10             =head1 NAME
11              
12             DBIx::BabelKit - Universal Multilingual Code Table Interface
13              
14             =head1 SYNOPSIS
15              
16             use DBIx::BabelKit;
17            
18             my $bk = new DBIx::BabelKit($dbh,
19             table => 'bk_code',
20             getparam => sub { $cgi->param(shift) },
21             getparams => sub { $cgi->param(shift.'[]') }
22             );
23              
24             =cut
25              
26             ### See the rest of the pod documentation at the end of this file. ###
27              
28             sub new {
29 0     0 0   my $class = shift;
30 0           my $dbh = shift;
31 0 0         my $args = ref($_[0]) ? shift : { @_ };
32 0           my $self = {};
33 0           bless $self, $class;
34              
35 0 0         croak 'DBIx::BabelKit->new($dbh): $dbh is not an object' unless ref $dbh;
36 0           $self->{dbh} = $dbh;
37              
38 0   0       $self->{table} = $args->{table} || 'bk_code';
39 0           $self->{getparam} = $args->{getparam};
40 0           $self->{getparams} = $args->{getparams};
41 0           $self->{native} = $self->_find_native;
42 0 0         croak "DBIx::BabelKit::new: unable to determine native language" .
43             " Check table '$self->{table}' for code_admin/code_admin record."
44             unless $self->{native};
45              
46 0           return $self;
47             }
48              
49              
50             # # # HTML display methods.
51              
52             sub desc {
53 0     0 0   my $self = shift;
54 0           return &htmlspecialchars( $self->render(@_) );
55             }
56              
57             sub ucfirst {
58 0     0 0   my $self = shift;
59 0           return CORE::ucfirst( $self->desc(@_) );
60             }
61              
62             sub ucwords {
63 0     0 0   my $self = shift;
64 0           my $str = $self->desc(@_);
65 0           $str =~ s/(^|\s)([a-z])/$1\u$2/g;
66 0           return $str;
67             }
68              
69              
70             # # # Data methods.
71              
72             sub render {
73 0     0 0   my $self = shift;
74 0           my $code_desc = $self->data(@_);
75 0 0         if ($code_desc eq '') {
76 0           $code_desc = $self->data($_[0], $self->{native}, $_[2]);
77 0 0         if ($code_desc eq '') {
78 0   0       $code_desc = $_[2] || '';
79             }
80             }
81 0           return $code_desc;
82             }
83              
84             sub data {
85 0     0 0   my $self = shift;
86 0           my $code_set = shift;
87 0           my $code_lang = shift;
88 0           my $code_code = shift;
89 0           $code_code .= ''; # DBI needs strings here.
90 0 0         $self->{data_sth} = $self->{dbh}->prepare("
91             select code_desc
92             from $self->{table}
93             where code_set = ?
94             and code_lang = ?
95             and code_code = ?
96             ") unless $self->{data_sth};
97 0           $self->{data_sth}->execute($code_set, $code_lang, $code_code);
98 0           my $code_desc = $self->{data_sth}->fetchrow;
99 0 0         $code_desc = '' unless defined $code_desc; # Avoid warnings.
100 0           return $code_desc;
101             }
102              
103             sub param {
104 0     0 0   my $self = shift;
105 0           return $self->data($_[0], $self->{native}, $_[1]);
106             }
107              
108              
109             # # # HTML select single value methods:
110              
111             sub select {
112 0     0 1   my $self = shift;
113 0           my $code_set = shift;
114 0           my $code_lang = shift;
115 0 0         my $args = ref($_[0]) ? shift : { @_ };
116              
117 0   0       my $var_name = $args->{var_name} || $code_set;
118 0           my $value = $args->{value};
119 0           my $default = $args->{default};
120 0           my $subset = $args->{subset};
121 0           my $options = $args->{options};
122 0           my $select_prompt = $args->{select_prompt};
123 0           my $blank_prompt = $args->{blank_prompt};
124              
125             # Variable setup.
126 0           $value = $self->_getparam($var_name, $value, $default);
127 0           my $Subset = &keyme($subset);
128 0 0         $options = $options ? " $options" : '';
129 0 0         $select_prompt = '' unless defined $select_prompt;
130 0 0         $blank_prompt = '' unless defined $blank_prompt;
131              
132             # Drop down box.
133 0           my $select = "
134              
135             # Blank options.
136 0           my $selected = '';
137 0 0         if ($value eq '') {
    0          
138 0 0         if ($select_prompt eq '') {
139 0           $select_prompt =
140             $self->ucwords('code_set', $code_lang, $code_set) . '?';
141             }
142 0           $select .= "
143 0           $selected = 1;
144             } elsif ($blank_prompt ne '') {
145 0           $select .= "
146             }
147              
148             # Show code set options.
149 0           my $set_list = $self->full_set($code_set, $code_lang);
150 0           for my $row ( @$set_list ) {
151 0           my ($code_code, $code_desc) = @$row;
152 0 0 0       next if ($Subset && !$Subset->{$code_code} && $code_code ne $value);
      0        
153 0           $code_desc = htmlspecialchars(CORE::ucfirst($code_desc));
154              
155 0 0         if ($code_code eq $value) {
    0          
156 0           $selected = 1;
157 0           $select .= "
158             } elsif ($row->[3] ne 'd') {
159 0           $select .= "
160             }
161             }
162              
163             # Show a missing value.
164 0 0         if (!$selected) {
165 0           $select .= "
166             }
167              
168 0           $select .= "\n";
169 0           return $select;
170             }
171              
172             sub radio {
173 0     0 0   my $self = shift;
174 0           my $code_set = shift;
175 0           my $code_lang = shift;
176 0 0         my $args = ref($_[0]) ? shift : { @_ };
177              
178 0   0       my $var_name = $args->{var_name} || $code_set;
179 0           my $value = $args->{value};
180 0           my $default = $args->{default};
181 0           my $subset = $args->{subset};
182 0           my $options = $args->{options};
183 0           my $blank_prompt = $args->{blank_prompt};
184 0           my $sep = $args->{sep};
185              
186             # Variable setup.
187 0           $value = $self->_getparam($var_name, $value, $default);
188 0           my $Subset = &keyme($subset);
189 0 0         $options = $options ? " $options" : '';
190 0 0         $blank_prompt = '' unless defined $blank_prompt;
191 0 0         $sep = "
\n" unless defined $sep;
192              
193             # Blank options.
194 0           my $select = '';
195 0           my $selected = '';
196 0 0         if ($value eq '') {
197 0           $selected = 1;
198 0 0         if ($blank_prompt ne '') {
199 0           $select .= "
200 0           $select .= " value=\"\" checked>$blank_prompt";
201             }
202             } else {
203 0 0         if ($blank_prompt ne '') {
204 0           $select .= "
205 0           $select .= " value=\"\">$blank_prompt";
206             }
207             }
208              
209             # Show code set options.
210 0           my $set_list = $self->full_set($code_set, $code_lang);
211 0           for my $row ( @$set_list ) {
212 0           my ($code_code, $code_desc) = @$row;
213 0 0 0       next if ($Subset && !$Subset->{$code_code} && $code_code ne $value);
      0        
214 0           $code_desc = htmlspecialchars(CORE::ucfirst($code_desc));
215 0 0         if ( $code_code eq $value ) {
    0          
216 0           $selected = 1;
217 0 0         $select .= $sep if $select;
218 0           $select .= "
219 0           $select .= " value=\"$code_code\" checked>$code_desc";
220             } elsif ($row->[3] ne 'd') {
221 0 0         $select .= $sep if $select;
222 0           $select .= "
223 0           $select .= " value=\"$code_code\">$code_desc";
224             }
225             }
226              
227             # Show missing values.
228 0 0         if (!$selected) {
229 0 0         $select .= $sep if $select;
230 0           $select .= "
231 0           $select .= " value=\"$value\" checked>$value";
232             }
233              
234 0           return $select;
235             }
236              
237              
238             # # # HTML select multiple value methods:
239              
240             sub multiple {
241 0     0 1   my $self = shift;
242 0           my $code_set = shift;
243 0           my $code_lang = shift;
244 0 0         my $args = ref($_[0]) ? shift : { @_ };
245              
246 0   0       my $var_name = $args->{var_name} || $code_set;
247 0           my $value = $args->{value};
248 0           my $default = $args->{default};
249 0           my $subset = $args->{subset};
250 0           my $options = $args->{options};
251 0           my $size = $args->{size};
252              
253             # Variable setup.
254 0           my $Value = $self->_getparams($var_name, $value, $default);
255 0           my $Subset = &keyme($subset);
256 0 0         $options = $options ? " $options" : '';
257              
258             # Select multiple box.
259 0           my $select = "
260 0 0         $select .= " size=\"$size\"" if ($size);
261 0           $select .= ">\n";
262              
263             # Show code set options.
264 0           my $set_list = $self->full_set($code_set, $code_lang);
265 0           for my $row ( @$set_list ) {
266 0           my ($code_code, $code_desc) = @$row;
267 0 0 0       next if ($Subset && !$Subset->{$code_code} && !$Value->{$code_code});
      0        
268 0           $code_desc = htmlspecialchars(CORE::ucfirst($code_desc));
269 0 0         if ( $Value->{$code_code} ) {
    0          
270 0           $select .= "
271 0           delete $Value->{$code_code};
272             } elsif ($row->[3] ne 'd') {
273 0           $select .= "
274             }
275             }
276              
277             # Show missing values.
278 0           for my $code_code ( keys %$Value ) {
279 0           $select .= "
280             }
281              
282 0           $select .= "\n";
283 0           return $select;
284             }
285              
286             sub checkbox {
287 0     0 0   my $self = shift;
288 0           my $code_set = shift;
289 0           my $code_lang = shift;
290 0 0         my $args = ref($_[0]) ? shift : { @_ };
291              
292 0   0       my $var_name = $args->{var_name} || $code_set;
293 0           my $value = $args->{value};
294 0           my $default = $args->{default};
295 0           my $subset = $args->{subset};
296 0           my $options = $args->{options};
297 0           my $sep = $args->{sep};
298              
299             # Variable setup.
300 0           my $Value = $self->_getparams($var_name, $value, $default);
301 0           my $Subset = &keyme($subset);
302 0 0         $options = $options ? " $options" : '';
303 0 0         $sep = "
\n" unless defined $sep;
304              
305             # Show code set options.
306 0           my $select;
307 0           my $set_list = $self->full_set($code_set, $code_lang);
308 0           for my $row ( @$set_list ) {
309 0           my ($code_code, $code_desc) = @$row;
310 0 0 0       next if ($Subset && !$Subset->{$code_code} && !$Value->{$code_code});
      0        
311 0           $code_desc = htmlspecialchars(CORE::ucfirst($code_desc));
312 0 0         if ( $Value->{$code_code} ) {
    0          
313 0 0         $select .= $sep if $select;
314 0           $select .= "
315 0           $select .= "$options value=\"$code_code\" checked>$code_desc";
316 0           delete $Value->{$code_code};
317             } elsif ($row->[3] ne 'd') {
318 0 0         $select .= $sep if $select;
319 0           $select .= "
320 0           $select .= "$options value=\"$code_code\">$code_desc";
321             }
322             }
323              
324             # Show missing values.
325 0           for my $code_code ( keys %$Value ) {
326 0 0         $select .= $sep if $select;
327 0           $select .= "
328 0           $select .= "$options value=\"$code_code\" checked>$code_code";
329             }
330              
331 0           return $select;
332             }
333              
334              
335             # # # Code Set Methods.
336              
337             sub lang_set {
338 0     0 0   my $self = shift;
339 0           my $code_set = shift;
340 0           my $code_lang = shift;
341 0 0         $self->{set_sth} = $self->{dbh}->prepare("
342             select code_code,
343             code_desc,
344             code_order,
345             code_flag
346             from $self->{table}
347             where code_set = ?
348             and code_lang = ?
349             order by code_order, code_code
350             ") unless $self->{set_sth};
351 0           $self->{set_sth}->execute($code_set, $code_lang);
352 0           return $self->{set_sth}->fetchall_arrayref;
353             }
354              
355             sub full_set {
356 0     0 0   my $self = shift;
357 0           my $code_set = shift;
358 0           my $code_lang = shift;
359              
360 0           my $native = $self->lang_set($code_set, $self->{native});
361 0 0         return $native if ($code_lang eq $self->{native});
362              
363 0           my $other = $self->lang_set($code_set, $code_lang);
364 0           my $lookup = {};
365 0           for my $row ( @$other ) { $lookup->{$row->[0]} = $row->[1]; }
  0            
366              
367 0           for ( my $i = 0; $i < @$native; $i++ ) {
368 0           my $code_desc = $lookup->{$native->[$i][0]};
369 0 0         $native->[$i][1] = $code_desc if defined $code_desc;
370             }
371              
372 0           return $native;
373             }
374              
375              
376             # # # Code Table Updates.
377              
378             sub slave {
379 0     0 0   my $self = shift;
380 0           my $code_set = shift;
381 0           my $code_code = shift;
382 0           my $code_desc = shift;
383 0 0         $code_desc = '' unless defined $code_desc;
384 0           my @old = $self->get($code_set, $self->{native}, $code_code);
385 0 0         if (@old) {
386 0           my ( $old_desc, $old_order, $old_flag ) = @old;
387 0 0         if ($code_desc ne $old_desc) {
388 0           $self->put($code_set, $self->{native}, $code_code, $code_desc,
389             $old_order, $old_flag);
390             }
391             } else {
392 0           $self->put($code_set, $self->{native}, $code_code, $code_desc);
393             }
394             }
395              
396             sub remove {
397 0     0 0   my $self = shift;
398 0           my $code_set = shift;
399 0           my $code_code = shift;
400 0           $code_code .= ''; # DBI needs strings here.
401 0 0         $self->{remove_sth} = $self->{dbh}->prepare("
402             delete from $self->{table}
403             where code_set = ?
404             and code_code = ?
405             ") unless $self->{remove_sth};
406 0           $self->{remove_sth}->execute($code_set, $code_code);
407             }
408              
409             sub get {
410 0     0 0   my $self = shift;
411 0           my $code_set = shift;
412 0           my $code_lang = shift;
413 0           my $code_code = shift;
414 0 0         $self->{get_sth} = $self->{dbh}->prepare("
415             select code_desc,
416             code_order,
417             code_flag
418             from $self->{table}
419             where code_set = ?
420             and code_lang = ?
421             and code_code = ?
422             ") unless $self->{get_sth};
423 0           $self->{get_sth}->execute($code_set, $code_lang, $code_code);
424 0           my @info = $self->{get_sth}->fetchrow_array;
425 0           return @info;
426             }
427              
428             sub put {
429 0     0 0   my $self = shift;
430 0           my $code_set = shift;
431 0           my $code_lang = shift;
432 0           my $code_code = shift;
433 0           my $code_desc = shift;
434 0           my $code_order = shift;
435 0           my $code_flag = shift;
436              
437             # Get the existing code info, if any.
438 0           my @old = $self->get($code_set, $code_lang, $code_code);
439              
440             # Field work.
441 0           $code_code .= ''; # DBI needs strings here.
442 0           $code_desc .= '';
443 0 0         if ($code_lang eq $self->{native}) {
444 0 0 0       if ( !@old and $code_code =~ /^\d+$/ and
      0        
      0        
445             ( not defined($code_order) or $code_order eq '' ) ) {
446 0           $code_order = $code_code;
447             }
448             { # Argument "" isn't numeric in int. Isn't that int's job?
449 1     1   6 no warnings;
  1         1  
  1         871  
  0            
450 0           $code_order = int($code_order);
451             }
452 0           $code_flag .= '';
453             } else {
454 0           $code_order = 0;
455 0           $code_flag = '';
456             }
457              
458             # Make it so: add, update, or delete.
459 0 0         if (@old) {
    0          
460 0           my ( $old_desc, $old_order, $old_flag ) = @old;
461 0 0         if ($code_desc ne '') {
462 0 0 0       if ($code_desc ne $old_desc ||
      0        
463             $code_order ne $old_order ||
464             $code_flag ne $old_flag) {
465 0           $self->_update($code_set, $code_lang, $code_code,
466             $code_desc, $code_order, $code_flag);
467             }
468             }
469             else {
470 0 0         if ($code_lang eq $self->{native}) {
471 0           $self->remove($code_set, $code_code);
472             } else {
473 0           $self->_delete($code_set, $code_lang, $code_code);
474             }
475             }
476             }
477             elsif ($code_desc ne '') {
478 0           $self->_insert($code_set, $code_lang, $code_code,
479             $code_desc, $code_order, $code_flag);
480             }
481             }
482              
483              
484             # # # Private methods.
485              
486             sub _find_native {
487 0     0     my $self = shift;
488 0           my $sth = $self->{dbh}->prepare("
489             select code_lang
490             from $self->{table}
491             where code_set = 'code_admin'
492             and code_code = 'code_admin'
493             ");
494 0           $sth->execute;
495 0           my $native = $sth->fetchrow;
496 0           return $native;
497             }
498              
499             sub _insert {
500 0     0     my $self = shift;
501 0 0         $self->{insert_sth} = $self->{dbh}->prepare("
502             insert into $self->{table} set
503             code_set = ?,
504             code_lang = ?,
505             code_code = ?,
506             code_desc = ?,
507             code_order = ?,
508             code_flag = ?
509             ") unless $self->{insert_sth};
510 0           $self->{insert_sth}->execute(@_);
511             }
512              
513             sub _update {
514 0     0     my $self = shift;
515 0           my $code_set = shift;
516 0           my $code_lang = shift;
517 0           my $code_code = shift;
518 0           my $code_desc = shift;
519 0           my $code_order = shift;
520 0           my $code_flag = shift;
521 0 0         $self->{update_sth} = $self->{dbh}->prepare("
522             update $self->{table} set
523             code_desc = ?,
524             code_order = ?,
525             code_flag = ?
526             where code_set = ?
527             and code_lang = ?
528             and code_code = ?
529             ") unless $self->{update_sth};
530 0           $self->{update_sth}->execute(
531             $code_desc,
532             $code_order,
533             $code_flag,
534             $code_set,
535             $code_lang,
536             $code_code
537             );
538             }
539              
540             sub _delete {
541 0     0     my $self = shift;
542 0 0         $self->{delete_sth} = $self->{dbh}->prepare("
543             delete from $self->{table}
544             where code_set = ?
545             and code_lang = ?
546             and code_code = ?
547             ") unless $self->{delete_sth};
548 0           $self->{delete_sth}->execute(@_);
549             }
550              
551             sub _getparam {
552 0     0     my $self = shift;
553 0           my $var_name = shift;
554 0           my $value = shift;
555 0           my $default = shift;
556 0 0         if ( not defined $value ) {
557 0 0         if ( $self->{getparam} ) {
558 0           $value = &{$self->{getparam}}($var_name);
  0            
559             }
560 0 0         $value = $default unless defined $value;
561 0 0         $value = '' unless defined $value;
562             }
563 0           return $value;
564             }
565              
566             sub _getparams {
567 0     0     my $self = shift;
568 0           my $var_name = shift;
569 0           my $value = shift;
570 0           my $default = shift;
571 0 0         if ( not defined $value ) {
572 0 0         my $call = $self->{getparams} ? $self->{getparams} : $self->{getparam};
573 0 0         if ( $call ) {
574 0           $value = [ grep { defined $_ } &$call($var_name) ];
  0            
575 0 0         $value = $value->[0] if ref $value->[0];
576             }
577 0 0         $value = $default unless defined $value;
578 0 0         $value = '' unless defined $value;
579             }
580 0   0       return &keyme($value) || {};
581             }
582              
583             sub keyme {
584 0     0 0   my $value = shift;
585 0 0         return $value if ref($value) eq 'HASH';
586 0           my $Keyhash;
587 0 0 0       if (ref($value) eq 'ARRAY') {
    0 0        
588 0           for my $val ( @$value ) { $Keyhash->{$val} = 1; }
  0            
589             } elsif (defined($value) && $value ne '' && !ref($value)) {
590 0           $Keyhash->{$value} = 1;
591             }
592 0           return $Keyhash;
593             }
594              
595             sub htmlspecialchars {
596 0     0 0   my $str = shift;
597 0           $str =~ s/&/\&/g;
598 0           $str =~ s/"/\"/g;
599 0           $str =~ s/
600 0           $str =~ s/>/\>/g;
601 0           return $str;
602             }
603              
604             1;
605              
606             __END__