MTはどうやって起動しているのか

| | トラックバック(0)

カテゴリ:

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();

}

comments powered by Disqus

トラックバック(0)

このブログ記事を参照しているブログ一覧: MTはどうやって起動しているのか

このブログ記事に対するトラックバックURL: http://nozawashinichi.sakura.ne.jp/MT-4.25/mt-tb.cgi/332

comments powered by Disqus

このブログ記事について

このページは、Shinichi Nozawaが2009年3月 5日 17:07に書いたブログ記事です。

ひとつ前のブログ記事は「MT::Pluginの継承関係」です。

次のブログ記事は「MTPlugin: Set Offset」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。