Maypole

 view release on metacpan or  search on metacpan

lib/Maypole/Manual/BuySpy.pod  view on Meta::CPAN

Dead right, but it was here that I got too clever. I guess it was the word
"component" that set me off. I thought that since the page was made up of a
large number of different modules, all requiring their own set of objects, I
should use a separate Maypole sub-request for each one, as shown in the
"Component-based pages" recipe in the
L<Request Cookbook|Maypole::Manual::Request>.

So this is what I did. I created a method in C<Portal::Module> that would
set the template to the appropriate C<ascx> file:

    sub view_desktop :Exported {
        my ($self, $r) = @_;
        $r->template($r->objects->[0]->definition->DesktopSrc);
    }

and changed the C<pane> macro to fire off a sub-request for each module:

    [% MACRO pane(panename) BLOCK;
        FOR module = tab.modules("pane", panename);
            SET path = "/module/view_desktop/" _ module.id;
            request.component(path);
        END;
    END; %]

This did the right thing, and a call to C</module/view_desktop/12> would
look up the C<Html Document> module definition, find the C<DesktopSrc> to
be F<DesktopModules/HtmlModule.ascx>, and process module 12 with that
template. Once I had converted F<HtmlModule.ascx> to be a Template Toolkit
file (and we'll look at the conversion of the templates in a second) it
would display nicely on my portal.

Except it was all very slow; we were firing off a large number of Maypole
requests in series, so that each template could get at the objects it
needed. Requests were taking 5 seconds.

That's when it dawned on me that these templates don't actually need different
objects at all. The only object of interest that C</module/view_desktop> is
passing in is a C<module> object, and each template figures everything out by
accessor calls on that. But we already have a C<module> object, in our C<FOR>
loop - we're using it to make the component call, after all! Why not just
C<PROCESS> each template inside the loop directly?

    [% MACRO pane(panename) BLOCK;
        FOR module = tab.modules("pane", panename);
            SET src = module.definition.DesktopSrc;
            TRY;
                PROCESS $src;
            CATCH DEFAULT;
                "Bah, template $src broke on me!";
            END;
        END;
    END; %]

This worked somewhat better, and took request times from 5 seconds down
to acceptable sub-second levels again. I could take the C<view_desktop>
method out again; fewer lines of code to maintain is always good. Now
all that remained to do for the view side of the portal was to convert
our ASP templates over to something sensible.

=head2 ASP to Template Toolkit

They're all much of a muchness, these templating languages. Some of
them, though, are just a wee bit more verbose than others. For instance,
the banner template which appears in the header consists of 104 lines
of ASP code; most of those are to create the navigation bar of tabs

lib/Maypole/Manual/Cookbook.pod  view on Meta::CPAN

given, calling the C<get_template_root> method to ask the front-end to
try to work it out. We can give the front-end a little bit of help, by
putting this method in our driver class:

    sub get_template_root {
        my $r = shift;
        my $browser = $r->headers_in->get('User-Agent');
        if ($browser =~ /mobile|palm|nokia/i) {
            "/home/myapp/templates/mobile";
        } else {
            "/home/myapp/templates/desktop";
        }
    }

(Maybe there's a better way to detect a mobile browser, but you get the
idea.)

=head2 Content display hacks

These hacks deal primarily with the presentation of data to the user,
modifying the F<view> template or changing the way that the results of



( run in 0.351 second using v1.01-cache-2.11-cpan-299005ec8e3 )