Building Your First Bean in ColdFusion

Exclusive offer: get 50% off this eBook here
Object-Oriented Programming in ColdFusion

Object-Oriented Programming in ColdFusion — Save 50%

Break free from procedural programming and learn how to optimize your applications and enhance your skills using objects and design patterns

$23.99    $12.00
by Matt Gifford | October 2010 | Web Development

Following the article on ColdFusion Components, we now have a fairly good understanding of what a ColdFusion component is. Object-oriented programming is a form of programming paradigm that utilizes "objects", structures of data that consist of data fields and methods, and the object interactions for development. Focusing on data rather than processes, the OOP methodology uses self-sufficient modules (the objects), which contain all the information they require to manipulate their own data structure.

In this article by Matt Gifford, author of Object-Oriented Programming in ColdFusion, we will look at the first ColdFusion component within the OOP design pattern, the Bean.

 

Object-Oriented Programming in ColdFusion

Object-Oriented Programming in ColdFusion

Break free from procedural programming and learn how to optimize your applications and enhance your skills using objects and design patterns

  • Fast-paced easy-to-follow guide introducing object-oriented programming for ColdFusion developers
  • Enhance your applications by building structured applications utilizing basic design patterns and object-oriented principles
  • Streamline your code base with reusable, modular objects
  • Packed with example code and useful snippets
        Read more about this book      

(For more resources on ColdFusion, see here.)

What is a Bean?

Although the terminology evokes the initial reaction of cooking ingredients or a tin of food from a supermarket, the Bean is an incredibly important piece of the object-oriented design pattern.

The term 'Bean' originates from the Java programming language, and for those developers out there who enjoy their coffee as much as I do, the thought process behind it will make sense: Java = Coffee = Coffee Bean = Bean.

A Bean is basically the building block for your object. Think of it as a blueprint for the information you want each object to hold and contain. In relation to other ColdFusion components, the Bean is a relatively simple CFC that primarily has two roles in life:

  • to store information or a collection of values
  • to return the information or collection of values when required

But what is it really?

Typically, a ColdFusion bean is a single CFC built to encapsulate and store a single record of data, and not a recordset query result, which would normally hold more than one record. This is not to say that the information within the Bean should only be pulled from one record within a database table, or that the data needs to be only a single string—far from it.

You can include information in your Bean from any source at your disposal; however, the Bean can only ever contain one set of information.

Your Bean represents a specific entity. This entity could be a person, a car, or a building. Essentially, any 'single' object can be represented by a bean in terms of development.

The Bean holds information about the entity it is written for. Imagine we have a Bean to represent a person, and this Bean will hold details on that individual's name, age, hair color, and so on. These details are the properties for the entity, and together they make up the completed Bean for that person.

In reality, the idea of the Bean itself is incredibly similar to a structure. You could easily represent the person entity in the form of a structure, as follows:

<!---Build an empty structure to emulate a Person entity.--->
<cfset stuPerson = {
name = '', age = '',
hairColor = ''} />

Listing: 3.1 – Creating an entity structure

This seems like an entirely feasible way to hold your data, right? To some extent it is. You have a structure, complete with properties for the object/entity, wrapped up into one tidy package.

You can easily update the structure to hold the properties for the individual, and retrieve the information for each property, as seen in the following code example:

<!---Build an empty structure to emulate a Person entity.--->
<cfset stuPerson = {
name = '', age = '',
hairColor = ''} />
<cfdump var="#stuPerson#" label="Person - empty data" />
<!---Update the structure with data and display the output--->
<cfset StructUpdate(
stuPerson, 'name', 'Matt Gifford') />
<cfset StructUpdate(
stuPerson, 'hairColor', 'Brown') />
<br />
<cfdump var="#stuPerson#" label="Person - data added" />
<br />
<cfoutput>
Name: #stuPerson.name#<br />
Hair: #stuPerson.hairColor#
</cfoutput>

Listing 3.2 – Populating the entity structure

Building Your First Bean in ColdFusion

Although the structure is an incredibly simple method of retaining and accessing data, particularly when looking at the code, they do not suit the purpose of a blueprint for an entity very well, and as soon as you have populated the structure it is no longer a blueprint, but a specific entity.

Imagine that you were reading data from the database and wanted to use the structure for every person who was drawn out from the query. Sure enough, you could create a standard structure that was persistent in the Application scope, for example. You could then loop through the query and populate the structure with the recordset results. For every person object you wanted, you could run ColdFusion's built-in Duplicate() function to create a copy of the original 'base' structure, and apply it to a new variable.

