File Coverage

blib/lib/CGI/Application/Demo/Basic.pm
Criterion Covered Total %
statement 24 181 13.2
branch 0 18 0.0
condition 0 10 0.0
subroutine 8 20 40.0
pod 3 12 25.0
total 35 241 14.5


line stmt bran cond sub pod time code
1             package CGI::Application::Demo::Basic;
2              
3             # Documentation:
4             # POD-style documentation is at the end. Extract it with pod2html.*.
5             #
6             # Note:
7             # o tab = 4 spaces || die
8             #
9             # Author:
10             # Ron Savage
11             # http://savage.net.au/index.html
12              
13 1     1   23786 use base 'CGI::Application';
  1         3  
  1         1447  
14 1     1   10882 use strict;
  1         3  
  1         41  
15 1     1   6 use warnings;
  1         3  
  1         41  
16              
17             require 5.005_62;
18              
19 1     1   837 use CGI::Application::Demo::Basic::Util::Config;
  1         3  
  1         31  
20 1     1   1000 use CGI::Application::Plugin::LogDispatch;
  1         34827  
  1         12  
21 1     1   939 use CGI::Application::Plugin::Session;
  1         8264  
  1         8  
22 1     1   1380 use CGI::Simple;
  1         21348  
  1         11  
23 1     1   973 use Class::DBI::Loader;
  1         276  
  1         14  
