Book Image

Object-Oriented Programming in ColdFusion

By : Matthew Gifford
Book Image

Object-Oriented Programming in ColdFusion

By: Matthew Gifford

Overview of this book

Are you tired of procedural programming or is your extensive code base starting to become un-manageable? Breathe some new life into your code and improve your development skills with the basic concepts of object-oriented programming. Utilize objects, modular components, and design patterns to expand your skills and improve your ColdFusion applications. Packed with example code, and written in a friendly, easy-to-read style, this book is just what you need if you are serious about ColdFusion.This book is a fast-paced tutorial to important ColdFusion object-oriented programming topics. It will give you clear, concise, and practical guidance to take you from the basics of ColdFusion to the skills that will make you a ColdFusion developer to be reckoned with. Don't be put off by jargon or complex diagrams; read and see how you can benefit from this book and extend your development skills in the process.Using the practical examples within this guide, you will learn how to structure your applications and code, applying the fundamental basics of object-oriented programming to develop modular, reusable components that will scale easily with your application. You will learn the basic fundamental practices of object-oriented programming, from object creation and re-use, to Bean objects, service layers, Data Access objects, and sample design patterns to gain a better understanding of OOP using examples that can be altered and applied in your application. Complete with detailed code samples and snippets, and written in a friendly easy-to-follow style, you will be able to break free from writing purely procedural code and enhance your applications by building structured applications utilizing basic design patterns and object-oriented principles.
Table of Contents (14 chapters)
Object-Oriented Programming in ColdFusion
Credits
Foreword
About the Author
Acknowledgement
About the Reviewer
Preface

Creating an object constructor


In our contacts.cfc, we have defined a method which contains a query. This query has the datasource name attribute defined to correctly reference the database setup within the ColdFusion administration console.

As with all good development, we want to restrict hardcoding any values or references wherever we can and instead use variables to define them, (in this case the datasource name attribute).

A common practice in application development is to create your datasource name and store it in the Application scope, ensuring its availability to every page template that is called, for example:

<cfset application.dsn = "projectTracker" />

You could use the Application scope variable application.dsn directly within your CFCs as the dynamic name referencing the datasource. However, this is not considered best coding practice, as you have instantly opened up your component methods to a fixed scope variable.

One of the main goals in component development is to create closed CFCs and methods that do not need to worry about whether or not a fixed variable exists.

If we refer back to the getName() function on page 7, we can see how it was originally fixed to read the first and last name from the URL scope. We resolved that issue by removing any fixed scope references and optimized the method by adding cfargument tags and the ability to pass in parameters.

We will do the same for our contacts.cfc to send in our datasource name for use in the cfquery tags.

Instead of creating a new argument for each method within the component that requires the datasource, we will create a new function that will hold the variables we need and will be open for all methods defined within the CFC to read variables from.

Creating an init() function

Let's modify our code within the contacts.cfc gallery to write the new function, init().

<cfcomponent name="contacts">
<cffunction name="init">
<cfargument name="datasource" type="string" required="true" />
<cfscript>
Variables.attributes = structNew();
Variables.attributes.dsn = arguments.datasource;
</cfscript>
<cfreturn this />
</cffunction>
<cffunction name="getContact">
<cfargument name="ID" type="numeric" default="0" />
<cfset var rstContact = "" />
<cfquery name="rstContact" datasource="projectTracker">
SELECT firstName,lastName FROM Owners
<cfif arguments.ID GT 0>
WHERE ID = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.ID#" />
</cfif>
</cfquery>
<cfreturn rstContact />
</cffunction>
</cfcomponent>

Listing 1.33

You can now see the init() method defined within the component. The concept of a constructor within an object is a common practice in most languages. We have included a cfargument tag with the name datasource, which will allow us to send in the name of the datasource we wish to use within this object.

Within the CFScript block, we then create a new structure that assigns the value of the datasource argument to the struct value dsn, and the structure has been assigned to the Variables scope within the CFC.

