In my previous post I took a look at selecting an existing event, retrieving its details and populating an edit form with those details, then updating the event with the new values. Today we will look at a very similar operation–adding a new event. The process is quite similar. First we instantiate an Event bean. Now we can display our form and enter the details of our new event. We submit the form, passing the form values to each corresponding Event bean property. After that we just call our create() method in the EventDAO which we persisted in the Application scope. That’s pretty much all there is to it. At the top of my display file, I add some logic to check if the form has been submitted. If it has, call the setters and pass in the corresponding form values. The code looks like this.
<cfset objEventBean = createObject("component","eventRegistration2.components.barrett.beans.Event").init()/>
<cfif structKeyExists(form, "submit")>
<cflocation url="event_select.cfm" addtoken="false" />
Now let’s see if we can eliminate the duplicate code that exists between the editEvent form and the addEvent form. Both pages begin by instantiating the Event bean. The difference is that for edit, we have passed an eventID which we then use to retrieve an existing record. In the case of a new event, no eventID is passed, rather the Event bean has the default value of 0. How about we use Event.getEventID() to check the value? If it’s not 0, we know it’s an existing record and we can then use EventDAO.retrieveByID() to grab the details and populate form. That takes care of the retrieval and display. We can now use one display page to handle creating a new event as well as editing an existing one.
On submit, we now need to know if we should call EventDAO.create() or EventDAO.update(). Let’s create an exists() method to check to see if we have a new or existing record. The exists() method will accept an Event bean as an argument. Just like we did above, the exists() method will check the eventID value. If the value not 0 we return true. Otherwise, we return false. All this method does is answer the question, “Does this eventID exist already?” That’s it. Of course now we need to create our save() method. The save() method looks like this:
<cffunction name="save" access="public" output="false" hint="I handle saving an Event" return="string">
<cfargument name="Event" type="eventRegistration2.components.barrett.beans.Event" required="true" hint="I am the Event bean"/>
<cfset var success = ""/>
<cfset success = update(arguments.Event)/>
<cfset success = create(arguments.Event)/>
The save() method is a sort of traffic cop. It passes the Event bean argument to the exists() method and then asks what the method returned? If true, the event exists and then calls the update() method. Otherwise, the event is new and it will call the create() method.
One last thing. Since we are no longer directly calling the create() or update() methods, we could change their access attribute to private. I’ve been reading Object Oriented Thought Process and it is recommended that we expose only as much of our objects as is absolutely necessary. So it makes sense to change these to private as they will be called by the exists() method now.
To continue in my series of posts about my experience of learning object oriented programming in ColdFusion. After working my way through Matt Gifford’s book, Object Oriented Programming in ColdFusion, I decided I would work with an old app I had worked with in the past. A while back I had paid for the code to Steve Moore’s Event Management System from steveeray.com. I used it as a model for a similar, more complex system I built using CFWheels. It’s a pretty simple, but nice app that has only a few database tables behind it. I figured I would use it practice my new found OO skills but this time with no framework. This is purely an exercise for me with no intention of actually deploying this app for any real use. The goal is just to see if I can get it to work exactly as I found it but using the OO techniques learned over the past few weeks. Sounds simple enough, I think.
I should begin by describing how the original app works. It is organized into events, which have sessions. Users can register for a session, by providing their basic contact info. On registration, users receive a confirmation email. There is an admin back end which handles adding events and sessions, viewing the session roster, moving people to different sessions, and sending participants emails. For ease of use, I began the way I usually do, by starting with the back end functionality.
The main admin page (I will not be dealing with authentication at this time) presents several options. I’ll work my way through each one building out the pages I need as I go. First up was Event Maintenance.
I had already built the Event Bean, DAO, and Gateway files using techniques learned from my book. The Event Bean contains its properties, the getters, and the setters. The EventDAO contains my CRUD methods to handle a single Event record. The EventGateway contains all other more complex functions that deal with multiple records. The main method at use in the gateway is the retrieveAllEvents() method. It’s worth noting that the data is not contained in the page, but rather in the Event object. I’m not performing any logic on the page, but rather within the Event object, or more precisely its methods. In my past my pages would contain logic and perform all kinds of operations on data as it got passed from page to page. In this way, I am calling the various operations that need to occur. The object already has everything it needs to do so.
The DAO and Gateway files were instantiated in my Application.cfc file to make it easy to access them throughout the application. So looking at the page, as well as the original code for the app shows that I need to retrieve a listing of events for the drop down menu. For this I used my EventGateway.retrieveAllEvents() method as follows:
The eventID value is passed on the the Event Information page where we are presented a form with the selected event’s details populated and ready for editing.
I won’t discuss the design code for the page, but the code to handle the Event does 2 things. First I use the EventDAO.retrieveEventByID(form.eventID) method to retrieve the selected event. This method returns an Event Bean that I then use to populate the form. It’s just one line of code that looks like this:
To populate the form, I just use the getters like so:
<cfinput type="Text" name="eventName" value="#objEventBean.geteventName()#" size="80" maxlength="250" required="yes" message="Enter the name of the Event" class="input">
To show the Event bean, I dumped its contents to the Event Information page.
After I make my changes to the form and submit, I update the Event bean and then pass the bean to the EventDAO.update() method. The code for this looks something like:
That’s about it. The event is updated and user is sent back to the Event Maintenance page.
The main takeaway from this so far is that there is no real logic in the page itself. The logic is all contained in the object itself. If nothing else, that should make maintenance easier. That realization was my big “Aha” moment. Next time I’ll look at the New Event page, which is actually the same as the Edit Event page–gotta keep it DRY.
Object oriented coding is not completely new to me. I’ve attempted to pick it up a few times over the years. I do not have a pure CS background–I majored in biology and minored in chemistry. Somehow any presentation on the subject always contained terms that I was not familiar with. So my attempts to learn OO in the past had always stalled. That is until the CFWheels framework came along a couple of years ago. I love how approachable the framework was for someone with no experience in OO. Even better, it had lots of documentation and example code to look at and use as a guide. It became my framework of choice. In fact, my work with the framework led me to my current job.
In the course of my daily work, I also deal with legacy code in another familiar framework, Fusebox 4. I love Fusebox and have worked with it in my past as well. However, I found myself thinking in CFWheels and OO terms while coding in FB. I remembered that FB can be used in an object oriented manner and our legacy code is in need of refactoring into OO so I thought this would be the perfect time to finally learn OO in CF without a framework. I’m not knocking the framework. Not at all. I love CFWheels and continue to use it. This is just another tool in my CF toolbox.
I started with some searching on the web for resources. I tried Nic Tunney’s CFOOP, which I’d heard about at a past CFUnited, but it appears to be defunct. I remembered hearing about a Object Oriented Programming in ColdFusion by Matt Gifford, so I picked up a copy from Amazon. There’s also a neat site run by Adrian Moreno called IKnowKung(Foo);. There is a great series on OO programming in CF there.
Resources in hand, I dove in, determined that this time I would get a handle on using object oriented programming in ColdFusion. It took me about a week to work my way through the book and its exercises and perhaps another week to try out the techniques by converting a fairly simple app from procedural to OO. I’m not done yet, but I’ve completed enough that I’m confident in my ability to finish shortly. My next few posts will detail my efforts to use my newly acquired knowledge to code my first app.
By all accounts, I’m not supposed to be a CF developer. You see as an undergrad, I majored in biological sciences and was focused to the point of tunnel vision on a career as a doctor. There’s a saying that goes, “If you want to make God laugh, tell him your plans.” That certainly holds true in my case. After 2 unsuccessful attempts at applying to med school, I had to look elsewhere for my career path. I was working as a lab tech and hated it because I wasn’t doing research and it certainly didn’t pay what I at the time thought was a decent salary.
I made a switch in 1995 to telecom and worked my way up from customer service to revenue assurance and became a software quality assurance analyst. In this position, I found myself butting heads constantly with developers. A few of them were nice enough to teach me a thing or two. In 1998 I got my first taste of developing my own personal web site. I tore my ACL in a touch football game and decided to document my surgery and recovery in what we now call a blog. I started getting emails from people asking questions about my injury and telling stories about their recovery. I was hooked. I would check the site each day to see how many hits I’d gotten. I updated the site nearly daily with some new story or picture.
Web development remained just a hobby for me until 2001. Like a lot of IT workers, I was laid off just after the September 11 attacks and spent quite some time unemployed. During this time I learned of a free state program that would train people in web application development. After completing the program, they would secure an internship which would lead to a 1 year job at a very small salary as a way to repay the free training. I learned HTML, ASP, SQL, and just enough ColdFusion to be dangerous and completed the program in August 2002. It took a few months but I landed my first paying ColdFusion job in October 2002 with the National Association of Secondary School Principals (NASSP), in Reston, VA. There I maintained principals.org as well as the sites for the National Honor Society and the National Association of Student Councils. We ran CF 4.5 and migrated up to CFMX, before they implemented an ASP.NET content management. I learned so much in those 2 years and had a lot of fun. I have gone on to work in ColdFusion as a government contractor and now as a federal government employee with the Archives of American Art at the Smithsonian Institution.
Recently at work, I was tasked with adding a one-off page to our site. Normally, I hate these kinds of assignments. They tend to break any rules you already have established for the site architecture and style; and once you say “yes” to one such project, you open the floodgates for others. However, I jumped at the opportunity since this was slightly new territory for me. For this page I was asked if there was a way to display pictures from our Flickr page on a page in our site for an exhibition about snapshots. Without thinking for too long, I answered yes. I remember way back when I was exploring Ruby on Rails, one of the first demos I saw was the one where the speaker accessed the Flickr api to pull in images that matched a given tag he passed in. I knew it was possible and fairly simple to do this. What I didn’t know at the time was how to do it and stay within the conventions of the CFWheels framework.
Create a page for the exhibition that displays 4 or 5 thumbnail images from selected sets from our Flickr account. Each image should be a link to the full image on the Flickr web site. Under each group of images should be a link to the full set of images on the Flickr site. The page should list the set title and description, along with its thumbnails, followed by a link to the set on Flickr. The selected photo set id’s would be provided.
I decided that since the photoset id’s would be provided, I could make them a list. I would then loop over the list and pass that it into the api to get the data I needed. I could then loop over the resultsets to create the display. Sounded simple enough.
Proof of Concept Prototype
After studying the Flickr public api, I settled on the flickr.photosets.getInfo() and flickr.photosets.getPhotos() methods to provide the data for the page. First, I hit the flickr.photosets.getInfo() method to get the title and description of each photoset. It looks something like this:
<cfset photosetList = “photosetID1, photosetID2, photosetID3, photosetID4”/>
<cfloop list = “#photosetList#” index=”x”>
<cfhttp url=”http://www.flickr.com/services/rest/” result=”photoSetResult”>
<cfhttpparam type=”url” name=”api_key” value=”myAPIKey”/>
<cfhttpparam type=”url” name=”method” value=”flickr.photosets.getInfo”/>
<cfhttpparam type=”url” name=”photoset_id” value=”#x#”/>
<!—Convert xml text response into an XML document—>
<cfset photosetXMLDoc = xmlParse(photosetResult.fileContent)/>
<cfset photosetNodes = xmlSearch(photosetXMLDoc, ‘//photoset’)/>
<!—Now grab the photos for this photoset—>
<cfhttp url=”http://www.flickr.com/services/rest/” result=”photosResult”>
<cfhttpparam type=”url” name=”api_key” value=”myAPIKey”/>
<cfhttpparam type=”url” name=”method” value=”flickr.photosets.getPhotos”/>
<cfhttpparam type=”url” name=”photoset_id” value=”#x#”/>
<cfset photosXMLDoc = xmlParse(photosResult.fileContent)/>
<cfset photosNodes = xmlSearch(photosXMLDoc, ‘//photo’)/>
<!—Loop over photosets to output photoset information—>
<cfloop from=”1” to=”#arrayLen(photosetNodes)#” index=”i”>
<cfset photosetsXML = xmlParse(photosetNodes[i]/>
<!—display 5 thumbnail images from each photoset—>
<cfloop from=”1” to=”5” index=”y”>
<cfset photosXML = xmlParse(photosNodes[y])/>
<a href=”http://www.flickr.com/photos/user_id/#photosXML.photo.xmlAttributes.id#/” target=”_blank”><img src=”http://farm#PhotosXML.photo.XMLAttributes.farm#.static.flickr.com/#PhotosXML.photo.XMLAttributes.server#/#PhotosXML.photo.XMLAttributes.id#_#PhotosXML.photo.XMLAttributes.secret#_m.jpg” alt=#PhotosXML.photo.XMLAttributes.title#”/></a>
<a href=”” target=”_blank”>View all snapshots in this set</a>
The above code works just fine and honestly, my internal client is satisfied with it. But I have a couple of problems with it.
- All this code is in the view file.
- If they decide they like this and want another similar page, I have to code an entirely new page with similar calls to the api.
- Logic and display all mixed together.
- It’s a lot of code ~50 lines.
A Better Way
There had to be a better way to separate logic and display and a way to make the api calls available to any view that needs it in the future. I knew there were CF scripts available for the Flickr api, but they aren’t ready made for CFWheels. I figured there would be a Flickr plugin and I was right. I downloaded the SimpleFlickr plugin and got to reading the documentation.
I was able to determine the plugin would do most of what I needed so I set about tweaking it a bit to get the rest. Turns out it was fairly simple and enabled me to separate out the logic from the display and make the api available across the site. Craig Kaminsky created the plugin which provided a great starting point for me. I contacted Craig to let him know I was using the plugin and wanted to tweak it a bit and he offered to integrate my changes into the full plugin. The SimpleFlickr plugin is installed in the plugins folder in my site and I modified the SimpleFlickr.cfc a bit to get the additional information needed for my display. So now my display code looks something like this.
<cfloop list=”#photosetList#” index=”x”>
<cfloop from=”1″ to=”#arrayLen(photosets)#” index=”i”>
<cfif x EQ “#photosets[i].id#”>
<cfset photos = getFlickrPhotoSetPhotos(#photosets[i].id#)/>
<cfloop from=”1″ to=”6″ index=”y”>
<a href=”#photos[y].link#” target=”_blank”><img src=”#photos[y].url#” alt=”#photos[y].title#”/></a>
<a href=”http://www.flickr.com/photos/#application.flickr_user_id#/sets/#Trim(x)#/” target=”_blank”><strong>View All Snapshots in this Theme</strong></a>
Ahh, that’s much better. Less code. No logic in the display. And any page in the future can call the api. Of course the result is identical to the client. I can live with that.
Nearly all of my modifications to the plugin were to the private methods that deal with manipulating the resultset from Flickr. Chiefly, I worked on the $getPhotosFromJSON() method to build the link url that would be used in my display. This also required me to add the photoset.owner and photoset.id into my return array. I have to thank Craig again for building the plugin in the first place which allowed me to tweak it to my needs. I really think this plugin is useful for those who need some basic functions from Flickr in their CFWheels apps.
I’ve blogged in the past about my Google Sketchup hobby. One resource I’ve found very useful is the Sketchup: A 3D Toolbox video podcast. Cameron Scott guides viewers through lots of techniques and projects to improve modeling skills. To mark the 50th episode, a new project modeling the Kaweah Falls house was kicked off. Using a floorplan, the project will model the house. This is pretty cool to me. I’ve always been interested in architecture so I’m really curious to see how to use Sketchup to model this interesting home.
In the first part of the exercise, we imported the floorplan so that we could begin modeling. Because this structure has some parts on different axes we use the axis tool to change the axis so that our lines can be drawn correctly. We then proceed to model the walls from the floorplan. This was followed by using the offset tool to add thickness to the walls. Before we use the push/pull tool to extrude the walls up to 8 feet, we first use the tool to extrude an 8 inch slab. Now we use the push/pull again to pull up walls to 8 feet in height. I made it sound so simple in just a few sentences, but it took me about an hour to get it right. Check out the project as it stands now. Looking forward to the next steps.
Continuing with my CFWheels powered Forum application, I had a desire to include a thread count and a post count for each forum listed on the main forum page. In my old spaghetti coding days, I would first have used a retrieveForums query. Then in my display code, while looping over the retrieveForums recordset, I would then query the threads table passing in the forumID foreign key to obtain a thread count for each forumID. In a similar fashion, I would get a post count for each forumID. The code below illustrates this scenario.
<cfquery name="getForums" datasource="myDSN">
SELECT * FROM forums
<cfquery name="getThreadCount" datasource="myDSN">
WHERE threads.forumID = #getForums.id#
While this is not the CFWheels way, I found out that it is very easy to convert this code into CFWheels syntax with the same results.
Enter Calculated Properties. Searching the CFWheels blog and documentation, I was able to find this little gem which allows me to assign additional properties to a given object based on a SQL query. In this manner, property then becomes part of that object without the need to loop over a query to retrieve it as in the above code block. This property can then be called just like any other property of that object. Honestly, I’m not entirely sure I worded that correctly, but the bottom line is the result is the same as my spaghetti code example. Let’s look at the new code in my forum model.
<cfcomponent extends="Model" output="false">
<!--- Associations --->
<!--- Properties --->
<cfset property(name="postCount", sql="(SELECT COUNT(posts.id) FROM posts INNER JOIN threads ON posts.threadid = threads.id WHERE threads.forumID = forums.id)")/>
<cfset property(name="threadCount", sql="SELECT COUNT(threads.id) FROM threads WHERE threads.forumID = forums.id")/>
<!--- Validations --->
<cfset validatesPresenceOf(property="forumName", message="Forum name is required.")/>
<cfset validatesPresenceOf(property="forumDescription", message="Description is required.")/>
And the new display code.
<!--- Here we are outputting the forums query. The forums query will return every forum with a post count --->
<tr height="35" <cfif currentRow MOD 2>bgcolor="##ebebeb"</cfif>>
<td> #linkTo(text="#forumName#", controller="forums", action="viewForum", key="#id#")#<br/> #ParagraphFormat(forumDescription)# </td>
My new calculated properties–threadCount and postCount are now part of the forums object and can be used just like any other field/property in that object.
I hope my explanation makes sense. Calculated properties will come in handy as I move forward with this project. CFWheels makes another programming task so much simpler.