1. Trang chủ
  2. » Công Nghệ Thông Tin

ColdFusion MX Bible phần 5 pdf

124 265 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 124
Dung lượng 0,94 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

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 1

456 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 2

Get 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 3

458 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 4

So 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 5

460 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 7

462 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 8

Persistent 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 9

464 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 10

So 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 11

466 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 12

But 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 13

468 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 14

Where 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 15

470 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 16

func-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 17

472 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 19

474 Part IV ✦ ColdFusion MX Components, Web Services, and Flash Integration

Trang 21

476 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 22

If 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 23

com-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 24

Whereas 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 25

480 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 26

SSN = ‘#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 27

pass-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 28

created 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 29

484 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 30

tele-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 31

486 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 32

Building 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 33

488 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 34

Another 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 35

490 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 36

Listing 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 37

492 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 38

any-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 39

494 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

Ngày đăng: 14/08/2014, 01:21

w