|
Comments
Did you read today's front page stories & breaking news?
SYS-CON.TV
|
BF on CF ColdFusion Components and Data Abstraction
CFCs provide basic object functionality to CF developers part 2
By: Ben Forta
Jul. 14, 2004 12:00 AM
In my last column we looked at using ColdFusion Components to abstract database access, essentially divorcing presentation code from anything database specific. As you will recall, the benefit of this was that when a database change occurred (a column being renamed, for example), presentation code was not impacted at all. In this column I'II take this concept one step further. Beyond Simple Abstraction
<!--- Get employees --->
<CFINVOKE COMPONENT="emps"
METHOD="list"
RETURNVARIABLE="employees">
<!--- Display list --->
<UL>
<CFOUTPUT QUERY="employees">
<LI>#LastName#, #FirstName#</LI>
</CFOUTPUT>
</UL>
<CFINVOKE> invokes list in component emps, which obtains an employee list. emps.cfc contains (as we left it last month), with two methods: list is used to obtain a list of users, and update is used to update an employee's name (see Listing 1). So far so good. Components Are NOT Query Replacements But CFCs aren't designed to simply be inline query replacements. In fact, CFCs need not map to database tables or queries at all. For example, if you had an online store you'd probably work with several types of components:
Components As Objects
<!--- Get employees object --->
<CFOBJECT COMPONENT="emps"
NAME="emp">
<!--- Get employees --->
<CFINVOKE COMPONENT="#emp#"
METHOD="list"
RETURNVARIABLE="employees">
<!--- Display list --->
<UL>
<CFOUTPUT QUERY="employees">
<LI>#LastName#, #FirstName#</LI>
</CFOUTPUT>
</UL>
If you were to run this code, it would generate the exact same output as the previous invocation example. But something is very different here. Previously, <CFINVOKE> was used to access a component and then invoke a method. It did both of those tasks, all in one tag. Here we have separated the component access from the method invocation. <CFOBJECT> loads the component as an object - the new object is named emp. This <CFOBJECT> call does not execute any method; in fact, no method name is even specified. It is <CFINVOKE> that invokes the list method in the already loaded component object. (Notice that #'s are used in the COMPONENT attribute in <CFINVOKE. This is because it refers to a variable as opposed to a file name). The advantage of this type of access and invocation is that it allows for components to be instantiated (obtain an instance of) independent of any method invocation. This allows for multiple invocations against the same component (perhaps a series of inserts or updates). It also allows components to persist (to stick around, especially if the object is in a persistent scope like SESSION or APPLICATION). And it allows for alternate forms of invocation. Look at this example:
<!--- Get employees object --->
<CFOBJECT COMPONENT="emps"
NAME="emps">
<!--- Get employees --->
<CFSET employees=emps.list()>
<!--- Display list --->
<UL>
<CFOUTPUT QUERY="employees">
<LI>#LastName#, #FirstName#</LI>
</CFOUTPUT>
</UL>
Once again, the code here accomplishes the same result as in the previous examples, but notice that there's no <CFINVOKE> tag used here. Rather, a simple <CFSET> is used to save the results of emp.list() (the list method in component emp) to a variable named employees. This form of invocation is used when working with objects, which is what the component here is being used as. Once a component is loaded as an object, it can be used in lots of different ways, and repeatedly too. Methods, More Methods, and Even More Methods For example, imagine we had a second component we could use. Unlike emps.cfc which is used to access all employees (lists of employees), emp.cfc provides access to a single employee, and everything that you'd need to know about him or her. Look at this simple invocation in Listing 2. <CFOBJECT> instantiates the employee object, just as we saw previously. But which employee's object is this? Actually, it's not associated with any employee - we'd need to do that ourselves. The <CFSET> statement invokes an Init method (as in initialize) and passes an employee ID as an argument (we've hard-coded it to 22 here, but you could pass a variable or any expression instead). Once initialized, the employee object can provide access to everything you'd want to know about an employee. The GetName method (invoked as #emp.GetName()#) returns the employee name, GetStartDate returns the employee start date (which is formatted using the DateFormat() function), GetYears returns the number of years at the company, and EligibleForCar returns true if the employee has worked long enough to be entitled to a company car (hey, we can all dream!). Load the object once, initialize it, and then use it over and over as needed. All of the code is presentation code. There is no database access, there is no logic, no calculations (as would be needed to figure our company car eligibility). All of that is buried in the little black box, the component. And once that component has been instantiated and initialized, all of the other methods can be invoked as needed. So what does the emp.cfc component look like? And how does it remember the employee that it is associated with? The code is shown at Listing 3. Component emp.cfc contains lots of methods. Init is an important one; it requires that an employee ID be passed to it as an argument, and it then uses it to query a database for employee details (using the emp_id in the SQL WHERE clause). The query name is THIS.emp, THIS is a special scope that refers to the CFC itself. As the query is placed into THIS, it persists for as long as the query does, and will be usable on subsequent method invocations. This is why, after calling init in the calling page, the code was able to make all of those subsequent method invocations. The GetName method returns an employee name, extracted from the saved query. The CFC need not query the database again, as the query created in init still exists (in THIS). GetFirstName and GetLastName do exactly what their names suggest. They are not used in our example, but you will generally want to create all the methods that you may end up using at some point. There's no downside to doing this, and the extra effort up front will make the components far more reusable. GetStartDate returns the employee start date stored in the table. GetYears uses the start date to calculate the numbers of years of employment. This is a great example of the type of calculation that's too often erroneously placed in presentation code (where it's used, but where it absolutely does not belong). The EligibleForCar method is similar; it does the calculation (need to have been employed for at least 5 years) and simply returns true or false. This type of calculation does not belong in presentation code, ever. Logic, business rules, data abstraction, all of that and more belong in CFC code. Presentation code is for, well, presentation. We're Just Getting Started But beyond simple database abstraction, ColdFusion Components should be used for all data abstraction, including calculations, business logic, any data processing, and more. Yes, it takes a little more time up front. But once you try it you'll be pleasantly surprised to discover that it really is just a little more time. And the upside?
Summary Reader Feedback: Page 1 of 1
Latest Cloud Developer Stories
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
|
SYS-CON Featured Whitepapers
Most Read This Week
Breaking Cloud Computing News
|
|||||||||||||||||||||||||||||||||||||||||||||||||