CGI-Ex
view release on metacpan or search on metacpan
lib/CGI/Ex/App.pod view on Meta::CPAN
<tr>
<td>[% loop.count %].</td>
<td><a href="[% script_name %]/view?id=[% row.id %]">[% row.title %]</a>
(<a href="[% script_name %]/edit?id=[% row.id %]">Edit</a>)
</td>
<td>[% row.date_added %]</td>
</tr>
[% END %]
<tr><td colspan=2 align=right><a href="[% script_name %]/add">Add new recipe</a></td></tr>
</table>
</html>
File: /var/www/templates/content/recipe/edit.html
### --------------------------------------------
<html>
<head>
<title>[% step == 'add' ? "Add" : "Edit" %] Recipe</title>
</head>
<h1>[% step == 'add' ? "Add" : "Edit" %] Recipe</h1>
<form method=post name=[% form_name %]>
<input type=hidden name=step>
<table>
[% IF step != 'add' ~%]
<tr>
<td><b>Id:</b></td><td>[% id %]</td></tr>
<input type=hidden name=id>
</tr>
<tr>
<td><b>Date Added:</b></td><td>[% date_added %]</td></tr>
</tr>
[% END ~%]
<tr>
<td valign=top><b>Title:</b></td>
<td><input type=text name=title>
<span style='color:red' id=title_error>[% title_error %]</span></td>
</tr>
<tr>
<td valign=top><b>Ingredients:</b></td>
<td><textarea name=ingredients rows=10 cols=40 wrap=physical></textarea>
<span style='color:red' id=ingredients_error>[% ingredients_error %]</span></td>
</tr>
<tr>
<td valign=top><b>Directions:</b></td>
<td><textarea name=directions rows=10 cols=40 wrap=virtual></textarea>
<span style='color:red' id=directions_error>[% directions_error %]</span></td>
</tr>
<tr>
<td colspan=2 align=right>
<input type=submit value="[% step == 'add' ? 'Add' : 'Update' %]"></td>
</tr>
</table>
</form>
(<a href="[% script_name %]">Main Menu</a>)
[% IF step != 'add' ~%]
(<a href="[% script_name %]/delete?id=[% id %]">Delete this recipe</a>)
[%~ END %]
[% js_validation %]
</html>
File: /var/www/templates/content/recipe/view.html
### --------------------------------------------
<html>
<head>
<title>[% title %] - Recipe DB</title>
</head>
<h1>[% title %]</h1>
<h3>Date Added: [% date_added %]</h3>
<h2>Ingredients</h2>
[% ingredients %]
<h2>Directions</h2>
[% directions %]
<hr>
(<a href="[% script_name %]">Main Menu</a>)
(<a href="[% script_name %]/edit?id=[% id %]">Edit this recipe</a>)
</html>
### --------------------------------------------
Notes:
The dbh method returns an SQLite dbh handle and auto creates the
schema. You will normally want to use MySQL or Oracle, or Postgres
and you will want your schema to NOT be auto-created.
This sample uses hand rolled SQL. Class::DBI or a similar module
might make this example shorter. However, more complex cases that
need to involve two or three or four tables would probably be better
off using the hand crafted SQL.
This sample uses SQL. You could write the application to use whatever
storage you want - or even to do nothing with the submitted data.
We had to write our own HTML (Catalyst and Ruby on Rails do this for
you). For most development work - the HTML should be in a static
location so that it can be worked on by designers. It is nice that
the other frameworks give you stub html - but that is all it is. It
is worth about as much as copying and pasting the above examples. All
worthwhile HTML will go through a non-automated design/finalization
process.
The add step used the same template as the edit step. We did
this using the add_name_step hook which returned "edit". The template
contains IF conditions to show different information if we were in
add mode or edit mode.
We reused code, validation, and templates. Code and data reuse is a
good thing.
The edit_hash_common returns an empty hashref if the form was ready to
validate. When hash_common is called and the form is ready to
validate, that means the form failed validation and is now printing
out the page. To let us fall back and use the "sticky" form fields
that were just submitted, we need to not provide values in the
hash_common method.
We use hash_common. Values from hash_common are used for both
template swapping and filling. We could have used hash_swap and
hash_fill independently.
The hook main_info_complete is hard coded to 0. This basically says
that we will never try and validate or finalize the main step - which
is most often the case.
=head1 SEPARATING STEPS INTO SEPARATE FILES
It may be useful sometimes to separate some or all of the steps of an
application into separate files. This is the way that CGI::Prototype
works. This is useful in cases were some steps and their hooks are
overly large - or are seldom used.
The following modifications can be made to the previous "recipe db"
example that would move the "delete" step into its own file. Similar
( run in 1.402 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )