Blog

Luis Majano

January 08, 2018

Spread the word


Share your thoughts

 

It is finally here! ColdBox 5 RC1 has landed with force! There are so many things to talk about, but we will focus on what RC brings and all the eco-system updates we have been working on. So let's begin this adventure.

Installation

In order to get started with the RC you can install it via CommandBox: install coldbox@5.0.0-rc.1. Also, if you want to work with the bleeding edge as we fix any issues with the RC you can just use the be tag: install coldbox@ be. This will give you the latest 5.0 bits as work progresses for final release.

Docs, Docs and More Docs!

We have reworked almost our entire suite of Docs for the ColdBox core. There are still pieces missing, but we are right on target for a full documentation overhaul. We now have two entry points to our documentation:

  • Intro Docs - The Intro docs are a bite-sized version of the ColdBox docs that will help newbies to get started with an MVC framework like ColdBox. No more scary docs! You can go over the intro docs in less than 30 minutes and have a fully RESTFul MVC application running by the end. Read Now!
  • Full Docs - The full docs includes the full ColdBox documentation but now in a more concise and less verbose organizational format. This is still a work in progress, but we hope you will find this new approach more consumable than before. Read Now!
  • Modern CFML in 100 Minutes - Not only that, but our new book to teach modern ColdFusion (CFML) in 100 minutes is now almost complete. So you can onboard new developers to ColdFusion (CFML) and then teach them MVC with ColdBox. Read Now

What's New and Upgrade Guide

Please follow the following links for the in-depth guides on what's new with ColdBox 5 and how to upgrade to ColdBox 5.

Global Versioning

All internal libraries have now a standard version according the the major ColdBox release of 5.0.0. Further releases of WireBox, CacheBox and LogBox will adhere to the unified version.

Engine Deprecation

It is also yet another source code reduction due to the dropping of support for the following CFML Engines:

  • Adobe ColdFusion 9
  • Adobe ColdFusion 10

That's right, you will need Adobe ColdFusion 11+ or Lucee 4.5+ in order to work with ColdBox 5.

Automation

We have fully automated all build processes with ColdBox 5 to include CommandBox and TestBox testing, Travis integration and a fully automated test suite that executes against ALL supported CFML engines. Our code coverage has increased due to this work dramatically. We discovered engine bugs that must have plagued our users for years. YAY for testing!

Performance Improvements & Optimizations

As we update core files we keep optimizing the source code and migrating to full cfscript and more functional programming techniques. This migration has allowed us to optimize very old code into modern times with significant performance gains. We have also moved from internal Java reflection to get file information to native CFML functions since now all engines support it. Just this alone has improved vanilla requests tremendously.

WireBox object creation and manipulation has also increased due to new locking strategies in our Mixer Util. You will especially see the difference when creating many transient objects. In the next release candidate or final version you will also see improved performance due to elimination of instance scopes and no scope-cascading lookups.

Lucee Full Null Support

Thanks to the community we have now full null support for the Lucee CFML engine and up-coming Adobe 2018.

Core Framework Exception Handling

The core framework has been revised with a fine tooth comb to provide better exception messages, better helpful messages and also the ability to intercept exceptions at the framework level via normal exception handlers. You will also see that ColdBox can detect response headers now and make sure it can avoid caching exceptions when event caching is turned on. The appropriate status code will now be reported.

You will also find in the log files attempts to reinit the framework with invalid or missing passwords.

Containers + Environments Support

ColdBox introduces two new methods that are available for your ColdBox.cfc and your ModuleConfig.cfc objects:

  • getSystemProperty( name, defaultValue ) - Retrieve a Java System property
  • getSystemSetting( name, defaultValue ) - Discover an environment variable either by searching system properties first and then system environment variables second.

Hint These methods are also found in the ColdBox core utility object: coldbox.system.core.util.Util which can be injected anywhere it is needed.

These methods will allow you to interact with docker environment variables and override settings, add new settings, and much more.

Modules, Modules and more Modules