Or perhaps, the structure might need to be written again on every page it is required in, or maybe written on a separate .cfm page that is included into the template using cfinclude.

Perhaps over time, your application will grow, requirements will change, and extra details will need to be stored. You would then be faced with the task of changing and updating every instance of the structures across your entire application to include additional keys and values, or remove some from the structure.

This route could possibly have you searching for code, testing, and debugging at every turn, and would not be the best method to optimize your development time and to enhance the scalability of your application.

Taking the time to invest in your code base and development practices from the start will greatly enhance your application, development time, and go some way to reduce unnecessary headaches caused by spaghetti code and lack of structure.

The benefit of using beans

By creating a Bean for each entity within your application, you have created a specific blueprint for the data we wish to hold for that entity. The rules of encapsulation are adhered to, and nothing is hardcoded into our CFC.

We have already seen how our objects are created, and how we can pass variables and data into them, which can be through the init() method during instantiation or perhaps as an argument when calling an included function within the component.

Every time you need to use the blueprint for the Person class, you can simply create an instance of the Bean.

You instantly have a completely fresh new object ready to populate with specific properties, and you can create a fully populated Person object in just one line of code within your application.

The main purpose of a Bean in object-oriented development is to capture and encapsulate a variety of different objects, be they structures, arrays, queries, or strings for example, into one single object, which is the Bean itself.

The Bean can then be passed around your application where required, containing all of the included information, instead of the application itself sending the many individual objects around or storing each one in, for example, the Application or Session scope, which could get messy.

This creates a nicely packaged container that holds all of the information we need to send and use within our applications, and acts as a much easier way to manage the data we are passing around.

If your blueprints need updating, for example more properties need to be added to the objects, you only have one file to modify, the CFC of the Bean itself. This instantly removes the problematic issues of having to search for every instance or every structure for your object throughout your entire code base.

A Bean essentially provides you with a consistent and elegant interface, which will help you to organize your data into objects, removing the need to create, persist, and replicate ad-hoc structures.

Creating our first Bean

Let's look at creating a Bean for use with the projects table in the database. We'll continue with the Person Bean as the primary example, and create the CFC to handle person objects.

An introduction to UML

Before we start coding the component, let's have a quick look at a visual representation of the object using Unified Modeling Language (UML).

UML is a widely-used method to display, share, and reference objects, Classes, workflows, and structures in the world of object-oriented programming, which you will come into contact with during your time with OOP development.

The modeling language itself is incredibly detailed and in-depth, and can express such a wide array of details and information.

Person object in UML

In this example, let's take a look at the basics of UML and the visual representation of the Person component that we will create, which looks like this:

Building Your First Bean in ColdFusion

At first glances, you can instantly see what variables and functions our component consists of.

With most UML objects, it is broken into segments for easier digestion. The actual name of the component is clearly visible within the top section of the diagram.

In the second section, we include the variables that will be included within our object. These have a '-' character in front of them, to indicate that these variables are private and are hidden within the component (they are not accessible externally).

These variables are followed by the variable type, separated by a colon (':'). This lets you easily see which variable type is expected. In this example, we can see that all of the variables are strings.

In the bottom section of the diagram we include the function references, which contain all methods within the component.

All of the functions are prefixed with a '+' to indicate that they are publically accessible, and so are available to be called externally from the component itself.

For any functions that require parameters, they are included inside the parenthesis. If a function returns a value, the returnType is specified after the ':'.

Based upon this UML diagram, let's create the core wrapper for the CFC, and create the constructor method—the init() function.

Create a new file called Person.cfc and save this file in the following location within your project folder: com/packtApp/oop/beans.

<cfcomponent displayname="Person" output="false"
hint="I am the Person Class.">
<cfproperty name="firstName" type="string" default="" />
<cfproperty name="lastName" type="string" default="" />
<cfproperty name="gender" type="string" default="" />
<cfproperty name="dateofbirth" type="string" default="" />
<cfproperty name="hairColor" type="string" default="" />

<!--- Pseudo-constructor --->
<cfset variables.instance = {
firstName = '', lastName = '', gender= '',
dateofbirth = '', hairColor = ''
} />
<cffunction name="init" access="public" output="false"
returntype="any" hint="I am the constructor method for the Person
Class.">
<cfargument name="firstName" required="true"
type="String" default="" hint="I am the first name." />
<cfargument name="lastName" required="true"
type="String" default="" hint="I am the last name." />
<cfargument name="gender" required="true"
type="String" default="" hint="I am the gender." />
<cfargument name="dateofbirth" required="true"
type="String" default="" hint="I am the date of birth." />
<cfargument name="hairColor" required="true"
type="String" default="" hint="I am the hair color." />
<cfreturn this />
</cffunction>
</cfcomponent>

