Perl Beginners - Addressbook Tutorial Step 5 - Adding the start method and our first HTML::Template file

Table of Contents | Step 4 | Step 6

In Step 4, we created the unrestricted Perl handler. The handler is the class called by the cgi to handle requests. In this step, we'll add a method to the handler to load the default search form.

What should this method do? We decided to search on several fields in different tables. Theoretically, we could provide regular text form inputs and have the user type in their search criteria. Or, we could provide <select> pull-downs to ease the search request. We may want to provide a pull-down with all the person names in it. But, if the database has thousands of names, this may be too tedious. What about a pull-down with all the city names? Again, there may be hundreds of different cites, so this could be tedious. How about a pull-down with all the area codes? That may not be so bad. And another one with the state names? Well, the most it could have would be 50 (52 if you count Puerto Rico and Washington D.C., I guess), so that doesn't seem too bad either.

So we'll need the start method to do the following:

  • select all the distinct area codes;
  • select all the distinct state abbreviations;
  • put the area code and state values into the handler's HTML::Template parameter hash; and
  • declare which template file the output will be sent to.
  • Before we write the method, let's go over how HTML::Template works. In a nutshell:

    
      use HTML::Template;
      my $template = HTML::Template->new(filename => 'somefile.tmpl');
      my @values = (
        {
          LAST_NAME => 'Osbourne',
          FIRST_NAME => 'Ozzy',
          BAND_NAME => 'Black Sabbath',
          OCCUPATION => 'Vocals'
        },
        {
          LAST_NAME => 'Gilmour',
          FIRST_NAME => 'David',
          BAND_NAME => 'Pink Floyd',
          OCCUPATION => 'Lead guitar and vocals'
        },
        {
          LAST_NAME => 'Hendrix',
          FIRST_NAME => 'Jimi',
          BAND_NAME => 'The Jimi Hendrix Experience',
          OCCUPATION => 'Daisy pusher'
        }
      );
      my %parameters = (
        GENRE => 'Rock and Roll',
        PEOPLE => \@values
      );
      $template->param(%parameters);
      print "Content-type:  text/html\n\n";
      print $template->output;
      

    After the use declaration, we construct a reference to a new HTML::Template object, passing in the name of the template file (somefile.tmpl) we'll use. We then set up an array of hash references. Each hash ref contains the last name, first name, band name, and occupation of each person. Then, we set up a parameter hash that contains the dynamic data to be displayed in the template. In the parameter hash, we have a scalar value (GENRE), and a reference to an array (PEOPLE).

    Here is what a corresponding template (somefile.tmpl) file may look like:

    
      <html>
      <head>
      <title><TMPL_VAR ESCAPE=HTML NAME=GENRE></title>
      </head>
      <body>
      <table>
      <tr>
      <th>Last Name</th>
      <th>First Name</th>
      <th>Band Name</th>
      <th>Occupation</th>
      </tr>
    
      <TMPL_LOOP NAME=PEOPLE>
      <tr>
      <td><TMPL_VAR ESCAPE=HTML NAME=LAST_NAME></td>
      <td><TMPL_VAR ESCAPE=HTML NAME=FIRST_NAME></td>
      <td><TMPL_VAR ESCAPE=HTML NAME=BAND_NAME></td>
      <td><TMPL_VAR ESCAPE=HTML NAME=OCCUPATION></td>
      </tr>
      </TMPL_LOOP>
    
      </table>
      </body>
      </html>
      

    Notice the scalar value in the parameter hash (GENRE) is named directly, but the array reference (PEOPLE) is named inside a <TMPL_LOOP>. <TMPL_LOOP> repeats whatever is between it and the closing </TMPL_LOOP> for each reference in the array, filling each <TMPL_VAR> with the values in each hash reference.

    It's a good idea to always use either the ESCAPE=HTML or ESCAPE=URL attribute in any <TMPL_VAR> tag. For example, assume we have a form input box where we pre-fill it with a length value:

    
      <input type="text" name="length" value="<TMPL_VAR ESCAPE=HTML NAME=LENGTH>">
      

    Assume the length value is 90". Therefore, the final HTML will look like this:

    
      <input type="text" name="length" value="90&quot;">
      

    Without the ESCAPE=HTML, the final HTML would look like this:

    
      <input type="text" name="length" value="90"">
      

    And it's unlikely any browser the HTML is displayed in will be able to grok that. Simply put, the ESCAPE=HTML attribute changes any occurrence of &, ", >, and < to &amp;, &quot;, &gt;, and &lt;, respectively. Similarly, the ESCAPE=URL will change ' ' and '/' to '+' and '%2F'.

    So the final HTML output for our example will look like this:

    
      <html>
      <head>
      <title>Rock and Roll</title>
      </head>
      <body>
      <table>
      <tr>
      <th>Last Name</th>
      <th>First Name</th>
      <th>Band Name</th>
      <th>Occupation</th>
      </tr>
    
      <tr>
      <td>Osbourne</td>
      <td>Ozzy</td>
      <td>Black Sabbath</td>
      <td>Vocals</td>
      </tr>
      <tr>
      <td>Gilmour</td>
      <td>David</td>
      <td>Pink Floyd</td>
      <td>Lead guitar and vocals</td>
      </tr>
      <tr>
      <td>Hendrix</td>
      <td>Jimi</td>
      <td>The Jimi Hendrix Experience</td>
      <td>Daisy pusher</td>
      </tr>
    
      </table>
      </body>
      </html>
      

    So let's write the start method, which we'll add to Handler.pm:

    
      use PEACE::AddressBook::Record;
    
      sub start {
        my ($self) = @_;
    
        my $record = PEACE::AddressBook::Record->new($self->_db);
        $self->{_TEMPLATE} = {
          AREA_CODES => $record->select_distinct_area_codes(),
          STATES => $record->select_distinct_states()
        };
        $self->{_TFILE} = 'search_form.tmpl';
        return;
      }
      

    First, we use our utility class Record.pm (which we have not written yet). Inside the start method we shift in the $self reference. Then, we construct an object reference to the utility class. We put the AREA_CODES and STATES values into the template parameter hash and set the output file.

    The corresponding template file (search_form.tmpl) will look something like this:

    
      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
      <html>
      <head>
      <title>Addressbook Search Form</title>
      <meta name="author" content="fliptop@peacecomputers.com">
      <meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
      </head>
    
      <body bgcolor="#FFFFFF" link="#0000FF" alink="#FF0000" vlink="#C000FF">
      <!--end header-->
    
      <table>
    
      <form method="post" action="/cgi-bin/handler.cgi">
    
      <tr>
      <td align="right">Last Name:</td>
      <td align="left"><input type="text" name="last_name" size="15" maxlength="50"></td>
      <td align="right">First Name:</td>
      <td align="left"><input type="text" name="first_name" size="15" maxlength="50"></td>
      </tr>
    
      <tr>
      <td align="right">Prefix:</td>
      <td align="left"><input type="text" name="prefix" size="15" maxlength="50"></td>
      <td align="right">City:</td>
      <td align="left"><input type="text" name="city" size="15" maxlength="50"></td>
      </tr>
    
      <tr>
      <td align="right">Area Code:</td>
      <td align="left">
        <select name="area_code">
        <option value="">Any</option>
        <TMPL_LOOP NAME=AREA_CODES>
          <option value="<TMPL_VAR ESCAPE=HTML NAME=AREA_CODE>"><TMPL_VAR ESCAPE=HTML NAME=AREA_CODE></option>
        </TMPL_LOOP>
        </select>
      </td>
      <td align="right">State:</td>
      <td align="left">
        <select name="state">
        <option value="">Any</option>
        <TMPL_LOOP NAME=STATES>
          <option value="<TMPL_VAR ESCAPE=HTML NAME=STATE>"><TMPL_VAR ESCAPE=HTML NAME=STATE></option>
        </TMPL_LOOP>
        </select>
      </td>
      </tr>
    
      <tr>
      <td colspan="2" align="center">
        <input type="submit" value="Search">
      </td>
      <td colspan="2" align="left">
        Enter your search criteria and click <i>Search</i>.
      </td>
      </tr>
      </table>
    
      <input type="hidden" name="action" value="search">
      </form>
    
      <!--begin footer-->
      </body>
      </html>
      

    Notice we're declaring in a hidden form value called action. When this form is submitted, it'll call the search method to process the form, search for matching records, and display the results (we'll write this method later).

    So what about the utility class, Record.pm? This class will provide the select_distinct_area_codes and select_distinct_states methods to Handler.pm. What will this utility class need to function? It will need:

  • a declaration to use the SQL class (which we have not written yet);
  • a handle to the database; and
  • methods that query the database and return any results.
  • We'll write these two classes in the next step.

    Coming next - Writing the utility and SQL classes, and using Class::MethodMaker.


    Copyright © 2001 by Peace Computer Systems