By: Ray Bayly

Dynamic Template Delivery (DTD) in FB3 and as a CFC
By Ray Bayly

It?s 9:00 AM on a Monday morning, the boss has called a meeting to discuss a new product as you sit there recovering from a late of night battling foes on the computer you notice your boss has that familiar malicious gleam in his eyes, you know the one it?s the same one he had when he asked if the apps on the server were ?508? compliant. As you begin sink in your chair you realize that he is looking at you smiling. He mentions a client and a ?Big Opportunity?. Then he mentions the word ?Portal? and that is when it dawn?s on you, He has found the stash of ?wired? magazines that you have been hiding from him. As the boss begins to layout his ?BIG PLAN? your mind goes to work. He wants an application that 200 companies can view from there own site?s look and feel. 200 Companies you think , That is allot of copied code , suddenly you think of 200 URL?S and 200 Folders on the server and you look over at Bill the IT Admin who is turning blue from trying not to scream. You mention words to your boss like ?statistical nightmare? disastrous support scenario?. But he just smiles blankly and asks if you can have that in a week.

Normally this would be a nightmare scenario with Code versions and multiple upgrades requiring an entire staff to stay on top of it. But fear not there is an easier way to manage an application like this. Now lets delve into that black bag of methodology  for you Fusebox guru?s this will seem very familiar.

The Methodology
Let talk for a second about the process behind Dynamic Template Delivery. We are of course talking about Model View Controller (MVC). This Methodology was first developed By Xerox PARC for Small talk 80. MVC is the ability to separate into three separate pieces the Model, User Interface (UI) and Controller. More of this is covered at length in ?Discovering Fuse box 3? or at www.fusebox.org I recommend you read up on it as it will become more and more relevant to developers as MX becomes the Dominant Version of CF.



 

The Database

So there you are blessed with the knowledge of Model View Control and an app plan starting to come out of the Monday fog in your head. You smile confidently at Bill the IT guy, visually assuring him that he can postpone the   Ritual Hari Kari in the server room because you have everything under control.  So now the boss, sensing your confidence and Zen like state throws another curve at you. The application now has to be managed by sales. With that sinking feeling coming back into the pit of your stomach you look over in the corner to Charlie the sales guy who at that moment is stomping and cursing about not being able to find Word on the Etch e Sketch you told him was a state of the art laptop not two weeks ago. But alas all is not lost, for you remember one of the key benefits of Cold Fusion is database delivery and you pull out your trusty Visor and begin to jot down a table design.

 

With a table like this you are able to later build an admin area that uses cffile to allow you to register and change sites and templates without the need for new code. Boy that was a close one, but once again you have triumphed and we are ready to get on with this scenario.

 

For this example go ahead and build this table and name it DTD_Test in a Database of your choice. Create a Datasource Called DTD_Test on the CFServer.

The Test Template

Now that you have come this far we are ready to create a couple of Templates. I want you to create three distinct Designs and separate them into header and footer. Call them header_1.htm, footer_1.htm and so on. I know all of you fuseboxers out there are looking a little confused. Why break them up when fusebox allows for a single template. Well there is a very simple reason. Since the templates are managed by someone other then a Programmer we remove a possibility of error. Most Administrators and or sales people are not programmers so there is a very real possibility that even a simple piece of code like <cfouput>#fusebox.layout#</cfoutput> would be too much to remember every time. So we very simply remove them from having to do that .

Place the template?s in your intepub directory under DTD_Test/Templates. 

