File Coverage

blib/lib/HTML/DataTable/DBI.pm
Criterion Covered Total %
statement 15 58 25.8
branch 0 24 0.0
condition 0 35 0.0
subroutine 5 12 41.6
pod 2 6 33.3
total 22 135 16.3


line stmt bran cond sub pod time code
1             package HTML::DataTable::DBI;
2 1     1   7022 use base HTML::DataTable;
  1         2  
  1         81  
3              
4 1     1   22 use 5.006;
  1         4  
  1         35  
5 1     1   6 use strict;
  1         2  
  1         36  
6 1     1   5 use warnings;
  1         2  
  1         26  
7              
8 1     1   2096 use DBI;
  1         17218  
  1         809  
9              
10             =head1 NAME
11              
12             HTML::DataTable::DBI - Print HTML tables from SQL queries
13              
14             =head1 VERSION
15              
16             Version 0.54
17              
18             =cut
19              
20             our $VERSION = 0.54;
21              
22             =head1 SYNOPSIS
23              
24             use HTML::DataTable::DBI;
25             my $list = HTML::DataTable::DBI->new(
26             data => $cgi_data,
27             columns => [
28             # hashrefs describing column formats
29             ],
30             sql => 'SELECT * FROM table_name WHERE foreign_key = ?',
31             sql_params => [ $some_value ],
32             delete => { } # Delete spec as shown below
33             );
34             print $list;
35              
36             =head1 METHODS
37              
38             Look in HTML::DataTable for column-definition and table formatting attributes
39              
40             =head2 ADDITIONAL ATTRIBUTES
41              
42             =head3 dsn
43              
44             A list containing a DBI connect string, username, and password.
45              
46             =head3 dbh
47              
48             You can supply a live DBI database handle instead of a DSN.
49              
50             =head3 sql
51              
52             A SQL query with optional "?" placeholders, which will be run and its results formatted and shown in the table.
53              
54             =head3 sql_params
55              
56             An optional arrayref containing the actual parameters for the SQL query.
57              
58             =head3 delete
59              
60             An optional hashref telling the list what record to delete. If this is included, a column will be added to the table to show trash icons. The hashref can take either of two forms. If the SQL query for this table is not parameterized - that is, the record's ID is all we need to know which record to delete - then the hashref can simply map the column index of the record ID to the CGI argument that supplies the one to delete:
61              
62             delete => {
63             sql => 'DELETE FROM table WHERE record_id = ?',
64             id => [ 0 => $args{delete} ],
65             }
66              
67             whereas if the query had a parameter the delete hashref has to give both the local and foreign keys:
68              
69             delete => {
70             sql => 'DELETE FROM table WHERE record_id = ? AND foreign_id = ?',
71             local => [ record_id => $args{speaker_id} ],
72             foreign => [ 0 => $args{delete} ],
73             }
74              
75             An optional "noun" attribute in that hashref can supply a word to replace "record" in the delete confirmation alert.
76              
77             =head3 trash_icon
78              
79             The URL of a trash can icon for use in the "Delete" column - defaults to /art/trash.gif.
80              
81             =head2 ADDITIONAL COLUMN ATTRIBUTES
82              
83             =head3 sql
84              
85             A paramterized SQL query that will be run to get results for this column.
86              
87             =head3 foreign_key_col
88              
89             The index of the column in the results from the main table's SQL query that will be used in the column's query's parameter. Defaults to 0.
90              
91             =head3 separator
92              
93             A character string that will be used to concatenate the results of the columns's query. Defaults to ", ".
94              
95             =cut
96              
97             sub set_letter {
98 0     0 0   my ($me, $letter) = @_;
99              
100 0           $me->{sql} .= ' WHERE lower(' . $me->{sort}->[0] . ") LIKE '" . lc $letter . "%'";
101             }
102              
103             sub set_search {
104 0     0 0   my ($me, $letter) = @_;
105              
106 0   0       $me->{_dbh} ||= $me->{dbh} || DBI->connect( @{ $me->{dsn} } ) || die "No DB connection";
      0        
107              
108 0           $me->{sql} .= ' WHERE ' . join ' OR ', map "position( lower(\$1) in lower($_) ) > 0",
109 0 0         ref $me->{search} eq 'ARRAY' ? @{$me->{search}} : split ' ', $me->{search};
110             }
111              
112             sub set_sort_order {
113 0     0 0   my $me = shift;
114              
115 0 0         return unless $me->{sort}->[0];
116 0           $me->{sql} .= ' ORDER BY ' . join ', ', map "$_ $me->{sort_dir}", @{$me->{sort}};
  0            
117             }
118              
119             sub list_HTML {
120 0     0 1   my $me = shift;
121              
122 0 0         if ( my $d = $me->{delete} ) {
123 0   0       $me->{trash_icon} ||= '/art/trash.gif';
124 0   0       my $to_delete = $d->{id} || $d->{foreign};
125 0 0         if ( $to_delete->[1] ) {
126 0   0       $me->{_dbh} ||= $me->{dbh} || DBI->connect( @{ $me->{dsn} } ) || die "No DB connection";
      0        
127 0   0       $me->{_dbh}->prepare( $d->{sql} )->execute( $d->{local}[1] || (), $to_delete->[1] );
128             }
129 0           push @{$me->{columns}}, {
130             style => 'text-align: center; vertical-align: middle;',
131             format => sub {
132 0           sprintf '',
133 0 0 0 0     ($d->{local} ? @{$d->{local}} : (_noop => 0)),
134             $_[$to_delete->[0]],
135             $d->{noun} || 'record',
136             $me->{trash_icon};
137             }
138             }
139 0           }
140              
141 0           return $me->SUPER::list_HTML(@_);
142             }
143              
144             sub next_row {
145 0     0 0   my $me = shift;
146              
147 0 0 0       return $me->SUPER::next_row(@_) unless $me->{sql} or $me->{_sth};
148              
149 0 0         unless ( $me->{_sth} ) {
150 0   0       $me->{_dbh} ||= $me->{dbh} || DBI->connect( @{ $me->{dsn} } ) || die "No DB connection";
      0        
151 0 0         $me->{_dbh}->trace( $me->{trace} ) if $me->{trace};
152 0           ( $me->{_sth} = $me->{_dbh}->prepare( $me->{sql} ) )->execute( @{$me->{sql_params}} );
  0            
153             }
154              
155 0 0         my @row = $me->{_sth}->fetchrow or do {
156 0           $me->{_sth}->finish;
157 0           undef $me->{_sth};
158 0 0         $me->{_dbh}->disconnect unless $me->{dbh};
159 0           return;
160             };
161              
162 0           return \@row;
163             }
164              
165             sub format {
166 0     0 1   my ($me, $col, $d) = @_;
167              
168 0 0         return $me->SUPER::format( $col, $d ) unless $col->{sql};
169              
170 0           my (@related);
171 0   0       $col->{_subquery_sth} ||= $me->{_dbh}->prepare( $col->{sql} );
172 0   0       $col->{_subquery_sth}->execute( $d->[ $col->{foreign_key_col} || 0 ] );
173 0           while ( my @d = $col->{_subquery_sth}->fetchrow ) {
174 0           push @related, $me->SUPER::format( $col, \@d );
175             }
176              
177 0 0 0       @related ? join( $col->{separator} || $col->{sep} || ', ', @related ) : $col->{none};
178             }
179              
180             1;
181              
182             =head1 SEE ALSO
183              
184             HTML::DataTable
185              
186             =head1 AUTHORS
187              
188             Nic Wolff
189             Jason Barden
190              
191             =cut