Skip to content

English plugin dev 4 2

semuel edited this page Apr 16, 2012 · 6 revisions

Creating a new application

Application, in MT, is a xxxx.cgi file, that the web server execute independantly. MT uses different application for different purposes.

For example, mt.cgi is the main CMS application. mt-comments.cgi is the application handling comments and commenters.
The rule-of-thumb is the if there is a need of a different authentication schema, use a different application. Otherwise, you can just add methods to an existing application, as we seen in previous chapters.

For this chapter, we will create an application for viewing / editing MT::Foo objects that we introduced later chapter.

Creating a new Application

We will use MyPlugin11 (where we added MT::Foo) as the basis of this chapter

Specification

  • Should have three screens: view, edit and new, for creating, editing and listing MT::Foo objects
  • Able to create and save new objects, as well as edit existing ones
  • Encodes correctly while displaying the text parts of the MT::Foo objects, using encode_html=1 (we don’t want XSS attacks…)
  • For accessing the plugin we will use the URL http://www.example.com/cgi-bin/mt504/plugins/MyPlugin12/newapp.cgi?blog_id=2 (blog_id is required)

config.yaml

A config.yaml is not really necessary for adding an application, but adding one will make it appear in the plugin listing in the CMS, so nobody will forget that it is in place

id: MyPlugin12
key: MyPlugin12
name: <__trans phrase="Sample Plugin New Application">
version: 1.0
description: <__trans phrase="_PLUGIN_DESCRIPTION">
author_name: <__trans phrase="_PLUGIN_AUTHOR">
author_link: http://www.example.com/about/
doc_link: http://www.example.com/docs/
l10n_class: MyPlugin12::L10N

newapp.cgi

This is the CGI file that the server will run. As done in the mt-xxx.cgi files, we use MT::Bootstrap to start our application, that will be stored in the MyPlugin12::NewApp Perl module

#!/usr/bin/perl -w
use strict;

use lib '../../lib';
use lib '../../extlib';

use MT::Bootstrap App => 'MyPlugin12::NewApp';

If you are using Linux / OSX, be sure to make the file runnable

$ cd $MT_DIR/plugins/MyPlugin12/
$ sudo chmod +x newapp.cgi

MtPlugin12/NewApp.pm

The main body of the application. the init_request function is used for initize the application. The view, new, edit and save function provide the necessary functionality

package MyPlugin12::NewApp;
use strict;

use base qw( MT::App );

sub init_request {
    my $app = shift;
    $app->SUPER::init_request(@_);
    $app->add_methods( main => \&view,
                       view => \&view,
                       new  => \&foo_new,
                       edit => \&edit,
                       save => \&save,
                     );
    $app->{ default_mode }   = 'main';
    $app->{ requires_login } = 1;
}

sub view {
    my $app = shift;
    my $q = $app->param;
    my $blog_id = $q->param('blog_id');
    my $blog = MT->model('blog')->load($blog_id);
    my $class = $app->model('foo');
    my ( $terms, $args );
    $terms = { blog_id => $blog_id };
    $args  = { sort      => 'created_on',
               direction => 'descend',
               limit     => 10,
             };
    my @foos = $class->load( $terms, $args );
    my $param;
    $param = { blog_name   => $blog->name,
               foos        => \@foos,
               plugin_template_path => 'tmpl',
             };
    $app->build_page( 'view_foo.tmpl', $param );
}

sub edit {
    my $app = shift;
    my $q = $app->param;
    my $blog_id = $q->param('blog_id');
    my $blog = MT->model('blog')->load($blog_id);
    my $id = $q->param('id');
    my $class = $app->model('foo');
    my $foo = $class->load( $id );
    my $param;
    $param = { blog_name   => $blog->name,
               id      => $id,
               blog_id => $blog_id,
               title   => $foo->title(),
               bar     => $foo->bar(),
               plugin_template_path => 'tmpl',
             };
    $app->build_page( 'edit_foo.tmpl', $param );
}

sub save {
    my $app = shift;
    my $q = $app->param;
    my $blog_id = $q->param('blog_id');
    my $blog = MT->model('blog')->load($blog_id);
    my $class = $app->model('foo');
    my $foo;
    my $id;
    if ( $id = $q->param('id') ) {
        $foo = $class->load($id);
    } else {
        $foo = $class->new();
        $foo->blog_id($blog_id);
    }

    $foo->title($q->param('title'));
    $foo->bar($q->param('bar'));

    $foo->save()
        or die $foo->errstr;

    $app->redirect( $app->return_uri . "blog_id=$blog_id" );
}

sub foo_new {
    my $app = shift;
    my $q = $app->param;
    my $blog_id = $q->param('blog_id');
    my $blog = MT->model('blog')->load($blog_id);

    my $param = { blog_name => $blog->name,
                  blog_id   => $blog_id,
                };

    $app->build_page( 'new_foo.tmpl', $param );
}

1;

Commentary

package MyPlugin12::NewApp;
use strict;

use base qw( MT::App );
  • Declares the MyPlugin12::NewApp Perl module
  • This module will inherit from MT::App
sub init_request {
    my $app = shift;
    $app->SUPER::init_request(@_);
    $app->add_methods( main => \&view,
                       view => \&view,
                       new  => \&foo_new,
                       edit => \&edit,
                       save => \&save,
                     );
    $app->{ default_mode } = 'main';
    $app->{ requires_login } = 1;
}
  • This function is for initializing the application
  • Get $app
  • Call parent class’s init_request() for application-independent initializing
  • $app->add_methods() is used to tell MT which modes this application supports, and which function to call for each mode
    • Ties main and view to the view function (\&view)
    • Ties new to \&foo_new, edit to \&edit and save to \&save
  • $app->{ default_mode } = 'main'; if mode is not specified, use main
  • $app->{ requires_login } = 1; Specify if a user need to be logged in to use this application
    • 1 : Log-in is required. If the user is not logged in, he will be redirected to the login screen
    • 0 : The user can be either logged in or not, he still can use the application
sub view {
    my $app = shift;
    my $q = $app->param;
    my $blog_id = $q->param('blog_id');
    my $blog = MT->model('blog')->load($blog_id);
    my $class = $app->model('foo');
    my ( $terms, $args );
    $terms = { blog_id => $blog_id };
    $args  = { sort      => 'created_on',
               direction => 'descend',
               limit     => 10,
             };
    my @foos = $class->load( $terms, $args );
    my $param;
    $param = { blog_name   => $blog->name,
               foos        => \@foos,
               plugin_template_path => 'tmpl',
             };
    $app->build_page( 'view_foo.tmpl', $param );
}
  • This function display the listing of MT::Foo objects
  • Gets $app – the application handle
  • $q will hold the collection of the request parameters
  • Get $blog_id from the parameters
  • From $blog_id load the blog object
  • Prepare the class of the foo object type
  • Prepare the terms and args for loading the list of foo objects
  • Put all the needed data into $param, and use it to build the output page with $app->build_page( 'view_foo.tmpl', $param ); The template that will be used here is view_foo.tmpl (we will write it later)
sub edit {
    my $app = shift;
    my $q = $app->param;
    my $blog_id = $q->param('blog_id');
    my $blog = MT->model('blog')->load($blog_id);
    my $id = $q->param('id');
    my $class = $app->model('foo');
    my $foo = $class->load( $id );
    my $param;
    $param = { blog_name   => $blog->name,
               id      => $id,
               blog_id => $blog_id,
               title   => $foo->title(),
               bar     => $foo->bar(),
               plugin_template_path => 'tmpl',
             };
    $app->build_page( 'edit_foo.tmpl', $param );
}
  • This function will output the edit screen for a MT::Foo object
  • Gets $app – the application handle
  • $q will hold the collection of the request parameters
  • Get $blog_id from the parameters
  • From $blog_id load the blog object
  • Get $id from the parameters – the id of the MT::Foo object to edit
  • Prepare the class of the foo object type
  • Use $id to load the relevant MT::Foo object to $foo
  • Push all the relevant data into $param, and use it to build the page using $app->build_page( 'edit_foo.tmpl', $param );. the template file that will be used is edit_foo.tmpl
sub save {
    my $app = shift;
    my $q = $app->param;
    my $blog_id = $q->param('blog_id');
    my $blog = MT->model('blog')->load($blog_id);
    my $class = $app->model('foo');
    my $foo;
    my $id;
    if ( $id = $q->param('id') ) {
        $foo = $class->load($id);
    } else {
        $foo = $class->new();
        $foo->blog_id($blog_id);
    }

    $foo->title($q->param('title'));
    $foo->bar($q->param('bar'));

    $foo->save()
        or die $foo->errstr;

    $app->redirect( $app->return_uri . "blog_id=$blog_id" );
}
  • This function handles saving an edited / new foo object
  • Gets $app – the application handle
  • $q will hold the collection of the request parameters
  • Get $blog_id from the parameters
  • From $blog_id load the blog object
  • If id parameter is supplied, then this is an edit of existing object. Load the edited object
  • If there is not id parameter, this is a new object. create a new object, and set its blog_id using $foo->blog_id($blog_id)
  • Set the title and bar properties
  • Save $foo, print an error on failure
  • After saving, redirect the user to the next page
