Movable Type Open Source Project を活用しよう。



Junnama Noda (Alfasado,Inc.)@KOF2007

Web制作 - アルファサード

自己紹介

本日のお題

Inside MT (Movable Typeの構成)

設定ファイルmt-config.cgi設定ファイル
Perl CGImt.cgiCMS本体
mt-comments.cgiコメントCGI
mt-search.cgi検索CGI
mt-tb.cgiトラックバックCGI
ライブラリlib/Perlモジュール
extlib/その他のPerlモジュール
PHPファイルphp/PHPダイナミックパブリッシング関連
CMSテンプレートtmpl/CMSのテンプレート
alt-tmpl/代替テンプレート
プラグインplugins/プラグイン
静的ファイルmt-static/CSS/Image/JavaScript等の静的ファイル

Movable Typeって何だろう?


強力なWeb アプリケーションフレームワーク!

MT Perl APIの基礎

#!/usr/bin/perl -w
use strict;
use lib '/path/to/mt/lib';
use MT;

my $mt = MT->new(Config => '/path/to/mt/mt-config.cgi');

print "content-type: text/plain; charset=utf-8¥n¥n";

my @entries = MT::Entry->load();
foreach my $entry (@entries) {
    print $entry->title . "¥t" . $entry->permalink . "¥n";
}

データベースアクセスとMT::Objectのサブクラス作成(1)

/mt/plugins/TemplateSelector/lib/Selector.pm

#!/usr/bin/perl -w
package TemplateSelector::Selector;
use strict;
@TemplateSelector::Selector::ISA = qw( MT::Object );
__PACKAGE__->install_properties({
	column_defs => {
		'id' => 'integer not null auto_increment',
		'blog_id' => 'integer not null',
		'entry_id' => 'integer not null',
		'template_name' => 'string(255)',
	},
	indexes => {
		blog_id => 1,
		entry_id => 1,
		template_name => 1,
	},
	child_of => 'MT::Entry',
	datasource => 'selector',
	primary_key => 'id',
});
1;

データベースアクセスとMT::Objectのサブクラス作成(2)

/mt/plugins/TemplateSelector/TemplateSelector.pl

package MT::Plugin::TemplateSelector;
use strict;
use MT;
use MT::Plugin;
use TemplateSelector::Selector;
require MT::Plugin;
use base qw( MT::Plugin );
@MT::Plugin::TemplateSelector::ISA = qw(MT::Plugin);
my $plugin = new MT::Plugin::TemplateSelector({
    name => 'TemplateSelector',
    'schema_version' => '1.0',
});

データベースアクセスとMT::Objectのサブクラス作成(3)

use TemplateSelector::Selector;
my $selector  = TemplateSelector::Selector->load(
                                                                { blog_id  => 1,
                                                                  entry_id => 1 } );
my @selectors = TemplateSelector::Selector->load(
                                                                { blog_id  => 1 },
                                                                { sort => 'entry_id',
                                                                  direction => 'descend', 
                                                                  limit => 10, } );
my $iter = TemplateSelector::Selector->load_iter(
                                                                { blog_id  => 1},
                                                                { sort => 'entry_id',
                                                                  direction => 'descend', 
                                                                  limit => 10, } );

データベースアクセスとMT::Objectのサブクラス作成(4)

簡単にテーブルを拡張できて,
RDBMSを問わず同じ書き方でアクセスできる

MTのテンプレートエンジン(1)






	<MTMyEntries>
		<MTMyEntryTitle>	<MTMyEntryPermalink>
	</MTMyEntries>



MTのテンプレートエンジン(2)