We continue to innovate in the Hierarchical MVC (HMVC) design of ColdBox by fine-tuning the modular services and interactions. Here are the major updates to modules in ColdBox 5.

  • All module interceptors are now namespaced to avoid name conflicts with other modules
  • New modules injected variable: coldboxVersion to be able to quickly detect what version of ColdBox they are running under. This will allow you to create modules that can respond to multiple ColdBox versions.

Inherited Entry Point

All modules have had a URL entry point since the beginning: this.entryPoint = "/route". This entry point is registered in the URL mappings to allow for a unique URL pattern to exist for specific modules. That is great! However, in modern times and with the amount of API centric applications that we are building we wanted to introduce an easier way to build resource centric APIs.

What if our resource URLs could match by convention our module inceptions? Well, with the new inherited entry points, you can do just that. By leveraging HMVC and module inception you can now create automatic URL nesting schemas.

You can turn this on just by adding the following flag in your ModuleConfig.cfc:

this.inheritEntryPoint = true

When the module is registered it will recurse its parent tree and discover all parent entry points and assemble the entry point accordingly. Let's see an example. We are working on an API and we want to create the following URL resource: /api/v1/users. We can leverage HVMC and create the following modular structure:

+ modules_app
+ api
+ modules_app
+ v1
+ modules_app
+ users

This models our URL resource modularly. We can now go into each of the module's ModuleConfig and add only the appropriate URL pattern and turn on inherit entry point.

api - this.entryPoint = /api
v1 - this.entryPoint = /v1
users - this.entryPoint = /users

This feature will not only help you identify API routing, but help you build with modularity in mind. You will also find a new method in the request context called getModuleEntryPoint() to retrieve a modules inherited entry point, which is great for URL building.

New Module Events

You can now listen to more events of the module life-cycle:

  • preModuleRegistration - before each module is registered
  • postModuleRegistration - after each module is registered
  • afterModuleRegistrations - This will fire when all modules have been registered. This is great if you want modules to dynamically depend on each other.
  • afterModuleActivations - This will fire when all modules have been succesfully activated. Great for caching updates, announcements, etc.

Modules_app convention for inception

We have now added the modules_app convention for all module inceptions.

Default Model Export Convention

If you create a module where there is a model with the same name, then we will automatically map it in Wirebox as @modulename.

cors = getInstance( "@cors" )

This is great for 1 model modules.

Routing Enhancements

We continue to push forward in making ColdBox the best RESTFul framework for ColdFusion (CFML). In ColdBox 5 we have great new additions for both routing and rendering.

Simplified URL Rewrites

The SES interceptor now has a boolean flag to denote if rewrites are turned on/off and you will no longer set a base URL. We will automatically detect the base URLs according to multi-domain hosting. Meaning you can out of the box create multi-tenant applications with ease. We will also be adding subdomain routing in our final release.

setFullRewrites( true ); // defaults to false.

Named Routes

This has been a long-time coming to ColdBox and I can't believe we had never added this before. Well, named routes are here, finally!

If you have used other frameworks in other languages, they allow you to name your routes so you can build links to them in an easier manner. We have done just the same. The addRoute() method accepts the name parameter and we have extended the request context with some new methods:

  • getCurrentRouteName() - Gives you the name of the current route, if any
  • route() - Allows you to build URLs according to named routes

Define the Route

// Create a named route
addRoute(
pattern = "/user/:username/:page",
name = "user_detail"
);

// Same for modules
routes = [

{
pattern = "/detail/:username/:page",
name = "user_detail"
}
];

Build Links

User Details

The route method signature can be seen below:

/**
* Builds links to named routes with or without parameters. If the named route is not found, this method will throw an `InvalidArgumentException`.
* If you need a route from a module then append the module address: `@moduleName` in order to find the right route.
*
* @name The name of the route
* @params The parameters of the route to replace
* @ssl Turn SSL on/off or detect it by default
*
* @throws InvalidArgumentException
*/
string function route( required name, struct params={}, boolean ssl )

