08 October 2005
This post may be outdated due to it was written on 2005. The links may be broken. The code may be not working anymore. Leave comments if needed.
昨晚跟 joe jiang, Qiang 和 cnhackTNT 讨论了下成立 Catalyst 学习小组的事。Qiang 还建了个 Livejournal 的 journal. 打算把大家的学习过程之中学到的经验或经历共享下。如果能对初学者有所帮助就再好不过。
因为我也算接触 Catalyst 比较久了,所以打算讲点对它的理解。一家之言,如有错误请批评指正。兴之所致而讲,如不连贯也见谅。

Catalyst 是对最近颇为流行的 MVC 模型或者说是 Ruby on rails 在 Perl 上的实现。在我看来,Perl 其实功能啥都不缺,就缺一组合。而 Catalyst 就是一个快速 Web 开发的漂亮组合拳。

M - Model, 一般用来将数据库对象化,这样能比较容易访问和操作。Perl 中最有名的就是 Class::DBI
V - View, 就是视图,用来处理界面显示。Perl 中比较有名的是 Template-Toolkit 和 Mason
C - Controller, 就是控制器。就是针对不同的 action 或 request, 来执行不同的代码。另外有个名词就是分发/Dispatch

Catalyst 中可以使用很多不同的 Model 和 View/Template. 看个人喜好而定,我一般偏向于使用最流行的 CDBI 和 TT.
Class::DBI 和 TT 本来在 Perl 世界中就很出名。而按一般逻辑思维,视图与模型搞定后就剩下事件处理了。Catalyst 无缝地整合了这两者,而事件处理/Controller 则让我赞不绝口。

首先从目录结构上来说(运行 catalyst MyApp),略过某些东西:

created "MyApp" # 整一目录
created "MyApp\lib"
created "MyApp\root" # 可以将一些静态文件放在这如 CSS/Gif/JS etc.
created "MyApp\lib\MyApp"
created "MyApp\lib\MyApp\M" # 这里就是放置 Model
created "MyApp\lib\MyApp\V" # 一般也就一个文件 TT.pm
created "MyApp\lib\MyApp\C" # 这里比较重要,所有的 Controller 都放这
created "MyApp\lib\MyApp.pm" # 主程序模块
created "MyApp/Build.PL" # 可以用来打包发布模块
created "MyApp\script" # 脚本目录
created "MyApp\script/myapp_cgi.pl" # 普通 CGI 环境下运行
created "MyApp\script/myapp_fastcgi.pl" # FastCGI
created "MyApp\script/myapp_server.pl" # 这个就是我们一般写代码要运行的脚本
created "MyApp\script/myapp_test.pl"
created "MyApp\script/myapp_create.pl" # 这个用来创建新的 C/M/V 模块
对 Controller 来讲,Catalyst 实行 URL-to-Action.
在服务器运行时它将检查 MyApp.pm 和 \M \V \C 这三目录下的所有模块文件。对于 \C 目录下模块文件中实行 URL-Action 匹配。比如我们在 \C 下有一新文件 List.pm (用 perl script/myapp_create.pl controller List 创建)。List.pm 中如果这么写:
sub list : Global { # 这个 Action 自动对应类如 http://fayland:3000/list 这样的 URL

sub view : Regexp('^tag/(.*)') { # 这个对应类如 http://fayland:3000/tag/Catalyst 这样的 URL

sub orderby : Local { # 这个对应 http://fayland:3000/list/orderby 这样的 URL
与 Global 不同的是它在 URL 中多了个模块名

还有其他后缀。这是个非常棒的东西。这样你就不用在一个文件中写哪个模块对应哪个子程序了(以前要用类如 CGI::Application 完成这功能)。很方便。

一般而言,把简单的 \V 和 \M 搞完后(真的很简单,里面一般一个文件十行代码就可以),剩下来的就是 Controller 的编写了。
Controller 一般子程序的第一行是 my ( $self, $c ) = @_;
这里就是引进了一个最重要的 $c, 其实你不必理会它是什么东西(其实是模块的一个实例),只需要知道项目里的所有东西你都可以从这得到。需要什么,找它就是。它又分为很多部件,包括 request, response, stash, config, forward 等。

request 包含你请求(浏览器对服务器的请求)时的所有信息。如 cookies, 参数/params 和其他头/header 信息。可以通过 my $value = $c->req->params->{'foo'}; 当你访问 http://fayland:3000/?foo=bar 时, $value 就是 bar 了。

response 就是服务器对浏览器的反馈。你对浏览器的输出等就是靠这个部件来解决。$c->res->output('Congratulations, NewApp is on Catalyst!'); 一般很少用 output, 因为输出一般用 Template 解决。

config 一般存储项目的配置文件。我一般用 YAML 来配置,然后通过 YAML::LoadFile 来导入该配置文件

forward 这个是很有用的东西。一般用来实现在子程序间的跳转。

stash 所有子程序传递到 TT 模块中的变量都是用这个变量来传递。(用过 TT 的人都应该知道的)

代码片断

package Eplanet::C::Add;

use base 'Catalyst::Base';

sub add : Global {
   my ( $self, $c ) = @_;
   $c->stash->{cates} = [ Eplanet::M::CDBI::Category->retrieve_all ];
}

Eplanet::M::CDBI::Category 这就是对象化后的数据库。retrieve_all 是 CDBI 的一个函数。就是获得所有数据。然后将其放到 $c->stash->{cates} 里,这样模块文件就能访问这数据了。
# add.tt 模版文件
<select name="cms_cat_id">
[% FOREACH cate IN cates -%]
<option value="[% cate.cat_id %]">[% cate.cat_name %]
[% END -%]
</select>
这样就是一个最基本的完整的过程。http://fayland:3000/add 实现 URL-Action, Eplanet::M::CDBI::Category 是数据库,然后通过 $c->stash 传递到模版里。一般的流程就是这样。

学习流程一般这样:

* 看 Catalyst::Manual::Intro
* svn co http://dev.catalyst.perl.org/repos/Catalyst/trunk 里看那文件夹里的 examples
* 订阅 http://lists.rawmode.org/mailman/listinfo/catalyst
* 写代码,做试验,问问题

Enjoy Catalyst.



blog comments powered by Disqus