Months Archive February 2007

 
 

Persisting Complex Objects

When it comes to programming pages, it’s almost always harder to create a page that accepts input (a form page), than a page that outputs (general dsp page). When displaying information from a database for instance, you may need to go the database and get everything you need while in the controller, then in the view display all that in some nice form. When you’re accepting input though, there can be quite a few more steps. If they’re editing something you’ll need to do the same amount of work in your controller, plus all the logic to actually saves the record when it’s submitted in addition to the form which must be prefilled with the current record. Usually when this form is submitted it’s going to be more difficult to save the record back than it was to get it in the first place as well.

So if we’re boiling this down to units of work for a display page, we might have 1u of work in the controller to get the record and 1u to display it in the view. For the form page though you’ll have those 2u + another 5u+ in the controller to param everything passed in, create the objects and then save them and forward the user to somewhere. If there are errors that’s another case to handle. The actual form to display this information now needs that initial data, additional form markup, additional validation markup and possibly results (“Object updated successfully”). All that being said you’re looking at 2 units of work for output, and a minimum 8 units for a form. It’s no surprise that making these 8 easier to work with is something that saves developers huge amounts of time.

How can these be made easier for us though? In Coldfusion there are a number of ways to handle something like this, but some things are just hard to find. Lets say you’re creating a form for adding and editing products. Products will primarily exist in one table at this point (we’ll go into more later). So how do you save this? Using Reactor you have two possibilities (probably many more, but two main ones come to mind).

1) When the user submits the page you could create a Product transfer object (denoted with “to” which is really just a structure) that corresponds to the table structure you’re inserting into (or as you have the table defined in Reactor). Then you pass this structure into the ProductDAO.create() method which will perform the actual insert. The downside of this method is that no validation is done in this situation. create() returns void, so unless there’s a caught error you won’t know anything is wrong. To paraphrase, your code might look something like this (assume no mvc framework, but coldspring/reactor).
[cfm]




[/cfm]

This example has no validation, although you could validate these with cfparam and catch the Validation exception, but that doesn’t take into account any business rules you have. For instance you might want all descriptions to be at least 150 characters and all product names to be more than 3 and less than 50 characters. Although you can define the maximums in your varchar fields, defining the rules and checking before you get to the database is much more of a drag, and should really be done in your business layer, not your controller.

2) When the user submits the page you create a ProductRecord object instead of a structure. In reactors there are heavyweight objects that contain everything you need to work with a ProductRecord. You can set fields on it, see if it validates and then save the record to the database. For instance, you could do something like this instead:

[cfm]









[/cfm]

The ProductRecord.save() method actually uses the ProductDAO.create() to do it’s work, but at at that point you have a lot more control over the life of the record than when you’re using the DAO directly.

Multiple Objects?
This is something I’m still trying to find a good solution to, but Model-Glue Unity offers one at least. To expand on this example, assume that each product also belongs to any number of categories. These are managed through a mapping table, so product has and belongs to many categories. Per linked to a good example of how this is done in Rails on the CFWheels google group, although it is surprisingly more code than the Model Glue way. How do they do it? Well, automagically.

Model-Glue 2: Unity has this concept of Generic events. You’ve probably seen them if you’ve ever tried scaffolding, or watching one of the videos on Model Glue. The idea is that you’ll create a small tag in your controller and it’ll perform all the work for you. For example, to insert a Product, complete with all related categories, your entire controller code might be as simple as:

<message name="ModelGlue.genericCommit">
  <argument name="recordName" value="productRecord" />
  <argument name="criteria" value="productID" />
  <argument name="object" value="product" />
  <argument name="validationName" value="productValidation" />
</message>

This is very abbreviated code for all this work. Basically this is telling ModelGlue to try to commit to the product table of the database, and if productID was passed in from the form it should instead an update, if no productID is passed in it will be an insert. If there’s a problem creating the product we’ll save the validation errors to productValidation. That’s quite a lot of information, but how does ModelGlue know to commit this? Well it’s all based on Reactor configuration of your object along with the naming of your form fields.

Getting the form setup isn’t difficult, but takes forethought that you’re going to use the genericCommit action rather than do the work yourself. Form field names on your form should match the database columns declared in the product table. Mapping those to be inserted is helpful, but how does it add all the categories? Assume in this case you have a list of checkboxes for your categories, where you check off whatever categories you want this product to be a part of. It would be important to name this checkbox category|categoryID if you want to it to work. This is assuming you have a category object in reactor as well as a link table that will contain just categoryID and productID. That’s actually all you need for this to be inserted/updated at that point. If you’re updating you’ll want a hidden field with the productID of course, but other than that.

