File Coverage

blib/lib/SQLite/Work/CGI.pm
Criterion Covered Total %
statement 15 600 2.5
branch 0 200 0.0
condition 0 39 0.0
subroutine 5 25 20.0
pod 20 20 100.0
total 40 884 4.5


line stmt bran cond sub pod time code
1             package SQLite::Work::CGI;
2             $SQLite::Work::CGI::VERSION = '0.16';
3 1     1   2651 use strict;
  1         1  
  1         32  
4 1     1   4 use warnings;
  1         1  
  1         25  
5              
6             =head1 NAME
7              
8             SQLite::Work::CGI - Report and update a SQLite database using CGI
9              
10             =head1 VERSION
11              
12             version 0.16
13              
14             =head1 SYNOPSIS
15              
16             use SQLite::Work::CGI;
17              
18             my $obj = SQLite::Work::CGI->new(%args);
19              
20             =head1 DESCRIPTION
21              
22             This module is an expansion of SQLite::Work suitable for use
23             in a CGI script to report and update a SQLite database.
24              
25             =cut
26              
27 1     1   1232 use CGI;
  1         10164  
  1         8  
28 1     1   48 use POSIX;
  1         9  
  1         6  
29 1     1   1594 use SQLite::Work;
  1         2  
  1         5443  
