.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35) .\" .\" 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 "Petal::Cookbook 3pm" .TH Petal::Cookbook 3pm "2020-05-22" "perl v5.30.2" "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" Petal::Cookbook \- Recipes for building templates with Petal .SH "DESCRIPTION" .IX Header "DESCRIPTION" This document contains some examples of Petal template usage. Most of these examples deal with using Petal to generate \s-1HTML\s0 files from \s-1HTML\s0 templates. .SH "BASICS" .IX Header "BASICS" .SS "Template location" .IX Subsection "Template location" When using Petal for web application development, your templates should not need to be accessible by the webserver. In fact, it could be a security risk if they are available since there may be code or comments which users should not see prior to processing by Petal. Thus, it is recommended to store your templates in a non-web accessible directory. Personally I prefer to place the directory outside of the web root but you could also use permissions or \&.htaccess files to control access to the directory. This directory path should go into the \f(CW$Petal::BASE_DIR\fR global setting or the 'base_dir' argument for the \&\fBnew()\fR constructor. .SS "Template naming" .IX Subsection "Template naming" Petal is indifferent about the name of the template files. Personally, I like to name my templates with the .tmpl extension to help myself and designers distinguish templates from static html. Some \s-1GUI\s0 editors, though, will not open files without a htm/html extension (esp. under Windows). .SS "Fixing invalid templates (Is this \s-1XML\s0 well-formed?)" .IX Subsection "Fixing invalid templates (Is this XML well-formed?)" If you are getting a parse_error when trying to process your template, you will need to clean up your \s-1XHTML\s0 template in order for Petal to process it. Two tools will be of great assistance in taking the step towards better standards compliance\*(--HTML Tidy () and xmllint. In addition, you can use the page validation services at W3C (). Alternatively, you could use the Petal::Parser::HTB module which will parse non well-formed \s-1HTML\s0 documents using HTML::TreeBuilder. .PP \&\s-1HTML\s0 Tidy will rewrite your document into valid \s-1XHTML\s0 and, if requested, even replace legacy formatting tags with their \s-1CSS\s0 counterparts. You can safely ignore the warnings about proprietary attributes. Be sure to read the output of what \s-1HTML\s0 Tidy is doing or else you may find it removing important tags which it thinks are empty or invalid (e.g., inline elements outside of a block). One of the important options that should be set is output_xhtml (\-asxhtml from the command-line). Here's an example of how to use it (see the documentation for complete details): .PP .Vb 1 \& tidy \-\-asxhtml original_file.html > new_file.html .Ve .PP Once your document is well-formed, you can use xmllint to do day-to-day checking that it stays well-formed without having to wade through the warnings that \s-1HTML\s0 Tidy will generate about proprietary attributes. The following command will check that a document is well-formed: .PP .Vb 1 \& xmllint \-\-noout .Ve .PP To prevent errors about undefined namespace prefix, be sure to include these in your template like so: .PP .Vb 3 \& .Ve .PP You may receive errors from xmllint about unknown entities such as  . These can be safely ignored, though you can use the numeric version   instead to keep xmllint happy. If you find a way to suppress these warnings, please let us know. In the meantime, you can pass the output through grep to ignore these bogus warnings:. .PP .Vb 1 \& xmllint \-\-noout tmpl/contact_info.tmpl >& grep \-v \*(AqEntity\*(Aq .Ve .PP Now you have no excuse for not creating well-formed \s-1XHTML\s0 documents. .SS "Passing a hashreference to Petal::process" .IX Subsection "Passing a hashreference to Petal::process" An effective way to collate data to send to the Petal process command is via a hash reference. Used as follows, this technique allows you to build up your data to be passed to the template slowly: .PP .Vb 7 \& my $hash = { string => \*(AqThree\*(Aq, \*(Aqnumber\*(Aq => 3 }; \& $hash\->{\*(Aqfoo\*(Aq} = "bar"; \& my $template = new Petal ( \*(Aqtest.tmpl\*(Aq ); \& my $html = $template\->process($hash); \& # Output the results \& print "Content\-type: text/html\en\en"; \& print $html; .Ve .SS "Basic loops with tal:repeat" .IX Subsection "Basic loops with tal:repeat" One way to use tal:repeat is to create an a reference to an array of anonymous hashes. Here is an example: .PP .Vb 8 \& my $array_ref= [ \& { firstname=>"David", \& surname=>"Lloyd" \& }, \& { firstname=>"Susan", \& surname=>"Jones" \& } \& ]; .Ve .PP With this array you can use the tal:repeat structure. Let's say you have this template \- this is a snippet so don't forget the proper name space declarations and such: .PP .Vb 5 \& \& \& \& \& \& \& \& \& \& \&
First NameLast Name
First NameLast Name
.Ve .PP If you processed that template and the method call \*(L"list_of_names\*(R" returned an array reference as described above, you'd get: .PP .Vb 5 \& \& \& \& \& \& \& \& \& \& \& \& \& \& \& \&
First NameLast Name
DavidLloyd
SusanJones
.Ve .PP So, in a tal:repeat construct: .PP .Vb 1 \& tal:repeat="tal_variable_name EXPRESSION" .Ve .PP tal_variable_name is the name of the variable you use in your tal template to refer to each row of data you are looping through. .PP \&\s-1EXPRESSION\s0 should return an array reference, where each row is an anonymous hash, array, scalar or object. .PP You can then refer to the members of the anonymous hash like this: .PP .Vb 1 \& "$tal_variable_name/key_from_hash" .Ve .SH "INTERMEDIATE TIPS" .IX Header "INTERMEDIATE TIPS" .SS "Assigning attributes (submitted by Warren Smith)" .IX Subsection "Assigning attributes (submitted by Warren Smith)" Up until now, if I wanted to use petal to pre-select an item in a selectbox, I would have to do each item twice, like so: .PP .Vb 6 \& \& \& $VAR1 = [ \& { value => 1, label => \*(AqOption 1\*(Aq, selected => 1 }, \& { value => 2, label => \*(AqOption 2\*(Aq, selected => 0 }, \& { value => 4, label => \*(AqOption 3\*(Aq, selected => 0 }, \& ]; .Ve .PP After reading the Petal source, I found that if you use petal:attributes to assign an attribute an undefined value, the attribute gets omitted, thus the above code can be replaced with the simpler version below: .PP .Vb 3 \& \& \& $VAR1 = [ \& { value => 1, label => \*(AqOption 1\*(Aq, selected => 1 }, \& { value => 2, label => \*(AqOption 2\*(Aq }, \& { value => 4, label => \*(AqOption 3\*(Aq }, \& ]; .Ve .PP It turns out that although not documented in Petal's documentation, this behavior is part of the \s-1TAL\s0 specification: .PP .Vb 1 \& http://www.zope.org/Wikis/DevSite/Projects/ZPT/TAL .Ve .PP Thanks to Fergal Daly for his knowledge of the \s-1TAL\s0 specification. .SS "Generating even/odd rows (submitted by Warren Smith)" .IX Subsection "Generating even/odd rows (submitted by Warren Smith)" I developed a decode: modifier that works similar to Oracle's decode statement. It provides an if/then/else construct and is part of the Petal::Utils collection of modifiers. Using decode, it is possible to make even/odd rows of a table different classes, which allows you to do things like alter color, font-size, etc, is relatively easy. .PP Example: .PP .Vb 6 \& \& \& \& ... \& \&
Employee Name
.Ve .PP See Petal::Utils for more information. .PP Alternatively, this can be done entirely with \s-1TAL\s0 (contributed by Jonathan Vanasco): .PP .Vb 10 \&
\& \& \&
\& This will use either the rowEven or rowOdd class. All of the \*(Aqtag\*(Aq \& elements are omitted on render. This uses a nested define tag in a \& condition tag, because define precedes condition in order of operations. \&
\&
.Ve .PP The simplest way to do odd/even rows may to duplicate the code entirely for each type or row, though this may cause maintenance headaches: .PP .Vb 7 \& \& \& \& \& ... \& \&
Employee NameEmployee Name
.Ve .SH "ADVANCED" .IX Header "ADVANCED" .SS "Invoking methods on objects" .IX Subsection "Invoking methods on objects" Petal supports the ability to call an object's methods if passed in to Petal::process via the \f(CW%hash\fR. Say you wish to check whether a particular record is contained in a recordset returned from an \s-1SQL\s0 query. Using OO-Perl techniques, you could use the following technique as described by Jean-Michel: .IP "\(bu" 4 all your records are hashrefs which come from some database .IP "\(bu" 4 you have a list of them to display .PP Let's say that the database table looks like this: .PP Raters (id, first_name, last_name, relation, phone, email) .PP You could bless each record into a package as is: .PP .Vb 4 \& use MyApplication::Record::Rater; \& my @records = complicated_query_somewhere_else(); \& bless $_, "MyApplication::Record::Rater" for (@records); \& $hash\->{\*(Aqrecords\*(Aq} = \e@records; .Ve .PP Your module could look like that: .PP .Vb 5 \& package MyApplication::Record::Rater; \& use strict; \& use warnings; \& use CGI; \& use Carp; \& \& sub is_current_id \& { \& my $self = shift; \& my $cgi = CGI\->new; \& my $id = $cgi\->param (\*(Aqrater.id\*(Aq); \& return unless (defined $id and $id and $id =~ /^\ed+$/); \& return $id == $self\->{id}; \& } \& \& 1; .Ve .PP Then on top of your existing data, you have a method which you can call from Petal, i.e. .PP .Vb 3 \&
    \&
  • Current id
  • \&
.Ve .PP This trick can also be used when you have foreign keys in database fields. .PP .PP For example, let's imagine that you have a column called 'friend_id'. It references another 'rater' which is supposed to be a friend of that person. .PP You could define the following subroutine: .PP .Vb 10 \& # give me the friend record for that person \& sub friend \& { \& my $self = shift; \& my $friend_id = $self\->{friend_id}; \& my $sql = \*(Aqselect * from rater where id = ?\*(Aq; \& my $sth = $::DBH_CONNECTION\->prepare_cached ($sql); \& $sth\->execute ($friend_id); \& my $hash = $sth\->fetchrow_hashref; \& return unless (defined $hash); \& \& bless $hash, "MyApplication::Record::Rater"; \& return $hash; \& } .Ve .PP Then in your template, you could do: .PP .Vb 3 \&
\& Your friend is: First Last \&
.Ve .PP
.PP Thanks to Jean-Michel Hiver for this tip. .PP If you are doing a lot of database manipulation via Petal, you probably should consider an object-relational mapping library . Personally, I recommend Class::DBI. There is a list of many of these tools at Perl Object Oriented Persistence (). .SS "Using \s-1CGI\s0.pm to build forms" .IX Subsection "Using CGI.pm to build forms" Calling the \s-1HTML\s0 generating methods of \s-1CGI\s0.pm from the Petal template provides an extremely simple means to develop forms. For example, the ususal ratnest of loops used to populate a checkbox group can be replaced by the simple and elegant construct below. You can put in a dummy checkbox to give the \s-1HTML\s0 designer something to look at. Be sure to call \s-1CGI\s0 with the \-compile option as follows: .PP .Vb 3 \& use CGI qw(\-compile [:all]); \& $hash\->{\*(Aqquery\*(Aq} = new CGI; \& $hash\->{\*(Aqchoices\*(Aq} = [1, 2, 3, 4]; \& \& \& Test \& .Ve .PP Thanks to Kurt Stephens for this tip. .SH "COPYRIGHT" .IX Header "COPYRIGHT" This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. .PP All code examples in these files are hereby placed into the public domain. You are permitted and encouraged to use this code in your own programs for fun or for profit as you see fit. A simple comment in the code giving credit would be courteous but is not required. .SH "AUTHOR" .IX Header "AUTHOR" William McKee . .PP Thanks to the following contributors: Jean-Michel Hiver, Kurt Stephens, Warren Smith, Fergal Daly. .SH "SEE ALSO" .IX Header "SEE ALSO" Petal, Petal::Utils, the test file t/084_Cookbook.t and the test template t/data/cookbook.html.