1Maypole::Manual::StandaUrsdeTremCpolnattreisb(u3t)ed PerMlayDpoocluem:e:nMtaantuiaoln::StandardTemplates(3)
2
3
4

NAME

6       Maypole::Manual::StandardTemplates - Maypole's Standard Templates and
7       Actions
8

DESCRIPTION

10       As we saw in our Create-Read-Update-Delete (CRUD) example, Maypole does
11       all it can to make your life easier; this inclues providing a set of
12       default actions and factory-supplied templates. These are written in
13       such a generic way, making extensive use of class metadata, that they
14       are more or less applicable to any table or application. However, in
15       order to progress from automatically generated CRUD applications to
16       real customized applications, we need to begin by understanding how
17       these default actions do their stuff, and how the default templates are
18       put together.  Once we have an understanding of what Maypole does for
19       us automatically, we can begin to customize and create our own
20       templates and actions.
21
22       Although the standard templates can be applied in many situations,
23       they're really provided just as examples, as a starting point to create
24       your own templates to suit your needs.  The goal of templating is to
25       keep templates simple so the presentation can be changed easily when
26       you desire.  We're not trying to build a single set of reusable
27       templates that cover every possible situation.
28
29   The standard actions
30       Remember that actions are just subroutines in the model classes with an
31       Exported attribute.  A simple, uncustomized Maypole model class, such
32       as one of the classes in the beer database application, provides the
33       following default actions - that is, provides access to the following
34       URLs:
35
36       "/[table]/view/[id]"
37          This takes the ID of an object in a table, retrieves the object, and
38          presents it to the view template.
39
40       "/[table]/edit/[id]"
41          This is the same as "view", but uses the edit template to provide a
42          web form to edit the object; it submits to "do_edit".
43
44       "/[table]/do_edit/[id]"
45          When called with an ID, the "do_edit" action provides row editing.
46
47       "/[table]/do_edit/"
48          When called without an ID, the "do_edit" action provides row
49          creation.
50
51       "/[table]/delete/id"
52          This deletes a row, returning to the "list" page.
53
54       "/[table]/list/"
55          This provides a paged list of the table suitable for browsing.
56
57       "/[table]/do_search/"
58          This handles a search query and presents the search results back to
59          the list template. Previously this was called search, but obviously
60          that clashes with a lot of stuff, and that usage is now deprecated.
61
62       We'll now look at how these actions are implemented, before moving on
63       to take a detailed look at the templates they drive.
64
65       "view" and "edit"
66
67       These actions are very simple; their job is to take a row ID, turn it
68       into an object, and hand it to the template to be displayed. However,
69       as taking the first argument and turning it into an object is such a
70       common action, it is handled directly by the model class's "process"
71       method.  Similarly, the default template name provided by the "process"
72       method is the name of the action, and so will be "view" or "edit"
73       accordingly.
74
75       So the code required to make these two actions work turns out to be:
76
77           sub view :Exported { }
78           sub edit :Exported { }
79
80       That's right - no code at all. This shows the power of the templating
81       side of the system. If you think about it for a moment, it is natural
82       that these actions should not have any code - after all, we have
83       separated out the concerns of "acting" and displaying. Both of these
84       "actions" are purely concerned with displaying a record, and don't need
85       to do any "acting". Remember that the "edit" method doesn't actually do
86       any editing - this is provided by "do_edit"; it is just another view of
87       the data, albeit one which allows the data to be modified later. These
88       two methods don't need to modify the row in any way, they don't need to
89       do anything clever. They just are.
90
91       So why do we need the subroutines at all? If the subroutines did not
92       exist, we would be sent to the "view" and "edit" templates as would be
93       expected, but these templates would not be provided with the right
94       arguments; we need to go through the "process" method in order to turn
95       the URL argument into a row and thence into an object to be fed to the
96       template. By exporting these methods, even though they contain no code
97       themselves, we force Maypole to call "process" and provide the class
98       and object to the templates.
99
100       The moral of this story is that if you need to have an action which is
101       purely concerned with display, not acting, but needs to receive an ID
102       and turn it into an object, then create an empty method. For instance,
103       if we want to make an alternate view of a row which only showed the
104       important columns, we might create a method
105
106           sub short_view :Exported {}
107
108       This will cause the row to be turned into an object and fed to the
109       "short_view" template, and that template would be responsible for
110       selecting the particular columns to be displayed.
111
112       "do_edit"
113
114       This action, on the other hand, actually has to do something. If it's
115       provided with an ID, this is turned into an object and we're in edit
116       mode, acting upon that object. If not, we're in create mode.
117
118           sub do_edit :Exported {
119               my ($self, $r) = @_;
120               my $h = CGI::Untaint->new(%{$r->params});
121               my ($obj) = @{$r->objects || []};
122               if ($obj) {
123                   # We have something to edit
124                   $obj->update_from_cgi($h);
125               } else {
126                   $obj = $self->create_from_cgi($h);
127               }
128
129       The "CDBI" model uses the "update_from_cgi" and "create_from_cgi"
130       methods of Class::DBI::FromCGI to turn "POST" parameters into database
131       table data. This in turn uses CGI::Untaint to ensure that the data
132       coming in is suitable for the table. If you're using the default "CDBI"
133       model, then, you're going to need to set up your tables in a way that
134       makes "FromCGI" happy.
135
136       The data is untainted, and any errors are collected into a hash which
137       is passed to the template. We also pass back in the parameters, so that
138       the template can re-fill the form fields with the original values. The
139       user is then sent back to the "edit" template.
140
141               if (my %errors = $obj->cgi_update_errors) {
142                   # Set it up as it was:
143                   $r->template_args->{cgi_params} = $r->params;
144                   $r->template_args->{errors} = \%errors;
145                   $r->template("edit");
146               }
147
148       Otherwise, the user is taken back to viewing the new object:
149
150           } else {
151               $r->template("view");
152           }
153           $r->objects([ $obj ]);
154
155       Notice that this does use hard-coded names for the templates to go to
156       next.  Feel free to override this in your subclasses:
157
158           sub do_edit :Exported {
159               my ($class, $r) = @_;
160               $class->SUPER::do_edit($r);
161               $r->template("my_edit");
162           }
163
164       Digression on "Class::DBI::FromCGI"
165
166       "CGI::Untaint" is a mechanism for testing that incoming form data
167       conforms to various properties. For instance, given a "CGI::Untaint"
168       object that encapsulates some "POST" parameters, we can extract an
169       integer like so:
170
171           $h->extract(-as_integer => "score");
172
173       This checks that the "score" parameter is an integer, and returns it if
174       it is; if not, "$h->error" will be set to an appropriate error message.
175       Other tests by which you can extract your data are "as_hex" and
176       "as_printable", which tests for a valid hex number and an ordinary
177       printable string respectively; there are other handlers available on
178       CPAN, and you can make your own, as documented in CGI::Untaint.
179
180       To tell the "FromCGI" handler what handler to use for each of your
181       columns, you need to use the "untaint_columns" methods in the classes
182       representing your tables. For instance:
183
184           BeerDB::Beer->untaint_columns(
185               integer => ["score", ... ],
186           );
187
188       This must be done after the call to "setup" in your handler, because
189       otherwise the model classes won't have been set up to inherit from
190       "Class::DBI::FromCGI".
191
192       Remember that if you want to use drop-downs to set the value of related
193       fields, such as the brewery for a beer, you need to untaint these as
194       something acceptable for the primary key of that table:
195
196           BeerDB::Beer->untaint_columns(
197               integer => ["score", "brewery", "style" ],
198               ...
199           );
200
201       This is usually integer, if you're using numeric IDs for your primary
202       key. If not, you probably want "printable", but you probably know what
203       you're doing anyway.
204
205       do_delete
206
207       The do_delete method takes a number of arguments and deletes those rows
208       from the database; it then loads up all rows and heads to the list
209       template.  You almost certainly want to override this to provide some
210       kind of authentication.
211
212       Previously this was called delete, but obviously that clashes with a
213       lot of stuff, and that usage is now deprecated.
214
215       list
216
217       Listing, like viewing, is a matter of selecting objects for
218       presentation. This time, instead of a single object specified in the
219       URL, we want, by default, all the records in the table:
220
221           sub list :Exported {
222               my ($class, $r) = @_;
223               $r->objects([ $self->retrieve_all ])
224           }
225
226       However, things are slightly complicated by paging and ordering by
227       column; the default implementation also provides a "Class::DBI::Pager"
228       object to the templates and uses that to retrieve the appropriate bit
229       of the data, as specified by the "page" URL query parameter. See the
230       "pager" template below.
231
232       search
233
234       Searching also uses paging, and creates a query from the "POST"
235       parameters. It uses the list template to display the objects once
236       they've been selected from the database.
237
238   The templates and macros
239       Once these actions have done their work, they hand a set of objects to
240       the templates; if you haven't specified your own custom template
241       globally or for a given class, you'll be using the factory specified
242       template. Let's take a look now at each of these and how they're put
243       together.
244
245       The beauty of the factory specified templates is that they make use of
246       the classes' metadata as supplied by the view class. Although you're
247       strongly encouraged to write your own templates, in which you don't
248       need to necessarily be as generic, the factory templates will always do
249       the right thing for any class without further modification, and as such
250       are useful examples of how to build Maypole templates.
251
252       Commonalities
253
254       There are certain common elements to a template, and these are
255       extracted out. For instance, all the templates call the header template
256       to output a HTML header, and nearly all include the macros template to
257       load up some common template functions. We'll look at these common
258       macros as we come across them.
259
260       view
261
262       template view
263
264       edit
265
266       The edit template is pretty much the same as view, but it uses
267       Maypole::Model::CDBI::AsForm's "to_field" method on each column of an
268       object to return a "HTML::Element" object representing a form element
269       to edit that property. These elements are then rendered to HTML with
270       "as_HTML" or to XHTML with "as_XML".  It expects to see a list of
271       editing errors, if any, in the "errors" template variable:
272
273            FOR col = classmetadata.columns;
274               NEXT IF col == "id";
275               "<P>";
276               "<B>"; classmetadata.colnames.$col; "</B>";
277               ": ";
278                   item.to_field(col).as_HTML;
279               "</P>";
280               IF errors.$col;
281                   "<FONT COLOR=\"#ff0000\">"; errors.$col; "</FONT>";
282               END;
283           END;
284
285       list
286
287       Browsing records and search results are both handled by the list
288       template.  The "search" template argument is used to distinguish
289       between the two cases:
290
291           [% IF search %]
292           <h2> Search results </h2>
293           [% ELSE %]
294           <h2> Listing of all [% classmetadata.plural %]</h2>
295           [% END %]
296
297       pager
298
299       The pager template controls the list of pages at the bottom (by
300       default) of the list and search views. It expects a "pager" template
301       argument which responds to the Data::Page interface.  There's a
302       description of how it works in the Template Toolkit section of the View
303       chapter.
304
305       macros
306
307       The macros template is included at the start of most other templates
308       and makes some generally-useful template macros available:
309
310       "link(table, command, additional, label)"
311           This makes an HTML link pointing to
312           "/base/table/command/additional" labelled by the text in label.
313           "base" is the template variable that contains the base URL of this
314           application.
315
316       "maybe_link_view(object)"
317           "maybe_link_view" takes something returned from the database -
318           either some ordinary data, or an object in a related class expanded
319           by a has-a relationship. If it is an object, it constructs a link
320           to the view command for that object. Otherwise, it just displays
321           the data.
322
323       "display_line(object)"
324           "display_line" is used in the list template to display a row from
325           the database, by iterating over the columns and displaying the data
326           for each column. It misses out the "id" column by default, and
327           magically URLifies columns called "url". This may be considered too
328           much magic for some.
329
330       "button(object, action)"
331           This is a simple button that is submitted to
332           "/base/table/action/id", where "table" and "id" are those belonging
333           to the database row "object".  The button is labelled with the name
334           of the action.  You can see buttons on many pages, including lists.
335
336       "view_related(object)"
337           This takes an object, and looks up its "related_accessors"; this
338           gives a list of accessor methods that can be called to get a list
339           of related objects. It then displays a title for that accessor,
340           (e.g. "Beers" for a "brewery.beers") calls the accessor, and
341           displays a list of the results.  You can see it in use at the
342           bottom of the standard view pages.
343
344   Links
345       Contents, Next The Request Workflow, Previous Maypole View Classes,
346
347
348
349perl v5.34.0                      2022-01-M2a1ypole::Manual::StandardTemplates(3)
Impressum