add files
|
1 | |
2 |
=encoding utf8 |
|
3 | ||
4 |
=head1 NAME |
|
5 | ||
6 |
Mojolicious::Guides::Rendering - Rendering |
|
7 | ||
8 |
=head1 OVERVIEW |
|
9 | ||
10 |
This document explains content generation with the L<Mojolicious> renderer. |
|
11 | ||
12 |
=head1 CONCEPTS |
|
13 | ||
14 |
Essentials every L<Mojolicious> developer should know. |
|
15 | ||
16 |
=head2 Renderer |
|
17 | ||
18 |
The renderer is a tiny black box turning stash data into actual responses |
|
19 |
utilizing multiple template systems and data encoding modules. |
|
20 | ||
21 |
{text => 'Hello.'} -> 200 OK, text/html, 'Hello.' |
|
22 |
{json => {x => 3}} -> 200 OK, application/json, '{"x":3}' |
|
23 |
{text => 'Oops.', status => '410'} -> 410 Gone, text/html, 'Oops.' |
|
24 | ||
25 |
Templates can be automatically detected if enough information is provided by |
|
26 |
the developer or routes. Template names are expected to follow the |
|
27 |
C<name.format.handler> scheme, with C<name> defaulting to C<controller/action> |
|
28 |
or the route name, C<format> defaulting to C<html> and C<handler> to C<ep>. |
|
29 | ||
30 |
{controller => 'users', action => 'list'} -> 'users/list.html.ep' |
|
31 |
{name => 'foo', format => 'txt'} -> 'foo.txt.ep' |
|
32 |
{name => 'foo', handler => 'epl'} -> 'foo.html.epl' |
|
33 | ||
34 |
All templates should be in the C<templates> directories of the application or |
|
35 |
the C<DATA> section of the class C<main>. |
|
36 | ||
37 |
__DATA__ |
|
38 | ||
39 |
@@ time.html.ep |
|
40 |
% use Time::Piece; |
|
41 |
% my $now = localtime; |
|
42 |
<!DOCTYPE html> |
|
43 |
<html> |
|
44 |
<head><title>Time</title></head> |
|
45 |
<body>The time is <%= $now->hms %>.</body> |
|
46 |
</html> |
|
47 | ||
48 |
@@ hello.txt.ep |
|
49 |
... |
|
50 | ||
51 |
The renderer can be easily extended to support additional template systems |
|
52 |
with plugins, but more about that later. |
|
53 | ||
54 |
=head2 Embedded Perl |
|
55 | ||
56 |
L<Mojolicious> includes a minimalistic but very powerful template system out |
|
57 |
of the box called Embedded Perl or C<ep> for short. It allows the embedding of |
|
58 |
Perl code right into actual content using a small set of special tags and line |
|
59 |
start characters. |
|
60 | ||
61 |
<% Perl code %> |
|
62 |
<%= Perl expression, replaced with XML escaped result %> |
|
63 |
<%== Perl expression, replaced with result %> |
|
64 |
<%# Comment, useful for debugging %> |
|
65 |
<%% Replaced with "<%", useful for generating templates %> |
|
66 |
% Perl code line, treated as "<% line =%>" |
|
67 |
%= Perl expression line, treated as "<%= line %>" |
|
68 |
%== Perl expression line, treated as "<%== line %>" |
|
69 |
%# Comment line, useful for debugging |
|
70 |
%% Replaced with "%", useful for generating templates |
|
71 | ||
72 |
Tags and lines work pretty much the same, but depending on context one will |
|
73 |
usually look a bit better. Semicolons get automatically appended to all |
|
74 |
expressions. |
|
75 | ||
76 |
<% my $i = 10; %> |
|
77 |
<ul> |
|
78 |
<% for my $j (1 .. $i) { %> |
|
79 |
<li> |
|
80 |
<%= $j %> |
|
81 |
</li> |
|
82 |
<% } %> |
|
83 |
</ul> |
|
84 | ||
85 |
% my $i = 10; |
|
86 |
<ul> |
|
87 |
% for my $j (1 .. $i) { |
|
88 |
<li> |
|
89 |
%= $j |
|
90 |
</li> |
|
91 |
% } |
|
92 |
</ul> |
|
93 | ||
94 |
Aside from differences in whitespace handling, both examples generate similar |
|
95 |
Perl code, a naive translation could look like this. |
|
96 | ||
97 |
my $output = ''; |
|
98 |
my $i = 10; |
|
99 |
$output .= '<ul>'; |
|
100 |
for my $j (1 .. $i) { |
|
101 |
$output .= '<li>'; |
|
102 |
$output .= xml_escape scalar $j; |
|
103 |
$output .= '</li>'; |
|
104 |
} |
|
105 |
$output .= '</ul>'; |
|
106 |
return $output; |
|
107 | ||
108 |
An additional equal sign can be used to disable escaping of the characters |
|
109 |
C<E<lt>>, C<E<gt>>, C<&>, C<'> and C<"> in results from Perl expressions, |
|
110 |
which is the default to prevent XSS attacks against your application. |
|
111 | ||
112 |
<%= 'lalala' %> |
|
113 |
<%== '<p>test</p>' %> |
|
114 | ||
115 |
Only L<Mojo::ByteStream> objects are excluded from automatic escaping. |
|
116 | ||
117 |
% use Mojo::ByteStream 'b'; |
|
118 |
<%= b('<p>test</p>') %> |
|
119 | ||
120 |
Newline characters can be escaped with a backslash. |
|
121 | ||
122 |
This is <%= 1 + 1 %> a\ |
|
123 |
single line |
|
124 | ||
125 |
And a backslash in front of a newline character can be escaped with another |
|
126 |
backslash. |
|
127 | ||
128 |
This will <%= 1 + 1 %> result\\ |
|
129 |
in multiple\\ |
|
130 |
lines |
|
131 | ||
132 |
You can also add an additional equal sign to the end of a tag to have it |
|
133 |
automatically remove all surrounding whitespace, this allows free indenting |
|
134 |
without ruining the result. |
|
135 | ||
136 |
<% for (1 .. 3) { %> |
|
137 |
<%= $foo =%> |
|
138 |
<% } %> |
|
139 | ||
140 |
Stash values that don't have invalid characters in their name get |
|
141 |
automatically initialized as normal variables in the template, and the |
|
142 |
controller object as C<$self>. |
|
143 | ||
144 |
$self->stash(name => 'tester'); |
|
145 | ||
146 |
Hello <%= $name %> from <%= $self->tx->remote_address %>. |
|
147 | ||
148 |
There are also many helper functions available, but more about that later. |
|
149 | ||
150 |
<%= dumper {foo => 'bar'} %> |
|
151 | ||
152 |
=head1 BASICS |
|
153 | ||
154 |
Most commonly used features every L<Mojolicious> developer should know about. |
|
155 | ||
156 |
=head2 Automatic rendering |
|
157 | ||
158 |
The renderer can be manually started by calling the method |
|
159 |
L<Mojolicious::Controller/"render">, but that's usually not necessary, |
|
160 |
because it will get automatically called if nothing has been rendered after |
|
161 |
the router finished its work. This also means you can have routes pointing |
|
162 |
only to templates without actual actions. |
|
163 | ||
164 |
$self->render; |
|
165 | ||
166 |
There is one big difference though, by calling it manually you can make sure |
|
167 |
that templates use the current controller object, and not the default |
|
168 |
controller specified with the attribute L<Mojolicious/"controller_class">. |
|
169 | ||
170 |
$self->render_later; |
|
171 | ||
172 |
You can also disable automatic rendering with the method |
|
173 |
L<Mojolicious::Controller/"render_later">, which can be very useful to delay |
|
174 |
rendering when a non-blocking operation has to be performed first. |
|
175 | ||
176 |
=head2 Rendering templates |
|
177 | ||
178 |
The renderer will always try to detect the right template, but you can also |
|
179 |
use the C<template> stash value to render a specific one. Everything before |
|
180 |
the last slash will be interpreted as the subdirectory path in which to find |
|
181 |
the template. |
|
182 | ||
183 |
# foo/bar/baz.*.* |
|
184 |
$self->render(template => 'foo/bar/baz'); |
|
185 | ||
186 |
Choosing a specific C<format> and C<handler> is just as easy. |
|
187 | ||
188 |
# foo/bar/baz.txt.epl |
|
189 |
$self->render(template => 'foo/bar/baz', format => 'txt', handler => 'epl'); |
|
190 | ||
191 |
Because rendering a specific template is the most common task it also has a |
|
192 |
shortcut. |
|
193 | ||
194 |
$self->render('foo/bar/baz'); |
|
195 | ||
196 |
If you're not sure in advance if a template actually exists, you can also use |
|
197 |
the method L<Mojolicious::Controller/"render_maybe"> to try multiple |
|
198 |
alternatives. |
|
199 | ||
200 |
$self->render_maybe('localized/baz') or $self->render('foo/bar/baz'); |
|
201 | ||
202 |
=head2 Rendering inline templates |
|
203 | ||
204 |
Some renderers such as C<ep> allow templates to be passed inline. |
|
205 | ||
206 |
$self->render(inline => 'The result is <%= 1 + 1 %>.'); |
|
207 | ||
208 |
Since auto detection depends on a path you might have to supply a C<handler> |
|
209 |
too. |
|
210 | ||
211 |
$self->render(inline => "<%= shift->param('foo') %>", handler => 'epl'); |
|
212 | ||
213 |
=head2 Rendering text |
|
214 | ||
215 |
Characters can be rendered to bytes with the C<text> stash value, the given |
|
216 |
content will be automatically encoded to bytes. |
|
217 | ||
218 |
$self->render(text => 'I ♥ Mojolicious!'); |
|
219 | ||
220 |
=head2 Rendering data |
|
221 | ||
222 |
Bytes can be rendered with the C<data> stash value, no encoding will be |
|
223 |
performed. |
|
224 | ||
225 |
$self->render(data => $bytes); |
|
226 | ||
227 |
=head2 Rendering JSON |
|
228 | ||
229 |
The C<json> stash value allows you to pass Perl data structures to the |
|
230 |
renderer which get directly encoded to JSON. |
|
231 | ||
232 |
$self->render(json => {foo => [1, 'test', 3]}); |
|
233 | ||
234 |
=head2 Partial rendering |
|
235 | ||
236 |
Sometimes you might want to use the rendered result directly instead of |
|
237 |
generating a response, for example to send emails, this can be done using the |
|
238 |
C<partial> stash value. |
|
239 | ||
240 |
my $html = $self->render('mail', partial => 1); |
|
241 | ||
242 |
No encoding will be performed, making it easy to reuse the result in other |
|
243 |
templates or to generate binary data. |
|
244 | ||
245 |
my $pdf = $self->render('invoice', format => 'pdf', partial => 1); |
|
246 |
$self->render(data => $pdf, format => 'pdf'); |
|
247 | ||
248 |
=head2 Status code |
|
249 | ||
250 |
Response status codes can be changed with the C<status> stash value. |
|
251 | ||
252 |
$self->render(text => 'Oops.', status => 500); |
|
253 | ||
254 |
=head2 Content type |
|
255 | ||
256 |
The C<Content-Type> header of the response is actually based on the MIME type |
|
257 |
mapping of the C<format> stash value. |
|
258 | ||
259 |
# Content-Type: text/plain |
|
260 |
$self->render(text => 'Hello.', format => 'txt'); |
|
261 | ||
262 |
# Content-Type: image/png |
|
263 |
$self->render(data => $bytes, format => 'png'); |
|
264 | ||
265 |
These mappings can be easily extended or changed with L<Mojolicious/"types">. |
|
266 | ||
267 |
# Application |
|
268 |
package MyApp; |
|
269 |
use Mojo::Base 'Mojolicious'; |
|
270 | ||
271 |
sub startup { |
|
272 |
my $self = shift; |
|
273 | ||
274 |
# Add new MIME type |
|
275 |
$self->types->type(txt => 'text/plain; charset=utf-8'); |
|
276 |
} |
|
277 | ||
278 |
1; |
|
279 | ||
280 |
=head2 Stash data |
|
281 | ||
282 |
Any of the native Perl data types can be passed to templates through the |
|
283 |
L<Mojolicious::Controller/"stash">. |
|
284 | ||
285 |
$self->stash(author => 'Sebastian'); |
|
286 |
$self->stash(frameworks => [qw(Catalyst Mojolicious)]); |
|
287 |
$self->stash(examples => {tweetylicious => 'a microblogging app'}); |
|
288 | ||
289 |
%= $author |
|
290 |
%= $frameworks->[1] |
|
291 |
%= $examples->{tweetylicious} |
|
292 | ||
293 |
Since everything is just Perl normal control structures just work. |
|
294 | ||
295 |
% for my $framework (@$frameworks) { |
|
296 |
<%= $framework %> was written by <%= $author %>. |
|
297 |
% } |
|
298 | ||
299 |
% while (my ($app, $description) = each %$examples) { |
|
300 |
<%= $app %> is a <%= $description %>. |
|
301 |
% } |
|
302 | ||
303 |
=head2 Content negotiation |
|
304 | ||
305 |
For resources with different representations and that require truly |
|
306 |
C<RESTful> content negotiation you can also use |
|
307 |
L<Mojolicious::Controller/"respond_to"> instead of |
|
308 |
L<Mojolicious::Controller/"render">. |
|
309 | ||
310 |
# /hello (Accept: application/json) -> "json" |
|
311 |
# /hello (Accept: application/xml) -> "xml" |
|
312 |
# /hello.json -> "json" |
|
313 |
# /hello.xml -> "xml" |
|
314 |
# /hello?format=json -> "json" |
|
315 |
# /hello?format=xml -> "xml" |
|
316 |
$self->respond_to( |
|
317 |
json => {json => {hello => 'world'}}, |
|
318 |
xml => {text => '<hello>world</hello>'} |
|
319 |
); |
|
320 | ||
321 |
The best possible representation will be automatically selected from the |
|
322 |
C<Accept> request header, C<format> stash value or C<format> GET/POST |
|
323 |
parameter and stored in the C<format> stash value. To change MIME type |
|
324 |
mappings for the C<Accept> request header or the C<Content-Type> response |
|
325 |
header you can use L<Mojolicious/"types">. |
|
326 | ||
327 |
$self->respond_to( |
|
328 |
json => {json => {hello => 'world'}}, |
|
329 |
html => sub { |
|
330 |
$self->content_for(head => '<meta name="author" content="sri">'); |
|
331 |
$self->render(template => 'hello', message => 'world') |
|
332 |
} |
|
333 |
); |
|
334 | ||
335 |
Callbacks can be used for representations that are too complex to fit into a |
|
336 |
single render call. |
|
337 | ||
338 |
# /hello (Accept: application/json) -> "json" |
|
339 |
# /hello (Accept: text/html) -> "html" |
|
340 |
# /hello (Accept: image/png) -> "any" |
|
341 |
# /hello.json -> "json" |
|
342 |
# /hello.html -> "html" |
|
343 |
# /hello.png -> "any" |
|
344 |
# /hello?format=json -> "json" |
|
345 |
# /hello?format=html -> "html" |
|
346 |
# /hello?format=png -> "any" |
|
347 |
$self->respond_to( |
|
348 |
json => {json => {hello => 'world'}}, |
|
349 |
html => {template => 'hello', message => 'world'}, |
|
350 |
any => {text => '', status => 204} |
|
351 |
); |
|
352 | ||
353 |
And if no viable representation could be found, the C<any> fallback will be |
|
354 |
used or an empty C<204> response rendered automatically. |
|
355 | ||
356 |
=head2 Rendering C<exception> and C<not_found> pages |
|
357 | ||
358 |
By now you've probably already encountered the built-in 404 (Not Found) and |
|
359 |
500 (Server Error) pages, that get rendered automatically when you make a |
|
360 |
mistake. Especially during development they can be a great help, you can |
|
361 |
render them manually with the methods |
|
362 |
L<Mojolicious::Controller/"render_exception"> and |
|
363 |
L<Mojolicious::Controller/"render_not_found">. |
|
364 | ||
365 |
use Mojolicious::Lite; |
|
366 |
use Scalar::Util 'looks_like_number'; |
|
367 | ||
368 |
get '/divide/:dividend/by/:divisor' => sub { |
|
369 |
my $self = shift; |
|
370 |
my ($dividend, $divisor) = $self->param(['dividend', 'divisor']); |
|
371 | ||
372 |
# 404 |
|
373 |
return $self->render_not_found |
|
374 |
unless looks_like_number $dividend && looks_like_number $divisor; |
|
375 | ||
376 |
# 500 |
|
377 |
return $self->render_exception('Division by zero!') if $divisor == 0; |
|
378 | ||
379 |
# 200 |
|
380 |
$self->render(text => $dividend / $divisor); |
|
381 |
}; |
|
382 | ||
383 |
app->start; |
|
384 | ||
385 |
You can also change the templates of those pages, since you most likely want |
|
386 |
to show your users something more closely related to your application in |
|
387 |
production. The renderer will always try to find C<exception.$mode.$format.*> |
|
388 |
or C<not_found.$mode.$format.*> before falling back to the built-in default |
|
389 |
templates. |
|
390 | ||
391 |
@@ exception.production.html.ep |
|
392 |
<!DOCTYPE html> |
|
393 |
<html> |
|
394 |
<head><title>Server error</title></head> |
|
395 |
<body> |
|
396 |
<h1>Exception</h1> |
|
397 |
<p><%= $exception->message %></p> |
|
398 |
<h1>Stash</h1> |
|
399 |
<pre><%= dumper $snapshot %></pre> |
|
400 |
</body> |
|
401 |
</html> |
|
402 | ||
403 |
=head2 Helpers |
|
404 | ||
405 |
Helpers are little functions you can use in templates and controller code. |
|
406 | ||
407 |
%= dumper [1, 2, 3] |
|
408 | ||
409 |
my $serialized = $self->dumper([1, 2, 3]); |
|
410 | ||
411 |
The helper L<Mojolicious::Plugin::DefaultHelpers/"dumper"> for example will |
|
412 |
use L<Data::Dumper> to serialize whatever data structure you pass it, this can |
|
413 |
be very useful for debugging. We differentiate between C<default helpers> |
|
414 |
which are more general purpose like C<dumper> and C<tag helpers>, which are |
|
415 |
template specific and mostly used to generate C<HTML> tags. |
|
416 | ||
417 |
%= javascript '/script.js' |
|
418 | ||
419 |
%= javascript begin |
|
420 |
var a = 'b'; |
|
421 |
% end |
|
422 | ||
423 |
A list of all built-in helpers can be found in |
|
424 |
L<Mojolicious::Plugin::DefaultHelpers> and L<Mojolicious::Plugin::TagHelpers>. |
|
425 | ||
426 |
=head2 Layouts |
|
427 | ||
428 |
Most of the time when using C<ep> templates you will want to wrap your |
|
429 |
generated content in a HTML skeleton, thanks to layouts that's absolutely |
|
430 |
trivial. |
|
431 | ||
432 |
@@ foo/bar.html.ep |
|
433 |
% layout 'mylayout'; |
|
434 |
Hello World! |
|
435 | ||
436 |
@@ layouts/mylayout.html.ep |
|
437 |
<!DOCTYPE html> |
|
438 |
<html> |
|
439 |
<head><title>MyApp</title></head> |
|
440 |
<body><%= content %></body> |
|
441 |
</html> |
|
442 | ||
443 |
You just select the right layout template with the helper |
|
444 |
L<Mojolicious::Plugin::DefaultHelpers/"layout"> and place the result of the |
|
445 |
current template with the helper |
|
446 |
L<Mojolicious::Plugin::DefaultHelpers/"content">. You can also pass along |
|
447 |
normal stash values to the C<layout> helper. |
|
448 | ||
449 |
@@ foo/bar.html.ep |
|
450 |
% layout 'mylayout', title => 'Hi there'; |
|
451 |
Hello World! |
|
452 | ||
453 |
@@ layouts/mylayout.html.ep |
|
454 |
<!DOCTYPE html> |
|
455 |
<html> |
|
456 |
<head><title><%= $title %></title></head> |
|
457 |
<body><%= content %></body> |
|
458 |
</html> |
|
459 | ||
460 |
Instead of the C<layout> helper you could also just use the C<layout> stash |
|
461 |
value, or call L<Mojolicious::Controller/"render"> with the C<layout> |
|
462 |
argument. |
|
463 | ||
464 |
$self->render(template => 'mytemplate', layout => 'mylayout'); |
|
465 | ||
466 |
To set a C<layout> stash value application wide you can use |
|
467 |
L<Mojolicious/"defaults">. |
|
468 | ||
469 |
# Application |
|
470 |
package MyApp; |
|
471 |
use Mojo::Base 'Mojolicious'; |
|
472 | ||
473 |
sub startup { |
|
474 |
my $self = shift; |
|
475 | ||
476 |
# Default layout |
|
477 |
$self->defaults(layout => 'mylayout'); |
|
478 |
} |
|
479 | ||
480 |
1; |
|
481 | ||
482 |
=head2 Including partial templates |
|
483 | ||
484 |
Like most helpers L<Mojolicious::Plugin::DefaultHelpers/"include"> is just a |
|
485 |
shortcut to make your life a little easier. |
|
486 | ||
487 |
@@ foo/bar.html.ep |
|
488 |
<!DOCTYPE html> |
|
489 |
<html> |
|
490 |
%= include 'header' |
|
491 |
<body>Bar</body> |
|
492 |
</html> |
|
493 | ||
494 |
@@ header.html.ep |
|
495 |
<head><title>Howdy</title></head> |
|
496 | ||
497 |
Instead of C<include> you could also just call |
|
498 |
L<Mojolicious::Controller/"render"> with the C<partial> argument. |
|
499 | ||
500 |
@@ foo/bar.html.ep |
|
501 |
<!DOCTYPE html> |
|
502 |
<html> |
|
503 |
%= $self->render('header', partial => 1) |
|
504 |
<body>Bar</body> |
|
505 |
</html> |
|
506 | ||
507 |
@@ header.html.ep |
|
508 |
<head><title>Howdy</title></head> |
|
509 | ||
510 |
But there is one small difference between the two, if you pass stash values to |
|
511 |
C<include>, they will get localized automatically and are only available in |
|
512 |
the partial template. |
|
513 | ||
514 |
@@ foo/bar.html.ep |
|
515 |
<!DOCTYPE html> |
|
516 |
<html> |
|
517 |
%= include 'header', title => 'Hello' |
|
518 |
<body>Bar</body> |
|
519 |
</html> |
|
520 | ||
521 |
@@ header.html.ep |
|
522 |
<head><title><%= $title %></title></head> |
|
523 | ||
524 |
=head2 Reusable template blocks |
|
525 | ||
526 |
It's never fun to repeat yourself, that's why you can build reusable template |
|
527 |
blocks in C<ep> that work very similar to normal Perl functions. |
|
528 | ||
529 |
@@ welcome.html.ep |
|
530 |
<% my $block = begin %> |
|
531 |
<% my $name = shift; %> |
|
532 |
Hello <%= $name %>. |
|
533 |
<% end %> |
|
534 |
<%= $block->('Sebastian') %> |
|
535 |
<%= $block->('Sara') %> |
|
536 | ||
537 |
Blocks are always delimited by the C<begin> and C<end> keywords. |
|
538 | ||
539 |
@@ welcome.html.ep |
|
540 |
% my $block = begin |
|
541 |
% my $name = shift; |
|
542 |
Hello <%= $name %>. |
|
543 |
% end |
|
544 |
% for (1 .. 10) { |
|
545 |
%== $block->('Sebastian') |
|
546 |
% } |
|
547 | ||
548 |
A naive translation to Perl code could look like this. |
|
549 | ||
550 |
@@ welcome.html.pl |
|
551 |
my $output = ''; |
|
552 |
my $block = sub { |
|
553 |
my $name = shift; |
|
554 |
my $output = ''; |
|
555 |
$output .= 'Hello '; |
|
556 |
$output .= xml_escape scalar $name; |
|
557 |
$output .= '.'; |
|
558 |
return Mojo::ByteStream->new($output); |
|
559 |
} |
|
560 |
for (1 .. 10) { |
|
561 |
$output .= scalar $block->('Sebastian'); |
|
562 |
} |
|
563 |
return $output; |
|
564 | ||
565 |
=head2 Content blocks |
|
566 | ||
567 |
Blocks and the helper L<Mojolicious::Plugin::DefaultHelpers/"content_for"> |
|
568 |
can also be used to pass whole sections of the template to the layout. |
|
569 | ||
570 |
@@ foo/bar.html.ep |
|
571 |
% layout 'mylayout'; |
|
572 |
% content_for header => begin |
|
573 |
<meta http-equiv="Content-Type" content="text/html"> |
|
574 |
% end |
|
575 |
<div>Hello World!</div> |
|
576 |
% content_for header => begin |
|
577 |
<meta http-equiv="Pragma" content="no-cache"> |
|
578 |
% end |
|
579 | ||
580 |
@@ layouts/mylayout.html.ep |
|
581 |
<!DOCTYPE html> |
|
582 |
<html> |
|
583 |
<head><%= content_for 'header' %></head> |
|
584 |
<body><%= content %></body> |
|
585 |
</html> |
|
586 | ||
587 |
=head2 Template inheritance |
|
588 | ||
589 |
Inheritance takes the layout concept above one step further, the helpers |
|
590 |
L<Mojolicious::Plugin::DefaultHelpers/"content"> and |
|
591 |
L<Mojolicious::Plugin::DefaultHelpers/"extends"> allow you to build a skeleton |
|
592 |
template with named blocks that child templates can override. |
|
593 | ||
594 |
@@ first.html.ep |
|
595 |
<!DOCTYPE html> |
|
596 |
<html> |
|
597 |
<head><title>Hello</title></head> |
|
598 |
<body> |
|
599 |
%= content header => begin |
|
600 |
Default header |
|
601 |
% end |
|
602 |
<div>Hello World!</div> |
|
603 |
%= content footer => begin |
|
604 |
Default footer |
|
605 |
% end |
|
606 |
</body> |
|
607 |
</html> |
|
608 | ||
609 |
@@ second.html.ep |
|
610 |
% extends 'first'; |
|
611 |
% content header => begin |
|
612 |
New header |
|
613 |
% end |
|
614 | ||
615 |
This chain could go on and on to allow a very high level of template reuse. |
|
616 | ||
617 |
=head2 Form validation |
|
618 | ||
619 |
You can use L<Mojolicious::Controller/"validation"> to validate GET/POST |
|
620 |
parameters submitted to your application. All unknown fields will be ignored |
|
621 |
by default, so you have to decide which should be required or optional before |
|
622 |
you can perform checks on their values. Every check is performed right away, |
|
623 |
so you can use the results immediately to build more advanced validation logic |
|
624 |
with methods like L<Mojolicious::Validator::Validation/"is_valid">. |
|
625 | ||
626 |
use Mojolicious::Lite; |
|
627 | ||
628 |
get '/' => sub { |
|
629 |
my $self = shift; |
|
630 | ||
631 |
# Check if parameters have been submitted |
|
632 |
my $validation = $self->validation; |
|
633 |
return $self->render unless $validation->has_data; |
|
634 | ||
635 |
# Validate parameters ("pass_again" depends on "pass") |
|
636 |
$validation->required('user')->size(1, 20)->like(qr/^[e-t]+$/); |
|
637 |
$validation->required('pass_again')->equal_to('pass') |
|
638 |
if $validation->optional('pass')->size(7, 500)->is_valid; |
|
639 | ||
640 |
# Render confirmation if validation was successful |
|
641 |
$self->render('thanks') unless $validation->has_error; |
|
642 |
} => 'index'; |
|
643 | ||
644 |
app->start; |
|
645 |
__DATA__ |
|
646 | ||
647 |
@@ index.html.ep |
|
648 |
<!DOCTYPE html> |
|
649 |
<html> |
|
650 |
<head> |
|
651 |
%= stylesheet begin |
|
652 |
label.field-with-error { color: #dd7e5e } |
|
653 |
input.field-with-error { background-color: #fd9e7e } |
|
654 |
% end |
|
655 |
</head> |
|
656 |
<body> |
|
657 |
%= form_for index => begin |
|
658 |
%= label_for user => 'Username (required, 1-20 characters, only e-t)' |
|
659 |
<br> |
|
660 |
%= text_field 'user' |
|
661 |
%= submit_button |
|
662 |
<br> |
|
663 |
%= label_for pass => 'Password (optional, 7-500 characters)' |
|
664 |
<br> |
|
665 |
%= password_field 'pass' |
|
666 |
<br> |
|
667 |
%= label_for pass_again => 'Password again (equal to the value above)' |
|
668 |
<br> |
|
669 |
%= password_field 'pass_again' |
|
670 |
% end |
|
671 |
</body> |
|
672 |
</html> |
|
673 | ||
674 |
@@ thanks.html.ep |
|
675 |
<!DOCTYPE html> |
|
676 |
<html><body>Thank you <%= validation->param('user') %>.</body></html> |
|
677 | ||
678 |
Form elements generated with tag helpers from |
|
679 |
L<Mojolicious::Plugin::TagHelpers> will automatically remember their previous |
|
680 |
values and add the class C<field-with-error> for fields that failed validation |
|
681 |
to make styling with CSS easier. |
|
682 | ||
683 |
<label class="field-with-error" for="user"> |
|
684 |
Username (required, only characters e-t) |
|
685 |
</label> |
|
686 |
<input class="field-with-error" type="text" name="user" value="sri" /> |
|
687 | ||
688 |
For a full list of available checks see also |
|
689 |
L<Mojolicious::Validator/"CHECKS">. |
|
690 | ||
691 |
=head2 Adding form validation checks |
|
692 | ||
693 |
Validation checks can be registered with L<Mojolicious::Validator/"add_check"> |
|
694 |
and return a false value if they were successful. A true value may be used to |
|
695 |
pass along additional information which can then be retrieved with |
|
696 |
L<Mojolicious::Validator::Validation/"error">. |
|
697 | ||
698 |
use Mojolicious::Lite; |
|
699 | ||
700 |
# Add "range" check |
|
701 |
app->validator->add_check(range => sub { |
|
702 |
my ($validation, $name, $value, $min, $max) = @_; |
|
703 |
return $value < $min || $value > $max; |
|
704 |
}); |
|
705 | ||
706 |
get '/' => 'form'; |
|
707 | ||
708 |
post '/test' => sub { |
|
709 |
my $self = shift; |
|
710 | ||
711 |
# Validate parameters with custom check |
|
712 |
my $validation = $self->validation; |
|
713 |
$validation->required('number')->range(3, 23); |
|
714 | ||
715 |
# Render form again if validation failed |
|
716 |
return $self->render('form') if $validation->has_error; |
|
717 | ||
718 |
# Prevent double submit with redirect |
|
719 |
$self->flash(number => $validation->param('number')); |
|
720 |
$self->redirect_to('form'); |
|
721 |
}; |
|
722 | ||
723 |
app->start; |
|
724 |
__DATA__ |
|
725 | ||
726 |
@@ form.html.ep |
|
727 |
<!DOCTYPE html> |
|
728 |
<html> |
|
729 |
<body> |
|
730 |
% if (my $number = flash 'number') { |
|
731 |
<p>Thanks, the number <%= $number %> was valid.</p> |
|
732 |
% } |
|
733 |
%= form_for test => begin |
|
734 |
% if (my $err = validation->error('number')) { |
|
735 |
<p> |
|
736 |
%= 'Value is required.' if $err->[0] eq 'required' |
|
737 |
%= 'Value needs to be between 3 and 23.' if $err->[0] eq 'range' |
|
738 |
</p> |
|
739 |
% } |
|
740 |
%= text_field 'number' |
|
741 |
%= submit_button |
|
742 |
% end |
|
743 |
</html> |
|
744 |
</html> |
|
745 | ||
746 |
=head2 Adding helpers |
|
747 | ||
748 |
Adding and redefining helpers is very easy, you can use them to do pretty much |
|
749 |
everything. |
|
750 | ||
751 |
use Mojolicious::Lite; |
|
752 | ||
753 |
helper debug => sub { |
|
754 |
my ($self, $str) = @_; |
|
755 |
$self->app->log->debug($str); |
|
756 |
}; |
|
757 | ||
758 |
get '/' => sub { |
|
759 |
my $self = shift; |
|
760 |
$self->debug('Hello from an action!'); |
|
761 |
} => 'index'; |
|
762 | ||
763 |
app->start; |
|
764 |
__DATA__ |
|
765 | ||
766 |
@@ index.html.ep |
|
767 |
% debug 'Hello from a template!'; |
|
768 | ||
769 |
Helpers can also accept template blocks as last argument, this for example |
|
770 |
allows very pleasant to use tag helpers and filters. |
|
771 | ||
772 |
use Mojolicious::Lite; |
|
773 |
use Mojo::ByteStream; |
|
774 | ||
775 |
helper trim_newline => sub { |
|
776 |
my ($self, $block) = @_; |
|
777 |
my $result = $block->(); |
|
778 |
$result =~ s/\n//g; |
|
779 |
return Mojo::ByteStream->new($result); |
|
780 |
}; |
|
781 | ||
782 |
get '/' => 'index'; |
|
783 | ||
784 |
app->start; |
|
785 |
__DATA__ |
|
786 | ||
787 |
@@ index.html.ep |
|
788 |
%= trim_newline begin |
|
789 |
Some text. |
|
790 |
%= 1 + 1 |
|
791 |
More text. |
|
792 |
% end |
|
793 | ||
794 |
Wrapping the helper result into a L<Mojo::ByteStream> object can prevent |
|
795 |
accidental double escaping. |
|
796 | ||
797 |
=head2 Helper plugins |
|
798 | ||
799 |
Some helpers might be useful enough for you to share them between multiple |
|
800 |
applications, plugins make that very simple. |
|
801 | ||
802 |
package Mojolicious::Plugin::DebugHelper; |
|
803 |
use Mojo::Base 'Mojolicious::Plugin'; |
|
804 | ||
805 |
sub register { |
|
806 |
my ($self, $app) = @_; |
|
807 |
$app->helper(debug => sub { |
|
808 |
my ($self, $str) = @_; |
|
809 |
$self->app->log->debug($str); |
|
810 |
}); |
|
811 |
} |
|
812 | ||
813 |
1; |
|
814 | ||
815 |
The C<register> method will be called when you load the plugin and to add your |
|
816 |
helper to the application you can use L<Mojolicious/"helper">. |
|
817 | ||
818 |
use Mojolicious::Lite; |
|
819 | ||
820 |
plugin 'DebugHelper'; |
|
821 | ||
822 |
get '/' => sub { |
|
823 |
my $self = shift; |
|
824 |
$self->debug('It works.'); |
|
825 |
$self->render(text => 'Hello.'); |
|
826 |
}; |
|
827 | ||
828 |
app->start; |
|
829 | ||
830 |
A skeleton for a full CPAN compatible plugin distribution can be automatically |
|
831 |
generated. |
|
832 | ||
833 |
$ mojo generate plugin DebugHelper |
|
834 | ||
835 |
And if you have a C<PAUSE> account (which can be requested at |
|
836 |
L<http://pause.perl.org>), you are only a few commands away from releasing it |
|
837 |
to CPAN. |
|
838 | ||
839 |
$ perl Makefile.PL |
|
840 |
$ make test |
|
841 |
$ make manifest |
|
842 |
$ make dist |
|
843 |
$ mojo cpanify -u USER -p PASS Mojolicious-Plugin-DebugHelper-0.01.tar.gz |
|
844 | ||
845 |
=head2 Bundling assets with plugins |
|
846 | ||
847 |
Assets such as templates and static files can be easily bundled with your |
|
848 |
plugins, even if you plan to release them to CPAN. |
|
849 | ||
850 |
$ mojo generate plugin AlertAssets |
|
851 |
$ mkdir AlertAssets/lib/Mojolicious/Plugin/AlertAssets |
|
852 |
$ cd AlertAssets/lib/Mojolicious/Plugin/AlertAssets |
|
853 |
$ mkdir public |
|
854 |
$ echo 'alert("Hello World!");' > public/alertassets.js |
|
855 |
$ mkdir templates |
|
856 |
$ echo '%= javascript "/alertassets.js"' > templates/alertassets.html.ep |
|
857 | ||
858 |
Just append their respective directories to the list of search paths when |
|
859 |
C<register> is called. |
|
860 | ||
861 |
package Mojolicious::Plugin::AlertAssets; |
|
862 |
use Mojo::Base 'Mojolicious::Plugin'; |
|
863 | ||
864 |
use File::Basename 'dirname'; |
|
865 |
use File::Spec::Functions 'catdir'; |
|
866 | ||
867 |
sub register { |
|
868 |
my ($self, $app) = @_; |
|
869 | ||
870 |
# Append "templates" and "public" directories |
|
871 |
my $base = catdir(dirname(__FILE__), 'AlertAssets'); |
|
872 |
push @{$app->renderer->paths}, catdir($base, 'templates'); |
|
873 |
push @{$app->static->paths}, catdir($base, 'public'); |
|
874 |
} |
|
875 | ||
876 |
1; |
|
877 | ||
878 |
Both will work just like normal C<templates> and C<public> directories once |
|
879 |
you've installed and loaded the plugin, with slightly lower precedence. |
|
880 | ||
881 |
use Mojolicious::Lite; |
|
882 | ||
883 |
plugin 'AlertAssets'; |
|
884 | ||
885 |
get '/alert_me'; |
|
886 | ||
887 |
app->start; |
|
888 |
__DATA__ |
|
889 | ||
890 |
@@ alert_me.html.ep |
|
891 |
<!DOCTYPE html> |
|
892 |
<html> |
|
893 |
<head> |
|
894 |
<title>Alert me!</title> |
|
895 |
%= include 'alertassets' |
|
896 |
</head> |
|
897 |
<body>You've been alerted.</body> |
|
898 |
</html> |
|
899 | ||
900 |
And it works just the same for assets bundled in the C<DATA> section of your |
|
901 |
plugin. |
|
902 | ||
903 |
package Mojolicious::Plugin::AlertAssets; |
|
904 |
use Mojo::Base 'Mojolicious::Plugin'; |
|
905 | ||
906 |
sub register { |
|
907 |
my ($self, $app) = @_; |
|
908 | ||
909 |
# Append class |
|
910 |
push @{$app->renderer->classes}, __PACKAGE__; |
|
911 |
push @{$app->static->classes}, __PACKAGE__; |
|
912 |
} |
|
913 | ||
914 |
1; |
|
915 |
__DATA__ |
|
916 | ||
917 |
@@ alertassets.js |
|
918 |
alert("Hello World!"); |
|
919 | ||
920 |
@@ alertassets.html.ep |
|
921 |
%= javascript "/alertassets.js" |
|
922 | ||
923 |
=head1 ADVANCED |
|
924 | ||
925 |
Less commonly used and more powerful features. |
|
926 | ||
927 |
=head2 Rendering static files |
|
928 | ||
929 |
If automatic rendering of static files is not enough, you can also render them |
|
930 |
manually from your C<DATA> sections and C<public> directories with |
|
931 |
L<Mojolicious::Controller/"render_static">. |
|
932 | ||
933 |
$self->res->headers->content_disposition('attachment; filename=bar.png;'); |
|
934 |
$self->render_static('foo/bar.png'); |
|
935 | ||
936 |
=head2 Custom responses |
|
937 | ||
938 |
For entirely custom responses to, for example, stream content directly from |
|
939 |
files, you can use L<Mojolicious::Controller/"rendered"> to tell the renderer |
|
940 |
that a response has been generated. |
|
941 | ||
942 |
$self->res->headers->content_type('text/plain'); |
|
943 |
$self->res->content->asset(Mojo::Asset::File->new(path => '/etc/passwd')); |
|
944 |
$self->rendered(200); |
|
945 | ||
946 |
=head2 Post-processing dynamic content |
|
947 | ||
948 |
While post-processing tasks are generally very easy with the C<after_dispatch> |
|
949 |
hook, for content generated by the renderer it is a lot more efficient to use |
|
950 |
C<after_render>. |
|
951 | ||
952 |
use Mojolicious::Lite; |
|
953 |
use IO::Compress::Gzip 'gzip'; |
|
954 | ||
955 |
hook after_render => sub { |
|
956 |
my ($c, $output, $format) = @_; |
|
957 | ||
958 |
# Check if "gzip => 1" has been set in the stash |
|
959 |
return unless $c->stash->{gzip}; |
|
960 | ||
961 |
# Check if user agent accepts GZip compression |
|
962 |
return unless ($c->req->headers->accept_encoding // '') =~ /gzip/i; |
|
963 |
$c->res->headers->append(Vary => 'Accept-Encoding'); |
|
964 | ||
965 |
# Compress content with GZip |
|
966 |
$c->res->headers->content_encoding('gzip'); |
|
967 |
gzip $output, \my $compressed; |
|
968 |
$$output = $compressed; |
|
969 |
}; |
|
970 | ||
971 |
get '/' => {template => 'hello', title => 'Hello', gzip => 1}; |
|
972 | ||
973 |
app->start; |
|
974 |
__DATA__ |
|
975 | ||
976 |
@@ hello.html.ep |
|
977 |
<!DOCTYPE html> |
|
978 |
<html> |
|
979 |
<head><title><%= title %></title></head> |
|
980 |
<body>Compressed content.</body> |
|
981 |
</html> |
|
982 | ||
983 |
=head2 Chunked transfer encoding |
|
984 | ||
985 |
For very dynamic content you might not know the response content length in |
|
986 |
advance, that's where the C<chunked> transfer encoding and |
|
987 |
L<Mojolicious::Controller/"write_chunk"> come in handy. A common use would be |
|
988 |
to send the C<head> section of an HTML document to the browser in advance and |
|
989 |
speed up preloading of referenced images and stylesheets. |
|
990 | ||
991 |
$self->write_chunk('<html><head><title>Example</title></head>' => sub { |
|
992 |
my $self = shift; |
|
993 |
$self->finish('<body>Example</body></html>'); |
|
994 |
}); |
|
995 | ||
996 |
The optional drain callback ensures that all previous chunks have been |
|
997 |
written before processing continues. An empty chunk or call to |
|
998 |
L<Mojolicious::Controller/"finish"> marks the end of the stream. |
|
999 | ||
1000 |
29 |
|
1001 |
<html><head><title>Example</title></head> |
|
1002 |
1b |
|
1003 |
<body>Example</body></html> |
|
1004 |
0 |
|
1005 | ||
1006 |
Especially in combination with long inactivity timeouts this can be very |
|
1007 |
useful for Comet (long polling). Due to limitations in some web servers this |
|
1008 |
might not work perfectly in all deployment environments. |
|
1009 | ||
1010 |
=head2 Encoding |
|
1011 | ||
1012 |
Templates stored in files are expected to be C<UTF-8> by default, but that can |
|
1013 |
be easily changed with L<Mojolicious::Renderer/"encoding">. |
|
1014 | ||
1015 |
# Application |
|
1016 |
package MyApp; |
|
1017 |
use Mojo::Base 'Mojolicious'; |
|
1018 | ||
1019 |
sub startup { |
|
1020 |
my $self = shift; |
|
1021 | ||
1022 |
# Different encoding |
|
1023 |
$self->renderer->encoding('koi8-r'); |
|
1024 |
} |
|
1025 | ||
1026 |
1; |
|
1027 | ||
1028 |
All templates from the C<DATA> section are bound to the encoding of the Perl |
|
1029 |
script. |
|
1030 | ||
1031 |
use Mojolicious::Lite; |
|
1032 | ||
1033 |
get '/heart'; |
|
1034 | ||
1035 |
app->start; |
|
1036 | ||
1037 |
__DATA__ |
|
1038 |
@@ heart.html.ep |
|
1039 |
I ♥ Mojolicious! |
|
1040 | ||
1041 |
=head2 Base64 encoded DATA files |
|
1042 | ||
1043 |
Base64 encoded static files such as images can be easily stored in the C<DATA> |
|
1044 |
section of your application, similar to templates. |
|
1045 | ||
1046 |
@@ favicon.ico (base64) |
|
1047 |
...base64 encoded image... |
|
1048 | ||
1049 |
=head2 Inflating DATA templates |
|
1050 | ||
1051 |
Templates stored in files get preferred over files from the C<DATA> section, |
|
1052 |
this allows you to include a default set of templates in your application that |
|
1053 |
the user can later customize. The C<inflate> command will write all templates |
|
1054 |
and static files from the C<DATA> section into actual files in the |
|
1055 |
C<templates> and C<public> directories. |
|
1056 | ||
1057 |
$ ./myapp.pl inflate |
|
1058 | ||
1059 |
=head2 Customizing the template syntax |
|
1060 | ||
1061 |
You can easily change the whole template syntax by loading |
|
1062 |
L<Mojolicious::Plugin::EPRenderer> with a custom configuration. |
|
1063 | ||
1064 |
use Mojolicious::Lite; |
|
1065 | ||
1066 |
plugin EPRenderer => { |
|
1067 |
name => 'mustache', |
|
1068 |
template => { |
|
1069 |
tag_start => '{{', |
|
1070 |
tag_end => '}}' |
|
1071 |
} |
|
1072 |
}; |
|
1073 | ||
1074 |
get '/:name' => {name => 'Anonymous'} => 'index'; |
|
1075 | ||
1076 |
app->start; |
|
1077 |
__DATA__ |
|
1078 | ||
1079 |
@@ index.html.mustache |
|
1080 |
Hello {{= $name }}. |
|
1081 | ||
1082 |
L<Mojo::Template> contains the whole list of available options. |
|
1083 | ||
1084 |
=head2 Adding your favorite template system |
|
1085 | ||
1086 |
Maybe you would prefer a different template system than C<ep>, and there is |
|
1087 |
not already a plugin on CPAN for your favorite one, all you have to do is add |
|
1088 |
a new C<handler> with L<Mojolicious::Renderer/"add_handler"> when C<register> |
|
1089 |
is called. |
|
1090 | ||
1091 |
package Mojolicious::Plugin::MyRenderer; |
|
1092 |
use Mojo::Base 'Mojolicious::Plugin'; |
|
1093 | ||
1094 |
sub register { |
|
1095 |
my ($self, $app) = @_; |
|
1096 | ||
1097 |
# Add "mine" handler |
|
1098 |
$app->renderer->add_handler(mine => sub { |
|
1099 |
my ($renderer, $c, $output, $options) = @_; |
|
1100 | ||
1101 |
# Check for one-time use inline template |
|
1102 |
my $inline = $options->{inline}; |
|
1103 | ||
1104 |
# Check for absolute template path |
|
1105 |
my $path = $renderer->template_path($options); |
|
1106 | ||
1107 |
# Check for appropriate template in DATA section |
|
1108 |
my $data = $renderer->get_data_template($options); |
|
1109 | ||
1110 |
# This part is up to you and your template system :) |
|
1111 |
... |
|
1112 | ||
1113 |
# Just die if an error occurs |
|
1114 |
die 'Something went wrong'; |
|
1115 | ||
1116 |
# Or pass the rendered result back to the renderer |
|
1117 |
$$output = 'Hello World!'; |
|
1118 | ||
1119 |
# And return true if something has been rendered or false otherwise |
|
1120 |
return 1; |
|
1121 |
}); |
|
1122 |
} |
|
1123 | ||
1124 |
1; |
|
1125 | ||
1126 |
Since most template systems don't support templates in the C<DATA> section, |
|
1127 |
the renderer provides methods to help you with that. |
|
1128 | ||
1129 |
use Mojolicious::Lite; |
|
1130 | ||
1131 |
plugin 'MyRenderer'; |
|
1132 | ||
1133 |
get '/' => 'index'; |
|
1134 | ||
1135 |
app->start; |
|
1136 |
__DATA__ |
|
1137 | ||
1138 |
@@ index.html.mine |
|
1139 |
... |
|
1140 | ||
1141 |
=head2 Adding a handler to generate binary data |
|
1142 | ||
1143 |
By default the renderer assumes that every C<handler> generates characters |
|
1144 |
that need to be automatically encoded, but this can be be easily disabled if |
|
1145 |
you're generating bytes instead. |
|
1146 | ||
1147 |
use Mojolicious::Lite; |
|
1148 |
use Mango::BSON ':bson'; |
|
1149 | ||
1150 |
# Add "bson" handler |
|
1151 |
app->renderer->add_handler(bson => sub { |
|
1152 |
my ($renderer, $c, $output, $options) = @_; |
|
1153 | ||
1154 |
# Disable automatic encoding |
|
1155 |
delete $options->{encoding}; |
|
1156 | ||
1157 |
# Encode BSON data from stash value |
|
1158 |
$$output = bson_encode delete $c->stash->{bson}; |
|
1159 | ||
1160 |
return 1; |
|
1161 |
}); |
|
1162 | ||
1163 |
get '/' => {bson => {i => '♥ mojolicious'}, handler => 'bson'}; |
|
1164 | ||
1165 |
app->start; |
|
1166 | ||
1167 |
=head1 MORE |
|
1168 | ||
1169 |
You can continue with L<Mojolicious::Guides> now or take a look at the |
|
1170 |
L<Mojolicious wiki|http://github.com/kraih/mojo/wiki>, which contains a lot |
|
1171 |
more documentation and examples by many different authors. |
|
1172 | ||
1173 |
=head1 SUPPORT |
|
1174 | ||
1175 |
If you have any questions the documentation might not yet answer, don't |
|
1176 |
hesitate to ask on the |
|
1177 |
L<mailing-list|http://groups.google.com/group/mojolicious> or the official IRC |
|
1178 |
channel C<#mojo> on C<irc.perl.org>. |
|
1179 | ||
1180 |
=cut |