.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40)
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings. \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
.\" nothing in troff, for use with C<>.
.tr \(*W-
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
. ds -- \(*W-
. ds PI pi
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
. ds L" ""
. ds R" ""
. ds C` ""
. ds C' ""
'br\}
.el\{\
. ds -- \|\(em\|
. ds PI \(*p
. ds L" ``
. ds R" ''
. ds C`
. ds C'
'br\}
.\"
.\" Escape single quotes in literal strings from groff's Unicode transform.
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\"
.\" If the F register is >0, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
.\" entries marked with X<> in POD. Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.\"
.\" Avoid warning from groff about undefined register 'F'.
.de IX
..
.nr rF 0
.if \n(.g .if rF .nr rF 1
.if (\n(rF:(\n(.g==0)) \{\
. if \nF \{\
. de IX
. tm Index:\\$1\t\\n%\t"\\$2"
..
. if !\nF==2 \{\
. nr % 0
. nr F 2
. \}
. \}
.\}
.rr rF
.\" ========================================================================
.\"
.IX Title "Intrors 3pm"
.TH Intrors 3pm "2021-01-05" "perl v5.32.0" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
.nh
.SH "NAME"
DBIx::Intrors \- Embperl and DBIx::Recordset
.SH "Embperl and DBIx::Recordset"
.IX Header "Embperl and DBIx::Recordset"
This introduction gives an overview how to use \fIDBIx::Recordset\fR together
with \fIHTML::Embperl\fR. Since there are only a few \fIEmbperl\fR specific
things herein, it should be also useful for non \fIEmbperl\fR users.
.SS "Overview"
.IX Subsection "Overview"
It is often very difficult to layout and design the output of normal \s-1CGI\s0
scripts, because you are dealing with
HTML-sourcecode which spans multiple prints, and it isn't possible to use
some sort of HTML-editor. Embperl takes a different approach to this problem.
With Embperl, you can build your HTML-pages
with any tool you like, and you can embed fragments of code directly
in the page. This makes it much easier for
non-programmers to use, because they are able to use
their usual tools and they see the fragments of code as normal text.
This indroduction will deal with the Perl Modules \fIHTML::Embperl\fR and
\&\fIDBIx::Recordset\fR, with a focus on database access.
.SS "Embperl"
.IX Subsection "Embperl"
In brief, the purpose of Embperl is to execute code that is
embedded in HTML-pages as the page is requested from the server.
There are two ways to do this with Embperl. The first way is to
embed the code between [\- and \-] tags. This will cause
Embperl to execute the code and remove it from the source before sending
the page. The second way is to use [+ and +] as the delimiter, in which case
the code will be executed and the result of the execution is send to the
browser in place of the code.
All database access is done via the module \fIDBIx::Recordset\fR, which simplifies
a lot of common tasks when accessing a database via \s-1DBI.\s0
.SH "Basic Example"
.IX Header "Basic Example"
The following example shows the basic functions of both modules. It shows the
contents of a table whose name is passed as a parameter:
.PP
Contents of table \*(L"[+ \f(CW$fdat\fR{'!Table'} +]\*(R"
.PP
.Vb 2
\& [\-
\& use DBIx::Recordset ;
\&
\& $fdat{\*(Aq!DataSource\*(Aq} = \*(Aqdbi:mysql:test\*(Aq ;
\& *set = DBIx::Recordset \-> Search(\e%fdat) ;
\& $names = $set \-> Names ;
\& \-]
\&
\&
\&
\& [+ $names \-> [$col] +] |
\&
\&
\& [\- $rec = $set[$row] \-]
\& [+ $rec \-> {$names\->[$col]} +] |
\&
\&
\&
.Ve
.PP
To show the contents of the table \f(CW\*(C`address\*(C'\fR you may call it with:
.PP
.Vb 1
\& http://www.domain.com/path/to/example1.htm?!Table=address
.Ve
.PP
All query parameters are placed in the hash \f(CW%fdat\fR by Embperl. In
our example, \f(CW$fdat{\*(Aq!Table\*(Aq}\fR would contain the value \f(CW\*(C`address\*(C'\fR.
Additionally, Embperl replaces the code between \f(CW\*(C`[+\*(C'\fR and \f(CW\*(C`+]\*(C'\fR with the
result, so the headline of the page would be 'Contents of table \*(L"address\*(R"'.
.PP
The following [\- \-] block will be executed by Embperl. No trace of it will show up
in the page that is sent to the browser. The first line sets the database which should be
accessed. The syntax is the same as for the \s-1DBI\s0 connect call. If you omit the line, you
must additionally send the databasename as a query parameter \- but for security reasons,
that isn't a very good idea.
.SS "Search"
.IX Subsection "Search"
Next we call the method \f(CW\*(C`Search\*(C'\fR of \fIDBIx::Recordset\fR, where we have the choice between
the object and the class-method. This applies to a lot of other methods as well.
When we call it as a class method, as we do in our example, it constructs a new \fIDBIx::Recordset\fR
object and uses the passed parameters to query the database. It's also possible to divide
these two steps and call \f(CW\*(C`Setup\*(C'\fR to first construct the object and then
\&\f(CW\*(C`Search\*(C'\fR with this object to execute the Search. In the example above, we do
not pass any query parameters \*(-- so \f(CW\*(C`Search\*(C'\fR will return the contents of the
whole table. (\fIDBIx::Recordset\fR converts the call internally to the \s-1SQL\s0
statement \f(CW\*(C`SELECT * FROM address\*(C'\fR).
.PP
The last line of the [\- \-] block retrieves the fieldnames of the table. Here we can see
a special feature of \fIDBIx::Recordset\fR, which we will discuss in detail later on. The
constructor returns a \fBtypeglob\fR (\f(CW*set\fR), but the call to \f(CW\*(C`Names\*(C'\fR uses a \fBscalar\fR (\f(CW$set\fR).
By returning a typeglob, \fIDBIx::Recordset\fR is able to return a \fBscalar\fR, an \fBarray\fR and
a \fBhash\fR at the same time. (If you don't like the idea of using typeglobs, you can also
construct all three with different methods).
.SS "Display the table"
.IX Subsection "Display the table"
At first glance, the following might appear to be a simple HTML-table. But \fIEmbperl\fR
expands it, so that the full contents of the database table is shown. Let us first look at
the header, which should show the fieldnames of the database-table: \f(CW$names\fR
contains a reference to an array which contains the fieldnames. \fIEmbperl\fR
gives us the magical variable \f(CW$col\fR. \f(CW$col\fR will be automatically
incremented as long as the result of the expression which contains \f(CW$col\fR
doesn't return \fBundefined\fR. At the same time, \fIEmbperl\fR repeats the
surrounding \f(CW\*(C` or \f(CW\*(C` | tags. If we have a table with the three columns
\&\f(CW\*(C`name\*(C'\fR, \f(CW\*(C`firstname\*(C'\fR and \f(CW\*(C`town\*(C'\fR, the output would look like this:
.PP
.Vb 1
\& | name | firstname | town |
.Ve
.PP
Now the header is ready and we can start to output the contents. Here we use
the array part of the typeglob that is returned by \f(CW\*(C`Search\*(C'\fR. Access to the
results of the SQL-query is done via the array \f(CW@set\fR, and every row of the
array \*(L"contains\*(R" one row of the database-table. It does not really contain the
row, but \fIDBIx::Recordset\fR will fetch the row from the databases for you if
you access the corresponding array row. The rows are stored as a hash, where
the fieldnames are the hashkeys. This is the same mechanism that helped us
to expand the columns of the header, but it's at work here in a
two-dimensional manner. \f(CW$row\fR contains the row-count and \f(CW$col\fR contains the
column-count.
.SS "Supplying query parameters"
.IX Subsection "Supplying query parameters"
But our small example can do even more: If we supply more query parameters
in our request, we can decide which parts of the table should be selected
(and therefor, shown). If we request the page with
.PP
.Vb 1
\& http://wwww.domain.com/path/to/example1.htm?!Table=address&town=Berlin
.Ve
.PP
\&\fIEmbperl\fR will not only place \f(CW\*(C`!\*(C'\fR\f(CW\*(C`T\*(C'\fR\f(CW\*(C`able\*(C'\fR in the hash \f(CW%fdat\fR, but also \f(CW\*(C`town\*(C'\fR.
Since \f(CW\*(C`town\*(C'\fR corresponds to a fieldname in our table, \fIDBIx::Recordset\fR interprets
it as a parameter for the \f(CW\*(C`WHERE\*(C'\fR part of the \f(CW\*(C`SELECT\*(C'\fR command. \fIDBIx::Recordset\fR
will generate the following SQL-query:
.PP
.Vb 1
\& SELECT * FROM address WHERE town=\*(AqBerlin\*(Aq ;
.Ve
.PP
The programmer doesn't have to pay attention to datatypes or quoting, this is
done automatically by \fIDBIx::Recordset\fR.
.PP
Also, complex queries are easy to implement: if, for example, the user wants
to be able to search for a name or for a town, it would be possible to use
the following form:
.PP
.Vb 5
\&
.Ve
.PP
If the user enters \*(L"Richter\*(R" to the input field and presses the submit button,
the following SQL-query will be generated:
.PP
.Vb 1
\& SELECT * FROM address WHERE name=\*(AqRichter\*(Aq OR town=\*(AqRichter\*(Aq ;
.Ve
.PP
Just by varying the parameters, it is possible to create simple or complex queries.
In this way, you can use the same page with different parameters to create
different sorts of queries.
.SH "Multiple tables"
.IX Header "Multiple tables"
Until now, we only have worked with one table. In real life, you often have to
deal with mulitple tables. For this reason, \fIDBIx::Recordset\fR helps you to
reduce the expense associated with dealing with multiple tables. The simplest
way to do this is to use the
parameters \f(CW\*(C`!TabJoin\*(C'\fR and \f(CW\*(C`!TabRelation\*(C'\fR to tell \fIDBIx::Recordset\fR to create
an SQL-join between two or more tables. This will link the tables together and
the result looks just like one great table.
.PP
More interesting is the possibility to create \fB\*(L"links\*(R"\fR. As an example, we'll take the same
table we used above and divide it into two tables: one table for the names and one
table for the towns. As a link we add an id-field. If the fields are following some naming
convention, \fIDBIx::Recordset\fR is able to find this link automatically. If fields are
named in another way, you have to tell \fIDBIx::Recordset\fR manually how the tables belong
together.
.PP
.Vb 2
\& Table name: firstname, name, town_id
\& Table town: id, town
.Ve
.PP
Here, every name has exactly one town and every town has a number of names assigned.
With a simple modification of our first example, we could get the same result
as above (except that we are now dealing with two tables instead of one):
.PP
.Vb 4
\& [\-
\& use DBIx::Recordset ;
\& $db = DBIx::Database \-> new (\*(Aqdbi:mysql:test\*(Aq) ;
\& $db \-> TableAttr (\*(Aqtown\*(Aq, \*(Aq!NameField\*(Aq, \*(Aqtown\*(Aq) ;
\&
\& $fdat{\*(Aq!DataSource\*(Aq} = $db ;
\& $fdat{\*(Aq!LinkName\*(Aq} = 3 ;
\& *set = DBIx::Recordset \-> Search(\e%fdat) ;
\& $names = $set \-> Names ;
\& \-]
.Ve
.PP
And the request would be:
.PP
.Vb 1
\& http://www.domain.com/path/to/example2.htm?!Table=name
.Ve
.SS "DBIx::Database"
.IX Subsection "DBIx::Database"
The new thing here is the \f(CW\*(C`DBIx::Database\*(C'\fR object. It gathers meta-information
about the database and stores it for later use. Because of the names of the fields
the object can detect that the field \f(CW\*(C`town_id\*(C'\fR in the table \f(CW\*(C`name\*(C'\fR points to
field \f(CW\*(C`id\*(C'\fR in the table \f(CW\*(C`town\*(C'\fR. Additionally, we tell the \f(CW\*(C`DBIx::Database\*(C'\fR object
which column(s) contain the human-readable name of the table \f(CW\*(C`town\*(C'\fR.
These initialisations only have to be executed once. If you use
\&\fImod_perl\fR, for example, you should be able to move these lines into
a common startup file.
.PP
Also new is the parameter \f(CW\*(C`!LinkName\*(C'\fR. It tells \fIDBIx::Recordset\fR to return
the human-readable name (in our example, \f(CW\*(C`town\*(C'\fR) instead of the field which links
the two tables together (\f(CW\*(C`town_id\*(C'\fR in our example). Internally, \fIDBIx::Recordset\fR
generates an SQL-join, so there is only one \f(CW\*(C`SELECT\*(C'\fR command necessary and the result
is just the same as in the last example.
.SS "Sub-Objects"
.IX Subsection "Sub-Objects"
But what to do if we have the \f(CW\*(C`id\*(C'\fR of a town and want to display all the names that
belongs to it? An \fIEmbperl\fR\-page that does this job might look something like this:
.PP
[\-
use DBIx::Recordset ;
\f(CW$fdat\fR{'!DataSource'} = 'dbi:mysql:test' ;
\f(CW$fdat\fR{'!Table'} = 'town' ;
*set = DBIx::Recordset \-> Search(\e%fdat) ;
\-]
.PP
.Vb 11
\& town: [+ $set{town} +]
\&
\&
\& name | firstname |
\&
\&
\& [\- $rec = $set{\-name}[$row] \-]
\& [+ $rec \-> {name} +] | [+ $rec \-> {firstname} +] |
\&
\&
\&
.Ve
.PP
A request to that page might look like this:
.PP
.Vb 1
\& http://www.domain.com/path/to/example3.htm?id=5
.Ve
.PP
In this example, we specify the name of the table directly inside the page, so it
can't be overwritten from outside. The call to \f(CW\*(C`Search\*(C'\fR returns the town for the
given query parameters. In our example, it will select the town with the \f(CW\*(C`id\*(C'\fR 5.
The command \f(CW\*(C`[+ $set{town} +]\*(C'\fR shows the value of the field town in the current
record. After the call to \f(CW\*(C`Search\*(C'\fR, this is the first selected record.
Next, we need to display all the names. This is very easy using the special field
\&\f(CW\*(C`\-name\*(C'\fR. \f(CW\*(C`\-name\*(C'\fR contains a sub-object for the table \f(CW\*(C`name\*(C'\fR. The query parameters
for this sub-object are set by \fIDBIx::Recordset\fR in such a way that it contains all
names which meet the link-condition. We just wrap it in a table and we are already done.
.SH "Modify the Database"
.IX Header "Modify the Database"
Up to this point, we have only discussed the retrieval and display of data.
But of course it's also possible to modify data. The simplest way to do this
is to assign new values to the result of a \f(CW\*(C`Search\*(C'\fR call. For example, you
may write \f(CW\*(C`$set{town} = \*(AqFrankfurt\*(Aq\*(C'\fR to change the name of the town.
\&\fIDBIx::Recordset\fR converts this into a vaild SQL-Update-command.
.PP
While this is very useful in normal Perl scripts, you probably won't use it very
often in a cgi script.
The methods \f(CW\*(C`Insert\*(C'\fR/\f(CW\*(C`Update\*(C'\fR/\f(CW\*(C`Delete\*(C'\fR will probably prove more useful.
Just like \f(CW\*(C`Search\*(C'\fR, these directly accept query parameters posted to the page.
The method \f(CW\*(C`Execute\*(C'\fR combines all four of these together,
making it possible to control the type of action via the CGI-parameters.
.PP
Here is an example:
.PP
Database Access with HTML::Embperl and DBIx::Recordset
.PP
.Vb 7
\& [\-
\& ### Database\-parameter ###
\& use DBIx::Recordset ;
\& $fdat{\*(Aq!DataSource\*(Aq} = \*(Aqdbi:mysql:test\*(Aq ;
\& $fdat{\*(Aq!Table\*(Aq} ||= \*(Aqtown\*(Aq ;
\& $fdat{\*(Aq!PrimKey\*(Aq} = \*(Aqid\*(Aq ;
\& $fdat{\*(Aq$max\*(Aq} = 10 ;
\&
\& ### Execute action according to the query parameters ###
\& *set = DBIx::Recordset \-> Execute (\e%fdat) ;
\& \-]
\&
\& [$if $DBI::errstr $]
\& Database Error [+ $DBI::errstr +]
\& [$else$]
\& [\-$names = $set \-> AllNames ; \-]
\& [$if $set[0] && $set \-> MoreRecords $]
\& [### We found more then one record ###]
\& [### \-> display as a table ###]
\&
\& [### Display header ###]
\& [+ ucfirst ($names \-> [$col]) +] |
\&
\& [### Display record \-> Table will be expanded by Embperl ###]
\& [\- $rec = $set[$row] \-]
\&
\& [\- $name = $names \-> [$col] \-]
\& [$if $name eq $fdat{\*(Aq!PrimKey\*(Aq} $]
\& [### Generate HTML link to edit this record ###]
\& [+ $rec \-> {$name} +]
\& [$elsif $set \-> Link4Field($name) $]
\& [### Link to other table \-> generate HTML link ###]
\& [\- $link = $set \-> Link($set \-> Link4Field($name)) \-]
\& [+$rec \-> {$name}+]
\& [$else$]
\& [### Display contents of field ###]
\& [+ $rec \-> {$names\->[$col]} +]
\& [$endif$]
\& |
\&
\&
\& [+ $set \-> PrevNextForm (\*(Aq\e<\e\e>\*(Aq, \e%fdat) +]
\&
\& Search record in table \*(Aq[+ $fdat{\*(Aq!Table\*(Aq} +]\*(Aq
\& [$else$]
\& [### We found no/one record(s) ###]
\& [### \-> Display form ###]
\&
\& [$endif$]
\& [$endif$]
\&
\&
.Ve
.PP
When you first request this page, it will show the contents of the
preset table. Alternatively, you can supply a tablename with the
parameter \f(CW\*(C`!T\*(C'\fR\f(CW\*(C`able\*(C'\fR. The link, which is shown at the bottom of the
page, leads you to an imput form. There, you can fill in one or
more fields and press the \fBSearch\fR button. This invokes the page
itself and \f(CW\*(C`Execute\*(C'\fR will be instructed by the parameter \f(CW\*(C`=s\*(C'\fR\f(CW\*(C`earch\*(C'\fR
(Name of the button \*(L"Search\*(R") to retrieve all records which match
the entered values.
.PP
If the query finds more then one record, a table with all records found
will be shown. If there are more records than specified by the parameter \f(CW$max\fR, only
\&\f(CW$max\fR records are displayed. If this is the case, the \f(CW\*(C`PrevNextForm\*(C'\fR method
adds a \*(L"Previous\*(R" and a \*(L"Next\*(R" button to the page, allowing you to browse
through the whole table.
In the example above, we assume that every table has a primary key,
which is passed
to \fIDBIx::Recordset\fR by the line \f(CW\*(C`$fdat{\*(Aq!PrimKey\*(Aq} = \*(Aqid\*(Aq ;\*(C'\fR. The column which
contains this primary key will be displayed as an \s-1HTML\s0 link containing the
parameters to execute a search for just this record. As you can see in
example4.htm, this can be used to display a form which includes some of
the data from the found record (see below).
Columns which are links to other tables will also be shown with an HTML-link. A click
on that link will open the linked table or record.
.PP
If the search only selects one record, the same form is shown, but with the data from
the record filled in. Now it's possible to change the content. The changes are
written to the database when you press the button \fBUpdate\fR (parameter \f(CW\*(C`=update\*(C'\fR).
A new, empty form could be shown with the button \fBNew\fR (parameter \f(CW\*(C`=empty\*(C'\fR) and if
you have written data into this empty form, you can add it as a new record with the
\&\fBAdd\fR button (parameter \f(CW\*(C`=insert\*(C'\fR). Last but not least, there is a \fBDelete\fR button
(parameter \f(CW\*(C`=delete\*(C'\fR). In all of these cases, the content of the form is sent to the page
itself, and the \f(CW\*(C`Execute\*(C'\fR method at the start of the page executes the desired action.
.PP
More comments can be found inside the source ([# #] blocks).