Alright the Templates are created and the datasource is set up. Now we are ready to populate the Database with some test data . Create a folder under the DTD_Test Directory called SCRIPTS. Create a new file called populate.cfm and place the following script in it.

 <cfoutput>
    <cfset I = 1>
    <cfset N = 3>
     <cfloop condition=?I LTE N?>
         <cfquery name=?Populate? datasource=?DTD_Test?>
               INSERT INTO Site_Master

                    (Site_Name, DNS, Site_Version, template_header,. Template_footer)
                  VALUES
                    ( ?Test Site #I#?, ?DTD_TEST?, ?1.0?, ?header_#I#.htm?, ?footer_#I#.htm?)
          </cfquery>
          <cfset I = I + 1>
   </cfloop>
</cfoutput>

 Once the file has complete running go ahead and delete it as you will not be needing it anymore. Now if you open the database you will notice three records with the template names under header, footer fields.

Now the Database is populated and we are ready to start coding. 

The Fusebox Files

First Go Ahead and Download the Core Fusebox 3 files. This lesson is going to assume you  know how to use them  so I won?t go into detail on how to set them up.  Go ahead and install them into the DTD_Test Directory. You can get the base Fusebox 3 files at http://www.fusebox.org/index.cfm?fuseaction=specs.cffusebox30

Once you have installed the fusebox 3 files into the DTD_Test directory amd set them properly  go ahead and open your favorite cfm editor.

First Let?s Create a File and Call it qry_GetSite.cfm save it in the DTD_Test directory.

Put the following code into the qry_GetSite.cfm file.

 <!---
<fusedoc fuse="qry_GetSite.cfm">
        <responsibilities>
                   I Dymanically Add the Visual Templates to the application.
       
</responsibilities> 
        <io>
           <in>
                 
<string name=?url.id? comments=?This is the optional passed id?/>

                
<out>
                              <string name="Request.SiteName" comments="Number of Records Returned " />
                              <string name="Request.Site_Version" comments="Site version of current code " />
 
                           <string name="Request.admin_email" comments="Administrative site " />
            
                 <string name="Request.support_email" comments="Support email for the site " />
               
             <string name="Request.template_header" comments="Header file name " />
                             
<string name="Request.template_footer" comments="Footer file name " />
                   </out>
       </io>

</fusedoc>
--->

<cftry>
     <cfif NOT IsDefined(
"url.id")>
           <cfquery name=
"GetSite" datasource="DTD_Test">
               SELECT SiteName, Site_Version, admin_email, support_email, template_header, template_footer
               FROM Site_Master
               WHERE dns = '<cfoutput>#cgi.HTTP_HOST#</cfoutput>'
           </cfquery>
     <cfelse>
           <cfquery name=
"GetSite" datasource="DTD_Test">
               SELECT SiteName, Site_Version, admin_email, support_email, template_header, template_footer
               FROM Site_Master
               WHERE id = '<cfoutput>#url.id#</cfoutput>'
           </cfquery>
    
</cfif>

     <cfif GetSite.recordcount EQ 0>
             <cfthrow type="any" message="No Template Available">
    
</cfif>

     <cfset Request.SiteName = GetSite.SiteName>
      <cfset Request.Site_Version = GetSite.Site_Version>
     <cfset Request.admin_email = GetSite.admin_email>
     <cfset Request.support_email = GetSite.support_email>
     <cfset Request.template_header = GetSite.template_header>
     <cfset Request.template_footer = GetSite.template_footer>

 <cfcatch type="Any">
       <cflocation url="maintenance.cfm">
 </cfcatch>
</cftry>

This is the core query file for your template system it will check to see if you are passing an id ?index.cfm?id=2? and if so it will query the database on that id, however if you don?t pass the query it will then look at the dns and query the database off of that. If no records are returned from either of them then the system will throw the user to a maintenance page.

 Once the file is created we are now ready to create our maintenance page. Create a new file called maintenance.cfm this is a simple page that only say?s ?We are under maintenance?.

Now save that to the root directory. This maintenance page is also used to catch error?s in this file , if an error occurs it automatically sends the user to this page.  By being able to keep and register the templates in a database we can keep track of all the sites using the system as well as the template versions, this is done with the site_version field in the database.

 Now open the index.cfm file and type the following above the include files on the page.

 <cfinclude template=?qry_GetSite.cfm?>

 Alright you are doing great

By adding this to the index.cfm page we insure we have full control over the base template at all times. Now open the fbx_Layouts.cfm file  change the  file to reflect the following.

<cfset fusebox.layoutFile = "dsp_LayoutControl.cfm">
<cfset fusebox.layoutDir =
"">

 Creat a  blank file and call it  dsp_LayoutControl.cfm in the DTD_Test directory, add the following code to the file and save it.

 <!---
<fusedoc fuse="dsp_LayoutControl.cfm">
         <responsibilities>
 
                I am the Display control file I add the dynamic template to the application
          </responsibilities> 
          <io>
                <in>
                    <string name="Request.template_header" comments="Number of Records Returned " />
                    <string name="Request.template_footer" comments="Number of Records Returned " />
                </in>
         </io>

</fusedoc>
--->

 <cfoutput>
    <cfinclude template="Templates/#Request.Template_header#">
    #fusebox.layout#
    <cfinclude template="Templates/#Request.Template_footer#">
</cfoutput>

 

This file will act as our fusebox display file. It will pull the template?s into the file and add then to the content of the application.

Now we are ready to test our application. First type in the app address

http://127.0.0.1/DTD_Test/index.cfm

Right now you should see a maintenance page. The reason for this is because we have not added the dns to the database so by not passing an ID or by using a registered dns we in effect don?t have any templates assigned. Now open the database and add then name of the server the app is on to the first record. IE if you are on your machine then add 127.0.0.1 to the field .

 Now open the application again and refresh the page. Notice now template 1 comes up . This is because you have now added the dns to the system . As a note if you are not IT support savvy the DNS server allows you to point more then one URL to a server. This is great if you are selling your site. Heres an example lets say it was a real estate application you were building and you wanted every state  to have its own look or feel on the application. So if you added richmondrealestate.com and marylandrealestate.com to the server they could both share the same application from the same source code with there own look and feel as well as since we are passing request variables to the application you are able to also have them view records local to them if you set your queries based on a site id or name.

 Now lets also try adding the id to the url so type in

http://127.0.0.1/DTD_Test/index.cfm?id=2

Now you will notice that the second template has come up if we change the id to 3 the third template has come up viola you know can deliver templates based on a system decision.

Now lets also look at the Cold Fusion Component version of this code. The benefit to the CFC version is it allows you to manage all of your template?s from a single source thus making  all templates available to all applications . This is good if you work for a company that is building multiple applications for multiple sites. By creating one CFC you can then call that CFC from any application on  the server.

First lets make a new file and call it DTD_test.cfc in this file place the following code into the file.

<cfcomponent>
        <cffunction name=
"GetTemplate" access="public" returntype="string">
                   <cfargument name="id" type="string" required="false">
                              <cfset var hdr = "">
                              <!---Create initial Variables--->
                              <!---This is changed based on the server it is on--->
                              <cfset  var Location = " templates\">
                              <cfparam name="dsn" default="127.0.0.1">
                              <cfparam name="id" default="1">
                              <cftry>
  
                                    <!--Query the database for the template information--->
                                       <cfquery name="GetSite" datasource="DTD_Test">
                                            SELECT SiteName, Site_Version, admin_email, support_email, template_header, template_footer
                                            FROM Site_Master
                                            WHERE id = '<cfoutput>#arguments.id#</cfoutput>'
                                      </cfquery>

                                     <cfif GetSite.recordcount EQ 0>
                                         <cfthrow type=
"any" message="No Template Available">
                                     
</cfif>
                                     
<!--Set the hdr return variable list--->
                                      <cfset hdr = Location & "|" & GetSite.template_header & "|" & GetSite.template_footer>

                                       <!---Catch any errors thrown by the cfc and set a default header--->
                                       <cfcatch type="Any">
                                          <cfset hdr =  Location &
"|" & "DefaultHeader.cfm" & "|" & "DefaultFooter.cfm">
                                      </cfcatch>
                              </cftry>
                   <cfreturn hdr>
      </cffunction>
</cfcomponent>

Now looking at the code for the cfc it is the same code minus the ability to pass the dns ,

also you will notice that it sets a default header and footer in the template in case an error is thrown, you may want to create these files (DefaultHeader.cfm, DefaultFooter.cfm) .Now you can change the cfc to accept the dns instead of the id , just change the query to look at the dns and change the next piece of code to pass the dns and not the id.

Now open your dsp_LayoutControl.cfm file. And replace the code in the file with the following code. 

<!---
<fusedoc fuse="dsp_LayoutControl.cfm">
             <responsibilities>
 
                  I am the Display control file I add the dynamic template to the application
             </responsibilities>
             <io>
                   <in>
                      <string name="Request.template_header" comments="Number of Records Returned " />
                      <string name="Request.template_footer" comments="Number of Records Returned " />
                   </in>
            </io>
</fusedoc>

--->


<cfparam name="url.id" default=1>

<cfinvoke
component="Dell_test"
              method="GetTemplate"
             
returnVariable="hdr"
            
 id=
"#url.id#">

<cfoutput>
     <cfinclude template=
"#ListGetAt(hdr, 1, "|")##ListGetAt(hdr, 2, "|")#">
   
#fusebox.layout#
     <cfinclude template=
"#ListGetAt(hdr, 1, "|")##ListGetAt(hdr, 3, "|")#">
</cfoutput>

Now I have used a list as the return , there are other ways to do this however I wanted to keep the example basic, so play around with the code and the theory and have fun making something that works for you ..  As with the developer in the scenario, who is I?m told faring well with the application and has now changed the location of those hidden wired magazines. I hope this will help you in managing your applications, if you have any questions please feel free to email me at rbayly@baylyconsulting.com with any questions or comments.


About the Author:

I currently hold the position of Lead Cold Fusion Developer For Media General?s Interactive Media Department.
I have been a CF MX Beta Tester since the program began.
Here are a couple of project types I am currently Developing
Dynamic Template Delivery (DTD) Flash and CF Integration with (AAVDD) Animation, Audio, Video, Data Delivery CF Portal Technologies and Web Services Using CFC.

I have 6 Years experience in the industry. I currently teach classes here for Jr. developers on basic to advanced Cold Fusion and other subjects

About This Tutorial
Author: Ray Bayly
Skill Level: Advanced 
 
 
 
Platforms Tested: CFMX,BlueDragon
Total Views: 138,174
Submission Date: April 03, 2003
Last Update Date: June 05, 2009
All Tutorials By This Autor: 1
Discuss This Tutorial
  • This is a good example of setting up a "branding" solution. However, calling this practice "DTD" is misleading because "Document Type Definition" is the more common term abbreviated by "DTD" in this field. Second, isolation of the header and footer is only a first step towards branding and fielding multiple types of users through a single codebase. I was suprised to get to the end of the article and not see a second page covering a form or report template also based on "site_master.id". ... for example, a table named "brand_includes" with columns: ID, site_masterID, include_name, user_typeID, pageID, include_typeID, priority_value and a snippet using it: select include_name from brand_includes where ( user_typeID = #client.some_user_type# AND pageID = #url.some_pageID# ) OR include_typeID = 1 order by priority_value


    include skipped: #include_name#.cfm
    .. this allows each of the branded sections to govern all the included content with the same flexibility intended to manage 200 brands. While this simple snippet borders on the issue of making a site "too dynamic" and thus expensive in terms of calls to the database, a further discussion could show the benefits of constructing a cfquery object with cfscript instead of a database call. However, bouncing the includes through the db like this allows the developer to give users the flexibility of turning componenets on and off... which in the case study above, may be a good idea for allowing the external content folks to "check in/check out" and publish their content. Any developer whose shop doesn't have strict sourcesafe or cvs policy will have to deal with this at some point. Using a "cftry" tag is another way to protect yourself as a developer from bunk content that you have no way of verifying. In my opinion, I dont think that a methodology like Fusebox should be treated like a monastic study. Using #fusebox.layout# is obviously handy for what goes between the header and footer, but for the comment poster preceding me, that still represents a blank wall. I think it's important to show how Fusebox is a solution derived from many years of skilled developers addressing refactoring issues.

  • dear sir, this tutorial is very helpful for me, but i need some more tutorials on fusebox. Developing coldfusion applications with coldfusion. I you can provide some more tutorials on it then it will be very helpful for me. thanks

Advertisement


Website Designed and Developed by Pablo Varando.