Listing 3.3 - com/packtApp/oop/beans/Person.cfc

Here, we have the init() method for the Person.cfc and the arguments defined for each property within the object. The bean will hold the values of its properties within the variables.instance structure, which we have defined above the init() method as a pseudo-constructor.

Object-Oriented Programming in ColdFusion Break free from procedural programming and learn how to optimize your applications and enhance your skills using objects and design patterns
Published: October 2010
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on ColdFusion, see here.)

What makes a Bean a Bean

We know that a Bean is a CFC representing a specific entity. But what differentiates a Bean from a normal ColdFusion component?

There are two conventions that a CFC can follow in order to officially declare it as a Bean, which are:

  • The class must have a public default/no-argument constructor
  • The class properties must be accessible to allow easy inspection and updating of Bean state

A default/no-argument constructor

Looking at the code we have just written, we can see the constructor method has the arguments required to populate the project Bean entity. However, when we instantiate the Bean in our code, we may not yet have that information to hand and we may not know what values to pass into the object to populate the properties.

As such, we have set the required attribute for each argument to required="false", and have set a default value for each argument based upon its expected type. For example, all arguments expecting a string have a blank default value, and all arguments expecting a numeric value have their default value set to "0".

So, although the constructor method does have arguments, they are not required to be populated upon creation, making this method a 'no-argument constructor', which conforms to the first requirement for Beans.

Easily accessible for introspection

Once the object has been instantiated using the init() method, a structure variable called "instance" is created within the Variables scope of the CFC. The Variables scope is a local private scope within the component, and cannot be modified from anywhere except within the CFC itself.

The variables.instance structure will hold data for the Bean's properties, and in order to access the structure to write data and read values from the Bean we need two methods for each property within the CFC.

Methods used to write values to properties are commonly referred to as Setters or Mutators, while methods used to retrieve values from the Bean are known as Getters or Accessors.

Setters/Mutators

Let's add some setter methods to our Person.cfc so that we can set values within the object. The methods should be placed underneath the init() method.

<!--- setters /mutators --->
<cffunction name="setFirstName" access="public"
output="false" hint="I set the first name into the
variables.instance scope.">
<cfargument name="firstName" required="true"
type="String" hint="I am the person's firstName." />
<cfset variables.instance.firstName = arguments.firstName />
</cffunction>

<cffunction name="setLastName" access="private"
output="false" hint="I set the last name into the
variables.instance scope.">
<cfargument name="lastName" required="true"
type="String" hint="I am the person's lastName." />
<cfset variables.instance.lastName = arguments.lastName />
</cffunction>

Listing 3.4 – Adding mutators to Person.cfc

The typical naming convention for a setter method is to call the function set[Property], replacing [property] with the name of the property within the Bean you wish to set. In the previous example, we have defined the setFirstName() and setLastName() functions.

Each function takes one argument, which is the value we want to set the specific property to, and the arguments are all set to required="true" to ensure we pass through the values when mutating the Bean.

When you call setFirstName(x) from within the init() method, which we will see in a later code example, the function will assign the value sent through in the argument to the firstName key within the variables.instance scope.

The setter functions do not return any information. They are purely used for setting information, not for reading and supplying back to the user.

Getters/Accessors

Now we have the methods in place to set values within the project Bean, but we also need to retrieve the information for each specific property, and we do so by creating one getter method within our CFC for each property. Place these methods underneath the setter methods defined in your CFC:

<!--- getters / accessors --->
<cffunction name="getFirstName" access="public"
output="false" hint="I return the first name.">
<cfreturn variables.instance.firstName />
</cffunction>

<cffunction name="getLastName" access="public"
output="false" hint="I return the last name.">
<cfreturn variables.instance.lastName />
</cffunction>

Listing 3.5 – Adding accessors to Person.cfc

Simple and elegant in terms of code and function, the getter methods also follow the same naming convention as the setter functions, so in the previous example we have getFirstName() and getLastName() to retrieve the values for those specific Bean properties.

The getter (or accessor) methods take no arguments. Instead, they simply read the specific key from the variables.instance structure and return that data back to the user.

We now have an easy way to interact, amend, and retrieve the properties within the Bean itself, thanks to the getter and setter methods we have defined. The CFC now conforms to the second requirement for true Bean status.

