Tuesday, July 19, 2011

06 Simple form handling example

So now we can put this knowledge to work and create something that will allow us to handle a simple form.

To show that we are not stuck to CFBuilder, I will use sublime text 2 with ColdBox Platform plugin active. (Available in package control)

Suppose we have a page in our website where visitors can leave their contact details so that a sales representative can contact them with a quote...

This feature or service is divided into three general events:
  1. Show a form to fill out.
  2. Handle the form when submitted and add the details to a database.
  3. Show a page to the visitor telling them the request has been received.
This list basically shows us the workflow that needs to be implemented into the controller, so without worrying too much about other things, lets create a handler for this workflow called ContactMe.

Right click on the handlers folder and create a new file named ContactMe.cfc.

To let ColdBox platform work its magic, type handler followed by the tab key:

There, ColdBox Platform generated a handler ContactMe.cfc with a lot of comments. Because we want this tutorial to be simple, we are not going to use any of the IMPLICIT FUNCTIONS, even though they are extremely useful, so we remove that entire comment block.

At this point we only have one event: function index(event, rc, prc) {}, which we will use to show our contact form. So we need to add two extra events, one for processing the form and one for confirming receipt.

Even though an event has a default view by convention in ColdBox (handlerName/eventName) I still like to set the view explicitly. For me this makes it easier down the line when reviewing and debugging code.
In actual fact, the event we use for processing a form does not have anything to show so it will not need a view and we hint this by explicitly not setting a view in the code.

The process event should actually redirect the browser to the confirmation page so that forms don't get submitted twice.

ContactMe.cfc handler

Lets have a look at our adjusted handler:
/**
* Service to visitors. They can leave their contact details for sales representatives to contact them with a quote
*/
component{
 
  // OPTIONAL HANDLER PROPERTIES
  this.prehandler_only  = "";
  this.prehandler_except  = "";
  this.posthandler_only  = "";
  this.posthandler_except = "";
  this.aroundHandler_only = "";
  this.aroundHandler_except = "";

  // REST Allowed HTTP Methods Ex: this.allowedMethods = {delete='POST,DELETE',index='GET'}
  this.allowedMethods = {};
  
  function index(event,rc,prc){
    event.setView("ContactMe/index");
  }

  function process(event,rc,prc){
    setNextEvent("ContactMe.confirm");
  }

  function confirm(event,rc,prc){
    event.setView("ContactMe/confirm");
  }
 
}

So now we have three events:
  • index(event,rc,prc)
  • process(event,rc,prc)
  • confirm(event,rc,prc)

In two of these functions there is a call to event.setView(ViewFile).
The value of ViewFile represents a path from your views folder to the file you want to display for this event. (.cfm is omitted as ColdBox adds it automatically for you)

So:
  • index will show the file at views/ContactMe/index.cfm,
  • process will redirect to the confirm event,
  • confirm will show the file at views/ContactMe/confirm.cfm
We still need to create those files, so lets do that quickly; in the views folder, create a folder called ContactMe. In there, create the two files: index.cfm and confirm.cfm with some content
The content can be something static for now, as long as we can see which view is being shown.

views/ContactMe/index.cfm
<h2>Index page</h2>

views/ContactMe/confirm.cfm
<h2>Confirmation page</h2>

So now we can test if our app is working so far.

First reinitialize your application by browsing to:
http://your_server/your_project_folder/index.cfm?fwreinit=true

Then browse to:
  • http://your_server/your_project_folder/index.cfm/ContactMe
  • http://your_server/your_project_folder/index.cfm/ContactMe/process
  • http://your_server/your_project_folder/index.cfm/ContactMe/confirm

index.cfm/ContactMe

index.cfm/ContactMe/process
Does in fact forward to the confirm page.

index.cfm/ContactMe/confirm


Ok not much to look at, but it does confirm that what we did so far works.

The views/ContactMe/index.cfm will have the html code for the form and the views/ContactMe/confirm.cfm will have the html that tells the person who submitted the form that the request was received.

Lets make us a simple contact me form and a simple confirmation page where we thank the visitor.

Fleshing out the views

Lets go ahead and change the views/ContactMe/index.cfm to resemble something like what is shown next:

