Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
Maypole::Manual::StandUsereContributed PeMaypole::Manual::StandardTemplates(3)

NAME
       Maypole::Manual::StandardTemplates - Maypole's Standard Templates and
       Actions

DESCRIPTION
       As we saw in our	Create-Read-Update-Delete (CRUD) example, Maypole does
       all it can to make your life easier; this inclues providing a set of
       default actions and factory-supplied templates. These are written in
       such a generic way, making extensive use	of class metadata, that	they
       are more	or less	applicable to any table	or application.	However, in
       order to	progress from automatically generated CRUD applications	to
       real customized applications, we	need to	begin by understanding how
       these default actions do	their stuff, and how the default templates are
       put together.  Once we have an understanding of what Maypole does for
       us automatically, we can	begin to customize and create our own
       templates and actions.

       Although	the standard templates can be applied in many situations,
       they're really provided just as examples, as a starting point to	create
       your own	templates to suit your needs.  The goal	of templating is to
       keep templates simple so	the presentation can be	changed	easily when
       you desire.  We're not trying to	build a	single set of reusable
       templates that cover every possible situation.

   The standard	actions
       Remember	that actions are just subroutines in the model classes with an
       Exported	attribute.  A simple, uncustomized Maypole model class,	such
       as one of the classes in	the beer database application, provides	the
       following default actions - that	is, provides access to the following
       URLs:

       "/[table]/view/[id]"
	  This takes the ID of an object in a table, retrieves the object, and
	  presents it to the view template.

       "/[table]/edit/[id]"
	  This is the same as "view", but uses the edit	template to provide a
	  web form to edit the object; it submits to "do_edit".

       "/[table]/do_edit/[id]"
	  When called with an ID, the "do_edit"	action provides	row editing.

       "/[table]/do_edit/"
	  When called without an ID, the "do_edit" action provides row
	  creation.

       "/[table]/delete/id"
	  This deletes a row, returning	to the "list" page.

       "/[table]/list/"
	  This provides	a paged	list of	the table suitable for browsing.

       "/[table]/do_search/"
	  This handles a search	query and presents the search results back to
	  the list template. Previously	this was called	search,	but obviously
	  that clashes with a lot of stuff, and	that usage is now deprecated.

       We'll now look at how these actions are implemented, before moving on
       to take a detailed look at the templates	they drive.

       "view" and "edit"

       These actions are very simple; their job	is to take a row ID, turn it
       into an object, and hand	it to the template to be displayed. However,
       as taking the first argument and	turning	it into	an object is such a
       common action, it is handled directly by	the model class's "process"
       method.	Similarly, the default template	name provided by the "process"
       method is the name of the action, and so	will be	"view" or "edit"
       accordingly.

       So the code required to make these two actions work turns out to	be:

	   sub view :Exported {	}
	   sub edit :Exported {	}

       That's right - no code at all. This shows the power of the templating
       side of the system. If you think	about it for a moment, it is natural
       that these actions should not have any code - after all,	we have
       separated out the concerns of "acting" and displaying. Both of these
       "actions" are purely concerned with displaying a	record,	and don't need
       to do any "acting". Remember that the "edit" method doesn't actually do
       any editing - this is provided by "do_edit"; it is just another view of
       the data, albeit	one which allows the data to be	modified later.	These
       two methods don't need to modify	the row	in any way, they don't need to
       do anything clever. They	just are.

       So why do we need the subroutines at all? If the	subroutines did	not
       exist, we would be sent to the "view" and "edit"	templates as would be
       expected, but these templates would not be provided with	the right
       arguments; we need to go	through	the "process" method in	order to turn
       the URL argument	into a row and thence into an object to	be fed to the
       template. By exporting these methods, even though they contain no code
       themselves, we force Maypole to call "process" and provide the class
       and object to the templates.

       The moral of this story is that if you need to have an action which is
       purely concerned	with display, not acting, but needs to receive an ID
       and turn	it into	an object, then	create an empty	method.	For instance,
       if we want to make an alternate view of a row which only	showed the
       important columns, we might create a method

	   sub short_view :Exported {}

       This will cause the row to be turned into an object and fed to the
       "short_view" template, and that template	would be responsible for
       selecting the particular	columns	to be displayed.

       "do_edit"

       This action, on the other hand, actually	has to do something. If	it's
       provided	with an	ID, this is turned into	an object and we're in edit
       mode, acting upon that object. If not, we're in create mode.

	   sub do_edit :Exported {
	       my ($self, $r) =	@_;
	       my $h = CGI::Untaint->new(%{$r->params});
	       my ($obj) = @{$r->objects || []};
	       if ($obj) {
		   # We	have something to edit
		   $obj->update_from_cgi($h);
	       } else {
		   $obj	= $self->create_from_cgi($h);
	       }

       The "CDBI" model	uses the "update_from_cgi" and "create_from_cgi"
       methods of Class::DBI::FromCGI to turn "POST" parameters	into database
       table data. This	in turn	uses CGI::Untaint to ensure that the data
       coming in is suitable for the table. If you're using the	default	"CDBI"
       model, then, you're going to need to set	up your	tables in a way	that
       makes "FromCGI" happy.

       The data	is untainted, and any errors are collected into	a hash which
       is passed to the	template. We also pass back in the parameters, so that
       the template can	re-fill	the form fields	with the original values. The
       user is then sent back to the "edit" template.

	       if (my %errors =	$obj->cgi_update_errors) {
		   # Set it up as it was:
		   $r->template_args->{cgi_params} = $r->params;
		   $r->template_args->{errors} = \%errors;
		   $r->template("edit");
	       }

       Otherwise, the user is taken back to viewing the	new object:

	   } else {
	       $r->template("view");
	   }
	   $r->objects([ $obj ]);

       Notice that this	does use hard-coded names for the templates to go to
       next.  Feel free	to override this in your subclasses:

	   sub do_edit :Exported {
	       my ($class, $r) = @_;
	       $class->SUPER::do_edit($r);
	       $r->template("my_edit");
	   }

       Digression on "Class::DBI::FromCGI"

       "CGI::Untaint" is a mechanism for testing that incoming form data
       conforms	to various properties. For instance, given a "CGI::Untaint"
       object that encapsulates	some "POST" parameters,	we can extract an
       integer like so:

	   $h->extract(-as_integer => "score");

       This checks that	the "score" parameter is an integer, and returns it if
       it is; if not, "$h->error" will be set to an appropriate	error message.
       Other tests by which you	can extract your data are "as_hex" and
       "as_printable", which tests for a valid hex number and an ordinary
       printable string	respectively; there are	other handlers available on
       CPAN, and you can make your own,	as documented in CGI::Untaint.

       To tell the "FromCGI" handler what handler to use for each of your
       columns,	you need to use	the "untaint_columns" methods in the classes
       representing your tables. For instance:

	   BeerDB::Beer->untaint_columns(
	       integer => ["score", ...	],
	   );

       This must be done after the call	to "setup" in your handler, because
       otherwise the model classes won't have been set up to inherit from
       "Class::DBI::FromCGI".

       Remember	that if	you want to use	drop-downs to set the value of related
       fields, such as the brewery for a beer, you need	to untaint these as
       something acceptable for	the primary key	of that	table:

	   BeerDB::Beer->untaint_columns(
	       integer => ["score", "brewery", "style" ],
	       ...
	   );

       This is usually integer,	if you're using	numeric	IDs for	your primary
       key. If not, you	probably want "printable", but you probably know what
       you're doing anyway.

       do_delete

       The do_delete method takes a number of arguments	and deletes those rows
       from the	database; it then loads	up all rows and	heads to the list
       template.  You almost certainly want to override	this to	provide	some
       kind of authentication.

       Previously this was called delete, but obviously	that clashes with a
       lot of stuff, and that usage is now deprecated.

       list

       Listing,	like viewing, is a matter of selecting objects for
       presentation. This time,	instead	of a single object specified in	the
       URL, we want, by	default, all the records in the	table:

	   sub list :Exported {
	       my ($class, $r) = @_;
	       $r->objects([ $self->retrieve_all ])
	   }

       However,	things are slightly complicated	by paging and ordering by
       column; the default implementation also provides	a "Class::DBI::Pager"
       object to the templates and uses	that to	retrieve the appropriate bit
       of the data, as specified by the	"page" URL query parameter. See	the
       "pager" template	below.

       search

       Searching also uses paging, and creates a query from the	"POST"
       parameters. It uses the list template to	display	the objects once
       they've been selected from the database.

   The templates and macros
       Once these actions have done their work,	they hand a set	of objects to
       the templates; if you haven't specified your own	custom template
       globally	or for a given class, you'll be	using the factory specified
       template. Let's take a look now at each of these	and how	they're	put
       together.

       The beauty of the factory specified templates is	that they make use of
       the classes' metadata as	supplied by the	view class. Although you're
       strongly	encouraged to write your own templates,	in which you don't
       need to necessarily be as generic, the factory templates	will always do
       the right thing for any class without further modification, and as such
       are useful examples of how to build Maypole templates.

       Commonalities

       There are certain common	elements to a template,	and these are
       extracted out. For instance, all	the templates call the header template
       to output a HTML	header,	and nearly all include the macros template to
       load up some common template functions. We'll look at these common
       macros as we come across	them.

       view

       template	view

       edit

       The edit	template is pretty much	the same as view, but it uses
       Maypole::Model::CDBI::AsForm's "to_field" method	on each	column of an
       object to return	a "HTML::Element" object representing a	form element
       to edit that property. These elements are then rendered to HTML with
       "as_HTML" or to XHTML with "as_XML".  It	expects	to see a list of
       editing errors, if any, in the "errors" template	variable:

	    FOR	col = classmetadata.columns;
	       NEXT IF col == "id";
	       "<P>";
	       "<B>"; classmetadata.colnames.$col; "</B>";
	       ": ";
		   item.to_field(col).as_HTML;
	       "</P>";
	       IF errors.$col;
		   "<FONT COLOR=\"#ff0000\">"; errors.$col; "</FONT>";
	       END;
	   END;

       list

       Browsing	records	and search results are both handled by the list
       template.  The "search" template	argument is used to distinguish
       between the two cases:

	   [% IF search	%]
	   <h2>	Search results </h2>
	   [% ELSE %]
	   <h2>	Listing	of all [% classmetadata.plural %]</h2>
	   [% END %]

       pager

       The pager template controls the list of pages at	the bottom (by
       default)	of the list and	search views. It expects a "pager" template
       argument	which responds to the Data::Page interface.  There's a
       description of how it works in the Template Toolkit section of the View
       chapter.

       macros

       The macros template is included at the start of most other templates
       and makes some generally-useful template	macros available:

       "link(table, command, additional, label)"
	   This	makes an HTML link pointing to
	   "/base/table/command/additional" labelled by	the text in label.
	   "base" is the template variable that	contains the base URL of this
	   application.

       "maybe_link_view(object)"
	   "maybe_link_view" takes something returned from the database	-
	   either some ordinary	data, or an object in a	related	class expanded
	   by a	has-a relationship. If it is an	object,	it constructs a	link
	   to the view command for that	object.	Otherwise, it just displays
	   the data.

       "display_line(object)"
	   "display_line" is used in the list template to display a row	from
	   the database, by iterating over the columns and displaying the data
	   for each column. It misses out the "id" column by default, and
	   magically URLifies columns called "url". This may be	considered too
	   much	magic for some.

       "button(object, action)"
	   This	is a simple button that	is submitted to
	   "/base/table/action/id", where "table" and "id" are those belonging
	   to the database row "object".  The button is	labelled with the name
	   of the action.  You can see buttons on many pages, including	lists.

       "view_related(object)"
	   This	takes an object, and looks up its "related_accessors"; this
	   gives a list	of accessor methods that can be	called to get a	list
	   of related objects. It then displays	a title	for that accessor,
	   (e.g. "Beers" for a "brewery.beers")	calls the accessor, and
	   displays a list of the results.  You	can see	it in use at the
	   bottom of the standard view pages.

   Links
       Contents, Next The Request Workflow, Previous Maypole View Classes,

perl v5.32.1			  2006-10Maypole::Manual::StandardTemplates(3)

NAME | DESCRIPTION

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=Maypole::Manual::StandardTemplates&sektion=3&manpath=FreeBSD+13.0-RELEASE+and+Ports>

home | help