We can then amend our getContact() method and alter the datasource attribute to use the new reference, stored in the Variables scope:

<cffunction name="getContact">
<cfargument name="ID" type="numeric" default="0" />
<cfset var rstContact = "" />
<cfquery name="rstContact" datasource="#variables.attributes.dsn#">
SELECT firstName,lastName FROM Owners
<cfif arguments.ID GT 0>
WHERE ID = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.ID#" />
</cfif>
</cfquery>
<cfreturn rstContact />
</cffunction>

Listing 1.34

By sending the value into the object constructor method when instantiating the component we have removed the hardcoded reference to the datasource.

The Variables scope

The Variables scope can be made available to the entire CFC by setting a value either within one of the methods or in the constructor. The value of that variable is then made available to any other method (including the constructor).

The Variables scope can be used in a similar way to storing values within the Application scope, whose values are always available throughout the entire application. This makes it ideal for sending in variables such as the datasource name.

Calling your init() function

To set the value of the datasource name into the Variables scope, we need to call the init function to pass through the argument.

In previous examples, we have already used the createObject() function to create an instance of the component. We are going to use exactly the same code, only this time we will append the init()function to the end of instantiation method call:

<!--- instantiate the object --->
<cfset objContacts = createObject('component', 'contacts').init(datasource="projectTracker") />

Listing 1.35

By doing this, we have passed our datasource name as an argument into the init() method within the contacts.cfc. The argument value is then stored within the Variables scope structure (Variables.attributes).

Note

Values stored within the Variables scope last as long as the component instance exists, and therefore can persist between calls to methods of a CFC instance.

The Variables scope within your CFC is available to any included pages (using the cfinclude tag), and any Variables scope variables that you have defined in the included page are also available to the CFC.

The This scope

At the end of the function, we have the cfreturn tag, which we have seen before. However, this particular method is returning a different value, which is This:

<cffunction name="init">
<cfreturn This />
</cffunction>

Listing 1.36

By adding a return type of This to the cfreturn tag, you are returning the entire object, including all of its methods, variables, and data.

In the query.cfm calling page, use the cfdump tag to display the object in the browser:

<!--- dump the contacts object --->
<cfdump var="#objContacts#" />

Listing 1.37

As the init() method returns the object in the This scope, we are able to access the object directly using the cfdump tag.

The This scope is similar to the Variables scope due to the fact that it is 'globally' accessible to the entire CFC. In addition, the This scope is accessible outside of the CFC, so you could call and reference the values from your object within your .cfm template calling page.

For example, if we amended the code within the init() method in the CFC from using the previously mentioned Variables scope to the This scope, we could access the datasource name from our calling page:

<cffunction name="init">
<cfargument name="datasource" required="true" />
<cfscript>
This.attributes = structNew();
This.attributes.dsn = arguments.datasource;
</cfscript>
<cfreturn This />
</cffunction>

Listing 1.38

In the query.cfm, we can now output the name of the datasource from the attributes structure stored within the This scope:

<!--- dump the contacts object --->
<cfdump var="#objContacts#" />
<cfoutput>The datasource name is #objContacts.attributes.dsn#</cfoutput>

Listing 1.39

Notice that the attributes structure is now publicly available, allowing us to access the name of the datasource directly from the CFC.

This highlights the difference between the Variables and This scope. When the attributes were assigned to the Variables scope, they were kept hidden from external views, despite being available to all methods within the CFC. As soon as we changed the init() method to store attributes within the This scope, the structure became a visible, 'public' variable that could be accessed outside of the CFC.

Although the This scope is a required tool for returning a complete CFC object, it is not best practice to store variables within the scope. This is because they can be accessed and altered. Unless you specifically choose to alter your object's variables in this manner, this would not be a safe development practice.

Note

Values stored within the This scope last as long as the component instance exists, and therefore can persist between calls to methods of a CFC instance.