views/ContactMe/index.cfm
<cfoutput>
<h1>Please Contact Me</h1>
<p>Fill out the form and one of our sales representatives will contact you shortly.</p>
<form action="#event.buildLink('ContactMe.process')#">
  <label for="firstName">First Name:</label><br/>
  <input id="firstName" name="firstName" type="text" /><br/><br/>
  <label for="surname">Surname:</label><br/>
  <input id="surname" name="surname" type="text" /><br/><br/>
  <label for="phoneNumber">Phone Number:</label><br/>
  <input id="phoneNumber" name="phoneNumber" type="text" /><br/><br/>
  <label for="emailAddress">Email Address:</label><br/>
  <input id="emailAddress" name="emailAddress" type="text" /><br/><br/>
  <input id="submit" name="submit" type="submit" value="Submit" />
</form>
</cfoutput>

As said, it is a very simple form...
It introduces a new function though: event.buildLink("ContactMe.process").
This is a very convenient function as we can build our links without having to worry what SES system we are using. ColdBox will build your link according to the SES interceptor that is being used. It is advised to use this function for all your links.

Now lets change the views/ContactMe/confirm.cfm to resemble something like this:

views/ContactMe/confirm.cfm
<cfoutput>
<h1>Request Confirmed</h1>
<p>Thank you! We have received your request and you will be contacted by one of our sales representatives soon.</p>
</cfoutput>

Now visit http://your_server/your_project_folder/index.cfm/ContactMe and you will be presented with a nice form.

Hit Submit and you will be presented with the confirmation page.



We know we actually posted the form to the process event and we were automatically redirected to the confirm event. So now we need to introduce a model to take care of form validation and accessing the database to log the request.

Creating a model

Ok, in my opinion the model integration on ColdBox wiki takes us way too far for this simple example. So I will make this very simple as was the goal of this tutorial.

Create a new file in the model folder called ContactMeService.
Let ColdBox platform work its magic by typing model followed by a tab.
Change the comment to something meaningful.



Following the naming convention described in model integration on ColdBox wiki we call our model ContactMeService. (it will be our service layer in future posts).

We give it an optional description.

Note, to keep things simple we will forget about dependency injection for now and instantiate our components the old fashioned way. Also, our ContactMeService will be a does it all component, where in good OO programming the service layer should be separated from the data access layer... We will forget about all that and create a very basic model that does what we need.

For persistence I will use sessions in the old fashioned way as well... And to make it even worse, I am adding the entire service object to the session which is also not advisable. In any case it is just meant to give you a good idea of how things will work.

So here is our simple model after editing it a bit:

model/ContactMeService.cfc
/**
* Handles ContactMe requests
*/
component accessors="true" {

  property name="id" type="numeric" default="0";
  property name="firstName" type="string" default="";
  property name="surname" type="string" default="";
  property name="phoneNumber" type="string" default="";
  property name="emailAddress" type="string" default="";
  
  ContactMeService function init(){
    return this;
  }
  
  public boolean function process(rc){
    // set the properties with values passed by rc
    setFirstName(rc.firstName);
    setSurname(rc.surname);
    setPhoneNumber(rc.phoneNumber);
    setEmailAddress(rc.emailAddress);
    // do some minor validation
    if(
      trim(firstName) == "" or
      trim(surname) == "" or
      trim(phoneNumber) == "" or
      trim(emailAddress) == ""
    ){
      return false;
    }
    // if all is valid, add the request to the database
    var queryService = new Query();
    queryService.setDatasource("someDSN");
    queryService.setSql("
      INSERT INTO ContactMes (
        firstName,
        surname,
        phoneNumber,
        emailAddress
      ) VALUES (
        :firstName,
        :surname,
        :phoneNumber,
        :emailAddress
      )
      OUTPUT INSERTED.id
    ");
    queryService.addParam(name="firstName",value="#firstName#",cfsqltype="VARCHAR");
    queryService.addParam(name="surname",value="#surname#",cfsqltype="VARCHAR");
    queryService.addParam(name="phoneNumber",value="#phoneNumber#",cfsqltype="VARCHAR");
    queryService.addParam(name="emailAddress",value="#emailAddress#",cfsqltype="VARCHAR");
    var result = queryService.execute();
    // get the output inserted.id and set the id property
    setId(result.id);
    return true;
  }
  
}

So it is a basic component with accessors set to true so we don't need to write getters and setters.
It has 5 properties and very simplistic, they each represent a column in my ContactMes table.
It has a init() method to initialize returning itself.
It has a process method that:
  1. Sets the properties by the values passed via rc
  2. Does some basic validation, returning false when validation fails
  3. If validation succeeds we add a record to a table in a database and records the new primary id
  4. Returns true after the insert

Ok we are ignoring any possible errors that could occur when inserting stuff into a database, but I'm sure you get the picture.

Now lets update our handler to make use of this model:

handlers/ContactMe.cfc
/**
* Service to visitors. They can leave their contact details for sales representatives to contact them with a quote
*/
component{
  
  // OPTIONAL HANDLER PROPERTIES
  this.prehandler_only  = "";
  this.prehandler_except  = "";
  this.posthandler_only   = "";
  this.posthandler_except = "";
  this.aroundHandler_only = "";
  this.aroundHandler_except = "";   
  this.allowedMethods = {};
  
  function index(event,rc,prc){
    if(!isDefined("session.contactMeService")){
      session.contactMeService = new model.ContactMeService();
    }
    event.setView("ContactMe/index");
  } 

  function process(event,rc,prc){
    event.paramValue("firstName","");
    event.paramValue("surname","");
    event.paramValue("phoneNumber","");
    event.paramValue("emailAddress","");
    if(session.contactMeService.process(rc)){
      setNextEvent("ContactMe/confirm");
    } else {
      getPlugin("MessageBox").setMessage("error","All values are required.");
      setNextEvent("ContactMe");
    }
  } 

  function confirm(event,rc,prc){
    structDelete(session, "contactMeService");
    event.setView("ContactMe/confirm");
  } 
  
}

A few things have changed here:
  1. In the index method I check if contactMeService is in the session and if not I create a new instance of our model component.
  2. In the process method I make sure that rc.firstName, ... exists by calling event.paramValue(variable, value). You could compare this to cfparam. Know that rc is a reference to a struct of values in event. So calling methods on event can change the values of rc.
  3. ColdBox is smart and prepares posted variables by putting them in the rc value. So we can pass rc to the process method of the contactMeService we have in the session.
  4. If the result is true, we get relocated to the confirm page and delete contactMeService from the session.
  5. If the result is false, we use a nifty plugin that ColdBox provides to set an error message and relocate back to the form
Note, this is not the best way of doing things, but it will get you started.

Now we need some small changes to the view that displays our form to:
  1. Display error messages.
  2. Repopulate the form fields.
Here is how I did it:

views/ContactMe/index.cfm
<cfoutput>
<h1>Please Contact Me</h1>
<p>Fill out the form and one of our sales representatives will contact you shortly.</p>

<!--- display any messages in the event --->
#getPlugin("MessageBox").renderit()#

<form action="#event.buildLink("ContactMe.process")#" method="post">
  <label for="firstName">First Name:</label><br/>
 <input id="firstName" name="firstName" type="text" value="#session.contactMeService.getFirstName()#" /><br/><br/>
  <label for="surname">Surname:</label><br/>
 <input id="surname" name="surname" type="text" value="#session.contactMeService.getSurname()#" /><br/><br/>
  <label for="phoneNumber">Phone Number:</label><br/>
 <input id="phoneNumber" name="phoneNumber" type="text" value="#session.contactMeService.getPhoneNumber()#" /><br/><br/>
  <label for="emailAddress">Email Address:</label><br/>
 <input id="emailAddress" name="emailAddress" type="text" value="#session.contactMeService.getEmailAddress()#" /><br/><br/>
  <input id="submit" name="submit" type="submit" value="Submit" />
</form>
</cfoutput>

And there we have it!!! A working example of a handling simple form.

Sunday, July 17, 2011

05 MVC in ColdBox

This post continues with the project we set up in the create a ColdBox project post. It is basically an empty project with an advanced application type skeleton.

For now we will ignore all the advanced stuff and focus on how to handle a simple form in the MVC pattern as ColdBox has set it up. We will focus our attention on four folders in our new project:

Model
  • model folder
    The model folder will contain classes that define our business logic and persistence logic to name a few.
View
  • layouts folder
    The layout folder contains files that depict our general look and feel.
  • views folder
    Beside a general look and feel, each different page in your website will have different details to show. The views folder will hold files that generate those details and ColdBox will inject them into your layout files.
Controller
  • handlers folder
    The handlers folder will contain our workflow; it defines event actions that will usually be called by browser events. For the scope of this tutorial, it will only be called by browser events.

Lets put this to the test and try handling a simple form.

04 About MVC

I assume you are already familiar with the concept of MVC, so I will not elaborate too much about what it is. Suffice to say that it provides you with a way to detach your web design (user interface) from the workflow and your business logic.
  • This means that it becomes easy for you to rearrange your look and feel and it is even possible to outsource the design to some html guru you may know without any risk that this guru will destroy your hard programming work. That is a major benefit!
  • It also means that you can rearrange your workflow without touching your business logic, which makes re-factoring easy.
  • Likewise, you can re-factor your business logic objects without messing up your workflow.
MVC layers are loosely coupled, this means that they are still coupled albeit loosely (duh). The more you practice the principles of MVC, the more adept you become, the looser they will be coupled. In my experience, the trick is to make good use of OO interface and abstraction principles and writing towards an API contract. (How to do this is beyond the scope of this tutorial, but fear not, the conventions in ColdBox will effectively decouple your layers without much thought.)

If you refactor in such a way that the API contract does not change, none of the other layers of the MVC will need to be changed. This requires a good understanding of OO (Object Oriented) concepts and design patterns will also be helpful. Although be careful not to loose your head in design patterns, they are an entire study on its own and will make the step from traditional sequencial scripting to OO seem all the more difficult and discouraging. Take baby steps!

Some nice resources on MVC:
Some nice resources on Design Patterns:

So how does this work in ColdBox?

03 Create a ColdBox Project

Create a new project








On to some more interesting stuff, lets talk about MVC.

Saturday, July 16, 2011

02 Installing ColdBox

I will not explain all the different ways to install ColdBox.
One way is enough to get you started, and once you are familiar with the framework you can explore the ColdBox Wiki for other ways to install it. Obviously this is not for your production server! It is just a way to get you started on your development machine.

Plain and simple:
  • Download the latest code: ColdBox Bundle
  • Unzip the file to a folder named "coldbox" in your webroot
That is it! Your development server is now ColdBox enabled.

I could now tell you to get the latest MXUnit code and unzip it to your webroot, but you don't need it to get started with ColdBox. I will save
that for a later blog when we dive into Unit Testing.

What I will advise you (and show you) is to download some plugins for Eclipse, ColdFusion Builder 1 or ColdFusion Builder 2. (don't worry, they all use the same plugin; just the method of installing will be slightly different for each IDE).

Those plugins will make your life easier AND I will be using them for my studies/tutorial.

Prepare ColdFusion Builder 1 for ColdBox development

I am still using ColdFusion Builder 1 so I will show you how to install the plugins for my IDE, but there's ample tutorials out there on how to install it on the other IDEs. In fact, I struggled to get things working on CF Builder 1 as most tutorials handle CF Eclipse or CF Builder 2.

Using the plugins in the three IDEs above is pretty much the same (as all three are Eclipse based) so folowing the study/tutorial will be possible regardless of the IDE you are using.

Lets be prepared and download everything we need:
  • ColdBox Platform Utilities
  • ColdBox CFBuilder Syntax Dictionary
  • ColdBox CFBuilder Snippets
Download it at ColdBox Extra Downloads.
The Platform Utilities are the same for CFEclipse and CFBuilder.
Where the Dictionary and the Snippets are concerned, you will find separate files for CFEclipse.

Step 1 - ColdBox Platform Utilities

In CFBuilder select the menu item Window - Show View - Other...


In the popup select ColdFusion - Extensions and click OK.


In the extension window, click the plus sign to add a new extension.
As you can see I am cheating because I already have the extension installed...


After clicking the plus sign you can browse for the ColdboxPlatformUtilities.zip file and you are good to go. CFBuilder 1 now has some super duper ColdBox 3 capabilities.

Step 2 - ColdBox CFBuilder Syntax Dictionary

Locate your ColdFusion Builder installation folder, go to plugins, then com.adobe.ide.coldfusion.dictionary_x.x.x.xxxxxx and finally dictionary.

You may have multiple com.adobe.ide.coldfusion.dictionary_x.x.x.xxxxxx folders, just take the most recent one. This is due to an update of CFBuilder and bad clean-up afterwards. (I suspect)

In my case:
D:\Program Files (x86)\Adobe\Adobe ColdFusion Builder\plugins\com.adobe.ide.coldfusion.dictionary_1.0.0.274293\dictionary

Copy the coldbox.builder.xml file that is in the cfbuilder_dictionary.zip archive you just downloaded into that folder.

Next edit the dictionaryconfig.xml to let CFBuilder know about the new dictionary, and whoosh, CFBuilder now has code completion for ColdBox features.

Step 3 - ColdBox CFBuilder Snippets

In the cfeclipse-cfbuilder-snippets.zip archive you downloaded you will find a readme file that states:

Just place the ColdBox snippets folder under your snippets directory of your CFEclipse or CF Builder installation.

To find your snippets folder do the following:

Click on Window > Preferences > ColdFusion > Snippets

On the right panel, you will see the snippets directory. There is where you place these files.

This was written by the one and only 'daddy' of ColdBox: Luis Majano

Do that and paste the content of the snippets folder from the archive into the folder you have just found.
In case you already had some snippets that you assigned hotkeys to, don't overwrite the KeyCombos.properties file. Rather open it with any text editor and paste the content of the one in the archive into your existing file.

And that's it, now you have some cool snippets at your disposal.

Last and maybe least

You can enable ColdBox help and References in your CFBuilder by clicking Help - Install New Software

In the popup window type the URL: http://www.coldboxframework.com/distribution/eclipse/

Check the Help & Reference box and click next. Follow the instructions and you are done!

Congrats, you now have a killer of a ColdBox IDE. Enjoy the benefits!

Now lets use these tools and create a ColdBox project.

Friday, July 15, 2011

01 Where to start?

After careful research, my company decided finally to start using ColdBox 3 as a framework for our development. I say finally because we were still developing in FuseBox 5 and support for that, as well as the community has been on a very low profile for the last couple of years.

So one of the reasons that made us go for ColdBox is certainly the fact that it is still very much alive and version 3.8 has been released just a few weeks ago. On top of that, ColdBox has a very lively community and the team puts great effort in documenting the framework.

Seamless integration with Unit Testing (MXUnit, MockBox and Selenium) is the second reason. As our company is growing rapidly and the demands of customers to re-factor become more and more a daily task, we needed a solid testing base, both for testing the Units and the user interfaces (Selenium).

Those are the two major reasons why we chose for ColdBox 3 and added to those are a whole range of other reasons which I will elaborate on during the course of my blogs.

What is this blog about?

I have been tasked to prepare for using ColdBox 3. Learning the framework so that I can teach my colleagues what I know before diving into paid courses to refine our knowledge.
One of my major concerns is the overdose of documentation available, this is both a blessing and a curse: ColdBox Wiki has so much to read through... And because the new version is extremely new, the documentation is fragmented, a mix of the old and the new versions of the framework.

This is not me pointing fingers... It is very understandable for the documentation to be behind, after all it is a hell of a lot of work to get everything ready in time. But it does make the already challenging learning curve of learning a new framework even more difficult.

Yesterday I read a blog of Dan Vega that clearly shows in the comments that a lot of dedicated ColdFusion programmers feel the same way about it. But a learning curve should not be a reason to ignore a framework. Personally when I decided to pursue a career in Software Development I already resigned to the FACT that I would need to study my entire life. That is actually what makes this job so great! Yes, we have our boring routines, but at the end of the day you need to keep thinking "innovation"; it will enhance your personal experience AND the quality of your software. I need to be able to be proud of my accomplishments, it's what keeps me going.

But anyway, enough of me boring you to death... My reason for starting this blog is simple:
Because I am completely new to the framework, I will try to log my progress. This is both in favor of my colleagues as it is for the community. Hopefully this will result in a nice top down tutorial that can be used as a red wire through the studies of any newbie like myself.

Secretly I hope that the content of the blog may one day find its way to the ColdBox Wiki for everybody to find.

I hope my effort can be of help to somebody.

Now off to installing ColdBox