sub foo_new {
    my $app = shift;
    my $q = $app->param;
    my $blog_id = $q->param('blog_id');
    my $blog = MT->model('blog')->load($blog_id);

    my $param = { blog_name => $blog->name,
                  blog_id   => $blog_id,
                };

    $app->build_page( 'new_foo.tmpl', $param );
}
  • This function will output the screen for creating new foo objects
  • Gets $app – the application handle
  • $q will hold the collection of the request parameters
  • Get $blog_id from the parameters
  • From $blog_id load the blog object
  • Push all the relevant data into $param, and use it to build the page using $app->build_page( 'new_foo.tmpl', $param );. the template file that will be used is new_foo.tmpl

tmpl/view_foo.tmpl

The template of the MT::Foo object listing screen

<html>
<head>
    <title>MT::Foo View</title>
</head>
<body>
<h1><mt:var name="blog_name" encode_html=1/></h1>

    <ul>
<mt:loop name="foos">
        <li><a href="<mt:GetVar name="script_url" />?__mode=edit&amp;id=<mt:GetVar name="id" />&amp;blog_id=<mt:GetVar name="blog_id" />"><mt:GetVar name="title" encode_html=1/></a></li>
</mt:loop>
    </ul>

<p><a href="<mt:GetVar name="script_url" />?__mode=new&amp;blog_id=2">New</a></p>

</body>
</html>

tmpl/edit_foo.tmpl

The screen to edit an existing foo object

<html>
<head>
    <title>MT::Foo Edit</title>
</head>
<body>
<h1><mt:var name="blog_name" /></h1>

<form method="post" action="<mt:GetVar name="script_url" escape_html=1 />">
<input type="hidden" name="__mode" value="save">
<input type="hidden" name="id" value="<mt:GetVar name="id">">
<input type="hidden" name="blog_id" value="<mt:GetVar name="blog_id">">
<table border="2">
    <tr><td>id</td><td><mt:GetVar name="id"></td></tr>
    <tr><td>blog_id</td><td><mt:GetVar name="blog_id"></td></tr>
    <tr><td>title</td><td><input name="title" type="text" value="<mt:GetVar name="title" escape_html=1>"></td></tr>
    <tr><td>bar</td><td><textarea name="bar"><mt:GetVar name="bar" escape_html=1></textarea></td></tr>
</table>
<br />
<input type="submit"><input type="reset">
</form>

<p><a href="<mt:GetVar name="script_url" />?__mode=main&amp;blog_id=2">Back</a></p>

</body>
</html>

tmpl/new_foo.tmpl

The screen for entering a new foo object

<html>
<head>
    <title>MT::Foo New</title>
</head>
<body>
<h1><mt:var name="blog_name" /></h1>

<form method="post" action="<mt:GetVar name="script_url" />">
<input type="hidden" name="__mode" value="save">
<input type="hidden" name="blog_id" value="<mt:GetVar name="blog_id">">
<table border="2">
    <tr><td>blog_id</td><td><mt:GetVar name="blog_id"></td></tr>
    <tr><td>title</td><td><input name="title" type="text" value="<mt:GetVar name="title">"></td></tr>
    <tr><td>bar</td><td><textarea name="bar"><mt:GetVar name="bar"></textarea></td></tr>
</table>
<br />
<input type="submit">
</form>

<p><a href="<mt:GetVar name="script_url" />?__mode=main&amp;blog_id=2">Back</a></p>

</body>
</html>

Directory Structure

$MT_DIR/
|__ plugins/
   |__ MyPlugin12/
      |__ config.yaml
      |__ lib/
      |  |_ MyPlugin12/
      |     |__ L10N.pm
      |     |_ L10N/
      |     |  |_ en_us.pm
      |     |  |_ ja.pm
      |     |__ NewApp.pm
      |__ newapp.cgi
      |__ tmpl/
         |_ edit_foo.tmpl
         |_ new_foo.tmpl
         |_ view_foo.tmpl

Plugin Download

MyPlugin12.zip(4.34KB)

Summary

The independent application option gives us a very interesting ability to work outside of the regular MT framework, and you get to decide how far from the regular you want to be, by overriding selected functions of the MT::App class.

Of course, there are very few cases that I saw where it was used, and of them it was unnecessary in some, but still, better to have it in our toolbox…

Navigation

Prev:Creating Your Own Objects << Index >> Next:Developing a transformer plug-in

Clone this wiki locally