Persistence and Constructors


Plato's theory of forms speaks of how the reality of a thing is distinct from the physical manifestation of it. There is, for example, a notion of a cupa container from which one may drink liquid. Without being told anything else, you probably already have a "mental image" of a cup. Does it have a handle of some sort? Is it made from glass or clay? Is it decorated with stripes or is it a solid color? It doesn't matter! You are still picturing a cup.

Next, imagine that you are brought to a table on which are placed a number of common itemsa hat, a book, some coins, and a cup. I would guess that, without regard to size, color, material, or the presence or absence of a handle, you would not have too much trouble identifying which object is the cup. How is it that you could make that identification when you didn't really know the details of the cup for which you were looking? According to Plato, it's because the notion of "cup" is the realitynot the individual, physical occurrences of each and every cup. There is such a thing as "cupness," which is shared by all the different cups that are and ever have been.

If you sit at a pottery wheel and make a cup, that which makes it a cup and not, say, a duck, will persist long after the physical cup that you make has turned to dust with age. So it's not "cupness" that you cast; it's a specific cup. Likewise, if you were to trip while carrying that cup full of steaming coffee to the breakfast table, it might smash beyond repair (and set you up for a generally lousy day), but that will not eradicate the notion of a cup from the mind of humankind. "Cup" will survive long after yours has gone.

From this example, and given the preceding discussion, you can probably see where this is going: This notion of a cup is like our component object, and each actual, physical cup is the instance of that component.

If a component represents an Actor, there will be (as was the case with Plato's cup) properties unique to each instance of that component (the names Harrison Fjord versus Mirror Sorvino, for example). Each of these instances can exist for certain durations in the ColdFusion applicationthe life of the page, a session, and so on. What if the instance of the component could last longer even that that? We don't want a paper cup that we use and throw out after each use, but rather a solid ceramic mug that greets us every morning!

Persistent components are components in which the instance-specific properties are permanently stored outside the Web application in a databasethe cupboard for your components, if you will. Each instance and its properties are manipulated with a common set of methods.

This common set of methods will already be familiar to anyone who has created most types of data maintenance applications with ColdFusion in the past. Consider what you do with records in those types of applications:

  • Create new records

  • Edit existing records

  • Retrieve existing records

  • Delete records

These actions correspond to the four basic SQL operations used:

  • Insert

  • Update

  • Select

  • Delete

In persistent components, there will be a method to do each of those tasks with names more intuitive than their SQL counterparts:

  • Create method

  • Edit method

  • Get method

  • Delete method

A fully persistent component, then, would be one with all four methods: create, edit, get, and delete. Let's create a persistent component that includes all four of the required methods.

The component will work exclusively from the THIS scope, so each method will manipulate the values in the THIS scope. We create an addActor function that inserts a record, deleteActor to remove one, and so on. addActor could take its information from arguments passed in, but since we have a persistent component, we will use the values in the THIS scope, and then insert the component current information into the database in addActor. Each of the four persistence methods, then, will perform one of the actions listed in Table 19.1.

Table 19.1. Persistence Methods

METHOD

ACTIONS

Create

Inserts new record into database table Sets the new identity field value into THIS scope

Edit

Updates database record with current corresponding THIS variable values

Get

Retrieves database record based on current THIS ID field value Sets other THIS variable values to result of database select

Delete

Removes record from database where ID equals THIS ID field


The Actor component is going to be the ColdFusion application's interface to a record in the Actors table of the OWS database (Figure 19.7). Anytime an instance of the component is created, the THIS scope must be populated with variables to correspond to each table column. This is one use of constructors, which we'll explore next.

Figure 19.7. The fields in the OWS Actors table.


Constructors

In the earlier section about the THIS scope, the very first bit of CFML that was shown after the <cfcomponent> tag (<cfset this.Items = arrayNew(1)>) was not in a <cffunction> block. In CFCs, any code that is within the <cfcomponent> tags but not inside of a <cffunction> tag block is executed when the component is instantiated and is called the component's constructor. As was the case in that earlier example, the constructor is a good place to do any "setting up" necessary for using the component: initializing variables, calling an initializing function, performing some preliminary database lookups, and so on. For our Actor component, then, we will use this constructor to create each of the THIS scope variables needed for the instance.

With a variable for each database column in the THIS scope of the component, all that remains is to code the four functions that will either pass data from the THIS scope to the database, or retrieve data from the database and add it to the THIS scope. Listing 19.12 shows the completed component.

Listing 19.12. pActor.cfcThe Database Persistent Actor Component

[View full width]

 <!---   pActor.cfc - Persistent Actor Component   As modified by Ken Fricklas (kenf@fricklas.com)   Modified: 2/15/2005   Code from Listing 19.12 ---> <cfcomponent hint="A Persistent Actor Component"> <!--- One param in the THIS scope for each field in the DB table ---> <cfset THIS.ActorID = "0"> <cfset THIS.NameFirst="NONE"> <cfset THIS.NameLast="NONE"> <cfset THIS.Age="0"> <cfset THIS.NameFirstReal="NONE"> <cfset THIS.NameLastReal="NONE"> <cfset THIS.AgeReal="0"> <cfset THIS.IsEgomaniac="1"> <cfset THIS.IsTotalBabe="0"> <cfset THIS.Gender="F"> <cffunction name="create">   <!--- Enter a new record into the DB table and set THIS.ActorID to the new ID --->   <!--- Wrap the two queries in a transaction so that INSERT and @@identity SELECT will be  treated as a single SQL statement to prevent concurrency problems    --->   <cftransaction>     <cfquery name="create" dataSource="OWS">       INSERT INTO Actors         (NameFirst, NameLast, Age, NameFirstReal, NameLastReal,           AgeReal, IsEgomaniac, IsTotalBabe, Gender)       VALUES         ('#THIS.NameFirst#', '#THIS.NameLast#', #THIS.Age#, '#THIS.NameFirstReal#', '#THIS .NameLastReal#', #THIS.AgeReal#, #THIS.IsEgomaniac#, #THIS.IsTotalBabe#, '#THIS.Gender#')     </cfquery>     <cfquery name="ID" dataSource="OWS">       SELECT @@identity as NewID     </cfquery>     <cfset THIS.ActorID = ID.NewID>   </cftransaction> </cffunction> <cffunction name="edit">   <!--- Set the DB record for THIS.ActorID to whatever values are currently in the THIS  scope --->   <cfquery name="edit" dataSource="OWS">   UPDATE Actors     SET NameFirst='#THIS.NameFirst#',      NameLast='#THIS.NameLast#',      Age='#THIS.Age#',      NameFirstReal='#THIS.NameFirstReal#',      NameLastReal='#THIS.NameLastReal#',      AgeReal=#THIS.AgeReal#,      IsEgomaniac=#THIS.IsEgomaniac#,      IsTotalBabe=#THIS.IsTotalBabe#,      Gender='#THIS.Gender#'     WHERE ActorID = #THIS.ActorID#   </cfquery> </cffunction> <cffunction name="get">   <!--- Retrieve an existing record from the DB and set it into the THIS scope --->   <cfquery name="get" dataSource="OWS">     SELECT *       FROM Actors       WHERE ActorID = #THIS.ActorID#   </cfquery>   <cfset THIS.NameFirst=get.NameFirst>   <cfset THIS.NameLast=get.NameLast>   <cfset THIS.Age=get.Age>   <cfset THIS.NameFirstReal=get.NameFirstReal>   <cfset THIS.NameLastReal=get.NameLastReal>   <cfset THIS.AgeReal=get.AgeReal>   <cfset THIS.IsEgomaniac=get.IsEgomaniac>   <cfset THIS.IsTotalBabe=get.IsTotalBabe>   <cfset THIS.Gender=get.Gender> </cffunction> <cffunction name="delete">   <!--- Delete the record corresponding to THIS.ActorID --->   <cfquery name="delete" dataSource="OWS">     DELETE       FROM Actors     WHERE ActorID = #THIS.ActorID#   </cfquery> </cffunction> </cfcomponent> 

Using this kind of component will result in CFML pages that are coded in a way quite different than what has been common when using versions of ColdFusion before ColdFusion MX. The function of the pages will be to view and set values in the THIS scope of component instances. For example, a page on which you will display an actor's detailed information will set the appropriate ID of the actor into the THIS scope and then execute the get method (Listing 19.13). The individual developing the CFML page doesn't need to know anything about the database or even SQLsimply the name of the method to execute. This can be extremely powerful in very large applications where multiple developers are working simultaneously on multiple tiers of the application. If the database architecture changes, the component developer can change the SQL accordingly and the page developer doesn't need to change a thing; she simply needs to know that the get method is the way to retrieve an Actor.

Listing 19.13. testPActor.cfcUsing a GET Method to Retrieve an Actor

[View full width]

 <!---   testPActor.cfc   Component that shows calling and outputting data from the persistent actor (pActor)  component.   Modified by Ken Fricklas (kenf@fricklas.com)   Modified: 2/15/2005 ---> <!DOCtype HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4 /loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <title>Test Persistent Actor</title> </head> <body> <cfscript>   // Create an instance of the Actor component   myActor = createObject("component","pActor");   // Set the ID in the THIS scope   myActor.ActorID=1;   // Get the details   myActor.get(); </cfscript> <!--- Regular output techniques are used ---> <cfoutput> #myActor.NameFirst# #myActor.NameLast# </cfoutput> </body> </html> 

How would a CFML page update an Actor using this approach? The same steps are used. An instance of the component is created, the values are set in the THIS scope (in this case, based on those in the FORM scope if coming from a form post), and, finally, the method (edit) is executed (Listing 19.14). For the person coding the implementation, this is a much more intuitive approach"Set the new values and save them" as opposed to "Update the database fields based on their corresponding values in the form."

Listing 19.14. updatePActor.cfmThe Complete Update Page
 <!---   updatePActor.cfm   Demonstrates update in a persistent component   Modified by Ken Fricklas (kenf@fricklas.com)   Modified: 2/15/2005   Code from Listing 19.13. ---> <HTML> <HEAD> <TITLE>Persistence - Update Actor</TITLE> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> </HEAD> <BODY> <cfif isDefined("FORM.doEdit")>   <cfscript>   // Create an instance of the Actor component     myActor = createObject("component","pActor");   // Set the ID in the THIS scope     myActor.ActorID = FORM.ActorID;   //Set all of the component's variables based on those that came from the FORM     myActor.NameFirst=FORM.NameFirst;     myActor.NameLast=FORM.NameLast;     myActor.NameFirstReal=FORM.NameFirstReal;     myActor.Age=FORM.Age;     myActor.IsEgomaniac=FORM.IsEgomaniac;     myActor.IsTotalBabe=FORM.IsTotalBabe;   // Execute the method     myActor.edit();   </cfscript> </cfif> <cfscript>   // Create an instance of the Actor component     myActor = createObject("component","pActor");   // Set the ID in the THIS scope     myActor.ActorID = 8;   // Get the details     myActor.get(); </cfscript> <cfoutput> <H1>Edit Actor</H1> <FORM ACTION="#cgi.script_name#" METHOD="post"> <INPUT TYPE="HIDDEN" NAME="ActorID" VALUE="#myActor.ActorID#"> <TABLE BORDER="1">   <TR>     <TD>First Name</TD>     <TD><INPUT NAME="NameFirst" TYPE="text" value="#myActor.NameFirst#"></TD>   </TR>   <TR>     <TD><EM>Real</EM> First Name</TD>     <TD><INPUT NAME="NameFirstReal" TYPE="text" value="#myActor.NameFirstReal#"></TD>   </TR>   <TR>     <TD>Last Name</TD>     <TD><INPUT NAME="NameLast" TYPE="text" value="#myActor.NameLast#"></TD>   </TR>   <TR>   <TR>     <TD>Age</TD>     <TD><INPUT NAME="Age" TYPE="text" value="#myActor.Age#"></TD>   </TR>   <TR>     <TD>A total babe?</TD>     <TD>       yes       <INPUT NAME="IsTotalBabe" TYPE="radio" VALUE="1"         #IIF(myActor.IsTotalBabe eq 1, DE("CHECKED"), DE(""))#>         &nbsp;&nbsp;       no       <INPUT NAME="IsTotalBabe" TYPE="radio" VALUE="0"         #IIF(myActor.IsTotalBabe eq 0, DE("CHECKED"), DE(""))#>     </TD>   </TR>   <TR>     <TD>An Egomaniac?</TD>     <TD>       yes       <INPUT NAME="isEgomaniac" TYPE="radio" VALUE="1"         #IIF(myActor.isEgomaniac eq 1, DE("CHECKED"), DE(""))#>         &nbsp;&nbsp;       no       <INPUT NAME="isEgomaniac" TYPE="radio" VALUE="0"         #IIF(myActor.isEgomaniac eq 0, DE("CHECKED"), DE(""))#>       </TD>   </TR> </TABLE> <BR>   <INPUT NAME="doEdit" TYPE="submit" VALUE="Save Changes"> </FORM> </cfoutput> </BODY> </HTML> 



Advanced Macromedia ColdFusion MX 7 Application Development
Advanced Macromedia ColdFusion MX 7 Application Development
ISBN: 0321292693
EAN: 2147483647
Year: 2006
Pages: 240
Authors: Ben Forta, et al

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net