NAME
Konstrukt::Doc::Tutorial::Plugin::Note::Template - 2) Using templates for the presentation
DESCRIPTION
This tutorial will teach you how to use templates for the output of your plugin. This is the preferred way to handle the presentation layer of your application.
Note: This tutorial builds up on the results of the previous tutorial.
CONVENTIONS AND SETTINGS
By convention the templates for each plugin are stored in a separate directory for each plugin. The path to this directory will usually be defined as a setting, which defaults to /templates/plugin_name/
.
So we add the init
method, in which we set the default template path for this plugin:
sub init {
my ($self) = @_;
$Konstrukt::Settings->default("note/template_path" => '/note/blog/');
$self->{template_path} = $Konstrukt::Settings->get("note/template_path");
return 1;
}
Additionally the templates are usually divided into two groups, which will be stored in these subdirectories:
layout: Templates to display the data
messages: Templates to display messages like errors (e.g. "permission denied") and confirmations (e.g. "entry successfully created")
THE TEMPLATES
For our note taking plugin, we can identify these views, for each we will use a template:
layout/note_show.template: Show the note.
layout/note_edit.template: Show the form to edit the note.
layout/note_delete.template: Show the confirmation to delete the note.
messages/edit_successful.template: The update was successful.
messages/delete_successful.template: The deletion was successful.
We won't offer a separate message for possible failures here, although you might do so for common errors that can occur.
The Konstrukt Framework offers a nifty autoinstallation feature for your templates (as well as for database definitions).
So we create an install
method for this plugin first, which uses this feature:
sub install {
my ($self) = @_;
return $Konstrukt::Lib->plugin_file_install_helper($self->{template_path});
}
Then we add a __DATA__
token at the end of the module file and after that we add the templates, which are separated like described in "plugin_file_install_helper" in Konstrukt::Lib:
-- 8< -- textfile: layout/note_show.template -- >8 --
<div class="note entry">
<h1>Current note</h1>
<+$ text $+>(no text)<+$ / $+>
</div>
-- 8< -- textfile: layout/note_edit.template -- >8 --
<div class="note form edit">
<form action="" method="post">
<input type="hidden" name="note_action" value="edit" />
<textarea name="text"><+$ text $+>(no text yet)<+$ / $+></textarea>
<input type="submit" value="Save" />
</form>
</div>
-- 8< -- textfile: layout/note_delete.template -- >8 --
<div class="note form delete">
<form action="" method="post">
<input type="hidden" name="note_action" value="delete" />
<input type="checkbox" id="delete" name="delete" value="1" />
<label for="delete">Really delete the note?</label>
<input type="submit" value="Delete" />
</form>
</div>
-- 8< -- textfile: messages/edit_successful.template -- >8 --
<div class="note message success">
<h1>Note updated!</h1>
<p>The note has been updated successfully.</p>
</div>
-- 8< -- textfile: messages/delete_successful.template -- >8 --
<div class="note message success">
<h1>Note deleted!</h1>
<p>The note has been deleted successfully.</p>
</div>
The templates will then be created automatically when the plugin is used and the setting autoinstall
is set to 1
. So we enable the autoinstallation in the konstrukt.settings
file:
autoinstall 1
MODIFY THE CODE
Until now, we print HTML markup directly from the code. We will now change the code to use the templates, we defined above.
We will use the template plugin to put out the templates. First we add
use Konstrukt::Plugin; #import use_plugin
at the top of the module to import the use_plugin
function. Within the methods we can then get a template plugin object like this:
my $template = use_plugin 'template';
In general, we will replace each print
statements with a commmand, that will add a template node to the result of this plugin request.
For example the print
statement of the default
action
print "
<form action=\"\" method=\"post\">
<input type=\"hidden\" name=\"note_action\" value=\"edit\" />
<textarea name=\"text\">$text</textarea>
<input type=\"submit\" value=\"Save\" />
</form>";
will be replaced by
$self->add_node(
$template->node("$self->{template_path}layout/note_show.template", { text => $text })
);
This command will add new node to the result. In particular it is a template plugin node, which loads the template layout/note_show.template
and fills the variables of this template with the specified values ("fill the text
template-variable with the contents of the $text
perl-variable").
As the procedure is mostly the same for the other methods, it won't be described for every single change. See below for the code with templates instead of print
statements.
WHAT'S NEXT?
Saving dynamic content in text files doesn't scale well. It would be better to save it in a database.
This will be done in the next tutorial.
APPENDIX: THE COMPLETE PLUGIN
package Konstrukt::Plugin::note;
use strict;
use warnings;
use base 'Konstrukt::SimplePlugin';
use Konstrukt::Plugin; #import use_plugin
sub init {
my ($self) = @_;
$Konstrukt::Settings->default("note/template_path" => '/templates/note/');
$self->{template_path} = $Konstrukt::Settings->get("note/template_path");
return 1;
}
sub install {
my ($self) = @_;
return $Konstrukt::Lib->plugin_file_install_helper($self->{template_path});
}
#show the note if exists
sub default : Action {
my ($self, $tag, $content, $params) = @_;
my $template = use_plugin 'template';
my $text = $Konstrukt::File->read("/note.txt");
if (defined $text) {
#add a template node to the result, that will display the specified template
$self->add_node(
$template->node("$self->{template_path}layout/note_show.template", { text => $text })
);
} else {
$self->edit($tag, $content, $params);
}
}
#show a form to edit the note or save the note, if a new one is entered
sub edit : Action {
my ($self, $tag, $content, $params) = @_;
my $template = use_plugin 'template';
if (exists $params->{text}) {
#overwrite note
$Konstrukt::File->write("/note.txt", $params->{text});
$self->add_node($template->node("$self->{template_path}messages/edit_successful.template"));
$self->default($tag, $content, $params);
} else {
#display a form to edit the note
$self->add_node(
$template->node(
"$self->{template_path}layout/note_edit.template",
{ text => $Konstrukt::File->read("/note.txt") }
)
);
}
}
#show a confirmation to delete to note
#or delete the note if the deletion has been confirmed
sub delete : Action {
my ($self, $tag, $content, $params) = @_;
my $template = use_plugin 'template';
if (exists $params->{delete} and $params->{delete}) {
#delete note
unlink $Konstrukt::File->absolute_path("/note.txt");
$self->add_node($template->node("$self->{template_path}messages/delete_successful.template"));
$self->default($tag, $content, $params);
} else {
#display a confirmation form
$self->add_node($template->node("$self->{template_path}layout/note_delete.template"));
}
}
1;
__DATA__
-- 8< -- textfile: layout/note_show.template -- >8 --
<div class="note entry">
<h1>Current note</h1>
<+$ text $+>(no text)<+$ / $+>
</div>
-- 8< -- textfile: layout/note_edit.template -- >8 --
<div class="note form edit">
<form action="" method="post">
<input type="hidden" name="note_action" value="edit" />
<textarea name="text"><+$ text $+>(no text yet)<+$ / $+></textarea>
<input type="submit" value="Save" />
</form>
</div>
-- 8< -- textfile: layout/note_delete.template -- >8 --
<div class="note form delete">
<form action="" method="post">
<input type="hidden" name="note_action" value="delete" />
<input type="checkbox" id="delete" name="delete" value="1" />
<label for="delete">Really delete the note?</label>
<input type="submit" value="Delete" />
</form>
</div>
-- 8< -- textfile: messages/edit_successful.template -- >8 --
<div class="note message success">
<h1>Note updated!</h1>
<p>The note has been updated successfully.</p>
</div>
-- 8< -- textfile: messages/delete_successful.template -- >8 --
<div class="note message success">
<h1>Note deleted!</h1>
<p>The note has been deleted successfully.</p>
</div>
AUTHOR
Copyright 2006 Thomas Wittek (mail at gedankenkonstrukt dot de). All rights reserved.
This document is free software. It is distributed under the same terms as Perl itself.
SEE ALSO
Next: Konstrukt::Doc::Tutorial::Plugin::Note::DBI
Previous: Konstrukt::Doc::Tutorial::Plugin::Note::Actions
Parent: Konstrukt::Doc
See also: Konstrukt::SimplePlugin, Konstrukt::Doc::CreatingPlugins, Konstrukt::Plugin::template