So how does this work? Well that’s opening a can of beans. Joe’s done an excellent job of creating helpful additions to the framework so fast that I haven’t seen people post each feature. The real magic for this occurs in the modelglue.unity.orm.ReactorAdapter.cfc file in the assemble() method. This method will get all the metadata from reactor for the table you’re working with, in this case product, and loop over it. The basic population is achieved with the makeEventBean() bean function which is extremely useful whether you’re using GenericCommits or not, but the magic for these related tables also exists here. The ReactorAdapter loops over all fields from the metadata structure and attempts to populate any that have a plural relationship with the product object. In the end this assemble() method will delete any records from the mapping table that weren’t passed in and add any new children to there. The whole Generic set of functions is one of the most impressive things about Model-Glue, and enables some extremely fast development if you know what you’re doing.

What about doing something like this in a more service oriented architecture though? What is the framework knew enough based on your form names to create tiered structure containing everything — the product and the categories. Basically I’m trying to find a service oriented approach to creating objects without hardcoding the relationships like categories as is done in the ModelGlue example. Basically the code would look something like this:

[cfm]
[/cfm]

This would then do a deep load of the object into the product object. Then you could call your default product.save(), product.validate(), product.hasErrors() methods. The downside is I don’t think something like this would be plausible, as then your error collection would have to recurse through all the objects that were edited as well. I’m sure there’s a better solution than that 8u example. ModelGlue2 gets it down to 5u by abstracting the validation, paraming and related objects though, so it’s definitely work looking into if you’re using ModelGlue.

One more Advanced Certified Coldfusion Developer

For my last weekday off before heading back to a new job this coming Monday, I decided it was a good time to study up and get Coldfusion Certified. I decided to do so about two weeks ago, just before the frameworks conference, and have been studying little by little since then. The end result? A respectable 89% on the exam, and a nice Advanced Certification title. Even though the first rule about adobe testing seems to be “Don’t talk about Adobe testing”, I thought I’d go over what Adobe Certification is, why I did it and how I studied for it.

What is it?
To be specific, I’m talking about the Certified ColdFusion MX 7 Developer certification. According to the adobe site, the test is 66 multiple choice questions which must be completed in 75 minutes. As far as scoring goes, if you get above 85% right (missing ~9 or less) you’ll be awarded an “Advanced Certified Developer” title, if you get above 70% (missing ~19 or less) you’ll earn the title of “Certified Developer”. The test costs $150.00 to take and is administered at a Virtual University Enterprise (VUE) testing center. Signup is easy on their site, even if it did take a day for me to get my password email.

Why get certified
Everyone has their own reasons to get certified, but for me it was mostly just to go outside my comfort zone in Coldfusion and see what else was out there. In two and half years at the my last job I have to say I touched on a majority of the test topics, but there are entire sections specified in the Exam Guidelines I had no idea on. A lot of things like cfrepot, cfdocument, cfchart, cfforms and customtags weren’t heavily used, so it was a good learning experience getting my head around them. I have to say though, there are a LOT of functions out there I just don’t see myself ever using. YesNoFormat()? But mainly by seeing what else is out there your code becomes cleaner by using the right tool for the right job.

Study Techniques
I’ve had Ben Forta’s Macromedia ColdFusion MX7 Certified Developer Study Guide for the last 8 months but hadn’t read more than a chapter or two. To make myself study, the first thing I did was sign up for the exam, scheduling it for 2 weeks later. Just the act of scheduling it certainly made my study more because I was no longer putting off the decision. I’d tried taking Ben Forta’s sample exam, and didn’t sign up until I could get above a 50% on it without preparation. To start off those two weeks I began reading about the topics that I had no knowledge of whatsoever. The tags mentioned above, some web service related functions, various scopes, cookies — just things I hadn’t worked with.

The most useful tool in studying came next though — I bought a copy of CFMX Exam Buster 7.0. Although it’s not the prettiest application, it serves one purpose and serves it sell. The software contains 875 exam-specific questions in a very flexible to use structure. There are 13 test exams with predefined questions that are the same each time, but also the ability to create random exams as well as taking tests on single topics, like an exam on arrays, charting, cfml functions, etc. After taking each exam it’ll show your score, how you faired in each category, a recap of every question on the exam with answers, details and reference links, and another tab that only shoes the questions answered incorrectly. After the first time taking an exam I’d always go over the entire exam, then on subsequent tests I’d skip to the incorrect tab right away. While taking the exam there is a “help” option which shows the right answer, help url and description about the answer that can be accessed for the current question. While taking exams the first time I’d also pretend it was the real exam – no looking up answers or using help. After that I’d use help on ones I wasn’t sure about, but for scoring purposes only after I picked what i thought it was. Taking the same test a few days later helps to be sure you understand the topics too, so that was a major help. Keeping track of your progress makes things a little clearer too and shows an accurate snapshot of your progress. For instance, here’s my progress as shown from these sample test scores:

