456 Part IV ✦ ColdFusion MX Components, Web Services, and Flash IntegrationBy now, you probably get the basic idea that, at its most basic level, a component is like acontainer for relat
Trang 1456 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
By now, you probably get the basic idea that, at its most basic level, a component is like acontainer for related functions, and invoking component functions is much like invoking localfunctions except that you must also specify the name of the component that contains thefunction
So big deal? You bet! Even the most basic use of the simplest components changes your
approach to ColdFusion development, because you’re now completely separating logic frompresentation; you’re exposing logic as a set of simple, yet formal function calls available toany part of your application (even remote applications, as you see in Chapters 25 and 26);and you’re encapsulating the functions related to a single entity into a single component.And if you think components are just a substitute for a bunch of CFINCLUDEs, keep reading
Separating logic from presentation
The need to separate logic from presentation is more important now than it has ever been for
a number of reasons, as outlined in the following list:
✦ The ever-increasing array of handheld devices and their widely varying display formats
✦ The renewed interest in syndicated content that must form-fit various Web layouts
✦ The trend away from delivering plain-text streams and HTML and toward deliveringgeneralized XML, XHTML, WML, and other “pivot” formats (i.e, formats that acts asintermediate steps in a data conversion process) that are further processed into fin-ished content on target devices
✦ The desire to easily expand very large corporate applications while minimizing newerrors or anomalies into the software
✦ The headlong rush into delivering better, faster Web applications through Flash MXRemoting technology
By encapsulating into a single component all the functionality related to an entity and thensimply calling on that component whenever data is needed to be retrieved, updated, deleted,and so on, you build applications that help achieve the goals of targeting common functional-ity to multiple display formats and building Enterprise-scale applications that are straightfor-ward to develop and easy to maintain
Another benefit of such encapsulation is the focus that it naturally places on good design Ifyou’ve developed in earlier versions of ColdFusion, think for a moment how you approachedpre-MX ColdFusion application design Data was the stuff that you shoved into and pulled out
of databases for the sole purpose of accomplishing some task spread out across a number ofindividual browser pages Sure, you had CFINCLUDE and custom tags, and you could createsnippets of reusable code if you were keen enough to spot duplicated code, but all your logicwas still thinly spread out across multiple templates located who-knows-where
If you take the opposite approach and gather together all the functionality related to an entityinto a single component, you begin to “think like the entity” and ask yourself, “What does acompany need to do?” After the obvious partial answer of “Create, read, update, delete, andlist,” you begin to uncover a few specialized needs such as “calculate the annual sales of thecompany” and “tell me how many people are employed by this company” — all of which can
be incorporated into that one Company component
Before you even know what you’ve done, you’ve built a centralized source from which torequest all operations and data related to companies, regardless of how the data is supplied
to or requested from that source Now, all you need to do is call this functionality and displaythe results
Trang 2Get used to passing messages
So things are a little different from earlier versions of ColdFusion, eh? Now you have a formalinput interface requiring data of specific types and a formal output interface returning data of
a specific type — as you learn in Chapter 17, as you first start building user-defined functions
by using the new CFFUNCTION tag Now everything is done through messages: one messagecontaining arguments going in and one message containing the single result variable comingout This technique may seem a little odd at first, but this is precisely how object-orientedlanguages work
The Nickel Tour of objects
Your telephone is an object; it is a specific instance of the general class of telephones As do all other instances of the class telephones, your telephone has all the general properties of a tele-
phone: a receiver to which you can listen, a transmitter into which you can speak, a control fordialing someone’s number, and so on Any phone can also be expected to support a set of func-
tions, or methods: picking up the receiver, dialing a number, ringing, hanging up, and so on.
This Nickel Tour uses a fictional object-oriented syntax for teaching purposes It’s similar to asimplified form of Java that doesn’t require formal data typing or other complications
That telephone object that you hold in your hand is the combination of all the properties that describe it and the methods that it can perform In the physical world, your telephone was
manufactured in a factory In the object-oriented world, your telephone is conceptually factured as follows:
manu-yourTelephone = new Telephone();
Now you have an object named yourTelephone that is an instance of the class Telephone In object-oriented terms, you have just instantiated a Telephone object named yourTelephone.
yourTelephonecontains all the properties and methods that any new Telephone wouldhave because it was manufactured in the Telephone “factory” (that is, instantiated from theTelephoneclass)
In the physical world, you pick up your telephone’s receiver and dial a number with your ger In the object-oriented world, you tell your telephone to pick up its own receiver and thenyou tell your telephone to dial the number for you, conceptually, as follows:
fin-yourTelephone.OffHook();
yourTelephone.DialNumber(‘1-770-446-8866’);
Your friend Stan Cox has a telephone, too, as follows:
stansTelephone = new Telephone();
But Stan isn’t calling Productivity Enhancement as you are; he’s trying to find a hot date with
a woman who shares his main interest in life, as the following example indicates:
stansTelephone.OffHook();
stansTelephone.DialNumber(‘1-900-4CF-CHIX’);
Clearly, your telephone and Stan’s telephone can do the same kinds of things because theyare both objects of the Telephone class, but each telephone might do the same thing in a dif-
ferent way (such as dial a different number) because each is a separate, distinct instance of a
Telephone Your instance of a Telephone is named yourTelephone, and Stan’s instance of aTelephoneis named stansTelephone Each instance is a complete, standalone copy of allthe properties and methods that any Telephone has
Note
Trang 3458 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
Not all telephones are exactly alike
Stan’s telephone is similar to most other telephones, but his probably has a few functionsthat a public telephone doesn’t have, and his probably doesn’t have some of the functions ofLarry Ellison’s telephone (such as Oracle-based speed dial)
Stan was so enamored with his date that he has asked the factory to invent a Stan-specifictelephone with a special speed-dial function, as the following code describes:
class StanPhone extends Telephone {SpeedDial(theNumber) {
this.OffHook();
if (theNumber == ‘1’) {this.DialNumber(‘1-900-4CF-CHIX’);
}}}And Stan wants the factory to manufacture one of these phones for him, as follows:
stansnewTelephone = new StanPhone();
Now, whenever Stan wants to talk with a beautiful, intelligent ColdFusion programmer of thefemale persuasion, all he must do is the following:
stansnewTelephone.SpeedDial (‘1’);
Stan’s very special telephone extends the capabilities of a normal telephone with an
addi-tional method named SpeedDial(), which in turn makes use of the methods available to anytelephone (OffHook() and DialNumber())
Notice the prefix this used in the preceding code example to call the inherited methodsOffHook()and DialNumber() If you guessed that this refers to this instance, you’re right Because the StanPhone class simply extends the Telephone class, all the methods available
to the Telephone class are automatically a part of the StanPhone class and, as such, areavailable in all instances of the StanPhone class
Sometimes you don’t need a telephone at all
The methods that we’ve discussed so far operate on a specific instance of an object Dialing a
number on stansnewTelephone, for example, just dials it on that one instance of a phone If stansnewTelephone didn’t exist, you couldn’t dial a number from it These meth-
tele-ods are known as instance methtele-ods.
Some methods don’t operate on a specific instance of an object, but instead operate with
respect to the entire class of objects If Stan called the telephone manufacturer and asked
how many telephones had been manufactured to date, for example, the manufacturer mayask itself the following:
telephonesManufacturedToDate = Telephone.GetCount();
The GetCount() function in this code queries the manufacturer’s database and totals thenumber of telephones manufactured in all production runs to the present date
These methods are known as class methods because they operate on the entire class of
objects and not on just a single instance of an object
Trang 4So there you have the Nickel Tour of objects — just enough terminology and explanation sothat you can make sense of a discussion of ColdFusion components and understand at least a
little bit of the discussions comparing CFCs to true objects If you want more — and you know
that you do — learn Java Your career is sure to thank you
Components are similar to objects
Listing 22-2 encapsulates into a single component all the functionality related to a company
Every time that you need to do something to or get something from a company, you invokeone of the Company component’s functions and pass in the CompanyID used to identify the tar-get company; then your functions go out and manipulate that company’s data in the database
None of these functions do anything with data associated with the component itself; all these
functions directly manipulate the database without any regard to the concept of an instance.
In other words, these component functions are the equivalent of class methods in traditional
com-this chapter, in that This refers in com-this case to This instance (The difference in the
capitaliza-tion of This is due to the difference in syntax between ColdFusion and Java, which I used inthe Nickel Tour.)
So suppose that, inside your component, you set a variable in the This scope, as follows:
<cfset This.CompanyName = “Productivity Enhancement”>
In this code, you create a property for This instance of the Company component And suppose
that you then create a component function named GetCompanyName() that simply returnsthat property, as follows:
<cffunction name=”GetCompanyName” ReturnType=”String”>
<cfreturn This.CompanyName>
</cffunction>
You’ve now given the caller what it wants directly from the properties of an instance of the component In other words, GetCompanyName() is an instance method rather than a class method.
Before you can set a component property, you must get the data from somewhere — typicallyfrom a database query — and this query requires processing overhead So setting componentproperties becomes practical only if those properties are going to persist longer than a singlecomponent-function call — otherwise, you may just as well manipulate the database eachtime that a function is called
We get into the details of designing effective persistent components and instance methods inthe section “Persistent components,” a little later in this chapter; then you build one step bystep in Chapter 23 But for starters, we show you in the following sections how to create aninstance of a component that persists longer than a single function call
Trang 5460 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
Invoking a Component Function
If you invoke a component function by using the CFINVOKE tag, ColdFusion creates aninstance of that component and calls the function named in the Method attribute In essence,ColdFusion instantiates an object of the class of that component, but the name of that object
is invisible to you (It’s internally referenced by ColdFusion Server.) If you use CFINVOKE tocall three of a component’s functions in a single ColdFusion template, as shown in Listing22-3, ColdFusion Server creates three separate instances of that component to give you whatyou want, and that’s not very efficient
Listing 22-3: Repetitively instantiating a component
Trang 6<cfinvokeargument name=”CompanyID” value=”8”>
Using the CFOBJECT tag isn’t the only way to instantiate an object The CreateObject()function returns an object as well The following three lines of code, for example, produce thesame results:
<cfobject name=”myCompany” component=”Company”>
<cfset myCompany = CreateObject(“Component”, “Company”)>
<cfscript>myCompany = CreateObject(“Component”, “Company”);</cfscript>
Similarly, using CFINVOKE isn’t the only way to invoke a component function After you create
an instance of a component, you can call its methods by using simple dot notation Listing22-5, for example, returns the list of companies produced by the ListCompanies function to
a variable named listOfCompanies
Listing 22-5: Invoking a component function by using dot notation
Note
Trang 7462 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
You can directly access component functions via forms and URLs, but the results are cally worthless Instead of defining a return value to pass from your function to the functioncall that invokes it, you must push displayable content directly out of the body of the func-tion, as shown in Listing 22-6
basi-Listing 22-6: Using direct function output instead of a return value
<cffunction name=”OutputTest” output=”yes”>
<cfquery name=”companyRecs” datasource=”#Request.MainDSN#”>
SELECTCompanyID,CompanyName,Address,City,State,ZipCode,CommentsFROM
CompanyORDER BYCompanyName
func-If you absolutely must create a function that directly outputs content, remove theReturnTypeattribute from the CFFUNCTION tag and add Output=”Yes” Never have both areturn type and direct output in the same function
The Output attribute actually has the following three states:
✦ Output=”Yes” treats the entire function as if it were inside a CFOUTPUT tag pair
✦ Output=”No” treats the entire function as if it were inside a CFSILENT tag pair
✦ Eliminating the Output attribute entirely enables explicit CFOUTPUT tags inside thefunction to leak output to the caller
We haven’t been explicit about the Output attribute yet because this is a learning chapter,and we want to eliminate as much extraneous code as possible so that you can focus your
concentration on specific topics Chapter 23, on the other hand, is a doing chapter, where you
start actually building these little monsters, so starting in that chapter, we explicitly specifyOutput=”No”for all component functions, which is a best practice
Trang 8Persistent Components
In the preceding sections of this chapter, you learn how to create a named instance of a ponent, you find out about the basics of instance properties in a component’s This scope,and you learn the differences between class methods and instance methods Now to putthese theories into action!
com-The instance of the component that you create in Listing 22-5 persists only as long as thepage request and then ColdFusion Server automatically destroys it If you want to work with apersistent component past a single page request, you simply must create it in a persistentscope that lives longer than one request, as shown in Listing 22-7
Listing 22-7: Persisting an instance of a component in a long-lived scope
This means that you can execute one ColdFusion template that creates an instance of theCompanycomponent, go have a cup of coffee, execute a second ColdFusion template thatinvokes a function of that component, go place a bid on eBay, execute a third ColdFusion template that invokes another function of that component, and so on, until you pause longerthan your session timeout permits and the instance is destroyed This is why we refer toCompanyas a long-lived persistent component.
Components can also be persisted in the Application scope as well Just remember that allusers of your application use the same instance of your component, so locking becomes evenmore critical and performance bottlenecks potentially become more of a concern if your component manipulates properties in its This scope
We bet that, right now, you’re thinking, “I’m clustering my application, which means that Idon’t use Session variables anywhere, so I’m going to persist my component instance by serializing it with WDDX (see Chapter 30 for details) and storing it in the Client scope.” That’s
a clever idea, but unfortunately, it doesn’t work If you serialize a component instance, theproperties in the This scope serialize just fine, but you lose all your functions, so on deserialization, all you get back are the properties
Why use a persistent component?
Why use a persistent component? Good question! Why create an “object-wannabe” that ries its own data (properties) around with it? A few practical applications of persistent com-ponents do exist, but one in particular clearly stands out
car-As you may remember from Chapter 8, if an attribute must be present to effectively describe
an entity, that attribute cannot contain a NULL value You can never, therefore, insert a partialrecord into a database table If one or more of these non-NULL values must be calculated from
Trang 9464 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
currently unavailable values, or if the value is discovered or created late in some user task,you need a temporary staging area to store your partial data, and a persistent component’sproperties fit the bill nicely for this purpose
So one good application for a long-lived persistent component is a wizard that collects datathroughout a complicated process and then calls component functions that insert or updatethe component’s properties into the database after you collect sufficient data to form eachentity completely
You begin to build a partial Company wizard in the next section, to see the basics of how apersistent component can be useful; then you complete the wizard in Chapter 23 to see howyou’d deploy it as a complete solution
The elements of a persistent component
The following list describes what you need to create a persistent component that makes use
of its properties:
✦ A granular locking mechanism bound to the component
✦ An Initialization() function that creates the component’s properties
✦ A GetEntity() function that retrieves data from the database
✦ A FlushEntityToDatabase() function that sends data to the database
The names of the preceding functions are only generalizations You may name your functionsanything you want
Some developers also create specific component functions to formally set and get specificproperties or collections of properties We discuss these “setters and getters” in the section
“Using setters and getters,” a little later in this chapter
A granular locking mechanism bound to the component
First, because your component persists in a shared memory scope (Session or Application),you need to pay attention to locking As we mention in Chapter 12, locking an entire scopecreates a bottleneck through which all requests to that scope’s variables must pass
To prevent such bottlenecks, we use named locks with persistent components We use the
CreateUUID()function to generate our lock name — which ensures that our lock name isunique from any other lock name — and we bind our lock name to the component itself bystoring it in a component property, as follows:
This.lockName = CreateUUID();
But where should we execute this line of code? We need our lock name to become available
as soon as we create an instance of the component, but we must execute this code only once
to prevent our lock name from changing, as we must refer to the lock name in calls to thecomponent
Fortunately, an initialization area inside every component serves this purpose Any code thatyou place between the CFCOMPONENT tag and the first CFFUNCTION tag executes only once if
an instance of the component is created through either CFOBJECT or CreateObject() orthrough a direct call to an uninstantiated component from CFINVOKE
Trang 10So we place our lock-naming code in the component’s initialization area, as follows:
An initialization() function that creates the component’s properties
After a persistent component is first instantiated, it should contain all the properties that it’sever to have during its lifecycle The values of these properties, of course, change as you addand modify data in the tasks that make use of the component, but they must start off withsome value — typically an empty string or zero, depending on the property’s data type
In this wizard example, you initialize these properties by using an InitCompany() function,
Trang 11466 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
A GetEntity() function that retrieves data from the database
The initialization function that you create in the preceding section initializes the componentproperties to a “blank canvas” ready to be painted with new values, but sometimes you’regoing to edit an existing collection of data rather than create new data, so you’re going toneed a way to get that data from your most common external source, the database The fol-lowing example shows you how to do so:
<cffunction name=”GetCompany” returntype=”query”>
<cfargument name=”CompanyID” type=”numeric” required=”yes”>
<cfquery name=”companyRec” datasource=”#Request.MainDSN#”>
SELECTCompanyID,CompanyName,Address,City,State,ZipCode,CommentsFROM
CompanyWHERECompanyID = #Arguments.CompanyID#
<cfscript>
This.lockName = CreateUUID();
InitCompany(10);
</cfscript>
<cffunction name=”InitCompany” returntype=”void”>
<cfargument name=”companyID” type=”numeric” required=”Yes”>
Trang 12But this method doesn’t serve you well at all, because it hard-codes CompanyID 10 into theinitialization function Passing an argument to the initialization area of a component is impos-sible, so you can call InitCompany() only from within the component initialization area.
The trick is to create an initialization function that takes an optional argument containing aCompanyIDand then set an additional property that describes whether the component is ini-tialized with empty values or data from a database record, as follows:
<cfscript>
This.lockName = CreateUUID();
InitCompany();
</cfscript>
<cffunction name=”InitCompany” returntype=”void”>
<cfargument name=”companyID” type=”numeric” required=”no”>
com-The other important thing that you do is to create an additional property namedisNewCompanythat indicates whether the component instance currently represents a newcompany to be created in the database or an existing company to be updated in the database
The following section shows how the isNewCompany property is used
Trang 13468 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
A FlushEntityToDatabase() function that sends data to the database
Your component’s properties eventually must find their way to the database so that they canpersist longer than the timeout of the Session or Application scope into which the component
is instantiated For this purpose, you create a function that either inserts or updates the record
in the database, depending on whether the properties represent a new or an existing record, asthe following example shows:
<cffunction name=”FlushCompanyToDatabase” returntype=”void”>
<cfif This.isNewCompany>
<cfquery name=”insCompany” datasource=”#Request.MainDSN#”>INSERT INTO Company(
CompanyName,Address,City,State,ZipCode,Comments)
CompanyName = ‘#Trim(This.companyName)#’,Address = ‘#Trim(This.address)#’,
City = ‘#Trim(This.city)#’,State = ‘#Trim(This.state)#’,ZipCode = ‘#Trim(This.zipCode)#’,Comments = ‘#Trim(This.comments)#’
WHERECompanyID = #This.companyID#
Trang 14Where to apply locking
If you’ve been highly suspicious of the persistent component in the preceding sections, you’re
on the ball! If you’re going to persist this component in the Session scope, where does the ing go? The complete answer is, “Anywhere that you access the This scope after initialization.”
lock-Because you no longer need to worry about data corruption in shared-memory scopes, you
now must concern yourself only with preventing race conditions, where two pieces of code
attempt to access the same shared-memory variables at the same moment During tion of a component instance into the Session or Application scope, nothing except the singleline of code that creates the object (the CFOBJECT tag or the CreateObject() function) canpossibly access that object, so locking is not needed to set This.lockName, nor is it needed
initializa-if InitCompany() is called from the initialization area of the component, so you can eliminatethe use of CFLOCK there
You do, however, need to lock the portions of the InitCompany() function that access theThisscope during all later calls, and because such code is inside a CFSCRIPT tag pair, youmust lock the entire CFSCRIPT block And because this access modifies the This scope ratherthan simply reading it, the lock needs to be an exclusive one, as in the following example:
The only other function in your persistent component that requires locking is theFlushCompanyToDatabase()function, because it reads from the This scope, as the follow-ing example shows:
Trang 15470 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
<cffunction name=”FlushCompanyToDatabase” returntype=”void”>
CompanyName = ‘#Trim(This.companyName)#’,Address = ‘#Trim(This.address)#’,
City = ‘#Trim(This.city)#’,State = ‘#Trim(This.state)#’,ZipCode = ‘#Trim(This.zipCode)#’,Comments = ‘#Trim(This.comments)#’
WHERECompanyID = #This.companyID#
Trang 16func-Preventing function variable leakage: the Var scope
If you declare a local variable in the standard fashion inside a function, that variable “leaksout” of the function and can be accessed and modified by code outside the function itself
This isn’t just a quibbling little piece of trivia, because such behavior can inadvertently ify values outside your function
mod-We discuss this problem in Chapter 17 but it bears repeating here because the problem lows user-defined functions whenever they are placed inside components If you have multi-ple functions in your component that use the same variable names (a very common andexpected occurrence), this variable leakage causes you no end of problems
fol-Solve this problem by creating a function variable declaration block immediately after the last
CFARGUMENTtag in your function and then declaring the initial values of the variables thatshould live only inside your function, as follows:
<cfset Var aVar = “”>
<cfset Var anotherVar = “”>
<cfset Var yetAnotherVar = “”>
The Var keyword places the declared variable into the Var scope, which is a special scopethat lives only inside user-defined functions By declaring function-only variables in the Varscope, you absolutely guarantee that your variables don’t leak outside the function
Declaring a variable in the Var scope can take place only before any logic is performed by thefunction, which is why you must always place your function variable declaration block imme-diately after the final CFARGUMENT tag in your function In fact, ColdFusion is so strict aboutthis rule that you can’t even use a CFSCRIPT block to perform simplified multiple Var declara-tions inside a CFFUNCTION tag, as the opening CFSCRIPT tag is considered to be a line of logic,
so it violates the rule that Var declarations must come first
Because of the placement restrictions of the function variable declaration block, you don’talways know the final value of all Var-scoped variables after they are declared In this case,just initialize the variable with an empty string (as shown in the example in the preceding section) Then later, whenever you want to assign the final value to the variable, just treat thevariable as if it is a local variable We can use this technique in the InitCompany() function
to prevent the variable containing the query object from leaking outside the function, as thefollowing example shows:
<cfargument name=”companyID” type=”numeric” required=”no”>
<cfset Var CompanyInitRec = “”>
Trang 17472 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
} else {This.companyID = 0;
CompanyInitRec If no such Var-scoped variable of the same name exists, ColdFusion creates
a local variable of that name that leaks outside the function
In fact, for every query you create inside a function, whether via CFQUERY or CFPROCRESULT,you should first CFSET a Var-scoped variable of the same name as the query to an emptystring This will prevent your queries from leaking out of the functions that create them Wedidn’t use this practice until now in this chapter in order to isolate you from details while youwere getting a basic understanding of components
Now you know that the core functionality makes a persistent component useful And now thatyou have a persistent component, you can play with it
Working with component properties
To begin learning how to work with component properties, persist an instance of your newPersistentCompany.cfccomponent in the Session scope, as follows:
<cfscript>
Session.myCompany = CreateObject(“Component”, “PersistentCompany”);
</cfscript>
At this point, all properties of Session.myCompany are empty strings and zeros If you want
to re-initialize Session.myCompany with the company that has a CompanyID = 10, you cancall the InitCompany() function as follows:
<cfscript>
Session.myCompany.InitCompany(10);
</cfscript>
Reading and modifying component properties directly
Now the properties of Session.myCompany contain data from the Company record that has aCompanyID = 10 So you can directly output the company name persisting in the instance asfollows:
Trang 18(Remember that the This inside the component instance correlates toSession.myCompany.outside the component instance).
Hey — doesn’t this locking look a little weird? Or at least very inconsistent? Well it may lookthat way, but it’s perfectly legitimate Let us explain
You don’t need to lock the instantiation of the component, even though it is being ated in the Session scope, because no race condition can possibly exist during instantiation
instanti-You also don’t need to lock the call to Session.myCompany.InitCompany(10) because theInitCompany()function handles its own locking
But now you come to what appears to be a conundrum: How do you acquire a named lockwhere the name of the lock itself is in the Session scope? Doesn’t
Session.myCompany.lockNameneed to be locked before it is accessed?
The answer is “no” because This.lockName (that is, Session.myCompany.lockName) isnever written to more than once throughout the entire life cycle of the component’s Thisscope (or the Session scope that, in turn, contains it) If This.lockName is, in essence, a
write-once constant, no race condition can ever occur, so no locking is needed.
If This.lockName can ever be rewritten, even with the same value that it already contained,you would need to lock it on every read The decision to lock is based on whether the vari-able is written to memory only once or multiple times during its scope’s life cycle and notwhether its value changes from one writing to the next
You do need to ReadOnly lock access to Session.myCompany.companyName on outputting it,
however, because it may be read while another piece of code attempts to modify its value
Similarly, you must exclusively lock any direct writes to the instance’s This scope (via
Using setters and getters
Our preference is to directly set and get instance properties by using the techniques shown
in the preceding section They are quick, easy, sure, and perfectly legitimate techniques — aslong as you pay careful attention to locking requirements
Another technique is often favored by developers who come from the object-oriented world,where a whole slew of specific granular component functions are created for the sole purpose
of setting and getting instance properties
So, for example, you don’t want to do the following:
Trang 19474 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
Trang 21476 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
Just don’t bow down to the self-appointed “object gods” who try to convince you that youmust employ setters and getters for absolutely everything that accesses the This scope Thetechnique that you choose to employ is entirely up to you
Security
Components centralize business logic rather than leaving it distributed among various plates and directories, and with this change in code location comes a necessary change inthe mechanism used to restrict code access
tem-ColdFusion MX has a new mechanism for authenticating and authorizing users that is verystraightforward and easy to use Based on user roles and requiring just a few simple tags andfunctions (CFLOGINUSER, IsUserInRole(), CFLOGOUT, and so on), the new security mecha-
nism creates an ID badge from a user name and a list of roles in which the user has been
granted membership; it then stores that ID badge in a nonpersistent cookie Each browserrequest presents this ID badge to ColdFusion Server, which uses it to determine whether theuser making the request is authenticated (that is, he is who he says he is) and authorized(that is, he has membership in a role that is authorized to access that part of the application).Chapter 40 contains an excellent discussion of exactly how ColdFusion MX’s security frame-work functions and how to build a working user login system for your own applications Ifyou’re not already familiar with all of MX’s security-related tags and functions, take a few minutes to read Chapter 40 before proceeding so that you can get more out of the followingdiscussion
Restricting access at the component level doesn’t make sense because a component maycontain many different functions So ColdFusion MX restricts access at the function levelinstead Preventing unauthorized access to a function is as simple as adding the Rolesattribute to the CFFUNCTION tag, as in the following example:
<cffunction name=”DeleteCompany”
returntype=”void”
output=”No”
Trang 22If the roles attribute is omitted from the CFFUNCTION tag, any user may access that function,provided that some other security mechanism doesn’t prevent him from calling the function.
Access Levels
Whereas component-function security grants access to users, setting the access level of
a component function grants access to software Access levels apply only to component
functions
You have the following four access levels:
✦ Public: This degree of access is the default access level for a component function.
Public access enables the function to be invoked by another local component orColdFusion template but not from an external source such as Flash Remoting Services
or consumed as a Web service
✦ Private: This level of access “hides” the component function from everything outside
the component that contains it so that it can be invoked only from other functionswithin the same component
✦ Package: This level of access restricts a component function to invocation by function,
either from within the same component or from within another component in the samepackage Component packages are discussed in the section “Advanced ComponentConcepts,” later in this chapter
✦ Remote: This level of access enables a component function to be invoked from any
local or remote system This is the access level that you must choose to make a nent function available as a Web service or to Flash Remoting applications
compo-Use a combination of tight security and restrictive access levels to diligently restrict all ponent functions to only those users and software that must have authorization
Trang 23com-478 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
Advanced Component Concepts
We like to “tell the story” of components, where we start with the simplest concepts andbuild up the topic with easily digestible layers of additional complexity This teaching methodworks really well for components, because they are such a radical departure from traditionalColdFusion development concepts, and they offer lots of new concepts to master
We’ve delayed talking about advanced concepts until the very end of this chapter, mainlybecause they are not absolutely critical to understanding and developing 90 percent of the
components that you’re likely to ever build You could probably work until retirement
build-ing ColdFusion components and never need to employ any of the concepts in the followbuild-ingsections, but if you do take the time to understand and use them where warranted, your codetakes on a more “natural” feel And the more naturally that your code conforms to gooddesign principles, the easier it is for others to understand and maintain it
Void functions
In traditional terms, a function returns a single result to its caller Code that simply goes out
and does something to something else without returning a result is commonly known as a
procedure In ColdFusion terms, a tag is a procedure, and a function is well, a function.
The line between these two became somewhat blurred with the introduction of object-oriented
languages, because the properties of an object are also known as data members, and the object’s methods are also known as member functions In fact, they’re known as member func-
tions even if they do not return a value; no such thing as a “member procedure” exists.Suddenly, “functions” didn’t need to return results to their callers To distinguish between
“normal” functions and these new-style functions that don’t return values, the term void tion was coined Basically, a void function is just a function that doesn’t return a result.
func-In the following code snippet, you call a getter that returns a string containing a zip code andthen call a setter that sets the zip code to a new value:
<cfscript>
theZipCode = Session.myCompany.GetZipCode();
Session.myCompany.SetZipCode(theZipCode & “-1234”);
</cfscript>
You may remember that SetZipCode() is a void function (as almost all setter functions are),
so it doesn’t return a value To invoke a void function, you simply call it directly rather thanset a variable to its return value, as shown in the first line of the preceding script
Some developers have an aversion to void functions and instead substitute traditional tions that return True on success or False on failure, but this is not a sound design, because
func-to implement such code, you must internally handle errors as exceptions and then produce aviable return value as a proxy for a genuine error This technique goes against the concepts ofsound exception handling An error that doesn’t describe an expected alternative (that is,
exception-al) path of execution is indeed an error that should either be rethrown from within
a CFTRY block or fall through your exception-handling framework to be caught by an handling template (See Chapter 21 for a detailed explanation.)
error-Don’t be afraid to implement void functions If your function doesn’t need to return a value, it
is indeed a void function If your void function throws an error, your exception-handlingframework can handle it
Trang 24Whereas components aggregate related functions into a single unit, packages aggregate related
components into an even larger unit A package contains components that are designed towork together as a complete library of functions with a general common purpose
Say, for example, that you have two components named Comp.cfc and Emp.cfc that handleemployee bonus calculations, and you want them to be part of the CalcBonus package
Creating a component package is rather simple — just follow these basic steps:
1 Create a directory (or hierarchy of directories) that is addressable by ColdFusion
Server
2 Place your components in that directory (or throughout your hierarchy of directories).
3 Set the access levels of your component functions to reflect the manner in which they
C:\inetpub\wwwroot\com\hisdomain\calcbonus\CompanyCalc.cfcC:\inetpub\wwwroot\com\hisdomain\calcbonus\Emp.cfc
The resulting ColdFusion notational equivalents to these disk paths are as follows:
com.herdomain.calcbonus.Compcom.herdomain.calcbonus.Emp
com.hisdomain.calcbonus.CompanyCalccom.hisdomain.calcbonus.Emp
Instantiating herdomain.com’s calcbonus package components is, therefore, as simple asusing the code shown in the following example:
<cfscript>
employeeServices = CreateObject(“Component”,
“com.herdomain.calcbonus.Emp”);
</cfscript>
The only difference that’s shown so far between using a component in a package and using a
standalone component is in the dot path, but the real difference lies inside the components
themselves, where access levels are established Listings 22-8 and 22-9 show the Comp.cfcand Emp.cfc components of the calcbonus package The CFSETs of This-scoped variablesare discussed in the following section on inheritance, but for now, pay special attention to thefunctions’ access levels
Trang 25480 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
Listing 22-8: The Comp.cfc component of the CalcBonus package
EmployeeWHERE
EmployeeWHERE
SSN = ‘#Trim(Arguments.SSN)#’
Trang 26SSN = ‘#Trim(Arguments.SSN)#’
</cfquery>
<cfreturn (Val(GetSalary.Salary) * 0.05) +XmasBonus(Arguments.SSN)>
1 The Bonus() function — a Public-access function because you must be able to call it
from anywhere within the ColdFusion application — is called with the argument
“012-34-5678”, which represents the SSN of the employee whose bonus is being calculated
2 A query retrieves the employee’s salary from the database, multiplies this value by
5 percent, and adds the product to the result of the XmasBonus() function, as follows:
a XmasBonus() — a Private-access function because it needs to be accessed only
from within the Emp component — in turn invokes Comp.SizeOfCompany(), ing the SSN of the employee whose bonus is being calculated
Trang 27pass-482 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
b Comp.SizeOfCompany() — a Package-access function because it needs to be
accessed only by functions in both its own component and the Emp component —returns to XmasBonus() the number of people working at the employee’semployer
c XmasBonus() returns to Bonus() the number of employees multiplied by 10.
3 Bonus() returns the final calculation of the employee’s bonus to the calling template.
During your design phase, don’t stop after you figure out which functions are going to bedeclared within which components Go the extra mile to see how your functions may call
each other between components and restrict access to them as “close to the vest” as
possi-ble Place the results in a logically named hierarchy of ColdFusion-accessible directories,
and — voila! — you’ve just created a very useful component package.
Inheritance
We’ve said much regarding the theory of ColdFusion component inheritance, and frankly, much
of it is seriously overblown Inheritance shares its name with the object-oriented world, butthat’s about all that it shares CFC inheritance can be easily summed up with the followingthree simple statements:
✦ One component can inherit from or extend another, after which the inheriting
compo-nent can make use of its ancestor’s properties and methods
✦ If the inheriting component declares its own methods named differently from those in its ancestor, both the ancestor’s methods and the inheriting component’s methods can
be called through the inheriting component The same holds true for declaring ties by using names that do not match their ancestor’s
proper-✦ If the inheriting component declares its own methods named the same as those in its ancestor, the inheriting component’s methods override the ancestor’s methods with the same name, as if the ancestor’s methods are hidden The same holds true for declaring
properties by using names that match their ancestor’s
Just keep these three simple principles in mind as you proceed through the following tions and don’t think that inheritance is any more complicated than this Inheritance has afew applications in real-world ColdFusion development, but you’re likely to find that they arerare Nevertheless, you should understand inheritance so that you can spot places in yourapplication where it may be warranted
sec-Extending inherited functions and properties
You can use the package that you create in Listings 22-8 and 22-9 to learn about extendingcomponents Although we didn’t discuss it earlier, we created a property in the Emp compo-nent named empProperty, as follows:
<cfset This.empProperty = “Original Emp”>
Creating a variable in the This scope of the Emp component makes that variable a property of
that component
Remember that all code in a component’s initialization area is executed once as an instance ofthe component is first created, which means that the empProperty property is automaticallycreated and initialized to the value Original Emp as each instance of the Emp component is
Trang 28created You can change the value of This.empProperty after it is initialized, and eachinstance of the Emp component may contain its own value of empProperty.
If you inherit or extend a component, the functions and properties of the ancestor are, in
essence, copied into the inheritor, where they can be called and used just as if they were apart of the inheritor
So, if you create a component named Manager that extends the Emp component, as shown inListing 22-10, the Manager component also contains a property named empProperty
Managerextends Emp, so Manager inherits Emp’s properties and functions.
Listing 22-10: The Manager component extends Emp with
The same principles of inheritance that work for component properties also work for nent functions
compo-The Emp component contains a Bonus() function that calculates the bonuses of rial employees, but managers make an additional 15 percent bonus To calculate manager
nonmanage-bonuses, you extend Manager’s functionality by declaring a function named ManagerBonus(),
as shown in Listing 22-10 To retrieve the normal bonus for an employee, ManagerBonus()
must call the Bonus() function that is declared in the Emp component But Manager extends
Emp, so Bonus() is available as one of Manager’s own functions; all ManagerBonus() must do
is return Bonus() multiplied by 1.15, as follows:
<cfreturn Bonus(Arguments.SSN) * 1.15>
Listing 22-11 shows inheritance in action Notice how the properties and functions of bothEmpand Manager are directly accessible from Manager
Trang 29484 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
Listing 22-11: Accessing Manager’s functions and properties
The result of executing Listing 22-11 is shown in Figure 22-2
Figure 22-2: The result of executing
Listing 22-11
Everything that you’ve done so far is known as extending because you leave all the functionality of the ancestor component unmodified and extend it only by adding new functions and properties.
In the object-oriented world, this technique is known as specialization: A manager is a specialized
employee who does the same basic things plus a few more To use a couple more object-oriented
terms, a manager is a subtype of an employee, and the employee is the supertype of the manager.
Don’t get hung up on these terms; we mention them here only so that you can follow along inthe inevitable discussions that you hear in comparing components to objects
Overriding inherited functions and properties
“And now for something completely different ” — Monty Python Overriding replaces inherited properties and functions with something completely different
from what was inherited To override a function or property, simply declare a function orproperty of the same name in the inheritor component It’s as simple as that
Listing 22-12 shows overriding in action The company that manufactured Stan Cox’s phone — Fooster — turns out to be scamming everyone Through creative trading contracts
Trang 30tele-with various “hot-talk” services and bundling service options tele-with Fooster’s Model ADHCC(AutoDial Hot ColdFusion Chicks) Telephone, Fooster alleged nonexistent profits that madeits stock price soar sky-high and attract investors The money started pouring in, so the com-pany had to find something to do with it The answer: employee bonuses.
Listing 22-12: The Fooster component overrides Bonus()
<cfcomponent extends=”com.herdomain.calcbonus.Emp”>
<cfset This.empProperty = “Fooster Override Emp”>
<cfset This.foostersOwnProperty = “Just for Fooster”>
So if you are a Fooster employee, your total annual bonus is your Christmas bonus plus 113
million dollars Sweet!
By declaring its own Bonus() function, the Fooster component overrides the Bonus() tion inherited from the Employee component, but the inherited XmasBonus() function is still
func-available because it wasn’t overridden Listing 22-13 shows Fooster’s bonus system in action.
Listing 22-13: Calling Fooster’s Bonus() function.
<p>These are all accessed through the Fooster component only:</p>
<p>Standard Bonus, Fooster-style:
Trang 31486 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
The result of executing Listing 22-13 is shown in Figure 22-3
Figure 22-3: The result of executing
over-Summary
You’ve learned quite a lot about components in this chapter Not only did you see one beingbuilt from the ground up, you followed the very structure of how they are built so you couldget a better feel for how to use them You learned how component functions are oftenreferred to as methods, how methods can be either class methods or instance methodsdepending on how the component that declares them is used, and how these principles aresimilar to object oriented development
You’ve also learned how to create component packages and how to declare a component withunique behavior by inheriting an existing component and overriding some of its methods.You also learned how to apply role-based security to component methods to prevent unau-thorized access
You’ve probably already heard a lot of talk about how ColdFusion components are similar toobjects in object-oriented programming languages, but although some similarities do exist, thetwo are very different In short, don’t try too hard to make ColdFusion components act thesame as objects, and don’t labor for hours on end creating elaborate coding schemes so thatyour components are forced into a bad ballet where they must dance and act like real objects
in Java or C++, because you’re only going to end up spending a lot of time being sorely
disap-pointed Components are not objects; they’re not even surrogates They’re object wannabes.
So don’t be afraid to break certain “object rules,” because they’re not component rules The
only components rules are the ones that you define for your applications If you decide to
directly set or get a persistent component property rather than call a component function to
do the same thing, the worst that you get are a few whiny tongue lashings from overlyexcitable discussion-list members
This chapter covers only what you need to understand the basics of components If we startweighing you down with more details before you build some for yourself, we may lose you So
in the Chapter 23, you build a couple components; then you finish up with the details that wepurposefully omit from this chapter, including component documentation, metadata, and themany caveats that you encounter in implementing component-based applications
After you finish reading the next chapter and building its components, you should have asolid understanding of both the theory and practice of designing and implementing compo-nents, and you should understand how critical engineering decisions affect the overallstrength of your application
Trang 32Building Your First ColdFusion Components
In this chapter, you’re going to build a simple application based ontwo ColdFusion components, or CFCs: one that handles companiesand another that handles its employees The Company componentdeclares only class methods, so persisting longer than a single pagerequest has no practical purpose, but the Employee component isdesigned to collect data submitted from multiple forms and, there-fore, must persist between page requests
A component may contain both instance methods and class methods,
but instance methods become truly useful only within the context of
a long-lived persistent component Don’t think of a component aseither a class (static) component or an instance component, becausesuch behavior is attributed to a component’s methods and not thecomponent itself
Chapter 23 is an exercise in building two components based onthe principles and techniques taught in Chapter 22, so this chaptermay not mean much to you unless you’ve already read and fullyunderstand Chapter 22
The Application That You’re Going to Build
You’re going to build in this chapter a component-based wizard thatcollects data about employees and then either inserts or updatesthose employees in the database This application shows you the ele-ments and techniques involved in building an effective component-based system, but we purposefully remove all exception handling andvalidation so that you can easily see exactly how ColdFusion reacts
to any mistakes in your code
You should follow along with the “building in layers” approach thatwe’re taking and enter your code the same way rather than just jump-ing to the finished listing The first layer is a sort of “50,000-foot view”
of the component, and successive layers focus in closer on more andmore details, so you can get a true feel for the component as a wholerather than as just a bunch of lines of code that you type in
Using components inyour applicationsUnderstanding MVCarchitectureWorking aroundcomponent caveatsDocumentingcomponents
Trang 33488 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
After you’re finished with this chapter, we invite you to experiment with what you’ve built.Modify it and see how ColdFusion reacts Add some validation and an exception-handlingframework to see how your wizard would operate in a production environment
You want to start with a clean slate Execute against your CFMXBible database the fileRefreshCh23Data.sqlin the Chapter 23 directory of the companion CD-ROM to replaceeverything in your Company, Employee, and Dependant tables with fresh data That way,your results match the figures in this chapter and you don’t think that something’s wrong.This wizard enables the user to add and enter employees The first three wizard pages are used
to enter data, and the fourth page is for viewing the employee data before it is committed to thedatabase On first thought, you may visualize the wizard’s application flow to look somethinglike what you see in Figure 23-1 (The heavy lines denote the main path of application flow.)
Figure 23-1: Initial concept of application flow.
Before you continue, however, you must first consider all possible interactions with other
entities Because employees require employers, you need to consider companies as well, so
your flowchart expands to Figure 23-2
Figure 23-2: Taking interaction with the Company component into consideration.
EmployeeCompany
Page1Ctrl Page2Ctrl Page3Ctrl Page4CtrlPage1
Model
Controller
View Page2 Page3 Page4
EmployeePage1Ctrl Page2Ctrl Page3Ctrl Page4CtrlPage1 Page2 Page3 Page4
Model
Controller
View
Trang 34Another consideration that can help you flesh out your application flow is the base of tions where the user starts his tasks and where he returns after those tasks are complete A
opera-common mechanism for such a base of operations is a list of the entities that you can ulate, as shown in Figure 23-3:
manip-Figure 23-3: Adding a base of operations to the application flow.
At this point, you look through your flowchart to determine whether you’ve neglected to sider any features in your application We noticed, for example, that we currently have no
con-interface for deleting an existing employee, so we add that feature to our application flow, as
shown in Figure 23-4
Figure 23-4: Adding a delete feature to the application flow.
And finally, the user needs a way to “jump ship” if he wants to delete his wizard entirely, soyou’ll add a WizardDeleted process, as shown in Figure 23-5
EmployeeCompany
Page1Ctrl
Page1Ctrl Page2Ctrl Page3Ctrl Page4Ctrl
Page1 Page2 Page3EmployeeList Page4
Model
Controller
View
Trang 35490 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
Figure 23-5: The finished application flow.
The elements of an application flow are separated into the following three distinct layers offunctionality:
✦ Model: The Model layer handles everything involving data Conceptually, all software in
the model layer should abstract access to data through simple function calls, so sumers of data don’t need to know anything about where the data originally came from,what platform it’s on, how it was acquired, and so on
con-✦ View: The View layer displays data to the user, collects data from the user, and is
responsible for the entire human interface with the application in general Elements inthe View layer request data from and send data to an intermediary known as theController layer
✦ Controller: The Controller layer is responsible for determining what a View element wants,
acquiring it from the Model, and then calling another View element to display a result orprovide the user with a next step in a process Similarly, the Controller may also receivedata from a View element, determine what to do with it, call the appropriate method in theModel to handle the task, and then call the next View element in the process
This process is the essence of what is known as Model-View-Controller, or MVC, Architecture.
MVC offers many advantages, namely the capability to isolate application functionality intomodules with narrowly defined purposes and formally defined interfaces As such, MVC is aperfect fit with ColdFusion MX’s new technologies, such as Web services and Flash Remoting,which also isolate functionality along the same lines You learn more about these new tech-nologies in chapters 25 and 26, but for now you concentrate on building a relatively simplecomponent-based application by using the MVC architecture
Building the Company Component
The Company component is almost identical to the one shown in the Chapter 22’s Listing 22-2,but you also need a function that returns the number of employees working for a specificcompany You build this component up a little faster than you did in Chapter 22, but you stilluse the layered approach You begin by declaring the functions that you need in Listing 23-1
Employee Company
Page1Ctrl
Trang 36Listing 23-1: The first layer: Declaring Company functions and their
return types
<cfcomponent>
<! - GetCompany() [class method] ->
<cffunction name=”GetCompany” returntype=”query”>
</cffunction>
<! - ListCompanies() [class method] ->
<cffunction name=”ListCompanies” returntype=”query”>
</cffunction>
<! - CreateCompany() [class method] ->
<cffunction name=”CreateCompany” returntype=”void”>
</cffunction>
<! - UpdateCompany() [class method] ->
<cffunction name=”UpdateCompany” returntype=”void”>
</cffunction>
<! - DeleteCompany() [class method] ->
<cffunction name=”DeleteCompany” returntype=”void”>
</cffunction>
<! - SizeOfCompany() [class method] ->
<cffunction name=”SizeOfCompany” returntype=”numeric”>
</cffunction>
</cfcomponent>
As you can see from this listing, we like to document the names of our functions (methods)before each is declared, and we include information on whether it is a class method or aninstance method We also begin our first pass by declaring both the function’s name and thedata type that is returned to the caller
After declaring all the functions that you need in your Company component, you start buildingout their interfaces with arguments and returns in Listing 23-2 Notice that you start out withonly the names and data types of the arguments at this point
Listing 23-2: The second layer: Declaring Company arguments and
returns
<cfcomponent>
<! - GetCompany() [class method] ->
<cffunction name=”GetCompany” returntype=”query”>
<cfargument name=”CompanyID” type=”numeric”>
<cfreturn companyRec>
</cffunction>
<! - ListCompanies() [class method] ->
Continued
Trang 37492 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
Listing 23-2 (continued)
<cffunction name=”ListCompanies” returntype=”query”>
<cfargument name=”CompanyFilter” type=”string”>
<cfreturn companyRecs>
</cffunction>
<! - CreateCompany() [class method] ->
<cffunction name=”CreateCompany” returntype=”void”>
<cfargument name=”CompanyName” type=”string”>
<cfargument name=”Address” type=”string”>
<cfargument name=”City” type=”string”>
<cfargument name=”State” type=”string”>
<cfargument name=”ZipCode” type=”string”>
<cfargument name=”Comments” type=”string”>
<cfreturn>
</cffunction>
<! - UpdateCompany() [class method] ->
<cffunction name=”UpdateCompany” returntype=”void”>
<cfargument name=”CompanyID” type=”numeric”>
<cfargument name=”CompanyName” type=”string”>
<cfargument name=”Address” type=”string”>
<cfargument name=”City” type=”string”>
<cfargument name=”State” type=”string”>
<cfargument name=”ZipCode” type=”string”>
<cfargument name=”Comments” type=”string”>
<cfreturn>
</cffunction>
<! - DeleteCompany() [class method] ->
<cffunction name=”DeleteCompany” returntype=”void”>
<cfargument name=”CompanyID” type=”numeric”>
<cfreturn>
</cffunction>
<! - SizeOfCompany() [class method] ->
<cffunction name=”SizeOfCompany” returntype=”numeric”>
<cfargument name=”CompanyID” type=”numeric”>
Trang 38any-Listing 23-3: The third layer: Adding Company business logic
<cfcomponent>
<! - GetCompany() [class method] ->
<cffunction name=”GetCompany” returntype=”query”>
<cfargument name=”CompanyID” type=”numeric”>
<cfset Var companyRec = “”>
<cfquery name=”companyRec”
datasource=”#Request.MainDSN#”>
SELECT CompanyID, CompanyName, Address, City, State, ZipCode, Comments FROM
Company WHERE CompanyID = #Arguments.CompanyID#
</cfquery>
<cfreturn companyRec>
</cffunction>
<! - ListCompanies() [class method] ->
<cffunction name=”ListCompanies” returntype=”query”>
<cfargument name=”CompanyFilter” type=”string”>
<cfset Var companyRecs = “”>
<cfquery name=”companyRecs”
datasource=”#Request.MainDSN#”>
SELECT CompanyID, CompanyName, Address, City, State, ZipCode, Comments FROM
Company
<cfif IsDefined(‘Arguments.CompanyFilter’)>
WHERE
Continued
Trang 39494 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration
Listing 23-3 (continued)
CompanyName LIKE ‘#Trim(Arguments.CompanyFilter)#%’
</cfif>
ORDER BY CompanyName
</cfquery>
<cfreturn companyRecs>
</cffunction>
<! - CreateCompany() [class method] ->
<cffunction name=”CreateCompany” returntype=”void”>
<cfargument name=”CompanyName” type=”string”>
<cfargument name=”Address” type=”string”>
<cfargument name=”City” type=”string”>
<cfargument name=”State” type=”string”>
<cfargument name=”ZipCode” type=”string”>
<cfargument name=”Comments” type=”string”>
<cfset Var insCompany = “”>
<cfquery name=”insCompany”
datasource=”#Request.MainDSN#”>
INSERT INTO Company(
CompanyName, Address, City, State, ZipCode, Comments )
<! - UpdateCompany() [class method] ->
<cffunction name=”UpdateCompany” returntype=”void”>
<cfargument name=”CompanyID” type=”numeric”>
<cfargument name=”CompanyName” type=”string”>
<cfargument name=”Address” type=”string”>
<cfargument name=”City” type=”string”>
<cfargument name=”State” type=”string”>
Trang 40<cfargument name=”ZipCode” type=”string”>
<cfargument name=”Comments” type=”string”>
<cfset Var updCompany = “”>
<cfquery name=”updCompany”
datasource=”#Request.MainDSN#”>
UPDATE Company SET
CompanyName = ‘#Trim(Arguments.CompanyName)#’, Address = ‘#Trim(Arguments.Address)#’,
City = ‘#Trim(Arguments.City)#’, State = ‘#Trim(Arguments.State)#’, ZipCode = ‘#Trim(Arguments.ZipCode)#’, Comments = ‘#Trim(Arguments.Comments)#’
WHERE CompanyID = #Arguments.CompanyID#
</cfquery>
<cfreturn>
</cffunction>
<! - DeleteCompany() [class method] ->
<cffunction name=”DeleteCompany” returntype=”void”>
<cfargument name=”CompanyID” type=”numeric”>
<cfset Var delCompany = “”>
<cfquery name=”delCompany”
datasource=”#Request.MainDSN#”>
DELETE Company WHERE CompanyID = #Arguments.CompanyID#
</cfquery>
<cfreturn>
</cffunction>
<! - SizeOfCompany() [class method] ->
<cffunction name=”SizeOfCompany” returntype=”numeric”>
<cfargument name=”CompanyID” type=”numeric”>
<cfset Var GetNumEmployees = “”>
<cfquery name=”GetNumEmployees”
datasource=”#Request.MainDSN#”>
SELECT COUNT(*) AS NumEmployees FROM
Employee
Continued