Mojoliciousでactionの前後に実行される独自のHookを作る。before_action、after_action編

Mojoliciousでactionの前後に実行される独自のHookを作る。before_action、after_action編

PerlのWebApplicationFrameworkであるMojoliciousでは様々なフックが用意されているのだけれど、actionの前後だけに実行したい場合は独自にフックポイントを追加しないといけない。

実装方法その1

一番単純な実装方法はaround_actionフックを使うのが良さそう。actionは$lastフラグが真の時に実行されるので前後に独自のフックをエミットする。

sub startup {
    my $self = shift;
    ...

    $self->hook(
        around_action => sub {
            my ( $next, $c, $action, $last ) = @_;
            return $next->() unless $last;

            # before_actionフックを実行
            $c->app->plugins->emit_hook( before_action => $c );

            # Controller::Actionを実行
            $c->$action();

            # after_actionフックを実行
            $c->app->plugins->emit_hook( after_action => $c );
        }
    );
}

このフックを使えば動的ページのみでフックを実行できる。session関連の操作とかに便利。

実装方法その2

上記のコードの場合は全てのactionに適用されてしまうので、フックを実行したくないcontrollerを作りたい場合はMojolicious::Controllerを継承したclassを作る事で実現できる。

# App
sub startup {
    my $self = shift;
    ...

    $self->hook(
        around_action => sub {
            my ( $next, $c, $action, $last ) = @_;
            return $next->() unless $last;

            $c->process($action);
        }
    );
}
# フックを使用するbase class
package MyApp::Controller;
use Mojo::Base 'Mojolicious::Controller';

sub process {
    my ( $c, $action ) = @_;
    $c->before();
    $c->action();
    $c->after();
}

sub before {
    my $c = shift;
    $c->app->plugins->emit_hook( before_action => $c );
}

sub after {
    my $c = shift;
    $c->app->plugins->emit_hook( after_action => $c );
}

1;
# フックを使用しない base class
package MyApp::NoHookController;
use Mojo::Base 'Mojolicious::Controller';

sub process {
    my ( $c, $action ) = @_;
    $c->action();
}

1;
# フックを使うcontroller
package MyApp::Controller::Fizz;
use Mojo::Base 'MyApp::Controller';

...

# フックを使わないcontroller
package MyApp::Controller::Buzz;
use Mojo::Base 'MyApp::NoHookController';

...

before/after_actionフックを使う場合はMyApp::Controllerを継承したcontrollerを作り、使わない場合はMyApp::NoHookControllerを継承したcontrollerにする。