読者です 読者をやめる 読者になる 読者になる

簡単な掲示板

MENTAの練習で簡単な掲示板を作成しました。

MENTAの解凍とリネーム


下記の手順で解凍して、ディレクトリ名を変更します。

$ tar xvzf MENTA-0.15.tar.gz
$ mv MENTA-0.15 simple_bbs
$ cd simple_bbs

MySQLのセットアップ


下記のテーブルを作成しました。

CREATE TABLE `bbs` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255)  DEFAULT NULL,
  `message` text ,
  `datetime` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8


またMENTAの方にもセットアップを行ないます。

menta.cgi

menta.cgiに、mysqlの設定を記述します。

    # あなたのアプリの設定                                                                   
    application => {
        title => '単純なBBS',
        mysql => {
            domain => 'localhost',
            dns => 'DBI:mysql:simple_bbs',
            user => 'root',
            password => '',
        },
    },
plugins/sql.pl


標準で付いてくるプラグインsql.plを利用したいと思います。
デフォルトでは、SQLiteを使う設定になっているので書き換えます。
sql_dbhの部分を下記のように書き換えました。

sub sql_dbh_for_mysql {
    if (@_) {
        my @args = @_;
        if ($MENTA::STASH->{sql_dbh}) {
            $MENTA::STASH->{sql_dbh}->disconnect;
            undef $MENTA::STASH->{sql_dbh};
        }
        my $dbh = DBI->connect(@args) or die "DBに接続できません: $DBI::errstr";
        $dbh->{unicode} = 1;
        $MENTA::STASH->{sql_dbh} = $dbh;
        $dbh;
    } else {
        $MENTA::STASH->{sql_dbh} ||= do {
            my $dsn = config->{application}->{sql}->{dsn} or die "設定に application.sql.dsn がありません";
            my $dbh = DBI->connect($dsn) or die "DBに接続できません: $DBI::errstr";
            $dbh->{unicode} = 1;
            $dbh;
        };
    }
}

sub sql_dbh {
    my $conf = MENTA::config->{application}->{mysql};
    sql_dbh_for_mysql($conf->{dns},$conf->{user},$conf->{password});
}

ページの作成

app/controllerにページ表示用のプログラムを記述していきます。

書き込み一覧ページ (http://localhost:5555/)


書き込みフォームと書き込まれた内容を表示するページを作成します。
プログラムファイル名とテンプレート名は、それぞれ「index.pl」「index.mt」にします。

# index.pl
use MENTA::Controller;

sub run {
    my ( $rows, $pager ) = sql_select_paginate(
        'SELECT id, title, message, datetime FROM bbs ORDER BY id DESC',
        [],
        { page => param('page') || 1,
          rows => 10,
        }
        );

    for my $r (@$rows) {
        utf8::decode($r->{title});
        utf8::decode($r->{message});
    }

    render_and_print('index.mt', $rows, $pager);
}
? my ($rows, $pager, $test) = @_;
<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
  <title>単純な掲示板</title>
 </head>
 <body>
  <h1>単純な掲示板</h1>
  <form method="POST" action="<?= uri_for('create') ?>">
   <div>
    Title
    <input type="text" name="title">
   </div>
   <div>Message</div>
   <div>
    <textarea name="message" cols="50" rows="10"></textarea>
   </div>
   <div>
    <input type="submit" value="Post">
   </div>
 </form>
 <div>
? foreach my $r (@$rows) {
  <div>
   <hr>
   <div>タイトル: <?= $r->{title} ?> (<?= $r->{datetime} ?>)</div>
   <div>メッセージ</div>
   <div><?= $r->{message} ?></div>
  </div>
? }
  </div>
 </body>
</html>
書き込み処理プログラム (http://localhost:5555/create)


データベースに書き込み内容を格納する処理を記述します。
フォームの「Post」ボタンを押すと起動します。
入力チェック、文字数チェックを行なって、不適切ならエラーメッセージを出すようにしています。

# create.pl

use MENTA::Controller;
use DateTime;

sub run {
    my $title = param('title');
    my $message = param('message');
  
    return render_and_print('error.mt','Please input title')
        unless $title;

    return render_and_print('error.mt', 'Please input message')
        unless $message;
   
    return render_and_print('error.mt', 'Title is too long')
        if length $title > 30;

    return render_and_print('error.mt', 'Message is too long')
        if length $message > 100;


    my $dt = DateTime->now( time_zone => 'Asia/Tokyo' );
    my $datetime = $dt->strftime('%Y/%m/%d %H:%M:%S');

    sql_prepare_exec('INSERT INTO bbs (title, message, datetime) VALUES (?,?,?)',
                     $title, $message, $datetime);

    redirect('/');
}
? my ($message) = @_;
<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
  <title>Error</title>
 </head>
 <body>
   <?= $message ?>
 </body>
</html>

起動

「./bin/cgi-server.pl」で、サーバを起動すると下記のような画面が表示されると思います。
f:id:memememomo:20100401112919p:image


フォームに書き込んで「POST」を押すと、DBにデータが書き込まれて、一覧に内容が表示されます。
f:id:memememomo:20100401112920p:image

起こった問題

いくつか問題があったので、メモしておきます。

データベースから取ってきた日本語文字が化ける


テンプレートに挿入される際にUTF8の文字が化けます。
プログラムに直書きしているときは、「use utf8;」をコントローラに記述すれば直ります。


しかし、データベースから取ってきたものに対しては、他の処理が必要です。
今回は、下記のように処理をすることによって、文字化けを回避しました。

   for my $r (@$rows) {
        utf8::decode($r->{title});
        utf8::decode($r->{message});
    }


UTF8のフラグが問題みたいです。こちらの詳細は後日調べたいと思います。

undefinedな変数の値を表示しようとするとエラーが出る


テンプレートにundefinedな変数の値を表示する事は禁止されているみたいです。
エラーが出ます。
こちらは動作としては、エラーが出ずに、空白が出力されてほしいところです。
HTML::Templateでは、オプション設定することによってできたはずです。
どうような設定ができる予感。

参考文献

かんたんプログラミング CGI/Perl

かんたんプログラミング CGI/Perl


この本の第5章にある「ひとことメッセージ掲示板」を基に作りました。
この本の筆者のBlogではMojolicious::Liteで書き直されています。

Mojolicious::Liteサンプル ひとことメッセージ掲示板