Resourceful Routes

In ColdBox 5, you can register resourceful routes to provide automatic mappings between HTTP verbs and URLs to event handlers and actions by convention. By convention, all resources map to a handler with the same name or they can be customized if needed. This allows for a standardized convention when building routed applications.

You will now have a new resources() method in the SES interceptor or a resources struct in your modules. Yes, all modules can have their own resourceful routes as well.

// Creates all resources that point to a photos event handler by convention
resources( "photos" );

// Register multiple resources either as strings or arrays
resources( "photos,users,contacts" )
resources( [ "photos" , "users", "contacts" ] );

// Register multiple fluently
resources( "photos" )
.resources( "users" )
.resources( "contacts" );

// Creates all resources to the event handler of choice instead of convention
resources( route="photos", handler="MyPhotoHandler" );

// All resources in a module
resources( route="photos", handler="photos", module="api" );

// Resources in a ModuleConfig
resources = [
{ resource="photos" },
{ resource="users", handler="user" }
];

This single resource declaration will create all the necessary variations of URL patterns and HTTP Verbs to actions to handle the resource. It will even create named routes for you.

For in-depth usage of the resources() method, let's investigate the API Signature:

/**
* Create all RESTful routes for a resource. It will provide automagic mappings between HTTP verbs and URLs to event handlers and actions.
* By convention, the name of the resource maps to the name of the event handler.
* Example: `resource = photos` Then we will create the following routes:
* - `/photos` : `GET` -> `photos.index` Display a list of photos
* - `/photos/new` : `GET` -> `photos.new` Returns an HTML form for creating a new photo
* - `/photos` : `POST` -> `photos.create` Create a new photo
* - `/photos/:id` : `GET` -> `photos.show` Display a specific photo
* - `/photos/:id/edit` : `GET` -> `photos.edit` Return an HTML form for editing a photo
* - `/photos/:id` : `POST/PUT/PATCH` -> `photos.update` Update a specific photo
* - `/photos/:id` : `DELETE` -> `photos.delete` Delete a specific photo
*
* @resource The name of a single resource or a list of resources or an array of resources
* @handler The handler for the route. Defaults to the resource name.
* @parameterName The name of the id/parameter for the resource. Defaults to `id`.
* @only Limit routes created with only this list or array of actions, e.g. "index,show"
* @except Exclude routes with an except list or array of actions, e.g. "show"
* @module If passed, the module these resources will be attached to.
* @namespace If passed, the namespace these resources will be attached to.
*/
function resources(
required resource,
handler=arguments.resource,
parameterName="id",
only=[],
except=[],
string module="",
string namespace=""
)

Event Execution

We have also done several update for event executions, event caching and overall MVC operations:

  • You can now return the event object from event handlers and the framework will not fail. It will be ignored.
  • setNextEvent() is now deprecated in favor of a relocate() method.
  • Request context has a getOnly( keys, private=false ) method to allow for retrieval of certain keys only from the public or private request contexts. Great for functional programming.

Event Caching Enhancements

Dynamic Cache Suffix

You can now leverage the cache suffix property in handlers to be declared as a closure so it can be evaluated at runtime instead of a static prefix.

this.EVENT_CACHE_SUFFIX = function( eventHandlerBean ){
return "a localized string, etc";
};

With this ability you can enable dynamic cache suffixes according to runtime environments on a per user basis.

Cache Provider Annotations

You can now add a cacheProvider annotation to your cache enabled functions and decide to what CacheBox provider the output will be cached too instead of the default provider of template:

function index( event, rc, prc ) cache=true cacheProvider=couchbase{

}

Rendering Enhancements

We have also done tremendous updates to the rendering engines in ColdBox 5, especially for RESTFul responses and content negotiation.

  • ColdBox now detects the rc.format not only to incoming URL extensions, but also via the Accept Header as content-negotiation.
  • New interception point afterRenderInit which will allow you to add your own injections to the main ColdBox renderer and modify the renderer at runtime.
  • The request context can now deliver files to users via our sendFile() method.d

