http://www.example.com/mt/mt.cgiというアドレスにアクセスするだけで、
MTは起動する。
だけど、mt.cgiの中身はと言えばたったこれだけ。
#!/usr/bin/perl -w
use strict;
use lib $ENV{MT_HOME} ? "$ENV{MT_HOME}/lib" : 'lib';
use MT::Bootstrap App => 'MT::App::CMS';
最初の2行はperlを使うときのおまじない。
use lib $ENV{MT_HOME} ? "$ENV{MT_HOME}/lib" : 'lib';
これは lib の場所を指定しているだけ。
というわけで、起動しているのはこの部分。
use MT::Bootstrap App => 'MT::App::CMS';
これの前の行でlibの場所が分かっているので、
MT::Bootstrap というモジュールにアクセスする事が、
この時点でできるようになっている。
App => 'MT::App::CMS';
これは { App => 'MT::App::CMS' } というハッシュをMT::Bootstrapを
useするときのパラメータとして渡している。
MT::Bootstrap.pmの中には2つのメソッドだけが定義されている。
- BEGIN
- import
どちらもuse されたときに呼び出される関数。 ( use Module = BEGIN { require Module; import Module} )
で、importメソッドは次の行で始まる。
my ($pkg, %param) = @_;
$pkgにはMT::Bootstrapが入り、
%paramには App => 'MT::App::CMS' が入るのだと思う。
その後に
my $class = $param{App} || $ENV{MT_APP};
とやって、$class に MT::App::CMS が入る。
で、いろいろごちゃごちゃ書いてあるけど、
要するに、
$app = $class->new( %param )
とやってnewしている。
これは、以下と同じ。
$app = MT::App::CMS->new( App => 'MT::App::CMS' )
このあと、
$app->run;
とやっている。
他のごちゃごちゃはエラー処理/例外処理なので、
結局MTを起動するっていうことは、
MT::App::CMSクラスのインスタンスが生成されるってことになる。
そうだろうと思っていたけど、やっとすっきりした。
と、ここまではOK。
じゃあ、MT::App::CMS のnewメソッドはどうなってんだ?
ということになる。
しかし、MT::App::CMS にはnewメソッドがない。
その代わりに、
package MT::App::CMS;
use strict;
use base qw( MT::App );
となっているから、MT::Appを継承していて、
MT::Appにnewメソッドが定義されているはず。
探すと、確かにある。
sub new {
my $pkg = shift;
my $app = $pkg->SUPER::new(@_);
$app->{init_request} = 0;
$app;
}
よくわからない。
$pkgに渡されているのはMT::App::CMSか?
MT::AppはMTクラスを継承しているから、
my $app = $pkg->SUPER::new(@_);
というのは
my $app = MT::App::CMS->MT::new(App => MT::App::CMS);
ということだろうか?
で、MT.pmを覗くと、MTのnewはこうなっている。
sub new {
my $mt = &instance_of;
$mt_inst ||= $mt;
$mt;
}sub instance_of {
my $class = shift;
$mt_inst{$class} ||= $class->construct(@_);
}
newで受け取った引数はどうなったんだ!
これ以上は自分の貧弱なPerlの知識では追えないので断念・・・。
ちなみに、$app->runに対応するメソッドはApp.pmにあって、
すごく長い。
sub run { my $app = shift; my $q = $app->param;
my $timer; if ( $app->config->PerformanceLogging ) { $timer = $app->get_timer(); $timer->pause_partial(); } my ($body); eval { # line __LINE__ __FILE__ $app->validate_request_params() or die; require MT::Auth; if ( $ENV{MOD_PERL} ) { unless ( $app->{no_read_body} ) { my $status = $q->parse; unless ( $status == Apache::Constants::OK() ) { die $app->translate('The file you uploaded is too large.') . "\n<!--$status-->"; } } } else { my $err; eval { $err = $q->cgi_error }; unless ($@) { if ( $err && $err =~ /^413/ ) { die $app->translate('The file you uploaded is too large.') . "\n"; } } } my $mode = $app->mode || 'default'; REQUEST: { # for Perl 5.6.x BugId:79755 $mode = $app->{forward} unless $mode; my $requires_login = $app->{requires_login}; my $code = $app->handlers_for_mode($mode); my @handlers = ref($code) eq 'ARRAY' ? @$code : ($code) if defined $code; foreach my $code (@handlers) { if ( ref $code eq 'HASH' ) { my $meth_info = $code; $requires_login = $requires_login & $meth_info->{requires_login} if exists $meth_info->{requires_login}; } } if ($requires_login) { my ($author) = $app->login; if ( !$author || !$app->is_authorized ) { $body = ref($author) eq $app->user_class ? $app->show_error( { error => $app->errstr } ) : $app->build_page( 'login.tmpl', { error => $app->errstr, no_breadcrumbs => 1, login_fields => sub { MT::Auth->login_form($app) }, can_recover_password => sub { MT::Auth->can_recover_password }, delegate_auth => sub { MT::Auth->delegate_auth }, } ); last REQUEST; } } unless (@handlers) { my $meth = "mode_$mode"; if ( $app->can($meth) ) { no strict 'refs'; $code = \&{ *{ ref($app) . '::' . $meth } }; push @handlers, $code; } } if ( !@handlers ) { $app->error( $app->translate( 'Unknown action [_1]', $mode ) ); last REQUEST; } $app->response_content(undef); $app->{forward} = undef; $app->pre_run; foreach my $code (@handlers) { if ( ref $code eq 'HASH' ) { my $meth_info = $code; $code = $meth_info->{code} || $meth_info->{handler}; if ( my $set = $meth_info->{permission} ) { my $user = $app->user; my $perms = $app->permissions; my $blog = $app->blog; my $allowed = 0; if ($user) { my $admin = $user->is_superuser() || ( $blog && $perms && $perms->can_administer_blog() ); my @p = split /,/, $set; foreach my $p (@p) { my $perm = 'can_' . $p; $allowed = 1, last if $admin || $perms && ( $perms->can($perm) && $perms->$perm() ); } } unless ($allowed) { $app->errtrans("Permission denied."); last REQUEST; } } } if ( ref $code ne 'CODE' ) { $code = $app->handler_to_coderef($code); } if ($code) { my @forward_params = @{ $app->{forward_params} } if $app->{forward_params}; $app->{forward_params} = undef; my $content = $code->( $app, @forward_params ); $app->response_content($content) if defined $content; } } $app->post_run; if ( my $new_mode = $app->{forward} ) { $mode = $new_mode; goto REQUEST; } $body = $app->response_content(); if ( ref($body) && ( $body->isa('MT::Template') ) ) { defined( my $out = $app->build_page($body) ) or die $body->errstr; $body = $out; } # Some browsers throw you to quirks mode if the doctype isn't # up front. $body =~ s/^\s+(<!DOCTYPE)/$1/s if defined $body; unless ( defined $body || $app->{redirect} || $app->{login_again} || $app->{no_print_body} ) { $body = $app->show_error( { error => $app->errstr } ); } $app->error(undef); } ## end REQUEST block }; if ( ( !defined $body ) && $app->{login_again} ) { # login again! require MT::Auth; $body = $app->build_page( 'login.tmpl', { error => $app->errstr, no_breadcrumbs => 1, login_fields => MT::Auth->login_form($app), can_recover_password => MT::Auth->can_recover_password, delegate_auth => MT::Auth->delegate_auth, } ) or $body = $app->show_error( { error => $app->errstr } ); } elsif ( !defined $body ) { my $err = $app->errstr || $@; $body = $app->show_error( { error => $err } ); } if ( ref($body) && ( $body->isa('MT::Template') ) ) { $body = $app->show_error( { error => $@ || $app->errstr } ); } if ( my $url = $app->{redirect} ) { if ( $app->{redirect_use_meta} ) { $app->send_http_header(); $app->print( '<meta http-equiv="refresh" content="0;url=' . $app->{redirect} . '">' ); } else { if ( $ENV{MOD_PERL} ) { $app->{apache}->header_out( Location => $url ); $app->response_code( Apache::Constants::REDIRECT() ); $app->send_http_header; } else { $app->print( $q->redirect( -uri => $url, %{ $app->{cgi_headers} } ) ); } } } else { unless ( $app->{no_print_body} ) { $app->send_http_header; if ( $MT::DebugMode && !( $MT::DebugMode & 128 ) ) { # no need to emit twice if ( $body =~ m!</body>!i ) { my $trace = ''; if ( $app->{trace} ) { foreach ( @{ $app->{trace} } ) { my $msg = encode_html($_); $trace .= '<li>' . $msg . '</li>' . "\n"; } } if ( $MT::DebugMode & 4 ) { my $h = MT::Object->driver->r_handle; my @msg = $h->{Profile}->as_text(); foreach my $m (@msg) { $trace .= '<li>' . $m . '</li>' . "\n"; } } $trace = "<li>" . sprintf( "Request completed in %.3f seconds.", Time::HiRes::time() - $app->{start_request_time} ) . "</li>\n" . $trace; if ( $trace ne '' ) { $trace = '<ul>' . $trace . '</ul>'; my $panel = "<div class=\"debug-panel\">" . "<h3>" . $app->translate("Warnings and Log Messages") . "</h3>" . "<div class=\"debug-panel-inner\">" . $trace . "</div></div>"; $body =~ s!(</body>)!$panel$1!i; } } } $app->print($body); } } if ($timer) { $timer->mark( ref($app) . '::run' ); } $app->takedown();
}