Completing our Projects Bean

In our current code for the Person Bean, we have the two methods for getting and setting the firstName and lastName properties. The CFC needs to set the values of the properties upon instantiation, so we need to amend the init() method like so:

<cffunction name="init" access="public" output="false"
returntype="any" hint="I am the constructor method for
the Person Class.">
<cfargument name="firstName" required="true" type="String"
default="" hint="I am the first name." />
<cfargument name="lastName" required="true" type="String"
default="" hint="I am the last name." />
<cfargument name="gender" required="true" type="String"
default="" hint="I am the gender." />
<cfargument name="dateofbirth" required="true" type="String"
default="" hint="I am the date of birth." />
<cfargument name="hairColor" required="true" type="String"
default="" hint="I am the hair color." />
<!--- Set the initial values of the Bean --->
<cfscript>
setFirstName(arguments.firstName);
setLastName(arguments.lastName);
</cfscript>
<cfreturn this />
</cffunction>

Listing 3.6 – Setting the variables within the constructor

You can see that we have placed the setFirstName() and setLastName() methods into the constructor function. These will set the relevant variables.instance properties with the values sent in through the arguments, which will use the default values if no arguments are specified.

Now, let's add the rest of the getter and setter methods to the CFC to complete the Bean, which should look like this:

<cfcomponent displayname="Person" output="false"
hint="I am the Person Class.">
<cfproperty name="firstName" type="string" default="" />
<cfproperty name="lastName" type="string" default="" />
<cfproperty name="gender" type="string" default="" />
<cfproperty name="dateofbirth" type="string" default="" />
<cfproperty name="hairColor" type="string" default="" />

<!--- Pseudo-constructor --->
<cfset variables.instance = {
firstName = '', lastName = '', gender = '',
dateofbirth = '', hairColor = ''
} />

<cffunction name="init" access="public" output="false"
returntype="any" hint="I am the constructor method for
the Person Class.">
<cfargument name="firstName" required="true" type="String"
default="" hint="I am the first name." />
<cfargument name="lastName" required="true" type="String"
default="" hint="I am the last name." />
<cfargument name="gender" required="true" type="String"
default="" hint="I am the gender." />
<cfargument name="dateofbirth" required="true" type="String"
default="" hint="I am the date of birth." />
<cfargument name="hairColor" required="true" type="String"
default="" hint="I am the hair color." />
<!--- Set the initial values of the Bean --->
<cfscript>
setFirstName(arguments.firstName);
setLastName(arguments.lastName);
setGender(arguments.gender);
setDateOfBirth(arguments.dateofbirth);
setHairColor(arguments.hairColor);
</cfscript>
<cfreturn this />
</cffunction>

<!--- getters / accessors --->
<cffunction name="getFirstName" access="public"
output="false" hint="I return the first name.">
<cfreturn variables.instance.firstName />
</cffunction>

<cffunction name="getLastName" access="public"
output="false" hint="I return the last name.">
<cfreturn variables.instance.lastName />
</cffunction>

<cffunction name="getGender" access="public"
output="false" hint="I return the gender.">
<cfreturn variables.instance.gender />
</cffunction>

<cffunction name="getDateOfBirth" access="public"
output="false" hint="I return the date of birth.">
<cfreturn variables.instance.dateofbirth />
</cffunction>

<cffunction name="getHairColor" access="public"
output="false" hint="I return the hair color.">
<cfreturn variables.instance.hairColor />
</cffunction>

<!--- setters /mutators --->

<cffunction name="setFirstName" access="public"
output="false" hint="I set the first name into the
variables.instance scope.">
<cfargument name="firstName" required="true"
type="String" hint="I am the person's firstName." />
<cfset variables.instance.firstName = arguments.firstName />
</cffunction>

<cffunction name="setLastName" access="public"
output="false" hint="I set the last name into the
variables.instance scope.">
<cfargument name="lastName" required="true"
type="String" hint="I am the person's lastName." />
<cfset variables.instance.lastName = arguments.lastName />
</cffunction>

<cffunction name="setGender" access="public"
output="false" hint="I set the gender into the
variables.instance scope.">
<cfargument name="gender" required="true"
type="String" hint="I am the person's gender." />
<cfset variables.instance.gender = arguments.gender />
</cffunction>

