File Coverage

lib/Parse/Dia/SQL/Output/HTML.pm
Criterion Covered Total %
statement 21 21 100.0
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 28 28 100.0


'; '; {/def:tablelistitem}
line stmt bran cond sub pod time code
1             package Parse::Dia::SQL::Output::HTML;
2              
3             # $Id: $
4              
5             =pod
6              
7             =head1 NAME
8              
9             Parse::Dia::SQL::Output::HTML - Create HTML documentation.
10              
11             =head1 SYNOPSIS
12              
13             use Parse::Dia::SQL;
14             my $dia = Parse::Dia::SQL->new(
15             file => 'foo.dia',
16             db => 'html' [ , htmlformat => {formatfile} ]
17             );
18             print $dia->get_sql();
19              
20             =head1 DESCRIPTION
21              
22             This sub-class creates HTML formatted database documentation.
23              
24             HTML formatting is controlled by templates selected with the optional
25             I parameter which supplies a format file. See L
26             formats"> for more.
27              
28             The generated HTML is intended to be useful rather than beautiful.
29              
30             This sub-class follows the same structure as the rdbms output
31             sub-classes with the intent of maintaining consistency, even though
32             this give less than optimum efficiency.
33              
34             =cut
35              
36 1     1   1235 use warnings;
  1         2  
  1         25  
37 1     1   2 use strict;
  1         2  
  1         14  
38              
39 1     1   2 use Text::Table;
  1         1  
  1         11  
40 1     1   3 use Data::Dumper;
  1         1  
  1         36  
41 1     1   3 use File::Spec::Functions qw(catfile);
  1         13  
  1         55  
42              
43 1     1   3 use lib q{lib};
  1         1  
  1         4  
44 1     1   65 use base q{Parse::Dia::SQL::Output}; # extends
  1         1  
  1         96  