30              
31             our @ISA = qw(SQLite::Work);
32              
33             =head1 CLASS METHODS
34              
35             =head2 new
36              
37             my $obj = SQLite::Work->new(
38             database=>$database_file,
39             row_ids=>{
40             episodes=>'title_id',
41             },
42             join_cols=>{
43             'episodes+recordings'=>'title_id',
44             }
45             },
46             report_template=>$report_template,
47             default_format=>{
48             'episodes' => {
49             'title'=>'title',
50             'series_title'=>'title',
51             }
52             },
53             input_format=>{
54             'reviews' => {
55             'Review'=>{
56             type=>'textarea',
57             cols=>60,
58             rows=>4,
59             }
60             }
61             },
62             max_sort_fields=>10,
63             sort_label=>'Zsort',
64             sort_reversed_prefix=>'Zsort_reversed_',
65             headers_label=>'Zheader_',
66             show_label=>'Zshow',
67             where_prefix=>'Zwhere_',
68             not_prefix=>'Znot_',
69             );
70              
71             Make a new report object.
72              
73             Takes the same arguments as L::new() plus the
74             following additions:
75              
76             =over
77              
78             =item input_format
79              
80             This contains information about what style of input field
81             should be used for this particular column in this table.
82             This is used for the Edit and Add forms.
83              
84             =item max_sort_fields
85              
86             The maximum number of sort fields required (default: 10)
87              
88             =item sort_label
89              
90             Name of the sort parameter.
91              
92             =item sort_reversed_prefix
93              
94             Prefix of the sort-reversed parameters.
95              
96             =item headers_label
97              
98             Name of the headers parameter.
99              
100             =item show_label
101              
102             Name of the columns-to-show parameter.
103              
104             =item where_prefix
105              
106             Prefix of the 'where' parameters.
107              
108             =item not_prefix
109              
110             Prefix of the not-where parameters.
111              
112             =back
113              
114             =cut
115              
116             sub new {
117 0     0 1   my $class = shift;
118 0           my %parameters = (@_);
119 0           my $self = SQLite::Work->new(%parameters);
120              
121             # CGI-related defaults
122 0           $self->{max_sort_fields} = 10;
123 0           $self->{max_headers} = 4;
124 0   0       $self->{sort_label} ||= 'Zsort';
125 0   0       $self->{sort_reversed_prefix} ||= 'Zsort_reversed_';
126 0   0       $self->{headers_label} ||= 'Zheader';
127 0   0       $self->{show_label} ||= 'Zshow';
128 0   0       $self->{where_prefix} ||= 'Zwhere_';
129 0   0       $self->{not_prefix} ||= 'Znot_';
130              
131 0           my $ldelim = $self->{ldelim};
132 0           my $rdelim = $self->{rdelim};
133 0           $self->{message} = '';
134              
135             # this creates a new CGI object which has already parsed the query
136 0           $self->{cgi} = new CGI;
137 0   0       bless ($self, ref ($class) || $class);
138             } # new
139              
140             =head1 OBJECT METHODS
141              
142             =head2 do_select
143              
144             $obj->do_select($table,
145             command=>'Search');
146              
147             Select data from a table in the database.
148             Uses CGI to get most of the parameters.
149              
150             The 'command' is 'Search' by default; if it is something else,
151             then the result generated has edit fields and buttons in it.
152              
153             =cut
154             sub do_select {
155 0     0 1   my $self = shift;
156 0           my $table = shift;
157 0           my %args = (
158             command=>'Search',
159             outfile=>'',
160             @_
161             );
162 0           my $command = $args{command};
163              
164 0           my $where_prefix = $self->{where_prefix};
165 0           my $not_prefix = $self->{not_prefix};
166 0           my $show_label = $self->{show_label};
167 0           my $sort_label = $self->{sort_label};
168 0           my $sort_reversed_prefix = $self->{sort_reversed_prefix};
169 0           my $headers_label = $self->{headers_label};
170 0           my @columns = ();
171 0           my %where = ();
172 0           my %not_where = ();
173 0           my @sort_by = ();
174 0           my @sort_r = ();
175 0           my %sort_reverse = ();
176 0           my @headers = ();
177 0           my $limit = $self->{cgi}->param('Limit');
178 0 0         $limit = 0 if !$limit;
179 0           my $page = $self->{cgi}->param('Page');
180 0 0         $page = 1 if !$page;
181 0           my $row_id_name = $self->get_id_colname($table);
182              
183             # build up the data
184 0           foreach my $pfield ($self->{cgi}->param())
185             {
186 0           my $pval = $self->{cgi}->param($pfield);
187 0 0         if ($pfield eq $show_label)
    0          
    0          
    0          
    0          
    0          
188             {
189 0           my (@show) = $self->{cgi}->param($pfield);
190 0           foreach my $scol (@show)
191             {
192             # only show non-empty values!
193 0 0         if ($scol)
194             {
195 0           push @columns, $scol;
196             }
197             }
198             }
199             elsif ($pfield =~ /^${where_prefix}(.*)/o)
200             {
201 0           my $colname = $1;
202 0 0         if ($pval)
203             {
204 0           my $not_where_field = "${not_prefix}${colname}";
205 0           $pval =~ m#([^`]*)#;
206 0           my $where_val = $1;
207 0           $where_val =~ s/\s$//;
208 0           $where_val =~ s/^\s//;
209 0 0         if ($where_val)
210             {
211 0           $where{$colname} = $where_val;
212 0 0         if ($self->{cgi}->param($not_where_field))
213             {
214 0           $not_where{$colname} = 1;
215             }
216             }
217             }
218             }
219             elsif ($pfield eq 'Edit_Row')
220             {
221             # show the row given in the Edit_Row value
222 0 0         if ($pval)
223             {
224 0           $pval =~ m#Edit Row ([\d]+)#;
225 0           my $where_val = $1;
226 0 0         if ($where_val)
227             {
228 0           $where{$row_id_name} = $where_val;
229             }
230             }
231             }
232             elsif ($pfield eq $sort_label)
233             {
234 0           my (@vals) = $self->{cgi}->param($pfield);
235 0           foreach my $val (@vals)
236             {
237             # only non-empty values!
238 0 0         if ($val)
239             {
240 0           push @sort_by, $val;
241             }
242             }
243             }
244             elsif ($pfield eq $headers_label)
245             {
246 0           my (@vals) = $self->{cgi}->param($pfield);
247 0           foreach my $val (@vals)
248             {
249             # only non-empty values!
250 0 0         if ($val)
251             {
252 0           push @headers, $val;
253             }
254             }
255             }
256             elsif ($pfield =~ /^${sort_reversed_prefix}(.*)/o)
257             {
258 0           my $ind = $1;
259 0 0         $sort_r[$ind] = ($pval ? 1 : 0);
260             }
261             }
262 0 0         @columns = $self->get_colnames($table) if !@columns;
263 0 0         if (@sort_by)
264             {
265 0           for (my $i=0; $i < @sort_r; $i++)
266             {
267 0 0         if ($sort_r[$i])
268             {
269 0           $sort_reverse{$sort_by[$i]} = 1;
270             }
271             }
272             }
273              
274             $self->do_report(
275 0 0         table=>$table,
    0          
    0          
276             table2=>($self->{cgi}->param('Table2')
277             ? $self->{cgi}->param('Table2') : ''),
278             command=>$command,
279             where=>\%where,
280             not_where=>\%not_where,
281             sort_by=>\@sort_by,
282             sort_reversed=>\%sort_reverse,
283             show=>\@columns,
284             headers=>\@headers,
285             limit=>$limit,
286             page=>$page,
287             report_style=>($self->{cgi}->param('ReportStyle')
288             ? $self->{cgi}->param('ReportStyle') : 'compact'),
289             layout=>($self->{cgi}->param('ReportLayout')
290             ? $self->{cgi}->param('ReportLayout') : 'table'),
291             outfile=>$args{outfile},
292             );
293              
294             } # do_select
295              
296             =head2 do_single_update
297              
298             Update a single column in a single row, or all columns
299             in a single row.
300              
301             =cut
302             sub do_single_update {
303 0     0 1   my $self = shift;
304 0           my $table = shift;
305 0           my %args = (
306             command=>'Update',
307             @_
308             );
309              
310 0           my $row_id_name = $self->get_id_colname($table);
311 0           my $row_id = $self->{cgi}->param($row_id_name);
312 0 0         if (!$row_id)
313             {
314 0           $self->print_message("Can't update table $table: row-id $row_id_name is NULL");
315 0           return 0;
316             }
317 0           my $update_field = $self->{cgi}->param('Update');
318 0           my %update_values = ();
319 0 0         if ($update_field eq $row_id_name)
320             {
321 0           my @columns = $self->get_colnames($table, do_rowid=>0);
322 0           foreach my $col (@columns)
323             {
324 0 0         if ($col ne $row_id_name)
325             {
326 0           $update_values{$col} = $self->{cgi}->param($col);
327 0           $update_values{$col} =~ s/\r//g;
328             }
329             }
330             }
331             else # update a single value
332             {
333 0           $update_values{$update_field} = $self->{cgi}->param($update_field);
334 0           $update_values{$update_field} =~ s/\r//g;
335             }
336 0 0         if ($self->update_one_row(table=>$table,
337             command=>$args{command},
338             row_id=>$row_id,
339             field=>$update_field,
340             update_values=>\%update_values))
341             {
342             # display the edit fields again
343 0           $self->{cgi}->param(-name=>"Zwhere_$row_id_name", -value=>$row_id);
344 0           $self->do_select($table, 'Edit');
345             }
346              
347             } # do_single_update
348              
349             =head2 do_add_form
350              
351             $obj->do_add_form($table);
352              
353             Set up for adding a row to the database.
354              
355             =cut
356             sub do_add_form {
357 0     0 1   my $self = shift;
358 0           my $table = shift;
359 0           my $command = 'Add';
360              
361             # read the template
362 0           my $template;
363 0 0 0       if ($self->{report_template} !~ /\n/
364             && -r $self->{report_template})
365             {
366 0           local $/ = undef;
367 0           my $fh;
368 0 0         open($fh, $self->{report_template})
369             or die "Could not open ", $self->{report_template};
370 0           $template = <$fh>;
371 0           close($fh);
372             }
373             else
374             {
375 0           $template = $self->{report_template};
376             }
377             # generate the form
378 0           my $form = $self->make_add_form($table);
379 0           my $title = $command . ' ' . $table;
380              
381             # Now print the page for the user to see...
382 0           my $out = $template;
383 0           $out =~ s//$title/g;
384 0           $out =~ s//$form/g;
385              
386 0           print "Content-Type: text/html\n";
387 0           print "\n";
388 0           print $out;
389              
390             } # do_add_form
391              
392             =head2 do_add
393              
394             Add a row to a table.
395              
396             =cut
397             sub do_add {
398 0     0 1   my $self = shift;
399 0           my $table = shift;
400 0           my %args = (
401             command=>'Add',
402             @_
403             );
404              
405 0           my @columns = $self->get_colnames($table, do_rowid=>0);
406 0           my $row_id_name = $self->get_id_colname($table);
407              
408 0           my %vals = ();
409 0           foreach my $col (@columns)
410             {
411 0           $vals{$col} = $self->{cgi}->param($col);
412 0           $vals{$col} =~ s/\r//g;
413             }
414 0 0         if ($self->add_one_row(
415             table=>$table,
416             add_values=>\%vals))
417             {
418             # display the edit fields again
419 0           my $row_id = $self->{dbh}->last_insert_id(undef, undef, $table, undef);
420 0           $self->{cgi}->param(-name=>"Zwhere_$row_id_name", -value=>$row_id);
421 0           $self->do_select($table, 'Edit');
422             }
423              
424             } # do_add
425              
426             =head2 do_single_delete
427              
428             Delete a single row.
429              
430             =cut
431             sub do_single_delete {
432 0     0 1   my $self = shift;
433 0           my $table = shift;
434 0           my %args = (
435             command=>'Delete',
436             @_
437             );
438              
439 0           my $row_id_name = $self->get_id_colname($table);
440 0           my $row_id = $self->{cgi}->param($row_id_name);
441              
442             # delete the row given in the Delete_Row value
443 0           my $pval = $self->{cgi}->param('Delete_Row');
444 0 0         if ($pval)
445             {
446 0           $pval =~ m#Delete Row ([\d]+)#;
447 0           $row_id = $1;
448             }
449 0 0         if (!$row_id)
450             {
451 0           $self->print_message("Can't delete from table $table: row-id $row_id_name is NULL");
452 0           return 0;
453             }
454 0 0         if ($self->delete_one_row(
455             table=>$table, row_id=>$row_id))
456             {
457             # display the edit search
458 0           $self->do_search_form($table, command=>'Edit');
459             }
460            
461             } # do_single_delete
462              
463             =head2 make_search_form
464              
465             Create the search form for the given table.
466              
467             my $form = $obj->make_search_form($table, %args);
468              
469             =cut
470             sub make_search_form {
471 0     0 1   my $self = shift;
472 0           my $table = shift;
473 0           my %args = (
474             command=>'Search',
475             @_
476             );
477              
478 0           my $table2 = $self->{cgi}->param('Table2');
479              
480             # read the template
481 0           my $template;
482 0 0 0       if ($self->{report_template} !~ /\n/
483             && -r $self->{report_template})
484             {
485 0           local $/ = undef;
486 0           my $fh;
487 0 0         open($fh, $self->{report_template})
488             or die "Could not open ", $self->{report_template};
489 0           $template = <$fh>;
490 0           close($fh);
491             }
492             else
493             {
494 0           $template = $self->{report_template};
495             }
496             # generate the search form
497 0           my $form = $self->search_form($table,
498             command=>$args{command},
499             table2=>$table2);
500 0           my $title = $args{command} . ' ' . $table;
501              
502 0 0         $form = "

$self->{message}

\n" . $form if $self->{message};
503              
504 0           my $out = $template;
505 0           $out =~ s//$title/g;
506 0           $out =~ s//$form/g;
507 0           return $out;
508              
509             } # make_search_form
510              
511             =head2 do_search_form
512              
513             Display the search form for the given table.
514              
515             =cut
516             sub do_search_form {
517 0     0 1   my $self = shift;
518            
519 0           my $out = $self->make_search_form(@_);
520              
521             # Now print the page for the user to see...
522 0           print "Content-Type: text/html\n";
523 0           print "\n";
524 0           print $out;
525              
526             } # do_search_form
527              
528             =head2 make_table_form
529              
530             Make the table selection form.
531              
532             =cut
533             sub make_table_form {
534 0     0 1   my $self = shift;
535 0 0         my $command = (@_ ? shift : '');
536              
537             # read the template
538 0           my $template;
539 0 0 0       if ($self->{report_template} !~ /\n/
540             && -r $self->{report_template})
541             {
542 0           local $/ = undef;
543 0           my $fh;
544 0 0         open($fh, $self->{report_template})
545             or die "Could not open ", $self->{report_template};
546 0           $template = <$fh>;
547 0           close($fh);
548             }
549             else
550             {
551 0           $template = $self->{report_template};
552             }
553              
554             # get the list of tables (and views)
555 0           my @tables = sort $self->get_tables(views=>($command ne 'Editing'));
556              
557             # generate the search form
558 0           my $url = $self->{cgi}->url();
559 0           my $form =<
560            
561            

Table:

562             EOT
563 0           foreach my $table (@tables)
564             {
565 0           $form .= "
$table";
566             }
567 0           $form .=<
568            

569            
570            
571            
572             EOT
573 0           my $title = "Select table";
574 0 0         $title .= " for $command" if $command;
575              
576 0           my $out = $template;
577 0           $out =~ s//$title/g;
578 0           $out =~ s//$form/g;
579              
580 0           return $out;
581              
582             } # make_table_form
583              
584             =head2 do_table_form
585              
586             Display the table selection form.
587              
588             =cut
589             sub do_table_form {
590 0     0 1   my $self = shift;
591            
592 0           my $out = $self->make_table_form(@_);
593              
594             # Now print the page for the user to see...
595 0           print "Content-Type: text/html\n";
596 0           print "\n";
597 0           print $out;
598              
599             } # do_table_form
600              
601             =head1 Helper Methods
602              
603             Lower-level methods, generally just called from other methods,
604             but possibly suitable for other things.
605              
606             =head2 print_message
607              
608             Print an (error) message to the user.
609              
610             $self->print_message($message); # error message
611              
612             $self->print_message($message, 0); # non-error message
613              
614             =cut
615             sub print_message {
616 0     0 1   my $self = shift;
617 0           my $message = shift;
618 0 0         my $is_error = (@_ ? shift : 1); # assume error message
619              
620             # read the template
621 0           my $template;
622 0 0 0       if ($self->{report_template} !~ /\n/
623             && -r $self->{report_template})
624             {
625 0           local $/ = undef;
626 0           my $fh;
627 0 0         open($fh, $self->{report_template})
628             or die "Could not open ", $self->{report_template};
629 0           $template = <$fh>;
630 0           close($fh);
631             }
632             else
633             {
634 0           $template = $self->{report_template};
635             }
636 0 0         my $title = ($is_error
637             ? "Error Message"
638             : "Message"
639             );
640              
641 0 0         my $contents = ($is_error
642             ? "

$message

\n"
643             : "

$message

\n"
644             );
645              
646 0           my $out = $template;
647 0           $out =~ s//$title/g;
648 0           $out =~ s//$contents/g;
649             # Now print the page for the user to see...
650 0           print "Content-Type: text/html\n";
651 0           print "\n";
652 0           print $out;
653             } # print_message
654              
655             =head2 search_form
656              
657             Construct a search-a-table form
658              
659             =cut
660             sub search_form {
661 0     0 1   my $self = shift;
662 0           my $table = shift;
663 0           my %args = (
664             command=>'Search',
665             @_
666             );
667              
668 0           my @columns = $self->get_colnames($table);
669 0           my $command = $args{command};
670 0           my $where_prefix = $self->{where_prefix};
671 0           my $not_prefix = $self->{not_prefix};
672 0           my $show_label = $self->{show_label};
673 0           my $sort_label = $self->{sort_label};
674 0           my $sort_reversed_prefix = $self->{sort_reversed_prefix};
675 0           my $headers_label = $self->{headers_label};
676              
677 0           my $action = $self->{cgi}->url();
678 0           my $out_str =<
679            
680            

681            
682             EOT
683 0 0         if ($command eq 'Edit')
684             {
685 0           $out_str .=<
686            
687             EOT
688             }
689 0           $out_str .=<
690            
691            

692            
693            
694            

Match by column: use * as a wildcard match,

695             and the ? character to match
696             any single character.
697             Click on the "NOT" checkbox to negate a match.
698            

699             \n\n"; \n";
700            
701             Columns
702             Match
703              
704            
705             EOT
706 0           for (my $i = 0; $i < @columns; $i++) {
707 0           my $col = $columns[$i];
708 0           my $wcol_label = "${where_prefix}${col}";
709 0           my $ncol_label = "${not_prefix}${col}";
710              
711 0           $out_str .= "
";
712 0           $out_str .= "$col";
713 0           $out_str .= "";
714 0           $out_str .= "";
715 0           $out_str .= "";
716 0           $out_str .= "NOT";
717 0           $out_str .= "
718 0           $out_str .= "
719             }
720 0           $out_str .=<
721            
722            
723            

Select the order of columns to display;

724             and which columns not to display.

725             "; \n";
726             EOT
727 0           for (my $i = 0; $i < @columns; $i++) {
728 0           my $col = $columns[$i];
729              
730 0           $out_str .= "
";
731 0           $out_str .= "
732 0           $out_str .= "\n";
733 0           foreach my $fname (@columns)
734             {
735 0 0         if ($fname eq $col)
736             {
737 0           $out_str .= "\n";
738             }
739             else
740             {
741 0           $out_str .= "\n";
742             }
743             }
744 0           $out_str .= "";
745 0           $out_str .= "
746 0           $out_str .= "
747             }
748 0           $out_str .=<
749            
750             EOT
751 0           $out_str .=<
752            

Num Results:

753            
754            
755            
756            
757            
758            
759            
760            

761            

Page:

762            
763            

764             EOT
765 0 0         if ($command eq 'Search')
766             {
767 0           $out_str .=<
768            

Report Layout:

769            
770            
771            
772            
773            

774             EOT
775             }
776              
777 0           $out_str .=<
778            

Report Style:

779            
780            
781            
782            
783            
784            

785             EOT
786 0           my @tables = $self->get_tables();
787 0 0         if (@tables > 1)
788             {
789 0           $out_str .=<
790            

Table #2

791            
NONE
792             EOT
793 0           foreach my $tn (@tables)
794             {
795 0 0         if ($tn ne $table)
796             {
797 0           $out_str .= "
$tn\n";
798             }
799             }
800 0           $out_str .= "

\n";
801             }
802              
803 0           $out_str .=<
804            
805            
806            
807            

Sort by: To set the sort order, select the column names.

808             To sort that column in reverse order, click on the Reverse
809             checkbox.
810            

811             "; \n"; ";
812             EOT
813              
814 0 0         my $num_sort_fields = ($self->{max_sort_fields} < @columns
815             ? $self->{max_sort_fields} : @columns);
816 0           for (my $i=0; $i < $num_sort_fields; $i++)
817             {
818 0           my $col = $columns[$i];
819 0           $out_str .= "
";
820 0           $out_str .= "
821 0           $out_str .= "\n";
822 0           foreach my $fname (@columns)
823             {
824 0           $out_str .= "\n";
825             }
826 0           $out_str .= "";
827 0           $out_str .= "
828 0           $out_str .= "Reverse ";
829 0           $out_str .= "
830 0           $out_str .= "
831             }
832 0           $out_str .=<
833            
834            
835             EOT
836 0 0         if ($command eq 'Search')
837             {
838 0           $out_str .=<
839            

Headers:

840             Indicate which columns you wish to be in headers by giving
841             the columns in template form; for example:
842             {\$Col1} {\$Col2}
843             means that the header contains columns Col1 and Col2.
844            
845             EOT
846 0           for (my $i=1; $i <= $self->{max_headers}; $i++)
847             {
848 0           $out_str .=<
849             Header $i
850            
851             EOT
852             }
853 0           $out_str .= "

\n";
854             }
855              
856 0           $out_str .=<
857            
858            
859            

860             EOT
861 0 0         if ($command eq 'Edit')
862             {
863 0           $out_str .=<
864            
865             EOT
866             }
867 0           $out_str .=<
868            

869            
870             EOT
871 0           return $out_str;
872             } # search_form
873              
874             =head2 make_add_form
875              
876             Construct an add-a-row form.
877              
878             =cut
879             sub make_add_form {
880 0     0 1   my $self = shift;
881 0           my $table = shift;
882 0           my %args = (
883             command=>'Add',
884             @_
885             );
886              
887 0           my $row_id_name = $self->get_id_colname($table);
888 0           my @columns = $self->get_colnames($table, do_rowid=>0);
889 0           my $command = $args{command};
890 0 0         my $table2_str = ($args{table2}
891             ? ""
892             : ''
893             );
894              
895 0           my $action = $self->{cgi}->url();
896 0           my $out_str =<
897            
898            

899            
900            
901             $table2_str
902            

903             \n"; \n";
904            
905             Columns
906             Value
907            
908             EOT
909 0           for (my $i = 0; $i < @columns; $i++) {
910 0           my $col = $columns[$i];
911              
912 0           $out_str .= "
";
913 0           $out_str .= "$col";
914 0           $out_str .= "";
915 0 0         if ($col eq $row_id_name)
916             {
917 0           $out_str .= "";
918             }
919             else
920             {
921 0           $out_str .= $self->get_input_field(table=>$table,
922             colname=>$col, value=>'');
923             }
924 0           $out_str .= "
925 0           $out_str .= "
926             }
927 0           $out_str .=<
928            
929            
930             EOT
931 0           return $out_str;
932             } # make_add_form
933              
934             =head2 make_buttons
935              
936             Make the buttons for the forms.
937              
938             =cut
939             sub make_buttons {
940 0     0 1   my $self = shift;
941 0           my %args = (
942             table=>'',
943             command=>'Search',
944             @_
945             );
946 0           my $table = $args{table};
947 0           my $table2 = $args{table2};
948 0           my $page = $args{page};
949 0           my $limit = $args{limit};
950 0           my $total = $args{total};
951 0           my $command = $args{command};
952              
953 0 0         my $num_pages = ($limit ? ceil($total / $limit) : 0);
954              
955 0           my $url = $self->{cgi}->url();
956 0           my @out = ();
957 0           push @out,<
958             \n"; \n"; \n"; \n";
959            
960            
961            
962            
963            
964             EOT
965 0 0         if ($command eq 'Edit')
966             {
967 0           push @out,<
968            
969             EOT
970             }
971 0           push @out,<
972            
973             EOT
974              
975 0 0         if ($args{limit})
976             {
977             # reproduce the query ops, with a different page
978             # first
979 0           push @out, "";
980 0           push @out, $self->make_page_button(command=>$command,
981             the_page=>1,
982             page_label=>' |< ');
983 0           push @out, "
984             # prev
985 0           push @out, "";
986 0           push @out, $self->make_page_button(command=>$command,
987             the_page=>$page - 1,
988             page_label=>' < ');
989 0           push @out, "
990             # next
991 0           push @out, "";
992 0           push @out, $self->make_page_button(command=>$command,
993             the_page=>$page + 1,
994             page_label=>' > ');
995 0           push @out, "
996             # last
997 0           push @out, "";
998 0           push @out, $self->make_page_button(command=>$command,
999             the_page=>$num_pages,
1000             page_label=>' >| ');
1001 0           push @out, "
1002 0           push @out, "
\n";
1003             }
1004             else # no pages
1005             {
1006 0           push @out,<
1007            
1008             EOT 1009             } 1010               1011 0           return join('', @out); 1012             } # make_buttons 1013               1014             =head2 make_page_button 1015               1016             Make a button for a particular page 1017               1018             =cut 1019               1020             sub make_page_button { 1021 0     0 1   my $self = shift; 1022 0           my %args = ( 1023             command=>'Search', 1024             the_page=>0, 1025             page_label=>'Page', 1026             @_ 1027             ); 1028 0           my $command = $args{command}; 1029 0           my $the_page = $args{the_page}; 1030 0           my $page_label = $args{page_label}; 1031               1032 0           my $url = $self->{cgi}->url(); 1033 0           my $result = ''; 1034 0           $result .=< 1035            
1036             1037             EOT 1038 0           foreach my $pfield ($self->{cgi}->param()) 1039             { 1040 0 0 0       if ($pfield ne 'Page' 1041             and $pfield ne $command) 1042             { 1043 0           my (@vals) = $self->{cgi}->param($pfield); 1044 0           foreach my $val (@vals) 1045             { 1046 0           $result .=< 1047             1048             EOT 1049             } 1050             } 1051             } 1052 0           $result .=< 1053             1054             1055             EOT 1056 0           return $result; 1057             } # make_page_button 1058               1059             =head2 print_select 1060               1061             Print a selection result. 1062             (slightly different for Edits than for Search) 1063               1064             =cut 1065             sub print_select { 1066 0     0 1   my $self = shift; 1067 0           my $sth = shift; 1068 0           my $sth2 = shift; 1069 0           my %args = ( 1070             table=>'', 1071             command=>'Search', 1072             @_ 1073             ); 1074 0           my @columns = @{$args{columns}};   0             1075 0           my @sort_by = @{$args{sort_by}};   0             1076 0           my $table = $args{table}; 1077 0           my $page = $args{page}; 1078               1079             # read the template 1080 0           my $template; 1081 0 0 0       if ($self->{report_template} !~ /\n/ 1082             && -r $self->{report_template}) 1083             { 1084 0           local $/ = undef; 1085 0           my $fh; 1086 0 0         open($fh, $self->{report_template}) 1087             or die "Could not open ", $self->{report_template}; 1088 0           $template = <$fh>; 1089 0           close($fh); 1090             } 1091             else 1092             { 1093 0           $template = $self->{report_template}; 1094             } 1095             # generate the HTML table 1096 0           my $count = 0; 1097 0           my $res_tab = ''; 1098 0           ($count, $res_tab) = $self->format_report($sth, 1099             %args, 1100             table=>$table, 1101             table2=>$args{table2}, 1102             columns=>\@columns, 1103             sort_by=>\@sort_by, 1104             ); 1105 0           my $buttons = $self->make_buttons(%args); 1106 0 0         my $main_title = ($args{title} ? $args{title} 1107             : "$table $args{command} result"); 1108 0 0         my $title = ($args{limit} ? "$main_title ($page)" 1109             : $main_title); 1110 0           my @result = (); 1111 0 0         push @result, $buttons if ($args{report_style} ne 'bare'); 1112 0           push @result, $res_tab; 1113 0 0 0       push @result, "