<cffunction name="setDateOfBirth" access="public"
output="false" hint="I set the dateofbirth into the
variables.instance scope.">
<cfargument name="dateofbirth" required="true"
type="String" hint="I am the person's dateofbirth." />
<cfset variables.instance.dateofbirth =
arguments.dateofbirth />
</cffunction>

<cffunction name="setHairColor" access="public"
output="false" hint="I set the hairColor into the
variables.instance scope.">
<cfargument name="hairColor" required="true"
type="String" hint="I am the person's hairColor." />
<cfset variables.instance.hairColor = arguments.hairColor />
</cffunction>
</cfcomponent>

Listing 3.7 – A complete Person.cfc.

Listing 3.7 contains a complete Person component. All properties now have a getter and setter method. We have also added all required setter methods into the constructor to set variables upon instantiation.

It may not look as clean and tidy as the project structure code, but the Bean is properly encapsulated and will allow you to easily update and get your data from the object with minimal fuss, and any future updates required for the object will only need to be written in one place—the Person CFC itself.

Calling our project Bean

We have already ensured that our Bean matches one of the conventions and that it is a no-argument constructor. We can create the object without sending any arguments to the init() method, as follows:

<cfscript>
// Instantiate the Person object
objPerson = createObject('component',
'com.packtApp.oop.beans.Person').init();
</cfscript>

Listing 3.8 – Instantiating the object

With the Person Bean now created, we can send data into the object.

As the values are being stored in the Variables scope within the CFC, we have no way of accessing this scope directly from outside of the component. To make life a little easier when it comes to debugging the values stored in the variables.instances structure, let's add the following method to the end of our Person.cfc file, before the closing </cfcomponent> tag:

<!--- utils --->
<cffunction name="getMemento" access="public"
output="false" hint="I return a dumped struct of the
variables.instance scope.">
<cfreturn variables.instance />
</cffunction>

Listing 3.9 – getMemento() method for Person.cfc

This getMemento() method will give us the ability to output the variables.instance structure onto our .cfm template so that we can see the values currently stored within it.

We can use the function as the one shown in the following example, which will provide us with a visual output of the current values within the Bean:

<cfscript>
// Instantiate the Person object
objPerson = createObject('component',
'com.packtApp.oop.beans.Person').init();
</cfscript>
<!--- View the content of the variables.instance scope using the
getMemento() method--->
<cfdump var="#objPerson.getMemento()#" label="Person -
variables.instance" />

Listing 3.10 – Viewing the variables.instance data

Building Your First Bean in ColdFusion

The returned output from the getMemento() method shows us that, as we already knew, the properties within the object are as of yet unpopulated and simply hold the default values as defined in the constructor method.

Summary

In this article, we have introduced the Bean into our ColdFusion object-oriented programming design pattern, and have understood that a Bean is a blueprint of an object, which we can create and populate at any time, and that this object represents a single record of data, or a specific entity.


Further resources on this subject:


Object-Oriented Programming in ColdFusion Break free from procedural programming and learn how to optimize your applications and enhance your skills using objects and design patterns
Published: October 2010
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

About the Author :


Matt Gifford

Matt officially began life as a developer in 2000, although he used to 'develop' simple applications using BASIC Programming on his Sinclair ZX Spectrum. After creating relational databases in VBScript and hand-coding HTML pages in text editors, the obvious route was to start developing websites using dynamic data.

He is now lead developer with Fuzzy Orange Ltd, and specializes in ColdFusion, Flex, and AIR development, and is also proud to be called an Adobe Community Professional for ColdFusion. He has spoken and presented regularly at national and international conferences and online meetings, and has written tutorials and articles for online resources and UK industry magazines.

Constantly striving to learn more and update any skill set he can, he loves to read development publications and community blogs, attend conferences, and discuss issues with other members of the development community.

A keen proponent for community resources and sharing knowledge, Matt writes and releases open-source ColdFusion applications and code samples as often as he can, and can also be seen updating resources and writing articles on his blog, http://www.mattgifford.co.uk.

Books From Packt


ColdFusion 9 Developer Tutorial
ColdFusion 9 Developer Tutorial

Building Websites with ExpressionEngine 2
Building Websites with ExpressionEngine 2

Drupal 7
Drupal 7

WordPress Top Plugins
WordPress Top Plugins

jQuery 1.4 Reference Guide
jQuery 1.4 Reference Guide

Building Websites with DotNetNuke 5
Building Websites with DotNetNuke 5

Inkscape 0.48 Essentials for Web Designers
Inkscape 0.48 Essentials for Web Designers

High Availability MySQL Cookbook
High Availability MySQL Cookbook


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software