ColdBox is an event-driven, convention based ColdFusion Development Platform. It provides a set of reusable code and tools that can be used to increase your development productivity, as well as a development standard for working in team environments. ColdBox is comprehensive and modular, which helps address most infrastructure concerns of typical ColdFusion applications.
In this guide you will have an overview of the main components of this Object Oriented Framework. Below are some good resources for you to read about design patterns and some object orientation goodness. Having some basic object oriented knowledge will help you tremendously during your initial stages of ColdBox development. However, if you are not an OO guru, no worries, the guides contained in this wiki will help you and take you to several learning paths of object orientation and software development. This is just an introductory guide, so you might encounter new terminology or features of the framework that you might have no clue about. I urge you to continue reading the guides in order to find a cohesive outlook of what is ColdBox.
Let's discuss some high level overviews of what ColdBox can bring to the application development table:
We are firm believers in developer education. We have over 30 step by step guides and over 550 pages worth of documentation right in this wiki. We believe that by empowering the user with knowledge, the adaptation rate will increase and the ability of the developer to find what they need will make their productivity increase.
Conventions over configurations is our motto. We get rid of verbosity of XML logic and use ColdFusion and a set of conventions for our applications. With ColdBox you can even define your own application layouts and conventions. This gives great flexibility to developers who are used to their own application layouts and conventions. Conventions are also used for registering events, interceptors, plugins and much more. The use of conventions over configurations is what makes ColdBox unique.
ColdBox doesn't rely on XML declarative logic where you have to define an event, what it does and where does it go. ColdBox is a conventions based framework that will let you program in ColdFusion to get things done. You basically expose methods on event handler CFC's (Controller Layer) by turning their access to public or remote. The framework then will auto-register the handler CFC's and now you are able to use the methods as ColdBox Events. So instead of working with a long and complex configuration file all the time, you are mostly working with ColdFusion code all the time, ColdBox is just an API.
ColdBox is built on the concepts of modular architecture and sports a wide array of best practices, tools and services to help you build applications using modules instead of a big monolithic application. Even the framework itself assembles its internal modules once your application loads up and only uses what you tell it to use. ColdBox can be as simple as just core MVC or complex enough to power mission critical enterprise applications.
We encourage you to build applications that can be organized around resources and standard HTTP verbs, especially for exposing services to multi-faceted applications. We have incredible URL mapping and RESTful support that will help you build not only MVC applications but also power any mobile application.
ColdBox comes bundled with an extensive set of plugins and interceptors that will help you on every day software application tasks like notifications, AOP file logging with auto-archiving, per-environment settings, storage facilities for cluster environments, object caching, datasource declarations, web services integrations, i18n, dependency injection, application security, and so much more. ColdBox is not only an MVC framework but a development platform.
ColdBox is a framework based on objects and Unit Testing is an integral part of development, then why shouldn't you be able to unit test your application in its entirety? We are tightly integrated with MXUnit to deliver different types of testing so you can test all of your development layers. Integration testing is core to ColdBox and you can test your entire application (top-down) without the need of a browser, from testing incoming FORM/URL variables to even browser headers and relocations. We even have our own mocking and stubbing framework, MockBox, that will be indispensable when doing isolation and unit testing.
The ColdBox proxy enables remote applications like Flex, AIR, AJAX, WSDL web services to communicate with ColdBox and provide an event model for your applications. You can create a Service Layer with built-in environmental settings, logging, error handling, event interception and chaining, you name it, and the possibilities are endless. This integration will provide you with the capability to create any amount of front ends using the same reusable ColdBox and model code.
We already mentioned that ColdBox is built modularly and here are the major libraries/frameworks that compose the ColdBox Platform. Please note that each of these libraries/frameworks are completely standalone and can be used with any other ColdFusion framework or ColdFusion application. The importance of these libraries are that they are decoupled from each other and you can pick, mix and match and use them in your applications as you see fit.
ColdBox uses both implicit and explicit invocation methods to execute events and render content; ColdBox is an event driven framework. You have one single configuration file: Coldbox.cfc, from where you can configure your entire application (No logic, just configuration data) and a set of folder conventions. This configuration file activates certain aspects of your application and configures all the implicit events that mostly reflect the events in the Application.cfc that ColdFusion exposes.
Remember that this framework will not solve all your problems. It is a standard, a foundation on which to develop on and thanks to its software programming aspects that it provides, this framework can also be a development toolkit. However, it is up to you to create GOOD code, this is not a magical framework that will make your code better. It will help you, but at the end of the day, it is your responsibility.
The core conventions delineate the contract between ColdBox and you for file/directory locations and more.
| Convention | Default Value | Required | Description |
|---|---|---|---|
| config file location | /config/Coldbox.cfc | true | The location of the application configuration file |
| handlers location | /handlers | true | Where all event handlers are located |
| layouts location | /layouts | false | Where all layouts are located |
| views location | /views | false | Where all views are located |
| plugins location | /plugins | false | Where all plugins are located |
| models location | /model | false | Where all model objects are located |
| modules location | /modules | false | Where all modules are located |
| default event action | index() | false | The name of the default event action (method) to use when an event handler is called with no method |
Above you will see the core conventions plus some extra files and folders:
| Folder/File | Required | Description |
|---|---|---|
| Application_noinheritance.cfc | false | The boostrap approach that uses non-inheritance (See Bootstrapper) |
| Application.cfc | true | Used to boostrap the framework application using inheritance (See Bootstrapper) |
| index.cfm | true | A placeholder file the framework needs for front controller operation. The file is usually empty. |
| includes | false | Where you can place static assets like (css,images,i18n,js,etc) |
| test | false | Where all your unit, mocks and integration tests go (Yes, you need to test!) |
As you can see from the diagram above, these are our major classes that you will be interacting with. The pivot class that is our core base class for anything ColdBox is the FrameworkSuperType class. All plugins, interceptors and event handlers internally inherit from the super type class, as they are part of the ColdBox family of objects. We also have build an awesome quick API docs application that can help you locate and method or any class: http://apidocs.coldbox.org. We would highly encourage you to bookmark this application.
Important: The FrameworkSuperType class is meant to be the base class for ColdBox related objects and NOT for domain layer objects.
All of the following property members exist in the object's variables scope for event handlers, interceptors and plugins.
| Property | Description |
|---|---|
| cacheBox | A reference to the CacheBox framework factory (coldbox.system.cache.CacheFactory) |
| controller | A reference to the application's ColdBox Controller (coldbox.system.web.Controller) |
| flash | A reference to the current configured Flash Object Implementation that inherits from the AbstractFlashScope AbstractFlashScope (derived coldbox.system.web.flash.AbstractFlashScope) |
| logBox | The reference to the LogBox library (coldbox.system.logging.LogBox) |
| log | A pre-configured LogBox Logger object for this specific class object (coldbox.system.logging.Logger) |
| wirebox | A reference to the WireBox object factory (coldbox.system.ioc.Injector) |
ColdBox makes use of the Front Controller design pattern as its means of operation while in MVC mode. This means that every request comes in through a single template, usually index.cfm. Once a request is received by the framework through this front controller, it will parse the request and re-direct appropriately to the correct event handler (controller).
The incoming URL, FORM and REMOTE variables are merged into a single structure that we call the request collection and since we love objects that collection is stored in an object called Request Context. We also create a secondary collection called the private request collection that cannot be affected by the outside world as nothing is merged into it. You can use it for private request variables and the like. The request context object has tons of methods to help you in setting and getting variables from one MVC layer to another, to getting request metadata, rendering RESTful content, setting HTTP headers and more. It is your information super highway for specific requests. Remember that the API Docs are your best friend!
Please see the application life cycle to understand the basics of ColdBox's request life cycles.
The way events are detected are via a URL/FORM or remote variable named by default event or by using the default SES URL Mapping routing techniques in ColdBox. This event variable holds a specific pattern that lets the framework know what controller to execute. This is called ColdBox event syntax:
NON SES MODE
index.cfm?event=[module:][handler|package].[action=index] // sample index.cfm?event=users.list index.cfm?event=package.users.list index.cfm?event=myModule:users.list
SES MODE
/index.cfm/{module}/{package}/{handler}/{action=index}
/{module}/{package}/{handler}/{action=index}
// sample
http://myapp.com/index.cfm/users/list
// Full rewrites activated
http://myapp.com/users/list
Once this is detected, our conventions kick in: The handler is the name of the event handler CFC and the action is the name of the public or remote method to execute. You can also pre-pend package/module names of where event handlers can be found. Please note that our recommendation is to use SES routing so you can create meaningful URI's and abstract out the real names of the handlers and locations. You can also see from the event syntax that index is the default action for any event handler CFC.
ColdBox Event handlers are CFC's that act as your application controllers. Most of this topic is covered in the Event Handlers Guide. Here is a brief introduction:
Here is a typical example of a simple event handler:
component{
// Inject a virtual coldbox service layer via ColdFusion ORM
property name="userService" inject="entityService:User";
function index(event,rc,prc){
// place a variable in the request collection
rc.welcome = "Hi and welcome!";
// set a view for rendering
event.setView("home/index");
}
function save(event,rc,prc){
// get a new user object and populate it from the incoming form
var user = populateModel( userService.new() );
// save it and relocate
userService.save( user );
// flash a message
flash.put("message","User saved!");
// relocate
setNextEvent("users.list");
}
}
All event handler methods receive the same three arguments:
ColdBox by convention can integrate (create, persist and wire) with your Model layer via our own dependency injection framework, WireBox, or you can use any other DI framework or none at all. All objects located in your model folder are available to your application with one method call or injection:
// get object myService = getModel("MyService"); // injected object property name="myService" inject="model";
ColdBox will enable you to create simple or enterprise ready model layers. We also give you the ability to easily integrate with ColdFusion ORM via our virtual and base service layers or our ActiveEntity approach that simulates the Active Record pattern using ColdFusion ORM. We also have our own Hibernate extensions that help you do incredible Object Oriented queries on ORM objects and their relationships using our ColdBox Hibernate Criteria Builder. Here is a taste of what you can do with our ORM integrations:
/** * A cool User entity */ component persistent="true" table="users" extends="coldbox.system.orm.hibernate.ActiveEntity"{ // Primary Key property name="userID" fieldtype="id" column="userID" generator="native"; // Properties property name="firstName" ormtype="string"; property name="lastName" ormtype="string"; property name="email" ormtype="string"; property name="username" ormtype="string"; property name="password" ormtype="string"; property name="age" ormtype="integer"; }
component{
function index(event,rc,prc){
var user = entityNew("User");
prc.usersFound = user.count();
prc.users = user.list(sortOrder="lastName");
event.setView("users/index");
}
function search(event,rc,prc){
rc.searchTerm = getPlugin("AntiSamy").clean( rc.searchTerm );
var criteria = entityNew("User").newCriteria();
prc.users = criteria.or( criteria.restrictions.like("firstName","%#rc.searchTerm#%"),
criteria.restrictions.like("lastName", "%#rc.searchTerm#%") ).list(max=20);
event.setView("users/search");
}
function edit(event,rc,prc){
prc.user = entityNew("User").get( rc.userID );
event.setView("users/edit");
}
function save(event,rc,prc){
var user = populateModel( entityNew("User").get( rc.userID ) );
user.save();
setNextEvent("users.list");
}
function remove(event,rc,prc){
entityNew("User").deleteByID( rc.userID );
setNextEvent("users.list");
}
}
component{
property name="userService" inject="entityService:User";
function index(event,rc,prc){
prc.usersFound = userService.count();
prc.users = userService.list(sortOrder="lastName");
event.setView("users/index");
}
function search(event,rc,prc){
rc.searchTerm = getPlugin("AntiSamy").clean( rc.searchTerm );
var criteria = userService.newCriteria();
prc.users = criteria.or( criteria.restrictions.like("firstName","%#rc.searchTerm#%"),
criteria.restrictions.like("lastName", "%#rc.searchTerm#%") ).list(max=20);
event.setView("users/search");
}
function edit(event,rc,prc){
prc.user = userService.get( rc.userID );
event.setView("users/edit");
}
function save(event,rc,prc){
var user = populateModel( userService.get( rc.userID ) );
userService.save( user );
setNextEvent("users.list");
}
function remove(event,rc,prc){
userService.deleteByID( rc.userID );
setNextEvent("users.list");
}
}
ColdBox sports its own awesome FORM and object validation engine that we call: ValidBox. It allows you to define a set of constraints for form elements or object properties that will be evaluated in your handlers via a method called validateModel(). Here is an example of our previous model object with validation data:
/** * A cool User entity */ component persistent="true" table="users" extends="coldbox.system.orm.hibernate.ActiveEntity"{ // Primary Key property name="userID" fieldtype="id" column="userID" generator="native"; // Properties property name="firstName" ormtype="string"; property name="lastName" ormtype="string"; property name="email" ormtype="string"; property name="username" ormtype="string"; property name="password" ormtype="string"; property name="age" ormtype="integer"; // Validation this.constraints = { firstName = { required = true }, lastName = { required = true}, username = {required=true, size=6..10}, password = {required=true, size=6..8}, email = {required=true, type="email"}, age = {required=true, type="numeric", min=18} }; }
Then you can validate them really easily:
component{
function save(event,rc,prc){
// create and populate a user object from an incoming form
var user = populateModel( entityNew("User") );
// validate model
prc.validationResults = validateModel( user );
// check for errors?
if( prc.validationResults.hasErrors() ){
// Use a cool MessageBox plugin to render out the validation messages in the UI
getPlugin("MessageBox").error(messageArray=prc.validationResults.getAllErrors() );
// Present the editor form for correction of validation
return edit(event,rc,prc);
}
else{
// save the user
user.save();
setNextEvent('users.list');
}
}
}
or if you use ActiveEntity the entity can validate itself:
component{
function save(event,rc,prc){
// create and populate a user object from an incoming form
var user = entityNew("User").populate( rc );
// validate model
if( !user.isValid() ){
// Use a cool MessageBox plugin to render out the validation messages in the UI
getPlugin("MessageBox").error(messageArray=user.getValidationResults().getAllErrors() );
// Present the editor form for correction of validation
return edit(event,rc,prc);
}
else{
// save the user
user.save();
setNextEvent('users.list');
}
}
}
ColdBox has a fantastic layout manager that can help you create tons of skins, layouts for different devices and so much more in pure CFML. You can have inside of your layouts multiple rendering regions for widgets or content variables or inline renderings, or even rendering other layouts in specific locations. It is a incredibly powerful feature!
Sample Layout
<cfoutput> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> #renderView('tags/metatags')# <title>Welcome to Coldbox!!</title> </head> <body> <div id="sidebar">#runEvent('viewlets.sidebar')#</div> <div id="mainContent"> #renderView()# </div> <div id="footer">#renderView('tags/footer')#</div> </body> </html> </cfoutput>
Sample View
<cfoutput> <div>ColdBox Says: #rc.welcome#</div> #html.href(href="#event.getCurrentEvent()#", text=html.button(value="Refresh"))# </cfoutput>
All layouts and views have several different variables and objects available in the variables scope:
ColdBox provides you with a utility method called renderData() located in the event object (request context) that can be used from your event handlers. This method will provide you with the ability to render data back to the browser or to a remote caller without rendering or creating views. The framework will take care of marshalling (converting) the data for you and return it back. This is an incredible tool to use when doing AJAX or remote interactions from flex or air or when building RESTful web services
Out of the box ColdBox can marshall data (structs, views, queries, arrays, complex or even ORM entities) into the following output formats:
ColdBox even helps you detect incoming extensions and creates a variable called format for you. So if you have a URL like this:
http://myapp/users/list.json
It will detect the extension and create a format=json so you can respond to it.
component{
// HTTP Method Security
this.allowedMethods = {
list = "GET", save = "POST,PUT", delete = "DELETE"
};
// restful handler
function list(event,rc,prc){
event.paramValue("format","html");
prc.data = userService.list();
switch(rc.format){
case "json": "jsont" : "xml" {
event.renderData(type=rc.format, data=rc.data);
break;
}
case "pdf" : {
event.renderData(type="pdf", data=renderView("users/list") );
break;
}
default: {
event.setView("users/list");
}
}
}
}
Another important ColdBox feature is the use of a plugin library of CFC's that extend the normal usage of ColdBox to application specific tasks but without hindering system performance. These plugins can be any CFC that's placed in the plugins folder convention of your application or part of the ColdBox core. Every ColdBox installation comes with a rich set of plugins that will help you build and maintain your applications.
ColdBox Modules are self-contained subsets of a ColdBox application that can be dropped in to any ColdBox application and become alive as part of the host application. They will bring re-usability and extensibility to any ColdBox application, as now you can break them down further into a collection of modules. This concept has been around in software design for a long time as it is always essential to partition a system into manageable modules or parts. ColdBox Modules will change the way you approach application development as you can now have a foundation architecture that can scale easily and provide you enough manageability to reduce maintenance and increase development. Such a design means that development, testing and maintenance becomes easier, faster and with a much lower cost. Welcome to a brave new world!
ColdBox interceptors increase functionality for applications and framework alike, without touching the core functionality, and thus encapsulating logic into separate objects. This pattern wraps itself around a request in specific execution points in which it can process, pre-process, post-process and redirect requests. These interceptors can also be stacked to form interceptor chains that can be executed implicitly. These stacked interceptor chains form a chain of separate, declaratively-deployable services to an existing web application or framework without incurring any changes to the main application or framework source code. Welcome to the world of event-driven architectures.
However, we went a step further with ColdBox interceptors and created the hooks necessary in order to implement an event-driven programming pattern into the entire interceptor service. Ok ok, what does this mean? It means, that you are not restricted to the pre-defined interception points that ColdBox provides, you can create your own WOW! Really? Yes, you can very easily declare execution points via the configuration file or register at runtime, create your interceptors with the execution point you declared (Conventions baby!!) and then just announce interceptions in your code via the interception API.
I hope that this overview gave you an insight into how powerful ColdBox is for building your web applications. It is a new generation framework based on conventions that will increase your productivity and adaptability in a team environment. Welcome to the ColdBox Platform!