O'Reilly logo

Embedding Perl in HTML with Mason by Ken Williams, Dave Rolsky

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Advanced Inheritance

In Chapter 3 we introduced you to the concept of component inheritance, and in this chapter we have discussed some of the ways you can use inheritance to create flexible, maintainable Mason sites. Now we show how inheritance interacts with other Mason features, such as multiple component roots and multiple autohandlers.

Inheritance and Multiple Component Roots

It is possible to tell Mason to search for components in more than one directory — in other words, to specify more than one component root. This is analogous to telling Perl to look for modules in the various @INC directories or to telling Unix or Windows to look for executable programs in your PATH. In Chapter 6 and Chapter 7 you will learn more about how to configure Mason; for now, we will just show by example:

my $ah = HTML::Mason::ApacheHandler->new(
  comp_root => [
                [main => '/usr/http/docs'],
                [util => '/usr/http/mason-util'],
               ]
);

or, in an Apache configuration file:

PerlSetVar MasonCompRoot 'main => /usr/http/docs'
PerlAddVar MasonCompRoot 'util => /usr/http/mason-util'

This brings up some interesting inheritance questions. How do components from the two component roots relate to each other? For instance, does a component in /usr/http/docs inherit from a top-level autohandler in /usr/http/mason-util? With this setup, under what conditions will a component call from one directory find a component in the other directory? The answers to these questions are not obvious unless you know the rules.

The basic rule is that Mason always searches for components based on their component paths, not on their source file paths. It will be perfectly happy to have a component in one component root inherit from a component in another component root. When calling one component from another, you always specify only the path, not the particular component root to search in, so Mason will search all roots.

If it helps you conceptually, you might think of the multiple component roots as getting merged together into one big über-root that contains all the files from all the multiple roots, with conflicts resolved in favor of the earliest-listed root.

Let’s think about some specific cases. Using the two component roots given previously, suppose you have a component named /dir/top_level.mas in the main component root and a component named /dir/autohandler in the util component root. /dir/top_level.mas will inherit from /dir/autohandler by default. Likewise, if /dir/top_level.mas calls a component called other.mas, Mason will search for other.mas first in the main component root, then in the utils root. It makes no difference whether the component call is done by using the component path other.mas or /dir/other.mas; the former gets transformed immediately into the latter by prepending the /dir/top_level.mas’s dir_path.

If there are two components with the same path in the main and util roots, you won’t be able to call the one in the util root by path no matter how hard you try, because the one in main overrides it.

This behavior is actually quite handy in certain situations. Suppose you’re creating lots of sites that function similarly, but each individual site needs to have some small tweaks. There might be small differences in the functional requirements, or you might need to put a different “look and feel” on each site. One simple way to do this is to use multiple component roots, with each site having its own private root and a shared root:

my $interp = HTML::Mason::Interp->new(
  comp_root => [
                [mine   => '/etc/httpd/sites/bobs-own-site'],
                [shared => '/usr/local/lib/mason/common'],
               ]
);

The shared root can provide a top-level autohandler that establishes a certain generic look and feel to the site, and the mine root can create its own top-level autohandler to override the one in shared.

Using this setup, any component call — no matter whether it occurs in a component located in the mine or shared component root — will look for the indicated component, first in mine, then in shared if none is found in mine.

An Advanced Inheritance Example

An example can help showcase several of the topics we’ve discussed in this chapter. The component in this section was originally written by John Williams, though we’ve removed a few features for the pedagogical purposes of this book. It implements an autohandler that allows you to run predefined SQL queries via a Mason component interface. For example, you might use the component as in Example 5-9.

Example 5-9. A calling component

<table>
<tr><th>Part Number</th><th>Quantity</th><th>Price</th><th>Total</th></tr>
<&| /query/order_items:exec, bind => [$OrderID] &>
<tr>
   <td><% $_->{PARTNUM} %></td>
   <td><% $_->{QUANTITY} %></td>
   <td><% $_->{PRICE} %></td>
   <td><% $_->{QUANTITY} * $_->{PRICE} %></td>
</tr>
</&>
</table>

Note that we’re passing a content block to the /query/order_items:exec method call. The idea is that the method will repeat the content block for every database row returned by an SQL query, and the $_ variable will hold the data for each row, as returned by the DBI method fetchrow_hashref( ). The query itself is specified in the /query/order_items file, which could look like Example 5-10.

Example 5-10. /query/order_items

SELECT * FROM items WHERE order_id = ?

Yes, it’s just one line. Where is the exec method we called earlier? It’s in the parent component, which (since we didn’t specify otherwise with an inherit flag) is query/autohandler. This autohandler is the component that does all the work; see Example 5-11.

Example 5-11. /query/autohandler

<%flags>
 inherit => undef
</%flags>

<%method exec>
 <%args>
  @bind => ( )
 </%args>
 
 <%init>
  local $dbh->{RaiseError} = 1;
  
  # Get the SQL from the base component
  my $sql = $m->scomp($m->base_comp, %ARGS);
  my $q = $dbh->prepare($sql);
  $q->execute(@bind);
  
  # Return now if called without content
  # (useful for insert/update/delete statements).
  return $dbh->rows unless defined $m->content;
  
  # Call the content block once per row
  local $_;
  while ($_ = $q->fetchrow_hashref('NAME_uc')) {
    $m->print( $m->content );
  }
  
  # Don't print any of the whitespace in this method
  return;
 </%init>
</%method>

Let’s step our way through the autohandler. The only code outside the exec method ensures that this component is parentless. It’s not strictly necessary, but we include it to make sure this example is isolated from any other interaction.

We access the database inside the exec method. Since we haven’t declared the $dbh variable, it’s assumed that it’s already set up for us as a global variable, probably initialized in the site’s top-level autohandler. The first thing we do is make sure that the code will throw an exception if anything goes wrong during the query, so we locally set $dbh->{RaiseError} to 1. Any exceptions thrown will be the responsibility of someone higher up the calling chain.

Next, we get the text of the SQL query. It’s contained in our base component, which in our example was /query/order_items. We call this component to get its output. Note that we also pass %ARGS to our base component, which lets us do additional substitutions into the SQL statement. For example, we could have a query that sorts by one of several different fields, using ORDER BY <% $ARGS{sort} %> inside the SQL statement.

After we fetch the SQL and prepare the query, we execute the query, passing any bound variables to the $q->execute( ) method. If there was no content block passed to us, then we’re done — this allows the component to be used for INSERT/UPDATE/DELETE statements in addition to SELECT statements.

Finally, we iterate through the rows returned by the query, storing the data for each row in $_. Note that we localize $_ before using it, since blowing away any value that’s already in there would be extremely impolite.

Be sure to notice that the $m->content body is reexecuted for each row. Because of this, its execution happens within the scope of the current $_ variable. This is really the only way this all could work, but it’s subtle enough that we had to point it out.

The advantage of using inheritance this way is that you capture the complicated parts of a task in a single component, and then all the rest of the components become very simple. If you get familiar with Mason’s inheritance model, you can create very sophisticated applications with a minimum of redundancy and hassle.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required