[cgiapp] CGI::Application status update from the maintainer

Rhesa Rozendaal perl at rhesa.com
Thu Sep 6 13:04:24 EDT 2012


On 09/06/2012 04:48 PM, B. Estrade wrote:

> You're limited to 2 generations below CAP if you want to subclass
> without explicitly calling on SUPER because you have 2 explicit
> methods -cgiapp_init and setup.  I am suggesting a way to provide any
> number of generations without having to call on SUPER.

You're not limited to 2 levels of inheritance. The grandchild's SUPER 
calls the child's method, and the child's SUPER calls the parent's 
method. It'll work the same even when you add a grandchild. (At some 
point I'd start asking myself if inheritance is really the way I'd want 
to structure my application).


> Here is my real world use case.  I split my applications into 2 parts;
> one amounts to the UI payload delivery, basically HTML that makes all
> calls asynchronously. The other is strictly non-UI and handles only
> asynchronous requests (i.e., the "REST" API). And I typically have
> this hierarchy:
>
> 1. WebCommon.pm (ISA CGI::Application; implements Authentication and common run modes)
> 2. WebApp.pm (ISA WebCommon; base class for the UI delivery or initial "view")
> 3. WebAPI.pm (ISA WebCommon; base class for the "REST" API)
>
>>From there, I may have another or even another 2 levels of WebApps or
> WebAPIs. In WebCommon.pm, I define cgiapp_init; in WebApps.pm and
> WebAPI.pm, I define a setup. Beyond that, I redefine setup with a call
> to $self->SUPER::setup - not something I really like doing.


You'd be better off setting up your runmodes in an init hook. That's the 
way I do it in CA::Plugin::RunmodeDeclare.

package WebCommon;
use base 'CGI::Application';

__PACKAGE__->add_callback( init => sub {
     $_[0]->run_modes([ ... ]);
});

package WebAPI;
use base 'WebCommon';

__PACKAGE__->add_callback( init => sub {
     $_[0]->run_modes([ ... ]);
});

package WebAPI::Stuff;
use base 'WebAPI';

__PACKAGE__->add_callback( init => sub {
     $_[0]->run_modes([ ... ]);
});



Then WebAPI has all the run modes of WebCommon, as well as its own run 
modes. And WebAPI::Stuff has those of WebAPI and its own.

However, I'd ask myself if I really want to have all those parent run 
modes in the child app.


> I want to use CGI::Simple, but do not want to enable uploads app-wide.
> I have a subclass (WebAPI::UploadApp, say) where I do want to enable
> uploads.
>
> In WebCommon.pm, I have to do this:
>
> our $cgi; #= CGI::Simple->new;

Don't do this. You need a query object that's an attribute of the 
current CA object. A package variable is going to have too wide a scope.

> sub cgiapp_get_query {
>      use CGI::Simple ();
>      $cgi = CGI::Simple->new();
>      return $cgi;
> }

This is better written as:

sub cgiapp_get_query {
     use CGI::Simple;
     return CGI::Simple->new;
}

> Then in order to override that CGI::Simple to enable uploads, in
> WebAPI::UploadApp, I have to do this:
>
> sub cgiapp_get_query {
>      my $self = shift;
>      use CGI::Simple ();
>      $CGI::Simple::DISABLE_UPLOADS = 0;
>      $self::SUPER::cgi             = CGI::Simple->new();
>      return $self::SUPER::cgi;
> }

That code makes little sense. cgiapp_get_query is supposed to return a 
CGI compatible object. It's not supposed to change variables in another 
package.

This is what you should do instead:

sub cgiapp_get_query {
     local $CGI::Simple::DISABLE_UPLOADS = 0;
     return $_[0]->SUPER::cgiapp_get_query;
}


> Granted, there is probably a more correct, cleaner, or better way to do
> this; if so, I am all ears.

The only ugly thing about that is that package variable to influence 
upload behavior. It'd be prettier if CGI::Simple had an accessor for 
that, or a constructor argument. That's what you get for trying to be 
compatible with CGI.pm I guess ;)

rhesa


More information about the cgiapp mailing list