Date Test Score Change
1/29/2007 1 63*
1/31/2007 2 66*
1/31/2007 1 95 +32
2/4/2007 3 66*
2/6/2007 1 93 -2
2/6/2007 4 78*
2/7/2007 2 81 +15
2/7/2007 3 89 +23
2/7/2007 5 80*
2/7/2007 6 77*
2/8/2007 4 93 +15
2/8/2007 5 89 +9
2/8/2007 2 89 +8
2/8/2007 6 93 +16
2/8/2007 7 77*
2/8/2007 8 80*
2/8/2007 7 96 +19
2/8/2007 8 96 +16
2/8/2007 9 77*
2/9/2007 10 81*
2/9/2007 11 90*
2/9/2007 12 81*
2/9/2007 13 86*
* – Denotes first time taking that exam

The last 3 exams I took the morning of the test. The last two were while parked at the testing center because I couldn’t get a parking spot at Panera (by Rollins College) to study. Even with two weeks I still ended up studying mostly in the last 3 days, but that’s to be expected. The night before the exam I ended up cramming a little more by going through every question in the certification book and reading up on why the ones I missed were wrong. The book provides answers in the back as well as descriptions of why. Ben Forta’s sample exam uses the same questions as from the Certification Book, which is great for finding out what else you’re having problems with. Unfortunately the exam is a little flaky. If you press back and resubmit an answer you’ll end up missing two questions, so don’t go back! Some of the multiple choice options are incorrect, as if they were copy/pasted there in a hurry, or the script wasn’t written to output the options correctly so it displays something wrong. After going through the book i retook this test a good 15 times until I was scoring in the 90s. It’s a short 30 questions (out of a pool of maybe 175) so they start to seem familiar after a while which is both good if you’re understanding them but bad if you’re just filling in the answers.

This process definitely made me happy that I’m no longer in school, although it was fun for a short time on something I’m already interested in. There were a few “aha!” moments when studying too when i realized how much easier something could be accomplished using a different function or tag which will come in handy down the line. If you’re planning on taking it yourself, then good luck!

Coldfusion On Wheels, the forgotten framework

One framework that was unfortunately not represented at the Frameworks Conference was Coldfusion on Wheels. Although it was heavily developed at first, it’s started to split off with some question of the direction it’s going in. The idea is that it will be a port of Ruby on Rails for Coldfusion. There are a lot of concerns that people put out about Rails structure, one of those being that it’s impossible to use it without the model layer bleeding into the controller. Coldfusion on Wheels at the moment is in a big state of flux, but ColdFusion on Wheels 0.6 Lite comes without the model layer at all. On my way home from the frameworks conference I decided to give this framework some time on the plane home and was pleasantly surprised with the status of the project, and the flexibility of the current version.

Getting it setup
Downloading the latest lite version of the framework requires no real setup actually. The current version must be in document root from what I have been able to gather though so keep that in mind. The core framework files reside in the “cfhweels” folder which can be removed from the main app and mapped in cf administrator.

Search Engine Safe URLs
One of the initial draws for me was to see just how the url rewriting works. For those unfamiliar with Ruby On Rails or CF Wheels, these two offer what’s known as search engine safe (SES) URLs where the URLs no longer have query parameters in them 9for the most part). For instance, instead of referring to a page like http://localhost/index.cfm?event=user.profile&id=123, a search engine safe URL might be something like http://localhost/user/profile/123. The end result of this is that it’s (supposedly) better for search engines and (definitely) better for the user when trying to type in URLs.

CF Wheels handles this in both IIS and apache (tested both to work) in their own ways. For apache it uses the familar .htaccess tag, while in IIS it relies on Isapi Rewrite. What’s important with both of these is that it’s optional, and requires no knowledge of how .htaccess or isapi rewrite rules work. Those files are static and do one thing but do it well. They translate a link like

http://localhost/user/profile/123

to something like

http://localhost/dispatch.cfm?wheelsaction=/user/profile/123

The key factor being that you can opt to use these safe URLs or not, it’s up to you. So what does this resolve to? Well that’s configured in the /config/routes.ini file. By default there are three routes already:
[cfm]

[/cfm]
What this means is that when this request comes in, it will go through those and find the first one it matches. In this case it’ll be the first one because it has 3 parameters, controller, action, id. Think of this as calling the user.profile action, to put it in fuseaction terms. In that action, there will be a variable defined, request.params.id, which contains the value 123 in this case.

To expand on that a little, you could easily add another route if we wanted the username in the url instead of the id. So if we wanted something like this:

http://localhost/user/profile/AdamFortuna

We could add another router in our routes.ini file that looks like this:
[cfm][/cfm]
The same user.profile action will be executed, but there will be a variable defined, request.params.username, with the value “AdamFortuna”. Sounds easy enough, doesn’t it? CF Wheels handles this completely internally using routes. Although I haven’t traced through the code for this, the end result is the same as rails.

Webserver setup
I grabbed this piece of code from the CF Wheels Google Group, which works on my 2.0.59 apache setup as well as the posters 2.2.x installation:

<VirtualHost 127.0.0.2:80>
  ServerName cfwheelsroottest
  DocumentRoot "C:/inetpub/devroot/cfwheelsroottest"
  <Directory "C:/inetpub/devroot/cfwheelsroottest">
    AllowOverride All
  </Directory>
</VirtualHost>

I like to edit my local hosts file so that 127.0.0.2 will resolve to the name of the site I’m working with as well. So locally I’ll go to dev.mysitename.com and due to the hosts file addition (note hosts file is in C:WindowsSystem32driversetchosts) this will resolve to my local website instead of the actual one. Easy way to test things locally. In order to get safe URLs setup in IIS, you must be able to modify the isapi filters and add in a new one. For shared hosting in IIS you might not be able to run this feature of wheels, but if you have control over this it’s a very easy install.

Form helpers
URL rewriting is one thing that’s helpful for it to handle, as otherwise there is a lot more work involved in getting something like this setup, but there’s one other very helpful feature that is so simple to implement in any language that it might be overlooked — grouping form inputs from a form in an easy to use manner. What I mean might best be explained with an HTML example. Lets look at a sample form for a user to signup for a site.

<form action="/user/create" method="post">
  <label for="username">Username:</label><input type="text" id="username" name="user[username]" value="#request.user.getUserID()#"/>
  <label for="email">Email:</label><input type="text" id="email" name="user[email]" value="#request.user.getEmailID()#"/>
  <label for="password">Password:</label><input type="password" id="password" name="user[password]" value=""/>
  <label for="password_confirmation">Password Again:</label><input type="password" id="password_confirmation" name="user[password_confirmation]" value=""/>
  <input type="submit">
</form>

When this is submitted, it’ll go to the user controller, and the create action with the contents of th form. Similar to the URL parameters above, they will be available in the request.params variable. Note the naming convention in there though — user[username]. Wheels translates this a little bit before it gets to your controller, and turns request.params.user into a structure containing username, email, password and password_confirmation. Does this sound like anything? request.params.user is a transfer object! If the UserDAO is cofigured in Coldspring and Reactor, you could do something like this to insert this record.
[cfm][/cfm]
With that one line in your controller, you’d technically have everything you need to insert the form values assuming the form is complete.

Putting it all together
To be realistic though, you have to take into account a few more things. Obviously this shouldn’t be run when they call the user/create page, it should be run when thy submit the form. Also, what if there are errors? What if we have more related fields so it’s not just dealing with the user but a few other things? Well, I’m not quite there yet in some of those cases, but we can make it a little cleaner. As I said, this version of cfwheels has no model components, it is ONLY a controller. The question is what do you want in your framework? Brian Koteks presentation on Designing framework agnostic models showed just how little the framework can handle, and how important it can be to have things defined in a service layer. So what if you use Cfwheels with this service layer? Turns out it plays pretty well.

First a little preliminary information about cfwheels setup. In the app/controllers directory, you’ll have controllers whose names match the controllers in your urls. So those requests to /user/create will go to /app/controllers/user_controller.cfc, with the create() method being called. Consider this the application logic that exists to execute your service layer. This would be in your controllers in Model-Glue, your circuit.xml (or act pages) in fusebox — that kind of logic. After that it will automatically run a view associated with that page (unless overwritten in that create() method). The view page that it would run is located in /app/views/user/create.cfm. So looking at that URL you can know you need to mess with the create() method and that other display page. What does that create() method look like?

[cfm]






[/cfm]

Whats this do? Well, if that user structure exists within the request.params structure then we create the new user, generate a message saying it was successful and redirect the user to a new page. Otherwise we get a new blank user object filled in with any defaults.

Without getting too far into how the service layer is setup, it’s basically the same as in Brian Koteks examples. our create() method in the service looks like this…
[cfm]


[/cfm]
This just passes on that value to reactor which does the real work. In my working examples this is done in a BaseService which is extended by the UserService, but I’ll get more into that another time, once I figure out how to get error handling and multiple table inserts working easily.

CF Wheels is certainly a lot farther along than I would’ve thought it to be. Although it has no model components for which rails earns a lot of it’s fame, that can be easily substituted with a service layer generated by coldspring and reactor.