1Mojolicious::Guides::ReUnsdeerriCnogn(t3r)ibuted Perl DoMcoujmoelnitcaitoiuosn::Guides::Rendering(3)
2
3
4
6 Mojolicious::Guides::Rendering - Rendering content
7
9 This document explains content generation with the Mojolicious
10 renderer.
11
13 Essentials every Mojolicious developer should know.
14
15 Renderer
16 The renderer is a tiny black box turning stash data into actual
17 responses utilizing multiple template systems and data encoding
18 modules.
19
20 {text => 'Hello.'} -> 200 OK, text/html, 'Hello.'
21 {json => {x => 3}} -> 200 OK, application/json, '{"x":3}'
22 {text => 'Oops.', status => '410'} -> 410 Gone, text/html, 'Oops.'
23
24 Templates can be automatically detected if enough information is
25 provided by the developer or routes. Template names are expected to
26 follow the "template.format.handler" scheme, with "template" defaulting
27 to "controller/action" or the route name, "format" defaulting to "html"
28 and "handler" to "ep".
29
30 {controller => 'users', action => 'list'} -> 'users/list.html.ep'
31 {template => 'foo', format => 'txt'} -> 'foo.txt.ep'
32 {template => 'foo', handler => 'epl'} -> 'foo.html.epl'
33
34 The "controller" value gets converted from "CamelCase" to "snake_case"
35 using "decamelize" in Mojo::Util and "-" characters replaced with "/".
36
37 {controller => 'My::Users', action => 'add'} -> 'my/users/add.html.ep'
38 {controller => 'my-users', action => 'show'} -> 'my/users/show.html.ep'
39
40 All templates should be in the "templates" directories of the
41 application, which can be customized with "paths" in
42 Mojolicious::Renderer, or one of the the "DATA" sections from "classes"
43 in Mojolicious::Renderer.
44
45 __DATA__
46
47 @@ time.html.ep
48 % use Time::Piece;
49 % my $now = localtime;
50 <!DOCTYPE html>
51 <html>
52 <head><title>Time</title></head>
53 <body>The time is <%= $now->hms %>.</body>
54 </html>
55
56 @@ hello.txt.ep
57 ...
58
59 The renderer can be easily extended to support additional template
60 systems with plugins, but more about that later.
61
62 Embedded Perl
63 Mojolicious includes a minimalistic but very powerful template system
64 out of the box called Embedded Perl or "ep" for short. It is based on
65 Mojo::Template and allows the embedding of Perl code right into actual
66 content using a small set of special tags and line start characters.
67 For all templates strict, warnings, utf8 and Perl 5.16 features are
68 automatically enabled.
69
70 <% Perl code %>
71 <%= Perl expression, replaced with XML escaped result %>
72 <%== Perl expression, replaced with result %>
73 <%# Comment, useful for debugging %>
74 <%% Replaced with "<%", useful for generating templates %>
75 % Perl code line, treated as "<% line =%>" (explained later)
76 %= Perl expression line, treated as "<%= line %>"
77 %== Perl expression line, treated as "<%== line %>"
78 %# Comment line, useful for debugging
79 %% Replaced with "%", useful for generating templates
80
81 Tags and lines work pretty much the same, but depending on context one
82 will usually look a bit better. Semicolons get automatically appended
83 to all expressions.
84
85 <% my $i = 10; %>
86 <ul>
87 <% for my $j (1 .. $i) { %>
88 <li>
89 <%= $j %>
90 </li>
91 <% } %>
92 </ul>
93
94 % my $i = 10;
95 <ul>
96 % for my $j (1 .. $i) {
97 <li>
98 %= $j
99 </li>
100 % }
101 </ul>
102
103 Aside from differences in whitespace handling, both examples generate
104 similar Perl code, a naive translation could look like this.
105
106 my $output = '';
107 my $i = 10;
108 $output .= '<ul>';
109 for my $j (1 .. $i) {
110 $output .= '<li>';
111 $output .= xml_escape scalar + $j;
112 $output .= '</li>';
113 }
114 $output .= '</ul>';
115 return $output;
116
117 An additional equal sign can be used to disable escaping of the
118 characters "<", ">", "&", "'" and """ in results from Perl expressions,
119 which is the default to prevent XSS attacks against your application.
120
121 <%= 'I ♥ Mojolicious!' %>
122 <%== '<p>I ♥ Mojolicious!</p>' %>
123
124 Only Mojo::ByteStream objects are excluded from automatic escaping.
125
126 <%= b('<p>I ♥ Mojolicious!</p>') %>
127
128 Whitespace characters around tags can be trimmed by adding an
129 additional equal sign to the end of a tag.
130
131 <% for (1 .. 3) { %>
132 <%= 'Trim all whitespace characters around this expression' =%>
133 <% } %>
134
135 Newline characters can be escaped with a backslash.
136
137 This is <%= 1 + 1 %> a\
138 single line
139
140 And a backslash in front of a newline character can be escaped with
141 another backslash.
142
143 This will <%= 1 + 1 %> result\\
144 in multiple\\
145 lines
146
147 A newline character gets appended automatically to every template,
148 unless the last character is a backslash. And empty lines at the end of
149 a template are ignored.
150
151 There is <%= 1 + 1 %> no newline at the end here\
152
153 At the beginning of the template, stash values that don't have invalid
154 characters in their name get automatically initialized as normal
155 variables, and the controller object as both $self and $c.
156
157 $c->stash(name => 'tester');
158
159 Hello <%= $name %> from <%= $c->tx->remote_address %>.
160
161 A prefix like "myapp.*" is commonly used for stash values that you
162 don't want to expose in templates.
163
164 $c->stash('myapp.name' => 'tester');
165
166 There are also many helper functions available, but more about that
167 later.
168
169 <%= dumper {foo => 'bar'} %>
170
172 Most commonly used features every Mojolicious developer should know
173 about.
174
175 Automatic rendering
176 The renderer can be manually started by calling the method "render" in
177 Mojolicious::Controller, but that's usually not necessary, because it
178 will get automatically called if nothing has been rendered after the
179 router finished its work. This also means you can have routes pointing
180 only to templates without actual actions.
181
182 $c->render;
183
184 There is one big difference though, by calling it manually you can make
185 sure that templates use the current controller object, and not the
186 default controller specified with the attribute "controller_class" in
187 Mojolicious.
188
189 $c->render_later;
190
191 You can also disable automatic rendering with the method "render_later"
192 in Mojolicious::Controller, which can be very useful to delay rendering
193 when a non-blocking operation has to be performed first.
194
195 Rendering templates
196 The renderer will always try to detect the right template, but you can
197 also use the "template" stash value to render a specific one.
198 Everything before the last slash will be interpreted as the
199 subdirectory path in which to find the template.
200
201 # foo/bar/baz.*.*
202 $c->render(template => 'foo/bar/baz');
203
204 Choosing a specific "format" and "handler" is just as easy.
205
206 # foo/bar/baz.txt.epl
207 $c->render(template => 'foo/bar/baz', format => 'txt', handler => 'epl');
208
209 Because rendering a specific template is the most common task it also
210 has a shortcut.
211
212 $c->render('foo/bar/baz');
213
214 If you're not sure in advance if a template actually exists, you can
215 also use the method "render_maybe" in Mojolicious::Controller to try
216 multiple alternatives.
217
218 $c->render_maybe('localized/baz') or $c->render('foo/bar/baz');
219
220 Rendering to strings
221 Sometimes you might want to use the rendered result directly instead of
222 generating a response, for example, to send emails, this can be done
223 with "render_to_string" in Mojolicious::Controller.
224
225 my $html = $c->render_to_string('mail');
226
227 No encoding will be performed, making it easy to reuse the result in
228 other templates or to generate binary data.
229
230 my $pdf = $c->render_to_string('invoice', format => 'pdf');
231 $c->render(data => $pdf, format => 'pdf');
232
233 All arguments passed will get localized automatically and are only
234 available during this render operation.
235
236 Template variants
237 To make your application look great on many different devices you can
238 also use the "variant" stash value to choose between different variants
239 of your templates.
240
241 # foo/bar/baz.html+phone.ep
242 # foo/bar/baz.html.ep
243 $c->render('foo/bar/baz', variant => 'phone');
244
245 This can be done very liberally since it only applies when a template
246 with the correct name actually exists and falls back to the generic one
247 otherwise.
248
249 Rendering inline templates
250 Some renderers such as "ep" allow templates to be passed "inline".
251
252 $c->render(inline => 'The result is <%= 1 + 1 %>.');
253
254 Since auto-detection depends on a path you might have to supply a
255 "handler" too.
256
257 $c->render(inline => "<%= shift->param('foo') %>", handler => 'epl');
258
259 Rendering text
260 Characters can be rendered to bytes with the "text" stash value, the
261 given content will be automatically encoded with "encoding" in
262 Mojolicious::Renderer.
263
264 $c->render(text => 'I ♥ Mojolicious!');
265
266 Rendering data
267 Bytes can be rendered with the "data" stash value, no encoding will be
268 performed.
269
270 $c->render(data => $bytes);
271
272 Rendering JSON
273 The "json" stash value allows you to pass Perl data structures to the
274 renderer which get directly encoded to JSON with Mojo::JSON.
275
276 $c->render(json => {foo => [1, 'test', 3]});
277
278 Status code
279 Response status codes can be changed with the "status" stash value.
280
281 $c->render(text => 'Oops.', status => 500);
282
283 Content type
284 The "Content-Type" header of the response is actually based on the MIME
285 type mapping of the "format" stash value.
286
287 # Content-Type: text/plain
288 $c->render(text => 'Hello.', format => 'txt');
289
290 # Content-Type: image/png
291 $c->render(data => $bytes, format => 'png');
292
293 These mappings can be easily extended or changed with "types" in
294 Mojolicious.
295
296 # Add new MIME type
297 $app->types->type(md => 'text/markdown');
298
299 Stash data
300 Any of the native Perl data types can be passed to templates as
301 references through the "stash" in Mojolicious::Controller.
302
303 $c->stash(description => 'web framework');
304 $c->stash(frameworks => ['Catalyst', 'Mojolicious', 'mojo.js']);
305 $c->stash(spinoffs => {minion => 'job queue'});
306
307 %= $description
308 %= $frameworks->[1]
309 %= $spinoffs->{minion}
310
311 Since everything is just Perl normal control structures just work.
312
313 % for my $framework (@$frameworks) {
314 <%= $framework %> is a <%= $description %>.
315 % }
316
317 % if (my $description = $spinoffs->{minion}) {
318 Minion is a <%= $description %>.
319 % }
320
321 For templates that might get rendered in different ways and where
322 you're not sure if a stash value will actually be set, you can just use
323 the helper "stash" in Mojolicious::Plugin::DefaultHelpers.
324
325 % if (my $spinoffs = stash 'spinoffs') {
326 Minion is a <%= $spinoffs->{minion} %>.
327 % }
328
329 Helpers
330 Helpers are little functions you can use in templates as well as
331 application and controller code.
332
333 # Template
334 %= dumper [1, 2, 3]
335
336 # Application
337 my $serialized = $app->dumper([1, 2, 3]);
338
339 # Controller
340 my $serialized = $c->dumper([1, 2, 3]);
341
342 We differentiate between default helpers, which are more general
343 purpose like "dumper" in Mojolicious::Plugin::DefaultHelpers, and tag
344 helpers like "link_to" in Mojolicious::Plugin::TagHelpers, which are
345 template specific and mostly used to generate HTML tags.
346
347 %= link_to Mojolicious => 'https://mojolicious.org'
348
349 In controllers you can also use the method "helpers" in
350 Mojolicious::Controller to fully qualify helper calls and ensure that
351 they don't conflict with existing methods you may already have.
352
353 my $serialized = $c->helpers->dumper([1, 2, 3]);
354
355 A list of all built-in helpers can be found in
356 Mojolicious::Plugin::DefaultHelpers and
357 Mojolicious::Plugin::TagHelpers.
358
359 Static files
360 Static files are automatically served from the "public" directories of
361 the application, which can be customized with "paths" in
362 Mojolicious::Static, or one of the "DATA" sections from "classes" in
363 Mojolicious::Static. And if that's not enough you can also serve them
364 manually with "reply->static" in Mojolicious::Plugin::DefaultHelpers
365 and "reply->file" in Mojolicious::Plugin::DefaultHelpers.
366
367 use Mojolicious::Lite -signatures;
368
369 get '/' => sub ($c) {
370 $c->reply->static('index.html');
371 };
372
373 get '/some_download' => sub ($c) {
374 $c->res->headers->content_disposition('attachment; filename=bar.png;');
375 $c->reply->static('foo/bar.png');
376 };
377
378 get '/leak' => sub ($c) {
379 $c->reply->file('/etc/passwd');
380 };
381
382 app->start;
383
384 By default static files do not use a prefix and are simply served with
385 a higher precedence than routes. This can be changed with "prefix" in
386 Mojolicious::Static.
387
388 # Serve static files only with a "/static" prefix
389 $app->static->prefix('/static');
390
391 To allow for the prefix to be configured dynamically, you can use
392 "url_for_file" in Mojolicious::Controller to generate URLs with it.
393 Many tag helpers will also use the prefix automatically when it makes
394 sense.
395
396 Static assets
397 While Mojolicious does not have any special support for frontend
398 frameworks like Vue.js <https://vuejs.org> and React
399 <https://reactjs.org>, the "public/assets" directory is reserved for
400 static assets created by bundlers like Webpack <https://webpack.js.org>
401 and Rollup.js <https://rollupjs.org> ahead of time. Asset files can be
402 of any type, they just have to follow the
403 "[name].[checksum].[extensions]" naming scheme, like
404 "myapp.ab1234cd5678ef.js". You can then use "url_for_asset" in
405 Mojolicious::Controller or "asset_tag" in
406 Mojolicious::Plugin::TagHelpers to generate URLs without having to know
407 the checksum.
408
409 # "/assets/myapp.ab1234cd5678ef.js"
410 $c->url_for_asset('/myapp.js');
411
412 # "<script src="/assets/myapp.ab1234cd5678ef.js"></script>"
413 $c->asset_tag('/myapp.js');
414
415 If your application runs in "development" mode, all assets will be
416 served with a "Cache-Control: no-cache" header, to speed up development
417 by preventing browser caching. Additionally all assets following the
418 "[name].development.[extensions]" naming scheme, like
419 "myapp.development.js", have a higher precedence than assets with
420 checksums. That way you can just overwrite your assets during
421 development, instead of having to manually delete them each time they
422 are rebuilt with a different checksum.
423
424 # "/assets/foo/bar.development.js"
425 $c->url_for_asset('/foo/bar.js');
426
427 Webpack configuration <https://webpack.js.org/configuration/> example
428 ("webpack.config.js"):
429
430 import Path from '@mojojs/path';
431
432 const isDev = process.env.MOJO_MODE === 'development';
433
434 export default {
435 output: {
436 filename: isDev ? '[name].development.js' : '[name].[chunkhash].js',
437 path: Path.currentFile().sibling('public', 'assets').toString(),
438 publicPath: ''
439 },
440
441 // Add your own rules and entry point here
442 };
443
444 Rollup configuration <https://rollupjs.org/guide/en/#configuration-
445 files> example ("rollup.config.js"):
446
447 import Path from '@mojojs/path';
448
449 const isDev = process.env.MOJO_MODE === 'development';
450
451 export default {
452 output: {
453 entryFileNames: isDev ? '[name].development.[ext]' : '[name].[hash].[ext]',
454 dir: Path.currentFile().sibling('public', 'assets').toString(),
455 format: 'iife'
456 },
457
458 // Add your own rules and entry point here
459 };
460
461 Everything else is up to your bundler of choice, so you need to consult
462 its documentation for further information. And where you keep your
463 asset sources, such as ".vue" and ".jsx" files, is not important, as
464 long as your bundler can find them. Using a directory named "assets" or
465 "frontend" in your application root directory is a good best practice
466 though.
467
468 Content negotiation
469 For resources with different representations and that require truly
470 RESTful content negotiation you can also use "respond_to" in
471 Mojolicious::Plugin::DefaultHelpers instead of "render" in
472 Mojolicious::Controller.
473
474 # /hello (Accept: application/json) -> "json"
475 # /hello (Accept: application/xml) -> "xml"
476 # /hello.json -> "json"
477 # /hello.xml -> "xml"
478 # /hello?_format=json -> "json"
479 # /hello?_format=xml -> "xml"
480 $c->respond_to(
481 json => {json => {hello => 'world'}},
482 xml => {text => '<hello>world</hello>'}
483 );
484
485 The best possible representation will be automatically selected from
486 the "_format" "GET"/"POST" parameter, "format" stash value or "Accept"
487 request header and stored in the "format" stash value. To change MIME
488 type mappings for the "Accept" request header or the "Content-Type"
489 response header you can use "types" in Mojolicious.
490
491 $c->respond_to(
492 json => {json => {hello => 'world'}},
493 html => sub {
494 $c->content_for(head => '<meta name="author" content="sri">');
495 $c->render(template => 'hello', message => 'world')
496 }
497 );
498
499 Callbacks can be used for representations that are too complex to fit
500 into a single render call.
501
502 # /hello (Accept: application/json) -> "json"
503 # /hello (Accept: text/html) -> "html"
504 # /hello (Accept: image/png) -> "any"
505 # /hello.json -> "json"
506 # /hello.html -> "html"
507 # /hello.png -> "any"
508 # /hello?_format=json -> "json"
509 # /hello?_format=html -> "html"
510 # /hello?_format=png -> "any"
511 $c->respond_to(
512 json => {json => {hello => 'world'}},
513 html => {template => 'hello', message => 'world'},
514 any => {text => '', status => 204}
515 );
516
517 And if no viable representation could be found, the "any" fallback will
518 be used or an empty 204 response rendered automatically.
519
520 # /hello -> "html"
521 # /hello (Accept: text/html) -> "html"
522 # /hello (Accept: text/xml) -> "xml"
523 # /hello (Accept: text/plain) -> undef
524 # /hello.html -> "html"
525 # /hello.xml -> "xml"
526 # /hello.txt -> undef
527 # /hello?_format=html -> "html"
528 # /hello?_format=xml -> "xml"
529 # /hello?_format=txt -> undef
530 if (my $format = $c->accepts('html', 'xml')) {
531 ...
532 }
533
534 For even more advanced negotiation logic you can also use the helper
535 "accepts" in Mojolicious::Plugin::DefaultHelpers.
536
537 Rendering "exception" and "not_found" pages
538 By now you've probably already encountered the built-in 404 (Not Found)
539 and 500 (Server Error) pages, that get rendered automatically when you
540 make a mistake. Those are fallbacks for when your own exception
541 handling fails, which can be especially helpful during development. You
542 can also render them manually with the helpers "reply->exception" in
543 Mojolicious::Plugin::DefaultHelpers and "reply->not_found" in
544 Mojolicious::Plugin::DefaultHelpers.
545
546 use Mojolicious::Lite -signatures;
547 use Scalar::Util qw(looks_like_number);
548
549 get '/divide/:dividend/by/:divisor' => sub ($c) {
550
551 my $dividend = $c->param('dividend');
552 my $divisor = $c->param('divisor');
553
554 # 404
555 return $c->reply->not_found unless looks_like_number $dividend && looks_like_number $divisor;
556
557 # 500
558 return $c->reply->exception('Division by zero!') if $divisor == 0;
559
560 # 200
561 $c->render(text => $dividend / $divisor);
562 };
563
564 app->start;
565
566 To change the HTTP status code of the exception, you can use "rendered"
567 in Mojolicious::Controller.
568
569 return $c->reply->exception('Division by zero!')->rendered(400) if $divisor == 0;
570
571 You can also change the templates of those pages, since you most likely
572 want to show your users something more closely related to your
573 application in production. The renderer will always try to find
574 "exception.$mode.$format.*" or "not_found.$mode.$format.*" before
575 falling back to the built-in default templates.
576
577 use Mojolicious::Lite;
578
579 get '/dies' => sub { die 'Intentional error' };
580
581 app->start;
582 __DATA__
583
584 @@ exception.production.html.ep
585 <!DOCTYPE html>
586 <html>
587 <head><title>Server error</title></head>
588 <body>
589 <h1>Exception</h1>
590 <p><%= $exception->message %></p>
591 <h1>Stash</h1>
592 <pre><%= dumper $snapshot %></pre>
593 </body>
594 </html>
595
596 The default exception format is "html", but that can be changed at
597 application and controller level. By default there are handlers for
598 "html", "txt" and "json" available. There are also various exception
599 helpers in Mojolicious::Plugin::DefaultHelpers for you to overload to
600 change the default behavior.
601
602 use Mojolicious::Lite -signatures;
603
604 app->exception_format('json');
605
606 get '/json' => sub ($c) {
607 die 'Just a test';
608 };
609
610 get '/txt' => sub ($c) {
611 $c->exception_format('txt');
612 die 'Just a test';
613 };
614
615 app->start;
616
617 The hook "before_render" in Mojolicious makes even more advanced
618 customizations possible by allowing you to intercept and modify the
619 arguments passed to the renderer.
620
621 use Mojolicious::Lite -signatures;
622
623 hook before_render => sub ($c, $args) {
624
625 # Make sure we are rendering the exception template
626 return unless my $template = $args->{template};
627 return unless $template eq 'exception';
628
629 # Switch to JSON rendering if content negotiation allows it
630 return unless $c->accepts('json');
631 $args->{json} = {exception => $c->stash('exception')};
632 };
633
634 get '/' => sub { die "This sho...ALL GLORY TO THE HYPNOTOAD!\n" };
635
636 app->start;
637
638 Layouts
639 Most of the time when using "ep" templates you will want to wrap your
640 generated content in an HTML skeleton, thanks to layouts that's
641 absolutely trivial.
642
643 use Mojolicious::Lite;
644
645 get '/' => {template => 'foo/bar'};
646
647 app->start;
648 __DATA__
649
650 @@ foo/bar.html.ep
651 % layout 'mylayout';
652 Hello World!
653
654 @@ layouts/mylayout.html.ep
655 <!DOCTYPE html>
656 <html>
657 <head><title>MyApp</title></head>
658 <body><%= content %></body>
659 </html>
660
661 You just select the right layout template with the helper "layout" in
662 Mojolicious::Plugin::DefaultHelpers and place the result of the current
663 template with the helper "content" in
664 Mojolicious::Plugin::DefaultHelpers. You can also pass along normal
665 stash values to the "layout" helper.
666
667 use Mojolicious::Lite;
668
669 get '/' => {template => 'foo/bar'};
670
671 app->start;
672 __DATA__
673
674 @@ foo/bar.html.ep
675 % layout 'mylayout', title => 'Hi there';
676 Hello World!
677
678 @@ layouts/mylayout.html.ep
679 <!DOCTYPE html>
680 <html>
681 <head><title><%= $title %></title></head>
682 <body><%= content %></body>
683 </html>
684
685 Instead of the "layout" helper you could also just use the "layout"
686 stash value, or call "render" in Mojolicious::Controller with the
687 "layout" argument.
688
689 $c->render(template => 'mytemplate', layout => 'mylayout');
690
691 To set a "layout" stash value application-wide you can use "defaults"
692 in Mojolicious.
693
694 $app->defaults(layout => 'mylayout');
695
696 Layouts can also be used with "render_to_string" in
697 Mojolicious::Controller, but the "layout" value needs to be passed as a
698 render argument (not a stash value).
699
700 my $html = $c->render_to_string('reminder', layout => 'mail');
701
702 Partial templates
703 You can break up bigger templates into smaller, more manageable chunks.
704 These partial templates can also be shared with other templates. Just
705 use the helper "include" in Mojolicious::Plugin::DefaultHelpers to
706 include one template into another.
707
708 use Mojolicious::Lite;
709
710 get '/' => {template => 'foo/bar'};
711
712 app->start;
713 __DATA__
714
715 @@ foo/bar.html.ep
716 <!DOCTYPE html>
717 <html>
718 %= include '_header', title => 'Howdy'
719 <body>Bar</body>
720 </html>
721
722 @@ _header.html.ep
723 <head><title><%= $title %></title></head>
724
725 You can name partial templates however you like, but a leading
726 underscore is a commonly used naming convention.
727
728 Reusable template blocks
729 It's never fun to repeat yourself, that's why you can build reusable
730 template blocks in "ep" that work very similar to normal Perl
731 functions, with the "begin" and "end" keywords. Just be aware that both
732 keywords are part of the surrounding tag and not actual Perl code, so
733 there can only be whitespace after "begin" and before "end".
734
735 use Mojolicious::Lite;
736
737 get '/' => 'welcome';
738
739 app->start;
740 __DATA__
741
742 @@ welcome.html.ep
743 <% my $block = begin %>
744 % my $name = shift;
745 Hello <%= $name %>.
746 <% end %>
747 <%= $block->('Wolfgang') %>
748 <%= $block->('Baerbel') %>
749
750 A naive translation of the template to Perl code could look like this.
751
752 my $output = '';
753 my $block = sub ($name) {
754 my $output = '';
755 $output .= 'Hello ';
756 $output .= xml_escape scalar + $name;
757 $output .= '.';
758 return Mojo::ByteStream->new($output);
759 };
760 $output .= xml_escape scalar + $block->('Wolfgang');
761 $output .= xml_escape scalar + $block->('Baerbel');
762 return $output;
763
764 While template blocks cannot be shared between templates, they are most
765 commonly used to pass parts of a template to helpers.
766
767 Adding helpers
768 You should always try to keep your actions small and reuse as much code
769 as possible. Helpers make this very easy, they get passed the current
770 controller object as first argument, and you can use them to do pretty
771 much anything an action could do.
772
773 use Mojolicious::Lite -signatures;
774
775 helper debug => sub ($c, $str) {
776 $c->app->log->debug($str);
777 };
778
779 get '/' => sub ($c) {
780 $c->debug('Hello from an action!');
781 } => 'index';
782
783 app->start;
784 __DATA__
785
786 @@ index.html.ep
787 % debug 'Hello from a template!';
788
789 Helpers can also accept template blocks as last argument, this for
790 example, allows very pleasant to use tag helpers and filters. Wrapping
791 the helper result into a Mojo::ByteStream object can prevent accidental
792 double escaping.
793
794 use Mojolicious::Lite -signatures;
795 use Mojo::ByteStream;
796
797 helper trim_newline => sub ($c, $block) {
798 my $result = $block->();
799 $result =~ s/\n//g;
800 return Mojo::ByteStream->new($result);
801 };
802
803 get '/' => 'index';
804
805 app->start;
806 __DATA__
807
808 @@ index.html.ep
809 %= trim_newline begin
810 Some text.
811 %= 1 + 1
812 More text.
813 % end
814
815 Similar to stash values, you can use a prefix like "myapp.*" to keep
816 helpers from getting exposed in templates as functions, and to organize
817 them into namespaces as your application grows. Every prefix
818 automatically becomes a helper that returns a proxy object containing
819 the current controller object and on which you can call the nested
820 helpers.
821
822 use Mojolicious::Lite -signatures;
823
824 helper 'cache_control.no_caching' => sub ($c) { $c->res->headers->cache_control('private, max-age=0, no-cache') };
825 helper 'cache_control.five_minutes' => sub ($c) { $c->res->headers->cache_control('public, max-age=300') };
826
827 get '/news' => sub ($c) {
828 $c->cache_control->no_caching;
829 $c->render(text => 'Always up to date.');
830 };
831
832 get '/some_older_story' => sub ($c) {
833 $c->cache_control->five_minutes;
834 $c->render(text => 'This one can be cached for a bit.');
835 };
836
837 app->start;
838
839 While helpers can also be redefined, this should only be done very
840 carefully to avoid conflicts.
841
842 Content blocks
843 The helper "content_for" in Mojolicious::Plugin::DefaultHelpers allows
844 you to pass whole blocks of content from one template to another. This
845 can be very useful when your layout has distinct sections, such as
846 sidebars, where content should be inserted by the template.
847
848 use Mojolicious::Lite;
849
850 get '/' => 'foo';
851
852 app->start;
853 __DATA__
854
855 @@ foo.html.ep
856 % layout 'mylayout';
857 % content_for header => begin
858 <meta http-equiv="Content-Type" content="text/html">
859 % end
860 <div>Hello World!</div>
861 % content_for header => begin
862 <meta http-equiv="Pragma" content="no-cache">
863 % end
864
865 @@ layouts/mylayout.html.ep
866 <!DOCTYPE html>
867 <html>
868 <head><%= content 'header' %></head>
869 <body><%= content %></body>
870 </html>
871
872 Forms
873 To build HTML forms more efficiently you can use tag helpers like
874 "form_for" in Mojolicious::Plugin::TagHelpers, which can automatically
875 select a request method for you if a route name is provided. And since
876 most browsers only allow forms to be submitted with "GET" and "POST",
877 but not request methods like "PUT" or "DELETE", they are spoofed with
878 an "_method" query parameter.
879
880 use Mojolicious::Lite -signatures;
881
882 get '/' => 'form';
883
884 # PUT /nothing
885 # POST /nothing?_method=PUT
886 put '/nothing' => sub ($c) {
887
888 # Prevent double form submission with redirect
889 my $value = $c->param('whatever');
890 $c->flash(confirmation => "We did nothing with your value ($value).");
891 $c->redirect_to('form');
892 };
893
894 app->start;
895 __DATA__
896
897 @@ form.html.ep
898 <!DOCTYPE html>
899 <html>
900 <body>
901 % if (my $confirmation = flash 'confirmation') {
902 <p><%= $confirmation %></p>
903 % }
904 %= form_for nothing => begin
905 %= text_field whatever => 'I ♥ Mojolicious!'
906 %= submit_button
907 % end
908 </body>
909 </html>
910
911 The helpers "flash" in Mojolicious::Plugin::DefaultHelpers and
912 "redirect_to" in Mojolicious::Plugin::DefaultHelpers are often used
913 together to prevent double form submission, allowing users to receive a
914 confirmation message that will vanish if they decide to reload the page
915 they've been redirected to.
916
917 Form validation
918 You can use "validation" in Mojolicious::Plugin::DefaultHelpers to
919 validate "GET" and "POST" parameters submitted to your application. All
920 unknown fields will be ignored by default, so you have to decide which
921 should be required or optional before you can perform checks on their
922 values. Every check is performed right away, so you can use the results
923 immediately to build more advanced validation logic with methods like
924 "is_valid" in Mojolicious::Validator::Validation.
925
926 use Mojolicious::Lite -signatures;
927
928 get '/' => sub ($c) {
929
930 # Check if parameters have been submitted
931 my $v = $c->validation;
932 return $c->render('index') unless $v->has_data;
933
934 # Validate parameters ("pass_again" depends on "pass")
935 $v->required('user')->size(1, 20)->like(qr/^[a-z0-9]+$/);
936 $v->required('pass_again')->equal_to('pass') if $v->optional('pass')->size(7, 500)->is_valid;
937
938 # Check if validation failed
939 return $c->render('index') if $v->has_error;
940
941 # Render confirmation
942 $c->render('thanks');
943 };
944
945 app->start;
946 __DATA__
947
948 @@ index.html.ep
949 <!DOCTYPE html>
950 <html>
951 <head>
952 <style>
953 label.field-with-error { color: #dd7e5e }
954 input.field-with-error { background-color: #fd9e7e }
955 </style>
956 </head>
957 <body>
958 %= form_for index => begin
959 %= label_for user => 'Username (required, 1-20 characters, a-z/0-9)'
960 <br>
961 %= text_field 'user', id => 'user'
962 %= submit_button
963 <br>
964 %= label_for pass => 'Password (optional, 7-500 characters)'
965 <br>
966 %= password_field 'pass', id => 'pass'
967 <br>
968 %= label_for pass_again => 'Password again (equal to the value above)'
969 <br>
970 %= password_field 'pass_again', id => 'pass_again'
971 % end
972 </body>
973 </html>
974
975 @@ thanks.html.ep
976 <!DOCTYPE html>
977 <html><body>Thank you <%= validation->param('user') %>.</body></html>
978
979 Form elements generated with tag helpers from
980 Mojolicious::Plugin::TagHelpers will automatically remember their
981 previous values and add the class "field-with-error" for fields that
982 failed validation to make styling with CSS easier.
983
984 <label class="field-with-error" for="user">
985 Username (required, only characters e-t)
986 </label>
987 <input class="field-with-error" type="text" name="user" value="sri">
988
989 For a full list of available checks see also "CHECKS" in
990 Mojolicious::Validator.
991
992 Adding form validation checks
993 Validation checks can be registered with "add_check" in
994 Mojolicious::Validator and return a false value if they were
995 successful. A true value may be used to pass along additional
996 information which can then be retrieved with "error" in
997 Mojolicious::Validator::Validation.
998
999 use Mojolicious::Lite -signatures;
1000
1001 # Add "range" check
1002 app->validator->add_check(range => sub ($v, $name, $value, $min, $max) {
1003 return $value < $min || $value > $max;
1004 });
1005
1006 get '/' => 'form';
1007
1008 post '/test' => sub ($c) {
1009
1010 # Validate parameters with custom check
1011 my $v = $c->validation;
1012 $v->required('number')->range(3, 23);
1013
1014 # Render form again if validation failed
1015 return $c->render('form') if $v->has_error;
1016
1017 # Prevent double form submission with redirect
1018 $c->flash(number => $v->param('number'));
1019 $c->redirect_to('form');
1020 };
1021
1022 app->start;
1023 __DATA__
1024
1025 @@ form.html.ep
1026 <!DOCTYPE html>
1027 <html>
1028 <body>
1029 % if (my $number = flash 'number') {
1030 <p>Thanks, the number <%= $number %> was valid.</p>
1031 % }
1032 %= form_for test => begin
1033 % if (my $err = validation->error('number')) {
1034 <p>
1035 %= 'Value is required.' if $err->[0] eq 'required'
1036 %= 'Value needs to be between 3 and 23.' if $err->[0] eq 'range'
1037 </p>
1038 % }
1039 %= text_field 'number'
1040 %= submit_button
1041 % end
1042 </body>
1043 </html>
1044
1045 Cross-site request forgery
1046 CSRF is a very common attack on web applications that trick your logged
1047 in users to submit forms they did not intend to send, with something as
1048 mundane as a link. All you have to do, to protect your users from this,
1049 is to add an additional hidden field to your forms with "csrf_field" in
1050 Mojolicious::Plugin::TagHelpers, and validate it with "csrf_protect" in
1051 Mojolicious::Validator::Validation.
1052
1053 use Mojolicious::Lite -signatures;
1054
1055 get '/' => {template => 'target'};
1056
1057 post '/' => sub ($c) {
1058
1059 # Check CSRF token
1060 my $v = $c->validation;
1061 return $c->render(text => 'Bad CSRF token!', status => 403) if $v->csrf_protect->has_error('csrf_token');
1062
1063 my $city = $v->required('city')->param('city');
1064 $c->render(text => "Low orbit ion cannon pointed at $city!") unless $v->has_error;
1065 } => 'target';
1066
1067 app->start;
1068 __DATA__
1069
1070 @@ target.html.ep
1071 <!DOCTYPE html>
1072 <html>
1073 <body>
1074 %= form_for target => begin
1075 %= csrf_field
1076 %= label_for city => 'Which city to point low orbit ion cannon at?'
1077 %= text_field 'city', id => 'city'
1078 %= submit_button
1079 %= end
1080 </body>
1081 </html>
1082
1083 For Ajax requests and the like, you can also generate a token directly
1084 with the helper "csrf_token" in Mojolicious::Plugin::DefaultHelpers,
1085 and then pass it along with the "X-CSRF-Token" request header.
1086
1088 Less commonly used and more powerful features.
1089
1090 Template inheritance
1091 Inheritance takes the layout concept above one step further, the
1092 helpers "content" in Mojolicious::Plugin::DefaultHelpers and "extends"
1093 in Mojolicious::Plugin::DefaultHelpers allow you to build skeleton
1094 templates with named blocks that child templates can override.
1095
1096 use Mojolicious::Lite;
1097
1098 # first > mylayout
1099 get '/first' => {template => 'first', layout => 'mylayout'};
1100
1101 # third > second > first > mylayout
1102 get '/third' => {template => 'third', layout => 'mylayout'};
1103
1104 app->start;
1105 __DATA__
1106
1107 @@ layouts/mylayout.html.ep
1108 <!DOCTYPE html>
1109 <html>
1110 <head><title>Hello</title></head>
1111 <body><%= content %></body>
1112 </html>
1113
1114 @@ first.html.ep
1115 %= content header => begin
1116 Default header
1117 % end
1118 <div>Hello World!</div>
1119 %= content footer => begin
1120 Default footer
1121 % end
1122
1123 @@ second.html.ep
1124 % extends 'first';
1125 % content header => begin
1126 New header
1127 % end
1128
1129 @@ third.html.ep
1130 % extends 'second';
1131 % content footer => begin
1132 New footer
1133 % end
1134
1135 This chain could go on and on to allow a very high level of template
1136 reuse.
1137
1138 Custom responses
1139 Most response content, static as well as dynamic, gets served through
1140 Mojo::Asset::File and Mojo::Asset::Memory objects. For somewhat static
1141 content, like cached JSON data or temporary files, you can create your
1142 own and use the helper "reply->asset" in
1143 Mojolicious::Plugin::DefaultHelpers to serve them while allowing
1144 content negotiation to be performed with "Range", "If-Modified-Since"
1145 and "If-None-Match" headers.
1146
1147 use Mojolicious::Lite -signatures;
1148 use Mojo::Asset::File;
1149
1150 get '/leak' => sub ($c) {
1151 $c->res->headers->content_type('text/plain');
1152 $c->reply->asset(Mojo::Asset::File->new(path => '/etc/passwd'));
1153 };
1154
1155 app->start;
1156
1157 For even more control you can also just skip the helper and use
1158 "rendered" in Mojolicious::Controller to tell the renderer when you're
1159 done generating a response.
1160
1161 use Mojolicious::Lite -signatures;
1162 use Mojo::Asset::File;
1163
1164 get '/leak' => sub ($c) {
1165 $c->res->headers->content_type('text/plain');
1166 $c->res->content->asset(Mojo::Asset::File->new(path => '/etc/passwd'));
1167 $c->rendered(200);
1168 };
1169
1170 app->start;
1171
1172 Helper plugins
1173 Some helpers might be useful enough for you to share them between
1174 multiple applications, plugins make that very simple.
1175
1176 package Mojolicious::Plugin::DebugHelper;
1177 use Mojo::Base 'Mojolicious::Plugin', -signatures;
1178
1179 sub register ($self, $app, $conf) {
1180 $app->helper(debug => sub ($c, $str) {
1181 $c->app->log->debug($str);
1182 });
1183 }
1184
1185 1;
1186
1187 The "register" method will be called when you load the plugin. And to
1188 add your helper to the application, you can use "helper" in
1189 Mojolicious.
1190
1191 use Mojolicious::Lite -signatures;
1192
1193 plugin 'DebugHelper';
1194
1195 get '/' => sub ($c) {
1196 $c->debug('It works!');
1197 $c->render(text => 'Hello!');
1198 };
1199
1200 app->start;
1201
1202 A skeleton for a full CPAN compatible plugin distribution can be
1203 automatically generated.
1204
1205 $ mojo generate plugin DebugHelper
1206
1207 And if you have a "PAUSE" account (which can be requested at
1208 <http://pause.perl.org>), you are only a few commands away from
1209 releasing it to CPAN.
1210
1211 $ perl Makefile.PL
1212 $ make test
1213 $ make manifest
1214 $ make dist
1215 $ mojo cpanify -u USER -p PASS Mojolicious-Plugin-DebugHelper-0.01.tar.gz
1216
1217 Bundling assets with plugins
1218 Assets such as templates and static files can be easily bundled with
1219 your plugins, even if you plan to release them to CPAN.
1220
1221 $ mojo generate plugin AlertAssets
1222 $ mkdir Mojolicious-Plugin-AlertAssets/lib/Mojolicious/Plugin/AlertAssets
1223 $ cd Mojolicious-Plugin-AlertAssets/lib/Mojolicious/Plugin/AlertAssets
1224 $ mkdir public
1225 $ echo 'alert("Hello World!");' > public/alertassets.js
1226 $ mkdir templates
1227 $ echo '%= javascript "/alertassets.js"' > templates/alertassets.html.ep
1228
1229 Just give them reasonably unique names, ideally based on the name of
1230 your plugin, and append their respective directories to the list of
1231 search paths when "register" is called.
1232
1233 package Mojolicious::Plugin::AlertAssets;
1234 use Mojo::Base 'Mojolicious::Plugin', -signatures;
1235
1236 use Mojo::File qw(curfile);
1237
1238 sub register ($self, $app, $conf) {
1239
1240 # Append "templates" and "public" directories
1241 my $base = curfile->sibling('AlertAssets');
1242 push @{$app->renderer->paths}, $base->child('templates')->to_string;
1243 push @{$app->static->paths}, $base->child('public')->to_string;
1244 }
1245
1246 1;
1247
1248 Both will work just like normal "templates" and "public" directories
1249 once you've installed and loaded the plugin, with slightly lower
1250 precedence.
1251
1252 use Mojolicious::Lite;
1253
1254 plugin 'AlertAssets';
1255
1256 get '/alert_me';
1257
1258 app->start;
1259 __DATA__
1260
1261 @@ alert_me.html.ep
1262 <!DOCTYPE html>
1263 <html>
1264 <head>
1265 <title>Alert me!</title>
1266 %= include 'alertassets'
1267 </head>
1268 <body>You've been alerted.</body>
1269 </html>
1270
1271 And it works just the same for assets bundled in the "DATA" section of
1272 your plugin.
1273
1274 package Mojolicious::Plugin::AlertAssets;
1275 use Mojo::Base 'Mojolicious::Plugin', -signatures;
1276
1277 sub register ($self, $app, $conf) {
1278
1279 # Append class
1280 push @{$app->renderer->classes}, __PACKAGE__;
1281 push @{$app->static->classes}, __PACKAGE__;
1282 }
1283
1284 1;
1285 __DATA__
1286
1287 @@ alertassets.js
1288 alert("Hello World!");
1289
1290 @@ alertassets.html.ep
1291 %= javascript "/alertassets.js"
1292
1293 Post-processing dynamic content
1294 While post-processing tasks are generally very easy with the hook
1295 "after_dispatch" in Mojolicious, for content generated by the renderer
1296 it is a lot more efficient to use "after_render" in Mojolicious.
1297
1298 use Mojolicious::Lite -signatures;
1299 use IO::Compress::Gzip qw(gzip);
1300
1301 hook after_render => sub ($c, $output, $format) {
1302
1303 # Check if "gzip => 1" has been set in the stash
1304 return unless $c->stash->{gzip};
1305
1306 # Check if user agent accepts gzip compression
1307 return unless ($c->req->headers->accept_encoding // '') =~ /gzip/i;
1308 $c->res->headers->append(Vary => 'Accept-Encoding');
1309
1310 # Compress content with gzip
1311 $c->res->headers->content_encoding('gzip');
1312 gzip $output, \my $compressed;
1313 $$output = $compressed;
1314 };
1315
1316 get '/' => {template => 'hello', title => 'Hello', gzip => 1};
1317
1318 app->start;
1319 __DATA__
1320
1321 @@ hello.html.ep
1322 <!DOCTYPE html>
1323 <html>
1324 <head><title><%= title %></title></head>
1325 <body>Compressed content.</body>
1326 </html>
1327
1328 If you want to compress all dynamically generated content you can also
1329 activate "compress" in Mojolicious::Renderer.
1330
1331 Streaming
1332 You don't have to render all content at once, the method "write" in
1333 Mojolicious::Controller can also be used to stream a series of smaller
1334 chunks.
1335
1336 use Mojolicious::Lite -signatures;
1337
1338 get '/' => sub ($c) {
1339
1340 # Prepare body
1341 my $body = 'Hello World!';
1342 $c->res->headers->content_length(length $body);
1343
1344 # Start writing directly with a drain callback
1345 my $drain = sub ($c) {
1346 my $chunk = substr $body, 0, 1, '';
1347 $c->write($chunk, length $body ? __SUB__ : undef);
1348 };
1349 $c->$drain;
1350 };
1351
1352 app->start;
1353
1354 The drain callback will be executed whenever the entire previous chunk
1355 of data has actually been written.
1356
1357 HTTP/1.1 200 OK
1358 Date: Sat, 13 Sep 2014 16:48:29 GMT
1359 Content-Length: 12
1360 Server: Mojolicious (Perl)
1361
1362 Hello World!
1363
1364 Instead of providing a "Content-Length" header you can also call
1365 "finish" in Mojolicious::Controller and close the connection manually
1366 once you are done.
1367
1368 use Mojolicious::Lite -signatures;
1369
1370 get '/' => sub ($c) {
1371
1372 # Prepare body
1373 my $body = 'Hello World!';
1374
1375 # Start writing directly with a drain callback
1376 my $drain = sub ($c) {
1377 my $chunk = substr $body, 0, 1, '';
1378 length $chunk ? $c->write($chunk, __SUB__) : $c->finish;
1379 };
1380 $c->$drain;
1381 };
1382
1383 app->start;
1384
1385 While this is rather inefficient, as it prevents keep-alive, it is
1386 sometimes necessary for EventSource and similar applications.
1387
1388 HTTP/1.1 200 OK
1389 Date: Sat, 13 Sep 2014 16:48:29 GMT
1390 Connection: close
1391 Server: Mojolicious (Perl)
1392
1393 Hello World!
1394
1395 Chunked transfer encoding
1396 For very dynamic content you might not know the response content length
1397 in advance, that's where the chunked transfer encoding and
1398 "write_chunk" in Mojolicious::Controller come in handy. A common use
1399 would be to send the "head" section of an HTML document to the browser
1400 in advance and speed up preloading of referenced images and
1401 stylesheets.
1402
1403 use Mojolicious::Lite -signatures;
1404
1405 get '/' => sub ($c) {
1406 $c->write_chunk('<html><head><title>Example</title></head>' => sub ($c) {
1407 $c->finish('<body>Example</body></html>');
1408 });
1409 };
1410
1411 app->start;
1412
1413 The optional drain callback ensures that all previous chunks have been
1414 written before processing continues. To end the stream you can call
1415 "finish" in Mojolicious::Controller or write an empty chunk of data.
1416
1417 HTTP/1.1 200 OK
1418 Date: Sat, 13 Sep 2014 16:48:29 GMT
1419 Transfer-Encoding: chunked
1420 Server: Mojolicious (Perl)
1421
1422 29
1423 <html><head><title>Example</title></head>
1424 1b
1425 <body>Example</body></html>
1426 0
1427
1428 Especially in combination with long inactivity timeouts this can be
1429 very useful for Comet (long polling). Due to limitations in some web
1430 servers this might not work perfectly in all deployment environments.
1431
1432 Encoding
1433 Templates stored in files are expected to be "UTF-8" by default, but
1434 that can be easily changed with "encoding" in Mojolicious::Renderer.
1435
1436 $app->renderer->encoding('koi8-r');
1437
1438 All templates from the "DATA" section are bound to the encoding of the
1439 Perl script.
1440
1441 use Mojolicious::Lite;
1442
1443 get '/heart';
1444
1445 app->start;
1446 __DATA__
1447
1448 @@ heart.html.ep
1449 I ♥ Mojolicious!
1450
1451 Base64 encoded DATA files
1452 Base64 encoded static files such as images can be easily stored in the
1453 "DATA" section of your application, similar to templates.
1454
1455 use Mojolicious::Lite;
1456
1457 get '/' => {text => 'I ♥ Mojolicious!'};
1458
1459 app->start;
1460 __DATA__
1461
1462 @@ favicon.ico (base64)
1463 ...base64 encoded image...
1464
1465 Inflating DATA templates
1466 Templates stored in files get preferred over files from the "DATA"
1467 section, this allows you to include a default set of templates in your
1468 application that the user can later customize. The command
1469 Mojolicious::Command::Author::inflate will write all templates and
1470 static files from the "DATA" section into actual files in the
1471 "templates" and "public" directories.
1472
1473 $ ./myapp.pl inflate
1474
1475 Customizing the template syntax
1476 You can easily change the whole template syntax by loading
1477 Mojolicious::Plugin::EPRenderer with a custom configuration.
1478
1479 use Mojolicious::Lite;
1480
1481 plugin EPRenderer => {
1482 name => 'mustache',
1483 template => {
1484 tag_start => '{{',
1485 tag_end => '}}'
1486 }
1487 };
1488
1489 get '/:name' => {name => 'Anonymous'} => 'index';
1490
1491 app->start;
1492 __DATA__
1493
1494 @@ index.html.mustache
1495 Hello {{= $name }}.
1496
1497 Mojo::Template contains the whole list of available options.
1498
1499 Adding your favorite template system
1500 Maybe you would prefer a different template system than "ep", which is
1501 provided by Mojolicious::Plugin::EPRenderer, and there is not already a
1502 plugin on CPAN for your favorite one. All you have to do, is to add a
1503 new "handler" with "add_handler" in Mojolicious::Renderer when
1504 "register" is called.
1505
1506 package Mojolicious::Plugin::MyRenderer;
1507 use Mojo::Base 'Mojolicious::Plugin', -signatures;
1508
1509 sub register ($self, $app, $conf) {
1510
1511 # Add "mine" handler
1512 $app->renderer->add_handler(mine => sub ($renderer, $c, $output, $options) {
1513
1514 # Check for one-time use inline template
1515 my $inline_template = $options->{inline};
1516
1517 # Check for appropriate template in "templates" directories
1518 my $template_path = $renderer->template_path($options);
1519
1520 # Check for appropriate template in DATA sections
1521 my $data_template = $renderer->get_data_template($options);
1522
1523 # This part is up to you and your template system :)
1524 ...
1525
1526 # Pass the rendered result back to the renderer
1527 $$output = 'Hello World!';
1528
1529 # Or just die if an error occurs
1530 die 'Something went wrong with the template';
1531 });
1532 }
1533
1534 1;
1535
1536 An "inline" template, if provided by the user, will be passed along
1537 with the options. You can use "template_path" in Mojolicious::Renderer
1538 to search the "templates" directories of the application, and
1539 "get_data_template" in Mojolicious::Renderer to search the "DATA"
1540 sections.
1541
1542 use Mojolicious::Lite;
1543
1544 plugin 'MyRenderer';
1545
1546 # Render an inline template
1547 get '/inline' => {inline => '...', handler => 'mine'};
1548
1549 # Render a template from the DATA section
1550 get '/data' => {template => 'test'};
1551
1552 app->start;
1553 __DATA__
1554
1555 @@ test.html.mine
1556 ...
1557
1558 Adding a handler to generate binary data
1559 By default the renderer assumes that every "handler" generates
1560 characters that need to be automatically encoded, but this can be
1561 easily disabled if you're generating bytes instead.
1562
1563 use Mojolicious::Lite -signatures;
1564 use Storable qw(nfreeze);
1565
1566 # Add "storable" handler
1567 app->renderer->add_handler(storable => sub ($renderer, $c, $output, $options) {
1568
1569 # Disable automatic encoding
1570 delete $options->{encoding};
1571
1572 # Encode data from stash value
1573 $$output = nfreeze delete $c->stash->{storable};
1574 });
1575
1576 # Set "handler" value automatically if "storable" value is set already
1577 app->hook(before_render => sub ($c, $args) {
1578 $args->{handler} = 'storable' if exists $args->{storable} || exists $c->stash->{storable};
1579 });
1580
1581 get '/' => {storable => {i => '♥ mojolicious'}};
1582
1583 app->start;
1584
1585 The hook "before_render" in Mojolicious can be used to make stash
1586 values like "storable" special, so that they no longer require a
1587 "handler" value to be set explicitly.
1588
1589 # Explicit "handler" value
1590 $c->render(storable => {i => '♥ mojolicious'}, handler => 'storable');
1591
1592 # Implicit "handler" value (with "before_render" hook)
1593 $c->render(storable => {i => '♥ mojolicious'});
1594
1596 You can continue with Mojolicious::Guides now or take a look at the
1597 Mojolicious wiki <https://github.com/mojolicious/mojo/wiki>, which
1598 contains a lot more documentation and examples by many different
1599 authors.
1600
1602 If you have any questions the documentation might not yet answer, don't
1603 hesitate to ask in the Forum <https://forum.mojolicious.org>, on Matrix
1604 <https://matrix.to/#/#mojo:matrix.org>, or IRC
1605 <https://web.libera.chat/#mojo>.
1606
1607
1608
1609perl v5.38.0 2023-09-11 Mojolicious::Guides::Rendering(3)