$count rows displayed of $args{total}.

\n" 1114             if ($args{report_style} ne 'bare' 1115             and $args{report_style} ne 'compact'); 1116 0 0 0       if ($args{limit} and $args{report_style} eq 'full') 1117             { 1118 0           my $num_pages = ceil($args{total} / $args{limit}); 1119 0           push @result, "

Page $page of $num_pages.

\n" 1120             } 1121 0 0         if (defined $sth2) 1122             { 1123 0           my @cols2 = $self->get_colnames($args{table2}); 1124 0           my $count2; 1125             my $tab2; 1126 0           ($count2, $tab2) = $self->format_report($sth2, 1127             %args, 1128             table=>$args{table2}, 1129             columns=>\@cols2, 1130             sort_by=>\@cols2, 1131             headers=>[], 1132             row_template=>'', 1133             ); 1134 0 0         if ($count2)     0           1135             { 1136 0           push @result,< 1137            

$args{table2}

1138             $tab2 1139            

$count2 rows displayed from $args{table2}.

1140             EOT 1141             } 1142             elsif ($args{command} eq 'Edit') 1143             { 1144 0           push @result,< 1145            

Edit $args{table2}

1146             EOT 1147             # no rows, but editing 1148 0           push @result, $self->make_add_form($args{table2}); 1149             } 1150             } 1151 0 0         push @result, $buttons if ($args{report_style} ne 'bare'); 1152               1153             # prepend the query and message 1154 0 0         unshift @result, "

$args{query}

\n" if ($args{debug}); 1155 0 0         unshift @result, "

$self->{message}

\n", if $self->{message}; 1156               1157 0           my $contents = join('', @result); 1158 0           my $out = $template; 1159 0           $out =~ s//$title/g; 1160 0           $out =~ s//$contents/g; 1161             # if we're given an outfile, print to that 1162 0 0         if ($args{outfile}) 1163             { 1164 0           my $fh; 1165 0 0         open($fh, ">", $args{outfile}) 1166             or die "Could not open $args{outfile} for writing"; 1167 0           print $fh $out; 1168 0           close($fh); 1169             } 1170             else 1171             { 1172             # Now print the page for the user to see... 1173 0           print "Content-Type: text/html\n"; 1174 0           print "\n"; 1175 0           print $out; 1176             } 1177             } # print_select 1178               1179             =head2 format_report 1180               1181             Format the report results 1182             If 'command' is 'Search' then use the parent format_report; 1183             otherwise make an edit-table. 1184               1185             =cut 1186             sub format_report { 1187 0     0 1   my $self = shift; 1188 0           my $sth = shift; 1189 0           my %args = ( 1190             table=>'', 1191             command=>'Edit', 1192             @_ 1193             ); 1194               1195 0 0         if ($args{command} eq 'Search')     0               0           1196             { 1197 0           return $self->SUPER::format_report($sth, %args); 1198             } 1199             elsif ($args{command} eq 'Edit') 1200             { 1201 0           return $self->make_edit_table($sth, %args); 1202             } 1203             elsif ($args{command} eq 'EditText') 1204             { 1205 0           return $self->make_edittext($sth, %args); 1206             } 1207               1208             } # format_report 1209               1210             =head2 make_edit_table 1211               1212             Make a table for editing a search result. 1213               1214             =cut 1215             sub make_edit_table { 1216 0     0 1   my $self = shift; 1217 0           my $sth = shift; 1218 0           my %args = ( 1219             table=>'', 1220             command=>'Edit', 1221             report_style=>'full', 1222             @_ 1223             ); 1224 0           my @columns = @{$args{columns}};   0             1225 0           my @sort_by = @{$args{sort_by}};   0             1226 0           my $command = $args{command}; 1227 0           my $table = $args{table}; 1228 0           my $table2 = $args{table2}; 1229 0           my $report_style = $args{report_style}; 1230 0           my $table_border = $args{table_border}; 1231 0           my $truncate_colnames = $args{truncate_colnames}; 1232               1233             # change things depending on report_style 1234 0 0         if (!defined $table_border) 1235             { 1236 0 0         if ($report_style eq 'bare') 1237             { 1238 0           $table_border = 0; 1239             } 1240             else 1241             { 1242 0           $table_border = 1; 1243             } 1244             } 1245 0 0         if (!defined $truncate_colnames) 1246             { 1247 0 0         if ($report_style eq 'full')     0               0           1248             { 1249 0           $truncate_colnames = 0; 1250             } 1251             elsif ($report_style eq 'medium') 1252             { 1253 0           $truncate_colnames = 6; 1254             } 1255             elsif ($report_style eq 'compact') 1256             { 1257 0           $truncate_colnames = 4; 1258             } 1259             else 1260             { 1261 0           $truncate_colnames = 0; 1262             } 1263             } 1264 0           my @out = (); 1265 0           my $count = 0; 1266 0           my $row_id_name = $self->get_id_colname($table); 1267 0           my $row_id_ind = -1; 1268 0           my $url = $self->{cgi}->url(); 1269             # by default, show all columns 1270 0           my @show_cols = (); 1271 0           for (my $i = 0; $i < @columns; $i++) 1272             { 1273 0           $show_cols[$i] = 1; 1274 0 0         if ($columns[$i] eq $row_id_name) 1275             { 1276 0           $row_id_ind = $i; 1277             } 1278             } 1279               1280 0           my @nice_cols = (); 1281 0           for (my $ci = 0; $ci < @columns; $ci++) 1282             { 1283 0           my $nicecol = $columns[$ci]; 1284 0 0         if ($truncate_colnames) 1285             { 1286 0           my @colwords = split('_', $nicecol); 1287 0           foreach my $cw (@colwords) 1288             { 1289 0           $cw = $self->{_tobj}->convert_value(value=>$cw, 1290             format=>"trunc${truncate_colnames}", 1291             name=>$columns[$ci]); 1292 0           $cw = $self->{_tobj}->convert_value(value=>$cw, 1293             format=>'proper', 1294             name=>$columns[$ci]); 1295             } 1296 0           $nicecol = join(' ', @colwords); 1297             } 1298             else 1299             { 1300 0           $nicecol =~ s/_/ /g; 1301 0           $nicecol = $self->{_tobj}->convert_value(value=>$nicecol, 1302             format=>'proper', 1303             name=>$columns[$ci]); 1304             } 1305 0           $nice_cols[$ci] = $nicecol; 1306             } 1307               1308             # get the rows 1309 0           my $tbl_ary_ref = $sth->fetchall_arrayref; 1310 0           my $single_row = (@{$tbl_ary_ref} == 1);   0             1311 0           my $new_table = 1; 1312 0           for (my $ri = 0; $ri < @{$tbl_ary_ref}; $ri++)   0             1313             { 1314 0           my @row = @{$tbl_ary_ref->[$ri]};   0             1315 0           $count++; 1316             # new table 1317 0           push @out,< 1318            
1319             1320             EOT 1321 0 0         if ($table2) 1322             { 1323 0           push @out,< 1324             1325             EOT 1326             } 1327 0           push @out, ""; '; \n"; \n"; '; \n"; '; \n";
1328 0 0         if ($report_style ne 'bare')
1329             {
1330 0           push @out, '
1331             # a single-row table has its columns on the side
1332 0           push @out, "ColumnValue
1333 0           push @out, "
1334             }
1335              
1336             # a row for each column-value
1337 0           for (my $ci = 0; $ci < @columns; $ci++)
1338             {
1339 0 0         if ($show_cols[$ci])
1340             {
1341 0           my $col = $columns[$ci];
1342 0           my $val = $row[$ci];
1343 0 0         $val = 'NULL' if !defined $val;
1344 0           push @out, '
1345 0           push @out, '';
1346 0           push @out, "";
1347 0           push @out, "
1348 0           push @out, '';
1349 0 0         if ($col ne $row_id_name)
1350             {
1351 0           push @out,$self->get_input_field(table=>$table,
1352             colname=>$col,
1353             value=>$val);
1354             }
1355             else
1356             {
1357 0           push @out,<
1358            
1359             $val
1360            
1361            
1362             EOT
1363             }
1364 0           push @out, '
1365 0           push @out, "
1366             }
1367             }
1368 0           push @out, "
\n"; 1369 0           push @out, "\n"; 1370             } 1371 0           if (0) 1372             { 1373             for (my $ri = 0; $ri < @{$tbl_ary_ref}; $ri++) 1374             { 1375             my @row = @{$tbl_ary_ref->[$ri]}; 1376             if ($new_table) 1377             { 1378             push @out,< 1379            
1380             1381             EOT 1382             if ($table2) 1383             { 1384             push @out,< 1385             1386             EOT 1387             } 1388             push @out, ""; '; "; "; \n"; "; \n"; \n";
1389             if ($report_style ne 'bare')
1390             {
1391             push @out, '
1392             push @out, " 
1393             for (my $ci = 0; $ci < @columns; $ci++)
1394             {
1395             if ($show_cols[$ci])
1396             {
1397             my $nicecol = $nice_cols[$ci];
1398             push @out, "$nicecol
1399             }
1400             }
1401             push @out, "
1402             }
1403             $new_table = 0;
1404             }
1405             push @out, "
1406             my $row_id_val = 'UNKNOWN';
1407             $row_id_val = $row[$row_id_ind] if ($row_id_ind >= 0);
1408             push @out,<
1409            
1410            
1411            
1412            
1413            
1414             EOT
1415             for (my $ci = 0; $ci < @columns; $ci++)
1416             {
1417             if ($show_cols[$ci])
1418             {
1419             my $col = $columns[$ci];
1420             my $val = $row[$ci];
1421             $val = 'NULL' if !defined $val;
1422             push @out, '';
1423             push @out, ($val ? $val : ' ');
1424             push @out, "
1425             }
1426             }
1427             push @out, "
1428             $count++;
1429             } # for each row
1430             }
1431              
1432 0           my $out_str = join('', @out);
1433 0           return ($count, $out_str);
1434             } # make_edit_table
1435              
1436             =head2 make_edittext
1437              
1438             Make a textarea for editing a search result.
1439              
1440             =cut
1441             sub make_edittext {
1442 0     0 1   my $self = shift;
1443 0           my $sth = shift;
1444 0           my %args = (
1445             table=>'',
1446             command=>'EditText',
1447             report_style=>'full',
1448             @_
1449             );
1450 0           my @columns = @{$args{columns}};
  0            
1451 0           my @sort_by = @{$args{sort_by}};
  0            
1452 0           my $command = $args{command};
1453 0           my $table = $args{table};
1454 0           my $table2 = $args{table2};
1455 0           my $report_style = $args{report_style};
1456 0           my $table_border = $args{table_border};
1457              
1458             # change things depending on report_style
1459 0 0         if (!defined $table_border)
1460             {
1461 0 0         if ($report_style eq 'bare')
1462             {
1463 0           $table_border = 0;
1464             }
1465             else
1466             {
1467 0           $table_border = 1;
1468             }
1469             }
1470 0           my @out = ();
1471 0           my $count = 0;
1472 0           my $row_id_name = $self->get_id_colname($table);
1473 0           my $row_id_ind = -1;
1474 0           my $url = $self->{cgi}->url();
1475             # by default, show all columns
1476 0           my @show_cols = ();
1477 0           for (my $i = 0; $i < @columns; $i++)
1478             {
1479 0           $show_cols[$i] = 1;
1480 0 0         if ($columns[$i] eq $row_id_name)
1481             {
1482 0           $row_id_ind = $i;
1483             }
1484             }
1485              
1486             # no change or truncation of colnames
1487 0           my @nice_cols = ();
1488 0           for (my $ci = 0; $ci < @columns; $ci++)
1489             {
1490 0           my $nicecol = $columns[$ci];
1491 0           $nice_cols[$ci] = $nicecol;
1492             }
1493              
1494             # get the rows
1495 0           my $tbl_ary_ref = $sth->fetchall_arrayref;
1496 0           my $single_row = (@{$tbl_ary_ref} == 1);
  0            
1497 0           my $new_table = 1;
1498 0           for (my $ri = 0; $ri < @{$tbl_ary_ref}; $ri++)
  0            
1499             {
1500 0           my @row = @{$tbl_ary_ref->[$ri]};
  0            
1501 0           $count++;
1502             # new table
1503 0           push @out,<
1504            
1505            
1506             EOT
1507 0 0         if ($table2)
1508             {
1509 0           push @out,<
1510            
1511             EOT
1512             }
1513 0           push @out, ""; '; \n"; \n"; '; \n"; '; \n";
1514 0 0         if ($report_style ne 'bare')
1515             {
1516 0           push @out, '
1517             # a single-row table has its columns on the side
1518 0           push @out, "ColumnValue
1519 0           push @out, "
1520             }
1521              
1522             # a row for each column-value
1523 0           for (my $ci = 0; $ci < @columns; $ci++)
1524             {
1525 0 0         if ($show_cols[$ci])
1526             {
1527 0           my $col = $columns[$ci];
1528 0           my $val = $row[$ci];
1529 0 0         $val = 'NULL' if !defined $val;
1530 0           push @out, '
1531 0           push @out, '';
1532 0           push @out, "";
1533 0           push @out, "
1534 0           push @out, '';
1535 0 0         if ($col ne $row_id_name)
1536             {
1537 0           push @out,$self->get_input_field(table=>$table,
1538             colname=>$col,
1539             value=>$val);
1540             }
1541             else
1542             {
1543 0           push @out,<
1544            
1545             $val
1546            
1547            
1548             EOT
1549             }
1550 0           push @out, '
1551 0           push @out, "
1552             }
1553             }
1554 0           push @out, "
\n";
1555 0           push @out, "\n";
1556             }
1557 0           if (0)
1558             {
1559             for (my $ri = 0; $ri < @{$tbl_ary_ref}; $ri++)
1560             {
1561             my @row = @{$tbl_ary_ref->[$ri]};
1562             if ($new_table)
1563             {
1564             push @out,<
1565            
1566            
1567             EOT
1568             if ($table2)
1569             {
1570             push @out,<
1571            
1572             EOT
1573             }
1574             push @out, ""; '; "; "; \n"; "; \n"; \n";
1575             if ($report_style ne 'bare')
1576             {
1577             push @out, '
1578             push @out, " 
1579             for (my $ci = 0; $ci < @columns; $ci++)
1580             {
1581             if ($show_cols[$ci])
1582             {
1583             my $nicecol = $nice_cols[$ci];
1584             push @out, "$nicecol
1585             }
1586             }
1587             push @out, "
1588             }
1589             $new_table = 0;
1590             }
1591             push @out, "
1592             my $row_id_val = 'UNKNOWN';
1593             $row_id_val = $row[$row_id_ind] if ($row_id_ind >= 0);
1594             push @out,<
1595            
1596            
1597            
1598            
1599            
1600             EOT
1601             for (my $ci = 0; $ci < @columns; $ci++)
1602             {
1603             if ($show_cols[$ci])
1604             {
1605             my $col = $columns[$ci];
1606             my $val = $row[$ci];
1607             $val = 'NULL' if !defined $val;
1608             push @out, '';
1609             push @out, ($val ? $val : ' ');
1610             push @out, "
1611             }
1612             }
1613             push @out, "
1614             $count++;
1615             } # for each row
1616             }
1617              
1618 0           my $out_str = join('', @out);
1619 0           return ($count, $out_str);
1620             } # make_edittext
1621              
1622             =head2 get_input_field
1623              
1624             Get the required input field for the table+column
1625              
1626             =cut
1627             sub get_input_field {
1628 0     0 1   my $self = shift;
1629 0           my %args = (
1630             table=>'',
1631             colname=>'',
1632             @_
1633             );
1634 0           my $col = $args{colname};
1635 0           my $val = $args{value};
1636 0           my $qval = $val;
1637 0           $qval =~ s/
1638 0           $qval =~ s/>/>/g;
1639 0           $qval =~ s/"/"/g;
1640              
1641 0           my $type = $self->{input_format}->{$args{table}}->{$col}->{type};
1642 0 0         if ($type eq 'textarea')
    0          
1643             {
1644 0           my $cols = $self->{input_format}->{$args{table}}->{$col}->{cols};
1645 0           my $rows = $self->{input_format}->{$args{table}}->{$col}->{rows};
1646 0           return <
1647            
1650             EOT
1651             }
1652             elsif ($type eq 'text')
1653             {
1654 0           my $size = $self->{input_format}->{$args{table}}->{$col}->{size};
1655 0           return <
1656            
1657             EOT
1658             }
1659 0           return <
1660            
1661             EOT
1662             } # get_input_field
1663              
1664             =head1 REQUIRES
1665              
1666             SQLite::Work
1667             CGI
1668              
1669             Test::More
1670              
1671             =head1 INSTALLATION
1672              
1673             To install this module, run the following commands:
1674              
1675             perl Build.PL
1676             ./Build
1677             ./Build test
1678             ./Build install
1679              
1680             Or, if you're on a platform (like DOS or Windows) that doesn't like the
1681             "./" notation, you can do this:
1682              
1683             perl Build.PL
1684             perl Build
1685             perl Build test
1686             perl Build install
1687              
1688             In order to install somewhere other than the default, such as
1689             in a directory under your home directory, like "/home/fred/perl"
1690             go
1691              
1692             perl Build.PL --install_base /home/fred/perl
1693              
1694             as the first step instead.
1695              
1696             This will install the files underneath /home/fred/perl.
1697              
1698             You will then need to make sure that you alter the PERL5LIB variable to
1699             find the modules, and the PATH variable to find the script.
1700              
1701             Therefore you will need to change:
1702             your path, to include /home/fred/perl/script (where the script will be)
1703              
1704             PATH=/home/fred/perl/script:${PATH}
1705              
1706             the PERL5LIB variable to add /home/fred/perl/lib
1707              
1708             PERL5LIB=/home/fred/perl/lib:${PERL5LIB}
1709              
1710              
1711             =head1 SEE ALSO
1712              
1713             perl(1).
1714              
1715             =head1 BUGS
1716              
1717             Please report any bugs or feature requests to the author.
1718              
1719             =head1 AUTHOR
1720              
1721             Kathryn Andersen (RUBYKAT)
1722             perlkat AT katspace dot com
1723             http://www.katspace.com
1724              
1725             =head1 COPYRIGHT AND LICENCE
1726              
1727             Copyright (c) 2005 by Kathryn Andersen
1728              
1729             This program is free software; you can redistribute it and/or modify it
1730             under the same terms as Perl itself.
1731              
1732              
1733             =cut
1734              
1735             1; # End of SQLite::Work::CGI
1736             __END__