[cgiapp] proposal for new cgiapp hook: loaded_html_tmpl

Michael Graham magog at the-wire.com
Tue Oct 27 10:28:21 EDT 2009


Hi Mark!

> How would your propose to deal with the "HTML::Template-like" modules
> that do not pass the "isa HTML::Template" test but are generally
> compatible? 
> 
> Could we test for the features we need instead of the classes they
> come from? 

Right, of course - that makes much more sense.  Maybe we could use 
'$class->can("query")' instead of '$class->isa("HTML::Template")'.

I'm thinking that each plugin that wanted to pass template parameters
would do something like this:

    ## hooked via load_tmpl
    sub my_load_tmpl_callback {   
        my ($c, $ht_params, $tmpl_params, $tmpl_file) = @_;
        
        my $template_class = $c->html_tmpl_class;
        eval "require $template_class;";

        # for HTML::Template and compatible templating
        # systems, don't add params here, add them in
        # the loaded_html_template callback instead
        
        # detect HTML::Template - compatibility by presence 
        # of a 'query' method
        return if eval { $template_class->can('query') };

        $tmpl_params->{'my_param'} = 'some_value';

    }
    
    ## hooked via loaded_html_tmpl
    sub my_html_template_loaded_callback {   
        my ($c, $ht_params, $tmpl_params, $tmpl_file, $tmpl_obj) = @_;
        
        my $template_class = $c->html_tmpl_class;
        eval "require $template_class;";
        
        # skip if not HTML::Template or compatible,
        # because we should have already added params under
        # the load_tmpl callback
        
        # detect HTML::Template - compatibility by presence 
        # of a 'query' method
        return unless eval { $template_class->can('query') };

        if (!exists $ht_params->{'die_on_bad_params'} 
          or $ht_params->{'die_on_bad_params'}) {
             return unless $tmpl_obj->query(
                 name =>  'my_param',
             );
        }

        $tmpl_obj->param('my_param' => 'some_value');
    }


Problems I see with this approach:

  1) html_tmpl_class being used contrary to its original purpose.
     Returning 'Petal' or 'Template' or 'Template::Toolkit' from this
     attribute seems weird, since it's named 'html_tmpl...' and none
     of these other templating systems are related to HTML::Template
     at all.  Maybe this isn't a big deal.

     At the very least, to support a mix of templating systems,
     plugins like CAP::TT and CAP::AnyTemplate should probably only
     set this attribute for the duration of the 'load_tmpl' hook, e.g.

         my $saved_class = $c->html_tmpl_class;
         $c->html_tmpl_class('Template');
         $self->call_hook('load_tmpl', ... );
         $c->html_tmpl_class($saved_class);


  2) What happens if another templating system provides a 'query' 
     method that does something completely different from what 
     HTML::Template's 'query' does?  

  3) Plugin code complexity.  While this approach does reduce the code 
     that plugins have to include, it's still a lot of code to write
     (and test) just to add a template parameter.  It's also pretty
     tricky and fragile for a standard API.  Maybe it could be wrapped
     up into its own "CAP::AddTemplateParams" plugin with a simpler
     API?

     A plugin that wanted to add template parameters would do
     something like this:
         
       use CGI::Application::Plugin::AddTemplateParams;

       sub import {
         my $caller = scalar(caller);
         if ($caller->can('add_callback')) {
           $caller->add_callback(
             'add_template_params' => \&_add_tmpl_parms
           );
         }
       }
        
       ## hooked via add_template_params
       sub _add_tmpl_parms {  
           my ($c, $tmpl_params) = @_;
           $tmpl_params->{'my_param'} = 'some_value';
       }



Michael



-- 
Michael Graham <magog at the-wire.com>




More information about the cgiapp mailing list