[perlメモ]perlのフレームワークCatalystで遊んでみる その3
◇参考記事:第4回 Catalyst(前編)—Perl向けWebアプリ・フレームワーク – 簡単実装で学ぶWeb技術:ITpro
というわけで参考記事を見ながら、perlのMVCフレームワークCatalystのお勉強その3なのです。
今日は、参考記事の4ページ目を見ながらサンプルのメモ帳プログラムを突くてみます。
MVCっていうのはM(モデル:データの事主にデータベースの事をさすのかな?)V(View:表示部分の制御)C(コントローラー:入力からの制御する部分)
普通にプログラム作ってもそんな感じだと思うけどより明確にプログラムを分割してやる設計というか技法という事ですね。
というわけで今日はやっとMの部分に入れるわけです。(ちょっと楽しみ、ブログ書きながらやらなければサクッと終わると思うんだけど、メモがてらです。)
◇参考:Model View Controller – Wikipedia
◎スケルトン作成
参考記事の5ページ目を見ながらメモ帳アプリのスケルトンを作成してみます。
コマンドプロンプトから、Memoスケルトンの作成。
F:\WWW\work>catalyst.pl Memo
created "Memo"
created "Memo\script"
created "Memo\lib"
created "Memo\root"
created "Memo\root\static"
created "Memo\root\static\images"
created "Memo\t"
created "Memo\lib\Memo"
created "Memo\lib\Memo\Model"
created "Memo\lib\Memo\View"
created "Memo\lib\Memo\Controller"
created "Memo\memo.conf"
created "Memo\lib\Memo.pm"
created "Memo\lib\Memo\Controller\Root.pm"
created "Memo/README"
created "Memo/Changes"
created "Memo\t/01app.t"
created "Memo\t/02pod.t"
created "Memo\t/03podcoverage.t"
created "Memo\root\static\images\catalyst_logo.png"
created "Memo\root\static\images\btn_120x50_built.png"
created "Memo\root\static\images\btn_120x50_built_shadow.png"
created "Memo\root\static\images\btn_120x50_powered.png"
created "Memo\root\static\images\btn_120x50_powered_shadow.png"
created "Memo\root\static\images\btn_88x31_built.png"
created "Memo\root\static\images\btn_88x31_built_shadow.png"
created "Memo\root\static\images\btn_88x31_powered.png"
created "Memo\root\static\images\btn_88x31_powered_shadow.png"
created "Memo\root\favicon.ico"
created "Memo/Makefile.PL"
created "Memo\script/memo_cgi.pl"
created "Memo\script/memo_fastcgi.pl"
created "Memo\script/memo_server.pl"
created "Memo\script/memo_test.pl"
created "Memo\script/memo_create.pl"
Change to application directory and Run "perl Makefile.PL" to make sure your ins
tall is complete
スケルトンができたら、ビューの作成。
F:\WWW\work>cd Memo
F:\WWW\work\Memo>script\memo_create.pl view TT TT
exists "F:\WWW\work\Memo\lib\Memo\View"
exists "F:\WWW\work\Memo\t"
created "F:\WWW\work\Memo\lib\Memo\View\TT.pm"
created "F:\WWW\work\Memo\t\view_TT.t"
コントロールの作成
Editコントロール(編集画面部分)
F:\WWW\work\Memo>script\memo_create.pl controller Edit
exists "F:\WWW\work\Memo\lib\Memo\Controller"
exists "F:\WWW\work\Memo\t"
created "F:\WWW\work\Memo\lib\Memo\Controller\Edit.pm"
created "F:\WWW\work\Memo\t\controller_Edit.t"
Writeコントロール(書き込み処理部分)
F:\WWW\work\Memo>script\memo_create.pl controller Write
exists "F:\WWW\work\Memo\lib\Memo\Controller"
exists "F:\WWW\work\Memo\t"
created "F:\WWW\work\Memo\lib\Memo\Controller\Write.pm"
created "F:\WWW\work\Memo\t\controller_Write.t"
Listコントロール(一覧画面部分)
F:\WWW\work\Memo>script\memo_create.pl controller List
exists "F:\WWW\work\Memo\lib\Memo\Controller"
exists "F:\WWW\work\Memo\t"
created "F:\WWW\work\Memo\lib\Memo\Controller\List.pm"
created "F:\WWW\work\Memo\t\controller_List.t"
Readコントロール(読み込み表示部分)
F:\WWW\work\Memo>script\memo_create.pl controller Read
exists "F:\WWW\work\Memo\lib\Memo\Controller"
exists "F:\WWW\work\Memo\t"
created "F:\WWW\work\Memo\lib\Memo\Controller\Read.pm"
created "F:\WWW\work\Memo\t\controller_Read.t"
Searchコントロール(検索画面部分)
F:\WWW\work\Memo>script\memo_create.pl controller Search
exists "F:\WWW\work\Memo\lib\Memo\Controller"
exists "F:\WWW\work\Memo\t"
created "F:\WWW\work\Memo\lib\Memo\Controller\Search.pm"
created "F:\WWW\work\Memo\t\controller_Search.t"
◎SQLiteを使ってデータベースを作成
SQLiteでデータベースを作成します。
「Memo\db」フォルダを作成して、その中にmemo.sqlというテキストファイルを作成。中身は参考記事の通り
CREATE TABLE memo (
id TEXT PRIMARY KEY,
title TEXT,
message TEXT
);
memo.sqlを作ったら、コマンドプロンプトから、以下のように入力してデータベースを作成。(参考記事と違うのはSQlite3を使っているのでコマンドがsqliteじゃなくてsqlite3になってるところ。)
F:\WWW\work\Memo\db>sqlite3 memo.db < memo.sql
F:\WWW\work\Memo\db>
ちなみに、sqlが間違ってると下の様にエラーが表示されます。(この場合最後の「;」(セミコロン)をうち忘れていた為にエラーとなった。)
F:\WWW\work\Memo\db>sqlite3 memo.db < memo.sql
Error: incomplete SQL: CREATE TABLE memo (
id TEXT PRIMARY KEY,
title TEXT,
message TEXT
)
「Memo\db」フォルダ内にmemo.dbが作成されていれば成功。
そして作成したこのデータベースを指定してモデルを作成します。
エラーになりました。
F:\WWW\work\Memo\db>cd ..
F:\WWW\work\Memo>script\memo_create.pl model DBIC DBIC dbi:SQLite:www/work/Memo/db/memo.db
exists "F:\WWW\work\Memo\lib\Memo\Model"
exists "F:\WWW\work\Memo\t"
Couldn’t load helper "Catalyst::Helper::Model::DBIC", "Can’t locate Catalyst/Helper/Model/DBIC.pm in @INC (@INC contains: C:/Perl/site/lib C:/Perl/lib .) at (eval 222) line 3."
F:\WWW\work\Memo>ppm
どうやら、Catalyst::Helper::Mdel::DBICモジュールが入っていない為の様です。
CPAN「Browse and search CPAN : Catalyst::Helper::Model::DBIC」で調べてppmからcatalyst-model-dbicをインストール
再度挑戦してみるとできたようです。
が、Catalyst::Helper::Model::DBICがDEPRECATED(非推奨)、つまり廃止予定なので使わないでねという事になってるようなので、ワーニングとか表示されます。たぶんこれを利用して実際に物を作るのはやめておいた方がいいでしょう。何らかの代替え手段があるはずです。最新の情報を収集しましょう。ここでは勉強なので無視しますw。
DBIx::Class::DB もDEPRECATEDみたいですね。
F:\WWW\work\Memo>script\memo_create.pl model DBIC DBIC dbi:SQLite:/www/work/Memo
/db/memo.db
created "F:\WWW\work\Memo\lib\Memo\Model"
exists "F:\WWW\work\Memo\t"
This module has been deprecated in favor of Catalyst::Model::DBIC::Schema at C:/
Perl/site/lib/Catalyst/Helper/Model/DBIC.pm line 46.
created "F:\WWW\work\Memo\lib\Memo\Model\DBIC.pm"
IMPORTANT: DBIx::Class::DB is DEPRECATED AND *WILL* BE REMOVED. DO NOT USE.
created "F:\WWW\work\Memo\lib\Memo\Model\DBIC"
created "F:\WWW\work\Memo\lib\Memo\Model\DBIC\Memo.pm"
exists "F:\WWW\work\Memo\t"
exists "F:\WWW\work\Memo\t\model_DBIC-Memo.t"
F:\WWW\work\Memo>
参考記事の5ページ目を見ながら、Edit.pmとedit.ttを作成。
Edit.pm
これを打ち込みながら思ったのは、これでDBからidに一致したレコード読んで表示できるんだすげーと思った。
package Memo::Controller::Edit;
use strict;
use warnings;
use Data::Uniqid qw(uniqid);
use parent ‘Catalyst::Controller’;
sub index :Path :Args(0) {
my ( $self, $c ) = @_;
#$c->response->body(‘Matched Memo::Controller::Edit in Edit.’);
$c->stash->{template} = ‘edit.tt’;
$c->stash->{hedline} = ‘Create new memo’;
$c->stash->{id} = uniqid;
$c->log->debug(‘Edit::default: id = ‘ . $c->stash->{id});
}
sub edit : Regex(‘^edit/(\w+)$’){
my ($self,$c) = @_;
$c->stash->{template} = ‘edit.tt’;
$c->stash->{id} = $c->request->snippets->[0];
$c->stash->{hedline} = ‘Edit memo’;
$c->stash->{memo} = $c->model(‘DBIC::Memo’)->find($c->stash->{id});
}
1;
edit.tt
これを打ち込みながら思ったのは、 [%INCLUDE header.tt %]の部分ってテンプレート中で他のテンプレート読み込んでるんだーと便利そうで関心した。
[ % INCLUDE header.tt %]
<h1>[% c.stash.headline %]</h1>
<form method="post" action="/write">
<input type="hidden" name="id" value="[% c.stash.id %]" />
title: <input type="text" name="title" size="40" value="[% memo.title %]" /><br />
<textarea name="message" cols="40" rows="10">[% memo.message %]</textarea><br />
<input type="submit" value="write">
</form>
[% INCLUDE footer.tt %]
Write.pm
package Memo::Controller::Write;
use strict;
use warnings;
use parent ‘Catalyst::Controller’;
sub index :Path :Args(0) {
my ( $self, $c ) = @_;
#$c->response->body(‘Matched Memo::Controller::Write in Write.’);
$c->stash->{template} = ‘write.tt’;
my $id = $c->request->params->{id};
unless($id){
$c->stash->{error} = "invvalid request: missing id ";
return 0;
}
my $table = $c->model(‘DBIC::Memo’);
my $record = $table->find_or_create(id => $id);
$record->id($id);
$record->title($c->request->params->{title});
$record->message($c->request->params->{message});
$record->update;
$c->log->debug(‘Write::default: id = ‘ . $id);
$c->response->redirect(‘/read/’ . $id);
}
1;
と、ここまで入力してみて、6ページ目をみると、記事がおわってるーw。
あれー、記事中には全部のソース載ってないのか―。
という事で、とりあえずこの状態でサーバーを動かしてみる。
Data::Uniqidがないと怒られてるのでppmからインストールした。
F:\WWW\work\Memo>script\memo_server.pl -restart
Can’t locate Data/Uniqid.pm in @INC (@INC contains: F:/WWW/work/Memo/script/../l
ib C:/Perl/site/lib C:/Perl/lib .) at F:/WWW/work/Memo/script/../lib/Memo/Contro
ller/Edit.pm line 5.
BEGIN failed–compilation aborted at F:/WWW/work/Memo/script/../lib/Memo/Control
ler/Edit.pm line 5.
Compilation failed in require at C:/Perl/site/lib/Catalyst/Utils.pm line 280.
Compilation failed in require at F:\WWW\work\Memo\script\memo_server.pl line 66.
Terminating on signal SIGINT(2)
F:\WWW\work\Memo>
Data::Uniqidインストール後再度サーバーを起動したら、とりあえず動いた。が、このままでは例によって、下の画面のままなので、参考記事の1ページ目のリンク先からサンプルプログラムのソースをダウンロードしてきて、root.ttとroot.pmを見ながらファイルを作成。
サンプルソース眺めるだけで結構面白いです。(勉強になる。)
root.pm
とりあえず、indexサブルーチンを以下のように修正。
sub index :Path :Args(0) {
my ( $self, $c ) = @_;
# Hello World
#$c->response->body( $c->welcome_message );
$c->stash->{template} = ‘root.tt’;
}
root.tt
[% INCLUDE header.tt %]とか面倒なので普通にべたなタグを指定。
<html>
<body>
<ul>
<li><a href="/edit">Create Memo</a></li>
<li><a href-"/list">List Memo</a></li>
</ul>
</body>
</html>
edit.ttも上と同様の理由で以下のように修正した。
<html>
<body>
<h1>[% c.stash.headline %]</h1>
<form method="post" action="/write">
<input type="hidden" name="id" value="[% c.stash.id %]" />
title: <input type="text" name="title" size="40" value="[% memo.title %]" /><br />
<textarea name="message" cols="40" rows="10">[% memo.message %]</textarea><br />
<input type="submit" value="write">
</form>
</body>
</html>
で、ブラウザで動作を確認。
リンクをクリックすると、書き込み画面が表示されました。
書き込んでみようと思ったけど、read(読み込み表示)部分作ってないやーと思って、どうしようかと思いましたが、何となく感じもわかったので、Read.pmとread.ttはダウンロードしたファイルを見ながら適当にコピペ―で作成。
で、書き込みしてみると。
なんかエラー出た。
Write.pmの30行目見直してみるとつづり間違ってたので修正。
再度書き込み。
36行目もつづりエラーで修正。
再度書き込み。
どうやら成功。
ざっとやってみた感じ、確かにデータベースへの書き込みと読みだしはかなり簡潔にできる感じでいいかもしれないですね。数行でデータの書き込み、読み出しができるのはなかなかいいです。複雑な事をしないアプリなら簡単に作れそうな感じ。
複雑な事をしようと思うとちょっとと勉強と慣れが必要かなーと思います。慣れてしまえば生産性は良さそうですね。
さくらインターネットのレンタルサーバーでもCatalystをユーザーディレクトリにインストールして使っている人もいるようなので、次に何か作るときはCatalystをつかって開発してみたいなーと思います。Catalyst関係のいい(日本語の)書籍があったら読んでみたいですね。
とりあえず、Plugin使っちゃダメというのは覚えておきます。
サンプルのheader.ttとかで[% c.config.encoding %]とか[% c.config.name %]とかあるんだけど、これってどこで定義されてるのか気になった。
なるほどー
work\Memo\lib\Memo.pm
のなかで、自由に設定できるのね。
__PACKAGE__->config( name => ‘Memo’ );
これとか見るとわかりやすいかも、英語読める人は英語の方が最新情報なのでいいですよ。
私もWrite.pmで”Can’t call method “find_or_create”とエラーが出てしまいます
my $record = $table->find_or_create(id => $id);
と書いてるのですがなにか間違ってるでしょうか?
いきなり来て質問で申し訳ありませんが教えていただけないでしょうか
ちょっと問題解決のきっかけにできる情報が少なすぎですね。
Can’t call methodにもいくつか種類があったと思うので、その後に続くエラー文の部分がないと判断ができないです。
ソースも提示されている部分には問題ないようなので、それ以前の部分に問題があるのではないかと思うので、提示されている部分だけではちょっと原因はわからないです。$tableオブジェクトを作成しているあたりを見直してみてはどうでしょうか?