Bug 4450 Use more consistent error returns in C4/Creators/*
[koha.git] / C4 / Creators / Lib.pm
1 package C4::Creators::Lib;
2
3 # Copyright 2009 Foundations Bible College.
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
11 #
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 use strict;
21 use warnings;
22
23 use autouse 'Data::Dumper' => qw(Dumper);
24
25 use C4::Context;
26 use C4::Debug;
27
28 BEGIN {
29     use version; our $VERSION = qv('1.0.0_1');
30     use base qw(Exporter);
31     our @EXPORT = qw(get_all_templates
32                      get_all_layouts
33                      get_all_profiles
34                      get_all_image_names
35                      get_batch_summary
36                      get_label_summary
37                      get_card_summary
38                      get_barcode_types
39                      get_label_types
40                      get_font_types
41                      get_text_justification_types
42                      get_output_formats
43                      get_column_names
44                      get_table_names
45                      get_unit_values
46                      html_table
47     );
48 }
49
50 #=head2 C4::Creators::Lib::_SELECT()
51 #
52 #    This function returns a recordset upon success and 1 upon failure. Errors are logged to the Apache log.
53 #
54 #    examples:
55 #
56 #        my $field_value = _SELECT(field_name, table_name, condition);
57 #
58 #=cut
59
60 sub _SELECT {
61     my @params = @_;
62     my $query = "SELECT $params[0] FROM $params[1]";
63     $params[2] ? $query .= " WHERE $params[2];" : $query .= ';';
64     my $sth = C4::Context->dbh->prepare($query);
65 #    $sth->{'TraceLevel'} = 3;
66     $sth->execute();
67     if ($sth->err) {
68         warn sprintf('Database returned the following error: %s', $sth->errstr);
69         return 1;
70     }
71     my $record_set = [];
72     while (my $row = $sth->fetchrow_hashref()) {
73         push(@$record_set, $row);
74     }
75     return $record_set;
76 }
77
78 my $barcode_types = [
79     {type => 'CODE39',          name => 'Code 39',              desc => 'Translates the characters 0-9, A-Z, \'-\', \'*\', \'+\', \'$\', \'%\', \'/\', \'.\' and \' \' to a barcode pattern.',                                  selected => 0},
80     {type => 'CODE39MOD',       name => 'Code 39 + Modulo43',   desc => 'Translates the characters 0-9, A-Z, \'-\', \'*\', \'+\', \'$\', \'%\', \'/\', \'.\' and \' \' to a barcode pattern. Encodes Mod 43 checksum.',         selected => 0},
81     {type => 'CODE39MOD10',     name => 'Code 39 + Modulo10',   desc => 'Translates the characters 0-9, A-Z, \'-\', \'*\', \'+\', \'$\', \'%\', \'/\', \'.\' and \' \' to a barcode pattern. Encodes Mod 10 checksum.',         selected => 0},
82     {type => 'COOP2OF5',        name => 'COOP2of5',             desc => 'Creates COOP2of5 barcodes from a string consisting of the numeric characters 0-9',                                                                     selected => 0},
83 #    {type => 'EAN13',           name => 'EAN13',                desc => 'Creates EAN13 barcodes from a string of 12 or 13 digits. The check number (the 13:th digit) is calculated if not supplied.',                           selected => 0},
84 #    {type => 'EAN8',            name => 'EAN8',                 desc => 'Translates a string of 7 or 8 digits to EAN8 barcodes. The check number (the 8:th digit) is calculated if not supplied.',                              selected => 0},
85 #    {type => 'IATA2of5',        name => 'IATA2of5',             desc => 'Creates IATA2of5 barcodes from a string consisting of the numeric characters 0-9',                                                                     selected => 0},
86     {type => 'INDUSTRIAL2OF5',  name => 'Industrial2of5',       desc => 'Creates Industrial2of5 barcodes from a string consisting of the numeric characters 0-9',                                                               selected => 0},
87 #    {type => 'ITF',             name => 'Interleaved2of5',      desc => 'Translates the characters 0-9 to a barcodes. These barcodes could also be called 'Interleaved2of5'.',                                                  selected => 0},
88 #    {type => 'MATRIX2OF5',      name => 'Matrix2of5',           desc => 'Creates Matrix2of5 barcodes from a string consisting of the numeric characters 0-9',                                                                   selected => 0},
89 #    {type => 'NW7',             name => 'NW7',                  desc => 'Creates a NW7 barcodes from a string consisting of the numeric characters 0-9',                                                                        selected => 0},
90 #    {type => 'UPCA',            name => 'UPCA',                 desc => 'Translates a string of 11 or 12 digits to UPCA barcodes. The check number (the 12:th digit) is calculated if not supplied.',                           selected => 0},
91 #    {type => 'UPCE',            name => 'UPCE',                 desc => 'Translates a string of 6, 7 or 8 digits to UPCE barcodes. If the string is 6 digits long, '0' is added first in the string. The check number (the 8:th digit) is calculated if not supplied.',                                 selected => 0},
92 ];
93
94 my $label_types = [
95     {type => 'BIB',     name => 'Biblio',               desc => 'Only the bibliographic data is printed.',                              selected => 0},
96     {type => 'BARBIB',  name => 'Barcode/Biblio',       desc => 'Barcode proceeds bibliographic data.',                                 selected => 0},
97     {type => 'BIBBAR',  name => 'Biblio/Barcode',       desc => 'Bibliographic data proceeds barcode.',                                 selected => 0},
98     {type => 'ALT',     name => 'Alternating',          desc => 'Barcode and bibliographic data are printed on alternating labels.',    selected => 0},
99     {type => 'BAR',     name => 'Barcode',              desc => 'Only the barcode is printed.',                                         selected => 0},
100 ];
101
102 my $font_types = [
103     {type => 'TR',      name => 'Times-Roman',                  selected => 0},
104     {type => 'TB',      name => 'Times-Bold',                   selected => 0},
105     {type => 'TI',      name => 'Times-Italic',                 selected => 0},
106     {type => 'TBI',     name => 'Times-Bold-Italic',            selected => 0},
107     {type => 'C',       name => 'Courier',                      selected => 0},
108     {type => 'CB',      name => 'Courier-Bold',                 selected => 0},
109     {type => 'CO',      name => 'Courier-Oblique',              selected => 0},
110     {type => 'CBO',     name => 'Courier-Bold-Oblique',         selected => 0},
111     {type => 'H',       name => 'Helvetica',                    selected => 0},
112     {type => 'HB',      name => 'Helvetica-Bold',               selected => 0},
113     {type => 'HBO',     name => 'Helvetica-Bold-Oblique',       selected => 0},
114 ];
115
116 my $text_justification_types = [
117     {type => 'L',       name => 'Left',                         selected => 0},
118     {type => 'C',       name => 'Center',                       selected => 0},
119     {type => 'R',       name => 'Right',                        selected => 0},
120 #    {type => 'F',       name => 'Full',                         selected => 0},
121 ];
122
123 my $unit_values = [
124     {type       => 'POINT',      desc    => 'PostScript Points',  value   => 1,                 selected => 0},
125     {type       => 'AGATE',      desc    => 'Adobe Agates',       value   => 5.1428571,         selected => 0},
126     {type       => 'INCH',       desc    => 'US Inches',          value   => 72,                selected => 0},
127     {type       => 'MM',         desc    => 'SI Millimeters',     value   => 2.83464567,        selected => 0},
128     {type       => 'CM',         desc    => 'SI Centimeters',     value   => 28.3464567,        selected => 0},
129 ];
130
131 my $output_formats = [
132     {type       => 'pdf',       desc    => 'PDF File'},
133     {type       => 'csv',       desc    => 'CSV File'},
134 ];
135
136 =head2 C4::Creators::Lib::get_all_templates()
137
138     This function returns a reference to a hash containing all templates upon success and undefined upon failure. Errors are logged to the Apache log.
139
140     examples:
141
142         my $templates = get_all_templates();
143
144 =cut
145
146 sub get_all_templates {
147     my %params = @_;
148     my @templates = ();
149     my $query = "SELECT " . ($params{'field_list'} ? $params{'field_list'} : '*') . " FROM creator_templates";
150     $query .= ($params{'filter'} ? " WHERE $params{'filter'};" : ';');
151     my $sth = C4::Context->dbh->prepare($query);
152     $sth->execute();
153     if ($sth->err) {
154         warn sprintf('Database returned the following error: %s', $sth->errstr);
155         return;
156     }
157     ADD_TEMPLATES:
158     while (my $template = $sth->fetchrow_hashref) {
159         push(@templates, $template);
160     }
161     return \@templates;
162 }
163
164 =head2 C4::Creators::Lib::get_all_layouts()
165
166     This function returns a reference to a hash containing all layouts upon success and undefined upon failure. Errors are logged to the Apache log.
167
168     examples:
169
170         my $layouts = get_all_layouts();
171
172 =cut
173
174 sub get_all_layouts {
175     my %params = @_;
176     my @layouts = ();
177     my $query = "SELECT " . ($params{'field_list'} ? $params{'field_list'} : '*') . " FROM creator_layouts";
178     $query .= ($params{'filter'} ? " WHERE $params{'filter'};" : ';');
179     my $sth = C4::Context->dbh->prepare($query);
180     $sth->execute();
181     if ($sth->err) {
182         warn sprintf('Database returned the following error: %s', $sth->errstr);
183         return;
184     }
185     ADD_LAYOUTS:
186     while (my $layout = $sth->fetchrow_hashref) {
187         push(@layouts, $layout);
188     }
189     return \@layouts;
190 }
191
192 =head2 C4::Creators::Lib::get_all_profiles()
193
194     This function returns an arrayref whose elements are hashes containing all profiles upon success and undefined upon failure. Errors are logged
195     to the Apache log. Two parameters are accepted. The first limits the field(s) returned. This parameter should be string of comma separted
196     fields. ie. "field_1, field_2, ...field_n" The second limits the records returned based on a string containing a valud SQL 'WHERE' filter.
197
198     NOTE: Do not pass in the keyword 'WHERE.'
199
200     examples:
201
202         my $profiles = get_all_profiles();
203         my $profiles = get_all_profiles(field_list => field_list, filter => filter_string);
204
205 =cut
206
207 sub get_all_profiles {
208     my %params = @_;
209     my @profiles = ();
210     my $query = "SELECT " . ($params{'field_list'} ? $params{'field_list'} : '*') . " FROM printers_profile";
211     $query .= ($params{'filter'} ? " WHERE $params{'filter'};" : ';');
212     my $sth = C4::Context->dbh->prepare($query);
213 #    $sth->{'TraceLevel'} = 3 if $debug;
214     $sth->execute();
215     if ($sth->err) {
216         warn sprintf('Database returned the following error: %s', $sth->errstr);
217         return;
218     }
219     ADD_PROFILES:
220     while (my $profile = $sth->fetchrow_hashref) {
221         push(@profiles, $profile);
222     }
223     return \@profiles;
224 }
225
226 =head2 C4::Creators::Lib::get_all_image_names()
227
228 =cut
229
230 sub get_all_image_names {
231     my $image_names = [];
232     my $query = "SELECT image_name FROM creator_images";
233     my $sth = C4::Context->dbh->prepare($query);
234 #    $sth->{'TraceLevel'} = 3 if $debug;
235     $sth->execute();
236     if ($sth->err) {
237         warn sprintf('Database returned the following error: %s', $sth->errstr);
238         return;
239     }
240     grep {push @$image_names, {type => $$_[0], name => $$_[0], selected => 0}} @{$sth->fetchall_arrayref([0])};
241     return $image_names;
242 }
243
244 =head2 C4::Creators::Lib::get_batch_summary()
245
246     This function returns an arrayref whose elements are hashes containing the batch_ids of current batches along with the item count
247     for each batch upon success and 1 upon failure. Item counts are stored under the key '_item_count' Errors are logged to the Apache log.
248     One parameter is accepted which limits the records returned based on a string containing a valud SQL 'WHERE' filter.
249
250     NOTE: Do not pass in the keyword 'WHERE.'
251
252     examples:
253
254         my $batches = get_batch_summary();
255         my $batches = get_batch_summary(filter => filter_string);
256
257 =cut
258
259 sub get_batch_summary {
260     my %params = @_;
261     my @batches = ();
262     my $query = "SELECT DISTINCT batch_id FROM creator_batches WHERE creator=?";
263     $query .= ($params{'filter'} ? " AND $params{'filter'};" : ';');
264     my $sth = C4::Context->dbh->prepare($query);
265 #    $sth->{'TraceLevel'} = 3;
266     $sth->execute($params{'creator'});
267     if ($sth->err) {
268         warn sprintf('Database returned the following error on attempted SELECT: %s', $sth->errstr);
269         return;
270     }
271     ADD_BATCHES:
272     while (my $batch = $sth->fetchrow_hashref) {
273         my $query = "SELECT count(batch_id) FROM creator_batches WHERE batch_id=? AND creator=?;";
274         my $sth1 = C4::Context->dbh->prepare($query);
275         $sth1->execute($batch->{'batch_id'}, $params{'creator'});
276         if ($sth1->err) {
277             warn sprintf('Database returned the following error on attempted SELECT count: %s', $sth1->errstr);
278             return;
279         }
280         my $count = $sth1->fetchrow_arrayref;
281         $batch->{'_item_count'} = @$count[0];
282         push(@batches, $batch);
283     }
284     return \@batches;
285 }
286
287 =head2 C4::Creators::Lib::get_label_summary()
288
289     This function returns an arrayref whose elements are hashes containing the label_ids of current labels along with the item count
290     for each label upon success and 1 upon failure. Item counts are stored under the key '_item_count' Errors are logged to the Apache log.
291     One parameter is accepted which limits the records returned based on a string containing a valud SQL 'WHERE' filter.
292
293     NOTE: Do not pass in the keyword 'WHERE.'
294
295     examples:
296
297         my $labels = get_label_summary();
298         my $labels = get_label_summary(items => @item_list);
299
300 =cut
301
302 sub get_label_summary {
303     my %params = @_;
304     my $label_number = 0;
305     my @label_summaries = ();
306     my $query = "     SELECT b.title, b.author, bi.itemtype, i.barcode, i.biblionumber
307                       FROM creator_batches AS c LEFT JOIN items AS i ON (c.item_number=i.itemnumber)
308                       LEFT JOIN biblioitems AS bi ON (i.biblioitemnumber=bi.biblioitemnumber)
309                       LEFT JOIN biblio AS b ON (bi.biblionumber=b.biblionumber)
310                       WHERE itemnumber=? AND batch_id=?;
311                   ";
312     my $sth = C4::Context->dbh->prepare($query);
313     foreach my $item (@{$params{'items'}}) {
314         $label_number++;
315         $sth->execute($item->{'item_number'}, $params{'batch_id'});
316         if ($sth->err) {
317             warn sprintf('Database returned the following error on attempted SELECT: %s', $sth->errstr);
318             return;
319         }
320         my $record = $sth->fetchrow_hashref;
321         my $label_summary;
322         $label_summary->{'_label_number'} = $label_number;
323         $record->{'author'} =~ s/[^\.|\w]$// if $record->{'author'};  # strip off ugly trailing chars... but not periods or word chars
324         $record->{'title'} =~ s/\W*$//;  # strip off ugly trailing chars
325         # FIXME contructing staff interface URLs should be done *much* higher up the stack - for the most part, C4 module code
326         # should not know that it's part of a web app
327         $record->{'title'} = '<a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=' . $record->{'biblionumber'} . '"> ' . $record->{'title'} . '</a>';
328         $label_summary->{'_summary'} = $record->{'title'} . " | " . ($record->{'author'} ? $record->{'author'} : 'N/A');
329         $label_summary->{'_item_type'} = $record->{'itemtype'};
330         $label_summary->{'_barcode'} = $record->{'barcode'};
331         $label_summary->{'_item_number'} = $item->{'item_number'};
332         $label_summary->{'_label_id'} = $item->{'label_id'};
333         push (@label_summaries, $label_summary);
334     }
335     return \@label_summaries;
336 }
337
338 =head2 C4::Creators::Lib::get_card_summary()
339
340     This function returns an arrayref whose elements are hashes containing the label_ids of current cards along with the item count
341     for each card upon success and 1 upon failure. Item counts are stored under the key '_item_count' Errors are logged to the Apache log.
342     One parameter is accepted which limits the records returned based on a string containing a valud SQL 'WHERE' filter.
343
344     NOTE: Do not pass in the keyword 'WHERE.'
345
346     examples:
347
348         my $cards = get_card_summary();
349         my $cards = get_card_summary(items => @item_list);
350
351 =cut
352
353 sub get_card_summary {
354     my %params = @_;
355     my $card_number = 0;
356     my @card_summaries = ();
357     my $query = "SELECT CONCAT_WS(', ', surname, firstname) AS name, cardnumber FROM borrowers WHERE borrowernumber=?;";
358     my $sth = C4::Context->dbh->prepare($query);
359     foreach my $item (@{$params{'items'}}) {
360         $card_number++;
361         $sth->execute($item->{'borrower_number'});
362         if ($sth->err) {
363             warn sprintf('Database returned the following error on attempted SELECT: %s', $sth->errstr);
364             return;
365         }
366         my $record = $sth->fetchrow_hashref;
367         my $card_summary->{'_card_number'} = $card_number;
368         $card_summary->{'_summary'} = $record->{'name'};
369         $card_summary->{'borrowernumber'} = $item->{'borrower_number'};
370         $card_summary->{'_label_id'} = $item->{'label_id'};
371         push (@card_summaries, $card_summary);
372     }
373     return \@card_summaries;
374 }
375
376 =head2 C4::Creators::Lib::get_barcode_types()
377
378     This function returns a reference to an array of hashes containing all barcode types along with their name and description.
379
380     examples:
381
382         my $barcode_types = get_barcode_types();
383
384 =cut
385
386 sub get_barcode_types {
387     return $barcode_types;
388 }
389
390 =head2 C4::Creators::Lib::get_label_types()
391
392     This function returns a reference to an array of hashes containing all label types along with their name and description.
393
394     examples:
395
396         my $label_types = get_label_types();
397
398 =cut
399
400 sub get_label_types {
401     return $label_types;
402 }
403
404 =head2 C4::Creators::Lib::get_font_types()
405
406     This function returns a reference to an array of hashes containing all font types along with their name and description.
407
408     examples:
409
410         my $font_types = get_font_types();
411
412 =cut
413
414 sub get_font_types {
415     return $font_types;
416 }
417
418 =head2 C4::Creators::Lib::get_text_justification_types()
419
420     This function returns a reference to an array of hashes containing all text justification types along with their name and description.
421
422     examples:
423
424         my $text_justification_types = get_text_justification_types();
425
426 =cut
427
428 sub get_text_justification_types {
429     return $text_justification_types;
430 }
431
432 =head2 C4::Creators::Lib::get_unit_values()
433
434     This function returns a reference to an array of  hashes containing all unit types along with their description and multiplier. NOTE: All units are relative to a PostScript Point.
435     There are 72 PS points to the inch.
436
437     examples:
438
439         my $unit_values = get_unit_values();
440
441 =cut
442
443 sub get_unit_values {
444     return $unit_values;
445 }
446
447 =head2 C4::Creators::Lib::get_output_formats()
448
449     This function returns a reference to an array of hashes containing all label output formats along with their description.
450
451     examples:
452
453         my $label_output_formats = get_output_formats();
454
455 =cut
456
457 sub get_output_formats {
458     return $output_formats;
459 }
460
461 =head2 C4::Creators::Lib::get_column_names($table_name)
462
463 Return an arrayref of an array containing the column names of the supplied table.
464
465 =cut
466
467 sub get_column_names {
468     my $table = shift;
469     my $dbh = C4::Context->dbh();
470     my $column_names = [];
471     my $sth = $dbh->column_info(undef,undef,$table,'%');
472     while (my $info = $sth->fetchrow_hashref()){
473         $$column_names[$info->{'ORDINAL_POSITION'}] = $info->{'COLUMN_NAME'};
474     }
475     return $column_names;
476 }
477
478 =head2 C4::Creators::Lib::get_table_names($search_term)
479
480 Return an arrayref of an array containing the table names which contain the supplied search term.
481
482 =cut
483
484 sub get_table_names {
485     my $search_term = shift;
486     my $dbh = C4::Context->dbh();
487     my $table_names = [];
488     my $sth = $dbh->table_info(undef,undef,"%$search_term%");
489     while (my $info = $sth->fetchrow_hashref()){
490         push (@$table_names, $info->{'TABLE_NAME'});
491     }
492     return $table_names;
493 }
494
495 =head2 C4::Creators::Lib::html_table()
496
497     This function returns an arrayref of an array of hashes contianing the supplied data formatted suitably to
498     be passed off as a T::P template parameter and used to build an html table.
499
500     examples:
501
502        my $table = html_table(header_fields, array_of_row_data);
503        $template->param(
504             TABLE => $table,
505        );
506
507     html example:
508
509        <table>
510             <!-- TMPL_LOOP NAME="TABLE" -->
511             <!-- TMPL_IF NAME="header_fields" -->
512             <tr>
513             <!-- TMPL_LOOP NAME="header_fields" -->
514                 <th><!-- TMPL_VAR NAME="field_label" --></th>
515             <!-- /TMPL_LOOP -->
516             </tr>
517             <!-- TMPL_ELSE -->
518             <tr>
519             <!-- TMPL_LOOP NAME="text_fields" -->
520             <!-- TMPL_IF NAME="select_field" -->
521                 <td align="center"><input type="checkbox" name="action" value="<!-- TMPL_VAR NAME="field_value" -->" /></td>
522             <!-- TMPL_ELSIF NAME="field_value" -->
523                 <td><!-- TMPL_VAR NAME="field_value" --></td>
524             <!-- TMPL_ELSE -->
525                 <td>&nbsp;</td>
526             <!-- /TMPL_IF -->
527             <!-- /TMPL_LOOP -->
528             </tr>
529             <!-- /TMPL_IF -->
530             <!-- /TMPL_LOOP -->
531         </table>
532
533 =cut
534
535 sub html_table {
536     my $headers = shift;
537     my $data = shift;
538     # no need to generate a table if there is not data to display
539     unless ( @{$data} ) {
540         return;
541     }
542     my $table = [];
543     my $fields = [];
544     my @table_columns = ();
545     my ($row_index, $col_index) = (0,0);
546     my $cols = 0;       # number of columns to wrap on
547     my $field_count = 0;
548     my $select_value = undef;
549     my $link_field = undef;
550     POPULATE_HEADER:
551     foreach my $header (@$headers) {
552         my @key = keys %$header;
553         if ($key[0] eq 'select' ) {
554             push (@table_columns, $key[0]);
555             $$fields[$col_index] = {hidden => 0, select_field => 0, field_name => ($key[0]), field_label => $header->{$key[0]}{'label'}};
556             # do special formatting stuff....
557             $select_value = $header->{$key[0]}{'value'};
558         }
559         else {
560             # do special formatting stuff....
561             $link_field->{$key[0]} = ($header->{$key[0]}{'link_field'} == 1 ? 1 : 0);
562             push (@table_columns, $key[0]);
563             $$fields[$col_index] = {hidden => 0, select_field => 0, field_name => ($key[0]), field_label => $header->{$key[0]}{'label'}};
564         }
565         $field_count++;
566         $col_index++;
567     }
568     $$table[$row_index] = {header_fields => $fields};
569     $cols = $col_index;
570     $field_count *= scalar(@$data);     # total fields to be displayed in the table
571     $col_index = 0;
572     $row_index++;
573     $fields = [];
574     POPULATE_TABLE:
575     foreach my $db_row (@$data) {
576         POPULATE_ROW:
577         foreach my $table_column (@table_columns) {
578             if (grep {$table_column eq $_} keys %$db_row) {
579                 $$fields[$col_index] = {hidden => 0, link_field => $link_field->{$table_column}, select_field => 0, field_name => ($table_column . "_tbl"), field_value => $db_row->{$table_column}};
580                 $col_index++;
581                 next POPULATE_ROW;
582             }
583             elsif ($table_column =~ m/^_((.*)_(.*$))/) {   # this a special case
584                 my $table_name = get_table_names($2);
585                 my $record_set = _SELECT($1, @$table_name[0], $2 . "_id = " . $db_row->{$2 . "_id"});
586                 $$fields[$col_index] = {hidden => 0, link_field => $link_field->{$table_column}, select_field => 0, field_name => ($table_column . "_tbl"), field_value => $$record_set[0]{$1}};
587                 $col_index++;
588                 next POPULATE_ROW;
589             }
590             elsif ($table_column eq 'select' ) {
591                 $$fields[$col_index] = {hidden => 0, select_field => 1, field_name => 'select', field_value => $db_row->{$select_value}};
592             }
593         }
594         $$table[$row_index] = {text_fields => $fields};
595         $col_index = 0;
596         $row_index++;
597         $fields = [];
598     }
599     return $table;
600 }
601
602 1;
603 __END__
604
605 =head1 AUTHOR
606
607 Chris Nighswonger <cnighswonger AT foundations DOT edu>
608
609 =cut