3
votes

Hi i don't want to repeate the same code in the controllers, so i created a sub in the main MyApp package:

sub do_stuff {
    my $input = shift;

    do something
}

But then i want to use it in controller MyApp::Controller::Foo

sub test : Chained('base') Args(0) {
    my ($self, $c) = @_;

    my $test = do_stuff($c->request->params->{s});

    do something more
}

i get following error:

Caught exception in MyApp::Controller::Foo->test "Undefined subroutine &MyApp::Controller::Foo::do_stuff called at /home/student/workspace/MyApp/script/../lib/MyApp/Controller/Foo.pm line 24, line 1000."

How can i create a subroutine / function to use global in all Catalyst Controllers???

2

2 Answers

4
votes

In principle it is already available in all the modules that were used by your main MyApp.

But if it is defined in the main package, you must either call it from within that namespace (either main or your MyApp namespace), or import it into your current package namespace.

Depending on where it was defined, use one of those ways.

my $test = main::do_stuff($c->request->params->{s});
my $test = MyApp::do_stuff($c->request->params->{s});

The alternative is to import it into your namespace in each package.

package MyApp::Controller::Foo;
if (defined &MyApp::do_stuff) {
  *do_stuff = *MyApp::do_stuff;
}

With defined you can check whether a subroutine exists.


On another note, maybe this do_stuff sub is better placed inside another module that has Exporter. You can use it in all your controllers or other modules where you need it, and Exporter will take care of importing it into your namespace on its own.

1
votes

The context object ($c) that you pass to most methods in Catalyst is already an object of type MyApp, so if you say

$c->do_stuff($c->request->params->{s})

it is the same as calling

MyApp::do_stuff($c, $c->request->params->{s});

If you expect your global subroutines to make use of this context object, then you'll want to consider writing them as methods (i.e., subroutines in a package where the first argument is always an instance of the package):

# to be called like   $c->do_stuff("s")  to do something with form input "s"
sub do_stuff {
    my ($c, $param) = @_;

    ... do something with $c->request->param($param) ...
}