WhatsNew:3.5.0

<< Back to Dashboard

Contents

What's New With ColdBox 3.5.0

Introduction

ColdBox 3.5.0 is a minor/major release based on our 3.0.0 platform, but includes tons of removals and deprecations. The most important aspect of 3.5.0 is that it no longer supports ColdFusion 7. Incredibly, this allowed us to drop around 3 MB of compatibility source code and has helped make ColdBox a leaner, meaner, development machine.

Internal Library Updates

Compatibility

We have also prepared a compatibility guide to assist in upgrading to ColdBox 3.5.0 -> Compatibility:3.5.0

Removals-Migrations-Deprecations

ColdBox Fixes

  • Mark modules as activated=true once they are activated (ticket #1252)
  • When rendering entity fields using the HTMLHelper, it needed to consider "insert" and "update" fields for display purposes (ticket #1253)
  • Exception on array locations when removing module routes when autoreload is configured for SES interceptor (ticket #1254)
  • HTMLHelper entityfields not treating properties with formulas correctly (ticket #1256)
  • HTMLHelper cdata fixes on JavaScript (ticket #1275)
  • Exception bean throws an exception on the $toString method when extraInfo is complex, it serializes to JSON now to avoid this (ticket #1272)
  • View all

ColdBox Enhancements

  • The setting UDFLibraryFile can now be more than one template that can be mixed in to your handlers, layouts and views. It can be a list or an array of templates to mixin.
UDFLibraryFile = [ "/includes/helpers/AppHelper" , "/includes/helpers/CFCompat" ]
  • The interceptor service now exposes the method: registerInterceptionPoint() which allows for direct interceptor registration on specific listener points:
interceptorService.registerInterceptionPoint(key="myInterceptor",state="preProcess",interceptor=this)
  • Fine tuning of the internal services and boot strapper now that ColdFusion 7 support is dropped and compatibility code has been removed.
  • Internal configuration data is now a CFC instead of XML, which makes loading the framework much faster as no XML parsing is needed at boot time.
  • Enhanced the Request Context Decorator to delay its configuration, to prevent wirebox objects or IOC objects from creating endless loops.
  • Environment control has now been added to modules in their ModuleConfig.cfc. So the same conventions that are used in the parent configuration can be used in the module; having the name of the environment match a method name in your module config. So if the following environments are declared in your parent:
environments = {
  dev = "^railo.*,^cf.*,^local.*"
};

function dev(){
  // my overrides here
  coldbox.handlerCaching = false;
}

Then the same convention translates to the ModuleConfig.cfc, so you can also create a dev() function in the module.

function dev(){
  // my overrides here
  settings.moduleOverride = true;
}
  • setLayout() now allows for a 'module' argument, so you can specify a layout from a specific module and not just the parent application
event.setlayout(layout="admin", module="contentbox");
  • setView() now allows for a 'module' argument, so you can specify a view from a specific module and not just the parent application
event.setView(view="home/site", module="contentbox");
  • Added the ability to assign global asset paths to HTMLHelper.addAsset() via settings: htmlhelper_js_path, htmlhelper_css_path
// configuration
settings = {
	htmlhelper_js_path = "/includes/js/",
	htmlhelper_css_path = "/includes/css/"
};

// usage
html.addAsset("myJS.js,cool.js");
  • The getSetting() methods now get a new argument: defaultValue so you can get a default value back if the setting does not exist:
var mySetting = getSetting(name="MySetting",defaultValue="NA");
  • New rendering interception points: preLayoutRender and postLayoutRender. This will allow you to intercept right before ANY layout is rendered and after it gets rendered.
  • The ColdBox rendering engine can now be tweaked to use case-insensitive or sensitive implicit views by creating a coldbox setting called: caseSensitiveImplicitViews. You can also now completely disable implicit views with the setting ImplicitViews. The default is to turn all implicit views to lower case and for implicit views to be turned on:
coldbox = {
	implicitViews = false,
	caseSensitiveImplicitViews = true
};
  • New RequestContext method: noLayout() to tell the framework not render to a layout with the view:
event.noLayout();
  • Module Service now allows for the a-la-carte loading of modules in any location in the server via the following methods: registerAndActivateModule(moduleName,invocationPath) and registerModule(moduleName,invocationPath).
  • New debugger configuration key (See ConfigurationCFC): showRCSnapshots which defaults to false. You can enable it to see how the RC and PRC are transformed across the span of a request. A great debugging tool but slow to profile.
  • The security interceptor has a new element: match which can either be event (default) or url. This tells the rule to match against a ColdBox event or an incoming URL pattern. That's right! You can now secure ANY incoming URL pattern with the ColdBox security interceptor. Your very own personal firewall.
<rules>
    <rule>
        <whitelist>user\.login,user\.logout,^main.*</whitelist>
        <securelist>^user\..*, ^admin</securelist>
		<match>event</match>
        <roles>admin</roles>
		<permissions></permissions>
        <redirect>user.login</redirect>
		<useSSL>false</useSSL>
    </rule>
	<rule>
        <whitelist></whitelist>
        <securelist>^projects-beta</securelist>
		<match>url</match>
        <roles></roles>
		<permissions>beta_program</permissions>
        <redirect>user.login</redirect>
		<useSSL>false</useSSL>
    </rule>
</rules>

RenderData Enhancements

  • JSONP is now fully supported by event.renderData(). If you want to learn more about JSONP please visit the Wikipedia entry. In a nutshell, JSONP denotes that the JSON packet will be wrapped in a JavaScript callback function of your choice. You will do this by using the type="JSONP" and jsonCallback="mycallback"' arguments.
event.renderData(type="jsonp", data=data, jsonCallback="myCallback");
  • PDF is now fully supported by event.renderData(). You can now render out PDF's from ColdBox using the render data method. The data argument can be either the full binary of the PDF or simple values to be rendered out as a PDF.
// from binary
function pdf(event,rc,prc){
  var binary = fileReadAsBinary( file.path );
  event.renderData(data=binary,type="PDF");
}

// from content
function pdf(event,rc,prc){
  event.renderData(data=renderView("views/page"), type="PDF");
}

There is also a pdfArgs argument in the render data method that can take in a structure of name-value pairs that will be used in the cfdocument (See docs) tag when generating the PDF. This is a great way to pass in arguments to really control the way PDF's are generated uniformly.

// from content and with pdfArgs
function pdf(event,rc,prc){
  var pdfArgs = { bookmark = "yes", backgroundVisible = "yes", orientation="landscape" };
  event.renderData(data=renderView("views/page"), type="PDF", pdfArgs=pdfArgs);
}
  • event.renderdata() now also supports a custom data conversion convention when marshalling CFCs. If you pass in a CFC that has a method called $renderdata(), then the marshalling utility will call that function for you instead of using the internal JSON/XML/WDDX marshalling utilities. You can pass in the custom content type for encoding:
event.renderData(type="plain", data=myCFC, contentType="text");
component accessors="true"{

	property name="name";
	property name="age";
	property name="cool";
	
	function init(){ return this; }
	
	function config(name,age,cool){
		setName( arguments.name );
		setAge( arguments.age );
		setCool( arguments.cool );
		return this;
	}
	
	function $renderdata(){
		var d = {
			n = variables.name,
			a = variables.age,
			c = variables.cool,
			today = now()
		};
		
		return d.toString();
	}

}

In this approach your $renderdata() function can be much more customizable than our internal serializers. Just remember to use the right contentType argument.

Event Caching Enhancements

  • Event caching for renderdata has been expanded as it now saves the right headers and content types in which the original render data was called with. This will reproduce from cache the exact same headers and content type for the marshalled content. GREAT for RESTful web services.
  • Cached events now return an extra header: 203 Non-Auhoritative Information

SES Enhancements

We have done incredible strides in perfecting our already amazing URL rewriting engine. Here are the updates:

  • All void or set methods now return itself so methods can be concatenated for building a URL rewriting DSL

Including Routes

We have created a new method: includeRoutes( includePath ) that will allow you to load multiple configuration files on demand from anywhere in your application. This can easily help you manage tons of routes in a system.

includeRoutes('/config/mypackageRoutes')
.includeRoutes('/config/adminRoutes');

The modules routes array definition can now also contain simple values that are pointers to configuration files to load using the includeRoutes() method behind the scenes. So now you don't have to define all the routes in your module configuration object (ModuleConfig.cfc) but abstract them into their own routes configuraiton template files and you can do more than 1 of course.

routes = [
	"config/routes.cfm",
	"config/routes2.cfm"
	{pattern="/sample", handler="test", action="execute"}
];

This will load the routes.cfm and routes2.cfm templates in the module's config directory. The SES interceptor is smart enough to detect you want to include those routing templates and also knows they are located within the module.

Module includes are smart as they are treated as relative paths from the module root and also assign them to the module in question automatically for you.

With Closures

We have created some cool context methods to allow for the prefixing of any of the addRoute() arguments by using what we call with closures. This allows you to prefix repetitive patterns in route declarations. The best way to see how it works is by example:

addRoute(pattern="/news", handler="public.news", action="index");
addRoute(pattern="/news/recent", handler="public.news", action="recent");
addRoute(pattern="/news/removed", handler="public.news", action="removed");
addRoute(pattern="/news/add/:title", handler="public.news", action="add");
addRoute(pattern="/news/delete/:slug", handler="public.news", action="remove");
addRoute(pattern="/news/v/:slug", handler="public.news", action="view");

As you can see from the routes above, we have lots of repetitive code that we can clean out. So let's look at the same routes but using some nice with closures.

with(pattern="/news", handler="public.news")
	.addRoute(pattern="/", action="index")
	.addRoute(pattern="/recent", action="recent")
	.addRoute(pattern="/removed", action="removed")
	.addRoute(pattern="/add/:title",  action="add")
	.addRoute(pattern="/delete/:slug", action="remove")
	.addRoute(pattern="/v/:slug", action="view")
.endWith();

As you can see, we start our URL mapping DSL with the with() method and pass in any argument the addRoute() method declares. In this case we pass a pattern and a handler. Meaning any addRoutes() that are concatenated in the with closure will be prefixed with that pattern and handler. Once we concatenate the last addRoute(), then we finalize the closure with an .endWith(); demarcation. BOOM! The patterns look so much manageable and declarable.

The arguments you can use for prefixing are:

Argument Description
pattern The URL pattern prefix
handler The handler prefix
action The action prefix
matchVariables The match variables prefix
view The view prefix
constraints The constraints to prefix
module The module prefix
namespace The namespace prefix

Important : It is extremely important that you close the with closures with an endWith() call or all subsequent addRoutes() calls, will be using the last with closure you declared.

URL Mapping Namespaces

You can now create a-la-carte namespaces for URL routes. Namespaces are cool groupings of routes according to a specific URL entry point. So you can say that all URLs that start with /testing will be found in the testing namespace and it will iterate through the namespace routes until it matches one of them. Much how modules work, where you have a module entry point, now you can create virtual entry point to ANY route by namespacing it. This route can be a module a non-module, package, or whatever you like.

You start off by registering the namespace using our new addNamespace(pattern, namespace) method:

addNamespace(pattern="/testing", namespace="test");
addNamespace(pattern="/news", namespace="blog");

Once a namespace is registered you can add routes to it via the addRoute() method or the with() closure.

// Via addRoute
addNamespace(pattern="/news", namespace="blog")
	.addRoute(pattern="/",handler="blog",action="index",namespace="blog")
	.addRoute(pattern="/:year-numeric?/:month-numeric?/:day-numeric?",handler="blog",action="index",namespace="blog");

// Via with closure
addNamespace(pattern="/news", namespace="blog");
with(namespace="blog", handler="blog")
	.addRoute(pattern="/",action="index")
	.addRoute(pattern="/:year-numeric?/:month-numeric?/:day-numeric?",action="index");
.endWith();

You can also register multiple URL patterns that point to the same namespace

Collection Rendering

The collection rendering mechanisms have been updated to allow for two new arguments; to allow for capping the rows or records to be iterated through and to specify a start row.

  • collectionStartRow : Defaults to 1 or your offset row for the collection rendering
  • collectionMaxRows : Defaults to show all rows or you can cap the rendering display
#renderView(view="home/news", collection=prc.news, collectionStartRow=2, collectionMaxRows=10)#

Layout Helpers

Just like views, our layouts now can have layout helpers by convention. So let's say you have a layout called main.cfm and you create a mainHelper.cfm, ColdBox will assemble those two views together for you. This creates a nice separation between helper code like custom dynamic JavaScript, CF UDFs, etc from your main layout code.

/layouts
  + {name}.cfm (A layout)
  + {name}Helper.cfm (The helper template)

You can also create folders in your layouts and create a helper for the entire folder. So if you create a folder called admin and you place inside it a helper template called adminHelper.cfm, that template will be dynamically stitched together for you for any layout inside of the admin folder.

/layouts
  /admin
    + adminHelper.cfm
    + login.cfm
    + main.cfm

External Views Helpers

Just like views, our external views now can have helpers by convention. So let's say you have an external view called /myshared/views/main.cfm and you create a /myshared/views/mainHelper.cfm, ColdBox will assemble those two views together for you. This creates a nice separation between helper code like custom dynamic JavaScript, CF UDFs, etc from your main view code. External views are rendered via our renderExternalView() method.

/myshared
  /views
    + {name}.cfm (A layout)
    + {name}Helper.cfm (The helper template)

ORM Integration

  • Updated the Base ORM Service createCriteriaQuery to accept a new convention; if an array element is a simple value it denotes to create another association query via createCriteria() for association criteria queries (see Hibernate Association Criteria Queries).
  • We have a new ColdBox Hibernate Criteria Builder DSL, that will help you programmatically create HQL in an OO fashion.
  • The method executeQuery() now has a unique argument for retreiving a unique object
  • New method: getEntityGivenName(entity) to retrieve the name of the entity when you only have an instance of the entity.
  • New property: defaultAsQuery on the Base ORM Service and Virtual Entity Service so that you specify whether list(), createCriteriaQuery() and executeQuery() will return a query by default or an array of objects.
  • Migrated transactioning to native ColdFusion transactions.
  • Base ORM Service -> get() now has an explicit returnNew argument that enables the return of a new entity of the incoming id is 0 or not found
  • Multiple datasource support thanks to Mike McKellip is now available on all ORM methods that support it as a datasource argument.
  • New orm configuration structure that enables entity injection and future orm integrations. This is a compatibility item also as the Autowire interceptor has been deprecated.
orm = {
	injection = {
		// enable entity injection
		enabled = true,
		// a list of entity names to include in the injections
		include = "",
		// a list of entity names to exclude from injection
		exclude = ""
	}	
}

Flash RAM Updates

The Flash RAM has been considerably updated and you can now configure all of its operations at a granular level.

  • All previous void methods now return itself for cool concatenations
  • Auto-save of Flash RAM on request end is now automatic
  • You can now configure the Flash RAM via the new flash configuration structure in your ConfigurationCFC
Key Type Required Default Description
scope string or instantiation path false session Determines what scope to use for Flash RAM. The available aliases are: session, client, cluster, ColdboxCache or a custom instantiation path
properties struct false {} Properties that can be used inside the constructor of any Flash RAM implementation
inflateToRC boolean false true Whatever variables you put into the Flash RAM, they will also be inflated or copied into the request collection for you automatically.
inflateToPRC boolean false false Whatever variables you put into the Flash RAM, they will also be inflated or copied into the private request collection for you automatically
autoPurge boolean false true This is what makes the Flash RAM work, it cleans itself for you. Be careful when setting this to false as it then becomes your job to do the cleaning
autoSave boolean false true The Flash RAM saves itself at the end of requests and on relocations via setNextEvent(). If you do not want auto-saving, then turn it off and make sure you save manually
// flash scope configuration
flash = {
	scope = "session,client,cluster,ColdboxCache,or full path",
	properties = {}, // constructor properties for the flash scope implementation
	inflateToRC = true, // automatically inflate flash data into the RC scope
	inflateToPRC = false, // automatically inflate flash data into the PRC scope
	autoPurge = true, // automatically purge flash data for you
	autoSave = true // automatically save flash scopes at end of a request and on relocations.
};

category Categories:
 
Download in other Formats:
markup Markup | pdf PDF | html HTML | word Word

comments Comments (0)


ColdBox Book

book