File Coverage

blib/lib/HTML/FormEngine/DBSQL.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             HTML::FormEngine::DBSQL - create html/xhtml forms for adding, updating
4             and removing records to / in / from sql database tables
5              
6             =cut
7              
8             ######################################################################
9              
10             package HTML::FormEngine::DBSQL;
11             require 5.004;
12              
13             # Copyright (c) 2003-2004, Moritz Sinn. This module is free software;
14             # you can redistribute it and/or modify it under the terms of the
15             # GNU GENERAL PUBLIC LICENSE, see COPYING for more information
16              
17 1     1   21236 use strict;
  1         2  
  1         51  
18 1     1   5 use vars qw(@ISA $VERSION);
  1         2  
  1         72  
19 1     1   2055 use HTML::FormEngine;
  0            
  0            
20             @ISA = qw(HTML::FormEngine);
21             $VERSION = '1.01';
22              
23             ######################################################################
24              
25             =head1 DEPENDENCIES
26              
27             =head2 Perl Version
28              
29             5.004
30              
31             =head2 Standard Modules
32              
33             Carp 1.01
34              
35             =head2 Nonstandard Modules
36              
37             HTML::FormEngine 1.0
38             Clone 0.13
39             Hash::Merge 0.07
40             Locale::gettext 1.01
41             Digest::MD5 2.24
42             DBI 1.42
43              
44             =head1 REQUIREMENTS
45              
46             This class was only tested with PostgreSQL. Please tell me about
47             your experiences with other DBMS. Thanks!
48              
49             =cut
50              
51             ######################################################################
52              
53             use Carp;
54             use Clone qw(clone);
55             use Hash::Merge qw(merge);
56             use Locale::gettext;
57             use Digest::MD5 qw(md5_hex);
58             use HTML::FormEngine::DBSQL::SkinClassic;
59              
60             ######################################################################
61              
62             =head1 SYNOPSIS
63              
64             =head2 Example Code
65              
66             #!/usr/bin/perl -w
67              
68             use strict;
69             use HTML::FormEngine::DBSQL;
70             use DBI;
71             use CGI;
72             #use POSIX; #for setlocale
73             #setlocale(LC_MESSAGES, 'german'); #for german error messages
74              
75             my $q = new CGI;
76             print $q->header;
77              
78             my $dbh = DBI->connect('dbi:Pg:dbname=test', 'test', 'test');
79             my $Form = HTML::FormEngine::DBSQL->new(scalar $q->Vars, $dbh);
80             $Form->dbsql_conf('user');
81             $Form->make();
82             print $q->start_html('FormEngine-dbsql example: User Administration');
83             if($Form->ok) {
84             if($_ = $Form->dbsql_insert()) {
85             print "Sucessfully added $_ user(s)!
";
86             $Form->clear;
87             }
88             }
89             print $Form->get,
90             $q->end_html;
91             $dbh->disconnect;
92              
93             =head2 Example Database Table
94              
95             Execute the following (Postgre)SQL commands to create the tables I used when developing the examples:
96              
97             CREATE SEQUENCE user_uid_seq;
98              
99             CREATE TABLE "user" (
100             uid integer DEFAULT nextval('user_uid_seq'::text) NOT NULL,
101             name character varying(40) NOT NULL,
102             forename character varying(40) NOT NULL,
103             street character varying(40) NOT NULL,
104             zip integer NOT NULL,
105             town character varying(40) NOT NULL,
106             email character varying(40) NOT NULL,
107             phone character varying(15)[] DEFAULT '{"",""}'::character varying[],
108             birthday date NOT NULL,
109             newsletter boolean DEFAULT true
110             );
111              
112             CREATE TABLE login (
113             uid integer DEFAULT currval('user_uid_seq'::text) NOT NULL,
114             username character varying(30) DEFAULT '-'::character varying NOT NULL,
115             "password" character varying(30) DEFAULT '-'::character varying NOT NULL
116             );
117              
118              
119             ALTER TABLE ONLY "user"
120             ADD CONSTRAINT user_pkey PRIMARY KEY (uid);
121              
122             ALTER TABLE ONLY login
123             ADD CONSTRAINT login_pkey PRIMARY KEY (uid);
124              
125             ALTER TABLE ONLY login
126             ADD CONSTRAINT "$1" FOREIGN KEY (uid) REFERENCES "user"(uid) MATCH FULL ON UPDATE CASCADE ON DELETE CASCADE;
127              
128             COMMENT ON COLUMN "user".zip IS 'ERROR=digitonly;';
129              
130             COMMENT ON COLUMN "user".email IS 'ERROR=rfc822;';
131              
132             COMMENT ON COLUMN "user".phone IS 'display_as={{,}};ERROR_IN={{{not_null,digitonly},{not_null,digitonly}}};SUBTITLE={{,/}};SIZE={{5,10}};';
133             COMMENT ON COLUMN login.username IS 'ERROR={{regex,"must only contain A-Z, a-z and 0-9","^[A-Za-z0-9]+$"},unique,dbsql_unique};';
134              
135             COMMENT ON COLUMN login."password" IS 'TYPE=password;VALUE=;ERROR={{regex,"must have more than 4 chars",".{5,}"}};';
136              
137             Of course you can use any other table(s) as well. The file C in the examples directory contains the whole database dump.
138              
139             =head2 Example Output
140              
141             This output is produced by FormEngine::DBSQL when using the example
142             code, the example table and no data was submitted:
143              
144            
145            
146            
147            
148            
149            
150            
151            
152            
153              
154            
155            
156            
157            
158            
159              
160            
161            
162              
163            
164              
165            
166            
167            
168            
169            
170            
171              
172            
173            
174            
175            
176            
177            
178            
179            
180            
181            
182              
183            
184              
185            
186            
187            
188              
189            
190              
191            
192            
193            
194            
195            
196            
197            
198            
199            
200            
201              
202            
203            
204            
205            
206            
207            
208              
209            
210              
211            
212            
213              
214            
215            
216            
217            
218            
219              
220            
221            
222            
223            
224            
225            
226            
227            
228            
229            
230              
231            
232            
233              
234            
235            
236            
237              
238              
239            
240            
241            
242            
243            
244            
245            
246            
247            
248            
249              
250            
251            
252            
253            
254            
255            
256            
257              
258              
259            
260            
261            
262              
263            
264            
265            
266            
267              
268            
269            
270            
271            
272            
273            
274            
275            
276            
277            
278              
279            
280            
281            
282              
283            
284            
285            
286              
287              
288            
289            
290            
291            
292            
293            
294            
295            
296            
297            
298              
299            
300            
301            
302            
303            
304            
305            
306              
307              
308            
309            
310            
311              
312            
313            
314            
315            
316              
317            
318            
319            
320              
321            
322            
323            
324              
325              
326            
327            
328            
329            
330            
331            
332            
333              
334            
335            
336            
337            
338            
339            
340            
341            
342            
343              
344            
345              
346            
347            
348            
349              
350            
351              
352            
353            
354            
355            
356            
357            
358            
359            
360            
361            
362              
363            
364            
365            
366            
367            
368            
369              
370            
371              
372              
373            
374            
375            
376            
377            
378              
379            
380            
381              
382            
383            
384            
385            
386            
387            
388            
389            
390              
391            
392            
393              
394            
395            
396            
397            
398            
399            
400            
401            
402              
403            
404              
405             =head1 DESCRIPTION
406              
407             DBSQL.pm is an exentsion of HTML::FormEngine, that means it inherits
408             all functionality from HTML::FormEngine and adds some new features.
409              
410             In web development, form data is mostly used to update a database. For
411             example most guestbooks or any similar webapplication store the
412             entered data in a database. Often very large forms are needed,
413             e.g. when the user should provide his personal data to subscribe to an
414             certain service.
415              
416             In most cases a SQL database is used. If you don't know anything about
417             SQL databases or you're not using such things, this module will hardly
418             help you. But if you do, you'll know that every record, that you want
419             to store in a certain SQL database table, has to have certain fields
420             and these fields must contain data of an certain type (datatype). So
421             the tables structure already defines how a form, that wants to add
422             data to this table, might look like (in case that you don't want to
423             process the whole data before adding it to the table).
424              
425             DBSQL.pm reads out the tables structure and creates a form definition
426             for HTML::FormEngine.
427              
428             Two examples:
429              
430             A field of type boolean will only accept 0 or 1, this is represented
431             in the form as 'Yes' or 'No'.
432              
433             a field of type VARCHAR(30) will accept strings of maximal 30
434             characters, so it's represented as an one-line-text-input-field in
435             which you can put maximal 30 characters.
436              
437             Of course you can re-adjust the resulting form configuration,
438             but in most cases you don't have to care about it!
439              
440             DBSQL.pm also provides methods for adding and updating records. So you
441             don't have to deal with sql commands.
442              
443             HTML::FormEngine::DBSQL was only tested with B so far, but
444             it should also work with other DBMS, like e.g. MySQL.
445              
446             =head1 OVERVIEW
447              
448             We expect that you know how to use HTML::FormEngine, if not, please
449             first read its documentation. Using HTML::FormEngine:DBSQL isn't much
450             diffrent: the C method is replaced by C and you may
451             pass a database handle as second argument to the C method, using
452             C is possible too. Before calling C, you
453             may call C for setting some variables by hand.
454              
455             To C you pass the tables name and optionally a where
456             condition (for updating records) and/or a reference to an array with
457             fieldnames (for setting explicit which fields to show resp. not to
458             show).
459              
460             =head1 USING FormEngine::DBSQL
461              
462             =head2 Configuring The Form Through The Database
463              
464             =head3 datatype handlers
465              
466             In DBSQL::DtHandler.pm you'll find all datatype handlers which come
467             with this module. Which handler to use for which datatype is defined
468             in DBSQL::SkinClassic, the default FormEngine skin for this module. If
469             for a certain datatype no handler is defined, the default datatype
470             handler will be called.
471              
472             A handler creates the main part of the form field configuration.
473              
474             You can easily add your own datatype handlers (see below).
475              
476             =head3 array handling
477              
478             Though the idea how to store arrays is taken from PostgreSQL, this
479             should work with any other DBMS too!
480              
481             In PostgreSQL every datatype can be arrayed. PostgreSQL arrays have
482             the following structure: '{firstelem,secondelem}', a two dimensional
483             array looks like this: '{{one,two},{three,four}}'. The problem is
484             that PostgreSQL arrays don't have a fixed size, but FormEngine::DBSQL
485             need such to represent the array in the form. Here we use a trick: the
486             size which should be represented in the form is determined by the
487             default value. So a field with '{,}' as default value will be
488             represented as an one dimensional array (in case you specify
489             C it'll be displayed according to that, see below). Of
490             course you can put values between the commas, which will then be
491             printed as defaults.
492              
493             The following feature might sound a bit complicated, don't worry about
494             it, you'll normaly not need it.
495              
496             There are two special variables which make array handling more
497             flexible. C can be used to specify how a database array
498             shall be represented in the form, C works in the other
499             direction, it defines in which format an array submitted by the form
500             is written in the database. This is probably a bit hard to understand,
501             so here is an example: you could save a telefon number in one database
502             field which is of type integer[] (integer array). The first element is
503             the code, the second the number. Of course in the database this is a
504             one dimensional array. But when the telefon field is now represented
505             by the form the one dimensional array will probably cause the two
506             fields to be on two diffrent rows, so you want to turn the one
507             dimensional array into an two dimensional array just by adding one
508             more dimension. This is simply done by setting C in
509             the database field comment (see L
510             the database>). Same with C. So if you specify
511             e.g. C<{{,}{,}}> for one of these variables it'll cause an array like
512             C<[1,2,3,4]> to be turned into C<[[1,2][3,4]]>. The elements are
513             simply read from left to right and putted into the template also from
514             left to right.
515              
516              
517             =head3 NOT NULL fields
518              
519             The form value of fields which have the NOT NULL property will be
520             automatically passed to the I check method. This means that
521             their I variable will be set to I.
522              
523             If the I variable was already set through C,
524             nothing will be changed. If the variable was set through the fields
525             comment (see L), the
526             I check will be added in front.
527              
528             If you called C the not_null check is
529             probably not added since a field which will just be ignored if empty
530             doesn't have to be checked whether it is empty. Read
531             L for more information.
532              
533             =head3 assigning FormEngine variables in the database
534              
535             PostgreSQL and other DBMS offer to set comments on database
536             objects. This feature can be used to explicitly set form field
537             variables in the database.
538              
539             You might e.g. want to store emailadresses in a certain field of a
540             database table, it makes sense to validate an address before inserting
541             it. First possibility is to use C to set the ERROR
542             variable to 'email' or 'rfc822', but perhaps you've more than one
543             script which inserts or updates the table and so you're using several
544             forms. In every script you now have to call the C
545             method and set the ERROR variable for the email field. This isn't
546             nice, because the necessity to check this field is given by the table
547             structure and so the check should also be set by the database. You
548             might set a check constraint, but this will cause an ugly database
549             error which the user might not understand. So beside defining an
550             constraint (which is recommended), FormEngine::DBSQL should check the
551             address before inserting it. Setting the database fields comment to
552             'ERROR=rfc822;' will force FormEngine::DBSQL to do so. You can still
553             overwrite this setting with C.
554              
555             Below you see the whole command:
556              
557             COMMENT ON COLUMN "user".email IS 'ERROR=rfc822;'
558              
559             Whenever you pass this tables name to the C method of
560             FormEngine::DBSQL, it'll remember to call the rfc822 check method
561             before inserting or updating a I field value.
562              
563             You can even assign array structures to a variable:
564              
565             COMMENT ON COLUMN "user".phone IS 'ERROR_IN={{{not_null,digitonly},{not_null,digitonly}}};';
566              
567             The I field is a string array, with the above command we
568             forbid NULL values and demand digits for the first two elements. More
569             about arrays and their representation in the form is described above
570             (L).
571              
572             It is possible to assign several variables:
573              
574             COMMENT ON COLUMN "user".zip IS 'ERROR=digitonly;TITLE=Postcode;';
575              
576             Don't forget the ';' at the end of every assignment!
577              
578             Of course you can still use the comment field to place normal comments
579             there as well:
580              
581             COMMENT ON COLUMN "user".birthday IS 'We\'re really a bit curious!;ERROR=date;';
582              
583             Note the ';' at the end of the trivial comment!
584              
585             In quoted areas ("..") '{', '}' and ',' are not interpreted. You can
586             prevent the parsing of '"' and ';' by putting an '\' (backslash) in
587             front.
588              
589             =head2 Methods
590              
591             =head3 new ([ HASHREF, DBHANDLE ])
592              
593             Works exactly like Ls C method but accepts a
594             second parameter, the database handle. This is needed for
595             communicating with the database. Alternatively it can be set through
596             L.
597              
598             =head3 dbsql_preconf ( HASHREF, PREPEND, APPEND )
599              
600             In the referenced hash you can predefine some parts of the form
601             configuration by hand. The hash keys must be named after the tables
602             fields. Every element must be a hash reference, in the referenced hash
603             you can set variables.
604              
605             You can use the special keys I and I to add extra
606             fields before or after the field.
607              
608             An example:
609              
610             my %preconf = (
611             name => {
612             TITLE => 'Fore- and Surname',
613             ERROR => sub {$_ = shift; m/\w\W\w/ ? return 0 : return 'failed';}
614             },
615             email => {
616             TITLE => 'Your Emailadress',
617             ERROR => 'email'
618             }
619             );
620             $Form->dbsql_preconf(\%preconf);
621              
622              
623             The field definitions passed for PREPEND or APPEND are added to the
624             top resp. the bottom of the generated form. If you want to add more
625             than one field, you have to reference an array which contains the
626             definitions, else you can reference the hash directly. See the
627             L for information about field definitions.
628              
629             When using the special key format I<__add_VARNAME_last>
630             resp. I<__add_VARNAME_first> the given values are added at the
631             beginning resp. the end of the (probably) already existing value
632             list. Of course you have to replace I with the name of the
633             variable to which you want to add something. If the sofar specified
634             value of the variable is a scalar its automatically turned into an
635             array.
636              
637             B If you pass more than one table name to C, you
638             must reference the fields with I!
639              
640             =cut
641              
642             ######################################################################
643              
644             sub dbsql_preconf {
645             my ($self,$preconf,$prepend,$append) = @_;
646             if(ref($preconf) eq 'HASH') {
647             $self->{dbsql_preconf} = merge($preconf, $self->{dbsql_preconf});
648             }
649             #rettarref returns an array reference
650             $self->{dbsql_prepend} = retarref($prepend);
651             $self->{dbsql_append} = retarref($append);
652             }
653              
654             ######################################################################
655              
656             =head3 dbsql_conf ( ... )
657              
658             The three dots stand for:
659             C
660              
661             This method creates a FormEngine-form-definition and calls FormEngines
662             C method.
663              
664             Normally you only want to manage records out of one table, then it is
665             sufficient to give this tables name as first argument. But you can
666             also pass several table names by using an array reference.
667              
668             If you provide COUNT, the form fields will be displayed COUNT times,
669             which means that you can insert COUNT records.
670              
671             If you want to update records, you should provide WHERECONDITION
672             instead. This must be a valid where-condition B the C
673             directive in front, or a hash reference. A hash reference you must
674             provide if you passed several tablenames and want to define diffrent
675             where conditions for theses tables. The keys must be the table names
676             and the elements the complying conditions.
677              
678             DBSQL then shows input fields for every found record and uses the
679             current values as defaults. The primary keys are stored in hidden
680             fields, so that they can't be changed. Later they're used for updating
681             the records.
682              
683             If you'd like to set only some of the tables fields, put their names
684             in an array and pass a reference as third and last argument
685             (FIELDNAMES). If the first array element is '!', all fields which
686             B found in the array will be displayed. You must use a hash
687             reference here if you passed more than one table name.
688              
689             =cut
690              
691             ######################################################################
692              
693             sub dbsql_conf {
694             my ($self,$table,$where,$fields) = @_;
695              
696             $self->{dbsql_tables} = retarref($table || $self->{dbsql_tables});
697              
698             if(! defined($self->{dbsql_tables}) || ! @{$self->{dbsql_tables}}) {
699             croak 'table not defined!';
700             }
701              
702             $self->{dbsql_where} = $where || $self->{dbsql_where};
703              
704             $self->{dbsql_fields} = $fields || $self->{dbsql_fields};
705              
706             #if the user references fields out of diffrent tables he must say which fields belong to which table
707             if(@{$self->{dbsql_tables}} > 1 && ref($self->{dbsql_fields}) ne 'HASH') {
708             croak 'fields must be assigned to tables!';
709             }
710             #in the case that we've only one table the user can be lazy and we transform into hash notation
711             elsif(@{$self->{dbsql_tables}} == 1 && ref($self->{dbsql_fields}) ne 'HASH') {
712             $self->{dbsql_fields} = {$self->{dbsql_tables}->[0] => retarref($self->{dbsql_fields})};
713             }
714             #the user could have setted dbsql_pkey before through dbsql_set_pkey
715             #if its not a hash he defined them only for one table
716             if(ref($self->{dbsql_pkey}) ne 'HASH') {
717             $_ = retarref($self->{dbsql_pkey});
718             $self->{dbsql_pkey} = {$self->{dbsql_tables}->[0] => {}};
719             foreach $_ (@{$_}) {
720             $self->{dbsql_pkey}->{$self->{dbsql_tables}->[0]}->{$_} = 1;
721             }
722             }
723              
724             my ($count, $where_cond);
725             #if we have a number we don't have a sql where condition, that means we're just asked to repeat the fields $count time
726             if(! ref($self->{dbsql_where}) and $self->{dbsql_where} =~ m/^[0-9]+$/) {
727             $count = $self->{dbsql_where};
728             } else {
729             #since we have a where condition we'll display the fields content and not the default
730             $self->dbsql_set_show_default(0) if($self->{dbsql_show_default} == 1);
731             #if a scalar was given we've to turn it into a hash ({table => wherecondition})
732             if(ref($self->{dbsql_where}) ne 'HASH') {
733             $where_cond = $self->{dbsql_where};
734             $self->{dbsql_where} = {};
735             } else {
736             $where_cond = '';
737             }
738             }
739              
740             my %donotuse;
741             foreach my $tbl (@{$self->{dbsql_tables}}) {
742             #if no fields are given we just take all
743             if(ref($self->{dbsql_fields}->{$tbl}) ne 'ARRAY' or ! @{$self->{dbsql_fields}->{$tbl}}) {
744             $self->{dbsql_fields}->{$tbl} = [undef];
745             }
746             #$where_cond is '' if nothing was given or if just a scalar was given it is set to that one
747             $self->{dbsql_where}->{$tbl} = $where_cond if(ref($self->{dbsql_where}) eq 'HASH' && ! defined($self->{dbsql_where}->{$tbl}));
748             #if the first field of the dbsql_fields array is '!' it means that the following fields should not be selected
749             $donotuse{$tbl} = {};
750             if(defined($self->{dbsql_fields}->{$tbl}->[0]) and $self->{dbsql_fields}->{$tbl}->[0] eq '!') {
751             delete $self->{dbsql_fields}->{$tbl}->[0];
752             foreach $_ (@{$self->{dbsql_fields}->{$tbl}}) {
753             $donotuse{$tbl}->{$_} = 1;
754             }
755             #select all, $donotuse will be used later
756             $self->{dbsql_fields}->{$tbl} = [undef];
757             }
758              
759             #no pkey was defined, so we've to get it/them
760             if(! defined($self->{dbsql_pkey}->{$tbl})) {
761             $self->{dbsql_pkey}->{$tbl} = {};
762             foreach $_ ($self->{dbsql}->primary_key(undef, undef, $tbl)) {
763             my $field = (@{$self->{dbsql_tables}} > 1 ? "$tbl.$_" : $_);
764             #like this we can prove better whether a certain field is part of the pkey or not
765             $self->{dbsql_pkey}->{$tbl}->{$field} = 1;
766             }
767             }
768             }
769              
770             my @fconf;
771             #configurations saved in dbsql_prepend must be added to the top
772             if(defined($self->{dbsql_prepend})) {
773             push @fconf, @{retarref($self->{dbsql_prepend})};
774             }
775              
776             foreach my $tbl (@{$self->{dbsql_tables}}) {
777             #get the tables structure
778             my @fields = @{$self->{dbsql_fields}->{$tbl}};
779             $self->{dbsql_fields}->{$tbl} = [];
780             foreach my $field (@fields) {
781             my $sth = $self->{dbsql}->column_info(undef, undef, $tbl, $field);
782             $sth->execute;
783             while(my $fstruct = $sth->fetchrow_hashref()) {
784             #jump over fields that shall not be displayed
785             next if($donotuse{$tbl}->{$fstruct->{COLUMN_NAME}});
786             #$_ now contains the form configuration for that field
787             local $_ = $self->_dbsql_makeconf($fstruct, $tbl);
788             #now we push only the fields that we really want
789             push @{$self->{dbsql_fields}->{$tbl}}, $_->{fname};
790             if(defined($_->{prepend})) {
791             push @fconf, @{retarref($_->{prepend})};
792             delete $_->{prepend};
793             }
794             push @fconf, $_;
795             # in case form field name and db table field name differ
796             $self->{dbsql_save_as}->{$_->{NAME}} = $_->{save_as} if(defined($_->{save_as}));
797             if(defined($_->{append})) {
798             push @fconf, @{retarref($_->{append})};
799             delete $_->{append};
800             }
801             }
802             $sth->finish;
803             }
804             }
805              
806             if(defined($self->{dbsql_append})) {
807             push @fconf, @{retarref($self->{dbsql_append})};
808             }
809              
810             #delete primary key fields which are not going to be selected
811             foreach my $tbl (@{$self->{dbsql_tables}}) {
812             foreach my $field (keys(%{$self->{dbsql_pkey}->{$tbl}})) {
813             delete $self->{dbsql_pkey}->{$tbl}->{$field} unless(grep {$field eq $_} @{$self->{dbsql_fields}->{$tbl}});
814             }
815             }
816             my %value;
817             #seems that we shall get the contents of the table fields
818             if(! defined($count)) {
819             $count = -254;
820             foreach my $tbl (@{$self->{dbsql_tables}}) {
821             my $sql = 'SELECT ';
822             foreach $_ (@{$self->{dbsql_fields}->{$tbl}}) {
823             if(m/^(.+)?\.(.+)/) {
824             $sql .= $self->{dbsql}->quote_identifier($1) . '.' . $self->{dbsql}->quote_identifier($2);
825             }
826             else {
827             $sql .= $self->{dbsql}->quote_identifier($_);
828             }
829             $sql .= ',';
830             }
831             $sql =~ s/,$//;
832             $sql .= ' FROM ' . $self->{dbsql}->quote_identifier($tbl);
833             if($self->{dbsql_where}->{$tbl} ne '') {
834             $sql .= ' WHERE '.$self->{dbsql_where}->{$tbl};
835             }
836             my $sth = $self->{dbsql}->prepare($sql);
837             if(! $sth->execute) {
838             carp($self->{dbsql}->errstr);
839             $self->_dbsql_sql_error($sth->{Statement});
840             return 0;
841             }
842             else {
843             #count was not set so we now set it on the number of data records
844             if($count == -254) {
845             $count = $sth->rows;
846             }
847             #the whole thing cannot work if the results for the tables used for the forms don't have the same count of records
848             elsif($count ne $sth->rows) {
849             croak('There must be the same count of records for each table!');
850             }
851             #only if dbsql_show_value is set we shall display the current value of the db fields
852             while($self->{dbsql_show_value} && (my $record = $sth->fetchrow_hashref)) {
853             local $_;
854             foreach $_ (keys(%{$record})) {
855             #we've to prepend the table name in case we've several tables
856             my $field = (@{$self->{dbsql_tables}} > 1 ? "$tbl.$_" : $_);
857             if(ref($value{$field}) ne 'ARRAY') {
858             $value{$field} = [];
859             }
860             #turn db arrays into perl arrays
861             if(defined($record->{$_}) and $record->{$_} =~ m/^\{.*\}$/) {
862             push @{$value{$field}}, $self->_dbsql_parse($record->{$_});
863             }
864             else {
865             push @{$value{$field}}, $record->{$_};
866             }
867             }
868             }
869             }
870             $sth->finish;
871             }
872             }
873             my @conf;
874             #dbsql_row says whether to print the fields belonging to one record in one line (1) or one per line (0)
875             #if dbsql_row was not explicitly set but the count of records is > 1 the default behaviour shall be to use one line per record
876             if($self->{dbsql_row} > 0 or $count > 1 and $self->{dbsql_row} == -254) {
877             $self->{dbsql_row} = 1;
878             my @title;
879             #we've to remove the title out of the configuration and instead use an extra title template which just prints them once at top
880             foreach $_ (@fconf) {
881             push @title, $_->{TITLE} unless($self->{hidden}->{$_->{templ}});
882             $_->{TITLE} = '';
883             #we want the error message to be printed underneath and not at the right
884             ##$_->{templ} = $self->{skin_obj}->dbsql_errmsg_bottom($_->{templ});
885             }
886             push @conf, {templ => 'title', TITLE => \@title};
887             }
888              
889             #get all primary key field names, we'll need that to get all pkey values and then create the md5 hash which ensures that none of the pkeys was altered
890             my @pkey = ();
891             foreach $_ (keys(%{$self->{dbsql_pkey}})) {
892             push @pkey, keys(%{$self->{dbsql_pkey}->{$_}});
893             }
894             my @pkeyval;
895             #the configuration templates for each field is in @fconf, now we create the real form configuration
896             for(my $i=0; $i<$count; $i++) {
897             @pkeyval = ();
898             my $record_conf = clone(\@fconf);
899             if(keys(%value) || $self->{skin_obj}->get_dbsql_secret()) {
900             foreach my $field (@$record_conf) {
901             #we'v to set the default values to the corresponding database record
902             if(keys(%value)) {
903             if(defined($field->{fname}) && defined($value{$field->{fname}})) {
904             #we shouldn't overwrite defaults setted by the user or by the database
905             unless(defined($field->{VALUE})) {
906             local $_;
907             $_ = shift @{$value{$field->{fname}}};
908             #display_as describes in which format the value should be displayed
909             if(ref($field->{display_as}) eq 'ARRAY') {
910             $_ = [$_] unless(ref($_) eq 'ARRAY');
911             ($field->{VALUE}) = _array2array($field->{display_as},[$self->_flatten_array(@{$_})]);
912             }
913             else {
914             $field->{VALUE} = $_;
915             }
916             }
917             }
918             }
919             #could be that the pkey value was setted by hand that's why we've to do this also when no value was fetched out of the database
920             push @pkeyval, $field->{VALUE} if ($field->{fname} and $self->{skin_obj}->get_dbsql_secret() && grep {$_ eq $field->{fname}} @pkey);
921             }
922             }
923              
924             #create and add the md5hash field which ensures that the pkeys can't be altered
925             $_ = md5_hex(join($self->{skin_obj}->get_dbsql_secret(), @pkeyval) . $self->{skin_obj}->get_dbsql_secret());
926             push @$record_conf, {templ => 'dbsql_hidden', NAME => 'md5hash', VALUE => $_} if(@pkeyval);
927             #we probably shall put all fields belonging to one record in one row
928             if($self->{dbsql_row} > 0) {
929             #ROWNUM should be replaced by something else in feature releases
930             push @conf, {templ => $self->{dbsql_row_tmpl}, ROWNUM => $i+1, sub => $record_conf};
931             }
932             #one field per row
933             else {
934             #the empty template should insert space between each line (do we really need that???)
935             push @conf, @$record_conf, {templ => $self->{dbsql_empty_tmpl}};
936             }
937             }
938             $self->set_seperate(1);
939             #we place all in body because we probably use more than 3 columns (which is expected by the 'main' template)
940             $self->conf([{templ => 'body', sub => \@conf}]);
941             #DEBUGGING
942             if($self->{debug}) {
943             foreach $_ (@fconf) {
944             print $_->{NAME}, "\n";
945             }
946             }
947             }
948              
949             ######################################################################
950              
951             =head3 dbsql_update
952              
953             This method can only be used if a where-condition was passed to
954             L.
955              
956             It updates the found table records to the submitted
957             values. If an error occurs the update statement and the DBMSs error
958             message and number is printed. If you want only some of this
959             information to be displayed, see L.
960              
961             Normally you must have defined a secret string if you want to use this
962             method, else an error message will be printed. See L
963             for more information.
964              
965             Before calling this method, you should prove that the form content is
966             valid (see L, C method).
967              
968             =cut
969              
970             ######################################################################
971              
972             sub dbsql_update {
973             my ($self) = @_;
974             my ($md5hash, @pkeyval, @pkeyval2, $ok, $val, $tbl);
975             local $_ = 0;
976             #ensure that there's a primary key defined for every table
977             foreach my $tbl (@{$self->{dbsql_tables}}) {
978             $_ = $tbl and last unless(keys(%{$self->{dbsql_pkey}->{$tbl}}));
979             }
980             if($_) {
981             #append at the form bottom
982             $self->_add_to_output($self->{dbsql_errmsg_tmpl}, {ERRMSG => gettext('Primary key is missing for table') . ' \'' . $_ . '\'!'});
983             return 0;
984             }
985              
986             #if dbsql_hide_pkey was set we must in anycase asure that pkey was not altered
987             if($self->{dbsql_hide_pkey}) {
988             foreach my $tbl (@{$self->{dbsql_tables}}) {
989             local $_;
990             foreach $_ (keys(%{$self->{dbsql_pkey}->{$tbl}})) {
991             push @pkeyval, $self->get_input($_);
992             }
993             }
994             my $md5hash = $self->get_input('md5hash');
995             $self->_add_to_output($self->{dbsql_errmsg_tmpl}, {ERRMSG => gettext('Can\'t update record(s) due to missing primary key checksum').'!'}) and return 0 unless($md5hash);
996             my $ok;
997             if(ref($md5hash) eq 'ARRAY') {
998             $ok = 1;
999             #get pkey value for each record and compare
1000             foreach $_ (@{$md5hash}) {
1001             @pkeyval2 = ();
1002             foreach $val (@pkeyval) {push @pkeyval2, shift @{$val} };
1003             $ok-- && last unless $self->_dbsql_chk_check_sum($_, \@pkeyval2);
1004             }
1005             }
1006             else {
1007             $ok = $self->_dbsql_chk_check_sum($md5hash, \@pkeyval);
1008             }
1009             $self->_add_to_output($self->{dbsql_errmsg_tmpl}, {ERRMSG => gettext('Can\'t update record(s) due to primary key cheksum mismatch').'!'}) and return 0 unless($ok);
1010             }
1011              
1012             return $self->_dbsql_write(1);
1013             }
1014              
1015             ######################################################################
1016              
1017             =head3 dbsql_insert
1018              
1019             This method inserts the transmitted data into the table. If an error
1020             occurs, the insert statement and the DBMSs error message and number are
1021             printed. If you don't want all or some of this information be
1022             displayed, see L.
1023             Before calling this method, you should prove that the form content is
1024             valid (see L, C method).
1025              
1026             =cut
1027              
1028             ######################################################################
1029              
1030             sub dbsql_insert {
1031             my ($self) = @_;
1032             return $self->_dbsql_write(0);
1033             }
1034              
1035             ######################################################################
1036              
1037             =head3 dbsql_set_dbh ( DBHANDLE )
1038              
1039             Use this function to set the internally used database handle. If you
1040             don't call this funtion, you must set it when creating the object with
1041             the L method.
1042              
1043             =cut
1044              
1045             ######################################################################
1046              
1047             sub dbsql_set_dbh {
1048             my ($self, $dbh) = @_;
1049             $self->{dbsql} = $dbh;
1050             if(ref($self->{dbsql}) ne 'DBI::db') {
1051             croak 'No valid database connection!';
1052             }
1053             }
1054              
1055             ######################################################################
1056              
1057             =head3 dbsql_set_hide_pkey ( BOOLEAN )
1058              
1059             By default the primary key fields are represented as I form
1060             fields. This makes sense because when updating records they mustn't be
1061             changed. Sometimes, especially when inserting new records, one might
1062             want to set them by hand. Then he should pass false (0) to this method.
1063              
1064             Passing false to this method will also disable the primary key md5
1065             checksum check when calling C. This means that it'll be
1066             allowed to change the primary keys even when updating records. By
1067             default this is not allowed for security reasons. B
1068             this method!>. DATA CAN EASILY GET OVERWRITTEN!!!
1069              
1070             You can as well set the pkey template by hand using
1071             L.
1072              
1073             =cut
1074              
1075             ######################################################################
1076              
1077             sub dbsql_set_hide_pkey {
1078             my $self = shift;
1079             $self->{dbsql_hide_pkey} = shift;
1080             }
1081              
1082             ######################################################################
1083              
1084             =head3 dbsql_set_show_value ( BOOLEAN )
1085              
1086             When you pass a valid where clause to the new method, the contents of
1087             the found records will be read in and displayed as defaults. In
1088             certain situations one might like to have the fields empty
1089             though. Passing false (0) to this method will do it.
1090              
1091             =cut
1092              
1093             ######################################################################
1094              
1095             sub dbsql_set_show_value {
1096             my $self = shift;
1097             $self->{dbsql_show_value} = shift;
1098             }
1099              
1100             ######################################################################
1101              
1102             =head3 dbsql_set_pkey ( SCALAR|ARRAYREF|HASHREF )
1103              
1104             Normally the primary key of a database table is
1105             autodetected. Sometimes someone might like to define other fields as
1106             primary key though (the primary key is important when updating
1107             records). You can pass a fieldname or a reference to an array with
1108             fieldnames to this method. This method should be called before
1109             L
1110             (for being sure, call this method as early as possible).
1111              
1112             B: If you pass several table names to dbsql_conf, you must pass
1113             as hash reference here, else the passed pkeys will only be used for
1114             the first table.
1115              
1116             =cut
1117              
1118             ######################################################################
1119              
1120             sub dbsql_set_pkey {
1121             my ($self,$pkey)= @_;
1122             if($pkey) {
1123             if(ref($pkey) ne 'HASH') {
1124             croak "You've to reference a hash since there's more than one table!" if(@{$self->{dbsql_tables}} > 1);
1125             $self->{dbsql_pkey} = $pkey;
1126             return 1;
1127             }
1128             foreach my $tbl (keys(%{$pkey})) {
1129             $self->{dbsql_pkey}->{$tbl} = {} if(ref($self->{dbsql_pkey}->{$tbl}) ne 'HASH');
1130             $pkey->{$tbl} = [$pkey->{$tbl}] if(ref($pkey->{$tbl}) ne 'ARRAY');
1131             local $_;
1132             foreach $_ (@{$pkey->{$tbl}}) {
1133             #in case that we've more than one table we reference fields by table.fieldname
1134             #is it ok to add the $tbl prefix here in any case or should i check that @{$self->{dbsql_tables}} > 1 ?
1135             $self->{dbsql_pkey}->{$tbl}->{"$tbl.$_"} = 1;
1136             }
1137             }
1138             return 1;
1139             }
1140             return 0;
1141             }
1142              
1143             ######################################################################
1144              
1145             =head3 dbsql_set_show_default ( BOOLEAN )
1146              
1147             If you pass true (1) to this method the field defaults defined in the
1148             database are used as defaults in the form. This is the default
1149             behavior in case you don't specify a where condition but a number (or
1150             nothing at all which defaults to 1) (see L). In case
1151             that you do specify a where condition its just logical to not use the
1152             database defaults since the real values of the defined database
1153             records are used as default values for the form. So this standard
1154             behaviour should be just fine and you normally don't need this
1155             method. Passing false (0) will force this module to not use the field
1156             defaults defined by the database table structure.
1157              
1158             =cut
1159              
1160             ######################################################################
1161              
1162             sub dbsql_set_show_default {
1163             my ($self, $set) = @_;
1164             #ensure to not set it to 1 since that is the default and it indicates that this function was NOT called
1165             $set++ if($set == 1);
1166             $self->{dbsql_show_default} = $set;
1167             }
1168              
1169             ######################################################################
1170              
1171             =head3 dbsql_set_write_null_fields ( INTEGER )
1172              
1173             With this method you can define whether the value of form fields for
1174             which the user didn't specify any value (he submitted them empty)
1175             should be interpreted as NULL and thus null will be written in the
1176             database or whether they should be ignored so that the default is used
1177             by the database (in case of an insert) resp. the value is not changed
1178             (in case of an update).
1179              
1180             The default is to interpret empty fields as NULL fields.
1181              
1182             B<0> forces the module to not pass empty fields to the database. This
1183             will cause problems when you perform an insert and a certain field is
1184             defined as not_null field and also doesn't have a default value. So
1185             its a bad idea to pass 0 in case you want to make an insert. Also when
1186             doing an update it doesn't make much sense normaly.
1187              
1188             B<1> forces the module to only ignore the null value if it was
1189             specified for a I field (the table structure forbids the
1190             null value for the field). This will cause the same problems as
1191             described for I<0> (see above). But this can be a good idea if your
1192             planning to make an update.
1193              
1194             B<2> forces the module to only ignore an empty field in case it is
1195             defined as I by the database and a default value is
1196             defined. This makes e.g. sense when you want to make an insert and the
1197             database shall just set the default values for fields which were not
1198             fill out by the user. Perhaps you also want to use
1199             I to prevent the default values
1200             from being displayed.
1201              
1202             B<3> this is the default behaviour. Empty field values are passed as
1203             NULL to the database.
1204              
1205             =cut
1206              
1207             ######################################################################
1208              
1209             sub dbsql_set_write_null_fields {
1210             my ($self, $set) = @_;
1211             $self->{dbsql_write_null_fields} = $set;
1212             }
1213              
1214             ######################################################################
1215              
1216             =head3 dbsql_set_errmsg_templ ( TEMPLATENAME )
1217              
1218             If you want to modifiy the output of the system error messages, create
1219             a new template (e.g. copy the default and fit it to your needs) and
1220             pass the new templates name to this method. By default the template
1221             called I of the configured skin ist used (the default skin is
1222             L).
1223              
1224             =cut
1225              
1226             ######################################################################
1227              
1228             sub dbsql_set_errmsg_templ {
1229             my($self, $set) = @_;
1230             $self->{dbsql_errmsg_tmpl} = $set if($set);
1231             }
1232              
1233             ######################################################################
1234              
1235             =head3 dbsql_set_sqlerr ( INTEGER )
1236              
1237             Perhaps you already read that whenever a database error occurs, the
1238             error message, error number and query command is printed out by
1239             default. Sometimes you might prove displaying the sql query a security
1240             lack. With the help of this method, you can define which information
1241             will be printed.
1242              
1243             Listing of the bits and their influence:
1244              
1245             1 error number
1246              
1247             2 error message
1248              
1249             4 sql command
1250              
1251             So if you pass 3 to this method the error number and message will be
1252             printed, but not the sql command.
1253              
1254             =cut
1255              
1256             ######################################################################
1257              
1258             sub dbsql_set_sqlerr {
1259             my($self, $set) = @_;
1260             $self->{dbsql_sqlerr_show} = $set;
1261             }
1262              
1263             ######################################################################
1264              
1265             =head3 dbsql_set_sqlerr_templ ( TEMPLATENAME )
1266              
1267             If you want to modifiy the output of the sql error messages, create a
1268             new template (e.g. copy the default and fit it to your needs) and pass
1269             the new templates name to this method. By default the template called
1270             I of the configured skin is used (the default skin is
1271             L).
1272              
1273             =cut
1274              
1275             ######################################################################
1276              
1277             sub dbsql_set_sqlerr_templ {
1278             my($self, $set) = @_;
1279             $self->{dbsql_sqlerr_tmpl} = $set if($set);
1280             }
1281              
1282             ######################################################################
1283              
1284             =head3 dbsql_set_row ( BOOLEAN )
1285              
1286             If you provided a I and more than one record was
1287             found, or you provided a number instead and it was higher than 1, then
1288             by default it'll be used only one line per record, which means that
1289             fields belonging to the same record will be printed on the same line.
1290              
1291             By passing 0 (false) to this method you can force the object to use
1292             one line per field, 1 (true) is the default.
1293              
1294             =cut
1295              
1296             ######################################################################
1297              
1298             sub dbsql_set_row {
1299             my($self,$set) = @_;
1300             $set -- if($set == -254);
1301             $self->{dbsql_row} = $set;
1302             }
1303              
1304             ######################################################################
1305              
1306             =head3 dbsql_set_row_tmpl ( TEMPLATENAME )
1307              
1308             By default the I template is used. If you want to use another
1309             template for placing the fields which belong to one record into one
1310             line, pass it to this method.
1311              
1312             =cut
1313              
1314             ######################################################################
1315              
1316             sub dbsql_set_row_tmpl {
1317             my ($self,$set) = @_;
1318             $self->{dbsql_row_tmpl} = $set if($set);
1319             }
1320              
1321             ######################################################################
1322              
1323             =head3 dbsql_set_empty_tmpl ( TEMPLATENAME )
1324              
1325             By default the I template is used for inserting space between
1326             the records, If you want to use another template pass its name to this
1327             method. The space is only inserted if every field takes one line.
1328              
1329             =cut
1330              
1331             ######################################################################
1332              
1333             sub dbsql_set_empty_tmpl {
1334             my ($self,$set) = @_;
1335             $self->{dbsql_empty_tmpl} = $set if($set);
1336             }
1337              
1338             ######################################################################
1339              
1340             =head3 dbsql_get_sqlerr
1341              
1342             This method returns an array with the error number and error message
1343             from the last database error. The sql command which caused the error
1344             will be the third and last element.
1345              
1346             =cut
1347              
1348              
1349             ######################################################################
1350              
1351             sub dbsql_get_sqlerr {
1352             my $self = shift;
1353             return @{$self->{dbsql_sqlerr}};
1354             }
1355              
1356             ######################################################################
1357              
1358             =head3 dbsql_add_extra_sql(SQLCOMMAND, ARRAY)
1359              
1360             This method can be used to define some more sql commands which then
1361             will be executed for each record when C or is called.
1362              
1363             The sql command might contain '?' (question marks). These will be
1364             replaced with the values of the fields defined by the second
1365             argument. The first '?' is replaced with the value of the first
1366             element and so on.
1367              
1368             A backslash before a question mark will prevent it from being parsed.
1369              
1370             =cut
1371              
1372             ######################################################################
1373              
1374             sub dbsql_add_extra_sql {
1375             my($self,$sql,@vars) = @_;
1376             push @{$self->{dbsql_extra_sql}}, [$sql, @vars] if($sql);
1377             }
1378              
1379             ######################################################################
1380             # INTERNAL METHODS #
1381             ######################################################################
1382              
1383             #this method is called by HTML::FormEngine s constructor
1384             sub _initialize_child {
1385             my $self = shift;
1386             # the remaining arguments are forwarded by HTML::FormEngine s new method
1387             $self->dbsql_set_dbh(shift);
1388             $self->{dbsql_preconf} = {};
1389             $self->{dbsql_where} = 1;
1390             $self->{dbsql_pkey} = {};
1391             $self->{dbsql_tables} = [];
1392             $self->{dbsql_fields} = {};
1393             $self->{dbsql_hide_pkey} = 1;
1394             $self->{dbsql_show_value} = 1;
1395             #-254 shall indicate that the value was not touched by the user
1396             $self->{dbsql_show_default} = 1;
1397             $self->{dbsql_write_null_fields} = 3;
1398             $self->{dbsql_sqlerr} = [];
1399             $self->{dbsql_sqlerr_show} = 7;
1400             $self->{dbsql_sqlerr_tmpl} = 'sqlerr';
1401             $self->{dbsql_errmsg_tmpl} = 'errmsg';
1402             $self->{dbsql_row_tmpl} = 'row';
1403             $self->{dbsql_empty_tmpl} = 'empty';
1404             #-254 shall indicate that the value was not touched by the user
1405             $self->{dbsql_row} = -254;
1406             $self->{dbsql_extra_sql} = [];
1407             $self->{dbsql_save_as} = {};
1408             $self->{dbsql_not_null_fields} = {};
1409             $self->{dbsql_has_default_fields} = {};
1410              
1411             #HTML::FormEngine::DBSQL::SkinClassic is the default skin for FormEngine::DBSQL
1412             $self->set_skin_obj(new HTML::FormEngine::DBSQL::SkinClassic);
1413              
1414             #just in case someone wants to inherit from this method
1415             $self->_dbsql_initialize_child;
1416             }
1417              
1418             sub _dbsql_initialize_child {
1419             }
1420              
1421             #this method writes the submitted values into the database
1422             sub _dbsql_write {
1423             my ($self,$update) = @_;
1424            
1425             my (%fields,$count);
1426             foreach my $tbl (@{$self->{dbsql_tables}}) {
1427             $fields{$tbl} = {};
1428             foreach $_ (@{$self->{dbsql_fields}->{$tbl}}) {
1429             my $val = $self->_get_input($_);
1430             $val = [$val] if(ref($val) ne 'ARRAY');
1431             #$count shall contain the count of submitted records
1432             $count = @{$val} if(!defined($count) || @{$val} > $count);
1433             $fields{$tbl}->{$_} = $val;
1434             }
1435             }
1436              
1437             $self->{dbsql}->begin_work;
1438             my $rec;
1439             #for each record..
1440             for($rec = 0; $rec<$count; $rec ++) {
1441             my @sql = ();
1442             my %tblvalues = ();
1443             foreach my $tbl (@{$self->{dbsql_tables}}) {
1444             my %values = ();
1445             my %pkey = ();
1446             local $_;
1447             foreach $_ (keys(%{$fields{$tbl}})) {
1448             #we can delete fields which don't have any value left
1449             if(! @{$fields{$tbl}->{$_}}) {
1450             delete $fields{$tbl}->{$_};
1451             }
1452             my $value = $fields{$tbl}->{$_}->[$rec];
1453             $value = undef if($value eq '');
1454              
1455             #save_as describes in which format the value should be saved to the database
1456             if(defined($self->{dbsql_save_as}->{$_}) and ref($self->{dbsql_save_as}->{$_}) eq 'ARRAY') {
1457             $value = [$value] unless(ref($value) eq 'ARRAY');
1458             ($value) = _array2array($self->{dbsql_save_as}->{$_},$value);
1459             }
1460              
1461             #turn perl arrays into database arrays
1462             $value = $self->_dbsql_arr2psql($value) if(ref($value) eq 'ARRAY');
1463            
1464             #we only write null fields according to the settings made through dbsql_set_write_null_fields resp. the default
1465             #but primary keys must never be set to NULL!
1466             if(
1467             (defined($value) and $value ne '') or !$self->{dbsql_pkey}->{$tbl}->{$_} &&
1468             ($self->{dbsql_write_null_fields} > 2 || (
1469             $self->{dbsql_write_null_fields} > 0 && (
1470             ! defined($self->{dbsql_not_null_fields}->{$_} || (
1471             $self->{dbsql_write_null_fields} > 1 && ! defined($self->{dbsql_has_default_fields}->{$_})
1472             )
1473             )
1474             )
1475             )
1476             )
1477             ) {
1478             #filter out the real field name (remove the table name which was added to distinguish the fields)
1479             (my $key = $_) =~ s/^(.+)\.(.+)$/$2/;
1480             #quote the key (fieldname) probably
1481             $key = $self->{dbsql}->quote_identifier($key);
1482             if($self->{dbsql_pkey}->{$tbl}->{$_}) {
1483             $pkey{$key} = $self->{dbsql}->quote($value);
1484             }
1485             $values{$key} = $self->{dbsql}->quote($value);
1486             $tblvalues{$_} = $values{$key};
1487             }
1488             }
1489              
1490             #create an update statement
1491             if($update) {
1492             push @sql, $self->_dbsql_mk_update([keys(%values)], [values(%values)], \%pkey, $tbl);
1493             }
1494             #create an insert statement (here we don't need any primary keys)
1495             else {
1496             push @sql, $self->_dbsql_mk_insert([keys(%values)], [values(%values)], $tbl);
1497             }
1498             }
1499              
1500             #add the specified extra sql statements which should be executed for every record (in most cases the user didn't specify any)
1501             foreach $_ (@{$self->{dbsql_extra_sql}}) {
1502             my $sql = $_->[0];
1503             #replace the ? with the corresponding field value
1504             for(my $x=1; $x<@{$_}; $x++) {
1505             $sql =~ s/(?!\\)(.)\?/$1.$tblvalues{$_->[$x]}/e;
1506             }
1507             $sql =~ s/\\\?/?/g;
1508             push @sql, $sql;
1509             }
1510             foreach my $sql (@sql) {
1511             if($self->{debug}) {
1512             print $sql, "\n";
1513             }
1514             my $sth = $self->{dbsql}->prepare($sql);
1515             #execute statements
1516             if(! $sth->execute) {
1517             $self->_dbsql_sql_error($sql);
1518             return 0;
1519             }
1520             }
1521             }
1522             $self->{dbsql}->commit;
1523             return $rec;
1524             }
1525              
1526              
1527             #this method turns a perl array into a database array ('{field1, field2, {subfield1, subfield2}, ...}')
1528             #it works recursive
1529             sub _dbsql_arr2psql {
1530             my ($self,$elem) = @_;
1531             my $res = '';
1532             if(ref($elem) eq 'ARRAY') {
1533             $res = '{';
1534             foreach $_ (@{$elem}) {
1535             $res .= $self->_dbsql_arr2psql($_) . ',';
1536             }
1537             $res =~ s/,$/\}/;
1538             }
1539             else {
1540             $res = $elem;
1541             }
1542             return $res;
1543             }
1544              
1545             #this method creates an insert statement
1546             sub _dbsql_mk_insert {
1547             my ($self,$fields,$values,$table) = @_;
1548             if(ref($fields) eq 'ARRAY' && ref($values) eq 'ARRAY' && $table ne '') {
1549             return 'INSERT INTO ' . $self->{dbsql}->quote_identifier($table) . ' ('.join(', ', @{$fields}).') VALUES ('.join(', ', @{$values}).')';
1550             }
1551             else {
1552             return '';
1553             }
1554             }
1555              
1556             #this method creates an update statement
1557             sub _dbsql_mk_update {
1558             my ($self,$fields,$values,$pkey,$table) = @_;
1559             my $sql = '';
1560              
1561             if(ref($fields) eq 'ARRAY' && ref($values) eq 'ARRAY' && ref($pkey) eq 'HASH' && $table ne '') {
1562             $sql = 'UPDATE ' . $self->{dbsql}->quote_identifier($table) . ' SET ';
1563             my $i = 0;
1564             foreach $_ (@{$fields}) {
1565             $sql .= "$_=" . $values->[$i] . ', ';
1566             $i ++;
1567             }
1568             $sql =~ s/, $//;
1569             $sql .= ' WHERE ';
1570             foreach $_ (keys(%{$pkey})) {
1571             $sql .= "$_=" . $pkey->{$_} . ' AND ';
1572             }
1573             $sql =~ s/ AND $//;
1574             }
1575            
1576             return $sql;
1577             }
1578              
1579             #this method creates a field configuration with the help of the database table structure information
1580             sub _dbsql_makeconf {
1581             my ($self,$info,$tbl) = @_;
1582             my %res = ();
1583             if(ref($info) eq 'HASH') {
1584             #($res{TITLE} = $info->{name}) =~ s/^([a-z]{1})/uc($1)/e; does raise an endless loop
1585             #by default the title shall be the name but with the first letter being capital
1586             $_ = $info->{COLUMN_NAME} and s/^([a-z]{1})/uc($1)/e and $res{TITLE} = $_;
1587             #attach $tbl in front so that fields with same names (out of diffrent tables) don't get confused
1588             $info->{COLUMN_NAME} = $tbl . '.' . $info->{COLUMN_NAME} if(@{$self->{dbsql_tables}} > 1);
1589             #fname is just a copy of name, i forgott what for :(
1590             $res{fname} = $info->{COLUMN_NAME};
1591             $res{NAME} = $info->{COLUMN_NAME};
1592             #parse the default
1593             #we should only use the default value if dbsql_show_default is true, primary keys should not be touched
1594             if($info->{COLUMN_DEF} && $self->{dbsql_show_default} > 0 && ! $self->{dbsql_pkey}->{$tbl}->{$res{NAME}}) {
1595             #removing the explizit datatype cast (this is new in postgres 7.4)
1596             $info->{COLUMN_DEF} =~ s/::[a-z ]+(\[\])?//g;
1597             $info->{COLUMN_DEF} =~ s/^'(.*)'$/$1/;
1598             #default can also be an array
1599             if($info->{COLUMN_DEF} =~ m/^\{.*,.*\}$/) {
1600             ($res{VALUE}) = $self->_dbsql_parse($info->{COLUMN_DEF});
1601             }
1602             else {
1603             $res{VALUE} = $info->{COLUMN_DEF};
1604             }
1605             }
1606             #call the datatype handlers
1607             $info->{TYPE_NAME} =~ s/\[\]$//;
1608             my $handler;
1609             if(ref($self->{skin_obj}->get_dbsql_dthandler($info->{TYPE_NAME})) eq 'CODE') {
1610             $handler = $self->{skin_obj}->get_dbsql_dthandler($info->{TYPE_NAME});
1611             }
1612             else {
1613             $handler = $self->{skin_obj}->get_dbsql_dthandler('default');
1614             }
1615             &$handler($self, \%res, $info);
1616             #hide primary keys
1617             if($self->{dbsql_pkey}->{$tbl}->{$info->{COLUMN_NAME}} && $self->{dbsql_hide_pkey}) {
1618             $res{templ} = 'dbsql_hidden';
1619             $res{TITLE} = '';
1620             }
1621              
1622             #the user can define configuration variables in the fields description
1623             #we parse the description here and ensure that the form configuration gets completed
1624             if($info->{REMARKS}) {
1625             while($info->{REMARKS} =~ m/\G.*?([A-Za-z_]+)\=(?:;|(.*?[^\\]{1});)/g) {
1626             my $var = $1;
1627             local $_;
1628             if(defined($2)) {
1629             ($_ = $2) =~ s/\\;/;/g;
1630             }
1631             else {
1632             $_ = '';
1633             }
1634             ($res{$var}) = $self->_dbsql_parse($_);
1635             $res{$var} = '' unless(defined($res{$var}));
1636             }
1637             }
1638              
1639             #display_as describes in which format the value should be displayed
1640             if(defined($res{display_as}) and defined($res{VALUE}) and ref($res{display_as}) eq 'ARRAY') {
1641             $res{VALUE} = [$res{VALUE}] unless(ref($res{VALUE}) eq 'ARRAY');
1642             my @test = $self->_flatten_array(@{$res{VALUE}});
1643             ($res{VALUE}) = _array2array($res{display_as},[$self->_flatten_array(@{$res{VALUE}})]);
1644             }
1645              
1646             # only if null fields are going to be written we set the not_null check, see dbsql_set_write_null_fields for better understanding
1647             if($self->{dbsql_write_null_fields} > 2 || ($self->{dbsql_write_null_fields} > 1 && !$info->{COLUMN_DEF}) and !$info->{NULLABLE}) {
1648             $res{ERROR} = ($res{ERROR} ? [$res{ERROR}] : []) unless(ref($res{ERROR}) eq 'ARRAY');
1649             push @{$res{ERROR}}, 'not_null';
1650             }
1651              
1652             #we need the following later to distinguish whether a field which was submitted with an empty value shall be written into database or not
1653             $self->{dbsql_not_null_fields}->{$res{fname}} = 1 unless($info->{NULLABLE});
1654             $self->{dbsql_has_default_fields}->{$res{fname}} = 1 unless(defined($info->{COLUMN_DEF}));
1655             #add the preconf settings made by the user
1656             if(ref($self->{dbsql_preconf}->{$info->{COLUMN_NAME}}) eq 'HASH') {
1657             foreach $_ (keys(%{$self->{dbsql_preconf}->{$info->{COLUMN_NAME}}})) {
1658             #the given values shall not overwrite but complete the default settings
1659             if($_ =~ m/^__add_(.+)_(first|last)$/) {
1660             my $varname = $1;
1661             my $pos = $2;
1662             $res{$varname} = [] if(!defined($res{$varname}));
1663             $res{$varname} = [$res{$varname}] if(ref($res{$varname}) ne 'ARRAY');
1664             my $addvalue = $self->{dbsql_preconf}->{$info->{COLUMN_NAME}}->{$_};
1665             $addvalue = [$addvalue] unless(ref($addvalue) eq 'ARRAY');
1666             if($pos eq 'last') {
1667             push @{$res{$varname}}, @$addvalue;
1668             }
1669             elsif($pos eq 'first') {
1670             #why not use unshift?
1671             @{$res{$varname}} = (@$addvalue, @{$res{$varname}});
1672             }
1673             }
1674             else {
1675             $res{$_} = $self->{dbsql_preconf}->{$info->{COLUMN_NAME}}->{$_};
1676             }
1677             }
1678             }
1679              
1680             }
1681             return \%res;
1682             }
1683              
1684             # transform array string-notation (database) into perl array
1685             # this method works recursive
1686             sub _dbsql_parse {
1687             my ($self,$struc) = @_;
1688             return [$self->_dbsql_parse($1,1)] if($struc =~ m/^\{([^{}]*)\}$/);
1689             my $struc2 = $struc;
1690             #just delete quoted (" ... ") sections since they shouldn't be parsed!
1691             while($struc2 =~ s/(\G|[^\\]{1})"(?!.*\\).*?"/$1/){};
1692             if($struc2 =~ m/^[^{\,}]*$/) {
1693             #remove the quotations, they're only for preventing certain parts of being parsed but not meant to be really part of the array in the end
1694             while($struc =~ s/(^|[^\\]{1})"/$1/g){};
1695             #to be able to print " in a quotated section the \ before an " marks it for not being interpreted
1696             #now we should remove those \ so that in the end everything looks normal again
1697             $struc =~ s/\\"/"/g;
1698             return $struc;
1699             }
1700             my @res = ();
1701             #we've a normal list of values here (seperated by ,), no subarrays, so we can easily split the list and just return the resulting array
1702             if($struc =~ m/^([^"{}]*\,[^"{}]*)$/) {
1703             local $_ = $1;
1704             push @res, split(/,/, $_) if($_);
1705             push @res, '' if($struc =~ m/,$/);
1706             push @res, '' if($struc =~ m/^,$/);
1707             return @res;
1708             }
1709              
1710             my ($off,$lbr,$rbr,$quot) = (0,0,0,0,0,0,0);
1711             my $last = $_ = '';
1712             for(my $i=0; $i
1713             $last = $_;
1714             $_ = substr($struc, $i, 1);
1715             last unless defined($_);
1716             #we found a quotation mark, now we've to wait till we reach the end
1717             ++ $quot && $i
1718             #we're not in a quoted area if $quot % 2 == 0
1719             unless($quot % 2) {
1720             ++ $lbr and next if($_ eq '{');
1721             #if we're at the end of the string we mustn't do a next because that would cause a break of the loop
1722             ++ $rbr and $i
1723             #when we find a ',' or we're at the end of the string and there are as may '{' as '}' we shall parse the piece from the last ',' or beginning till here
1724             if($_ eq ',' || $i >= length($struc)-1 and $lbr == $rbr) {
1725             # when we're at the end we must add 1 more because $i wasn't increased because we didn't do a 'next'
1726             local $_ = substr($struc,$off,$i-$off);
1727             #remove brackets
1728             if(m/^{(.*)}$/) {
1729             push @res, [$self->_dbsql_parse($1)];
1730             }
1731             else {
1732             push @res, $self->_dbsql_parse($_);
1733             }
1734             $off=$i+1;
1735             next;
1736             }
1737             }
1738             }
1739             return @res;
1740             }
1741              
1742             #compare given checksum with the checksum of the given value
1743             sub _dbsql_chk_check_sum {
1744             my($self,$md5hash,$val) = @_;
1745             return 1 if($md5hash eq md5_hex(join($self->{skin_obj}->get_dbsql_secret(), @{$val}) . $self->{skin_obj}->get_dbsql_secret()));
1746             return 0;
1747             }
1748              
1749             #gets error string and error number from dbi object, the sqlstatement which causes the error should be passed to the method. it then adds part of this information (depending on dbsql_sqlerr_show) to the bottom of the form using a special template which name is provided by dbsql_sqlerr_tmpl (can be changed by method dbsql_set_sqlerr_templ)
1750             sub _dbsql_sql_error {
1751             my($self, $sql) = @_;
1752             $self->{dbsql_sqlerr} = [$self->{dbsql}->errstr, $sql, $self->{dbsql}->err];
1753             my %errconf = (
1754             ERRNUM => $self->{dbsql_sqlerr_show} & 1 ? $self->{dbsql}->err : gettext('can\'t be displayed'),
1755             ERRMSG => $self->{dbsql_sqlerr_show} & 2 ? $self->{dbsql}->errstr : gettext('can\'t be displayed'),
1756             SQLSTAT => $self->{dbsql_sqlerr_show} & 4 ? $sql : gettext('can\'t be displayed')
1757             );
1758             $self->_add_to_output($self->{dbsql_sqlerr_tmpl},\%errconf);
1759             }
1760              
1761             #this method is for internal use only, it just ensures that the given value is an array reference, if not it turns it into one
1762             sub retarref {
1763             my $arr = shift;
1764             defined($arr) ? return [$arr] : return [] if(ref($arr) ne 'ARRAY');
1765             return $arr;
1766             }
1767              
1768             # expects 2 array references. it then takes the first arrays structure as a template in which it puts the values of the second array. the result is returned.
1769             sub _array2array {
1770             my($arr1,$arr2,$i) = @_;
1771             $i = 0 unless($i);
1772             my (@res,$elem);
1773             foreach $elem (@$arr1) {
1774             if(ref($elem) eq 'ARRAY') {
1775             local $_;
1776             ($_,$i) = _array2array($elem,$arr2,$i);
1777             push @res, $_;
1778             }
1779             else {
1780             push @res, defined($arr2->[$i]) ? $arr2->[$i] : '';
1781             $i ++;
1782             }
1783             }
1784             return (\@res, $i);
1785             }
1786              
1787             ######################################################################
1788              
1789             =head1 EXTENDING FORMENGINE::DBSQL
1790              
1791             =head2 Write A Handler For Another Datatype
1792              
1793             Have a look at DtHandler.pm and read
1794             L.
1795              
1796             =head2 Suiting the Layout
1797              
1798             For this task you should create a new skin. For general information
1799             about FormEngine skins, have a look at L and its
1800             submodules. You should also read
1801             L and its source code, the
1802             templates which are defined there are necessary for DBSQL.pm and you
1803             should at least implement replacements for them in your new skin. Use
1804             C to load your skin.
1805              
1806             =head1 MORE INFORMATION
1807              
1808             Have a look at ...
1809              
1810             =over
1811              
1812             =item
1813              
1814             L and its source code for
1815             information about writing datatype handlers.
1816              
1817             =item
1818              
1819             L and its source code for
1820             information about the DBSQL.pm specific templates.
1821              
1822             =back
1823              
1824             =head1 BUGS
1825              
1826             Please use
1827             L to
1828             inform you about reported bugs and to report bugs.
1829              
1830             If it doesn't work feel free to email directly to
1831             moritz@freesources.org.
1832              
1833             Thanks!
1834              
1835             =head1 AUTHOR
1836              
1837             (c) 2003-2004, Moritz Sinn. This module is free software; you can
1838             redistribute it and/or modify it under the terms of the GNU General
1839             Public License (see http://www.gnu.org/licenses/gpl.txt) as published
1840             by the Free Software Foundation; either version 2 of the License, or
1841             (at your option) any later version.
1842              
1843             This module is distributed in the hope that it will be useful, but
1844             WITHOUT ANY WARRANTY; without even the implied warranty of
1845             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1846             General Public License for more details.
1847              
1848             I am always interested in knowing how my work helps others, so if you
1849             put this module to use in any of your own code please send me the
1850             URL. If you make modifications to the module because it doesn't work
1851             the way you need, please send me a copy so that I can roll desirable
1852             changes into the main release.
1853              
1854             Please use
1855             L for
1856             comments, suggestions and bug reports. If it doesn't work feel free to
1857             mail to moritz@freesources.org.
1858              
1859             =head1 CREDITS
1860              
1861             Special thanks to Mark Stosberg, he helped a lot by reporting bugs,
1862             contributing new ideas and sending patches.
1863              
1864             =head1 SEE ALSO
1865              
1866             HTML::FormEngine by Moritz Sinn
1867              
1868             HTML::FormTemplate by Darren Duncan
1869              
1870             =cut
1871              
1872             1;
1873              
1874             __END__