45             use Config;
46              
47             require Parse::Dia::SQL::Logger;
48             require Parse::Dia::SQL::Const;
49              
50              
51             =head2 new
52              
53             The constructor.
54              
55             Object names in HTML have no inherent limit. 64 has been arbitrarily chosen.
56              
57             =cut
58              
59             sub new {
60             my ( $class, %param ) = @_;
61             my $self = {};
62              
63             # Set defaults for sqlite
64             $param{db} = q{html};
65             $param{object_name_max_length} = $param{object_name_max_length} || 64;
66             $param{htmlformat} = $param{htmlformat} || '';
67              
68             $self = $class->SUPER::new( %param );
69             bless( $self, $class );
70              
71             $self->{dbdata} = {}; # table data, keyed by tablename
72             $self->{htmltemplate} = {}; # html template elements
73             $self->set_html_template($param{htmlformat}); # find the template elements based on the selected format
74              
75             return $self;
76             }
77              
78             =head2 get_sql
79              
80             Return all sql documentation.
81              
82             First build the data structures:
83              
84             schema create
85             view create
86             permissions create
87             inserts
88             associations create (indices first, then foreign keys)
89              
90             Then generate the output:
91              
92             html start
93             html comments
94             body start
95             generate main html
96             body end
97             html end
98              
99             =cut
100              
101             sub get_sql {
102             my $self = shift;
103              
104             ## no critic (NoWarnings)
105             no warnings q{uninitialized};
106              
107             $self->get_schema_create();
108             $self->get_view_create();
109             $self->get_permissions_create();
110             $self->get_inserts();
111             $self->get_associations_create();
112              
113             my $html = ''
114             . $self->_get_preamble()
115             . $self->_get_comment()
116             . $self->get_smallpackage_pre_sql()
117             . $self->generate_html()
118             . $self->get_smallpackage_post_sql()
119             . $self->_get_postscript()
120             ;
121              
122             return $html;
123             }
124              
125             =head2 _get_preamble
126              
127             HTML Header
128              
129             =cut
130             sub _get_preamble {
131             my $self = shift;
132             my $files_word =
133             (scalar(@{ $self->{files} }) > 1)
134             ? q{Input files}
135             : q{Input file};
136              
137             my $data = $self->{htmltemplate}{htmlpreamble};
138              
139             # File name
140             my $value = $self->{files}[0];
141             $data =~ s/{filename}/$value/mgi;
142              
143             # todo: meta tags?
144             return $data
145             }
146              
147              
148             =head2 _get_comment
149              
150             Comment for HTML Header
151              
152             =cut
153              
154             sub _get_comment {
155             my $self = shift;
156             my $files_word =
157             (scalar(@{ $self->{files} }) > 1)
158             ? q{Input files}
159             : q{Input file};
160              
161             $self->{gentime} = scalar localtime();
162              
163             my @arr = (
164             [ q{Parse::SQL::Dia}, qq{version $Parse::Dia::SQL::VERSION} ],
165             [ q{Documentation}, q{http://search.cpan.org/dist/Parse-Dia-SQL/} ],
166             [ q{Environment}, qq{Perl $], $^X} ],
167             [ q{Architecture}, qq{$Config{archname}} ],
168             [ q{Target Database}, $self->{db} ],
169             [ $files_word, join(q{, }, @{ $self->{files} }) ],
170             [ q{Generated at}, $self->{gentime} ],
171             );
172              
173             $self->{filename} = join(q{, }, @{ $self->{files} });
174              
175             my $value = '';
176             my $data = $self->{htmltemplate}{htmlcomment};
177             my $tb = Text::Table->new();
178             $tb->load(@arr);
179              
180             $value = scalar $tb->table();
181             $data =~ s/{htmlcomment}/$value/mgi;
182              
183             return $data;
184             }
185              
186             =head2 get_smallpackage_pre_sql
187              
188             HTML Body start
189              
190             =cut
191             sub get_smallpackage_pre_sql {
192             my $self = shift;
193             my $data;
194              
195             $data = $self->{htmltemplate}{htmlstartbody};
196              
197             return $data
198             }
199              
200             =head2 get_smallpackage_post_sql
201              
202             HTML Body close
203              
204             =cut
205             sub get_smallpackage_post_sql {
206             my $self = shift;
207             my $data;
208              
209             $data = $self->{htmltemplate}{htmlendbody};
210             $data =~ s/{gentime}/$self->{gentime}/mgi;
211              
212             return $data
213             }
214              
215             =head2 _get_postscript
216              
217             HTML close
218              
219             =cut
220              
221             sub _get_postscript {
222             my $self = shift;
223             my $data = '';
224              
225             $data = $self->{htmltemplate}{htmlend};
226              
227             return $data
228             }
229              
230             =head2 _get_create_table_sql
231              
232             Extracts the documentation details for a single table.
233              
234             =cut
235              
236             sub _get_create_table_sql {
237             my ( $self, $table ) = @_;
238             #my $sqlstr = '';
239             my $temp;
240             my $comment;
241             my $tablename;
242             my $update;
243             my $primary_keys = '';
244             my $order = 0;
245              
246             my $tabletemplate = '';
247             my $tablerowemplate = '';
248             my $tabledata = '';
249             my $tablerowdata = '';
250              
251             # Table name
252             $tablename = $table->{name};
253             $self->{'dbdata'}{$tablename} = {};
254              
255             # Comments 1 - strip the autoupdate bits
256             $comment = $table->{comment};
257             if ( !defined( $comment ) ) { $comment = ''; }
258             if ( $comment ne '' ) {
259             $comment =~ s/\n//g;
260             $comment =~ s///mgi;
261             }
262              
263             # Comments 2 - just the autoupdate bits
264             $update = $table->{comment};
265             if ( !defined( $update ) ) { $update = ''; }
266             if ( $update =~ //mi ) {
267             $update = $3; # update code
268             }
269              
270             # Set up build the table documentation
271             $self->{'dbdata'}{$tablename}{'name'} = $tablename;
272             $self->{'dbdata'}{$tablename}{'comment'} = $comment;
273             $self->{'dbdata'}{$tablename}{'autoupdate'} = $update;
274             $self->{'dbdata'}{$tablename}{'fields'} = {}; # field list, keyed by field name
275             $self->{'dbdata'}{$tablename}{'keyfields'} = {}; # primary key fields
276             $self->{'dbdata'}{$tablename}{'ref_by'} = {}; # tables that use this as a FK
277             $self->{'dbdata'}{$tablename}{'ref_to'} = {}; # tables that this uses for FK
278             $self->{'dbdata'}{$tablename}{'permissions'} = []; # permissions array
279             $self->{'dbdata'}{$tablename}{'indices'} = {}; # indices keyed by index name
280              
281             # Fields
282             # Check not null and primary key property for each column. Column
283             # visibility is given in $columns[3]. A value of 2 in this field
284             # signifies a primary key (which also must be defined as 'not null'.
285             $tablerowdata = '';
286             foreach my $column (@{ $table->{attList} }) {
287              
288             if (ref($column) ne 'ARRAY') {
289             $self->{log}
290             ->error(q{Error in view attList input - expect an ARRAY ref!});
291             next COLUMN;
292             }
293              
294             # Don't warn on uninitialized values here since there are lots
295             # of them.
296              
297             ## no critic (ProhibitNoWarnings)
298             no warnings q{uninitialized};
299              
300             # Field sequence:
301             my ($col_name, $col_type, $col_val, $col_vis, $col_com) = @{$column};
302             $self->{'dbdata'}{$tablename}{'fields'}{$col_name} = {
303             'name' => $col_name,
304             'type' => $col_type,
305             'default' => $col_val,
306             'comment' => $col_com,
307             'order' => $order,
308             };
309             $order ++;
310              
311             ## Add 'not null' if field is primary key
312             if ($col_vis == 2) {
313             $self->{'dbdata'}{$tablename}{'fields'}{$col_name}{'default'} = 'not null';
314             $self->{'dbdata'}{$tablename}{'keyfields'}{$col_name} = 1;
315             }
316             }
317              
318             return '';
319             }
320              
321             =head2 get_schema_drop
322              
323             Do nothing
324              
325             =cut
326              
327             sub get_schema_drop {
328             return '';
329             }
330              
331             =head2 get_view_drop
332              
333             Do nothing
334              
335             =cut
336              
337             sub get_view_drop {
338             return '';
339             }
340              
341             =head2 _get_fk_drop
342              
343             Do nothing
344              
345             =cut
346              
347             sub _get_fk_drop {
348             return '';
349             }
350              
351             =head2 _get_drop_index_sql
352              
353             Do nothing
354              
355             =cut
356              
357             sub _get_drop_index_sql {
358             return '';
359             }
360              
361             =head2 get_permissions_create
362              
363             Permissions are formatted as C<{type} {name} to {list of roles}> where:
364              
365             C is the operation C, C etc
366              
367             C is the permission name C
368              
369             C is the set of datbase roles affected.
370              
371             =head3 Warning
372              
373             Permissions are at best lightly tested (ie potentially buggy)
374              
375             =cut
376              
377             sub get_permissions_create {
378             my $self = shift;
379             #my $sqlstr = '';
380             #my $temparrayref;
381              
382             # Check classes
383             return unless $self->_check_classes();
384              
385             # loop through classes looking for grants
386             foreach my $table (@{ $self->{classes} }) {
387              
388             foreach my $operation (@{ $table->{ops} }) {
389              
390             if (ref($operation) ne 'ARRAY') {
391             $self->{log}->error(
392             q{Error in ops input - expect an ARRAY ref, got } . ref($operation));
393             next OPERATION;
394             }
395              
396             my ($opname, $optype, $colref) =
397             ($operation->[0], $operation->[1], $operation->[2]);
398              
399             # 2nd element can be index, unique index, grant, etc
400             next if (lc($optype) ne q{grant} and lc($optype) ne q{revoke} );
401             # TODO:BUG in core code - should accecpt revoke or grant, not just grant
402              
403             # Add backticks if option is set and dbtype is correct
404             my $tablename = $self->_quote_identifier($table->{name});
405              
406             my $temp = qq{$optype $opname to } . join(q{,}, @{$colref});
407             push @{ $self->{'dbdata'}{$tablename}{'permissions'} }, $temp;
408             }
409             }
410              
411             return '';
412             }
413              
414             =head2 get_permissions_drop
415              
416             Do nothing
417              
418             =cut
419              
420             sub get_permissions_drop {
421             return '';
422             }
423              
424             =head2 _get_create_association_sql
425              
426             Extracts the documentation for table relationships.
427              
428             =cut
429              
430             # Create sql for given association.
431             sub _get_create_association_sql {
432             my ( $self, $association ) = @_;
433             my $temp;
434              
435             # Sanity checks on input
436             if ( ref( $association ) ne 'ARRAY' ) {
437             $self->{log}
438             ->error( q{Error in association input - cannot create association sql!} );
439             return;
440             }
441              
442             my (
443             $table_name, $constraint_name, $key_column,
444             $ref_table, $ref_column, $constraint_action
445             ) = @{$association};
446              
447             $self->{'dbdata'}{$ref_table}{'ref_by'}{$constraint_name} = {'table' => $table_name, 'key' => $key_column, 'fk' => $ref_column, 'action' => $constraint_action};
448             $self->{'dbdata'}{$table_name}{'ref_to'}{$constraint_name} = {'table' => $ref_table, 'key' => $ref_column, 'fk' => $key_column, 'action' => $constraint_action};
449              
450             return '';
451             }
452              
453              
454             =head2 _get_create_index_sql
455              
456             Extracts the documentation for table indices.
457              
458             =cut
459              
460             # Create sql for all indices for given table.
461             sub _get_create_index_sql {
462             my ($self, $table) = @_;
463             my $sqlstr = q{};
464              
465             # Sanity checks on input
466             if (ref($table) ne 'HASH') {
467             $self->{log}->error(q{Error in table input - cannot create index sql!});
468             return;
469             }
470              
471             OPERATION:
472             foreach my $operation (@{ $table->{ops} }) {
473              
474             if (ref($operation) ne 'ARRAY') {
475             $self->{log}->error(
476             q{Error in ops input - expect an ARRAY ref, got } . ref($operation));
477             next OPERATION;
478             }
479              
480             # Extract elements (the stereotype is not in use)
481             my ($opname, $optype, $colref, $opstereotype, $opcomment) = (
482             $operation->[0], $operation->[1], $operation->[2],
483             $operation->[3], $operation->[4]
484             );
485              
486             # 2nd element can be index, unique index, grant, etc.
487             # Accept "index" only in this context.
488             if ($optype !~ qr/^(unique )?index$/i) {
489             $self->{log}->debug(qq{Skipping optype '$optype' - not (unique) index});
490             next OPERATION;
491             }
492              
493             my $idx_opt =
494             (defined $opcomment && $opcomment ne q{})
495             ? $opcomment
496             : join(q{,}, @{ $self->{index_options} });
497              
498             $optype =~ s/index(\w*)//; # remove the 'index' word, leaving unique
499             $self->{'dbdata'}{$table->{name}}{'indices'}{$opname} = {'columns' => join(q{, }, @{$colref}), 'comment' => $idx_opt, 'type' => $optype};
500             # Use operation comment as index option if defined, otherwise
501             # use default (if any)
502             }
503             return '';
504             }
505              
506              
507             =head2 generate_html
508              
509             Do the output
510              
511             =cut
512              
513             sub generate_html {
514             my $self = shift;
515             my $html = '';
516             my $table = '';
517             my $tabledata = '';
518             my $rowdata = '';
519             my $field = '';
520             my $temp = '';
521             my $value = '';
522             my $sep = '';
523             #my $temparray;
524             my $fieldblank = $self->{htmltemplate}{fieldblank};
525              
526             $html = '';
527             $sep = '';
528             $rowdata = '';
529             # Table list
530             foreach $table (sort keys %{$self->{'dbdata'}}) {
531             $tabledata = $self->{htmltemplate}{tablelistitem};
532              
533             # Table name
534             $temp = $self->{'dbdata'}{$table}{'name'} || $fieldblank;
535             $tabledata =~ s/{tablename}/$temp/mgi;
536              
537             # Table comment
538             $value = $self->{'dbdata'}{$table}{'comment'};
539             if ( $value) {
540             $temp = $self->{htmltemplate}{tablecommentlist};
541             $temp =~ s/{comment}/$value/mgi;
542             }
543             else {
544             $temp = $fieldblank; # list context
545             }
546             $tabledata =~ s/{tablecomment}/$temp/mgi;
547              
548             $rowdata .= $sep . $tabledata;
549             $sep = $self->{htmltemplate}{tablelistsep};
550             }
551             $temp = $self->{htmltemplate}{tablelist};
552             $temp =~ s/{tablelist}/$rowdata/mgi;
553             $value = $self->{filename};
554             $temp =~ s/{filename}/$value/mgi;
555             $html .= $temp;
556              
557            
558             # Table details
559             $temp = $self->{htmltemplate}{tablestart};
560             $html .= $temp;
561             foreach $table (sort keys %{$self->{'dbdata'}}) {
562             $tabledata = $self->{htmltemplate}{table};
563              
564             # Table name
565             $temp = $self->{'dbdata'}{$table}{'name'};
566             $tabledata =~ s/{tablename}/$temp/mgi;
567              
568             # Table comment
569             $value = $self->{'dbdata'}{$table}{'comment'};
570             if ( $value) {
571             $temp = $self->{htmltemplate}{tablecomment};
572             $temp =~ s/{comment}/$value/mgi;
573             }
574             else {
575             $temp = '';
576             }
577             $tabledata =~ s/{tablecomment}/$temp/mgi;
578              
579             # Autoupdate
580             $value = $self->{'dbdata'}{$table}{'autoupdate'};
581             if ( $value) {
582             $temp = $self->{htmltemplate}{autoupdate};
583             $temp =~ s/{autoupdate}/$value/mgi;
584             }
585             else {
586             $temp = '';
587             }
588             $tabledata =~ s/{autoupdate}/$temp/mgi;
589              
590             # Field data
591             $rowdata = '';
592             # PK fields first - in diagram order
593             foreach $field (sort {$self->{'dbdata'}{$table}{'fields'}{$a}{'order'} <=> $self->{'dbdata'}{$table}{'fields'}{$b}{'order'}} keys %{$self->{'dbdata'}{$table}{'keyfields'}}) {
594             $temp = $self->{htmltemplate}{tablekeyrow};
595             $value = $self->{'dbdata'}{$table}{'fields'}{$field}{'name'} || $fieldblank;
596             $temp =~ s/{name}/$value/mgi;
597             $value = $self->{'dbdata'}{$table}{'fields'}{$field}{'type'} || $fieldblank;
598             $temp =~ s/{type}/$value/mgi;
599             $value = $self->{'dbdata'}{$table}{'fields'}{$field}{'default'} || $fieldblank;
600             $temp =~ s/{default}/$value/mgi;
601             $value = $self->{'dbdata'}{$table}{'fields'}{$field}{'comment'} || $fieldblank;
602             $value =~ s/\n//gmi;
603             $temp =~ s/{comment}/$value/mgi;
604             $rowdata .= $temp;
605             }
606              
607             # Other fields - in diagram order
608             foreach $field (sort {$self->{'dbdata'}{$table}{'fields'}{$a}{'order'} <=> $self->{'dbdata'}{$table}{'fields'}{$b}{'order'}} keys %{$self->{'dbdata'}{$table}{'fields'}}) {
609             if ( not defined($self->{'dbdata'}{$table}{'keyfields'}{$field})){
610             $temp = $self->{htmltemplate}{tablerow};
611             $value = $self->{'dbdata'}{$table}{'fields'}{$field}{'name'} || $fieldblank;
612             $temp =~ s/{name}/$value/mgi;
613             $value = $self->{'dbdata'}{$table}{'fields'}{$field}{'type'} || $fieldblank;
614             $temp =~ s/{type}/$value/mgi;
615             $value = $self->{'dbdata'}{$table}{'fields'}{$field}{'default'} || $fieldblank;
616             $temp =~ s/{default}/$value/mgi;
617             $value = $self->{'dbdata'}{$table}{'fields'}{$field}{'comment'} || $fieldblank;
618             $value =~ s/\n//gmi;
619             $temp =~ s/{comment}/$value/mgi;
620             $rowdata .= $temp;
621             }
622             }
623             $tabledata =~ s/{tablerowdata}/$rowdata/mgi;
624              
625             # References
626             $rowdata = '';
627             $sep = '';
628             foreach $field (sort keys %{$self->{'dbdata'}{$table}{'ref_by'}}) {
629             $temp = $self->{htmltemplate}{refbyitem};
630             $value = $self->{'dbdata'}{$table}{'ref_by'}{$field}{'table'};
631             $temp =~ s/{tablename}/$value/mgi;
632             $value = $self->{'dbdata'}{$table}{'ref_by'}{$field}{'key'};
633             $temp =~ s/{key}/$value/mgi;
634             $value = $self->{'dbdata'}{$table}{'ref_by'}{$field}{'fk'};
635             $temp =~ s/{fk}/$value/mgi;
636             $value = $self->{'dbdata'}{$table}{'ref_by'}{$field}{'action'};
637             $temp =~ s/{action}/$value/mgi;
638             $temp =~ s/{refname}/$field/mgi;
639             $rowdata .= $sep . $temp;
640             $sep = $self->{htmltemplate}{refbysep};
641             }
642             if ( $rowdata ) {
643             $temp = $self->{htmltemplate}{refby};
644             $temp =~ s/{refbylist}/$rowdata/mgi;
645             $tabledata =~ s/{refby}/$temp/mgi;
646             }
647             else {
648             $tabledata =~ s/{refby}//mgi;
649             }
650              
651             $rowdata = '';
652             $sep = '';
653             foreach $field (sort keys %{$self->{'dbdata'}{$table}{'ref_to'}}) {
654             $temp = $self->{htmltemplate}{reftoitem};
655             $value = $self->{'dbdata'}{$table}{'ref_to'}{$field}{'table'};
656             $temp =~ s/{tablename}/$value/mgi;
657             $value = $self->{'dbdata'}{$table}{'ref_to'}{$field}{'key'};
658             $temp =~ s/{key}/$value/mgi;
659             $value = $self->{'dbdata'}{$table}{'ref_to'}{$field}{'fk'};
660             $temp =~ s/{fk}/$value/mgi;
661             $value = $self->{'dbdata'}{$table}{'ref_to'}{$field}{'action'};
662             $temp =~ s/{action}/$value/mgi;
663             $temp =~ s/{refname}/$field/mgi;
664             $rowdata .= $sep . $temp;
665             $sep = $self->{htmltemplate}{refbysep};
666             }
667             if ( $rowdata ) {
668             $temp = $self->{htmltemplate}{refto};
669             $temp =~ s/{reftolist}/$rowdata/mgi;
670             $tabledata =~ s/{refto}/$temp/mgi;
671             }
672             else {
673             $tabledata =~ s/{refto}//mgi;
674             }
675              
676             # Indices
677             $rowdata = '';
678             $sep = '';
679             foreach $field (sort keys %{$self->{'dbdata'}{$table}{'indices'}}) {
680             $temp = $self->{htmltemplate}{indexitem};
681             $temp =~ s/{tablename}/$table/mgi;
682             $value = $self->{'dbdata'}{$table}{'indices'}{$field}{'columns'};
683             $temp =~ s/{columns}/$value/mgi;
684             $value = $self->{'dbdata'}{$table}{'indices'}{$field}{'comment'};
685             $temp =~ s/{comment}/$value/mgi;
686             $value = $self->{'dbdata'}{$table}{'indices'}{$field}{'type'};
687             $temp =~ s/{type}/$value/mgi;
688             $temp =~ s/{indexname}/$field/mgi;
689             $rowdata .= $sep . $temp;
690             $sep = $self->{htmltemplate}{indexsep};
691             }
692             if ( $rowdata ) {
693             $temp = $self->{htmltemplate}{indices};
694             $temp =~ s/{indexlist}/$rowdata/mgi;
695             $tabledata =~ s/{indices}/$temp/mgi;
696             }
697             else {
698             $tabledata =~ s/{indices}//mgi;
699             }
700              
701             # Permissions
702             $rowdata = '';
703             $sep = '';
704             if (scalar(@{ $self->{'dbdata'}{$table}{'permissions'} })) {
705             foreach $field (@{ $self->{'dbdata'}{$table}{'permissions'} }) {
706             $temp = $self->{htmltemplate}{permissionitem};
707             $temp =~ s/{permission}/$field/mgi;
708             $rowdata .= $sep . $temp;
709             $sep = $self->{htmltemplate}{permissionsep};
710             }
711             }
712             if ( $rowdata ) {
713             $temp = $self->{htmltemplate}{permission};
714             $temp =~ s/{permissionlist}/$rowdata/mgi;
715             $tabledata =~ s/{permissions}/$temp/mgi;
716             }
717             else {
718             $tabledata =~ s/{permissions}//mgi;
719             }
720              
721             $html .= $tabledata;
722              
723             }
724              
725             return $html;
726             }
727              
728              
729              
730             =head2 set_html_template
731              
732             Set up the formatting template
733              
734             Template elements use C<{placeholders}> to identify how the document should be built.
735              
736             =cut
737              
738             sub set_html_template {
739             my $self = shift;
740             my $format = shift;
741              
742             $format = lc($format);
743              
744             # Standard HTML bits
745             $self->{htmltemplate}{htmlpreamble} = "\nDatabase documentation: {filename}";
746             $self->{htmltemplate}{htmlcomment} = "\n\n";
747             $self->{htmltemplate}{htmlstartbody} = '';
748             $self->{htmltemplate}{htmlendbody} = '

Generated at {gentime}.

';
749             $self->{htmltemplate}{htmlend} = '';
750              
751             # List of tables
752             $self->{htmltemplate}{tablelist} = <<"END";
753              
754            

Data Dictionary for {filename}

755            

List of Tables

756             {tablelist}
757            
758              
759             END
760              
761             $self->{htmltemplate}{tablestart} = "

Table details

\n";
762             $self->{htmltemplate}{tablelistitem} = "{tablename}";
763             $self->{htmltemplate}{tablelistsep} = ', ';
764              
765             # Table: a single table details, mostly placeholders for individual elements
766             $self->{htmltemplate}{table} = <<"END";
767            

Table: {tablename}

768             {tablecomment}
769             {refto}
770             {refby}
771            
772            
FieldTypeDefaultDescription
773             {tablerowdata}
774            
775             {autoupdate}
776             {indices}
777             {permissions}
778            
779             END
780              
781             # tablekeyrowtemplate - a single Primary Key row
782             $self->{htmltemplate}{tablekeyrow} = '
{name}{type}{default}{comment}
783              
784             # tablerowtemplate - a single non-Key row
785             $self->{htmltemplate}{tablerow} = '
{name}{type}{default}{comment}
786              
787             # comment - for the table comments (if any)
788             $self->{htmltemplate}{tablecomment} = '

{comment}

';
789             $self->{htmltemplate}{tablecommentlist} = '{comment}';
790              
791             # autoupdate
792             $self->{htmltemplate}{autoupdate} = '

Automatically set:{autoupdate}

';
793              
794             # References - a list of tables that refer to this one via foreign keys
795             # Each is formatted with 'refbyitem', separated by 'refbysep'.
796             $self->{htmltemplate}{refby} = '

Referenced by: {refbylist}

';
797             $self->{htmltemplate}{refbyitem} = "{tablename}"; #"{tablename}[{key}]";
798             $self->{htmltemplate}{refbysep} = ', ';
799              
800             # References - a similar list of tables which which this one refers
801             # Each is formatted with 'reftoitem', separated by 'reftosep'.
802             $self->{htmltemplate}{refto} = '

References: {reftolist}

';
803             $self->{htmltemplate}{reftoitem} = "{tablename}"; # "{tablename}[{key}] ({fk}, {action})";
804             $self->{htmltemplate}{reftosep} = ', '; # '
';
805              
806             # Permissions - a list of permissions on this table
807             # Each is formatted with 'permissionitem', separated by 'permissionsep'.
808             $self->{htmltemplate}{permission} = '

Permissions

{permissionlist}

';
809             $self->{htmltemplate}{permissionitem} = '{permission}';
810             $self->{htmltemplate}{permissionsep} = '
';
811              
812             # Indices - a list of indices on this table
813             # Each is formatted with 'indexitem', separated by 'indexsep'.
814             $self->{htmltemplate}{indices} = '

Indices

{indexlist}

';
815             $self->{htmltemplate}{indexitem} = '{indexname}: {type} on {columns} {comment}';
816             $self->{htmltemplate}{indexsep} = '
';
817            
818             $self->{htmltemplate}{fieldblank} = ' ';
819              
820             # If we have a format parameter, try to read that HTML template elements from it, overriding the defaults
821              
822             if ( $format) {
823             local $/=undef; # so we can slurp the whole file as one lump
824             open my $fh, '<', $format or die "Couldn't open format file: '$format' $!\n";
825             my $contents = <$fh>;
826             close $fh;
827             my $tag;
828             my $htmlelement;
829             while ($contents =~ m/\{(?:def\:)(.*?)(?:})(.*?)\{.def\:(\g1)/gsi ) {
830             $tag = $1;
831             $htmlelement = $2;
832             $htmlelement =~s/\\n/\n/g; # Replace \n's with \n's
833             $self->{htmltemplate}{$tag} = $htmlelement
834             }
835             }
836              
837             return;
838             }
839              
840             1;
841              
842             =head1 HTML Formats
843              
844             The default format may be all you need.
845             If you want to create different HTML formats for different uses, create a format file
846             with template elements defined between C<{def:element}> and C<{/def:element}> markers.
847             You only need to define those elements that you want to be I from the defaults.
848              
849             Any text outside the C<{def:element}> and C<{/def:element}> is ignored, so you can add comments without affecting the output.
850              
851             Any C<\n> literals in the format file are replaced with newlines; although newlines in the generated HTML typically have
852             no effect on the layout, they can make the output easier for humans to read.
853              
854              
855             =head2 Template elements
856              
857             =head3 htmlpreamble
858              
859             The start of the html document.
860              
861             I: filename
862              
863             I: \nDatabase documentation: {filename}
864              
865             =head3 htmlcomment
866              
867             A generated comment at the start of the html document. This is the standard comment at the start of the SQL script.
868              
869             I: htmlcomment
870              
871             I: \n\n
872              
873              
874             =head3 htmlstartbody
875              
876             The start body html tag.
877              
878             I:
879              
880              
881             =head3 htmlendbody
882              
883             The end body html tag.
884              
885             I: gentime
886              
887             I:

Generated at {gentime}.

888              
889              
890             =head3 htmlend
891              
892             The end html tag.
893              
894             I:
895              
896              
897             =head3 tablelist
898              
899             The bit at the top of the page which lists all the tables.
900             Each is formatted with L, separated by L.
901              
902             I: tablelist (the assembled list of table), filename
903              
904             I:
905              
906            

Data Dictionary for {filename}

907             List of Tables
908             {tablelist}
909            
910              
911              
912             =head3 tablelistitem
913              
914             An individual element (table) in the table list
915              
916             I: tablename, tablecomment
917              
918             I: {tablename}
919              
920              
921             =head3 tablelistsep
922              
923             Separator between individual elements in the table list.
924              
925             I: C<, >
926              
927              
928             =head3 tablestart
929              
930             Introduction to the table details
931              
932             I:

Table details

933              
934             =head3 table
935              
936             Details of one table.
937              
938             I: tablename, comment, refto, refby, tablerowdata, autoupdate, indices, permissions.
939              
940             I:
941              
942            

Table: {tablename}

943             {comment}
944             {refto}
945             {refby}
946            
947            
FieldTypeDefaultDescription
948             {tablerowdata}
949            
950             {autoupdate}
951             {indices}
952             {permissions}
953            
954              
955             =head3 tablekeyrow, tablerow
956              
957             Details of an individual field (column) from the (table) in the table detail.
958              
959             tablekeyrow is used for primary key fields, tablerow for other fields.
960              
961             I: name, type, default, comment.
962              
963             I B:
{name}{type}{default}{comment}
964              
965             I B:
{name}{type}{default}{comment}
966              
967              
968             =head3 tablecomment
969              
970             Table comments/description.
971              
972             I: comment
973              
974             I:

{comment}

975              
976             =head3 tablecommentlist
977              
978             Table comments/description in a list context
979              
980             I: comment
981              
982             I: {comment}
983              
984             =head3 autoupdate
985              
986             Auto update code, if used.
987              
988             I: autoupdate
989              
990             I:

Automatically set:{autoupdate}

991              
992              
993             =head3 refby, refto
994              
995             References by - a list of tables that refer to this one via foreign keys.
996              
997             References to - a list of tables to which this table refers via foreign keys.
998              
999             The whole section is omitted if there are no references (including any static text).
1000              
1001             I: refbylist, reftolist respectively.
1002              
1003             I: B

Referenced by: {refbylist}

1004              
1005             I: B

References: {reftolist}

1006              
1007              
1008             =head3 refbyitem, reftoitem
1009              
1010             A single item in the reference by list
1011              
1012             I: tablename, key, fk, action, refname
1013              
1014             Here I is the other table, I is the field in this table, I is the field in the other table,
1015             I in the action on update/delete (such as cascade or update) and I is the name of the constraint.
1016              
1017             I: {tablename}
1018              
1019              
1020             =head3 refbysep, reftosep
1021              
1022             Separator between references.
1023              
1024             I: C<, >
1025              
1026             =head3 indices
1027              
1028             List of indices on this tables.
1029              
1030             The whole section is omitted if there are no indices (including any static text).
1031              
1032             I: indexlist
1033              
1034             I:

Indices

{indexlist}

1035              
1036             =head3 indexitem
1037              
1038             A single item in the index list
1039              
1040             I: tablename, columns, comment, type, indexname
1041              
1042             Here I is the indexed (ie current) table, I is the set of columns in the index, I is the index comment if any,
1043             I is 'unique' (or blank) and I is the name of the index.
1044              
1045             I: {indexname}: {type} on {columns} {comment}
1046              
1047             =head3 indexsep
1048              
1049             Separator between indices.
1050              
1051             I: C<>
1052              
1053              
1054             =head3 permission
1055              
1056             A list of permissions granted on this table.
1057              
1058             I: permissionlist
1059              
1060             I:

Permissions

{permissionlist}

1061              
1062              
1063             =head3 permissionitem
1064              
1065             A single permission in the list
1066              
1067             I: permission
1068              
1069             I: {permission}
1070              
1071              
1072             =head3 permissionsep
1073              
1074             Separator between permissions.
1075              
1076             I:
1077              
1078              
1079             =head3 fieldblank
1080              
1081             Replacement character(s) for blank values. Default value is empty.
1082              
1083              
1084             =head2 Sample format file
1085              
1086             This format file generates vertical lists of tables and references rather than single paragraph, comma separated
1087             lists (which is the default).
1088              
1089             {def:tablelist}
1090            

List of Tables

1091            
1092            
NameDescription
1093             {tablelist}
1094            
1095              
1096            
1097             {/def:tablelist}
1098              
1099             {def:tablelistitem}
{tablename}{tablecomment}
1100             {def:tablelistsep}\n{/def:tablelistsep}
1101              
1102             {def:refby}

Referenced by:
{refbylist}

{/def:refby}
1103             {def:refbyitem}{fk}={tablename}.{key} {action}{/def:refbyitem}
1104             {def:refbysep}
{/def:refbysep}
1105              
1106             {def:refto}

References:
{reftolist}

{/def:refto}
1107             {def:reftoitem} {fk}={tablename}.{key} {action}{/def:reftoitem}
1108             {def:reftosep}
{/def:reftosep}
1109              
1110             # Comments don't matter
1111             {def:permission}

Permissions

{permissionlist}

{/def:permission}
1112             {def:permissionitem}{permission}{/def:permissionitem}
1113             {def:permissionsep}
{/def:permissionsep}
1114              
1115             Note that comments or other text outside the {def:}
1116             The other template elements are the same as the default.
1117              
1118              
1119             =head1 TODO
1120              
1121             Things that might get added in future versions:
1122              
1123             Views are not currently documented.
1124              
1125             Bugs etc
1126              
1127             =cut
1128              
1129             __END__