24              
25             our $VERSION = '1.06';
26              
27             # -----------------------------------------------
28              
29             sub build_basic_pane
30             {
31 0     0 0   my($self, $submit) = @_;
32 0           my($content) = $self -> load_tmpl('basic.tmpl');
33 0   0       my($count) = $self -> session -> param('count') || 0;
34              
35 0           $count++;
36              
37 0           $self -> session -> param(count => $count);
38              
39 0           my(@tr_loop);
40              
41 0           for my $table (sort keys %{$self -> param('cgi_app_demo_tables')})
  0            
42             {
43 0           my($class) = ${$self -> param('cgi_app_demo_tables')}{$table};
  0            
44 0           my(@column) = $self -> get_columns($class);
45 0           my(@column_name) = sort @{$column[2]};
  0            
46              
47 0           push @tr_loop,
48             {
49             th => 'Table',
50             td => $table,
51             },
52             {
53             th => 'Class',
54             td => $class,
55             },
56             {
57             th => 'Columns',
58             td => join(', ', @column_name),
59             },
60             }
61              
62 0           $content -> param(count => "sub build_basic_pane has run $count time(s)");
63 0           $content -> param(tr_loop => \@tr_loop);
64 0           $content -> param(commands => $self -> build_commands_output
65             ([
66             'Refresh',
67             ]) );
68 0           $content -> param(notes => $self -> build_notes_output
69             ([
70             'Hint: Click Refresh (below)',
71             "Previous command: $submit",
72             ]) );
73              
74 0           return $content -> output;
75              
76             } # End of build_basic_pane.
77              
78             # -----------------------------------------------
79              
80             sub build_commands_output
81             {
82 0     0 0   my($self, $command) = @_;
83 0           my($content) = $self -> load_tmpl('commands.tmpl');
84 0           my(@loop) = ();
85 0           my($max_column_count) = $self -> param('columns_of_commands_option');
86 0           my($row_count) = int( (@$command + $max_column_count - 1) / $max_column_count);
87 0           my($command_index) = - 1;
88              
89 0           my($row, $col);
90              
91 0           for $row (1 .. $row_count)
92             {
93 0           my(@td_loop);
94              
95 0           for $col (1 .. $max_column_count)
96             {
97 0           $command_index++;
98              
99 0 0         next if ($command_index > $#$command);
100              
101 0 0         if (ref($$command[$command_index]) eq 'ARRAY')
102             {
103 0           push @td_loop, {td => $$command[$command_index][0], onClick => $$command[$command_index][1]};
104             }
105             else
106             {
107 0           push @td_loop, {td => $$command[$command_index]};
108             }
109             }
110              
111 0           push @loop, {col_loop => \@td_loop};
112             }
113              
114 0 0         $content -> param(commands => $#$command == 0 ? 'Command' : 'Commands');
115 0           $content -> param(row_loop => \@loop);
116              
117 0           return $content -> output;
118              
119             } # End of build_commands_output.
120              
121             # -----------------------------------------------
122              
123             sub build_notes_output
124             {
125 0     0 0   my($self, $note) = @_;
126 0           my($content) = $self -> load_tmpl('notes.tmpl');
127 0           my(@loop) = ();
128              
129 0           push @loop, {td => $_} for (@$note);
130              
131 0           $content -> param(note_loop => \@loop);
132              
133 0           return $content -> output;
134              
135             } # End of build_notes_output.
136              
137             # -----------------------------------------------
138              
139             sub build_options_pane
140             {
141 0     0 0   my($self, $submit) = @_;
142 0           my($content) = $self -> load_tmpl('options.tmpl');
143 0           my(@key) = sort keys %{${$self -> param('key')}{'option'} };
  0            
  0            
144              
145 0           my(@loop, $minimum, $maximum, $s);
146              
147 0           for (@key)
148             {
149 0           $minimum = ${$self -> param('key')}{'option'}{$_}{'minimum'};
  0            
150 0           $maximum = ${$self -> param('key')}{'option'}{$_}{'maximum'};
  0            
151 0           ($s = $_) =~ s/_option$//;
152 0           $s =~ tr/_/ /;
153 0           $s = "Number of $s ($minimum .. $maximum)";
154              
155 0           push @loop,
156             {
157             option => $s,
158             name => $_,
159             value => $self -> session -> param($_),
160             };
161             }
162              
163 0           $content -> param(commands => $self -> build_commands_output
164             ([
165             ['Update options', q|onClick = "set('update_options')"|],
166             ]) );
167 0           $content -> param(notes => $self -> build_notes_output
168             ([
169             'DSN: ' . $self -> param('dsn'),
170             "Previous command: $submit",
171             ]) );
172 0           $content -> param(tr_loop => \@loop);
173              
174 0           return $content -> output;
175              
176             } # End of build_options_pane.
177              
178             # -----------------------------------------------
179              
180             sub cgiapp_get_query
181             {
182 0     0 1   my($self) = @_;
183              
184 0           return CGI::Simple -> new;
185              
186             } # End of cgiapp_get_query.
187              
188             # -----------------------------------------------
189              
190             sub cgiapp_init
191             {
192 0     0 1   my($self) = @_;
193 0           my($config) = CGI::Application::Demo::Basic::Util::Config -> new('basic.conf') -> config;
194              
195             # All this stuff is here so that we can call
196             # CGI::Application::Plugin::LogDispatch's log_config, if at all,
197             # in cgiapp_init (as suggested by its docs) rather than in setup.
198              
199 0           $self -> param(config => $config);
200 0           $self -> param(css_url => $$config{'css_url'});
201 0           $self -> param(dsn => $$config{'dsn'});
202 0           $self -> param(title => $$config{'dsn'});
203 0           $self -> param(tmpl_path => $$config{'tmpl_path'});
204              
205             # Set up the classes for each table, via the magic of Class::DBI.
206             # I have used a constraint because this is a demo, and I've only
207             # created one module for Class::DBI to chew on:
208             # CGI::Application::Demo::Basic::Faculty.
209              
210 0           my($loader) = Class::DBI::Loader -> new
211             (
212             constraint => '^faculty$',
213             dsn => $$config{'dsn'},
214             user => $$config{'username'},
215             password => $$config{'password'},
216             options => $$config{'dsn_attribute'},
217             namespace => '',
218             relationships => 1,
219             );
220              
221 0           $self -> setup_db_interface($loader);
222 0           $self -> param(dbh => ${$self -> param('cgi_app_demo_classes')}[0] -> db_Main);
  0            
223              
224             # Set up interface to logger.
225              
226 0           $self -> log_config
227             (
228             LOG_DISPATCH_MODULES =>
229             [{
230             dbh => $self -> param('dbh'),
231             min_level => 'info',
232             module => 'CGI::Application::Demo::Basic::Util::LogDispatchDBI',
233             name => __PACKAGE__,
234             },
235             ]
236             );
237              
238             # Set up interface to CGI::Session.
239              
240 0           $self -> session_config
241             (
242             CGI_SESSION_OPTIONS => [$$config{'session_driver'}, $self -> query, {Handle => $self -> param('dbh')}],
243             DEFAULT_EXPIRY => $$config{'session_timeout'},
244             SEND_COOKIE => 0,
245             );
246              
247             # Recover options from session, if possible.
248             # If not, initialize them.
249             # This hash holds details of the set of options.
250              
251 0           $self -> param(key =>
252             {
253             option =>
254             {
255             columns_of_commands_option =>
256             {
257             default => 3,
258             maximum => 20,
259             minimum => 1,
260             size => 2,
261             type => 'integer',
262             },
263             records_per_page_option =>
264             {
265             default => 100,
266             maximum => 1000,
267             minimum => 1,
268             size => 4,
269             type => 'integer',
270             },
271             },
272             });
273              
274 0           my(@key) = keys %{${$self -> param('key')}{'option'} };
  0            
  0            
275              
276 0           $self -> param($_ => $self -> session -> param($_) ) for @key;
277              
278             # Pick any option to see if they've all be initialized.
279              
280 0 0         if (! $self -> param('records_per_page_option') )
281             {
282 0           my($value);
283              
284 0           for (@key)
285             {
286 0           $value = ${$self -> param('key')}{'option'}{$_}{'default'};
  0            
287              
288 0           $self -> param($_ => $value);
289 0           $self -> session -> param($_ => $value);
290             }
291             }
292              
293             } # End of cgiapp_init.
294              
295             # --------------------------------------------------
296             # Note: This code retrieves the config in order to access 'dsn'.
297             # This illustrates a different method of accessing config data
298             # than, say, sub setup. The latter uses the fact that some data
299             # (tmpl_path) has been copied out of the config into an app param.
300             # This copying took place near the start of sub cgiapp_init.
301             # In the same way (as the latter technique) sub start uses
302             # css_url, which was also copied in sub cgiapp_init.
303              
304             sub db_vendor
305             {
306 0     0 0   my($self) = @_;
307 0           my($config) = $self -> param('config');
308 0           my($vendor) = $$config{'dsn'} =~ /[^:]+:([^:]+):/;
309              
310 0           return uc $vendor;
311              
312             } # End of db_vendor.
313              
314             # -----------------------------------------------
315             # Given a class we return an array of 3 elements:
316             # 0: An array ref of primary column names
317             # 1: An array ref of all other column names
318             # 2: An array ref of all column names
319             # The names are in the order returned by the class, which is best because
320             # the database designer probably set up the table with the columns in a
321             # specific order, and the names of the primary key columns are in a
322             # specific order anyway. And the caller can sort the [1] if desired.
323              
324             sub get_columns
325             {
326 0     0 0   my($self, $class) = @_;
327 0           my(@column) = $class -> columns;
328 0           my(@primary_column) = $class -> primary_columns;
329              
330 0           my(%primary_column);
331              
332 0           @primary_column{@primary_column} = (1) x @primary_column;
333 0           my(@other_column) = grep{! $primary_column{$_} } @column;
  0            
334              
335 0           return ([@primary_column], [@other_column], [@column]);
336              
337             } # End of get_columns.
338              
339             # -----------------------------------------------
340              
341             sub setup
342             {
343 0     0 1   my($self) = @_;
344              
345 0           $self -> run_modes(start => \&start, update_options => \&update_options);
346 0           $self -> tmpl_path($self -> param('tmpl_path') );
347              
348             } # End of setup.
349              
350             # -----------------------------------------------
351              
352             sub setup_db_interface
353             {
354 0     0 0   my($self, $parameter ) = @_;
355 0           my($classes) = [];
356              
357 0 0         if (ref($parameter) eq 'ARRAY')
    0          
358             {
359 0           for my $cdbi_class (@$parameter)
360             {
361             # Check to see if it's loaded already.
362              
363 0 0         if (! $cdbi_class::)
364             {
365 0           my($file) = $cdbi_class;
366 0           $file =~ s|::|/|g;
367              
368             eval
369 0           {
370 0           require "$file.pm";
371              
372 0           $cdbi_class -> import;
373             };
374              
375 0 0         die "CGI::Application::Demo::Basic::setup_db_interface: Couldn't require class: $cdbi_class: $@" if ($@);
376             }
377              
378 0           push @$classes, $cdbi_class;
379             }
380             }
381             elsif (ref($parameter) =~ /^Class::DBI::Loader/)
382             {
383 0           push @$classes, $_ for $parameter -> classes;
384             }
385             else
386             {
387 0           my($ref) = ref($parameter);
388              
389 0           die "CGI::Application::Demo::Basic::setup_db_interface: Invalid parameter\nParameter must either be an array reference of Class::DBI classes or a Class::DBI::Loader object\nYou gave me a $ref object.";
390             }
391              
392 0           $self -> param(cgi_app_demo_classes => $classes);
393              
394 0           my($tables) = {};
395              
396 0           for my $cdbi_class (@{$self -> param('cgi_app_demo_classes')})
  0            
397             {
398 0           my($table) = $cdbi_class -> table;
399 0           $$tables{$table} = $cdbi_class;
400             }
401              
402 0           $self -> param(cgi_app_demo_tables => $tables);
403              
404             } # End of setup_db_interface.
405              
406             # -----------------------------------------------
407              
408             sub start
409             {
410 0     0 0   my($self) = shift;
411 0           my($config) = $self -> param('config');
412 0   0       my($submit) = $self -> query -> param('submit') || '';
413 0           my($template) = $self -> load_tmpl($$config{'tmpl_name'});
414 0           my($content) = $self -> build_basic_pane($submit) . $self -> build_options_pane($submit);
415              
416 0           $template -> param(content => $content);
417 0           $template -> param(css_url => $self -> param('css_url') );
418 0           $template -> param(rm => $self -> query -> param('rm') );
419 0           $template -> param(sid => $self -> session -> id);
420 0           $template -> param(title => $self -> param('title') );
421 0           $template -> param(url => $self -> query -> url . $self -> query -> path_info);
422              
423 0           return $template -> output;
424              
425             } # End of start.
426              
427             # -----------------------------------------------
428              
429             sub update_options
430             {
431 0     0 0   my($self) = @_;
432 0           my(@key) = keys %{${$self -> param('key')}{'option'} };
  0            
  0            
433              
434 0           $self -> log -> info('Called update_options');
435              
436 0           my($value, $default, $minimum, $maximum);
437              
438 0           for (@key)
439             {
440 0           $default = ${$self -> param('key')}{'option'}{$_}{'default'};
  0            
441 0           $minimum = ${$self -> param('key')}{'option'}{$_}{'minimum'};
  0            
442 0           $maximum = ${$self -> param('key')}{'option'}{$_}{'maximum'};
  0            
443 0           $value = $self -> query -> param($_);
444 0 0 0       $value = $default if (! defined($value) || ($value < $minimum) || ($value > $maximum) );
      0        
445              
446 0           $self -> param($_ => $value);
447 0           $self -> session -> param($_ => $value);
448             }
449              
450 0           return $self -> start;
451              
452             } # End of update_options.
453              
454             # -----------------------------------------------
455              
456             1;
457              
458             __END__