The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Konstrukt::Doc::Tutorial::Plugin::Note::Actions - 1) Create a simple note taking plugin performing different actions

DESCRIPTION

This tutorial will teach you how to create a simple plugin, which uses the CGI-action -> plugin-method mapping to perform different tasks according to an action CGI parameter.

This is especially useful, when writing a plugin, where the user can perform several actions like creating content, viewing it, deleting it and so on.

Note: For the setup of the usage of custom plugins see "SETUP" in Konstrukt::Doc::Tutorial::Plugin::Randomline.

CREATE THE PLUGIN

We will create a plugin, that by default shows a note, that is stored in a text file on the server (if exists). It also shows a link to actions, which allow the user to edit and delete the note.

We can identify these actions:

  • default: show the note, if exists

  • edit: show a form to edit the note or save the note, if a new one is entered

  • delete: show a confirmation to delete to note or delete the note if the deletion has been confirmed

First, create a file (e.g. note.html) with this content:

        <& note / &>
        <a href="?">show</a>

Create a file note.pm in your custom plugin directory with this skeleton:

        package Konstrukt::Plugin::note;
        
        use strict;
        use warnings;
        
        use base 'Konstrukt::SimplePlugin';
        
        #show the note if exists
        sub default : Action {
                my ($self, $tag, $content, $params) = @_;
                print 'note action';
        }
        
        #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) = @_;
                print 'edit action';
        }
        
        #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) = @_;
                print 'delete action';
        }
        
        1;

You can now point your web browser to the web page (e.g. note.html) and you will see the text:

        note action

which is the output of the default action.

You can manually specify the actions, that should be executed by supplying the CGI parameter note_action. For example, you could call the website with the URL note.html?note_action=edit and you'll see this text:

        edit action

If you enter an action, that does not exist, an error will be produced. If you enter no action, the default action will be executed. Note that you must add the : Action attribute to your methods to let them be accessible from the outside.

ADD THE LOGIC

We want to read a file from disk and display the contents on the web page. If no note exists, display a form to create one. So we replace the print statement of the default action with this code:

        my $text = $Konstrukt::File->read("/note.txt");
        if (defined $text) {
                print $text;
                print '
                        <br />
                        <a href="?note_action=edit">edit</a><br />
                        <a href="?note_action=delete">delete</a>';
        } else {
                $self->edit($tag, $content, $params);
        }

Now we add the functionality to edit the note. If no text is specified and a note already exists, a form with the existing text will be displayed. Otherwise an empty form will be displayed. If a new text is specified, we overwrite the existing node.

We replace the print statement of the edit action with this code:

        if (exists $params->{text}) {
                #overwrite note
                $Konstrukt::File->write("/note.txt", $params->{text});
                $self->default($tag, $content, $params);
        } else {
                #display a form to edit the note
                my $text = $Konstrukt::File->read("/note.txt") || '(no note yet)';
                print "
                        <form action=\"\" method=\"post\">
                                <input type=\"hidden\" name=\"note_action\" value=\"edit\" />
                                <textarea name=\"text\">$text</textarea>
                                <input type=\"submit\" value=\"Save\" />
                        </form>";
        }

Now we only need to handle the deletion of the note. If the CGI parameter delete is true, the file will be deleted. Otherwise a confirmation to delete the file will be displayed.

We replace the print statement of the delete action with this code:

        if (exists $params->{delete} and $params->{delete}) {
                #delete note
                unlink $Konstrukt::File->absolute_path("/note.txt");
                print "Note deleted!\n";
                $self->default($tag, $content, $params);
        } else {
                #display a confirmation form
                print "
                        <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>";
        }

That's it! Restart/reload your Apache, and try it out.

WHAT'S NEXT?

That's a minimal example. Usually you should not print out HTML from your plugins - instead you should use templates, which contain the HTML.

Also the hardcoded filename to the file containing the note is not very flexible. You might use a filename that is specified in a tag attribute:

        <& note file="/foo.txt" / &>

This can then be accessed though the $tag reference:

        my $filename = $tag->{tag}->{attributes}->{file};

Additionally you could just store the note in a database.

Templating and database usage are topics of the next tutorials.

APPENDIX: THE COMPLETE PLUGIN

        package Konstrukt::Plugin::note;
        
        use strict;
        use warnings;
        
        use base 'Konstrukt::SimplePlugin';
        
        #show the note, if exists
        sub default : Action {
                my ($self, $tag, $content, $params) = @_;
                
                my $text = $Konstrukt::File->read("/note.txt");
                if (defined $text) {
                        print $text;
                        print '
                                <br />
                                <a href="?note_action=edit">edit</a><br />
                                <a href="?note_action=delete">delete</a>';
                } 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) = @_;
                
                if (exists $params->{text}) {
                        #overwrite note
                        $Konstrukt::File->write("/note.txt", $params->{text});
                        $self->default($tag, $content, $params);
                } else {
                        #display a form to edit the note
                        my $text = $Konstrukt::File->read("/note.txt") || '(no note yet)';
                        print "
                                <form action=\"\" method=\"post\">
                                        <input type=\"hidden\" name=\"note_action\" value=\"edit\" />
                                        <textarea name=\"text\">$text</textarea>
                                        <input type=\"submit\" value=\"Save\" />
                                </form>";
                }
        }
        
        #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) = @_;
                
                if (exists $params->{delete} and $params->{delete}) {
                        #delete note
                        unlink $Konstrukt::File->absolute_path("/note.txt");
                        print "Note deleted!\n";
                        $self->default($tag, $content, $params);
                } else {
                        #display a confirmation form
                        print "
                                <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>";
                }
        }
        
        1;

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::Template

Previous: Konstrukt::Doc::Tutorial::Plugin::Randomline

Parent: Konstrukt::Doc

See also: Konstrukt::SimplePlugin, Konstrukt::Doc::CreatingPlugins, Konstrukt::File