Jeen - Yet anothere techlog

STFUAWSC

Catalyst - ActionRole

Action Role

오래된 이야기이지만 Catalyst 가 Moose 기반으로 만들어지면서 ActionRole 이라는 개념이 만들어졌었지요. 실제 업무에서 적용해볼 껀덕지가 없어서 만져보지는 못했습니다만, 최근에 업무에서 ActionRole 을 적용해서 간단한 수정작업을 진행했습니다.

~~~ perl package MyApp::Web::ActionRole::Logger; use Moose::Role; use namespace::autoclean;

after execute => sub {

my ($self, $controller, $c) = @_;

# ...

}

1; ~~~

일단 업무에서 사용한 ActionRole 의 기본형은 위와 같습니다.

Catalyst App 을 만들 때 사용한 네임스페이스를 기준으로 ActionRole::"RoleName" 을 사용합니다. 그러니 위에서 봤을 때 Catalyst App 의 이름은 MyApp::Web 이 되겠죠. 당연히 ActionRole 의 이름은 Logger 입니다.

또한, Logger 라는 ActionRole 을 참조할 때, Catalyst 는 MyApp::Web 뿐만 아니라 Catalyst::ActionRole::Logger 가 있으면 이를 참조할 수 있습니다.

MyApp::Web::ActionRole::LoggerCatalyst::ActionRole::Logger 두개가 존재할 시에는 앞의 MyApp::Web::ActionRole::Logger 를 우선적으로 사용하게 됩니다.

주의점

위의 코드의 after execute => sub { ... } 에서 주의할 점이 한가지 있습니다. Catalyst 의 auto, begin, end 등의 Private Action 들 또한 실행이 된다는 점 입니다. 예를들어 /user/login 이라는 수행하기 위해서 각 컨트롤러 마다 auto, begin 등의 Private Action 이 정의되어 있다고 하면, 아마 아래와 같이 나올 것입니다.

.——————————————————————————————+—————–. | Action | Time | +——————————————————————————————+—————–+ | /auto | 0.000600s | | /user/auto | 0.000208s | | /user/login | 0.000219s | | /user/end | 0.009542s | | –> MyApp::Web::View::Default->process | 0.008665s | ‘——————————————————————————————+—————–’

애시당초 /user/login 가 끝나면 무엇무엇을 한다라고 ActionRole::Logger 에 정의한 마당에서 해당 액션이 2-3회 중복해서 실행되는 경우가 발생하는 것입니다. 바로 auto, end 가 끝난 다음에도 해당 ActionRole 을 참고한다는 것이죠.

~~~ perl package MyApp::Web::ActionRole::Logger; use Moose::Role; use namespace::autoclean;

after execute => sub {

my ($self, $controller, $c) = @_;

return if $self =~ /(?:auto|begin|end)/;

# ...

}

1; ~~~

그래서 적절하게 auto, begin, end 는 필터링해줍니다. $self 변수에 어떤 액션에서 온 것인지 알 수 있습니다. 전 처음에 계속 $c->action 으로 알고 착각을 했더랬습니다.

아, 물론 ActionRole 을 추가해줬다고 바로 쓸 수 있는 것은 아닙니다. 해당 ActionRole 을 사용할 컨트롤러의 기본 상속 모듈을 Catalyst::Controller 에서 Catalyst::Controller::ActionRole 로 바꾸도록 합니다.

package MyApp::Web::Controller::Root;
use Moose;
use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller::ActionRole` };

Conclusion

위의 예제에서는 그냥 단순히 Root 에서만 사용하고 있는 것 처럼 보이지만, 업무상에서는 특정 컨트롤러 몇개를 제외한 나머지 모든 컨트롤러에서 공통으로 사용하고 있습니다.

거의 모든 컨트롤러 상의 액션이 끝날 때, 시작될 때, 혹은 양쪽 모두에서 공통적으로 특정 행동을 정의할 때 ActionRole 과 함께하면 좀 더 유연하고 아름다운 코드작성에 도움이 되지 않을까 생각하고 있습니다.

Comments