sub init_registry {
    my $plugin = shift;
    $plugin->registry({
        tags => {
            block => {
                'MyEntries' => ¥_entries,
            function => {
                'MyEntryTitle' => ¥_entry_title,
            function => {
                'MyEntryPermalink' => ¥_entry_permalink,
            },
        }
   });
}

MTのテンプレートエンジン(3)

sub _entries {
    my ($ctx, $args, $cond) = @_;
    my $tokens = $ctx->stash('tokens');
    my $builder = $ctx->stash('builder');
    my $blog = $ctx->stash('blog');
    my @entries = MT::Entry->load( { blog_id => $blog->id } );
    my $res = '';
    foreach my $entry (@ entries) {
        local $ctx->{__stash}{'entry'} = $entry;
        my $out = $builder->build($ctx, $tokens, $cond);
        $res .= $out;
    }
    $res;
}

sub _entry_title {
    my $entry = $ctx->stash('entry');
    return $entry->title;
}

sub _entry_permalink {
    return $entry->permalink;
}

MTのテンプレートエンジン(4) - CMS編

<mt:setvarblock name="page_title">
 <$mt:var name="page_title"$>
</mt:setvarblock>
<mt:include name="include/header.tmpl">
<div id="msg-block">
 <div id="saved-changes" class="msg msg-success">
  <a href="javascript:void(0)"
        onclick="javascript:hide('saved-changes');return false;"
        class="close-me"><span>close</span></a>
 <$mt:var name="page_msg"$>
 </div>
</div>
<mt:include name="include/footer.tmpl">

MTのテンプレートエンジン(5) - CMS編

sub _clear_cache {
    my $app = shift;

    # do something

    $app->{plugin_template_path} 
        = File::Spec->catdir($plugin->path,'tmpl');
    my %param;
    $param{'page_title'} = $plugin->translate('Clear Cache');
    $param{'page_msg'} = $plugin->translate('Cache Cleared.');
    my $tmpl = 'clear_cache.tmpl';
    return $app->build_page($tmpl, ¥%param);
}

Perlプラグインによる拡張

sub init_registry {
    my $plugin = shift;
    $plugin->registry({
        object_types => {
            # 新しいテーブルを登録したり既存のテーブルを拡張
        },
        callbacks => {
            'MT::App::CMS::template_source.foo'
                => # テンプレートのソースに対する処理
            'MT::App::CMS::template_param.foo'
                => # テンプレートに渡すパラメタを定義
            'cms_post_save.foo'
                => # オブジェクトfooが保存された直後の処理
            'build_file_filter'
                => # 再構築の直前
        },
        tags => {
            block => {
                'Iffoo?' => # 条件分岐のタグ,
                'foo' => # ブロック(ループなど)タグ,
            function => {
                'bar' => # ファンクションタグ,
            function => {
                'bar' => # ファンクションタグ,
            modifier => {
                'baz' => # タグ属性(フィルター),
            },
        },
        applications => {
            cms => {
                menus => {
                    'create:buzz' => {
                        label => # メニューのテキスト,
                        dialog => # ダイアログ名,
                        order => # メニューの表示順,
                        permission => # 権限,
                        view   => # CMSの各ブログ画面で有効に,
                    },
                    'manage:fizz' => {
                        label => # メニューのテキスト,
                        mode => 'hoge', # 新しいモード mt.cgi?__mode=hoge...
                        order => # メニューの表示順,
                        permission =>  # 権限,
                    },
                    methods => {
                        buzz => # ダイアログの処理
                                'MT::Plugin::MyPlugin::buzz', 
                        hoge => # モード実行時の処理
                                'MT::Plugin::MyPlugin::hoge',
                    },
                },
            },
        },
   });
}

Bootstrap.pmを利用したアプリ開発(1)

/mt/plugins/SimpleAuth/SimpleAuth.cgi




#!/usr/bin/perl -w

use strict;
use lib 'lib';
use lib '../../lib';
use lib '../../extlib';
use MT::Bootstrap App => 'SimpleAuth';

Bootstrap.pmを利用したアプリ開発(2)

/mt/plugins/SimpleAuth/lib/SimpleAuth.pm


package SimpleAuth;
use strict;
use MT::App;
@SimpleAuth::ISA = qw(MT::App);

sub init_request {
	my $app = shift;
	$app->SUPER::init_request(@_);
	$app->{default_mode} = 'unprotected';
	$app->{requires_login} = 1 unless $app->mode eq 'unprotected';
	$app->add_methods( unprotected => ¥&_unprotected );
	$app->add_methods( login => ¥&_login );
	$app;
}
sub _unprotected {
    my $app = shift;
    my $login = $app->login;
    if (defined $login) {
        return 'Hi! ' . $app->user->nickname . ', Welcome to MTOS!';
    } else {
        my $tmpl = 'login.tmpl';
        my %param;
        $app->set_header('Status','401 Unauthorized');
        return $app->build_page($tmpl, ¥%param);
	}
}

PHPによるダイナミックパブリッシング(1)

/mt/plugins/HelloWorld/php/mthelloworld.php





<?php
function smarty_function_mthelloworld ($args, &$ctx) {
    return 'Hello World!';
}
?>


PHPによるダイナミックパブリッシング(2)

/mt/plugins/HelloWorld/php/mtblognamefromdb.php

<?php
function smarty_function_mtblognamefromdb ($args, &$ctx) {
    $param = getenv('REDIRECT_QUERY_STRING');
    parse_str($param);
    if ($blog_id) {
        if (preg_match("/^[0-9]+$/", $blog_id)) {
            $sql = "SELECT blog_name "
                 . "FROM mt_blog "
                 . "WHERE blog_id=$blog_id ";
            $results = $ctx->mt->db->get_results( $sql , ARRAY_N );
            if (count($results)) {
                return $results[0][0];
            }
        }
    }
}
?>

オープンソースならではの活用方法を考えよう

MTOS MT4 個人利用 MT4 商用利用
費用 無料 無料 有料
商用利用はok? Yes No Yes
個人的利用はok? Yes Yes Yes
作成出来る
ブログ数は?
無制限 無制限 無制限
ログイン
ユーザー数は?
無制限 無制限 ユーザー数に
よって課金
される
再配布可能? Yes No No
サポートは? コミュニティ
から
Six Apartから Six Apartから
機能 基本機能のみ 基本機能 +
追加機能
基本機能 +
追加機能

結局のところ, Movable Typeって何なのか?

View - (X)HTML + CSS + MTタグ (+ JavaScript) / Visual Design マークアップ担当 / デザイン担当
Controller - MT+プラグイン (or Bootstrap アプリケーション) プログラム担当
Model - MT (MT::Object 及びサブクラス群と各種ルーチン群) 既に用意されている (拡張も可能)
Database - MySQL, PostgreSQL, SQLite... 既に用意されている


デザイナーがテンプレート記法を理解しているテンプレートエンジンと
MVCパターンにより移植性が高く分業が容易な開発プラットフォーム!

まとめ

情報はどこに?

お礼!

ありがとうございました!