Writing Template Datasources

Templates Tutorial : Writing Template Datasources

Overview

A template consists of two parts: the ADP page and the TCL executable file. The purpose of the TCL file is to generate the datasources used by the ADP page, and to run other setup code. In particular, the TCL file may perform any of the following tasks:
  1. Retrieve the attributes of the current item
  2. Run and document database queries
  3. Create and process forms

Retrieving attributes of the current item

When an item is accessed (either by being viewed in the browser or by being published), the template assigned to the item receives an implicit reference to the item's attributes. The TCL file may call
content::get_content
in order to access the item's attributes. The attributes will be placed in a onerow datasource (i.e., a TCL array) called content; the live revision for the item is used to look up the attributes. For convenience, the TCL file may call
template::util::array_to_vars content
in order to convert the datasource to local variables, which may be used as onevalue datasources by the ADP file.

The content datasource is guaranteed to contain the following fields:

In addition, any extra attributes defined by the item's content type will be present in the datasource. For example, if the current item has the press_release content type, which defines a company_name attribute, the content datasource will contain a company_name field.

Content API Pitfalls

The content API may lead to some unexpected behavior if used incorrectly; some common errors are outlined below.

Updating revisions

The attributes of each revision are cached, in order to improve performance. This may lead to unexpected behavior. Consider the following scenario:
  1. The my_press_release item (item_id = 1) has a live revision, whose revision_id is 4
  2. The item is served in the browser, and the attributes for the revision #4 are used. The title of the revision is "My Press Release"; this title is cached along with other attributes
  3. Some TCL script executes an update statement on the cr_revisions table, changing the title of revision #4 to "The Care and Feeding of Manatees"
  4. The item's page is refreshed in the browser. Since the attributes for the revision #4 are cached, the title shows up as "My Press Release", even though the title column in the database is set to "The Care and Feeding of Manatees"
To avoid this behavior, TCL and PL/SQL scripts should never update the cr_revisions table. Instead, the scripts should create a new revision for the item.

Using connection-specific calls

Sometimes, the item's template may need to retrieve the URL of the current item, the package key of the active package, etc. Standalone TCL scripts and templates may use ns_conn or ad_conn in order to retrieve this information. However, when the item is being published (i.e., written to the filesystem), the current URL is the URL of the publishing script (typically, cms/modules/items/publish.tcl), not the URL of the item itself. Similarly, the data in the ad_conn fields will pertain to the CMS package. Thus, content items will render correctly when being previewed in CMS or served directly from the database, but will not render correctly when published to the filesystem.

To remedy this situation, the TCL file for the item's template should avoid using [ns_conn url] and other connection-specific calls. Instead, the TCL file may call content::get_content in order to retrieve the item_id of the item, and then call

set current_url [item::get_url $content(item_id)]
Once the item's ID and URL are known, the TCL file may retrieve other information about the current page by using standard APIs. Note: This situation could be remedied, but the solution would involve some nontrivial coding. However, CMS-TCL is frozen, and so no solution exists at this time.

Manually querying the database

In addition to the item::get_url call mentioned above, the item namespace provides other procs which retrieve miscellaneous data about the item. For example, item::get_extended_url can be used to compute the full URL of the item (including the file extension). Most of the queries performed by the item procs are cached for efficiency. In addition, the item procs are more flexible than hardcoded SQL queries; when the CMS implementation changes (to support subsites, for example), the implementation of the procs will change, but the interface will remain the same.

For more information, see the auto-generated documentation on the item namespace.

Querying the database

The TCL file may query the database in order to create datasources which the ADP page will use to render the page. In order to simplify the SQL queries, the Content Repository provides an "x" view along with each content type. The view joins together all the attributes of the content type, and contains all revisions for each content item with the given content type. For example, consider an index page whose purpose is to serve press releases for a company. Each press release has the content type press_release Thus, a SQL query such as
select 
  title, topic, content_item.get_path(item_id) as press_url
from
  press_releasesx
will select all revisions of all press releases in the system. In order to select only the live revisions, the TCL file may join with the cr_items table:
select 
  x.title, x.topic, content_item.get_path(x.item_id) as press_url
from
  press_releasesx x, cr_items i
where
  i.live_revision = x.revision_id
This query, when executed through the ACS DB API or template::query, will produce a multirow datasource which the ADP page may then use to render a list of all available press releases. For example, the template may use the following markup:
<ul>
  <multiple name=press_releases>
    <li>
      <a href="@press_releases.press_url@">@press_releases.title@</a>
      (@press_releases.topic@) 
    </li>
  </multiple>
</ul>
resulting in a list of press releases: Multirow datasources may also be created manually, by using the template::multirow command. In addition, the template may create onerow (TCL arrays) and onevalue (TCL variables) datasources; see the templating system documentation for more information.

Documenting the Datasources

In addition to creating the datasources, the TCL file should document them, so that the CMS Templates UI may describe them to the user in the Datasources pane. The format for datasource documentation is similar to Javadoc:
# @datasource datasource_name datasource_type datasource_comment
# @column column_name column_comment
# @column column_name column_comment
# ...
The fields are explained in greater detail below: For example, consider a fragment of the master-2 template, which is installed by the CMS Demo:
# @datasource articles multirow
# @column location 
# @column name
# @column title 
# This datasource enumerates all articles across all locations
#
# @datasource location onevalue the user clicked location
#
# @datasource current_url onevalue
This documentation fragment describes three datasources: articles, location and current_url. The articles datasource is a multirow datasource with three columns, location, name and title. The location and current_url are both onevalue datasources.

These pseudo-Javadoc tags merely describe the datasources - they do not have any impact on how the template is actually rendered. However, the tags help clarify the purpose of the template. The CMS Templating UI will attempt to parse the template if it detects no pseudo-Javadoc datasource comments; however, the parsed results cannot compare in quality to human-generated documentation.

Creating and Processing Forms

In addition to the forms API provided by the templating system, the CMS Forms API provides various procs designed to automate the content item creation process. The simplest way to create a new item is to perform the following TCL calls:
content::new_item_form -form_name form_name -contnent_type content_type

if { [template::form is_valid form_name] } {
  content::new_item form_name
  template::forward next_page_url
}
This snippet of code will execute the following steps:
  1. Construct a blank form for the creation of the new item. The form is constructed based on form widgets registered to the content type in the CMS Content Type UI
  2. Validate the form. If any required elements are missing, if any user-entered values do not match the proper datatypes, or if any other error occurs, the error will be reported to the user and the form will not submit
  3. Process the form, creating a new content item and its first revision based on the user-entered values
  4. Forward the user to the next page in page flow
The CMS Forms API also includes other, less powerful but more versatile procs. For example, content::add_revision_form may be used to generate a form for editing an existing content item. More help can be found in the auto-generated documentation of the content namespace, or directly in the source code of form-procs.tcl.