Native JSON Responses + Handler Auto-Marshalling

JSON is the native response now for event handlers that return complex variables.

function data( event, rc, prc ){
return [1,2,3];
}

function data( event, rc, prc ){
return myservice.getQuery();
}

That's it! If you return a complex variable from an event handler, ColdBox will convert it to JSON for you automatically. We will even inspect the return object and if it has a $renderdata() method, we will call it for you and return your very own marshalled data! But there's more. You can add a renderData annotation to your action and add any valid renderdata() type and it will return it accordingly.

function data( event, rc, prc ) renderdata="xml"{
return [1,2,3];
}

function data( event, rc, prc ) renderdata="pdf"{
event.setView( "users/index" );
}

You can even add a default response type by adding the renderdata annotation to the component construct:

component renderdata="json"{

}

Named Regions

We have introduced the concept of named rendering regions with ColdBox 5. As we increase the reuse of views and create many self-sufficient views or widgets, we end up with setView() or renderView() method calls that expose too much logic, location, parameters, etc. With named regions, we can actually abstract or describe how a region should be rendered and then render it when we need it via a name.

Definition

event.setView(
view = "users/detail",
args = { data = userData, border = false },
layout = "main",
name = "userDetail"
);

event.setView(
view = "users/banner",
args = { data = userData },
name = "userBanner"
);

Rendering



#renderView( name="userDetail" )#

Testing Enhancements

Here are some of the major updates for integration testing with ColdBox and TestBox:

  • Reset the response when calling setup() in integration testing to avoid duplicate headers within same request executions.
  • Base test case doesn't allow for inherited annotations. Now it does since we moved the testing life-cycle methods to annotation based instead of by name.
  • Added dynamic methods getRenderData() and getStatusCode() helpers to the request context upon execute() execution. This will allow you a shorthand approach to getting response status codes and response rendering data struct.

Add Your Comment

(6)

Jan 08, 2018 15:15:45 UTC

by Francesco

This is great!!!

Jan 08, 2018 18:54:21 UTC

by Cory Silva

We appreciate all the hard work! I am going to love these new features and with null support coming CFML will be relevant again!

Jan 09, 2018 07:08:16 UTC

by Animesh Dtta

Happy New Year

Jan 09, 2018 07:18:04 UTC

by Animesh Dutta

I have earlier used ColdBox with the combination of Adobe ColdFusion? Now is it possible to use ColdBox 5 with Lucee? I am new to Lucee ?

Jan 10, 2018 14:12:22 UTC

by Brad Wood

Hi Animesh, ColdBox has always worked with Lucee (and Railo)!! We work very hard to maintain compatibility and have a Travis CI build that tests every ColdBox commit against all supported versions of Adobe ColdFusion and Lucee server. All of our Ortus sites run Lucee, including this very blog.

Jan 12, 2018 04:10:50 UTC

by David Sedeño

Great news! we could try to migrate our site to Coldbox with the Lucee full null support. Thanks for the great work!

Recent Entries

Why BoxLang When You Have Kotlin, Groovy, Scala, and more…

Why BoxLang When You Have Kotlin, Groovy, Scala, and more…

As we approach a stable release of BoxLang and our continued marketing reaches more folks, many have asked about its purpose. Why create a new language when the JVM ecosystem already includes established languages like Kotlin, Groovy, and Scala, to name a few.

Luis Majano
Luis Majano
December 18, 2024
ColdBox Free Tip 6 - Using Routing with Wildcard Domains!

ColdBox Free Tip 6 - Using Routing with Wildcard Domains!

ColdBox gives you the flexibility to create domain-specific routes, making it perfect for multi-tenant applications or projects that need to respond differently based on the domain or subdomain being accessed. In this tip, we’ll dive into how to use the withDomain() method to create routes that match specific domains or sub-domains.

Maria Jose Herrera
Maria Jose Herrera
December 18, 2024