Bric::Util::Burner - Publishes stories and deploys templates
use Bric::Util::Burner qw(:modes);
# Create a new publish object.
$burner = new Bric::Util::Burner;
# Deploy a template.
$burner = $burner->deploy($template_asset);
# Undeploy a template.
$burner = $burner->undeploy($template_asset);
# Burn an asset given an output chanels and category
$burner->burn_one($asset, $output_channel, $category);
# set list of page extensions
$burner->set_page_extensions(@page_extensions);
# get list of page extensions
@page_extensions = $burner->get_page_extensions();
# set page numbering start
$burner->set_page_numb_start($start);
# retrieve page numbering start
$page_numb_start = burner->get_page_numb_start;
This module accomplishes two tasks:
Manages the process of deploying and undeploying of templates through deploy() and undeploy().
Manages the process of publishing and previewing business assets via the publish() and preview() methods, respectively. The actual work of publishing is done by one of Bric::Util::Burner's subclasses depending on the burner_type of the asset being published. See Bric::Util::Burner::Mason and Bric::Util::Burner::Template for details.
We anticipate that new Burner subclasses will be added to the system. Here's a brief guide to adding a new Burner to Bricolage:
Modify Bric::Biz::OutputChannel.
To use your Burner you'll need to be able to assign output channels to it. To do this edit Bric::Biz::OutputChannel and add a constant for your burner. For example, Bric::Util::Burner::Template's constant is BURNER_TEMPLATE. Next, edit the my_meths() entry for the "burner" type to include an entry for your constant.
Decide on a file naming scheme for your templating architecture. The file name suffix or suffixes must be unique across Bricolage burners, as must the base file name of your category templates. See the calls to _register_subclass() in the other burner classes to ensure that your choices are unique. You must also decide whether or not your category template file names will have suffixes. We generally recommend that they don't, so as to prevent possible conflicts with the names of element templates (see the Mason and PHP burners for an example).
Write the burner tests by implementing /t/Bric/Util/Burner/Foo/DevTest.pm. See /t/Bric/Util/Burner/Mason/DevTest.pm for an example. You will need to use the constant defined in Bric::Biz::OutputChannel and the file name standards defined in the last step to have the base class, /t/Bric/Util/Burner/DevTest.pm, properly create and load the test templates.
You will also have to create the test templates. The templates go into the same directory as the new DevTest.pm file. For example, if you had elected to go with the file suffix "foo" and gone with "cat_me" for your category template name, and the category template does not include the file suffix, the templates you would need to create would be:
The root-level category template. Port the Mason test's autohandler template.
A subcategory template. This template will wrap the execution of the story template and be wrapped by the execution of the cat_me template. Port the Mason test's sub_autohandler template.
The story element template. Port the Mason test's story.mc template.
A page subelement template. Port the Mason test's pull_quote.mc template. This template should be used from paginated content, which will result in the output of two separate files for the test story.
The pull quote subelement template. Port the Mason test's pull_quote.mc template.
A utility template. Should be called from some other template, usually cat_me. Port from the Mason test's util.mc template.
Write Bric::Util::Burner::Foo.
You'll need to create a new subclass of Bric::Util::Burner that implements three methods - new(), chk_syntax(), and burn_one(). You can use an existing subclasses as a model for the interface and implementation of these methods. Make sure that when you execute your templates, you do it in the name space reserved by the TEMPLATE_BURN_PKG directive -- get this constant by adding
use Bric::Config qw(:burn);
to your new Burner subclass.
Your burner class will also need to call the _register_burner() method when it loads so as to register itself, its category base file name and its file name suffix or suffixes. Again, see the existing subclasses for some examples.
Modify Bric::Util::Burner to load your burner subclass, provided the necessary prerequisites are installed. For example, the PHP burner is loaded like so:
require Bric::Util::Burner::PHP if eval { require PHP::Interpreter };
If all of your tests pass, you're done! You must have a freshly-built Bricolage database to successfully run the tests. To just run your new burner's tests, use this command:
perl inst/runtests.pl -V t/Bric/Util/Burner/Foo/DevTest.pm
When that's working, make sure that all tests pass by running:
make devtest TEST_VERBOSE=1
Create a patch using the instructions in Bric::Hacker and send them to the Bricolage developer's mailing list!
Profit.
In addition to the class and object methods documented below, Bric::Util::Burner can export a number of constants. These constants are used for comparing the values stored in the mode property of a burner object. They can be imported individually, or by using the :modes or :all export tags. The supported constants are:
PUBLISH_MODEThe burner object is in the process of publishing an asset.
PREVIEW_MODEThe burner object is in the process of previewing an asset.
SYNTAX_MODEThe burner object is in the process of checking the syntax of a template.
Creates a new burner object. The parameters that can be passed via the $init hash reference are:
data_dirThe directory where the Burner stores compiled template files. Defaults to the value stored in the BURN_DATA_ROOT directive set in bricolage.conf.
user_idID of the user to get a sandbox to deploy/undeploy templates for previewing. sandbox_dir is set from this value.
comp_dirThe directory to which the burner deploys and can find templates for burning. Defaults to the value stored in the BURN_COMP_ROOT directive set in bricolage.conf.
out_dirThe directory in which the burner writes burned content files upon publication or preview. Defaults to the value stored in the BURN_DATA_ROOT directive set in bricolage.conf.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Dummy method to prevent wasting time trying to AUTOLOAD DESTROY.
Returns the name of the burner class that handles templates with the extension passed in. The extension must be the full extension name without with the ".", such as "mc" or "tmpl".
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the name of the burner class that handles category templates with the base file name passed in. The file name must be the base file name, omitting any exception, such as "autohandler" or "category".
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns true if the category template with the base file name $filename has a file extension, and false if it doesn't. For example Mason category templates have no extension, so this method returns false for the $filename "autohandler". On the other hand, HTML::Template templates do have extensions, so this method returns true for the $filename "category".
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns an array reference of array references of burner file name extensions mapped to labels for each. Suitable for use in select widgets. Pass in a Burner ID (such as BURNER_MASON, as exported by Bric::Biz::OutputChannel) to get back an array reference of only the burner file name extensions available for that burner.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Goes through the list of documents queued for publish by publish_another() and schedules them to be published. This method is called by the cleanup handler and/or by bric_queued, and therefore not generally of interest to template developers (unless you want to flush the queue to force a publish after every call to publish_another(), but be careful! You might force the publication of documents passed to publish_another() by other templates in the same request!).
Returns the data directory.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Sets the data directory.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the component directory.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Sets the component directory.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the output directory.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Sets the output directory.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the burn mode. The value is an integer corresponding to one of the following constants: "PUBLISH_MODE", "PREVIEW_MODE", and "SYNTAX_MODE".
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns true if the burner is currently in publish, preview, or syntax mode, respectively. Really it's just sugar for checking the mode directly.
Returns the character set encoding to be used to write out the contents of a burn to a file. Defaults to "utf8".
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Sets the character set encoding to be used to write out the contents of a burn to a file under Perl 5.8.0 and later. Use this attribute if templates are converting output data from Bricolage's native UTF-8 encoding to another encoding. Use "raw" if your templates are outputting binary data. Defaults to "utf8".
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the story currently being burned -- that is, during the execution of templates by burn_one().
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the element currently being burned -- that is, during the execution of the various element templates by burn_one().
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the output channel in which the story returned by get_story() is currently being burned.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the category to which the story returned by get_story() is currently being burned.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the index number of the page that's currently being burned. The index is 0-based. The first page is "0", the second page is "1" and so on.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the base name used to create the file names of all files created by the current burn. This will have the same value as $burner->get_oc->get_filename.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the filename extension used to create the file names of all files created by the current burn. This will have the same value as $burner->get_oc->get_file_ext.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the local file system path to the directory that will be used as the base path for all files written for documents within a given output channel.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the local file system path to the directory into which all files created by the current burn will be written.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the base URI to the directory into which all files created by the current burn will be written.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Sets page extensions to be used during burning. Will revert to page numbering once the extensions are all used. Each of the page extensions passed must be unique or an exception will be thrown.
Throws: NONE.
Side Effects: NONE.
Notes:
Example:
$burner->set_page_extensions(qw(intro main conc));
$burner->display_pages('page');
for a 3 page story with a slug of story and a filetype of html will produce burnt pages with filenames storyintro.html, storymain.html, and storyconc.html.
Returns the page extensions to be used during burning.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Sets the start to be used when numbering pages after array passed to set_page_extensions has been exhausted.
Throws: NONE.
Side Effects: NONE.
Notes:
Normally after all page extension strings have been used, pages are numbered using the page number, where the first page after the explicitly named pages is page 1.
Setting page extensions to qw(en de) and burning three pages will give:
storyen.html storyde.html story1.html
If you want numbering to correspond to the actual story page number, then you would pass the number of page extensions plus 1.
Returns the page extension start.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Deploys a template to the file system. If the burner object was provided with a user_id, the template is deployed into the user's sandbox.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Deletes a template from the file system. If the burner object was provided with a user_id, the template is undeployed from the user's sandbox.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Not designed to be called from a template, preview() sends story or media to preview server and returns URL. The supported arguments are:
$baA business asset object to preview.
$keyThe string "story" or "media".
$user_idThe ID of the user publishing the asset.
$oc_idOutput channel ID (optional).
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Burns a story or media document, distributes it to the preview server and returns the URL. It is designed to be the complement of publish_another(), to be used in templates during previews to burn and distribute related documents so that they'll be readily available on the preview server within the context of previewing another document. Like publish_another(), it will not bother to preview the document if it's the same story as the currently burning story. The supported arguments are:
$baA business asset object to burn and send to the preview server.
$oc_idThe ID of the output channel to use to burn a story. Defaults to the primary output channel of the story.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Designed to be called from a template, preview_another_all_ocs() complements preview_another() and previews a story or media document in all of the the output channels it is associated with. The supported arguments are:
$baA business asset object to burn and send to the preview servers.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Designed to be called from a template, blaze_another() is a high level method that wraps around the entire publish/preview process. It takes a story or media document as an argument, and in publish mode, it publishes it, and in preview mode, it previews it with preview_another_all_ocs(). The supported arguments are:
$baA business asset object to publish or to burn and preview, based on the burn context.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Not designed to be called from a template, publish() publishes an asset. Returns 1 if publish was successful, else 0. The supported arguments are:
$baA business asset object to publish.
$keyThe string "story" or "media".
$user_idThe ID of the user publishing the asset.
$publish_dateThe date to set to schedule publishing job. If not defined it will default set up the asset to be published immediately.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
$burner->publish_another($ba);
$burner->publish_another($ba, $publish_time);
$burner->publish_another($ba, $publish_time, $anytime);
Designed to be called from within a template, this method schedules the publication of a document other than the one currently being published. This is useful when a template for one document type needs to trigger the publication of another document. Look up that document via the Bricolage API and then pass it to this method to have it scheduled for publication at the same time as the story currently being published.
If the mode isn't PUBLISH_MODE or if the document passed in is the same story as the currently burning story, the publish will not actually be executed. Pass in an ISO-8601 datetime string to specify a date and time different than the current story to publish the document at a different time. Pass in a true value as the third argument to trigger the publish in any mode, including PREVIEW_MODE (not recommended).
If the document to be published has been published before, then the previously-published version will be published instead of the current version. This will help prevent removing stories from workflow while users are working on them.
Note that any values stored in the notes attribute of the current burner will be copied to the publish job, and will therefore be available in templates when the other document is published, but only if the publish date and time is before now and if the QUEUE_PUBLISH_JOBS bricolage.conf directive is not enabled.
Throws: NONE.
Side Effects: NONE.
Notes:
All documents passed to publish_another() are stored in a publish queue internal to Bric::Util::Burner; they will not be published immediately. The queue may be cleared and all documents in it published by calling the flush_another_queue() class method.
You do not need to flush the publish queue from your templates, however, unless you want to always force an immediate republish. The reason for this is so that, if the bulk publication of a lot of stories at once causes the same document to be repeatedly passed to publish_another, it will only be published once per Apache request or per poll time by bric_queued. So in principal, you don't need to worry about this at all.
Burn an asset in a given output channel and category, this is usually called by the preview or publish method. Returns a list of resources burned.
Parameters are:
$baA business asset object to burn.
$ocThe output channel to which to burn the asset.
$catA category in which to burn the asset.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Compiles the template. If the compile succeeds with no errors, chk_syntax() returns true. Otherwise, it returns false, and the error will be in the $err varible passed by reference.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
This method is designed to be called from within a template. When passed a true value, it causes the burner to burn the current story and page again, creating another file. This is useful for creating multi-file output without extra paginated subelements. For example, if you need to create an index of stories, and you only want to list 10 on a page over multiple pages, you can use this method to force the burner to burn as many pages as you need to get the job done.
When the burner prepares to burn the page again, it resets the burn_again attribute. So you'll need to set it for every page for which another page burned.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns true if the document being published has been published before. Returns false if it has not. Only relevant during a call to publish(), so in templates, that's when publish_mode is set to PUBLISH.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns true if the document is being published for the first time. Returns false if it has not. Only relevant during a call to publish(), so in templates, that's when publish_mode is set to PUBLISH.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
% # Mason syntax.
% my $page_file = $burner->page_file($number);
<a href="<% $page_file %>">Page Number <% $number %></a>
Returns the file name for a page in a story as the story is being burned. The page number must be greater than 0.
Throws:
Page number not greater than zero.
Side Effects: NONE.
Notes: This method does not check to see if the page number passed in is actually a page in the story. Caveat templator.
% # Mason syntax.
% my $page_uri = $burner->page_uri($number);
<a href="<% $page_uri %>">Page Number <% $number %></a>
Returns the URI for a page in a story as the story is being burned. The page number must be greater than 0.
Throws:
Page number not greater than zero.
Side Effects: NONE.
Notes: This method does not check to see if the page number passed in is actually a page in the story. Caveat templator.
Returns the complete local file system file name for a page in a story as the story is being burned. The page number must be greater than 0.
Throws:
Page number not greater than zero.
Side Effects: NONE.
Notes: This method does not check to see if the page number passed in is actually a page in the story. Caveat templator.
% if (my $prev = $burner->prev_page_file) {
<a href="<% $prev %>">Previous Page</a>
% }
Returns the file name for the previous file in a story as the story is being burned. If there is no previous file, prev_page_file() returns undef.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
% if (my $prev = $burner->prev_page_uri) {
<a href="<% $prev %>">Previous Page</a>
% }
Returns the URI for the previous file in a story as the story is being burned. If there is no previous URI, prev_page_uri() returns undef.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
% if (my $next = $burner->next_page_file) {
<a href="<% $next %>">Next Page</a>
% }
Returns the file name for the next file in a story as the story is being burned. If there is no next file, next_page_file() returns undef.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
% if (my $next = $burner->next_page_uri) {
<a href="<% $next %>">Next Page</a>
% }
Returns the URI for the next file in a story as the story is being burned. If there is no next URI, next_page_uri() returns undef.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
% if (my $rel_story = $element->get_related_story) {
<a href="<% $burner->best_uri($rel_story)->as_string %>">
<% $rel_story->get_title %>
</a>
% }
Returns a URI object representing Bricolage's best guess as to the appropriate URI to use to link to the story or media object passed as an argument. See the URI docs for information on its interface. The semantics that best_uri() uses to create the URI are as follows:
First, it checks to see if the asset's Site ID is the same as the the Site ID for the current output channel. If it is, then the URI is returned without the protocol or server name, but formatted for either the current output channel or for the document's primary output channel.
If the document isn't in the current output channel's site, best_uri() looks for an alias to the document in the current output channel's site. If there is one the alias is used to create the URI, and the URI is returned without the protocol or server name, but formatted for either the current output channel or for the alias' primary output channel.
And finally, if the document is in another site and there is no alias in the current site, best_uri() will return a full URI with the prtocol and the document's site's domain name, formatted according to the settings of the document's primary output channel.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
my $notes = $burner->notes;
while (my ($k, $v) = each %$notes) {
print "$k => $v\n";
}
my $last = 10;
$burner->notes( last_story => $last );
$last = $burner->notes('last_story');
The notes() method provides a place to store burn data data, giving template developers a way to share data among multiple burns over the course of publishing a single story in a single category to a single output channel. Any data stored here persists for the lifetime of the burner object, as well as to any burners generated by calls to publish_another() or preview_another(). Use clear_notes() to manually clear the notes.
Conceptually, notes() contains a hash of key-value pairs. notes($key, $value) stores a new entry in this hash. notes($key) returns a previously stored value. notes() without any arguments returns a reference to the entire hash of key-value pairs.
notes() is similar to the mod_perl method $r->pnotes(). The main differences are that this notes() can be used in a non-mod_perl environment (such as when a story is published by bric_queued), and that its lifetime is tied to the lifetime of the burner object.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
$cb_request->clear_notes;
Use this method to clear out the notes hash.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
$burner->display_pages($element_key_name)
$burner->display_pages($element_key_name, %ARGS)
$burner->display_pages(\@element_key_names, %ARGS)
A method to be called from template space. Use this method to display paginated elements. If this method is used, the burn system will run once for every page element listed in \@paginated_element_key_names (or just $paginated_element_key_name) in the story; this is so that category templates and story element type templates will be executed when appropriate. All arguments after the first argument will be passed to the template executed as its %ARGS hash.
Throws: NONE.
Side Effects: NONE.
Notes: This method requires that the burner subclass has implemented a display_element() method.
my $media = $element->get_related_media or $burner->throw_error(
'Hey, you forgot to associate a media document! ',
'What were you thinking?',
);
Throws a Bric::Util::Fault::Exception::Burner::User exception. The arguments passed to the method will be joined into a single erroor message that will be displayed in the UI so that your user can see any mistakes you caught and fix them.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
$burner->add_resource($filename, $uri);
Adds a Bric::Dist::Resource object to a burn. Pass in the file name and URI of the resource. Called by the burner subclasess after they've written files to disk.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
__PACKAGE__->_register_burner( Bric::Biz::OutputChannel::BURNER_TEMPLATE,
category_fn => 'category',
exts =>
{ 'pl' => 'HTML::Template Script (.pl)',
'tmpl' => 'HTML::Template Template (.tmpl)'
}
);
Protected method only called by Burner subclasses when they're loaded. This method registers the subclasses, along with their Bric::Biz::OutputChannel constants, file names, and file extenstions. Note that the category_fn and must be unique among all burners, as must the file extensions passed via the exts directive.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Returns the subclass of Bric::Util::Burner appropriate for handling the $ba template object.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Sets up an expiration job for resources.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
Looks up or creates a resource objct for the given path/URI combination. SQL LIKE wildcard characters are escaped so as to avoid bogus lookups.
Throws: NONE.
Side Effects: NONE.
Notes: NONE.
NONE.
Garth Webb <garth@perijove.com>
Sam Tregar <stregar@about-inc.com>
Matt Vella <mvella@about-inc.com>
David Wheeler <david@justatheory.com>
Bric, Bric::Util::Burner::Mason, Bric::Util::Burner::Template.