WhatsNew:3.5.0
|
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
- ColdFusion 7 support
- Archive Cache implementations
- Custom JSON support in favor of ColdFusion functions for JSON
- Environment Control interceptor in favor of ConfigurationCFC
- Configuration of a ColdBox application via an XML file
- TransactionAspect in our ORM package in favor of WireBox-AOP
- StringBuffer plugin moved to ForgeBox
- BeanFactory compatibility mode removed
- SideBar interceptor removed from core and moved to ForgeBox
- Deploy interceptor removed from core and moved to http://www.coldbox.org/forgebox/view/deploy
- Setting flashURLPersistScope removed in favor of theFlash RAM configuration structure
- Setting ConfigAutoReload removed
- Autowire Interceptor has been deprecated in favor of WireBox and the ColdBox ORM Event Handler Entity Injector
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
- ColdBox now has its own Form and Object validation engine, validate in style!
- 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.
- New i18n locale storage for users: request (See ConfigurationCFC).
- 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.
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();
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. };
Categories:

SideBar
User Login 




Comments (