I have been asked quite a few times why not make a ColdBox lite version where you can only have the basics? Well, not many people know that this already exists. Therefore, I am linking to the SimpleMVC template you can use if you are just starting with ColdBox. This template is just the basic ColdBox conventions and a few settings, that's it. This template will ease you in to ColdBox MVC development. Once you are comfortable with just the basics of how to build apps with conventions you can always add on and start brining in extra features from the Coldbox Platform like: caching, logging, AOP, interceptors, feed integrations, security, etc. However, you won't feel as intimidated as if you where starting with a huge settings file.
The reason of having all the settings listed out is to tell the developer that there are all these settings you can use. It is also hard to create templates when everybody's level and approach is different. However, this can be overwhelming to entry level users, therefore we are now including the SimpleMVC template in the coldbox downloads to come or you can download it from here now: http://www.coldbox.org/downloads/simpleMVC.zip (3.0 template)
So let's do a simple ColdBox for Newbies guide:
Application Root:
In your application root you have an empty index.cfm template an a basic Application.cfc that is already configured for you, season if you like but it is already cooked.
Conventions basics:
You have 5 folders:
- config: where your config file goes and your URL routes go.
- handlers: where you have your controllers as cfc's (event handlers) that respond to actions.
- layouts: where you have your output layouts. We include one as the default.
- model: where your services and business objects go
- views: where your views go
That's it!
How to execute something? Before I just went to a page like users/list.cfm, now you have an event handler cfc that responds to URL/FORM events. However, since we prefer pretty url's as they are more descriptive, they already exist in ColdBox. We create one route or pattern that the framework responds to by default. Most of the time for simple stuff you use one route and that's it. When you want to create your own URL's, do url abstractions or get funky with routing, then you can expand. If not, one pattern is enought for simplicity's sake:
http://localhost/myapp/index.cfm/{handler}/{action}
So if I do this on the users/list.cfm example, this becomes
http://localhost/myapp/index.cfm/users/list
* You can remove the index.cfm by using an external rewrite tool like mod_rewrite
So from that URL, ColdBox looks for a users.cfc in our handlers directory and a list() method. Simple as that. You want a new event on the users link then just create a new method and voila! So in non MVC apps we would create a page, put some code on it, have if statements for when you submitted the page so it could do inserts or updates or business actions, and then display the html output. This basically get's split in two: a handler action (method) and the same view content. So now your events responds to the request. How does these methods look:
<cffunction name="list" output="false" returnType="void">
<cfargument name="event">
<cfset var rc = event.getCollection()>
<cfset rc.qUsers = getModel('UserService").getUsers()>
<cfset event.setView("users/list")>
</cffunction>
This is for very simple MVC, once you learn about ses and url routing, you can get fancy and create your own URL's, very snazzy!
The code above uses the getModel() method and it can retrieve model objects for you, no need to do create objects or persist them or do dependencies. ColdBox searches for those objects in your model folder and does all the persistence and wiring for you, so it helps out even more. Then once you are in the flow of things, you can even get rid of those getModel() calls and let ColdBox autowire your handlers by doing cfproperty annotations:
<cfproperty name="UserService" type="model" />
So what about my model, in this case it is a simple user service that provides data for me. So this is how it could look like:
<cfcomponent output="false">
<!--- Inject a Datasource Bean by coldbox --->
<cfproperty name="dsn" type="coldbox:datasource:mydsn">
<cffunction name="init" returntype="any" >
<cfreturn this>
</cffunction>
<cffunction name="getUsers" returntype="query">
<cfset var q = "">
<cfquery name="q" datasource="#dsn.getName()#">
select * from users
</cfquery>
<cfreturn q>
</cffunction>
</cfcomponent>
Very simple, you also use cfproperty to add dependecies, like datasource names, settings, other objects, and much more. You can get as simple or as complex as you like here.
The other important part of the handler code is the event object the method receives. This is called a request context that basically has all the variables that the request came in with (FORM/URL) all bundled into one. However, this object has tons of utility methods that you will discover as you move forward. However, the method that is mostly used is called getCollection(). This basically get's you a reference of the structure holding these variables and creates a local function variable to point to it. You can now use all the variables just like a normal structure as you did before using FORM/URL scopes, now you use the RC scope. (RC=Request Collection).
The call: event.setView("users/list") is also using conventions, you are telling the framework to look for the view "users/list.cfm" in the convention views folder. That's it. Then it will try to render that view in the default layout we have for our application. You can also say to not even render the view in a layout by just adding a nolayout=true argument to the setView() method.
Views/Layouts
ColdBox helps you create views that can be rendered within layouts much like a templating engine or layout engine does. All you do is describe your layout and then have a placeholder for where you want your views to render. Remember that a controller set's which view to render. So let's look at a simple example:
<cfoutput>
<html>
<head>
<title>Hello Template</title>
</head>
<body>
<div id="header">#renderview('tags/header')#</div>
<div id="content">#renderView()#</div>
<div id="footer">#renderview('tags/footer')#</div>
</body>
</html>
As you can see, I can use the renderview() method to render stuff in place, and when it is called with no arguments then it tells ColdBox to look for the view the controller set. That's it, then the framework assembles the final view for you. So let's look at a view that displays a query of users.
<h1>Users</h1>
<a href="#event.buildLink('users.add')#">Add User</a>
<ul>
<cfloop query="rc.qUsers">
<li>#rc.qUsers.name#</li>
</cfloop>
</ul>
The important question here is what's up with the rc scope? Well, ColdBox transports data from your event handlers (controller layer) down to the layouts/views by setting two variables for you to use implicitly (That means we do it for you):
- rc = A reference to the request collection structure.
- event = A reference to the event context object (coldbox.system.beans.RequestContext)
Then you can use any of these variables to display your data. We prefer you use the rc structure as access is faster and you basically are used to dealing with a structure. Just remember that the event object has some cool methods on it, like buildLink() which helps you create links between pages and also for form submits. Let's do a link to another event to create a user: users.add
<a href="#event.buildLink('users.add')#">Add User</a>
And that's it for simple mvc. So if you wanted to create a contact page for example, you can do this:
1. Add a contact.cfc event handler with an index() method that does event.setView("contact/index")
2. Add a view in the views folder called: contact/index.cfm and add stuff to it.
3. That's it, what you wanted more?
I hope that this simple MVC approach encourages those that have never done any development using an MVC framework. ColdBox in its roots is a very simplistic conventions based MVC framework. However, as your application grows and you have more needs, then you can tap into the ColdBox Platform for more tools and enterprisey stuff. So don't be afraid of an MVC framework, just give this template a shot, you will be surprised how quickly you can start putting things together. We even have an eclipse syntax dictionary that can help you introspect all the method functions for you to make things even easier!
Add Your Comment
(9)
Jul 22, 2009 23:05:23 UTC
by Henrik Joreteg
Yo Luis! While I enjoy the powerful configuration options I really think it's good that you wrote this. Sometimes people just want something up and working before they start to add too much complexity. Once they've got the basics it gives them confidence and lets them dig deeper and find all the other goodies in ColdBox. Nice work!
Jul 23, 2009 02:28:00 UTC
by Juerg Anderegg
beginners question, but that's what I see in many examples, and I'm a bit confused... What's the difference between
...
AND
...
I don't get this "instance"-Scope...
Jul 23, 2009 12:11:26 UTC
by Luis Majano
The instance scope is a scope that holds instance data. Ok, le t me rephrase. ColdFusion stores not only variables but the methods of a cfc in the THIS or VARIABLES scope. Therefore, if you dump the variables scope of a CFC, you get the data plus the methods. By creating a structure called instance in the variables scope you can safely clear the instance (properties) of a cfc without affecting its methods. This follows a design pattern called state pattern or memento. It is a best practice so you can very easily populate, replace or dump the state of an object very easily. Again, this makes sense on objects that contain state.
Jul 24, 2009 08:31:58 UTC
by Tony Garcia
"this makes sense on objects that contain state" Another way to say this is to use the "instance" scope (or structure) in transient objects (i.e. user.cfc, product.cfc, etc.), but not singletons (i.e. services, DAO's)
Jul 24, 2009 10:45:36 UTC
by Luis Majano
@tony, well, some services and singletons might also still use instance data, maybe for properties (dependencies), datasources, etc. As a best practice, I always have an instance scope on all my objects, whether I use it or not. I like this approach, because of the simplicity I get when I really need to see what is inside of an object without all the UDF's getting in the way
Jul 24, 2009 10:46:35 UTC
by Luis Majano
I also think that cf9 will change the scope on this a little, because by just defining cfproperties, we get implicit getters/setters, but at the end of the day, how can we dump the state of the object?
Jul 31, 2009 02:29:58 UTC
by Mark
Is this example not running under ColdBox 2.6.4 RENEWED ?
Jul 31, 2009 12:02:22 UTC
by Luis Majano
Yes just modify the config file to 2.6.4 standard
May 04, 2011 05:11:20 UTC
by Riddhi Bhavsar
Hello sir, I am working with ColdBox Sample available online. That examples are not working under the HTTPS server. Any Ideas?