Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 259 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

8.x

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

For Newbies

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Getting Started

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

The Basics

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Settings

These are custom application settings that you can leverage in your application.

// Custom Settings
settings = {
    useSkins = true,
    myCoolArray = [1,2,3,4],
    skinsPath = "views/skins",
    myUtil = createObject("component","#appmapping#.model.util.MyUtility")
};

You can read our Using Settings section to discover how to use all the settings in your application.

Conventions

This element defines custom conventions for your application. By default, the framework has a default set of conventions that you need to adhere too. However, if you would like to implement your own conventions for a specific application, you can use this setting, otherwise do not declare it:

//Conventions
conventions = {
    handlersLocation = "controllers",
    viewsLocation      = "views",
    layoutsLocation  = "views",
    modelsLocation      = "model",
    modulesLocation  = "modules",
    eventAction      = "index"
};

InterceptorSettings

This structure configures the interceptor service in your application.

//Interceptor Settings
interceptorSettings = {
    throwOnInvalidStates = false,
    customInterceptionPoints = "onLogin,onWikiTranslation,onAppClose"
};

throwOnInvalidStates

This tells the interceptor service to throw an exception if the state announced for interception is not valid or does not exist. Defaults to false.

customInterceptionPoints

This key is a comma delimited list or an array of custom interception points you will be registering for custom announcements in your application. This is the way to provide an observer-observable pattern to your applications.

Info Please see the section for more information.

What is ColdBox

ColdBox is a conventions-based HMVC web development framework for BoxLang and ColdFusion (CFML) that provides structure, scalability, and powerful features for modern application development.

ColdBox is a conventions-based MVC framework for ColdFusion (CFML). It is fast, scalable, and runs on CFML engines such as Adobe ColdFusion and the open source CFML engine , for a completely free and open source development stack. ColdBox itself is Professional Open Source Software, backed by which provides support, training, architecture, consulting and commercial additions.

ColdBox was the first ColdFusion (CFML) framework to embrace Conventions Over Configuration and comes with a modular architecture to enhance developer and team productivity. It integrates seamlessly with CLI to provide you with REPL interfaces, package management, console development, testing, and automation.

Hereโ€™s a look at some of the core components of the ColdBox platform. Each of these come bundled with the framework, but are also available as separate stand-alone libraries that can be used in ANY ColdFusion application or framework:

60 Minute Quick Start

A 60 minute guide to start working with ColdBox

This guide has been designed to get you started with ColdBox in fewer than 60 minutes. We will take you by the hand and help you build a RESTFul application in 60 minutes or less. After you complete this guide, we encourage you to move on to the and then to the other guides in this book.

You can find the source code of this quickstart here:

Requirements

Release History

All the major information about ColdBox Releases

Versioning Schema

ColdBox is maintained under the guidelines as much as possible. Releases will be numbered in the following format:

And constructed with the following guidelines:

  • Breaking backward compatibility bumps the major (and resets the minor and patch)

Contributing Guide

The best way to contribute to ColdBox

Hola amigo! I'm excited that you are interested in contributing to ColdBox, CacheBox, LogBox, and/or WireBox. Before submitting your contribution, please make sure to take a moment and read through the following guidelines:

Code Of Conduct

This project is open source, and as such, the maintainers give their free time to build and maintain the source code held within. They make the code freely available in the hope that it will be of use to other developers and/or businesses. Please be considerate towards maintainers when raising issues or presenting pull requests. We all follow the Golden Rule: Do to others as you want them to do to you.

About This Book

Learn about the authors of ColdBox and how to support the project.

The source code for this book is hosted on GitHub: . You can freely contribute to it and submit pull requests. The contents of this book are copyrighted by and cannot be altered or reproduced without the author's consent. All content is provided "As-Is" and can be freely distributed.

  • The majority of code examples in this book are done in cfscript.

  • The majority of code generation and running of examples are done via CommandBox: The ColdFusion (CFML) CLI, Package Manager, REPL -

Configuration

Learn how to configure ColdBox programmatically via config/ColdBox.cfc. Understand conventions over configuration and fine-grained control settings.

In this area we will learn how to configure ColdBox programmatically via the config/ColdBox.cfc file. Most of the configurations in ColdBox are pre-set thanks to it's conventions over configuration approach. So the majority of settings are for fine-grained control, third-party modules and more.

ColdBox relies on conventions instead of configurations.

Next Steps

Congratulations! Did you finish this guide in less than 60 minutes? If you did, please leave us some great feedback below. If you didn't, please tell us why; we would love to improve our guides.

You can now move on to the next level in becoming a ColdBox Guru! Choose your path below:

WireBox

This configuration structure is used to configure the dependency injection framework embedded in ColdBox.

binder

The location of the WireBox configuration binder to use for the application. If empty, we will use the binder in the config folder called by conventions: WireBox.cfc

singletonReload

A great flag for development. If enabled, WireBox will flush its singleton objects on every request so you can develop without any headaches of reloading.

Warning : This operation can cause some thread issues and it is only meant for development. Use at your own risk.

Interceptors

This is an array of interceptor definitions that you will use to register in your application. The key about this array is that ORDER matters. The interceptors will fire in the order that you register them whenever their interception points are announced, so please watch out for this caveat. Each array element is a structure that describes what interceptor to register.

Warning : Important: Order of declaration matters! Also, when declaring multiple instances of the same CFC (interceptor), make sure you use the name attribute in order to distinguish them. If not, only one will be registered (the last one declared).

Layouts

The layouts array element is used to define implicit associations between layouts and views/folders, this does not mean that you need to register ALL your layouts. This is a convenience for pairing them, we are in a conventions framework remember.

Before any renderings occur or lookups, the framework will check this array of associations to try and match in what layout a view should be rendered in. It is also used to create aliases for layouts so you can use aliases in your code instead of the real file name and locations.

Modules

The modules structure is used to configure the behavior of the .

Danger Please be very careful when using the autoReload flag as module routing can be impaired and thread consistency will also suffer. This is PURELY a development flag that you can use at your own risk.

LayoutSettings

This structure allows you to define a system-wide default layout and view.

Hint Please remember that the default layout is Main.cfm

HTML Base Tag

The base tag in HTML allows you to tell the browser what is the base URL for assets in your application. This is something that is always missed when using frameworks that enable routing.

base tag defines the base location for links on a page. Relative links within a document (such as <a href="someplace.html"... or <img src="someimage.jpg"... ) will become relative to the URI specified in the base tag. The base tag must go inside the head element.

We definitely recommend using this HTML tag reference as it will simplify your asset retrievals.

Interceptors
Learn about Caching
  • Learn about Logging

  • Learn about Testing

  • Getting Help

    If you run into issues or have questions, please jump on our community forum or our Slack team and ask away.

    ColdBox is Professional Open Source under the Apache 2.0 license. We'd love to have your help with the product.

    Learn about HMVC via ColdBox Modules
    Learn about Dependency Injection
    // wirebox integration
    wirebox = {
        binder = 'config.WireBox',
        singletonReload = true
    };
    WireBox
    //Register interceptors as an array, we need order
    interceptors = [
    
        { 
            // The CFC instantiation path
            class="",
            // The alias to register in WireBox, if not defined it uses the name of the CFC
            name="",
            // A struct of data to configure the interceptor with.
            properties={}
        }
    
        { class="mypath.MyInterceptor",
          name="MyInterceptor",
          properties={useSetterInjection=false}
        }
    ];
    //Register Layouts
    layouts = [
        { 
            // The alias of a layout
            name="",
            // The layout file
            file="",
            // A list of view names to render within this layout
            views="",
            // A list of regex names to match a view
            folders=""
        }
    
        // Examples
        { name="tester",file="Layout.tester.cfm",views="vwLogin,test",folders="tags,pdf/single"    },
        { name="login",file="Login.cfm",folders="^admin/security"}
    ];
    modules = {
        // Will auto reload the modules in each request. Great for development but can cause some loading/re-loading issues
        autoReload = true,
        // An array of modules to load ONLY
        include = [],
        // An array of modules to EXCLUDE for operation
        exclude = [ "paidModule1", "paidModule2" ]
    };
    ColdBox Modules
    //Layout Settings
    layoutSettings = {
        // The default layout to use if NOT defined in a request
        defaultLayout = "Main",
        // The default view to use to render if NOT defined in a request
        defaultView   = "youForgot"
    };

    Caution If you do not use this tag, then every asset reference must be an absolute URL reference.

    <base href="#event.getHTMLBaseURL()#">

    Routing Namespaces

    You can 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, 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 the addNamespace( pattern, namespace ) method or the fluent route().toNamespaceRouting() method.

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

    Once you declare the namespace you can use the grouping functionality to declare all the namespace routes or you can use a route().withNamespace() combination.

    // Via Grouping
    route( "/news" ).toNamespaceRouting( "blog" )
    	.group( { namespace = "blog" }, function(){
    		route( "/", "blog.index" )
      		.route( "/:year-numeric?/:month-numeric?/:day-numeric?", "blog.archives" );
    	} );
      
    
    // Via Routing DSL
    addNamespace( "/news", "blog" );
      
    route( "/" )
      .withNameSpace( "blog" )
      .to( "blog.index" );
    
    route( "/:year-numeric?/:month-numeric?/:day-numeric?" )
      .withNameSpace( "blog" )
      .to( "blog.archives" );
    

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

    Rendering External Views

    So what if I want to render a view outside of my application without using the setting explained above? Well, you use the externalView() method.

    <cfoutput>#externalView(view='/myViewsMapping/tags/footer')#</cfoutput>

    If you are using ColdBox 6.4 or older, you will want to use the renderExternalView() method name. In ColdBox 6.5.2+, renderExternalView() was deprecated in favor of the new externalView() method.

    Basic Layouts

    <cfoutput>
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <title>#prc.title#</title>
    </head>
    <body>
      <!--- Header: Direct Render --->
      #view( view='tags/header')#
    
      <div id="content">
        <!--- Render set view --->
        #view()#
      </div>
    
      #view( view='tags/footer' )#
    </body>
    </html>
    </cfoutput>
    If you make changes to any of the main configuration files you will need to re-initialize your application for the settings to take effect.

    Re-initializing an Application

    Please note that anytime you make any configuration changes or there are things in memory you wish to clear out, you will be using a URL action that will tell the ColdBox Bootstrapper to reinitialize the application. This special URL variable is called fwreinit and can be any value or a specific password you setup in the ColdBox configuration directive.

    You can also use CommandBox CLI to reinit your application if you are using its embedded server:

    // reinit with no password
    index.cfm?fwreinit=1
    
    // reinit with password
    index.cfm?fwreinit=mypass
    $ coldbox reinit
    WireBox

    Managing your domain objects has never been easier with this Dependency Injection and Inversion of Control (IOC) framework. WireBox supports all forms of injection as well as maintaining persistence for your domain objects. WireBox can also interface and provide Java classes, web services, and aspects of the ColdBox framework itself. WireBox also has built-in Aspect Oriented Programming (AOP) support; youโ€™ll never need another Dependency Injection engine again.

    LogBox

    This is a highly-configurable logging library which can be set up to relay messages of different types from any portion of your application to any number of predefined logging appenders.

    CacheBox

    A highly-versatile caching aggregator and enterprise cache that allows for multiple named caching stores as well as granular control over cache behaviors and eviction policies. CacheBox can interface out of the box with Ehcache, Adobe ColdFusion cache, and any Lucee cache.

    Lucee
    Ortus Solutions
    CommandBox
    Please make sure you download and install the latest CommandBox CLI. We will show you how in the Installing ColdBox section.
  • Grab a cup of coffee or tea

  • Get comfortable

  • Need Help?

    The Ortus Community is the way to get any help for our entire platform and modules: https://community.ortussolutions.com

    Getting Started Guide
    https://github.com/coldbox-samples/60-minute-quickstart
  • New additions without breaking backward compatibility bump the minor (and resets the patch)

  • Bug fixes and misc changes bump the patch

  • LTS - Support Policy

    For all ColdBox releases, updates are provided for 12 months, and security fixes are provided for 2 years after the next major release.

    Version
    Release
    Updates
    Security Fixes

    8.x

    2025

    2026

    2027

    7.x

    2023

    2024

    2025

    6.x

    2022

    2023

    If you need professional support, please contact Ortus Solutions.

    Releases

    In this section, you will find the release notes and links for each version's documentation. If you are looking for the release notes of previous major versions, use the version switcher at the top left of this documentation book.

    • Version 7.0 - May 2023

    • Version 6.0 - August 2020

    • Version 5.0 - July 2018

    • Version 4.0 - January 2015

    • Version 3.0 - March 2011

    • Version 2.0 - April 2007

    • Version 1.0 - June 2006

    Semantic Versioning

    As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.

  • Participants will be tolerant of opposing views.

  • Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.

  • Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions not aligned with this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.

  • When interpreting the words and actions of others, participants should always assume good intentions. Emotions cannot be derived from textual representations.

  • Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.

  • Bug Reporting

    Each of the main standalone frameworks in ColdBox has separate locations for submitting bug reports. Please also ensure that if you submit a pull request, you link it to the appropriate issue.

    • ColdBox Core: https://ortussolutions.atlassian.net/browse/COLDBOX

    • CacheBox : https://ortussolutions.atlassian.net/browse/CACHEBOX

    • LogBox : https://ortussolutions.atlassian.net/browse/LOGBOX

    • WireBox: https://ortussolutions.atlassian.net/browse/WIREBOX

    If you file a bug report, your issue should contain a title, a clear description of the issue, a way to replicate the issue, and any support files we might need to replicate your issue. The goal of a bug report is to make it easy for yourself - and others - to replicate the bug and develop a fix for it. All issues that do not contain a way to replicate will not be addressed.

    Support Questions

    If you have questions about usage, professional support, or just ideas to bounce off the maintainers, please do not create an issue. Leverage our support channels first.

    • Ortus Community Discourse: https://community.ortussolutions.com/c/communities/coldbox/13

    • Box Slack Team: http://boxteam.ortussolutions.com/

    • Professional Support: https://www.ortussolutions.com/services/support

    Pull Request Guidelines

    • The master branch is just a snapshot of the latest stable release. All development should be done in dedicated branches. Do not submit PRs against the master branch. They will be closed.

    • All pull requests should be sent against the development branch or the LTS version branch releases/v{version}

    • It's OK to have multiple small commits as you work on the PR - GitHub will automatically squash it before merging.

    • Make sure all local tests pass before submitting the merge.

    • Please make sure all your pull requests have companion tests.

    • Please link the Jira issue in your PR title when sending the final PR

    Security Vulnerabilities

    If you discover a security vulnerability, please email the development team at [email protected] and make sure you report it to the #security channel in our Box Team Slack Channel. All security vulnerabilities will be promptly addressed.

    Development Setup

    We have added all the necessary information to develop on ColdBox in our readme collaboration area and our tests readme so you can set up the database to test against.

    Language Compatibility

    Please make sure your code runs on the following Supported CFML Engines:

    • BoxLang 1+

    • Lucee 5+

    • Adobe ColdFusion 2023+

    Coding Styles & Formatting

    We are big on coding styles and have included a .cfformat.json in the root of the project so that you can run the formatting tools and CommandBox scripts:

    We recommend that anytime you hack on the core, you start the format watcher (box run-script format:watch). This will monitor your changes and auto-format your code for you.

    You can also see the Ortus Coding Standards you must follow here: https://github.com/Ortus-Solutions/coding-standards.

    CFC Docs With DocBox

    All CFCs are self-documenting, and we leverage DocBox to document the entire software. All functions must be properly documented using the DocBox syntax: https://docbox.ortusbooks.com/getting-started/annotating-your-code

    Financial Contributions

    You can support ColdBox and all of our Open Source initiatives at Ortus Solutions by becoming a Patreon. You can also get lots of goodies and services depending on the level of contributions.

    • Become a backer or sponsor on Patreon

    • One-time donations via PayPal

    Contributors

    Thank you to all the people who have already contributed to ColdBox! We: heart: : heart: : heart: love you!

    Made with contributors-img

    External Trademarks & Copyrights

    Flash, Flex, ColdFusion, and Adobe are registered trademarks and copyrights of Adobe Systems, Inc.

    ColdBox, CommandBox, FORGEBOX, TestBox, ContentBox, and Ortus Solutions are all trademarks and copyrights of Ortus Solutions, Corp.

    Notice of Liability

    The information in this book is distributed โ€œas isโ€ without warranty. The author and Ortus Solutions, Corp shall not have any liability to any person or entity concerning loss or damage caused or alleged to be caused directly or indirectly by the content of this training book, software, and resources described in it.

    Contributing

    We highly encourage contributions to this book and our open-source software. The source code for this book can be found in our GitHub repository where you can submit pull requests.

    Charitable Proceeds

    10% of the proceeds of this book will go to charity to support orphaned kids in El Salvador - https://www.harvesting.org/. So please donate and purchase the printed version of this book, every book sold can help a child for almost 2 months.

    Shalom Children's Home

    Shalom Children's Home

    Shalom Childrenโ€™s Home (https://www.harvesting.org/) is one of the ministries that are dear to our hearts located in El Salvador. During the 12-year civil war that ended in 1990, many children were left orphaned or abandoned by parents who fled El Salvador. The Benners saw the need to help these children and received 13 children in 1982. Little by little, more children came on their own, churches and the government brought children to them for care, and the Shalom Childrenโ€™s Home was founded.

    Shalom now cares for over 80 children in El Salvador, from newborns to 18 years old. They receive shelter, clothing, food, medical care, education, and life skills training in a Christian environment. The home is supported by a child sponsorship program.

    We have personally supported Shalom for over 6 years now; it is a place of blessing for many children in El Salvador who either has no families or have been abandoned. This is a good earth to seed and plant.

    https://github.com/ortus-docs/coldbox-docs
    Ortus Solutions, Corp
    http://www.ortussolutions.com/products/commandbox

    Introduction

    ColdBox is a conventions-based HMVC web development framework for the BoxLang JVM Language and ColdFusion (CFML).

    ColdBox HMVC v8.x

    HMVC Framework
    Standalone Libraries

    ColdBox Hierarchical MVC is the de-facto enterprise-level HMVC framework for the BoxLang JVM language and the ColdFusion (CFML) language. It's professionally backed, conventions-based, modular, highly extensible, and productive. Getting started with ColdBox is quick and painless. ColdBox takes the pain out of development by giving you a standardized methodology for modern web development with features such as:

    • Much More

    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.

    What is BoxLang?

    BoxLang is a modern dynamic JVM language developed by the ColdBox team that can be deployed on multiple runtimes: operating system (Windows/Mac/*nix/Embedded), web server, lambda, iOS, android, web assembly, and more. BoxLang combines many features from different programming languages, including Java, CFML, Python, Ruby, Go, and PHP, to provide developers with a modern, functional and expressive syntax.

    ColdBox has been designed to work in both BoxLang and CFML language engines. However, it is extremely optimized for BoxLang, since it is the same team that develops the language and the framework.

    Read more about BoxLang here:

    License

    The ColdBox Platform is open source and licensed under the License.

    • Copyright by Ortus Solutions, Corp

    • ColdBox, CacheBox, WireBox, and LogBox are registered trademarks of Ortus Solutions, Corp.

    Discussion & Help

    The Ortus Community is how to get help for our entire platform and modules: .

    You can also join our Slack Box Team at:

    Reporting a Bug

    We all make mistakes from time to time :) So why not let us know about it and help us out? We also love ๐Ÿ˜ pull requests, so please star us and fork us at:

    Jira Issue Tracking

    Professional Open Source

    ColdBox is a professional open source software backed by offering services like:

    • Custom Development

    • Professional Support & Mentoring

    • Training

    • Server Tuning

    Resources

    • Official Site:

    • Community:

    • Video Training:

    HONOR GOES TO GOD ABOVE ALL

    Because of His grace, this project exists. If you don't like this, don't read it, it's not for you.

    "Therefore being justified by faith, we have peace with God through our Lord Jesus Christ: By whom also we have access by faith into this grace wherein we stand, and rejoice in hope of the glory of God." Romans 5:5

    Requirements

    Routing is enabled by default in the ColdBox application templates in order to work with URL's like this:

    http://localhost/index.cfm/home/about

    As you can see they still contain the index.cfm in the URL. In order to enable full URL rewrites that eliminates that index.cfm you must have a rewrite enabled webserver like Apache, nginx or IIS or a Java rewrite filter which ships with CommandBox by default.

    http://localhost/home/about

    CommandBox has built in rewrites powered by Tuckey and you can enable a server with rewrites by running:

    server start --rewritesEnable

    Caution Some J2EE servlet containers do not support the forwarding of SES parameters via the routing template (index.cfm) out of the box. You might need to enable full URL rewriting either through a web server or a J2EE filter.

    Some Resources

    • via .htaccess or configuration files (Free)

    • ISAPI rewrite filter for IIS (Paid)

    • native rewrite filter (Free)

    View Helpers

    This is a nifty little feature that enables you to create nice helper templates on a per-view, per-folder and per-application basis. If the framework detects the helper, it will inject it into the rendering view so you can use methods, properties or whatever. All you need to do is follow a set of conventions. Let's say we have a view in the following location:

    /views
      /general
        +home.cfm

    Then we can create the following templates

    • homeHelper.cfm : Helper for the home.cfm view.

    • generalHelper.cfm : Helper for any view in the general folder.

    homeHelper.cfm

    That's it. Just append Helper to the view or folder name and there you go, the framework will use it as a helper for that view specifically. What can you put in these helper templates:

    • NO BUSINESS CODE

    • UI logic functions or properties

    • Helper functions or properties

    • Dynamic JavaScript or CSS

    Hint External views can also use our helper conventions

    Application wide helpers

    You can also use the coldbox.viewsHelper directive to tell the framework what helper file to use for ALL views and layouts rendered:

    Rendering With Local Variables

    You can pass localized arguments to the view() and layout() methods in order to encapsulate the rendering via the args struct argument. Much like how you make method calls with arguments. Inside of your layouts and views you will receive the same args struct reference as well.

    This gives you great DRYness (yes that is a word) when building new and edit forms or views as you can pass distinct arguments to distinguish them and keep structure intact.

    Universal Form

    <h1>#args.type# User</h1>
    <form method="post" action="#args.action#">
    ...
    </form>

    New Form

    Edit Form

    Getting & Setting Values

    We all need values in our applications. That is why we interact with the in order to place data from our model layer into it so our views can display it, or to retrieve data from a user's request. You will either interact with the event object to get/set values or put/read values directly via the received rc and prc references.

    We would recommend you use the private request collection (prc) for setting manual data and using the standard request collection (rc

    HTTP Method Spoofing

    Although we have access to all the HTTP verbs, modern browsers still only support GET and POST. With ColdBox and HTTP Method Spoofing, you can take advantage of all the HTTP verbs in your web forms.

    By convention, ColdBox will look for an _method field in the FORM scope. If one exists, the value of this field is used as the HTTP method instead of the method from the execution. For instance, the following block of code would execute with the DELETE action instead of the POST action:

    You can manually add these _method fields yourselves, or you can take advantage of ColdBox's HTML Helper startForm() method. Just pass the method you like, we will take care of the rest:

    Building Routable Links

    In your views, layouts and handlers you can use the buildLink method provided by the request context object (event) to build routable links in your application.

    Just pass in the routed URL or event and it will create the appropriate routed URL for you:

    QueryString Struct

    The queryString argument can be a simple query string or a struct that represents the query variables to append.

    Routing By Convention

    Every router has a default route already defined for you in the application templates, which we refer to as routing by convention:

    The URL pattern in the default route includes two special position placeholders, meaning that the handler and the action will come from the URL. Also note that the :action has a question mark (?), which makes the placeholder optional, meaning it can exist or not from the incoming URL.

    • :handler - The handler to execute (It can include a Package and/or Module reference)

    Pre Advices

    With this interceptor you can intercept local event actions and execute things before the requested action executes. You can do it globally by using the preHandler() method or targeted to a specific action pre{actionName}().

    The arguments received by these interceptors are:

    • event : The request context reference

    Layouts

    A layout is simply an HTML file that acts as your shell where views can be rendered in and exists in the layouts folder of your application. The layouts can be composed of multiple views and one main view. The main view is the view that gets set in the request collection during a request via event.setView() usually in your handlers or interceptors.

    You can have as many layouts as you need in your application and they are super easy to override or assign to different parts of your application. Imagine switching content from a normal HTML layout to a PDF or mobile layout with one line of code. How cool would that be? Well, it's that cool with ColdBox. Another big benefit of layouts, is that you can see the whole picture of the layout, not the usual cfmodule calls where tables are broken, or divs are left open as the module wraps itself around content. The layout is a complete html document and you basically describe where views will be rendered. Much easier to build and simpler to maintain.

    Info Another important aspect of layouts is that they can also consume other layouts as well. So you can create nested layouts very easily via the renderLayout()

    Routing Groups

    There will be a time where your routes will become very verbose and you would like to group them into logical declarations. These groupings can also help you prefixes repetitive patterns in many routes with a single declarative construct. These needs are met with the group() method in the router.

    The best way to see how it works is by example:

    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 grouping action.

    The options struct can contain any values that you can use within the closure. Grouping can also be very nice when creating , which is our next section.

    <major>.<minor>.<patch>
    # Format everything
    box run-script format
    
    # Start a watcher, type away, save and auto-format for you
    box run-script format:watch

    2024

    native web server (free)
  • Tuckey J2EE rewrite filter (free)

  • Apache mod_rewrite
    Helicon Tech
    IIS 7
    nginx
    /views
      /general
        +home.cfm
        +homeHelper.cfm
        +generalHelper.cfm
    coldbox.viewsHelper = "includes/helpers/viewsHelper.cfm;
    #view(view='forms/universal',args={type='new',action='user.create'})#
    #view(view='forms/universal',args={type='edit',action='user.update'})#
    <cfoutput>
    <form method="POST" action="#event.buildLink( 'posts/#prc.post.getId()#' )#">
        <input type="hidden" name="_method" value="DELETE" />
        <button type="submit">Delete</button>
    </form>
    </cfoutput>
    <cfoutput>
    #html.startForm( action = "posts.#prc.post.getId()#", method="DELETE" )#
        #html.submitButton( name = "Delete", class = "btn btn-danger" )#
    #html.endForm()#
    </cfoutput>
    function group( struct options={}, body );
    route( pattern="/news", target="public.news.index" );
    route( pattern="/news/recent", target="public.news.recent" );
    route( pattern="/news/removed", target="public.news.removed" );
    route( pattern="/news/add/:title", target="public.news.add" );
    route( pattern="/news/delete/:slug", target="public.news.remove" );
    route( pattern="/news/v/:slug", target="public.news.view" );
    group( { pattern="/news", target="public.news." }, function(){
    	route( "/", "index" )
    	.route( "/recent", "recent" )
    	.route( "/removed", "removed" )
    	.route( "/add/:title", "add" )
    	.route( "/delete/:slug", "remove" )
    	.route( "/v/:slug", "view" );
    } );
    namespaces

    Flash

    This directive is how you will configure the Flash RAM for operation. Below are the configuration keys and their defaults:

    // flash scope configuration
    flash = {
        // Available scopes are: session,client,cache,mock or your own class path
        scope = "session",
        // constructor properties for the flash scope implementation
        properties = {},
        // automatically inflate flash data into the RC scope at the beginning of a request
        inflateToRC = true, 
        // automatically inflate flash data into the PRC scope at the beginning of a request
        inflateToPRC = false, 
        // automatically purge flash data for you
        autoPurge = true, 
        // automatically save flash scopes at end of a request and on relocations.
        autoSave = true 
    };

    CacheBox

    The CacheBox structure is based on the CacheBox declaration DSL, and it allows you to customize the caches in your application. Below are the main keys you can fill out, but we recommend you review the CacheBox documentation for further detail.

    Info : We would recommend you create a config/CacheBox.cfc and put all your caching configuration there instead of in the main ColdBox configuration file. This will give you further portability and decoupling.

    ConfigFile

    An absolute or relative path to the CacheBox configuration CFC or XML file to use instead of declaring the rest of the keys in this structure. So if you do not define a cacheBox structure, the framework will look for the default value: config/CacheBox.cfc and it will load it if found. If not found, it will use the default CacheBox configuration found in /coldbox/system/web/config/CacheBox.cfc

    ScopeRegistration

    A structure that enables scope registration of the CacheBox factory in either server, cluster, application or session scope.

    DefaultCache

    The configuration of the default cache which will have an implicit name of default which is a reserved cache name. It also has a default provider of CacheBox which cannot be changed.

    Caches

    A structure where you can create more named caches for usage in your CacheBox factory.

    Overriding Layouts

    Ok, now that we have started to get funky, let's keep going. How can I change the layout on the fly for a specific view? Very easily, using yet another new method from the event object, called setLayout() or the layout argument to the setView() method.

    event.setLayout( name );
    event.setView( view="", layout=name );

    This is great, so we can change the way views are rendered on the fly programmatically. We can switch the content to a PDF in an instant. So let's do that

    function home(event,rc,prc){
    
        if( event.valueExists('print') ){
            event.setLayout('layout.PDF');
        }
    
        // logic here
    
        // set view
        event.setView('general/home');
    
    }

    Layouts From A Module

    If you need the set layout to be rendered from a specific module then use the module argument from the setLayout() or renderLayout() methods:

    component name="general"{
    
        function index(event,rc,prc){
    
            // call some model for data and put into the request collection
            prc.myQuery = getInstance('MyService').getData();
            // set the view for rendering
            event.setLayout( name="admin", module="contentbox" );
    
        }
    
    }
    Named Routes

    Please note that the to argument can be a simple route path, but it can also be a struct. This struct is for routing to named routes. Even though we recommend to use the route() method instead.

    Inspecting The Current Route

    The request context object (event) also has some handy methods to tell you the name or even the current route that was selected for execution:

    • getCurrentRouteName() - Gives you the name of the current route, if any

    • getCurrentRoute() - Gives you the currently executed route

    • getCurrentRoutedURL() - Gives you the complete routed URL pattern that matched the route

    • getCurrentRoutedNamespace() - Gives you the current routed namespace, if any

    <a href="#event.buildLink( 'home.about' )#">About</a>
    <a href="#event.buildLink( 'user.edit.id.#user.getID()#' )#">Edit User</a>

    :action - The action to relocate to (See the ?, this means that the action is optional)

    Behind the scenes the router creates two routes due to the optional placeholder in the following order:

    1. route( "/:handler/:action" )

    2. route( "/:handler)

    Tip The :handler parameter allows you to nest module names and handler names. Ex: /module/handler/action

    If no action is passed the default action is index

    This route can handle pretty much all your needs by convention:

    Convention Name-Value Pairs

    Any extra name-value pairs in the remaining URL of a discovered URL pattern will be translated to variables in the request collection (rc) for you automagically.

    Tip: You can turn this feature off by using the valuePairTranslation( false ) modifier in the routing DSL on a route by route basis

    route( "/pattern" ) .to( "users.show" ) .valuePairTranslation( false );

    <cfscript>
    // facade to get i18n resource
    function $r(){ return getResource(argumentCollection=arguments); }
    // cool formatted date function
    function today(){ return dateFormat(now(),"full"); }
    </cfscript>
    //cachebox configuration
    cachebox = {
        // Location of the configuration CFC for CacheBox
        configFile = "config/CacheBox.cfc",
        // Scope registration for CacheBox
        scopeRegistration = {enabled=true,scope=application,key=cacheBox},
        // Default Cache Configuration
        defaultCache  = "views",
        // Caches Configuration
        caches      = {}
    };
    /**
     * Builds links to events or URL Routes
     *
     * @to          The event or route path you want to create the link to
     * @queryString The query string to append which can be a regular query string string, or a struct of name-value pairs
     * @translate   Translate between . to / depending on the SES mode on to and queryString arguments. Defaults to true.
     * @ssl         Turn SSl on/off on URL creation, by default is SSL is enabled, we will use it.
     * @baseURL     If not using SES, you can use this argument to create your own base url apart from the default of index.cfm. Example: https://mysample.com/index.cfm
     */
    string function buildLink(
    	to,
    	queryString       = "",
    	boolean translate = true,
    	boolean ssl,
    	baseURL = ""
    ){
    <a href="#event.buildLink( 'home.about', "page=2&format=simple" )#">About</a>
    
    <a href="#event.buildLink( 'home.about', { page : 2, format: "simple" } )#">About</a>
    
    event.buildLink( {
        name : "routeName",
        params : { ... }
    } )
    
    event.route( "routeName", { ... } )
    route( ":handler/:action?").end();
    // Basic Routing
    http://localhost/general -> event=general.index
    http://localhost/general/index -> event=general.index
    
    // If 'admin' is a package/folder in the handlers directory
    http://localhost/admin/general/index -> event=admin.general.index 
    
    // If 'admin' is a module
    http://localhost/admin/general/index -> event=admin:general.index
    http://localhost/general/show/page/2/name/luis
    # translate to
    event=general.show, rc.page=2, rc.name=luis
    
    http://localhost/users/show/export/pdf/name
    # translate to
    event=users.show, rc.export=pdf, rc.name={empty value}

    Security Hardening

  • Code Reviews

  • Much More

  • https://learn.boxlang.io

  • http://youtube.com/ortussolutions

  • Source Code: https://github.com/coldbox/coldbox-platform

  • Bug Tracker: https://ortussolutions.atlassian.net/browse/COLDBOX

  • Social

    • Facebook: https://www.facebook.com/coldboxplatform

    • X: @coldbox @ortussolutions

    • Slack: https://boxteam.ortussolutions.com

  • Conventions instead of configuration
    Modern routing engine
    RESTFul API ready
    A hierarchical approach to MVC using ColdBox Modules
    Event-driven programming
    Async and Parallel programming constructs
    Integration & Unit Testing
    Included dependency injection
    Caching engine and API
    Logging engine
    An extensive ecosystem
    https://boxlang.io
    Apache 2
    https://community.ortussolutions.com
    https://boxteam.ortussolutions.com
    https://github.com/coldbox/coldbox-platform
    https://ortussolutions.atlassian.net/browse/COLDBOX
    https://ortussolutions.atlassian.net/browse/WIREBOX
    https://ortussolutions.atlassian.net/browse/LOGBOX
    https://ortussolutions.atlassian.net/browse/CACHEBOX
    Ortus Solutions, Corp
    https://www.coldbox.org
    https://community.ortussolutions.com
    https://www.cfcasts.com
    ) for reading the user's unsafe request variables. This way a clear distinction can be made on what was sent from the user and what was set by your code.

    Important The most important paradigm shift from procedural to an MVC framework is that you NO LONGER will be talking to URL, FORM, REQUEST or any ColdFusion scope from within your handlers, layouts, and views. The request collection already has URL, FORM, and REQUEST scope capabilities, so leverage it.

    request context
    RC/PRC Data Super Highway
    //set a value for views to use
    event.setValue( "name", "Luis" );
    event.setPrivateValue( "name", "Luis" );
    
    // retrieve a value the user sent
    event.getValue( "name" );
    // retrieve a value the user sent or give me a default value
    event.getValue( "isChecked", false );
    
    // retrieve a private value
    event.getPrivateValue( "name" );
    // retrieve a private value or give me a default value
    event.getPrivateValue( "isChecked", false );
    
    // param a value
    event.paramValue( "user_id", "" );
    // param a private value
    event.paramPrivateValue( "user_id", "" );
    
    // remove a value
    event.removeValue( "name" );
    // remove a private value
    event.removePrivateValue( "name" );
    
    //check if value exists
    if( event.valueExists( "name" ) ){
    
    }
    //check if private value exists
    if( event.privateValueExists( "name" ) ){
    
    }
    
    // set a view for rendering
    event.setView( 'blog/index' );
    
    // set a layout for rendering
    event.setLayout( 'main' );
    
    // set a view and layout
    event.setView( view="blog/userinfo", layout="ajax" );
    action : The action name that was intercepted by preHandler()
  • eventArguments : The struct of extra arguments sent to an action if executed via runEvent()

  • rc : The RC reference

  • prc : The PRC Reference

  • Here are a few options for altering the default event execution:

    • Use event.overrideEvent('myHandler.myAction') to execute a different event than the default.

    • Use event.noExecution() to halt execution of the current event. ONLY works when executed by interceptions before the main event. It will never work in pre/post advices.

    See the RequestContext documentation for more details.

    Exceptions & Only Lists

    You can fine tune these interception methods by leveraging two public properties in the handler:

    • this.prehandler_only : A list of actions that preHandler() will ONLY fire on

    • this.prehandler_except : A list of actions that preHandler() will NOT fire on

    method.

    Linking Events Together

    ColdBox provides you with a nice method for generating links between events by leveraging an object called event that is accessible in all of your layouts/views and event handlers. This event object is called behind the scenes the request context object, which models the incoming request and even contains all of your incoming FORM and URL variables in a structure called rc.

    Tip: You will use the event object to set views, set layouts, set HTTP headers, read HTTP headers, convert data to other types (json,xml,pdf), and much more.

    Building Links

    You can easily build links with ColdBox by using two methods:

    1. event.buildLink() - Build links to events or URL routes

    2. event.route() - Build links to specifically

    Here are the signatures

    Edit Your View

    Edit the views/virtual/hello.cfm page and wrap the content in a cfoutput and create a link to the main ColdBox event, which by convention, is main.index. You can use main.index or just main (Remember that index is the default action)

    This code will generate a link to the main.index event in a search engine-safe manner and in SSL detection mode. Go execute the event: http://localhost:{port}/virtual/hello and click on the generated URL; you will now be navigating to the default event /main/index. This technique will also apply to FORM submissions:

    Tip You can visit our API Docs for further information about the event object and the buildLink method: .

    For extra credit try to use more of the buildLink arguments.

    Routing

    We have been using routing by convention, but let's do named routes now to control the URL. Let's create a /home route that will execute the main.index event and update our view to change the building of the URL via route(). Let's open the config/Router.cfc

    We use the route() method to register URL patterns and then tell the router what to execute if matched. This can be an event, but it can also be a view, an inline action, a relocation, and much more. Since we registered new URLs you need to reinit the app (?fwreinit=1). Now let's update the link in the hello view:

    Try it out now!

    Tip: Check out the routing API Docs for further information.

    Application Templates

    The best way to get started with ColdBox

    The best way to get started with ColdBox is with our application templates that you can find here: coldbox-templates. We have a curated collection of starter templates to get you kicking the tires quickly. You will do so via the coldbox create app command in the CLI:

    Here is a listing of the latest supported templates:

    Template
    Slug
    Description

    Default

    default

    The default ColdBox application template

    CommandBox Integration

    The coldbox create app command has integration to our application templates via the skeleton argument. This can be the name of each of the templates in our repositories or you can use the following alternatives:

    • A name of a ForgeBox entry: cbtemplate-advanced-script,cbtemplate-simple

    • A Github shortcut: github-username/repo

    • An HTTP/S URL to a zip file containing a template:

    ModuleSettings

    Option 1: Coldbox Config

    This structure within config/Coldbox.cfc is used to house module configurations. Please refer to each module's documentation on how to create the configuration structures. Usually the keys will match the name of the module to be configured.

    Option 2: Config Object Override

    Starting in ColdBox 7, you can store module configurations as their own configuration file within the applicationโ€™s config folder outside of the config/Coldbox.cfc. The naming convention is config/modules/{moduleName}.cfc

    The configuration CFC will have one configure() method that is expected to return a struct of configuration settings as you did before in the moduleSettings

    The following example overrides the original module configuration entirely:

    For large module configs where only a few keys need to be changed, you can update the config by modifying the struct passed in as an argument and then returning the updated version.

    Injections

    Just like a ModuleConfig this configuration override also gets many injections:

    • controller

    • coldboxVersion

    • appMapping

    • moduleMapping

    Env Support

    This module configuration object will also inherit the ModuleConfig.cfc behavior that if you create methods with the same name as the environment you are on, it will execute it for you as well.

    Then you can change the original struct as you see fit for that environment.

    Pattern Placeholders

    Alphanumeric Placeholders

    In your URL pattern you can also use the : syntax to denote a variable placeholder. These position holders are alphanumeric by default:

    Once a URL is matched to the route above, the placeholders (:year/:month?/:day?) will become request collection (RC) variables:

    Optional Placeholders

    Sometimes we will want to declare routes that are very similar in nature and since order matters, they need to be declared in the right order. Like this one:

    However, we just wrote 4 routes for this approach when we can just use optional variables by using the ? symbol at the end of the placeholder. This tells the processor to create the routes for you in the most detailed manner first instead of you doing it manually.

    Caution Just remember that an optional placeholder cannot be followed by a non-optional one. It doesn't make sense.

    Numeric Placeholders

    ColdBox gives you also the ability to declare numerical only routes by appending -numeric to the variable placeholder so the route will only match if the placeholder is numeric. Let's modify the route from above.

    This route will only accept years, months and days as numbers.

    Alpha Placeholders

    ColdBox gives you also the ability to declare alpha only routes by appending -alpha to the variable placeholder so the route will only match if the placeholder is alpha only.

    This route will only accept page names that are alpha only.

    There are two ways to place a regex constraint on a placeholder, using the -regex: placeholder or adding a constraints structure to the route declaration.

    Regular Expression Placeholders

    You can also have the ability to declare a placeholder that must match a regular expression by using the -regex( {regex_here} ) placeholder.

    The rc variable format must match the regex supplied: (xml|json)

    Regular Expression Constraints

    You can also apply a structure of regular expressions to a route instead of inlining the regular expressions in the placeholder location. You will do this using the constraints() method of the router.

    The key in the structure must match the name of the placeholder and the value is a regex expression that must be enclosed by parenthesis ().

    Author

    Author biographies of the ColdBox Platform

    Luis Fernando Majano Lainez

    Luis F. Majano Lainez

    Luis Majano is a Computer Engineer, and published author that has been creating software since the year 2000. He was born in San Salvador, El Salvador in the late 70s, during a period of economical instability and civil war. He lived in El Salvador until 1995 and then moved to Miami, Florida where he studied and completed his Bachelor of Science in Computer Engineering at Florida International University.

    He is the founder and CEO of Ortus Solutions, a consulting firm specializing in web development, ColdFusion (CFML), Java development, and all open-source professional services under the ColdBox, CommandBox, and ContentBox stack. He is the creator of ColdBox, ContentBox, WireBox, TestBox, LogBox, and anything โ€œBOXโ€, and contributes to over 250 open-source projects. He has a passion for learning and mentoring developers so they can succeed with sustainable software practices and the usage and development of open-source software. You can read his blog at

    Luis has a passion for Jesus, tennis, golf, volleyball, and anything electronic. Random Author Facts:

    • He played volleyball in the Salvadorean National Team at the tender age of 17

    • The Lord of the Rings and The Hobbit are his favorite books (Geek!)

    • His first ever computer was a Texas Instrument TI-86 that his parents gave him in 1986. After some time digesting his very first BASIC book, he had written his own tic-tac-toe game at the age of 9. (Extra geek!)

    Keep Jesus number one in your life and in your heart. I did and it changed my life from desolation, defeat and failure to an abundant life full of love, thankfulness, joy and overwhelming peace. As this world breathes failure and fear upon any life, Jesus brings power, love and a sound mind to everybody!

    โ€œTrust in the LORD with all your heart, and do not lean on your own understanding.โ€ โ€“ Proverbs 3:5

    Contributors

    Jorge Emilio Reyes Bendeck

    Jorge is an Industrial and Systems Engineer born in El Salvador. After finishing his Bachelor studies at the Monterrey Institute of Technology and Higher Education , Mexico, he went back to his home country where he worked as the COO of. In 2012 he left El Salvador and moved to Switzerland in pursuit of the love of his life. He married her and today he resides in Basel with his lovely wife Marta and their daughter Sofรญa.

    Jorge started working as project manager and business developer at Ortus Solutions, Corp. in 2013, . At Ortus he fell in love with software development and now enjoys taking part on software development projects and software documentation! He is a fellow Christian who loves to play the guitar, worship and rejoice in the Lord!

    Therefore, if anyone is in Christ, the new creation has come: The old has gone, the new is here! 2 Corinthians 5:17

    Brad Wood

    Brad grew up in southern Missouri where he systematically disassembled every toy he ever owned which occasionally led to unintentional shock therapy (TVs hold a charge long after they've been unplugged, you know) After high school he majored in Computer Science with a music minor at (Olathe, KS). Today he lives in Kansas City with his wife and three girls where he still disassembles most of his belongings (including automobiles) just with a slightly higher success rate of putting them back together again.) Brad enjoys church, all sorts of international food, and the great outdoors.

    Brad has been programming CFML for 12+ years and has used every version of CF since 4.5. He first fell in love with ColdFusion as a way to easily connect a database to his website for dynamic pages. Brad blogs at () and likes to work on solder-at-home digital and analog circuits with his daughter as well as building projects with Arduino-based microcontrollers.

    Brad's CommandBox Snake high score is 141.

    System Settings (Java Properties and Environment Variables)

    ColdBox makes it easy to access the configuration stored in your Java system properties and your server's environment variables, even if you don't know which one it is in! Three methods are provided for your convenience:

    Name
    Arguments
    Description

    getSystemSetting

    ( key, defaultValue )

    Looks for key in properties first, env second. Returns the defaultValue if neither exist.

    getSystemProperty

    ( key, defaultValue )

    Returns the Java System property for key. Returns the defaultValue if it does not exist.

    Accessing System Settings in config/ColdBox.cfc or a ModuleConfig.cfc

    If you are inside config/ColdBox.cfc or a ModuleConfig.cfc or a config/WireBox.cfc you can use the three system settings functions directly! No additional work required.

    Accessing System Settings in Application.cfc

    If you would like to access these methods in your Application.cfc, create an instance of coldbox.system.core.delegates.Env and access them off of that component. This is required when adding a datasource from environment variables.

    Example:

    Accessing System Settings in other files

    If you need to access these configuration values in other components, consider adding the values to your and injecting the values into your other components

    RESTFul Extension Detection

    Usage

    ColdBox allows you to detect incoming extensions from incoming paths automatically for you. This is great for building multi-type responses or to just create virtual extensions for events.

    http://localhost/users
    http://localhost/users.json
    http://localhost/users.xml
    http://localhost/users.pdf
    http://localhost/users.html    

    If an extension is detected in the incoming URL, ColdBox will grab it and store it in the request collection (RC) as the variable format. If there is no extension, then rc.format will not be stored and thus will not exist.

    Configuration

    You can configure the extension detection using the following configuration methods:

    Please note that if you have set to throw exceptions if an invalid extension is detected then a 406 exception will be thrown.

    How are events called?

    Events are determined via a special variable that can be sent in via the FORM, URL, or REMOTELY called event. If no event is detected as an incoming variable, the framework will look in the configuration directives for the DefaultEvent and use that instead. If you did not set a DefaultEvent setting then the framework will use the following convention for you: main.index

    Hint : You can even change the event variable name by updating the EventName setting in your coldbox .

    Please note that ColdBox supports both normal variable routing and , usually referred to as pretty URLs.

    Event Syntax

    In order to call them you will use the following event syntax notation format:

    • no event : Default event by convention is main.index

    • event={handler} : Default action method by convention is index()

    • event={handler}.{action} : Explicit handler + action method

    This looks very similar to a Java or CFC method call, example: String.getLength(), but without the parentheses. Once the event variable is set and detected by the framework, the framework will tokenize the event string to retrieve the CFC and action call to validate it against the internal registry of registered events. It then continues to instantiate the event handler CFC or retrieve it from cache, finally executing the event handler's action method.

    Examples

    Relocating

    The framework provides you with the relocate() method that you can use to relocate to other events thanks to the framework super type object, the grand daddy of all things ColdBox.

    After calling relocate, further code will still be processed until you return from handler.

    Please see the Super Type CFC Docs for further investigation of all the goodness of methods you have available.

    /**
    * Relocate user browser requests to other events, URLs, or URIs.
    *
    * @event The name of the event to run, if not passed, then it will use the default event found in your configuration file
    * @URL The full URL you would like to relocate to instead of an event: ex: URL='http://www.google.com'
    * @URI The relative URI you would like to relocate to instead of an event: ex: URI='/mypath/awesome/here'
    * @queryString The query string to append, if needed. If in SES mode it will be translated to convention name value pairs
    * @persist What request collection keys to persist in flash ram
    * @persistStruct A structure key-value pairs to persist in flash ram
    * @addToken Whether to add the tokens or not. Default is false
    * @ssl Whether to relocate in SSL or not
    * @baseURL Use this baseURL instead of the index.cfm that is used by default. You can use this for ssl or any full base url you would like to use. Ex: https://mysite.com/index.cfm
    * @postProcessExempt Do not fire the postProcess interceptors
    * @statusCode The status code to use in the relocation
    */
    void function relocate(
    	event,
    	URL,
    	URI,
    	queryString,
    	persist,
    	struct persistStruct,
    	boolean addToken,
    	boolean ssl,
    	baseURL,
    	boolean postProcessExempt,
    	numeric statusCode
    )

    It is extremely important that you use this method when relocating instead of the native ColdFusion methods as it allows you to gracefully relocate to other events or external URIs. By graceful, we mean it does a lot more behind the scenes like making sure the flash scope is persisted, logging, post processing interceptions can occur and safe relocations.

    So always remember that you relocate via relocate() and if I asked you: "Where in the world does event handlers get this method from?", you need to answer: "From the super typed inheritance".

    HTTP Method Security

    More often you will find that certain web operations need to be restricted in terms of what HTTP verb is used to access a resource. For example, you do not want form submissions to be done via GET but via POST or PUT operations. HTTP Verb recognition is also essential when building strong RESTFul APIs when security is needed as well.

    Manual Solution

    You can do this manually, but why do the extra coding :)

    This solution is great and works, but it is not THAT great. We can do better.

    Allowed Methods Property

    Another feature property on an event handler is called this.allowedMethods. It is a declarative structure that you can use to determine what the allowed HTTP methods are for any action on the event handler.

    If the request action HTTP method is not found in the approved list, it will look for a onInvalidHTTPMethod() on the handler and call it if found. Otherwise ColdBox throws a 405 exception that is uniform across requests.

    You can listen for methods using the coldbox.onInvalidHTTPMethodHandler located in your config/ColdBox.cfc.

    If the action is not listed in the structure, then it means that we allow all HTTP methods. Just remember to either use the onError() or onInvalidHTTPMethod() method conventions or an exception handler to deal with the security exceptions.

    Allowed Methods Annotation

    You can tag your event actions with a allowedMethods annotation and add a list of the allowed HTTP verbs as well. This gives you a nice directed ability right at the function level instead of a property. It is also useful when leveraging DocBox documentation as it will show up in the API Docs that are generated.

    Default Layout

    Default Layout

    The default layout in a ColdBox application is layouts/main.cfm by convention. You can change this by using the layoutSettings in your Coldbox.cfc.

    //Layout Settings
    layoutSettings = {
        defaultLayout = "basic.cfm"
    }

    Default View

    There is no default view in ColdBox, but you can configure one by using the same layoutSettings configuration directive and the defaultView directive:

    This means that if no view is set in the request context, ColdBox will fallback to this view for rendering.

    Post Advices

    With this interceptor you can intercept local event actions and execute things after the requested action executes. You can do it globally by using the postHandler() method or targeted to a specific action post{actionName}().

    The arguments received by these interceptors are:

    • event : The request context reference

    • action : The action name that was intercepted by postHandler()

    • eventArguments : The struct of extra arguments sent to an action if executed via runEvent()

    • rc : The RC reference

    • prc : The PRC Reference

    Exceptions & Only Lists

    You can fine tune these interception methods by leveraging two public properties in the handler:

    • this.posthandler_only : A list of actions that the postHandler() action will fire ONLY!

    • this.posthandler_except : A list of actions that the postHandler() action will NOT fire on

    View Events

    All rendered views have associated events that are announced whenever the view is rendered via ColdBox Interceptors. These are great ways for you to be able to intercept when views are rendered and transform them, append to them, or even remove content from them in a completely decoupled approach. The way to listen for events in ColdBox is to write Interceptors, which are essential simple CFC's that by convention have a method that is the same name as the event they would like to listen to. Each event has the capability to receive a structure of information which you can alter, append or remove from. Once you write these Interceptors you can either register them in your Configuration File or programmatically.

    Event

    Data

    Description

    preViewRender

    view - The name of the view to render

    Executed before a view is about to be rendered

    postViewRender

    Caution You can disable the view events on a per-rendering basis by passing the prePostExempt argument as true when calling renderView() methods.

    Sample Interceptor

    Here is a sample interceptor that trims any content before it is renderer:

    Of course, I am pretty sure you will be more creative than that!

    What is MVC

    Model View Controller

    Intro to MVC

    "A developer often wishes to separate data (model) and user interface (view) concerns, so that changes to the user interface will not affect data handling, and that the data can be reorganized without changing the user interface. The model-view-controller solves this problem by decoupling data access and business logic from data presentation and user interaction, by introducing an intermediate component: the controller." โ€‹

    MVC is a popular design pattern called which seeks to promote good maintainable software design by separating your code into 3 main tiers:

    My First Handler & View

    Handler Scaffolding

    Now let's create our first event handler controller, which in ColdBox is called Event Handler. Let's go to CommandBox again:

    This will generate the following files:

    • A new handler called

    Routing

    ColdBox's powerful routing service provides robust URL mappings for building expressive applications and RESTful services with clean, SEO-friendly URLs.

    ColdBox supports a Routing Service that will provide you with robust URL mappings for building expressive applications and RESTFul services. By convention URL routing will allow you to create URL's without using verbose parameter delimiters like ?event=this.that&m1=val and execute ColdBox events.

    If you are leveraging CommandBox as your server, then full URL rewrites are enabled by default. This means you do not need a web server to remove the index.cfm from the URL.

    Installing ColdBox

    Welcome to the world of ColdBox!

    We are excited you are taking this development journey with us. Before we get started with ColdBox let's install CommandBox CLI, which will allow you to install/uninstall dependencies, start servers, have a REPL tool and much more. Please remember to us in Github.

    IDE Tools

    ColdBox has the following supported IDE Tools:

    Adding A Layout

    Every time the framework renders a view, it will try to leverage the default layout located in layouts/Main.cfm by convention. This is a reusable CFML template that gives format to your HTML output and contains the location of where the view you want should be rendered.

    Tip : The request context can also be used to choose a different layout at runtime via the event.setLayout() method or the layout argument in the event.setView( layout: "login" ) method.

    Using Settings

    The ColdBox Controller (stored in ColdFusion application scope as application.cbController) stores all your application settings and also your system settings:

    • ColdboxSettings : Framework specific system settings

    Conventions

    Discover the major conventions of the ColdBox framework

    The core conventions delineate the contract between ColdBox and you for file/directory locations and more. Below is a table of the core conventions:

    Directory/File Conventions

    • /config - Where configuration files are stored

    Named Routes

    You can register routes in ColdBox with a human friendly name so you can reference them later for link generation and more.

    Registering Named Routes

    You will do this in two forms:

    1. Using the route()

    Routing DSL

    The ColdBox Routing DSL will be used to register routes for your application, which exists in your application or module router object. Routing takes place using several methods inside the router, which are divided into the following 3 categories:

    1. Initiators - Starts a URL pattern registration, but does not fully register the route until a terminator is called (target).

    2. Modifiers - Modifies the pattern with extra metdata to listen to from the incoming request.

    ColdBox.cfc

    The ColdBox.cfc is the main applications' configuration object.

    The ColdBox configuration CFC is the heart of your ColdBox application. It contains the initialization variables for your application and extra information used by third-party modules and ultimately how your application boots up. In itself, it is also an event listener or , so it can listen to life-cycle events of your application.

    This CFC is instantiated by ColdBox and decorated at runtime so you can take advantage of some dependencies. Here is a table of the automatic injection this object has:

    Executing Routes

    A part from using runEvent() to execute events, you can also abstract it by using the runRoute() method. This method is fairly similar but with the added benefit of executing a NAMED route instead of the direct event it represents. This gives you the added flexibility of abstracting the direct event and leveraging the named route.

    All the same feature of runEvent() apply to runRoute()

    RunRoute()

    RESTFul Data

    Out of the box, ColdBox gives you all the RESTFul capabilities you will need to create robust and scalable RESTFul services. Let's add some RESTFul capabilities to our contact listing we created in the previous section.

    Tip: You can find much more information about building ColdBox RESTFul services in our

    Rendering Collections

    You have a few arguments in the view() method that deal with collection rendering. Meaning you can pass any array or query and the Renderer will iterate over that collection and render out the view as many times as the records in the colleciton.

    • collection : A data collection that can be a query or an array of objects, structs or whatever

    • collectionAs : The name of the variable in the variables scope that will hold the collection pivot.

    LogBox

    The logBox structure is based on the LogBox declaration DSL, see the for much more information.

    Info : If you do not define a logBox DSL structure, the framework will look for the default configuration file config/LogBox.cfc. If it does not find it, then it will use the framework's default logging settings.

    ConfigFile

    You can use a configuration CFC instead of inline configuration by using this setting. The default value is config/LogBox.cfc, so by convention you can just use that location. If no values are defined or no config file exists, the default configuration file is coldbox/system/web/config/LogBox.cfc.

    Implicit Methods

    Every event handler controller has some implicit methods that if you create them, they come alive. Just like the implicit methods in Application.cfc

    onMissingAction()

    With this convention you can create virtual events that do not even need to be created or exist in a handler. Every time an event requests an action from an event handler and that action does not exist in the handler, the framework will check if an onMissingAction() method has been declared. If it has, it will execute it. This is very similar to ColdFusion's onMissingMethod()

    Interception Methods

    There are several simple implicit (Aspect Oriented Programming) interceptor methods, usually referred to as advices, that can be declared in your event handler that the framework will use in order to execute them before/after and around an event as its fired from the current handler.

    This is great for intercepting calls, pre/post processing, localized security, logging, RESTful conventions, and much more. Yes, you got that right, just for you and without all the complicated setup involved! If you declared them, the framework will execute them.

    Pathinfo Providers

    By default, the URL mapping processor will detect routes by looking at the CGI.PATH_INFO variable, but you can override this and provide your own function. This feature can be useful to set flags for each request based on a URL and then clean or parse the URL to a more generic form to allow for simple route declarations. Uses may include internationalization (i18n) and supporting multiple experiences based on devices such as Desktop, Tablet, Mobile and TV.

    To modify the URI used by the Routing Services before route detection occurs simply follow the convention of adding a function called pathInfoProvider() to your application Router (config/Router.cfc).

    The pathInfoProvider() function is responsible for returning the string used to match a route.

    Sending Files

    We all need to deliver files to users at one point in time. ColdBox makes it easy to deliver any type of file even binary files via the (event) sendFile() method.

    Method Signature

    The API Docs can help you see the entire format of the method:

    The method signature is as follows:

    Validation

    ColdBox Core MVC does not have validation built-in but it is implemented via the official core cbValidation module. You can easily install the module in your application via:

    You can find much more information about this module in the following resources:

    • Source:

    • Documentation:

    Nested Layouts

    You can also wrap layouts within other layouts and get incredible reusability. This is accomplished by using the layout() method in the Renderer. As always, refer to the CFC API for the latest method arguments and capabilities.

    So if I wanted to wrap my basic layout in a PDF wrapper layout (pdf.cfm) I could do the following:

    That's it! The layout() method is extremely powerful as it can allow you to not only nest layouts but actually render a-la-carte layout/view combinations also.

    // executes before any action
    function preHandler( event, rc, prc, action, eventArguments ){
    }
    
    // executes before the list() action ONLY
    function preList( event, rc, prc, eventArguments ){
    }
    
    // concrete example
    function preHandler( event, rc, prc, action, eventArguments ){
        if( !security.isLoggedIn() ){
            event.overrideEvent( 'security.login' );
            log.info( "Unauthorized accessed detected!", getHTTPRequestData() );
        }
    }
    function preList( event, rc, prc, eventArguments ){
        log.info("Starting executing the list action");
    }
    // only fire for the actions: save(), delete()
    this.prehandler_only = "save,delete";
    // DO NOT fire for the actions: login(), doLogin(), logout()
    this.prehandler_except = "login,doLogin,logout"
    coldbox create app help
    component {
    
         function configure() {
    
             moduleSettings = {
                 myModule = {
                    someSetting = "overridden"
                 }
            };
        }
    }
    route( "blog/:year/:month?/:day?", "blog.index" );
    http://localhost/blog/2012/12/22 -> rc.year=2012, rc.month=12, rc.day=22
    http://localhost/blog/2012/12-> rc.year=2012, rc.month=12
    http://localhost/blog/2012-> rc.year=2012
    http://localhost/users => rc.format is null, does not exist
    http://localhost/users.json => rc.format = json
    http://localhost/users.xml => rc.format = xml
    http://localhost/users.pdf => rc.format = pdf
    http://localhost/users.html => rc.format = html
    function delete(event,rc,prc){
        // determine incoming http method
        if( event.getHTTPMethod() == "GET" ){
            flash.put("notice","invalid action");
            relocate("users.list");
        }
        else{
            // do delete here.
        }
    }
    // executes after any action
    function postHandler( event, rc, prc, action, eventArguments ){
    }
    
    // executes after the list() action ONLY
    function postList( event, rc, prc, eventArguments ){
    }
    
    // concrete examples
    function postHandler( event, rc, prc, action, eventArguments ){
        log.info("Finalized executing #action#");
    }
  • /Coldbox.cfc - Your application configuration object (optional )

  • /CacheBox.cfc - Your application CacheBox configuration (optional )

  • /Router.cfc - Your application URL Router (optional )

  • /Scheduler.cfc - Your application global task scheduler (optional)

  • /WireBox.cfc - Your application WireBox Configuration (optional )

  • /handlers - This holds the app's event handlers (controller layer)

  • /includes - For public assets, helpers and i18n resources

    • /css - This can hold your CSS (optional)

    • /js - This can hold your JavaScript (optional)

  • /layouts - Your HTML layouts (view layer)

  • /models - This holds your app's CFCs (model layer)

  • /modules - This holds the CommandBox tracked modules

  • /modules_app - This holds your app's modules

  • /tests - Your test harness, including unit and integration testing

    • /specs - Where your test bundles go

  • /views - Your HTML views will go here (view layer)

  • Execution Conventions

    ColdBox also has several execution conventions. This means that we have a convention or a default for the event, action, and layout to be used if you do not tell it what to use:

    Convention

    Default Value

    Description

    Default Event

    main.index

    The default event to execute when no event is specified

    Default Action

    index()

    The default action to execute in an event handler controller if none is specified

    Default Layout

    layouts/Main.cfm

    The default system layout to use

    Terminators - Finalizes the registration process usually by telling the router what happens when the route pattern is detected. This is refered to as the target.

    Please note that order of declaration of the routes is imperative. Order matters.

    Please remember to check out the latest API Docs for the latest methods and argument signatures.

    Initiators

    The following methods are used to initiate a route registration process.

    Please note that a route will not register unless a terminator is called or the inline target terminator is passed.

    • route( pattern, [target], [name=arguments.pattern] ) - Register a new route with optional target terminators and a name

    • get( pattern, [target], [name] ) - Register a new route with optional target terminators, a name and a GET http verb restriction

    • post( pattern, [target], [name] ) - Register a new route with optional target terminators, a name and a POST http verb restriction

    • put( pattern, [target], [name] ) - Register a new route with optional target terminators, a name and a PUT http verb restriction

    • patch( pattern, [target], [name] ) - Register a new route with optional target terminators, a name and a PATCH http verb restriction

    • options( pattern, [target], [name] ) - Register a new route with optional target terminators, a name and a OPTIONS http verb restriction

    • group( struct options, body ) - Group routes together with options that will be applied to all routes declared in the body closure/lambda.

    Modifiers

    Modifiers will tell the routing service about certain restrictions, conditions or locations for the routing process. It will not register the route just yet.

    • header( name, value, overwrite=true ) - attach a response header if the route matches

    • headers( map, overwrite=true ) - attach multiple response headers if the route matches

    • as( name ) - Register the route as a named route

    • rc( name, value, overwrite=true ) - Add an RC value if the route matched

    • rcAppend map, overwrite=true ) - Add multiple values to the RC collection if the route matched

    • prc( name, value, overwrite=true ) - Add an PRC value if the route matched

    • prcAppend map, overwrite=true ) - Add multiple values to the PRC collection if the route matched

    • withHandler( handler ) - Map the route to execute a handler

    • withAction( action ) - Map the route to execute a single action or a struct that represents verbs and actions

    • withModule( module ) - Map the route to a module

    • withNamespace( namespace ) - Map the route to a namespace

    • withSSL() - Force SSL

    • withCondition( condition ) - Apply a runtime closure/lambda enclosure

    • withDomain( domain ) - Map the route to a domain or subdomain

    • withVerbs( verbs ) - Restrict the route to listen to only these HTTP Verbs

    • packageResolver( toggle ) - Turn on/off convention for packages

    • valuePairTranslator( toggle ) - Turn on/off automatic name value pair translations

    Terminators

    Terminators finalize the routing process by registering the route in the Router.

    • end() - Register the route as it exists

    • toAction( action ) - Send the route to a specific action or RESTFul action struct

    • toView( view, layout, noLayout=false, viewModule, layoutModule ) - Send the route to a view/layout

    • toRedirect( target, statusCode=301 ) - Relocate the route to another event

    • to( event ) - Execute the event if the route matches

    • toHandler( handler ) - Execute the handler if the route matches

    • toResponse( body, statusCode=200, statusText="ok" ) - Inline response action

    • toModuleRouting( module ) - Send to the module router for evaluation

    • toNamespaceRouting( namespace ) - Send to the namespace router for evaluation

    Method

    Description

    setExtensionDetection( boolean )

    By default ColdBox detects URL extensions like json, xml, html, pdf which can allow you to build awesome RESTful web services. Default is true.

    setValidExtensions( list )

    Tell the interceptor what valid extensions your application can listen to. By default it listens to: json, jsont, xml, cfm, cfml, html, htm, rss, pdf

    setThrowOnInvalidExtensions( boolean )

    By default ColdBox does not throw an exception when an invalid extension is detected. If true, then the interceptor will throw a 406 Invalid Requested Format Extension: {extension} exception. Default is false.

    He has a geek love for circuits, microcontrollers, and overall embedded systems.
  • He has of late (during old age) become a fan of organic gardening.

  • www.luismajano.com
    ITESM
    Industrias Bendek S.A.
    MidAmerica Nazarene University
    http://www.codersrevolution.com
    named routes
    http://apidocs.ortussolutions.com/coldbox/current/index.html?coldbox/system/web/context/RequestContext.html

    modulePath

  • logBox

  • log

  • wirebox

  • binder

  • cachebox

  • getJavaSystem

  • getSystemSetting

  • getSystemProperty

  • getEnv

  • appRouter

  • router

  • getEnv

    ( key, defaultValue )

    Returns the server environment variable for key. Returns the defaultValue if it does not exist.

    ColdBox settings
    via dependency injection.
    relocate( "home" );
    relocate( event="shop", ssl=true );
    relocate( event="user.view", queryString="id=#rc.id#" );
    relocate( url="http://www.google.com" );
    relocate( uri="/docs/index.html" )
    global invalid HTTP
    //Layout Settings
    layoutSettings = {
        defaultLayout = "basic.cfm",
        defaultView   = "noview.cfm"
    }

    All of the data above plus:

    Executed after a view was rendered

    component{
    
        function postViewRender(event,interceptData){
            interceptData.renderedView = trim( interceptData.renderedView );
        }
    }
    //LogBox DSL
    logBox = {
        // The configuration file without fileextension to use for operation, instead of using this structure
        configFile = "config/LogBox", 
        // Appenders
        appenders = {
            appenderName = {
                class="class.to.appender", 
                layout="class.to.layout",
                levelMin=0,
                levelMax=4,
                properties={
                    name  = value,
                    prop2 = value 2
                }
        },
        // Root Logger
        root = {levelMin="FATAL", levelMax="DEBUG", appenders="*"},
        // Granualr Categories
        categories = {
            "coldbox.system" = { levelMin="FATAL", levelMax="INFO", appenders="*"},
            "model.security" = { levelMax="DEBUG", appenders="console"}
        }
        // Implicit categories
        debug  = ["coldbox.system.interceptors"],
        info   = ["model.class", "model2.class2"],
        warn   = ["model.class", "model2.class2"],
        error  = ["model.class", "model2.class2"],
        fatal  = ["model.class", "model2.class2"],
        off    = ["model.class", "model2.class2"]
    };
    LogBox Documentation

    The Rewrite rules section has another useful example for a pathInfo provider

    // Example PathInfoProvider for detecting a mobile request
    function PathInfoProvider( event ){
      var rc = event.getCollection();
      var prc = event.getCollection(private=true);
    
      local.URI = CGI.PATH_INFO;
    
      if (reFindNoCase('^/m',local.URI) == 0)
      {
        // Does not look like this could be a mobile request...
        return local.URI;
      }
    
      // Mobile Request? Let's find out.
    
      // If the URI is "/m" it is easy to determine that this is a
      // request for the Mobile Homepage.
      if (len(local.URI) == 2)
      {
        prc.mobile = true;
        // Simply return "/" since they want the mobile homepage
        return "/";
      }
    
      // Only continue with our mobile evaluation if we have a slash after
      // our "/m". Without a slash following the /m the route is something
      // else like coldbox.org/makes/cool/stuff
      if (REFindNoCase('^/m/',local.URI) == 1)
      {
        // Looks like we are mobile!
        prc.mobile = true;
    
        // Remove our "/m/" determination and continue
        // processing for languages...
        local.URI = REReplaceNoCase(local.URI,'^/m/','/');
      }
    
      // The URI starts with an "m" but does not look like
      // a mobile request. So, simply return the URI for normal
      // route detection...
      return local.URI;
    }

    Please note that the file argument can be an absolute path or an actual binary file to stream out.

    function report( event, rc, prc ){
        var prc.reportFile = reportService.createReport();
        
        event
            .sendFile(
                file = prc.reportFile,
                name = "UserReport.xls",
                deleteFile = true
            )
            .noRender();
    }
    Request Context's
    https://apidocs.ortussolutions.com/coldbox/6.6.1/coldbox/system/web/context/RequestContext.html#sendFile()

    ForgeBox : http://forgebox.io/view/cbvalidation

    box install cbvalidation
    https://github.com/coldbox/cbox-validation
    https://coldbox-validation.ortusbooks.com
    layout([any layout], [any module=''], [any view=''], [struct args={}], [any viewModule=''], [boolean prePostExempt='false'])
    <cfdocument pagetype="letter" format="pdf">
    
        <!---  Header --->
        <cfdocumentitem type="header">
        <cfoutput>
        <div>
        #dateformat(now(),"MMM DD, YYYY")# at #timeFormat(now(),"full")#
        </div>
        </cfoutput>
        </cfdocumentitem>
    
        <!---  Footer --->
        <cfdocumentitem type="footer">
        <cfoutput>
        <div>
        Page #cfdocument.currentpagenumber# of #cfdocument.totalpagecount#
        </div>
        </cfoutput>
        </cfdocumentitem>
    
        <!---  Main Content via nested layout --->
        <cfoutput>
        #layout(layout="basic")#
        </cfoutput>
    
    </cfdocument>
    hello.cfc
    inside of the
    handlers
    folder
  • A view called index.cfm in the views/hello folder

  • An integration test at tests/specs/integration/helloTest.cfc.

  • Default URL Routing

    Now go to your browser and enter the following URL to execute the generated event:

    You will now see a big hello.index outputted to the screen. You have now created your first handler and view combination. However, how did this work? It works by convention.

    Your application router is located at : config/Router.cfc. It will include a few default routes for you and the following default URL route:

    This route tells ColdBox to look for the names of handlers (including directory names) and names of the handler actions (functions). The ? on the :action portion denotes that the action might or might not exist in the URL. If it doesn't exist, then another convention is in play, the default action, which is index.

    So /main will execute main.index and /main/index will execute main.index

    Handler Code

    Let's check out the handler code:

    As you can see, a handler is a simple CFC with functions on them. Each function maps to an action that is executed via the URL. The default action in ColdBox is index()which receives three arguments:

    • event - An object that represents the request and can modify the response. We call this object the request context.

    • rc - A struct that contains both URL/FORM variables (unsafe data)

    • prc - A secondary struct that is private only settable from within your application (safe data)

    The event object is used for many things, in the case of this function we are calling a setView() method which tells the framework what view to render to the user once execution of the action terminates.

    Tip: The view is not rendered in line 7, but rendered after the execution of the action by the framework.

    Executing Events

    Did you detect a convention here?

    The sections in the URL are the same as the name of the event handler CFC (hello.cfc) and method that was generated index(). By convention, this is how you execute events in ColdBox by leveraging the following URL pattern that matches the name of a handler and action function.

    Tip : You can also nest handlers into folders and pass the name of the folder(s) as well.

    If no action is defined in the URL, then the default action of index will be used.

    All of this URL magic happens thanks to the URL mappings capabilities in ColdBox. By convention, you can write beautiful URLs that are RESTFul and by convention. You can also extend them and create more expressive URL Mappings by leveraging the config/Router.cfc which is your application router.

    Tip: Please see the event handlers guide for more in-depth information.

    My First Virtual Event

    Now let's create a virtual event, just a view we want to execute with no event handler controller needed. This is a great way to incorporate non-mvc files into ColdBox. Migrating from a traditional application?

    Open the view now (/views/virtual/hello.cfm) and add the following:

    Then go execute the virtual event:

    You will get the Hello From ColdBox Land! displayed! This is a great way to create tests or even bring in legacy/procedural templates into an MVC framework.

    Tip: You can see our layouts and views section for more in-depth information.

    What is a route?

    A route is a declared URL pattern that if matched it will translate the URL into one of the following:

    • A ColdBox event to execute

    • A View/Layout to render

    • A Reponse function to execute

    • A Redirection to occur

    It will also inspect the URL for placeholders and translate them into the incoming Request Collection variables (RC).

    Examples

    Routing Benefits

    There are several benefits that you will get by using our routing system:

    • Complete control of how URL's are built and managed

    • Ability to create or build URLs' dynamically

    • Technology hiding

    • Greater application portability

    • URL's are more descriptive and easier to remember

    Route Visualizer

    As you create route-heavy applications visualizing the routes will be challenging especially for HMVC apps with lots of modules. Just install our ColdBox Route Visualizer and you will be able to visually see, test and debug all your routing needs.

    Tip : The request context can also be used to render a view with NO layout at all via the event.noLayout() method or event.setView( noLayout: true )

    Layout Code

    The layout has everything you want to wrap views or other layouts with. You can use our rendering methods to do inline renderings or tell ColdBox where the set view should render:

    • view() - Render the set view via event.setView()

    • view( name: "toolbar" ) - Render a named view

    • view( "partials/footer" ) - Render a explicit view

    • layout( name ) - Render another layout within this layout

    The call to the view() method with no arguments tells the framework to render the view that was set using event.setView(). This is called a rendering region. You can use as many rendering regions within layouts or views.

    Named Regions: The setView() method even allows you to name these regions and then render them in any layout or other views using the name argument.

    Creating A Layout

    Let's create a new simple layout with two rendering regions. Open up CommandBox and issue the following commands:

    Open the layouts/Funky.cfm layout and let's modify it a bit by adding the footer view as a rendering region.

    Now let's do our footer:

    Settings

    As you can see from the footer, we introduced a new function called getSetting() . All layouts, handlers, interceptors, and views inherit the Framework Super Type functionality. There are tons of methods inherited from this class that you can use in your application, from getting models to settings, relocating, async computations, and so much more.

    Using The Layout

    Now, let's open the handler we created before, called handlers/hello.cfc and add some code to use our new layout explicitly by adding a layout argument to our setView() call.

    Go execute the event now: http://localhost:{port}/hello/index and you will see the view rendered with the words funky layout and footer view at the bottom. Eureka, you have now created a layout.

    You can also leverage the function event.setLayout( "Funky" ) to change layouts and even concatenate the calls:

    event .setView( "hello/index" ) .setLayout( "Funky" );

    method and the
    name
    argument
  • Using the as() method

  • If you do not pass the name argument to the route() method, we will use the pattern as the name of the route.

    Generating URLs to Named Routes

    You will generate URLs to named routes by leveraging the route() method in the request context object (event).

    Let's say you register the following named routes:

    Then we can create routing URLs to them easily with the event.route() method:

    Inspecting The Current Route

    The request context object (event) also has some handy methods to tell you the name or even the current route that was selected for execution:

    • getCurrentRouteName() - Gives you the name of the current route, if any

    • getCurrentRoute() - Gives you the currently executed route

    • getCurrentRoutedURL() - Gives you the complete routed URL pattern that matched the route

    • getCurrentRoutedNamespace() - Gives you the current routed namespace, if any

    Just like you can create links based on named routes and params, you can execute named routes and params as well internally via runRoute()

    Parameters

    The params argument you pass to the runRoute() method will be translated into event arguments. Therefore they will be passed as arguments to the event the route represents:

    In the example above, the userData named route points to the user.data event.

    Module Routes

    If you want to execute module routes, no problem! Just use our @ or : notation to tell the controller from which module's router we should pick the route from.

    // Execute
    runRoute( "userData", { id=4 } )
    # Using @ destination
    runRoute( "userData@user", { id=4 } )
    
    # Using : prefix
    runRoute( "user:userData", { id=4 } )
    Producing JSON

    If you know beforehand what type of format you will be responding with, you can leverage ColdBox auto-marshaling in your handlers. By default, ColdBox detects any return value from handlers, and if they are complex, it will convert them to JSON automatically for you:

    ColdBox detects the array and automatically serializes it to JSON. Easy Peasy!

    renderData()

    The request context object has a special function called renderData() that can take any type of data and marshall (convert) it for you to other formats like xml, json, wddx, pdf, text, html or your own type.

    Tip: You can find more information at the API Docs for renderData() here http://apidocs.ortussolutions.com/coldbox/current/index.html?coldbox/system/web/context/RequestContext.html#renderData()

    So let's open the handlers/contacts.cfc and lets create a new action called data

    This tells ColdBox to render the contacts data in 4 formats: XML, JSON, pdf, and HTML. WOW! So how would you trigger each format? Via the URL, of course.

    Format Detection

    ColdBox has the ability to detect formats via URL extensions or an incoming Accepts header. If no extension is sent, then ColdBox attempts to determine the format by inspecting the Accepts header. If we still can't figure out what format to choose, the default of html is selected for you.

    Tip: You can also avoid the extension and pass a URL argument called format with the correct format type: ?format=json.

    Routing

    Let's add a new route to our system that is more RESTFul than /contacts/index.json. You will do so by leveraging the application's router found at config/Router.cfc. Find the configure() method, and let's add a new route:

    We have registered the API route and also defaulted the format to JSON. Try it out.

    Make sure you add routes above the default ColdBox route. If not, your route will never fire.

    Tip: Every time you add new routes, make sure you reinit the application: http://localhost:{port}/?fwreinit.

    You can now visit the new URL pattern, and you have successfully built a RESTFul API for your contacts.

    You can find much more about routing in our full docs

    full docs.

    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

  • collectionDelim : An optional delimiter to use to separate the collection renderings. By default it is empty.

  • Once you call view() with a collection, the renderer will render the view once for each member in the collection. The views have access to the collection via arguments.collection or the member currently iterating. The name of the member being iterated as is by convention the same name as the view. So if we do this in any layout or simple view:

    Then the tags/comment will be rendered as many times as the collection rc.comments has members on it and by convention the name of the variable is comment the same as the view name.

    If you don't like that, then use the collectionAs argument:

    So let's see the collection view now:

    You can see that I just call methods on the member as if I was looping (which we are for you). But you will also see two little variables here:

    • _counter : A variable created for you that tells you in which record we are currently looping on

    • _items : A variable created for you that tells you how many records exist in the collection

    This will then render that specific dynamic HTML view as many times as their are records in the rc.comments array and concatenate them all for you. In my case, I separate each iteration with a simple but you can get fancy and creative.

    #view(view='tags/comment',collection=rc.comments)#
    but on an event-driven framework.

    This event has an extra argument: missingAction which is the missing action that was requested. You can then do any kind of logic against this missing action and decide to do internal processing, error handling or anything you like. The power of this convention method is extraordinary, you have tons of possibilities as you can create virtual events on specific event handlers.

    onError()

    This is a localized error handler for your event handler. If any type of runtime error occurs in an event handler and this method exists, then the framework will call your method so you can process the error first. If the method does not exist, then normal error procedures ensue.

    Please note that compile time errors will not fire this method, only runtime exceptions.

    onInvalidHTTPMethod()

    This method will be called for you if a request is trying to execute an action in your handler without the proper approved HTTP Verb. It will then be your job to determine what to do next:

    function onMissingAction( event, rc, prc, missingAction, eventArguments ){
    
    }
    /**
     * Builds links to events or URL Routes
     *
     * @to          The event or route path you want to create the link to
     * @queryString The query string to append which can be a regular query string string, or a struct of name-value pairs
     * @translate   Translate between . to / depending on the SES mode on to and queryString arguments. Defaults to true.
     * @ssl         Turn SSl on/off on URL creation, by default is SSL is enabled, we will use it.
     * @baseURL     If not using SES, you can use this argument to create your own base url apart from the default of index.cfm. Example: https://mysample.com/index.cfm
     */
    string function buildLink(
    	to,
    	queryString       = "",
    	boolean translate = true,
    	boolean ssl,
    	baseURL = ""
    )
    
    
    /**
     * 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` or prefix it like in run event calls `moduleName:routeName` 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 - If thre requested route name is not registered
     */
    string function route( required name, struct params = {}, boolean ssl )
    
    <cfoutput>
        <h1>Hello from ColdBox Land!</h1>
        <p><a href="#event.buildLink( "main" )#">Go home</a></p>
    </cfoutput>
    <form action="#event.buildLink( 'user.save' )#" method="post">
    ...
    </form>
    // @app_routes@
    
    route( "/home" ).as( "home" ).to( "main.index" );
    
    // Conventions-Based Routing
    route( ":handler/:action?" ).end();
    <cfoutput>
        <h1>Hello from ColdBox Land!</h1>
        <p><a href="#event.route( "home" )#">Go home</a></p>
    </cfoutput>
    component{
    
        function configure( original ){
            return {
                key : value
            };
        }
    
    }
    component{
    
        function configure( original ){
            // override only specific keys, not the entire config
    	original.users.requireEmailVerification = false;
    	return original;
        }
    
    }
    function development( original ){
       // add overides to the original struct
    }
    route( "/blog/:year-numeric/:month-numeric/:day-numeric" );
    route( "/blog/:year-numeric/:month-numeric" );
    route( "/blog/:year-numeric/" );
    route( "/blog/" );
    route( "/blog/:year-numeric?/:month-numeric?/:day-numeric?" );
    route( "blog/:year-numeric/:month-numeric?/:day-numeric?", "blog.index" );
    route( "wiki/:page-alpha", "wiki.show" );
    // route with regex placeholders
    route(
        pattern="/api/:format-regex:(xml|json)/",
        target="api.execute"
    );
    // route with custom constraints
    route(
        pattern = "/api/:format/:entryID",
        target  = "api.execute"
    ).constraints( {
        format  = "(xml|json)",
        entryID = "([0-9]{4})" 
    } );
    Application.cfc
    
    component {
    
        variables.env = new coldbox.system.core.delegates.Env();
    
        this.datasources[ "my_datasource" ] = {
            driver = env.getSystemSetting( "DB_DRIVER" ),
            host = env.getSystemSetting( "DB_HOST" ),
            port = env.getSystemSetting( "DB_PORT" ),
            database = env.getSystemSetting( "DB_DATABASE" ),
            username = env.getSystemSetting( "DB_USERNAME" ),
            password = env.getSystemSetting( "DB_PASSWORD" )
        };
    
    }
    this.allowedMethods = {
        actionName : "List of approved HTTP Verbs"
    };
    component{
    
        this.allowedMethods = {
            delete : "POST,DELETE",
            list   : "GET"
        };
    
        function list(event,rc,prc){
            // list only
        }
    
        function delete(event,rc,prc){
            // do delete here.
        }
    }
    function index( event, rc, prc) allowedMethods="GET,POST"{
        // my code here
    }
    /**
     * This method will send a file to the browser or requested HTTP protocol according to arguments.
     * CF11+ Compatibility
     *
     * @file The absolute path to the file or a binary file to send
     * @name The name to send to the browser via content disposition header.  If not provided then the name of the file or a UUID for a binary file will be used
     * @mimeType A valid mime type to use.  If not passed, then we will try to use one according to file type
     * @disposition The browser content disposition (attachment/inline) header
     * @abortAtEnd If true, then this method will do a hard abort, we do not recommend this, prefer the event.noRender() for a graceful abort.
     * @extension Only used for binary files which types are not determined.
     * @deleteFile Delete the file after it has been streamed to the user. Only used if file is not binary.
     */
    function sendFile(
        file="",
        name="",
        mimeType="",
        disposition="attachment",
        boolean abortAtEnd="false",
        extension="",
        boolean deleteFile=false
    )
    coldbox create handler name="hello" actions="index" --open
    # With rewrites enabled
    http://localhost:{port}/hello/index
    // Conventions based routing
    route( ":handler/:action?" ).end();
    component{
    
        /**
         * Default Action
         */
         function index( event, rc, prc ){
            event.setView( "hello/index" );
         }
    
    
    }
    http://localhost:{port}/folder/handler/action
    http://localhost:{port}/handler/action
    http://localhost:{port}/handler
    coldbox create view name="virtual/hello" --open
    <h1>Hello from ColdBox Land!</h1>
    http://localhost:{port}/virtual/hello
    // Old Style
    http://localhost/index.cfm?event=home.about&page=2
    http://localhost/index.cfm?city=24&page=3&county=234324324
    // New Routing Style
    http://localhost/home/about/page/2
    http://localhost/dade/miami/page/3
    config/Router.cfc
    function configure(){
    
        // Routing with placeholders to an event with placeholders
        route( "/blog/:year-numeric{4}/:month?/:day?" )
            .to( "blog.list" );
    
        // Redirects
        route( "/old/book" )
            .toRedirect( "/mybook" );
    
        // Responses
        route( "/echo" ).toResponse( (event,rc,prc) => {
            return "hello luis";
        } );
    
        // Shortcut to above
        route( "/echo", (event,rc,prc) => {
            return "hello luis";
        } );
    
        // Show view
        route( "/contact-us" )
            .toView( "main/contact" );
    
        // Direct to handler with action from URL
        route( "/users/:action" )
            .toHandler( "users" );
    
        // Inline pattern + target and name
        route( pattern="/wiki/:page", target="wiki.show", name="wikipage" );
    
    }
    box install route-visualizer
    <div id="maincontent">
    #view()#
    </div>
    # Create a Funky layout
    coldbox create layout name="Funky" --open
    
    # Create a footer
    coldbox create view name="main/footer" --open
    <cfoutput>
    <!DOCTYPE html>
    <html lang="en">
        <head></head>
        <body>
            <h1>funky Layout</h1>
            <div class="container">
                #view()#
            </div>
            <hr>
            #view( "main/footer" )#
        </body>
    </html>
    </cfoutput>
    <cfoutput>
    <small>I am a funky footer generated at #now()# running in #getSetting( 'environment' )#</small>
    </cfoutput>
    function index( event, rc, prc ){
        // param an incoming variable.
        event.paramValue( "name", "nobody" );
        // set a private variable
        prc.when = dateFormat( now(), "full" );
    
        // set the view to render with our new layout
        event.setView( view="hello/index", layout="Funky" );
        // or we can do this:
        // event.setView( "hello/index" ).setLayout( "Funky" );
    }
    // Using the pattern by convention
    route( pattern="/healthcheck" ).to( "healthcheck" );
    
    // Using the name argument
    route( 
        pattern = "/users/list", 
        target = "users.index", 
        name = "usermanager" 
    );
    
    route( 
        pattern = "/user/:id/profile", 
        target = "users.show", 
        name = "userprofile"
    );
    
    // Using the as() method
    route( "/users/:id/profile" )
      .as( "usersprofile" )
      .to( "users.show" )
    route(
        // The name of the route
        required name,
        // The params to pass, can be a struct or array
        struct params={},
        // Force or un-force SSL, by default we keep the same protocol of the request
        boolean ssl
    );
    route( 
        pattern = "/users/list", 
        target = "users.index", 
        name = "usermanager" 
    );
    
    route( 
        pattern = "/user/:id/profile", 
        target = "users.show", 
        name = "userprofile"
    );
    <!-- Named Route with no params -->
    <a href="#event.route( 'usermanager' )#">Manage Users</a>
    
    <!-- Named Route with struct params -->
    <a href="#event.route( 'userprofile', { id = 3 } )#">View User</a>
    
    <!-- Named Route with array params -->
    <a href="#event.route( 'userprofile', [ 3 ] )#">View User</a>
    
    <a href="#event.route( '/healthcheck' )#">Health check</a>
    /**
     * Executes internal named routes with or without parameters. If the named route is not found or the route has no event to execute then this method will throw an `InvalidArgumentException`.
     * If you need a route from a module then append the module address: `@moduleName` or prefix it like in run event calls `moduleName:routeName` in order to find the right route.
     * The route params will be passed to events as action arguments much how eventArguments work.
     *
     * @name The name of the route
     * @params The parameters of the route to replace
     * @cache Cached the output of the runnable execution, defaults to false. A unique key will be created according to event string + arguments.
     * @cacheTimeout The time in minutes to cache the results
     * @cacheLastAccessTimeout The time in minutes the results will be removed from cache if idle or requested
     * @cacheSuffix The suffix to add into the cache entry for this event rendering
     * @cacheProvider The provider to cache this event rendering in, defaults to 'template'
     * @prePostExempt If true, pre/post handlers will not be fired. Defaults to false
     *
     * @throws InvalidArgumentException
     */
    any function runRoute(
    	required name,
    	struct params={},
    	boolean cache=false,
    	cacheTimeout="",
    	cacheLastAccessTimeout="",
    	cacheSuffix="",
    	cacheProvider="template",
    	boolean prePostExempt=false
    )
    user.cfc
    component{
    
        property name="userService" inject;
    
        function data( event, rc, prc, id=0 ){
            if( id == 0 )
                return {};
                
            return userService.getData( id );
        }
    }
    contacts.cfc
    any function data( event, rc, prc ){
        return contactService.getAll();    
    }
    contacts.cfc
    any function data( event, rc, prc ){
        prc.aContacts = contactService.getAll();    
        event.renderData( data=prc.aContacts, formats="xml,json,pdf" );
    }
    # Default: The view is presented using no extension or html,cfm
    http://localhost:{port}/contacts/index
    http://localhost:{port}/contacts/index.html
    http://localhost:{port}/contacts/index.cfm
    
    # JSON output
    http://localhost:{port}/contacts/index.json
    # OR Accepts: application/json
    
    # XML output 
    http://localhost:{port}/contacts/index.xml
    # OR Accepts: application/xml
    
    # PDF output
    http://localhost:{port}/contacts/index.pdf
    # OR Accepts: application/pdf
    
    // Restuful Route
    route( "/api/contacts" )
        .as( "api.contacts" )
        .rc( "format", "json" )
        .to( "contacts.data" );
    
    // Default Route
    route( ":handler/:action?" ).end();
    http://localhost:{port}/api/contacts.json
    <h1>Title: #comment.Title# (#_counter# of #_items#</h1>
    <p>Author: #comment.Author#</p>
    #comment.Comment#
    <hr/>
    #view(view='tags/comment',collection=rc.comments,collectionAs='MyComment')#
    <h1>Title: #MyComment.Title# (#_counter# of #_items#</h1>
    <p>Author: #MyComment.Author#</p>
    #MyComment.Comment#
    <hr/>
    #view(view="home/news", collection=prc.news, collectionStartRow=11, collectionMaxRows=20)#
    // On Error
    function onError( event, rc, prc, faultAction, exception, eventArguments ){
        // prepare a data packet
        var data = {
            error = true,
            messages = exception.message & exception.detail,
            data = ""
        }
    
        // log via the log variable already prepared by ColdBox
        log.error("Exception when executing #arguments.faultAction# #data.messages#", exception);    
    
        // render out a json packet according to specs status codes and messages
        event.renderData(data=data,type="json",statusCode=500,statusMessage="Error ocurred");
    
    }
    function onInvalidHTTPMethod( faultAction, event, rc, prc ){
        return "Go away!";
    }

    A folder containing a template: /opt/shared/templates/my-template

  • A zip file containing the template: /opt/shared/templates/my-template.zip

  • Elixir

    elixir

    The default template with ColdBox elixir support for asset pipelines

    Modern (experimental)

    modern

    A fresh new approach to ColdBox applications that are non-root based. Still experimental

    Rest

    rest

    A base REST API using ColdBox

    Rest HMVC

    rest-hmvc

    An HMVC REST API using modules

    Super Simple

    supersimple

    Barebones conventions baby!

    http://myapptemplates.com/template.zip

    event={package}.{handler}.{action} : Packaged notation

  • event={module}:{package}.{handler}.{action} : Module Notation (See ColdBox Modules)

  • configuration directive
    URL mapping routing
    • Model - Business Logic, Data, Queries, Etc

    • View - Representation of your models, queries, data.

    • Controller - Orchestrator of client request to the appropriate models and views

    Let's go a little deeper.

    Model

    The Model is the heart of your application. Your business logic should mostly live here in the form of services, beans, entities and DAOs. A dependency injection framework becomes invaluable when dealing with object oriented model layers: WireBox (Dependency Injection Framework) is the framework of choice for dependency injection and aspect oriented programming.

    Views

    The Views are what the users see and interact with. They are the templates used to render your application out for the web browser. Typically this means cfm/HTML, but it can also be JSON, XML, data views, etc.

    In modern times, your views can even be pure HTML with a combination of a JavaScript MVC framework. The major players in the MVC front-end world that we would recommend in order of personal preference:

    • VueJS - https://vuejs.org/

    • Angular - https://angular.io/

    • ReactJS - https://reactjs.org/

    • EmberJS -

    Controllers

    Controllers are the traffic cops of your application. They direct flow control, and interface directly without incoming parameters from FORM and URL scopes. It is the controllerโ€™s job to communicate with the appropriate models for processing, and set up either a view to display results or return serialized data like JSON, XML, PDF, etc.

    Benefits of MVC

    By implementing an MVC Framework to your applications you will gain several benefits that come inherent to the MVC design pattern. The most important benefit of MVC is that you will be separating the presentation from the model. This is a very important heuristic of software development as separation of concerns is applied and responsibilities are delegated upon the layers.

    Separation of Concerns

    The model and the view layers have different concerns about their implementations. A view layer is concerned with how to render the data, the type of browser, or remote rendering, etc. While the model is more concerned with the business rules of the application, how to store data and even database operations. You use different development approaches to each layer.

    Multiple GUIโ€™s

    Due to this separation, you can easily create multiple views for the same model data without affecting how the model works or is coded. The view layers can adapt to the model by coding their own implementations. This makes it really easy to create multiple GUIโ€™s for applications.

    Unit and Behavioral Testing

    Non-visual objects are easier to test than visual objects, in theory. With the introduction of Selenium, integration and visual UI testing has become rather simple. However, the key benefit here is that testing can be done separately. Frameworks like ColdBox even give you the ability to do UI and integration testing within its domain.

    Dependency

    The most important benefit that we can arise out of the MVC pattern, is the direction of the dependencies. A view depends on its model data and controller, but the model itself does not depend on the view or controllers. This is how you want to build your business logic, encapsulated and providing a good API.

    Evolution of MVC Architecture

    There are many types of MVC architectures and hopefully the following diagrams can help you in the progression from spaghetti hell to the most complex MVC architecture using an ORM or Object Relational Mapper.

    Spaghetti Hell

    As you can see from the spaghetti hell diagram above, everything is linear and can become extremely convoluted. Tracking bugs are difficult, maintenance suffers and reusability is not efficient. Everything is in the same bowl of soup.

    MVC

    With the introduction of MVC we can hack away our spaghetti hell and at least have three distinct and separate layers of logic. Ahh much better. However, we can get even more complex.

    MVC Plus

    MVC Plus shows us how you can further partition your model layer into more layers. We can identify now a layer of service CFCs and data access object CFCs. The main transportation of data between these layers by default is implied to be ColdFusion Query objects.

    MVC Plus Objects

    In this architecture approach, we have replaced (mostly) queries as our data structure of preference and converted to the usage of business objects. We are approaching a more object oriented architectural style. Remember that data is just data, objects are data plus behavior. We can encapsulate more features and abstract more behavior into actual objects now, which we could not do with queries.

    MVC Plus ORM

    In this architecture approach we have replaced business objects for ORM entities and replaced our data access layer to be controlled now by the ORM. This takes us very deep into object oriented land where the majority of our model is now modeled vi relational objects.

    Stern Warning: ORMs are NOT silver bullets. They are an incredible tool that must be used for the right reasons and at the right time. Do not be confused in that you must ONLY use the ORM. No, you can still use DAOs and queries for certain things that matter. You do not need to retrieve entire object graph collections if NOT needed.

    We have even build a companion package for ColdBox called cborm that will help you build more pragmatic and enjoyable ORM applications.

    More Resources

    • โ€‹http://en.wikipedia.org/wiki/Domain_modelโ€‹

    • โ€‹http://domaindrivendesign.org/โ€‹

    • โ€‹http://martinfowler.com/eaaCatalog/domainModel.htmlโ€‹

    Wikipedia
    Model View Controller

    Sublime - https://packagecontrol.io/packages/ColdBox Platform

  • VSCode - https://marketplace.visualstudio.com/items?itemName=ortus-solutions.vscode-coldbox

  • CommandBox CLI

    The first step in our journey is to install CommandBox. CommandBox is a ColdFusion (CFML) Command Line Interface (CLI), REPL, Package Manager, and Embedded Server. We will be using CommandBox for almost every exercise in this book, and it will also allow you to get up and running with ColdFusion and ColdBox in a much speedier manner.

    Download CommandBox

    You can download CommandBox from the official site: https://www.ortussolutions.com/products/commandbox#download and install on your preferred Operating System (Windows, Mac, *unix). CommandBox comes in two flavors:

    1. No Java Runtime (30mb)

    2. Embedded Runtime (80mb)

    So make sure you choose your desired installation path and follow the instructions here: https://commandbox.ortusbooks.com/setup/installation

    Starting CommandBox

    Once you download and expand CommandBox, you will have the box.exe or box binary, which you can place in your Windows Path or *Unix /usr/bin folder to have it available system-wide. Then open the binary, and CommandBox will unpack to your user's directory: {User}/.CommandBox. This happens only once, and the next thing you know, you are in the CommandBox interactive shell!

    CommandBox Shell

    We can execute a-la-carte commands from our command line or go into the interactive shell for multiple commands. We recommend the interactive shell as it is faster and can remain open in your project root.

    All examples in this book are based on having an interactive shell open.

    Installing ColdBox CLI

    We can now use CommandBox to install the ColdBox CLI to assist us in all aspects of ColdBox Development:

    You will now have a coldbox command namespace. You can do coldbox help and get all the help you need with the commands.

    Installing ColdBox

    To get started, open the CommandBox binary or enter the shell by typing box in your terminal or console. Then let's create a new folder and install ColdBox into a directory.

    CommandBox will resolve coldbox from ForgeBox (www.forgebox.io); use the latest version available, and download and install it in this folder alongside a box.json file that represents your application package.

    Tip : You can also install the latest bleeding-edge version by using the coldbox@be slug instead, or any previous version.

    CommandBox can now track this version of ColdBox for you in this directory. In the next section we will scaffold a ColdBox application using an application template.

    You can find many scaffolding templates for ColdBox in our Github organization: github.com/coldbox-templates

    Uninstalling ColdBox

    To uninstall ColdBox from this application folder, just type uninstall coldbox. Try it out!

    Updating ColdBox

    To update ColdBox from a previous version, just type update coldbox.

    Star
    ConfigSettings : Your application settings

    You can use the following methods to retrieve/set/validate settings in your handlers/layouts/views and interceptors:

    You can also get access to these methods in handlers via the ColdBox Controller component:

    or using the application scope from modules and other locations where controller isn't injected:

    Injecting Settings

    You can use the WireBox injection DSL to inject settings in your models or non-ColdBox objects. Below are the available DSL notations:

    • coldbox:setting:{key} : Inject a specified config setting key

    • coldbox:coldboxSetting:{key} : Inject a specified ColdBox setting key

    • coldbox:configSettings : Inject a reference to the application settings structure

    • coldbox:coldboxSettings : Inject a reference to the ColdBox System settings structure

    controller.getSetting()
    controller.getColdBoxSetting()
    controller.setSetting()
    controller.settingExists()
    controller.getConfigSettings()
    controller.getColdBoxSettings()

    coldboxVersion

    The version of the framework

    controller

    The ColdBox running app controller

    logBoxConfig

    A reference to a LogBox configuration object

    getJavaSystem()

    Function to get access to the java system

    getSystemSetting()

    Retrieve a Java System property or env value by name. It looks at properties first then environment variables

    getSystemProperty()

    Retrieve a Java System property value by key

    getEnv()

    Retrieve a Java System environment value by name

    webMapping

    The application's web mapping

    Configuration Storage

    Once the application starts up, a reference to the instantiated configuration CFC will be stored in the configuration settings inside the ColdBox Main Controller (application.cbController) with the key coldboxConfig. You can then retrieve it later in your handlers, interceptors, modules, etc if you need to.

    Configuration Interceptor

    ColdBox Event Listeners

    Another cool concept for the Configuration CFC is that it is also registered as a ColdBox Interceptor once the application starts up automatically for you. You can create functions that will listen to application events by simply registering them by name:

    Note that the config CFC does not have the same variables mixed into it that a "normal" interceptor has. You can still access everything you need, but will need to get it from the controller in the variables scope.

    Property

    Description

    appMapping

    The ColdBox app mapping

    ColdBox Interceptor
    ColdBox.cfc EcoSystem

    pre{action}()

    Executes before the {action} requested ONLY

    postHandler()

    Executes after any requested action (In the same handler CFC)

    post{action}()

    Executes after the {action} requested ONLY

    aroundHandler()

    Executes around any request action (In the same handler CFC)

    around{action}()

    Executes around the {action} requested ONLY

    Interceptor Method

    Description

    preHandler()

    Executes before any requested action (In the same handler CFC)

    AOP
    Aspect Oriented Programming
    // only fire for the actions: save(), delete()
    this.posthandler_only = "save,delete";
    // DO NOT fire for the actions: login(), doLogin(), logout()
    this.posthandler_except = "login,doLogin,logout"

    View Caching

    You can also pass in the caching arguments below and your view will be rendered once and then cached for further renderings. Every ColdBox application has two active cache regions: default and template. All view and event caching renderings go into the template cache.

    Argument

    Type

    Required

    Default

    Description

    cache

    boolean

    Purging Views

    So now that our views are cached, how do I purge them programmatically? Well, you need to talk to the template cache provider and use the clearing methods:

    Then we can perform several operations on views:

    • clearView(string viewSnippet): Used to clear a view from the cache by using a snippet matched according to name + cache suffix.

    • clearMultiView(any viewSnippets): Clear using a list or array of view snippets.

    • clearAllViews([boolean async=true]) : Can clear ALL cached views in one shot and can be run asynchronously.

    Disable View Caching

    To turn off view caching for your entire application, set the viewCaching setting to false in your config/Coldbox.cfc config file.

    Viewlets - Reusable Events

    A viewlet is a self sufficient view or a widget that can live on its own, its data is pre-fetched and can just be renderer anywhere in your system.

    What in the world is this? Well, imagine a portal, in which each section of the portal is self-sufficient, with controls and data. You don't want to call all the handlers for this data for every single piece of content. It's not efficient, you need to create a separation. Well, a viewlet is such a separation that provides you with the ability to create reusable events. So how do we achieve this?

    1. You will use the method runEvent() anywhere you want a viewlet to be displayed or the content rendered. This calls an internal event that will be in charge to prepare and render the viewlet.

    2. Create the portable event but make sure it returns the produced content.

    Simple Example

    This code just renders out the results of a runEvent() method call. Please note that you can pass in arguments to the event using the eventArguments argument. This makes the event act like a method call with arguments to it. Remember that all events you call via runEvent() will share the same RC/PRC.

    I would suggest you look at to discover all arguments to the runEvent() method call.

    Event Code

    As you can see from the code above, the handler signature can accept arguments which are passed via the eventArguments structure. It talks to a service layer and place some data on the private request collection the viewlet will use. It then returns the results of a view() call that will render out the exact viewlet I want. You can be more creative and do things like:

    • render a layout + view combo

    • render data

    • return your own custom strings

    • etc

    Caution We would suggest you namespace or prefix your private request collection variables for viewlets in order to avoid collisions from multiple viewlet events in the same execution thread or instead pass the necessary arguments into a view via the args argument.

    View Code

    The view is a normal standard view, it doesn't even know it is a viewlet, remember, views are DUMB!

    Content Variables

    A content variable is a variable that contains HTML/XML or any kind of visual content that can easily be rendered anywhere. So instead of running the viewlet event in the view, you can abstract it to the controller layer and assign the output to a content variable:

    So how do I render it?

    Another example, is what if we do not know if the content variable will actually exist? How can we do this? Well, we use the event object for this and its magic getValue() method.

    So now, if no content variable exists, an empty string will be rendered.

    Important String manipulation in Java relies on immutable structures, so performance penalties might ensue. If you will be doing a lot of string manipulation, concatenation or rendering, try to leverage native java objects: StringBuilder or StringBuffer

    Executing Events

    Apart from executing events from the URL/FORM or Remote interfaces, you can also execute events internally, either public or private from within your event handlers or from interceptors, other handlers, layouts or views.

    RunEvent()

    You do this by using the runEvent() method which is inherited from our FrameworkSuperType class. Here is the method signature:

    The interesting aspect of internal executions is that all the same rules apply, so your handlers can return content like widgets, views, or even data. Also, the eventArguments enables you to pass arguments to the method just like method calls:

    Executions

    Declaration

    Caching

    As you can see from the function signature you can tell ColdBox to cache the result of the event call. All of the cached content will go into the template cache by default unless you use the cacheProvider argument. The cache keys are also based on the name of the event and the signature of the eventArguments structure. Meaning, the framework can cache multiple permutations of the same event call as long as the eventArguments are different.

    Tip: You can disable event caching by using the coldbox.eventCaching directive in your config/ColdBox.cfc

    Setting Views

    Views (Default Layout)

    The event object is the object that will let you set the views that you want to render, so please explore its API in the CFC Docs. To quickly set a view to render, do the following:

    The view name is the name of the template in the views directory without appending the .cfm. If the view is inside another directory, you would do this:

    The views you set will use the default layout defined in your configuration file which by default is the layouts/Main.cfm

    We recommend that you set your views following the naming convention of your event. If your event is users.index, your view should be users/index. This will go a long way with maintainability and consistency and also will activate implicit views where you don't even have to use the set view method call.

    View With Custom Layouts

    You can also use the setView(), setLayout() methods to tell the framework which view and layout combination to use:

    Views With No Layout

    You can also tell the framework to set a view for rendering by itself with no layout using the noLayout argument

    setView() Arguments

    Here are the arguments for the setView() method:

    Cached Views

    You can leverage the caching arguments in the setView() method in order to render and cache the output of the views once the framework renders it. These cached views will be stored in the template cache region, which you can retrieve or purge by talking to it: getCache( 'template' ).

    View Arguments

    Data can be passed from your handler to the view via rc or prc. If you want to pass data to a view without polluting rc and prc, you can pass it directly via the args parameter, much like a method call.

    Access the data in the view like so:

    No Rendering

    If you don't want to, you don't have to. The framework gives you a method in the event object that you can use if this specific request should just terminate gracefully and not render anything at all. All you need to do is use the event object to call on the noRender() method and it will present to the user a lovely white page of death.

    Working with Events

    Event handlers are the controller layer in ColdBox and is what you will be executing via the URLor a FORMpost. All event handlers are singletons, which means they are cached for the duration of the application, so always remember to var scope your variables in your functions.

    Tip: For development we highly encourage you to turn handler caching off or you will have to reinit the application in every request, which is annoying. Open the config/ColdBox.cfc

    Layouts & Views

    ColdBox's flexible layout manager and content renderer system. Create beautiful, dynamic layouts and views with powerful rendering mechanisms for HTML, JSON, XML and more.

    ColdBox provides you with a very simple but flexible and powerful layout manager and content renderer. You no longer need to create module tags or convoluted broken up HTML anymore. You can concentrate on the big picture and create as many as your application needs. Then you can programmatically change rendering schemas (or skinning) and also create composite or component based views.

    In this section we will explore the different rendering mechanisms that ColdBox offers and also how to utilize them. As you know, are our controller layer in ColdBox and we will explore how these objects can interact with the user in order to render content, whether HTML, JSON, XML or any type of rendering data.

    Please note that you can use ColdBox as a pure API solution with modern JavaScript frameworks for the front end like VueJS, Reactor, Angular, etc.

    Installation

    Get up and running with ColdBox easily.

    Welcome to the world of ColdBox!

    We are excited you are taking this development journey with us. Before we get started with ColdBox let's install CommandBox CLI, which will allow you to install/uninstall dependencies, start servers, have a REPL tool and much more.

    Requirements

    Please note that the supported CFML engines can change from major version to major version. Always verify them in the

    Around Advices

    Around advices are the most powerful of all as you completely hijack the requested action with your own action that looks, smells and feels exactly as the requested action. This is usually referred to as a

    This will allow you to run both before and after advices but also surround the method call with whatever logic you want like transactions, try/catch blocks, locks or even decide to NOT execute the action at all.

    You can do it globally by using the aroundHandler() method or targeted to a specific action around{actionName}().

    Environments

    The configuration CFC has embedded environment control and detection built-in. Environments can be detected by:

    • regex matching against cgi.http_host

    • detection of an environmental variable called ENVIRONMENT ( Coldbox 5.2 and higher )

    • usage of a detectEnvironment()

    event={module:}{package.}{handler}{.action}
    // Call the users.cfc index() method
    index.cfm?event=users.index
    // Call the users.cfc index() method implicitly
    index.cfm?event=users
    // Call the users.cfc index() method via URL mappings
    index.cfm/users/index
    // Call the users.cfc index() method implicitly via URL mappings
    index.cfm/users
    install coldbox-cli
    mkdir 60-minute-quickstart --cd
    install coldbox
    Dir coldbox
    File box.json
    FrameworkSuperType.cfc
    /**
     * Get a setting from the system
     *
     * @name The key of the setting
     * @defaultValue If not found in config, default return value
     *
     * @throws SettingNotFoundException
     *
     * @return The requested setting
     */
    function getSetting( required name, defaultValue )
    
    /**
     * Get a ColdBox setting
     *
     * @name The key to get
     * @defaultValue The default value if it doesn't exist
     *
     * @throws SettingNotFoundException
     *
     * @return The framework setting value
     */
    function getColdBoxSetting( required name, defaultValue )
    
    /**
     * Check if the setting exists in the application
     *
     * @name The key of the setting
     */
    boolean function settingExists( required name )
    
    /**
     * Set a new setting in the system
     *
     * @name The key of the setting
     * @value The value of the setting
     *
     * @return FrameworkSuperType
     */
    any function setSetting( required name, required value )
    
    /**
     * Get a module's settings structure or a specific setting if the setting key is passed
     *
     * @module The module to retrieve the configuration settings from
     * @setting The setting to retrieve if passed
     * @defaultValue The default value to return if setting does not exist
     *
     * @return struct or any
     */
    any function getModuleSettings( required module, setting, defaultValue )
    application.cbController.getSetting()
    application.cbController.setSetting()
    application.cbController.settingExists()
    application.cbController.getConfigSettings()
    application.cbController.getColdBoxSettings()
    component{
    
        property name="mysetting"    inject="coldbox:setting:mysetting";
        property name="path"         inject="coldbox:coldboxSetting:path";
        property name="config"       inject="coldbox:configSettings";
        property name="settings"     inject="coldbox:coldboxSettings";
    
    }
    // retrieve it
    config = getSetting( 'coldboxConfig' );
    
    // inject it
    property name="config" inject="coldbox:setting:coldboxConfig";
    function preProcess( event, interceptData, buffer, rc, prc ){
        writeDump( 'I just hijacked your app!' );abort;
    }
    function preRender( event, interceptData, buffer, rc, prc ){
        controller.getWirebox().getInstance( 'loggerService' ).doSomething();
    }
    /**
    * Executes events with full life-cycle methods and returns the event results if any were returned.
    * @event The event string to execute, if nothing is passed we will execute the application's default event.
    * @prePostExempt If true, pre/post handlers will not be fired. Defaults to false
    * @private Execute a private event if set, else defaults to public events
    * @defaultEvent The flag that let's this service now if it is the default event running or not. USED BY THE FRAMEWORK ONLY
    * @eventArguments A collection of arguments to passthrough to the calling event handler method
    * @cache Cached the output of the runnable execution, defaults to false. A unique key will be created according to event string + arguments.
    * @cacheTimeout The time in minutes to cache the results
    * @cacheLastAccessTimeout The time in minutes the results will be removed from cache if idle or requested
    * @cacheSuffix The suffix to add into the cache entry for this event rendering
    * @cacheProvider The provider to cache this event rendering in, defaults to 'template'
    */
    function runEvent(
    	event="",
    	boolean prePostExempt=false,
    	boolean private=false,
    	boolean defaultEvent=false,
    	struct eventArguments={},
    	boolean cache=false,
    	cacheTimeout="",
    	cacheLastAccessTimeout="",
    	cacheSuffix="",
    	cacheProvider="template"
    )
    event.setView( 'view' );
    event.setView( 'mydirectory/myView' );

    false

    false

    Cache the view to be rendered

    cacheTimeout

    numeric

    false

    (provider default)

    The timeout in minutes or whatever the cache provider defines

    cacheLastAccessTimeout

    numeric

    false

    (provider default)

    The idle timeout in minutes or whatever the cache provider defines

    cacheSuffix

    string

    false

    ---

    Adds a suffix key to the cached key. Used for providing uniqueness to the cacheable entry

    the API docs
    function

    The first option (regex matching) is the easiest to use, but not very reliable if you are using multiple hostnames or commandbox for re-initialization.

    If you are using commandbox please read ALL options below

    Default: Regex matching against cgi.http_host

    To detect your environments you will setup a structure called environments in your coldbox configuration with the named environments and their associated regular expressions for its cgi host names to match for you automatically. If the framework matches the regex with the associated cgi.http_host, it will set a setting called Environment in your configuration settings and look for that environment setting name in your CFC as a method by convention. That's right, it will check if your CFC has a method with the same name as the environment and if it exists, it will call it for you. Here is where you basically override, remove, or add any settings according to your environment.

    Warning : The environment detection occurs AFTER the configure() method is called. Therefore, whatever settings or configurations you have on the configure() method will be stored first, treat those as Production settings.

    The regex match will also create a global setting called "environment" which you can access and use like this:

    In the above example, I declare a development key with a value list of regular expressions. If I am in a host that starts with cf2016, this will match and set the environment setting equal to development. It will then look for a development method in this CFC and execute it.

    Detection of an environmental variable called ENVIRONMENT

    If you are using environmental variables for your different environments, you can specify an environmental variable called ENVIRONMENT and name it staging, development, testing etcetera, depending on the required environment. As in the regex example, a function named after your environment (e.g. staging() or development() ) will be called after your configure method.

    This method is more reliable than relying on cgi.http_host, since it will never change once configured correctly.

    Custom Environment Detection

    If you are NOT using environmental variables you can use your own detection algorithm instead of looking at the cgi.http_host variable. You will NOT fill out an environments structure but actually create a method with the following signature:

    This method will be executed for you at startup and it must return the name of the environment the application is on. You can check for any condition which distinguishes your environment from your other environments. As long as you return an environment name based on your own logic it will then store it and execute the method if it exists.

    component name="general"{
    
        function index(event,rc,prc){
    
            // call some model for data and put into the request collection
            prc.myQuery = getInstance('MyService').getData();    
            // view with caching parameters
            event.setView(
                view="general/index",
                cache=true,
                cacheTimeout=60,
                cacheLastAccessTimeout=15,
                cacheSuffix=getfwLocale()
            );
        }
    
    }
    // get a reference to the template cache
    cache = cachebox.getCache( 'template' );
    // or via shortcut notation
    cache = getCache( "template" );
    // or injection
    property name="cache" inject="cachebox:template";
    cachebox.getCache( 'template' ).clearView('general/index');
    cachebox.getCache( 'template' ).clearAllViews(async=true);
    cachebox.getCache( 'template' ).clearMultiView('general/index','index','home');
    coldbox = {
    // Activate view caching
    viewCaching = false
    }
    <div id="leftbar">
    #runEvent( event='viewlets.userinfo', eventArguments={ userID=4 } )#
    </div>
    viewlets.cfc
    function userinfo( event, rc, prc, userID=0 ){
    
        // place data in prc and prefix it to avoid collisions
        prc.userinfo_qData = userService.getUserInfo( arguments.userID );
    
        // render out content 
        return view( "viewlets/userinfo" );
    }
    viewlets/userinfo.cfm
    <cfoutput>
        <div>User Info Panel</div>
        <div>Username: #prc.userinfo_qData.username#</div>
        <div>Last Login: #prc.userinfo_qData.lastLogin#</div>
    </cfoutput>
    function home(event,rc,prc){
    
        // render some content variables with funky arguments
        prc.sideColumn = view(view='tags/sideColumn',cache=true,cacheTimeout=10);
    
        // set view
        event.setView('general/home');
    }
    <div id="content">
      <div id="leftColumn">
      <cfoutput>#prc.sideColumn#</cfoutput>
      </div>
    
      <div id="mainView">
      <cfoutput>#view()#</cfoutput>
      </div>
    </div>
    <div id="content">
      <div id="leftColumn">
      <cfoutput>#prc.sideColumn ?: ''#</cfoutput>
      </div>
    
      <div id="mainView">
      <cfoutput>#view()#</cfoutput>
      </div>
    </div>
    //public event
    runEvent( 'users.save' );
    
    //post exempt
    runEvent( event='users.save', prePostExempt=true );
    
    //Private event
    runEvent( event='users.persist', private=true );
    
    // Run event as a widget
    <cfoutput>#runEvent(
        event         = 'widgets.userInfo',
        prePostExempt = true,
        eventArguments= { widget=true }
    )#</cfoutput>
    
    // Run with Caching
    runEvent( event="users.list", cache=true, cacheTimeout=30 );
    // handler responding to widget call
    function userInfo( event, rc, prc, widget=false ){
    
        prc.userInfo = userService.get( rc.id );
    
        // set or widget render
        if( arguments.widget ){
            return view( "widgets/userInfo" );
        }
    
        // else set view
        event.setView( "widgets/userInfo" );
    }
    runEvent( event="users.widget", eventArguments={ max=10, page=1 }, cache=true );
    
    // Cached as a new key
    runEvent( event="users.widget", eventArguments={ max=10, page=2 }, cache=true );
    
    function index( event, rc, prc ){
        // Inline
        event.setView( view="main/index", layout="2columns" );
        
        // Concatenated
        event.setView( "main/index" )
            .setLayout( "2columns" );
    }
    function index( event, rc, prc ){
        // Inline
        event.setView( view="widgets/users", nolayout=true );   
    }
    * @view The name of the view to set. If a layout has been defined it will assign it, else if will assign the default layout. No extension please
    * @args An optional set of arguments that will be available when the view is rendered
    * @layout You can override the rendering layout of this setView() call if you want to. Else it defaults to implicit resolution or another override.
    * @module The explicit module view
    * @noLayout Boolean flag, wether the view sent in will be using a layout or not. Default is false. Uses a pre set layout or the default layout.
    * @cache True if you want to cache the rendered view.
    * @cacheTimeout The cache timeout in minutes
    * @cacheLastAccessTimeout The last access timeout in minutes
    * @cacheSuffix Add a cache suffix to the view cache entry. Great for multi-domain caching or i18n caching.
    * @cacheProvider The cache provider you want to use for storing the rendered view. By default we use the 'template' cache provider
    * @name This triggers a rendering region.  This will be the unique name in the request for specifying a rendering region, you can then render it by passing the unique name to view();
    // Cache in the template cache for the default amount of time
    event.setView( view='myView', cache=true );
    // Cache in the template cache for up to 60 minutes, or 20 minutes after the last time it's been used
    event.setView( view='myView', cache=true, cacheTimeout=60, cacheLastAccessTimeout=20 );
    // Cache a different version of the view for each language the site has
    event.setView( view='myView', cache=true, cacheSuffix=prc.language );
    var viewData = {
      data1 = service.getData1(),
      data2 = service.getData2()
    };
    
    event.setView( view='myView', args=viewData );
    <cfoutput>
      Data 1: #args.data1#<br>
      Data 2: #args.data2#
    </cfoutput>
    event.noRender();
    environments = {
        // The key is the name of the environment
        // The value is a list of regex to match against cgi.http_host
        development = "^cf2016.,^lucee.,localhost",
        staging = "^stg"
    };
    if ( getSetting('environment') == 'development' ){
        doSomeMajik();
    }
    /**
    * Executed whenever the development environment is detected
    */
    function development(){
        // Override coldbox directives
        coldbox.handlerCaching = false;
        coldbox.eventCaching = false;
        coldbox.debugPassword = "";
        coldbox.reinitPassword = "";
    
        // Add dev only interceptors
        arrayAppend( interceptors, {class="#appMapping#.interceptors.CustomLogger} );
    }
    string public function detectEnvironment(){
    }
    and look for the
    coldbox.handlerCaching
    setting.

    By default this is already done for you on the application templates.

    Handler Code

    Go open the handlers/main.cfc and let's explore the code.

    Let's recap: Every action in ColdBox receives three arguments:

    • event - An object that models and is used to work with the current request, called the request context.

    • rc - A struct that contains both URL/FORM variables (unsafe data)

    • prc - A secondary struct that is private only settable from within your application (safe data)

    Setting Views - Default Layout

    This line event.setView( "main/index" ) in the index action told ColdBox to render a view back to the user found in views/main/index.cfm.

    ColdBox also has the concept of layouts, which are essentially reusable views that can wrap up other views or layouts. They allow you to reuse content to render views/layouts inside a specific location in the CFML content. By convention, ColdBox looks for a layout called layouts/Main.cfm. This is yet another convention, the default layout. Your application can have many layouts or non-layouts at all.

    Working With Incoming Data

    Now, let's open the handler we created before called handlers/hello.cfc and add some public and private variables so our views can render the variables.

    Let's open the view now: views/hello/index.cfm and change it to this:

    Please note that we used the ColdFusion function encodeForHTML() (https://cfdocs.org/encodeforhtml) on the public variable. Why? Because you can never trust the client and what they send, make sure you use the built-in ColdFusion encoding functions in order to avoid XSS hacks or worse on incoming public (rc) variables.

    If you execute the event now: http://localhost:{port}/hello/index you will see a message of Hello nobody.

    Now change the incoming URL to this: http://localhost:{port}/hello/index?name=ColdBox and you will see a message of Hello ColdBox.

    Tip: Please see the layouts and views section for in-depth information.

    Routing Params

    Now let's expect the name as part of the URL pattern; open the config/Router.cfc and let's add another route:

    We use the : colon to denote incoming URL/FORM placeholder params that, if found are translated to the request collection (rc). So let's try it out: http://localhost:{port}/hello/coldbox

    You can use the route() to generate the URL with params in a nice struct way:

    Conventions

    Let's do a recap of our conventions for layouts and view locations:

    ColdBox Renderer

    It is imperative to know who does the rendering in ColdBox and that is the Renderer class that you can see from our diagram above. As you can tell from the diagram, it includes your layouts and/or views into itself in order to render out content. So by this association and inheritance all layouts and views have some variables and methods at their disposal since they get absorbed into the object. You can visit the API docs to learn about all the Renderer methods.

    All of the following property members exist in all layouts and views rendered by the Renderer:

    Property

    Description

    event

    A reference to the Request Context object

    rc

    A reference to the request collection inside of the request context (For convenience)

    prc

    A reference to the private request collection inside of the request context (For convenience)

    html

    A reference to the that can help you build interactive and safe HTML

    cacheBox

    A reference to the framework factory (coldbox.system.cache.CacheFactory)

    controller

    A reference to the application's ColdBox Controller (coldbox.system.web.Controller)

    As you can see, all views and layouts have direct reference to the request collections so it makes it incredibly easy to get and put data into it. Also, remember that the Renderer inherits from the Framework SuperType so all methods are at your disposal if needed.

    Injecting In Your Models

    You can also inject the ColdBox Renderer into your models so you can render email templates, views, etc. directly from your model code:

    In previous versions you would need to use a provider: syntax due to the Renderer being a transient. This is no longer true in ColdBox 6.0.

    layouts
    event handlers

    BoxLang 1+

  • Lucee 5+

  • Adobe 2023+

  • IDE Tools

    ColdBox has the following supported IDE Tools:

    • Sublime - https://packagecontrol.io/packages/ColdBox Platform

    • VSCode - https://marketplace.visualstudio.com/items?itemName=ortus-solutions.vscode-coldbox

    CommandBox CLI

    The first step in our journey is to install CommandBox. CommandBox is a ColdFusion (CFML) Command Line Interface (CLI), REPL, Package Manager, and Embedded Server. We will be using CommandBox for almost every exercise in this book, and it will also allow you to get up and running with ColdFusion and ColdBox in a much speedier manner.

    Note : However, you can use your own ColdFusion server setup as you see fit. We use CommandBox as everything is scriptable and fast!

    Download CommandBox

    You can download CommandBox from the official site: https://www.ortussolutions.com/products/commandbox#download and install in your preferred Operating System (Windows, Mac, *unix). CommandBox comes in two flavors:

    1. No Java Runtime (80mb)

    2. Embedded Runtime (120mb)

    So make sure you choose your desired installation path and follow the instructions here: https://commandbox.ortusbooks.com/setup/installation

    Starting CommandBox

    Once you download and expand CommandBox, you will have the box.exe or box binary, which you can place in your Windows Path or *Unix /usr/bin folder to have it available system-wide. Then just open the binary and CommandBox will unpack itself your user's directory: {User}/.CommandBox. This happens only once and the next thing you know, you are in the CommandBox interactive shell!

    CommandBox Shell

    We can execute a-la-carte commands from our command line or go into the interactive shell for multiple commands. We recommend the interactive shell as it is faster and can remain open in your project root.

    All examples in this book are based on having an interactive shell open.

    Installing ColdBox CLI

    The ColdBox CLI is your best friend when developing with ColdBox and it's based on CommadBox. Just fire up that terminal and install it

    Now you will have a coldbox namespace of commands. Explore them coldbox help. To install ColdBox, you can do so via install coldbox or by scaffolding a starter application template. We would highly encourage you to visit our application templates section to discover how to get started quickly.

    Please remember to Star us in Github.

    Updating ColdBox

    To update ColdBox from a previous version, just type update coldbox. You can also run the command outdated periodically to verify the packages in your application.

    project's readme.
    Examples

    The arguments received by these interceptors are:

    • event : The request context reference

    • targetAction : The function pointer to the action that got the around interception. It will be your job to execute it (Look at samples)

    • eventArguments : The struct of extra arguments sent to an action if any

    • rc : The RC reference

    • prc : The PRC Reference

    Exceptions & Only Lists

    You can fine tune these interception methods by leveraging two public properties in the handler:

    • this.aroundhandler_only : A list of actions that the aroundHandler() action will fire ONLY!

    • this.aroundhandler_except : A list of actions that the aroundHandler() action will NOT fire on

    proxy design pattern.
    https://www.emberjs.com/

    Configuration Directives

    The basic configuration object has 1 method for application configuration called configure() where you will place all your configuration directives and settings:

    Directives

    Inside of this configuration method you will place several core and third-party configuration structures that can alter your application settings and behavior. Below are the core directives you can define:

    Directive

    GitHub - coldbox-samples/60-minute-quickstart: 60 Minute QuickstartGitHub
    Slackboxteam.ortussolutions.com
    boxteam.ortussolutions.com
    Ortus Solutions CommunityOrtus Solutions Community
    community.ortussolutions.com

    Rewrite Rules

    Here are just a few of those rewrite rules for you for major rewrite engines. You can spice them up as needed.

    .htaccess

    Recent versions of Apache don't send the CGI.PATH_INFO variable to your cfml engine when using ProxyPass and ProxyPassMatch without the PT

    Request Context

    The Request Context Object models incoming requests and provides access to form, URL, and remote variables. Learn how to interact with client data and manage responses.

    On every request to a ColdBox event, the framework creates an object that models the incoming request. This object is called the Request Context Object. This object will be passed to an and will be processed by an and is by convention called an event)

    It contains the incoming FORM/REMOTE/URL variables the client sent in and the object lives in the ColdFusion request scope and you will use to for responses and interacting with client data.

    Please visit the latest for further information about the request context.

    Bootstrapper - Application.cfc

    The Application.cfc is one of the most important files in your application as it is where you define all the implicit ColdFusion engine events, session, client scopes, ORM, etc. It is also how you tell ColdFusion to bootstrap the ColdBox Platform for your application. There are two ways to bootstrap your application:

    1. Leverage composition and bootstrap ColdBox (Default)

    2. Leverage inheritance and bootstrap ColdBox

    Event Handlers

    Event handlers are ColdBox's controllers that manage application flow, handle user interactions, call business logic, and prepare responses. Learn MVC controller patterns.

    Event handlers are ColdBox's version of controllers in the MVC design pattern. So every time you hear "event handler", you are talking about a controller that can listen to external events or internal events in ColdBox. Event handlers are responsible for controlling your application flow, calling business logic, preparing a display to a user and much more.

    Locations

    All your handlers will be stored in the handlers folder of your application template. If you get to the point where your application needs even more decoupling and separation, please consider building

    config/Coldbox.cfc
    /**
     * Development environment
     */
    function development() {
        coldbox.customErrorTemplate = "/coldbox/system/exceptions/Whoops.cfm"; // interactive bug report
        coldbox.handlerCaching = false;
        coldbox.handlersIndexAutoReload = true;
        coldbox.eventCaching = false;
        coldbox.viewCaching = false;
    }
    component extends="coldbox.system.EventHandler" {
    
        /**
         * Default Action
         */
        function index( event, rc, prc ) {
            prc.welcomeMessage = "Welcome to ColdBox!";
            event.setView( "main/index" );
        }
    
        /**
         * Produce some restfulf data
         */
        function data( event, rc, prc ) {
            return [
                { "id" : createUUID(), name : "Luis" },
                { "id" : createUUID(), name : "JOe" },
                { "id" : createUUID(), name : "Bob" },
                { "id" : createUUID(), name : "Darth" }
            ];
        }
    
        /**
         * Relocation example
         */
        function doSomething( event, rc, prc ) {
            relocate( "main.index" );
        }
    
        /************************************** IMPLICIT ACTIONS *********************************************/
    
        function onAppInit( event, rc, prc ) {
        }
    
        function onRequestStart( event, rc, prc ) {
        }
    
        function onRequestEnd( event, rc, prc ) {
        }
    
        function onSessionStart( event, rc, prc ) {
        }
    
        function onSessionEnd( event, rc, prc ) {
            var sessionScope     = event.getValue( "sessionReference" );
            var applicationScope = event.getValue( "applicationReference" );
        }
    
        function onException( event, rc, prc ) {
            event.setHTTPHeader( statusCode = 500 );
            // Grab Exception From private request collection, placed by ColdBox Exception Handling
            var exception = prc.exception;
            // Place exception handler below:
        }
    
    }
    function index( event, rc, prc ){
        // param an incoming variable.
        event.paramValue( "name", "nobody" );
        // set a private variable
        prc.when = dateFormat( now(), "full" );
        // set the view to render
        event.setView( "hello/index" );
    }
    <cfoutput>
    <p>Hello #encodeForHTML( rc.name )#, today is #prc.when#</p>
    </cfoutput>
    route( "/hello/:name" ).as( "hello" ).to( "hello" )
    <a href="#event.route( "hello", { name: "Luis" } )#">Say Hello Luis</a>
    + application
      + layouts
      + views
    component{
    
        property name="renderer" inject="coldbox:renderer";
    
        function renderSomething(){
            return renderer.view( view="mail/mymail", args={} );
        }
    }
    install coldbox-cli
    users.list => users.aroundHandler() <=> list()
    // executes around any action
    function aroundHandler(event,targetAction,eventArguments,rc,prc){
    }
    
    // executes around the list() action ONLY
    function aroundList(event,targetAction,eventArguments,rc,prc){
    }
    
    // Around handler advice for transactions
    function aroundHandler(event,targetAction,eventArguments,rc,prc){
    
        // log the call
        log.debug("Starting to execute #targetAction.toString()#" );
    
        // start a transaction
        transaction{
    
            // prepare arguments for action call
            var args = {
                event = arguments.event,
                rc    = arguments.rc,
                prc   = arguments.prc
    
            };
            structAppend( args, eventArguments );
            // execute the action now
            var results = arguments.targetAction( argumentCollection=args );
        }
    
        // log the call
        log.debug( "Ended executing #targetAction.toString()#" );
    
        // return if it exists
        if( !isNull( results ) ){ return results; }
    }
    
    // Around handler advice for try/catches
    function aroundHandler(event,targetAction,eventArguments,rc,prc){
    
        // log the call
        if( log.canDebug() ){
            log.debug( "Starting to execute #targetAction.toString()#" );
        }
    
        // try block
        try{
    
            // prepare arguments for action call
            var args = {
                event = arguments.event,
                rc    = arguments.rc,
                prc   = arguments.prc
    
            };
            structAppend( args, eventArguments );
            // execute the action now
            return arguments.targetAction( argumentCollection=args );
        }
        catch(Any e){
            // log it
            log.error("Error executing #targetAction.toString()#: #e.message# #e.detail#", e);
            // set exception in request collection and set view to render
            event.setValue( "exception", e)
                .setView( "errors/generic" );
    
        }
    
    }
    // only fire for the actions: save(), delete()
    this.aroundhandler_only = "save,delete";
    // DO NOT fire for the actions: login(), doLogin(), logout()
    this.aroundhandler_except = "login,doLogin,logout"
    ColdBox.cfc
    /**
    * A simple CFC that configures a ColdBox application.  You can even extend, compose, strategize and do your OO goodness.
    */
    component{
    
        // Mandatory configuration method
        function configure(){
            coldbox = {
              
            };
        }
        
    }

    Type

    Description

    cachebox

    struct

    An optional structure used to configure CacheBox. If not setup the framework will use its default configuration found in /coldbox/system/web/config/CacheBox.cfc

    coldbox

    struct

    The main coldbox directives structure that holds all the coldbox settings.

    conventions

    struct

    A structure where you will configure the application convention names

    environments

    struct

    A structure where you will configure environment detection patterns

    flash

    struct

    A structure where you will configure the FlashRAM

    interceptorSettings

    struct

    An optional structure to configure application wide interceptor behavior

    interceptors

    array

    An optional array of interceptor declarations for your application

    layoutSettings

    struct

    A structure where you define how the layout manager behaves in your application

    layouts

    array

    An array of layout declarations for implicit layout-view-folder pairings in your application

    logbox

    struct

    An optional structure to configure the logging and messaging in your application via LogBox

    modules

    struct

    An optional structure to configure application wide module behavior

    moduleSettings

    struct

    An optional structure to configure individual modules installed in your application.

    settings

    struct

    A structure where you can put your own application settings

    wirebox

    struct

    An optional structure used to define how WireBox is loaded

    ( Pass Through ) directive.

    On current versions of Coldbox, you can also use a pathInfoProvider function in your router.cfc or use the updated PassThrough configuration with a leading slash on the index.cfm below

    Updated syntax for Apache:

    The following solution will also work if you are using recent versions of Apache and Coldbox:

    Now you can create a pathInfo provider function in your router.cfc which brings back your path info to the router:

    nginx

    IIS7 web.config

    Please note that URL rewriting is handled by an optional module in IIS. More info here: https://www.iis.net/downloads/microsoft/url-rewrite

    Tuckey Rewrite

    RewriteEngine on
    #if this call related to adminstrators or non rewrite folders, you can add more here.
    RewriteCond %{REQUEST_URI} ^/(.*(CFIDE|cfide|CFFormGateway|jrunscripts|railo-context|lucee|mapping-tag|fckeditor)).*$
    RewriteRule ^(.*)$ - [NC,L]
    
    #Images, css, javascript and docs, add your own extensions if needed.
    RewriteCond %{REQUEST_URI} \.(bmp|gif|jpe?g|png|css|js|txt|xls|ico|swf)$
    RewriteRule ^(.*)$ - [NC,L]
    
    #The ColdBox index.cfm/{path_info} rules.
    RewriteRule ^$ index.cfm [QSA,NS]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.cfm/%{REQUEST_URI} [QSA,L,NS]
    #The ColdBox index.cfm/{path_info} rules.
    RewriteRule ^$ index.cfm [QSA,NS]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ /index.cfm/%{REQUEST_URI} [PT,QSA,L,NS]
    #The ColdBox index.cfm/{path_info} rules.
    RewriteEngine On
    RewriteRule ^$ /index.cfm?redirect_path=/ [QSA,NS]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ /index.cfm?redirect_path=%{REQUEST_URI} [PT,QSA,L,NS]
    router.cfc
    function PathInfoProvider( event ){
      var p = cgi.path_info;
      if (len(p)) {
        return p;
      } else if (url.keyExists("redirect_path")) {
        return url.redirect_path;
      } else {
        return "";
      }
    }
    ################### LOCATION: ROOT #####################
    location / {
         # First attempt to serve real files or directory, else it sends it to the @rewrite location for processing
         try_files $uri $uri/ @rewrite;
    }
    
    ################### @REWRITE: COLDBOX SES RULES #####################
    # Rewrite for ColdBox (only needed if you want SES urls with this framework)
    # If you don't use SES urls you could do something like this
    # location ~ \.(cfm|cfml|cfc)(.*)$ {
    location @rewrite {
      rewrite ^/(.*)? /index.cfm/$request_uri last;
      rewrite ^ /index.cfm last;
    }
    
    ################### CFM/CFC LUCEE HANDLER #####################
    # The above locations will just redirect or try to serve cfml files
    # We need this to tell NGinx that if we receive the following requests to pass them to Lucee
    location ~ \.(cfm|cfml|cfc|jsp)(.*)$ {
    # Include our connector
    include lucee.conf;
    }
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <system.webServer>
            <rewrite>
                <rules>
                   <rule name="Application Administration" stopProcessing="true">
                        <match url="^(.*)$" />
                        <conditions logicalGrouping="MatchAll">
                            <add input="{SCRIPT_NAME}" pattern="^/(.*(CFIDE|cfide|CFFormGateway|jrunscripts|lucee|railo-context|fckeditor)).*$" ignoreCase="false" />
                        </conditions>
                        <action type="None" />
                    </rule>
                    <rule name="Flash and Flex Communication" stopProcessing="true">
                        <match url="^(.*)$" ignoreCase="false" />
                        <conditions logicalGrouping="MatchAll">
                            <add input="{SCRIPT_NAME}" pattern="^/(.*(flashservices|flex2gateway|flex-remoting)).*$" ignoreCase="false" />
                        </conditions>
                        <action type="Rewrite" url="index.cfm/{PATH_INFO}" appendQueryString="true" />
                    </rule>
                    <rule name="Static Files" stopProcessing="true">
                        <match url="^(.*)$" />
                        <conditions logicalGrouping="MatchAll">
                            <add input="{SCRIPT_NAME}" pattern="\.(bmp|gif|jpe?g|png|css|js|txt|pdf|doc|xls)$" ignoreCase="false" />
                        </conditions>
                        <action type="None" />
                    </rule>
                    <rule name="Insert index.cfm" stopProcessing="true">
                        <match url="^(.*)$" ignoreCase="false" />
                        <conditions logicalGrouping="MatchAll">
                            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                        </conditions>
                        <action type="Rewrite" url="index.cfm/{PATH_INFO}" appendQueryString="true" />
                    </rule>
                </rules>
            </rewrite>
        </system.webServer>
    </configuration>
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.2//EN" "http://tuckey.org/res/dtds/urlrewrite3.2.dtd">
    <urlrewrite>
        <rule>
            <note>ContentBox Media URLs</note>
            <condition type="request-uri" operator="equal">^/__media/.*$</condition>
            <from>^/(.*)$</from>
            <to type="passthrough">/index.cfm/$1</to>
        </rule>
        <rule>
            <note>Generic Front-Controller URLs</note>
            <condition type="request-uri" operator="notequal">/(index.cfm|robots.txt|osd.xml|flex2gateway|cfide|cfformgateway|railo-context|lucee|admin-context|modules/contentbox-dsncreator|modules/contentbox-installer|modules/contentbox|files|images|js|javascripts|css|styles|config).*</condition>
            <condition type="request-uri" operator="notequal">\.(bmp|gif|jpe?g|png|css|js|txt|xls|ico|swf|woff|ttf|otf)$</condition>
            <condition type="request-filename" operator="notdir"/>
            <condition type="request-filename" operator="notfile"/>
            <from>^/(.+)$</from>
            <to type="passthrough">/index.cfm/$1</to>
        </rule>
    </urlrewrite>

    This object contains two structures internally:

    1. RC - The Request Collection which contains the FORM/REMOTE/URL data merged into a single structure. This is considered to be unsafe data as it comes from any request.

    2. PRC - The Private Request Collection which is a structure that can be used to safely store sensitive data. This structure cannot be modified from the outside world.

    The order of preference of variables when merged is FORM first then REMOTE then URL.

    REMOTE variables are from leveraging the ColdBox Proxy.

    You will use these objects in the controller and view layer of your application to get/set values, get metadata about the request, generate URLs, transform data for RESTful requests, and so much more. It is the glue that binds the controller and view layer together. As we progress in the guides, you will progress in mastering the request context.

    RC/PRC Data Super Highway

    Note that there is no model layer in the diagram. This is by design; the model will receive data from the handlers/interceptors directly.

    Most Commonly Used Methods

    Below you can see a listing of the most commonly used methods in the request context object. Please note that when interacting with a collection you usually have an equal private collection method.

    • buildLink() : Build a link in SES or non SES mode for you with tons of nice abstractions.

    • clearCollection() : Clears the entire collection

    • collectionAppend() : Append a collection overwriting or not

    • getCollection() : Get a reference to the collection

    • getEventName() : The event name in use in the application (e.g. do, event, fa)

    • getSelf() : Returns index.cfm?event=

    • getValue() : get a value

    • getTrimValue() : get a value trimmed

    • isProxyRequest() : flag if the request is an incoming proxy request

    • isSES() : flag if ses is turned on

    • isAjax() : Is this request ajax based or not

    • noRender(boolean) : flag that tells the framework to not render any html, just process and silently stop.

    • overrideEvent() : Override the event in the collection

    • paramValue(): param a value in the collection

    • removeValue() : remove a value

    • setValue() : set a value

    • setLayout() : Set the layout to use for this request

    • setView() : Used to set a view to render

    • valueExists() : Checks if a value exists in the collection.

    • renderData() : Marshall data to JSON, JSONP, XML, WDDX, PDF, HTML, etc.

    Some Samples:

    Please see the online API Docs for the latest methods and arguments.

    Request Metadata Methods

    • getCurrentAction() : Get the current execution action (method)

    • getCurrentEvent() : Get the current incoming event, full syntax.

    • getCurrentHandler() : Get the handler or handler/package path.

    • getCurrentLayout() : Get the current set layout for the view to render.

    • getCurrentView() : Get the current set view

    • getCurrentModule() : The name of the current executing module

    • getCurrentRoutedNamespace() : The current routed URL mapping namespace if found.

    • getCurrentRouteRecord() : Get the current routed record used in resolving the event

    • getCurrentRouteMeta() : Get the current routed record metdata struct

    • getCurrentRoutedURL() : The current routed URL if matched.

    • getDefaultLayout() : Get the name of the default layout.

    • getDefaultView() : Get the name of the default view.

    Event Handler
    Action
    API Docs

    The composition approach allows you to have a more flexible configuration as it will allow you to use per-application mappings for the location of the ColdBox Platform.

    Tip: To see the difference, just open the appropriate Application.cfc in the application templates.

    Composition

    Inheritance

    Directives

    You can set some variables in the Application.cfc that can alter Bootstrapping conditions:

    Variable

    Default

    Description

    COLDBOX_APP_ROOT_PATH

    App Directory

    Automatically set for you. This path tells the framework what is the base root location of your application and where it should start looking for all the agreed upon conventions. You usualy will never change this, but you can.

    COLDBOX_APP_MAPPING

    /

    The application mapping is ESSENTIAL when dealing with Flex or Remote (SOAP) applications. This is the location of the application from the root of the web root. So if your app is at the root, leave this setting blank. If your application is embedded in a sub-folder like MyApp, then this setting will be auto-calculated to /MyApp.

    COLDBOX_CONFIG_FILE

    config/ColdBox.cfc

    The absolute or relative path to the configuration CFC file to load. This bypasses the conventions and uses the configuration file of your choice.

    COLDBOX_APP_KEY

    Lock Timeout

    The Boostrapper also leverages a default locking timeout of 30 seconds when doing loading operations. You can modify this timeout by calling the setLockTimeout() method on the Bootsrapper object.

    instead.

    Tip: You can create packages or sub-folders inside of the handlers directory. This is encouraged on large applications so you can organize or package handlers logically to facilitate better maintenance and URL experience.

    External Location

    You can also declare a HandlersExternalLocation directive in your Configuration CFC. This will be a dot notation path or instantiation path where more external event handlers can be found.

    If an external event handler has the same name as an internal conventions event, the internal conventions event will take precedence.

    Development Settings

    By default, ColdBox will only scan for event handlers on startup. For development we highly encourage you leverage the following configuration directives:

    Anatomy

    Event handlers are CFCs that will respond to FORM posts, HTTP requests and/or remote requests (like Flex,Air, SOAP, REST) via an incoming RC variable called event or by URL mappings (Which we saw in the previous section).

    Components

    You can also remove the inheritance from the CFC and WireBox will extend the coldbox.system.EventHandler for you using Virtual Inheritance.

    Event Handlers are treated as singletons by ColdBox, so make sure you make them thread-safe and properly scoped. Persistence is controlled by the coldbox.handlerCaching directive

    Actions

    They are composed of functions which are called actions that will always have the following signature:

    Each action receives three arguments:

    1. event - An object that models and is used to work with the current request (otherwise known as the Request Context)

    2. rc - A struct that contains both URL/FORM variables (unsafe data)

    3. prc - A secondary struct that is private. This structure is only accessible from within your application (safe data)

    An action will usually do one of the following:

    • Set a view/layout to render

    • Return HTML

    • Return Complex Data which is converted to JSON by default

    • Relocate to another event/URL Route

    The default action for all event handlers is called index(). This means that when you execute an event, you can omit the index if you so desire.

    Private Actions

    So what about private functions? Private functions are not executable from the outside world, but can be executed internally via a function available to all handlers called runEvent(), which we will explore later.

    Composed Properties

    It is important to note that there is a pre-defined object model behind every event handler controller that will enable you to do your work more efficiently. The following are the automatically generated properties every event handler makes available in their variables scope:)

    Event Handler UML
    • cachebox : A reference to the CacheBox library (coldbox.system.cache.CacheFactory)

    • controller : A reference to the Application Controller (coldbox.system.web.Controller)

    • flash: A flash memory object (coldbox.system.web.flash.AbstractFlashScope)

    • logbox: A reference to the application (coldbox.system.logging.LogBox)

    • log: A pre-configured logging (coldbox.system.logging.Logger)

    • wirebox : A reference to the application (coldbox.system.ioc.Injector)

    • $super: A reference to the virtual super class if using non-inheritance approach.

    ColdBox Modules

    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)

    HTML Helper
    CacheBox

    Adding A Model

    MVC

    Let's complete our saga into MVC by developing the M, which stands for model. This layer is all your business logic, queries, external dependencies, etc. of your application, which represents the problem to solve or the domain to solve.

    WireBox

    This layer is controlled by WireBox, the dependency injection framework within ColdBox, which will give you the flexibility of wiring your objects and persisting them for you.

    Creating A Service Model

    Let's create a simple contact listing, so open up CommandBox and issue the following command:

    This will create a models/ContactService.cfc with a getAll() method and a companion unit test at tests/specs/unit/ContactServiceTest.cfc. Let's open the model object:

    Notice the singleton annotation on the component tag. This tells WireBox that this service should be cached for the entire application lifespan. If you remove the annotation, then the service will become a transient object, which means that it will be re-created every time it is requested.

    Add Some Data

    Let's mock an array of contacts so we can display them later. We can move this to a SQL call later.

    We also have created a project to mock any type of data: . Just use CommandBox to install it: install mockdatacfc

    You can then leverage it to mock your contacts or any simple/complex data requirement.

    Wiring Up The Model To a Handler

    We have created our model, so let's tell our event handler about it. Let's create a new handler using CommandBox:

    This will create the handler/contacts.cfc handler with an index() action, the views/contacts/index.cfm view and the accompanying integration test tests/specs/integration/contactsTest.cfc.

    Let's open the handler and add a new ColdFusion property that will have a reference to our model object.

    Please note that inject annotation on the property definition. This tells WireBox what model to inject into the handler's variablesscope.

    By convention, it looks in the models folder for the value, which in our case, is ContactService. Now let's call it and place some data in the private request collection prc so our views can use it.

    Presenting The Data

    Now that we have put the array of contacts into the prc struct as aContacts, let's display it to the screen using .

    The ColdBox HTML Helper is a companion class in all layouts and views that allows you to generate semantic HTML without the needed verbosity of nesting or binding to ORM/Business objects.

    Please check out the API Docs to discover the HTML Helper:

    Open the contacts/index.cfm and add the following to the view:

    Note: If your models are singletons, they will persist for the lifespan of your ColdFusion application. To see code changes for singletons, you have to reinit the framework by using the ?fwreinit={password} Url action or via CommandBox using coldbox reinit. Please check out the API Docs to discover CommandBox: []

    That's it! Execute the event: http://localhost:{port}/contacts/index and view the nice table of contacts being presented to you.

    Congratulations, you have made a complete MVC circle!

    Tip You can find much more information about models and dependency injection in our

    Application Router

    Every ColdBox application has a URL router and can be located by convention at config/Router.cfc. This is called the application router and it is based on the router core class: coldbox.system.web.routing.Router. Here is where you will configure router settings and define routes using our routing DSL.

    Please see the latest API Docs for investigating all the methods and properties of the Router.

    Tip: Unlike previous versions of ColdBox, the new routing services in ColdBox 5 are automatically configured to detect the base URLs and support multi-domain hosting. There is no more need to tell the Router about your base URL.

    Application Router - Router.cfc

    The application router is a simple CFC that virtually inherits from the core ColdBox Router class and is configured via the configure() method. It will be decorated with all the capabilities to work with any request much like any event handler or interceptor. In this router you will be doing 1 of 2 things:

    1. Configuring the Router

    2. Adding Routes via the Routing DSL

    Router as an Interceptor

    The router and indeed all module routers are also registered as full fledged ColdBox interceptors. So they can listen to any event within your application.

    Generated Settings

    Once the routing service loads your Router it will create several application settings for you:

    • SesBaseUrl : The multi-domain URL base URL of your application: http://localhost

    • SesBasePath : The multi-domain path with no protocol or host

    • HtmlBaseUrl : The same path as SESBaseURL

    Configuration Methods

    You can use the following methods to fine tune the configuration and operation of the routing services:

    The next sections will discus how to register routes for your application.

    Rendering Views

    Rendering Methods

    We have now seen how to set views to be rendered from our handlers. However, we can use some cool methods to render views and layouts on demand. These methods exist in the Renderer, and several facade methods exist in the supertype, so you can call it from any handler, interceptor, view, or layout.

    1. view()

    2. externalView()

    3. layout()

    Check out the latest for the latest arguments.

    view()

    externalView()

    layout()

    Examples

    Inline renderings are a great asset for reusing views and doing layout compositions

    Model Rendering

    If you need rendering capabilities in your model layer, we suggest using the following injection DSL:

    This will inject a of a Renderer into your model objects. Remember that renderers are transient objects so you cannot treat them as singletons. The provider is a proxy to the transient object, but you can use it just like the normal object:

    ColdBox

    The ColdBox directive is where you configure the framework for operation.

    Application Setup

    Info : Please note that there are no mandatory settings as of ColdBox 4.2.0. If fact, you can remove the config file completely and your app will run. It will be impossible to reinit the app however without a reinit password set.

    Views

    Views are HTML content that can be rendered inside a layout or by themselves. They can be rendered on-demand or set by an event handler. Views can also produce content apart from HTML, like JSON/XML/WDDX, via our view renderer, which we will discover. So get ready for some rendering goodness!

    Setting Views For Rendering - setView()

    Event handlers are usually the ones responsible for setting views for rendering. However, it's important to understand that ANY object with access to the request context object can also perform this task. This knowledge will keep you informed about the rendering process. The setView() method in the request context object is the tool that enables this functionality.

    Model Data Binding

    Easily bind incoming data into your models.

    ColdBox allows you to populate data from FORM/URL/REMOTE/XML/JSON/Struct into your model objects by convention. This is done via capabilities.

    populate()

    The super type has a method called populate which you will use to trigger the data binding. The supported incoming data sources are:

    // test if this is an MVC request or a remote request
    if ( event.isProxyRequest() ){
      event.setValue('message', 'We are in proxy mode right now');
    }
    
    // param a variable called page
    event.paramValue('page',1);
    // then just use it
    event.setValue('link','index.cfm?page=#rc.page#');
    
    // get a value with a default value
    event.getValue('link','index.cfm?page=#event.getValue('page',1)#');
    
    // Set the view to render
    event.setView('homepage');
    
    // Set the view to render with no layout
    event.setView('homepage',true);
    
    // set the view to render with caching stuff
    event.setview(name='homepage',cache='true',cacheTimeout='30');
    
    // override a layout
    event.setLayout('Layout.Ajax');
    
    // check if a value does not exists
    if ( !event.valueExists('username') ) {
    
    }
    
    // Tell the framework to stop processing gracefully, no renderings
    event.noRender();
    
    // Build a link
    <form action="#event.buildLink( 'user.save' )#" method="post">
    </form>
    Application.cfc
    component{
        // Application properties
        this.name = hash( getCurrentTemplatePath() );
        this.sessionManagement = true;
        this.sessionTimeout = createTimeSpan(0,0,30,0);
        this.setClientCookies = true;
    
        // COLDBOX STATIC PROPERTY, DO NOT CHANGE UNLESS THIS IS NOT THE ROOT OF YOUR COLDBOX APP
        COLDBOX_APP_ROOT_PATH = getDirectoryFromPath( getCurrentTemplatePath() );
        // The web server mapping to this application. Used for remote purposes or static purposes
        COLDBOX_APP_MAPPING   = "";
        // COLDBOX PROPERTIES
        COLDBOX_CONFIG_FILE      = "";
        // COLDBOX APPLICATION KEY OVERRIDE
        COLDBOX_APP_KEY          = "";
        // By default if an app is reiniting and a request hits it, we will fail fast with a message
        COLDBOX_FAIL_FAST        = true;
    
        // application start
        public boolean function onApplicationStart(){
            application.cbBootstrap = new coldbox.system.Bootstrap( COLDBOX_CONFIG_FILE, COLDBOX_APP_ROOT_PATH, COLDBOX_APP_KEY, COLDBOX_APP_MAPPING, COLDBOX_FAIL_FAST );
            application.cbBootstrap.loadColdbox();
            return true;
        }
    
        // request start
        public boolean function onRequestStart(String targetPage){
            // Process ColdBox Request
            application.cbBootstrap.onRequestStart( arguments.targetPage );
    
            return true;
        }
    
        public void function onSessionStart(){
            application.cbBootStrap.onSessionStart();
        }
    
        public void function onSessionEnd( struct sessionScope, struct appScope ){
            arguments.appScope.cbBootStrap.onSessionEnd( argumentCollection=arguments );
        }
    
        public boolean function onMissingTemplate( template ){
            return application.cbBootstrap.onMissingTemplate( argumentCollection=arguments );
        }
    
    }
    Application.cfc
    component extends="coldbox.system.Bootstrap"{
    
        // Application properties
        this.name = hash( getCurrentTemplatePath() );
        this.sessionManagement = true;
        this.sessionTimeout = createTimeSpan(0,0,30,0);
        this.setClientCookies = true;
    
        // COLDBOX STATIC PROPERTY, DO NOT CHANGE UNLESS THIS IS NOT THE ROOT OF YOUR COLDBOX APP
        COLDBOX_APP_ROOT_PATH = getDirectoryFromPath( getCurrentTemplatePath() );
        // The web server mapping to this application. Used for remote purposes or static purposes
        COLDBOX_APP_MAPPING   = "";
        // COLDBOX PROPERTIES
        COLDBOX_CONFIG_FILE      = "";
        // COLDBOX APPLICATION KEY OVERRIDE
        COLDBOX_APP_KEY          = "";
        // By default if an app is reiniting and a request hits it, we will fail fast with a message
        COLDBOX_FAIL_FAST        = true;
    }
    application.bootstrapper.setLockTimeout( 10 );
    coldbox.handlersExternalLocation  = "shared.myapp.handlers";
    // Rescan handlers on each request, turn OFF in production please
    coldbox.handlersIndexAutoReload = true;
    // Deactivate singleton caching of the handlers, turn ON in production pleaese
    coldbox.handlerCaching = false;
    Main.cfc
    component extends="coldbox.system.EventHandler"{
    
        /**
         * Default Action
         */
        function index( event, rc, prc ){
            prc.message = "Hello From ColdBox";
            event.setView( "main/index");
        }
    
        /**
         * Action returning complex data, converted to JSON automatically by ColdBox
         */
        function data( event, rc, prc ){
            var data = getInstance( "MyModel" ).getArray();
            return data;
        }
    
    }
    function name( event, rc, prc )
    component extends="coldbox.system.EventHandler"{
    
        function index( event, rc, prc ){
            return "<h1> Hi from handler land!</h1>";
        }
    
        function save( event, rc, prc ){
            getInstance( "MyService" ).save( rc );
            relocate( "users/list" );
        }
    
        function myData( event, rc, prc ){
            return ['coldbox', 'wirebox', 'cachebox', 'logbox'];
        }
    }
    Logo
    but without any
    index.cfm
    in it (Just in case you are using
    index.cfm
    rewrite). This is a setting used most likely by the HTML
    <base>
    tag.
  • HtmlBasePath : Does not include protocol or host

  • By default ColdBox detects URL extensions like json, xml, html, pdf which can allow you to build awesome RESTful web services. Default is true.

    setValidExtensions( list )

    Tell the interceptor what valid extensions your application can listen to. By default it listens to: json, jsont, xml, cfm, cfml, html, htm, rss, pdf

    setThrowOnInvalidExtensions( boolean )

    By default ColdBox does not throw an exception when an invalid extension is detected. If true, then the interceptor will throw a 406 Invalid Requested Format Extension: {extension} exception. Default is false.

    Method

    Description

    setEnabled( boolean )

    Enable/Disable routing, enabled by default

    setFullRewrites( boolean )

    If true, then no index.cfm will be used in the URLs. If false, then /index.cfm/ will be added to all generated URLs. Default is false.

    setBaseURL( string )

    The base URL to use for URL writing and relocations. This is automatically detected by ColdBox 5 e.g. http://www.coldbox.org/, http://mysite.com/index.cfm''

    setLooseMatching( boolean )

    By default URL pattern matching starts at the beginning of the URL, however, you can choose loose matching so it searches anywhere in the URL. Default is false.

    setMultiDomainDiscovery( boolean )

    Defaults to true. With this setting on, every request will be inspected for the incoming host for usage in building links and domain detection.

    setExtensionDetection( boolean )

    API Docs
    provider
    Development Settings

    reinitPassword

    Protect the reinitialization of the framework URL actions. For security, if this setting is omitted, we will create a random password. Setting it to an empty string will allow you to reinitialize without a password. Always have a password set for public-facing sites.

    reinitKey

    The key used in FORM or URL to reinit the framework. The default is fwreinit but you can change it to whatever you like.

    handlersIndexAutoReload

    Will scan the conventions directory for new handler CFCs on each request if activated. Use false for production, this is only a development true setting.

    Implicit Event Settings

    These settings map 1-1 from ColdBox events to the Application.cfc life-cycle methods. The only one that is not is the defaultEvent, which selects what event the framework will execute when no incoming event is detected via URL/FORM or REMOTE executions.

    Extension Points

    The ColdBox extension points are a great way to create federated applications that can reuse a centralized core instead of the local conventions. It is also a great way to extend some core classes with your own.

    applicationHelper

    A list or array of absolute or relative paths to a UDF helper file. The framework will load all the methods found in this helper file globally. Meaning it will be injected in ALL handlers, layouts and views.

    viewsHelper

    This is a location within your application or an absolute path to a cfm or bxm template that will act as your global helper for all rendered views.

    modulesExternalLocation

    A list or array of locations of where ColdBox should look for modules to load into your application. The path can be a cf mapping or cfinclude compatible location. Modules are searched and loaded in the order of the declared locations. The first location ColdBox will search for modules is the conventions folder modules

    viewsExternalLocation

    The CF include path of where to look for secondary views for your application. Secondary views look just like normal views except the framework looks in the conventions folder first and if not found then searches this location.

    layoutsExternalLocation

    The CF include path of where to look for secondary layouts for your application. Secondary layouts look just like normal layouts except the framework looks in the conventions folder first and if not found then searches this location.

    handlersExternalLocation

    The CF dot notation path of where to look for secondary events for your application. Secondary events look just like normal events except the framework looks in the conventions folder first and if not found then searches this location.

    requestContextDecorator

    The CF dot notation path of the CFC that will decorate the system Request Context object.

    controllerDecorator

    The CF dot notation path of the CFC that will decorate the system Controller

    Exception Handling

    exceptionHandler

    The event handler to call whenever ANY non-catched exception occurs anywhere in the request lifecycle execution. Before this event is fired, the framework will log the error and place the exception in the prc as prc.exception.

    invalidHTTPMethodHandler

    The event handler to call whenever a route or event is accessed with an invalid HTTP method.

    invalidEventHandler

    This is the event handler that will fire masking a non-existent event that gets requested. This is a great place to place 302 or 404 redirects whenever non-existent events are being requested.

    customErrorTemplate

    The relative path from the application's root level of where the custom error template exists. This template receives a key in the private request collection called exception that contains the exception. By default ColdBox does not show robust exceptions, you can turn on robust exceptions by choosing the following template:

    Application Aspects

    autoMapModels

    ColdBox by convention can talk to, use and inject models from the models folder by just using their name. On startup it will scan your entire models folder and will register all the discovered models. This setting is true by default.

    caseSensitiveImplicitViews

    By default implicit views are case sensitive since ColdBox version 5.2.0, before this version the default was false.

    eventCaching

    This directive tells ColdBox that when events are executed they will be inspected for caching metadata. This does not mean that ALL events WILL be cached if this setting is turned on. It just activates the inspection mechanisms for whenever you annotate events for caching or using the runEvent() caching methods.

    handlerCaching

    This is useful to be set to false in development and true in production. This tells the framework to cache your event handler objects as singletons.

    implicitViews

    Allows you to use implicit views in your application and view dispatching. You can get a performance boost if you disable this setting.

    identifierProvider

    This setting allows you to configure a lambda/closure that will return back the user's request identifier according to your own algorithms. This overrides the internal way ColdBox identifies requests incoming to the application which are used internally to track sessions, flash rams, etc.

    The discovery algorithm we use is the following:

    1. If we have an identifierProvider closure/lambda/udf, then call it and use the return value

    2. If we have sessions enabled, use the jessionId or session URL Token

    3. If we have cookies enabled, use the cfid/cftoken

    4. If we have in the URL the cfid/cftoken

    5. Create a request based tracking identifier: cbUserTrackingId

    proxyReturnCollection

    This is a boolean setting used when calling the ColdBox proxy's process() method from a Flex or SOAP/REST call. If this setting is set to true, the proxy will return back to the remote call the entire request collection structure ALWAYS! If set to false, it will return, whatever the event handler returned back. Our best practice is to always have this false and return appropriate data back.

    viewCaching

    This directive tells ColdBox that when views are rendered, the cache=true parameter will be obeyed. Turning on this setting will not cause any views to be cached unless you are also passing in the caching parameters to your view() or event.setView() calls.

    Setting a view does not mean that it gets rendered immediately. This means that it is deposited in the context of the request. Later on in the execution process, the framework will pick those variables up and do the actual rendering. To do immediate rendering, you will use the inline rendering methods described later.

    We use the setView() method to set the view views/general/index.cfm to be rendered. The cool thing about this is that we can override the view to be rendered anytime during the request flow. So, the last process to execute the setView() method is the one that counts. Also, notice a few things:

    • No extension is needed.

    • You can traverse directories by using / like normal cfinclude notation.

    • The view can exist in the conventions directory views or your configured external locations

    • You did not specify a layout for the view, so the application's default layout (Main) will be used.

    It is best practice that view locations should simulate the event. So, if the event is general.index, there should be a general folder in the root views folder with a view called index.cfm/bxm

    Let's look at the view code:

    I am using our cool HTML Helper class, which is smart enough to render tables, data, HTML 5 elements, etc., and even bind to ColdFusion ORM entities.

    Views With No Layout

    So what happens if I DO NOT want the view rendered within a layout? Am I doomed? Of course not, use the same method with the noLayout argument or event.noLayout() method:

    Views With Layouts

    If you need the view to be rendered in a specific layout, then use the layout argument or the setLayout() method:

    Views From Modules

    If you need the set a view to be rendered from a specific ColdBox Module then use the module argument alongside any other argument combination:

    View Regions

    The setView() method also has a name argument, which you can use to denote a rendering region. This will not affect the main set view rendered by the framework. This will set up the arguments to render the view, and then YOU will use the #view( name : "myRegion" )# code to render it wherever you like. The purpose of this method is to encapsulate rendering mechanics from views and let the handlers control it.

    Now that you have set the named region, you can evaluate it and render it it using the view()method

    Render Nothing

    You can also tell the renderer not to render anything back to the user by using the event.noRender() method. Maybe you just took some input and need to gracefully shut down the request into the infamous white screen of death.

    Implicit Views

    You can also omit the explicit event.setView() if you want, ColdBox will then look for the view according to the executing event's syntax by convention. So if the incoming event is called general.index and no view is explicitly defined in your handler, ColdBox will look for a view in the general folder called index.cfm. We recommend matching event resolution to view resolution, even if you use implicit views.

    Tip: This feature is more for convention purists than anything else. However, we do recommend, as best practice, explicitly declaring the view to be rendered when working with team environments, as everybody will know what happens.

    Caution: If using implicit views, please note that the name of the view will ALWAYS be in lowercase. So please be aware of this limitation. I would suggest creating URL Mappings with explicit event declarations to control case and location. When using implicit views, you will also lose fine rendering control.

    Disabling Implicit Views

    You can also disable implicit views by using the coldbox.implicitViews configuration setting in your config/ColdBox.cfc. This is useful as implicit lookups are time-consuming.

    Case Sensitivity

    The ColdBox rendering engine can also be tweaked to use case-insensitive or sensitive implicit views by using the coldbox.caseSensitiveImplicitViews directive in your config/ColdBox.cfc. The default is to turn all implicit views to lowercase, so the value is always false.

    request collection RC

  • structs

  • json

  • xml

  • query

  • The method will try to match the incoming variables names in the data packet to a setter or property in the target model object. If there is a match, then it will inject that data into the model or call it's setter for you.

    Let's explore the API

    Examples

    Let's do a quick example. Here is a Person.cfc that has two properties with automatic getters/setters.

    Person.cfc

    editor.cfm

    Here is an editor to submit a form to create the person.

    Event Handler -> person.cfc

    Here is an event handler to do the saving

    Run the code, and you will see that the populator matched the incoming variables into the model and thus binding it.

    ORM Integration

    The populator can also bind ORM objects natively. However, it can also build out relationships via the composeRelationships argument. This allows you to create the objects from simple identifiers for the following relationships:

    • one-to-one : The id of the relationship

    • many-to-one : The id of the parent relationship

    • one-to-many : A list of identifiers to link to the target object which ends up being an array of objects

    • many-to-many : A list of identifiers to link to the target object which ends up being an array of objects

    So if we have a User object with a many-to-one of Role and a many-to-many of Permissions, we could populate the User with all of it's data graph:

    This packet has the two relationships role and permissions as an incoming list. The list can be a simple string or an actual JSON array. To populate we can do this:

    That's it. ColdBox will take care of matching and building out the relationships.

    You can also use the nullEmptyInclude and nullEmptyExclude properties to include and exclude null value population.

    You can also use ignoreEmpty to ignore all the empty values on population so the ORM treats them as null

    Mass Population Control: this.population

    ColdBox also supports the ability for target objects to dictate how they will be populated. This convention allows for objects to encapsulate the way the mass population of data is treated. This way, you donโ€™t have to scrub or pass include excludes lists via population arguments; it can all be nicely encapsulated in the targeted objects. Just declare a this.population in your object's pseudo constructor:

    The populator will look for a this.population struct with the following keys:

    • include : an array of property names to allow population ONLY

    • exclude : an array of property names to NEVER allow population

    Ignoring Mass Population

    The population methods also have an argument called: ignoreTargetLists which defaults to false, meaning it inspects the objects for these population markers. If you pass it as true then the markers will be ignored. This is great for the population of objects from queries or an array of structs or mementos that YOU have control of. Great in DAOs or service layers.`

    WireBox's object population
    config/Router.cfc
    component {
    
    	function configure() {
    		// Set Full Rewrites
    		setFullRewrites( true );
    
    		/**
    		 * --------------------------------------------------------------------------
    		 * App Routes
    		 * --------------------------------------------------------------------------
    		 *
    		 * Here is where you can register the routes for your web application!
    		 * Go get Funky!
    		 *
    		 */
    
    		// A nice healthcheck route example
    		route( "/healthcheck", function( event, rc, prc ) {
    			return "Ok!";
    		} );
    
    		// A nice RESTFul Route example
    		route( "/api/echo", function( event, rc, prc ) {
    			return {
    				"error" : false,
    				"data"  : "Welcome to my awesome API!"
    			};
    		} );
    
    		route(
    			pattern : "/api/contacts",
    			target  : "contacts.index",
    			name    : "api.contacts"
    		);
    
    		// Conventions based routing
    		route( ":handler/:action?" ).end();
    	}
    
    }
    
    function configure(){
    
        setFullRewrites( true );
        setExtensionDetection( true );
        setValidExtensions( "json,cfm,pdf" );
        setMultiDomainDiscovery( false )
    
    }
    /**
     * Render out a view
     *
     * @view                   The the view to render, if not passed, then we look in the request context for the current set view.
     * @args                   A struct of arguments to pass into the view for rendering, will be available as 'args' in the view.
     * @module                 The module to render the view from explicitly
     * @cache                  Cached the view output or not, defaults to false
     * @cacheTimeout           The time in minutes to cache the view
     * @cacheLastAccessTimeout The time in minutes the view will be removed from cache if idle or requested
     * @cacheSuffix            The suffix to add into the cache entry for this view rendering
     * @cacheProvider          The provider to cache this view in, defaults to 'template'
     * @collection             A collection to use by this Renderer to render the view as many times as the items in the collection (Array or Query)
     * @collectionAs           The name of the collection variable in the partial rendering.  If not passed, we will use the name of the view by convention
     * @collectionStartRow     The start row to limit the collection rendering with
     * @collectionMaxRows      The max rows to iterate over the collection rendering with
     * @collectionDelim        A string to delimit the collection renderings by
     * @prePostExempt          If true, pre/post view interceptors will not be fired. By default they do fire
     * @name                   The name of the rendering region to render out, Usually all arguments are coming from the stored region but you override them using this function's arguments.
     * @viewVariables          A struct of variables to incorporate into the view's variables scope.
     */
    function view(
    	view                   = "",
    	struct args            = getRequestContext().getCurrentViewArgs(),
    	module                 = "",
    	boolean cache          = false,
    	cacheTimeout           = "",
    	cacheLastAccessTimeout = "",
    	cacheSuffix            = "",
    	cacheProvider          = "template",
    	collection,
    	collectionAs               = "",
    	numeric collectionStartRow = "1",
    	numeric collectionMaxRows  = 0,
    	collectionDelim            = "",
    	boolean prePostExempt      = false,
    	name,
    	viewVariables = {}
    )
    /**
     * Renders an external view anywhere that cfinclude works.
     *
     * @view                   The the view to render
     * @args                   A struct of arguments to pass into the view for rendering, will be available as 'args' iview.
     * @cache                  Cached the view output or not, defaults to false
     * @cacheTimeout           The time in minutes to cache the view
     * @cacheLastAccessTimeout The time in minutes the view will be removed from cache if idle or requested
     * @cacheSuffix            The suffix to add into the cache entry for this view rendering
     * @cacheProvider          The provider to cache this view in, defaults to 'template'
     * @viewVariables          A struct of variables to incorporate into the view's variables scope.
     */
    function externalView(
    	required view,
    	struct args            = getRequestContext().getCurrentViewArgs(),
    	boolean cache          = false,
    	cacheTimeout           = "",
    	cacheLastAccessTimeout = "",
    	cacheSuffix            = "",
    	cacheProvider          = "template",
    	viewVariables          = {}
    )
    /**
     * Render a layout or a layout + view combo
     *
     * @layout        The layout to render out
     * @module        The module to explicitly render this layout from
     * @view          The view to render within this layout
     * @args          An optional set of arguments that will be available to this layouts/view rendering ONLY
     * @viewModule    The module to explicitly render the view from
     * @prePostExempt If true, pre/post layout interceptors will not be fired. By default they do fire
     * @viewVariables A struct of variables to incorporate into the view's variables scope.
     */
    function layout(
    	layout,
    	module                = "",
    	view                  = "",
    	struct args           = getRequestContext().getCurrentViewArgs(),
    	viewModule            = "",
    	boolean prePostExempt = false,
    	viewVariables         = {}
    )
    <cfoutput>
    // render inline
    #view( 'tags/metadata' )#
    
    // render from a module
    #view( view="security/user", module="security" )#
    
    // render a region
    #view( name : "userLogins" )#
    
    // render and cache
    #view(
        view="tags/longRendering", 
        cache=true, 
        cacheTimeout=5, 
        cacheProvider="couchbase"
    )#
    
    // render a view from the handler action
    function showData(event,rc,prc){
        // data here
        return view( "general/showData" );    
    }
    
    // render an email body content in an email template layout
    body = layout( layout='email',view='templates/email_generic' );
    </cfoutput>
    property name="renderer" inject="provider:coldbox:renderer";
    function sendEmail(){
        
        // code here.
        var body = renderer.view( "templates/email" );
    
    }
    coldbox = {
        // The name of the application
        appName     = "My App",
        // The name of the incoming URL/FORM/REMOTE variable that tells the framework what event to execute. Ex: index.cfm?event=users.list
        eventName   = "event",
        // The URI of the ColdBox application on the webserver. Use when ColdBox app exists within subdirectory from project root, otherwise can be omitted
        appMapping  = ""
    };
    coldbox = {
        reinitPassword = "h1cker",
        reinitKey = "fwReinit",
        handlersIndexAutoReload = true
    };
    // reinit with no password
    http://localhost/?fwreinit=1
    // reinit with password
    http://localhost/?fwreinit=mypass
    coldbox = {
        reinitKey = "myreinit"
    }
    coldbox={
        //Implicit Events
        defaultEvent  = "Main.index",
        requestStartHandler     = "Main.onRequestStart",
        requestEndHandler   = "Main.onRequestEnd",
        applicationStartHandler = "Main.onAppInit",
        applicationEndHandler = "Main.onAppEnd",
        sessionStartHandler = "Main.onSessionStart",
        sessionEndHandler = "Main.onSessionEnd",
        missingTemplateHandler = "Main.onMissingTemplate"
    }
    coldbox={
        //Extension Points
        applicationHelper             = "includes/helpers/ApplicationHelper.cfm",
        viewsHelper                    = "",
        modulesExternalLocation        = [],
        viewsExternalLocation        = "",
        layoutsExternalLocation     = "",
        handlersExternalLocation      = "",
        requestContextDecorator     = "",
        controllerDecorator         = ""
    }
    coldbox.viewsHelper = "includes/helpers/global"
    coldbox = {
        // Error/Exception Handling handler
        exceptionHandler        = "",
        // Invalid HTTP method Handler
        invalidHTTPMethodHandler = "",
        // The handler to execute on invalid events
        invalidEventHandler = "",
        // The default error template    
        customErrorTemplate     = "/coldbox/system/exceptions/BugReport-Public.cfm"
    }
    coldbox.customErrorTemplate = "/coldbox/system/exceptions/BugReport.cfm";
    coldbox = {
        // Persist handlers
        handlerCaching             = false,
        // Activate event caching
        eventCaching            = true,
        // Activate view  caching
        viewCaching              = true,
        // Return RC struct on Flex/Soap Calls
        proxyReturnCollection     = false,
        // Activate implicit views
        implicitViews           = true,
        // Case for implicit views
        caseSensitiveImplicitViews = true,
        // Auto register all model objects in the `models` folder into WireBox
        autoMapModels     = true,
        // Your very own session tracking identifier
        identifierProvider = function(){
            return my own session tracking id;
        }
    }
    /**
     * Set the view to render in this request. Private Request Collection Name: currentView, currentLayout
     *
     * @view                   The name of the view to set. If a layout has been defined it will assign it, else if will assign the default layout. No extension please
     * @args                   An optional set of arguments that will be available when the view is rendered
     * @layout                 You can override the rendering layout of this setView() call if you want to. Else it defaults to implicit resolution or another override.
     * @module                 The explicit module view
     * @noLayout               Boolean flag, wether the view sent in will be using a layout or not. Default is false. Uses a pre set layout or the default layout.
     * @cache                  True if you want to cache the rendered view.
     * @cacheTimeout           The cache timeout in minutes
     * @cacheLastAccessTimeout The last access timeout in minutes
     * @cacheSuffix            Add a cache suffix to the view cache entry. Great for multi-domain caching or i18n caching.
     * @cacheProvider          The cache provider you want to use for storing the rendered view. By default we use the 'template' cache provider
     * @name                   This triggers a rendering region.  This will be the unique name in the request for specifying a rendering region, you can then render it by passing the unique name to the view();
     *
     * @return RequestContext
     */
    function setView(
     view,
     struct args = {},
     layout,
     module                 = "",
     boolean noLayout       = false,
     boolean cache          = false,
     cacheTimeout           = "",
     cacheLastAccessTimeout = "",
     cacheSuffix            = "",
     cacheProvider          = "template",
     name
    )
    handlers/main.cfc
    component
    {
    
        function index(event,rc,prc){
            // call some model for data and put into the request collection
            prc.myQuery = getInstance('MyService').getData();
            // set the view for rendering
            event.setView( "general/index" );
    
        }
    
    }
    main/index.cfm
    <cfoutput>
    <h1>My Cool Data</h1>
    #html.table( data=prc.myQuery, class="table table-striped table-hover" )#
    </cfoutput>
    component{
    
        function index(event,rc,prc){
            // call some model for data and put into the request collection
            prc.myQuery = getInstance('MyService').getData();
            // set the view for rendering
            event.setView( view="general/index", noLayout=true );
        }
    
        function index(event,rc,prc){
            // call some model for data and put into the request collection
            prc.myQuery = getInstance('MyService').getData();
            // set the view for rendering
            event.setView( "general/index" ).noLayout();
        }
    }
    component name="general"{
    
        function index(event,rc,prc){
            // call some model for data and put into the request collection
            prc.myQuery = getInstance('MyService').getData();
            // set the view for rendering
            event.setView( view="general/index", layout="Ajax" );
        }
    
        function index(event,rc,prc){
            // call some model for data and put into the request collection
            prc.myQuery = getInstance('MyService').getData();
            // set the view for rendering
            event.setView( "general/index" ).setLayout( "Ajax" );
        }
    
    }
    component name="general"{
    
        function index( event, rc, prc ){
    
            // call some model for data and put into the request collection
            prc.myQuery = getInstance('MyService').getData();
            // set the view for rendering
            event.setView( view="general/index", module="shared-views" );
    
        }
    
    }
    function index( event, rc, prc ){
        ...
        event.setView(
            name : "userLogins",
            args : { data : userService.getLatestLogins() },
            .. Any other view arguments
        )
        ...
    }
    <div id="latestLogins">#view( name : "userLogins" )#</div>
    component name="general"{
    
        function saveData(event,rc,prc){
            // do your work here โ€ฆ..
    
            // set for no render
            event.noRender();
        }
    
    }
    component name="general"{
    
        function index( event, rc, prc ){
            // call some model for data and put into the request collection
            prc.myQuery = getInstance( 'MyService' ).getData();    
        }
    
    }
    coldbox.implicitViews = false;
    coldbox.caseSensitiveImplicitViews = true;
    
    /**
     * Populate an object from the incoming request collection
     *
     * @model                The name of the model to get and populate or the acutal model object. If you already have an instance of a model, then use the populateBean() method
     * @scope                Use scope injection instead of setters population. Ex: scope=variables.instance.
     * @trustedSetter        If set to true, the setter method will be called even if it does not exist in the object
     * @include              A list of keys to include in the population
     * @exclude              A list of keys to exclude in the population
     * @ignoreEmpty          Ignore empty values on populations, great for ORM population
     * @nullEmptyInclude     A list of keys to NULL when empty
     * @nullEmptyExclude     A list of keys to NOT NULL when empty
     * @composeRelationships Automatically attempt to compose relationships from memento
     * @memento              A structure to populate the model, if not passed it defaults to the request collection
     * @jsonstring           If you pass a json string, we will populate your model with it
     * @xml                  If you pass an xml string, we will populate your model with it
     * @qry                  If you pass a query, we will populate your model with it
     * @rowNumber            The row of the qry parameter to populate your model with
     * @ignoreTargetLists    If this is true, then the populator will ignore the target's population include/exclude metadata lists. By default this is false.
     *
     * @return The instance populated
     */
    function populate(
    	required model,
    	scope                        = "",
    	boolean trustedSetter        = false,
    	include                      = "",
    	exclude                      = "",
    	boolean ignoreEmpty          = false,
    	nullEmptyInclude             = "",
    	nullEmptyExclude             = "",
    	boolean composeRelationships = false,
    	struct memento               = getRequestCollection(),
    	string jsonstring,
    	string xml,
    	query qry,
    	boolean ignoreTargetLists = false
    )
    models/Person.cfc
    component accessors="true"{
    
        property name="name";
        property name="email";
    
        function init(){
            setName('');
            setEmail('');
        }
    }
    views/person/editor.cfm
    <cfoutput>
    <h1>Funky Person Form</h1>
    #html.startForm( action='person.save' )#
    
        #html.textfield( label="Your Name:", name="name", wrapper="div")#
        #html.textfield( label="Your Email:", name="email", wrapper="div")#
    
        #html.submitButton( value="Save" )#
    
    #html.endForm()#
    </cfoutput>
    handlers/person.cfc
    component{
    
        function editor(event,rc,prc){
            event.setView( "person/editor" );        
        }
    
        function save(event,rc,prc){
    
            var person = populateModel( "Person" );
    
            writeDump( person );
            abort;
        }
    
    }
    user.json
    {
       "fname" : "luis",
       "lname" : "coldbox",
       "role" : 123,
       "permissions" : "123,456,789"
    }
    populate( model : "User", composeRelationships : true )
    this.population = {
        include : [ "firstName", "lastName", "username", "role" ],
        exclude : [ "id", "password", "lastLogin" ]
    };
    populateFromStruct(
        target : userService.newUser(),
        memento : record,
        ignoreTargetLists : true
    }

    cbController

    The name of the key the framework will store the application controller under in the application scope.

    COLDBOX_FAIL_FAST

    true

    By default if an app is reiniting and a request hits it, we will fail fast with a message. This can be a boolean indicator or a closure.

    MockDataCFC
    ColdBox's HTML Helper
    http://apidocs.ortussolutions.com/coldbox/current/index.html?coldbox/system/modules/HTMLHelper/models/HTMLHelper.html
    https://apidocs.ortussolutions.com/commandbox/current/index.html
    full docs
    LogBox
    logger object
    WireBox Injector

    My First ColdBox Application

    The coldbox create app command enables you to create application skeletons using one of our official skeletons or your own. Here are the names of the common ones you can find in our Github Organization:

    • Default: The default app template

    • Elixir : A ColdBox Elixir based template to do asset compilation for you

    • Rest: A RESTFul services template

    • Rest-hmvc: A RESTFul service built with modules

    • SuperSimple : The bare-bones template

    • Vite: The default template using VITE for asset bundling

    You can find all our template skeletons here:

    Scaffolding Our Application

    So let's create our first app using the default template skeleton:

    File/Folder Conventions

    Here are some of the major files and directory conventions you should know about:

    Directory
    Convention
    Mandatory
    Description

    Here are the major files you should know about:

    File
    Convention
    Mandatory
    Description

    Now let's start a server so we can see our application running:

    Default Event

    This command will start a server with URL rewrites enabled, open a web browser for you, and execute the index.cfm which in turn executes the default event by convention in a ColdBox application: main.index. This is now our first runtime convention!

    Instead of executing pages like in a traditional application, we always execute the same page but distinguish the event we want via . When no mappings are present, we execute the default event by convention.

    Tip: ColdBox Events map to handlers (cfc) and appropriate actions (functions)

    Tip: The default event can also be changed in the configuration file: config/Coldbox.cfc

    Hooray, we have scaffolded our first application, started a server, and executed the default event. Explore the application template generated, which contains useful information about your application.

    Tip: Type coldbox create app help to get help on all the options for creating ColdBox applications.

    Let's open the handler and see the code, so open handlers/main.cfc

    The action (function) we are interested in is the index() function.

    It sets a message in an incoming prc argument and then calls a method in the incoming event argument to set a view for rendering. We will discover these arguments in the next section. For now, we need to understand that handler actions are in place of traditional CFML pages. Depending on the incoming URL route, we execute the appropriate handler and action function.

    Re-initializing the Application

    There will be times when you make configuration or metadata/singleton code changes that are not reflected immediately in the application due to caching. You can tell the framework to reinit or restart the application for you via the URL by leveraging the special URL variable fwreinit.

    You can also use CommandBox to reinit the application:

    Tip: You can add a password to the reinit procedures for further security, please see the .

    Getting Started Guide

    The ColdBox HMVC Platform is the de-facto enterprise-level HMVC framework for CFML developers. Quick and painless getting started guide.

    The ColdBox HMVC Platform is the de-facto enterprise-level HMVC framework for CFML developers. It's professionally backed, highly extensible, and productive. Getting started with ColdBox is quick and painless. The only thing you need to begin is , a command line tool for CFML developers. Please remember to us in Github.

    This is a one-page introductory guide to ColdBox. If you are new to MVC or ColdBox, you can also leverage our as well.

    Need Help

    Upgrading to ColdBox 8

    The official ColdBox 8 upgrade guide

    The major compatibility issues will be covered, as well as how to upgrade to this release from previous ColdBox versions smoothly. You can also check out the guide to give you a full overview of the changes.

    An upgrade from ColdBox 7 should not incur any breaking changes, but you should still read through the guide to ensure you are not using any deprecated or removed features.

    ColdFusion 2018-2021 Support Dropped

    ColdFusion 2018-2021 support has been dropped. Adobe doesn't support them anymore, so neither do we.

    Model Integration

    We have a complete section dedicated to the , but we wanted to review a little here since event handlers need to talk to the model layer all the time. By default, you can interact with your models from your event handlers in two ways:

    • Dependency Injection ()

    • Request, use and discard model objects ()

    ColdBox offers its own dependency injection framework, , which allows you, by convention, to talk to your model objects. However, ColdBox also allows you to connect to third-party dependency injection frameworks via the IOC module:

    Resourceful Routes

    Resourceful routes are convention based to help you create routing with less boilerplate.

    In ColdBox, you can register resourceful routes (resources()) 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 and less typing ๐Ÿ˜‰

    This single resource declaration will create all the necessary variations of URL patterns and HTTP Verbs to actions to handle the resource. Please see the table below with all the permutations it will create for you.

    Verb
    Route
    Event
    Purpose
    coldbox create service name="ContactService" methods="getAll" --open
    /**
     * I am a new Model Object
     */
    component singleton accessors="true"{
    
    	// Properties
    	
    
    	/**
    	 * Constructor
    	 */
    	ContactService function init(){
    
    		return this;
    	}
    
    	/**
    	 * getAll
    	 */
    	function getAll(){
    
    	}
    
    
    }
    /**
     * I am a new Model Object
     */
    component singleton accessors="true"{
    
    	// Properties
    	property name="data" type="array";
    
    	/**
    	 * Constructor
    	 */
    	ContactService function init(){
    	  variables.data = [
                { "id"=1, "name"="coldbox" },
                { "id"=2, "name"="superman" },
                { "id"=3, "name"="batman" }
              ];
    		return this;
    	}
    
    	/**
    	 * Get all the contacts
    	 */
    	function getAll(){
    	  return variables.data;
    	}
    
    
    }
    coldbox create handler name="contacts" actions="index" --open
    component{ 
    
        property name="contactService" inject="ContactService";
    
        any function index( event, rc, prc ){ 
            event.setView( "contacts/index" ); 
        }
    }
    any function index( event, rc, prc ){
        prc.aContacts = contactService.getAll();
        event.setView( "contacts/index" );
    }
    <cfoutput>
    <h1>My Contacts</h1>
    
    #html.table( data=prc.aContacts, class="table table-striped" )#
    </cfoutput>
    Logo
    Logo
    Removals

    CacheBox Tag Interfaces: ICacheProvider, IStats

    The old interfaces that had been marked for deprecation in 6 are now removed. If you have custom cache providers or stats providers, you will need to update them to extend from the base classes:

    • coldbox.system.cache.ICacheProvider -> coldbox.system.cache.providers.ICacheProvider

    • coldbox.system.cache.IStats -> coldbox.system.cache.util.IStats

    BeanPopulator

    The BeanPopulator class has been removed. This class was deprecated in ColdBox 6 and was replaced by the ObjectPopulator class. Please use coldbox.system.core.dynamic.ObjectPopulator instead.

    Client Flash

    The Client Flash has been removed as it was deprecated in v6. The client scope is a very old, unperformant and insecure way of storing data. We recommend using CacheBox or Session scope instead.

    ColdBox Util Env/System Methods

    The following methods were removed in preference to the Environment Delegate class: coldbox.system.core.delegates.Env.

    Binder.getProperty() default Argument Removed

    The default argument was deprecated in ColdBox 6 and has now been removed. Please use defaultValue instead.

    Binder.getCacheBoxConfig() Removed

    The getCacheBoxConfig() method was deprecated in ColdBox 6 and has now been removed. Please use getCacheBox() instead.

    RequestContext SES Methods Removed

    The following methods were removed from the RequestContext class. These methods were deprecated in ColdBox 7.

    • isSES()

    • setSESEnabled()

    Router.getModulesRoutingTable() Removed

    The getModulesRoutingTable() method was deprecated in ColdBox 7 and has now been removed. Please use getModuleRoutingTable() instead.

    Router.includeRoutes() removed

    The includeRoutes() method was deprecated in ColdBox 6 and has now been removed. This was for cfm routers which are no longer in use.

    Router.with() and endWith() removed

    The with() and endWith() methods were deprecated in ColdBox 7 and have now been removed. Please use the group() method with closures instead.

    Router.addRoute() matchVariables Argument Removed

    The matchVariables string argument that mimicked a query string was deprecated in ColdBox 6 and has now been removed. Please use the rc or prc struct arguments instead.

    Router.setFullRewrites() Removed

    The setFullRewrites() method has been removed from the Router. This method was used to enable/disable SES URL rewrites but is no longer needed as SES routing is handled automatically.

    InterceptorService.processState() Removed

    The processState() method has been removed from the InterceptorService (COLDBOX-1358). This method was deprecated and has now been completely removed.

    Migration: Use the announce() method instead.

    Deprecations

    The following methods were deprecated in ColdBox 7 and will be removed in ColdBox 9.

    Super Type Methods

    • renderView() -> use view()

    • renderLayout() -> use layout()

    • renderExternalView() -> use externalView()

    • announceInterception() -> use announce()

    • populateModel() -> use populate()

    ScheduledExecutor

    • newSchedule() -> use newTask()

    AI-Assisted Upgrade Instructions

    The following instructions are designed to help AI assistants inspect and automatically upgrade ColdBox applications from version 7 to version 8.

    Code Inspection Patterns

    When analyzing ColdBox applications for upgrade compatibility, check for these patterns:

    1. Cache Provider Interface Usage

    Look for implementations extending deprecated interfaces:

    2. BeanPopulator Usage

    3. Client Flash Scope Usage

    4. Environment Method Usage

    5. Deprecated Binder Methods

    6. RequestContext SES Methods

    7. Router Removed Methods

    8. InterceptorService Removed Methods

    9. Super Type Method Usage

    Automated Replacement Rules

    Apply these replacements when upgrading code:

    Cache Provider Updates

    BeanPopulator to ObjectPopulator

    Environment Method Delegation

    Binder Method Updates

    Router Method Updates

    InterceptorService Method Updates

    Super Type Method Updates

    Client Flash Removal

    Upgrade Validation

    After applying automated changes, verify:

    1. Engine Compatibility: Ensure minimum ColdFusion 2021+ or Lucee 5.3+

    2. Test Coverage: Run existing test suites to validate functionality

    3. Cache Providers: Test custom cache provider implementations

    4. Module Compatibility: Verify all modules work with updated router methods

    5. Environment Variables: Ensure environment delegate usage works correctly

    Manual Review Required

    These patterns require manual developer review:

    • Custom cache providers extending old interfaces need logic review

    • Complex routing configurations using deprecated methods may need restructuring

    • Client flash scope usage requires architectural decisions for replacement

    • Environment method usage in performance-critical code may benefit from injection optimization

    Completion Checklist

    What's New
    /**
    * @deprecated Refactor to use the Env Delegate: coldbox.system.core.delegates.Env
    */
    function getSystemSetting( required key, defaultValue ){
        return new coldbox.system.core.delegates.Env().getSystemSetting( argumentCollection = arguments );
    }
    
    /**
    * @deprecated Refactor to use the Env Delegate: coldbox.system.core.delegates.Env
    */
    function getSystemProperty( required key, defaultValue ){
        return new coldbox.system.core.delegates.Env().getSystemProperty( argumentCollection = arguments );
    }
    
    /**
    * @deprecated Refactor to use the Env Delegate: coldbox.system.core.delegates.Env
    */
    function getEnv( required key, defaultValue ){
        return new coldbox.system.core.delegates.Env().getEnv( argumentCollection = arguments );
    }
    // Old way - removed
    with( namespace = "luis" )
        .addRoute(
            pattern = "contactus",
            view    = "simpleview"
        )
        .addRoute(
            pattern      = "contactus2",
            view         = "simpleview",
            viewnoLayout = true
        )
        .endWith();
    
    // New way - use group() with closure
    group( { namespace : "luis" }, ( options ) => {
        route( pattern: "contactus" ).toView( view: "simpleview" );
        route( pattern: "contactus2" ).toView( view: "simpleview", noLayout: true );
    } );
    
    // Old way - removed
    router.addRoute(
            pattern : "/myroute",
            handler : "myHandler",
            action : "myAction",
            matchVariables : "id=1&name=test"
        )
    
    // New way - use rc or prc
    router.addRoute(
            pattern : "/myroute",
            handler : "myHandler",
            action : "myAction",
            rc : { id = 1, name = "test" }
        )
    // Old way - removed
    interceptorService.processState( "myEvent", data );
    
    // New way - use announce()
    interceptorService.announce( "myEvent", data );
    // Search for these deprecated patterns:
    - extends="coldbox.system.cache.ICacheProvider"
    - extends="coldbox.system.cache.IStats"
    // Search for BeanPopulator instantiation or injection:
    - new coldbox.system.core.dynamic.BeanPopulator()
    - property name="beanPopulator" inject="BeanPopulator"
    - wirebox.getInstance( "BeanPopulator" )
    // Search for client flash scope references:
    - flash.setFlash()
    - flash.getFlash()
    - flashScope="client"
    - setNextEvent( flashScope="client" )
    // Search for deprecated util methods:
    - getSystemSetting()
    - getSystemProperty()
    - getEnv()
    // When found in non-Env delegate contexts
    // In WireBox binders, search for:
    - .getProperty( default=
    - .getCacheBoxConfig()
    // Search for these method calls:
    - event.isSES()
    - event.setSESEnabled()
    // Search for these router method calls:
    - router.getModulesRoutingTable()
    - router.includeRoutes()
    - router.with()
    - router.endWith()
    - router.setFullRewrites()
    - matchVariables argument in addRoute()
    // Search for deprecated InterceptorService method calls:
    - interceptorService.processState()
    - processState() // when called within interceptor context
    // Search for these method calls in handlers/interceptors:
    - renderView()
    - renderLayout()
    - renderExternalView()
    - announceInterception()
    - populateModel()
    - newSchedule() // in ScheduledExecutor context
    // Replace:
    extends="coldbox.system.cache.ICacheProvider"
    // With:
    extends="coldbox.system.cache.providers.ICacheProvider"
    
    // Replace:
    extends="coldbox.system.cache.IStats"
    // With:
    extends="coldbox.system.cache.util.IStats"
    // Replace all instances of:
    BeanPopulator
    // With:
    ObjectPopulator
    
    // Replace injection:
    inject="BeanPopulator"
    // With:
    inject="ObjectPopulator"
    // Replace utility method calls with Env delegate:
    getSystemSetting( "key", "default" )
    // With:
    new coldbox.system.core.delegates.Env().getSystemSetting( "key", "default" )
    
    // Or inject the delegate:
    property name="env" inject="coldbox.system.core.delegates.Env";
    // Then use:
    env.getSystemSetting( "key", "default" )
    // Replace:
    .getProperty( key, default=value )
    // With:
    .getProperty( key, defaultValue=value )
    
    // Replace:
    .getCacheBoxConfig()
    // With:
    .getCacheBox()
    // Replace:
    router.getModulesRoutingTable()
    // With:
    router.getModuleRoutingTable()
    
    // Replace with() and endWith() patterns:
    router.with( "api", function( route ) {
        route.get( "/users", "users.index" );
    } ).endWith();
    // With:
    router.group( { prefix: "api" }, function( route ) {
        route.get( "/users", "users.index" );
    } );
    
    // Replace matchVariables:
    router.addRoute(
        pattern="/route",
        handler="handler",
        matchVariables="id=1&name=test"
    )
    // With:
    router.addRoute(
        pattern="/route",
        handler="handler",
        rc={ id=1, name="test" }
    )
    // Replace:
    interceptorService.processState( "eventName", data )
    // With:
    interceptorService.announce( "eventName", data )
    
    // Replace:
    processState( "eventName", data )
    // With:
    announce( "eventName", data )
    // Replace deprecated methods:
    renderView() -> view()
    renderLayout() -> layout()
    renderExternalView() -> externalView()
    announceInterception() -> announce()
    populateModel() -> populate()
    newSchedule() -> newTask()
    // Remove or replace client flash usage:
    // Replace with session or cachebox alternatives
    setNextEvent( url="page", flashScope="client" )
    // With:
    setNextEvent( url="page" ) // uses session by default
    // Or:
    setNextEvent( url="page", flashScope="session" )

    config

    Configurations and module configurations

    handlers

    Event handler controllers

    includes

    i18n, JavaScript, helpers, CSS

    interceptors

    Event driven listeners go here

    layouts

    Application CFML layouts

    lib

    Java libraries or third party libraries

    models

    Model objects

    modules

    CommandBox driven dependencies

    modules_app

    Custom applicaiton modules

    tests

    Your application specs

    views

    Application CFML views

    .env

    Environment variables (Never commit)

    .env.example

    Example env file

    Application.cfc

    Your application bootstrap

    box.json

    Your CommandBox package descriptor

    index.cfm

    Front placeholder file

    server.json

    CommandBox server control

    .vscode

    Mappings and build tasks for VSCode

    build

    Docker helpers

    coldbox

    .cfconfig.json

    Loads the CFML Engine settings

    .cfformat.json

    Formatting rules

    .cflintrc

    github.com/coldbox-templates
    URL routing
    configuration section

    The framework library

    Linting rules

    The Ortus Community is the way to get any help for our entire platform and modules: https://community.ortussolutions.com

    IDE Tools

    ColdBox has the following supported IDE Tools:

    • Sublime - https://packagecontrol.io/packages/ColdBox Platform

    • VSCode - https://marketplace.visualstudio.com/items?itemName=ortus-solutions.vscode-coldbox

    Install CommandBox and ColdBox CLI

    You can read through our one-page CommandBox Getting Started Guide. Or simply grab the CommandBox executable from the download page and double click it to run.

    http://www.ortussolutions.com/products/commandbox

    You should now be seeing a prompt that looks like this:

    CommandBox Shell

    Now let's install the ColdBox CLI

    Now you will have the coldbox namespace of commands. Run coldbox help and discover it.

    Create A New Site

    Now we're cooking with gas! Let's create a new ColdBox application. CommandBox comes with built-in commands for scaffolding out new sites as well as installing ColdBox and other libraries. We'll start by changing into an empty directory where we want our new app to live. If necessary, you can create a new folder.

    Now let's ask CommandBox to create a new ColdBox app for us.

    Tip: You can find many scaffolding templates for ColdBox in our Github organization: github.com/coldbox-templates

    You can also issue a coldbox create app help command and get help for the creation command.

    File/Folder Conventions

    This command will place several new folders and files in your working directory. Let's run the ls command to view them.

    Here's a rundown of the important bits (Even though they might be more generated files/folders)

    • coldbox - This is the ColdBox framework managed by CommandBox

    • config/Coldbox.cfc - Your application configuration object

    • config/Router.cfc - Your application URL Router

    • handlers - Your controller layer, which in ColdBox they are called event handlers

    • layouts - Your HTML layouts

    • models - This holds your model CFCs

    • modules - This holds the CommandBox tracked modules

    • modules_app - This holds your app's modules

    • tests - Your test harness for unit and integration testing

    • views - Your HTML views will go here

    Start It Up

    Now that our shiny new MVC app is ready let's fire it up using the embedded server built into CommandBox. You don't need any other software installed on your PC for this to work. CommandBox has it all!

    In a few seconds, a browser window will appear with your running application. This is a full server with access to the web administrator, where you can add data sources, and mappings, or adjust the server settings. Notice the handy icon added to your system tray as well. The --rewritesEnable flag will turn on some basic URL rewriting so we have nice, pretty URLs.

    Tip: If you are creating an app to run on any server other than the CommandBox server, you will need to set up URL rewriting manually. More info here: /the-basics/routing/requirements

    Generated ColdBox App

    Take A Look Around

    ColdBox uses easy conventions to define the controllers and views in your app. Let's open up our main app controller in your default editor to have a looksie.

    At the top, you'll see a function named index. This represents the default action that runs for this controller, which in ColdBox land they are referred to as event handlers.

    Now let's take a look in the main/index view. It's located int he views folder.

    This line of code near the top of the view outputs the prc.welcomeMessage variable we set in the controller.

    Try changing the value being set in the handler and refresh your browser to see the change.

    Building On

    Let's define a new event handler now. Your controllers act as event handlers to respond to requests, REST API, or remote proxies.

    Pull up CommandBox again and run this command.

    That's it! You don't need to add any special configuration to declare your handler. Now we have a new handler called helloWorld with actions index, add, edit, and list. The command also created a test case for our handler as well as stubbed-out views for each of the actions.

    Let's hit this new controller we created with a URL like so. Your port number will probably be different.

    127.0.0.1:43272/helloWorld

    Normally the URL would have index.cfm before the /helloWorld bit, but our --rewritesEnable flag when we started the server makes this nicer URL possible.

    Install Packages

    ColdBox's MVC is simple, but its true power comes from the wide selection of modules you can install into your app for additional functionality. You can checkout the full list of modules available on the FORGEBOX directory: www.forgebox.io.

    Here's some useful examples:

    • BCrypt -- Industry-standard password hashing

    • cbdebugger -- For debugging Coldbox apps

    • cbjavaloader - For interacting with Java classes and libraries

    • cbMarkdown - For writing in markdown

    • cbMessagebox -- Display nice error/success messages

    • cborm -- Awesome ORM Services

    • cb18n -- For multilingual sites

    • cbt - ColdBox templating language

    • cbValidation - Back-end validation framework

    • qb - Fluent query builder and schema builder

    • route-visualizer - For visualizing your application routes

    Install cbmessagebox from the CommandBox prompt like this:

    We can see the full list of packages by using the list command.

    Right now we can see that our app depends on coldbox and cbmessagebox to run. We'll use our new cbmessagebox module in a few minutes. But first, we'll create a simple Model CFC to round out our MVC app.

    Creating A Model

    Models encapsulate the business logic of your application. They can be services, entities, or DAOs. We'll use CommandBox to create a GreeterService in our new app with a sayHello method.

    Tip: The --open is a nice shortcut that opens our new model in our default editor after creating it.

    Let's finish implementing the sayHello() method by adding this return statement and save the file.

    We can also add the word singleton to the component declaration. This will tell WireBox to only create one instance of our service.

    What is WireBox?

    WireBox is a dependency injection framework that is included with ColdBox. It will manage all object creations, persistence and assembling. You don't have to worry about using new or createobject() for CFCs anymore.

    Tie It All Together

    Ok, let's open up that helloWorld handler we created a while back. Remember, you can hit tab while typing to auto-complete your file names.

    We'll inject our greeterService and the cbmessagebox service into the handler by adding these properties to the top of /handlers/helloWorld.cfc.

    What is this magical injection? Injection is a way to get references of other objects placed in the variables scope of other objects. This makes your life easier as you don't have to manually create objects or even know where they exist.

    This will put the instance of our services in the variables scope where we can access it in our action methods.

    And now, in our index method, we'll set the output of our service into an info message.

    One final piece. Open up the default layout located in layouts/Main.cfm and find the #view()#. Add this line right before it to render out the message box that we set in our handler.

    Here we leverage the cbMessagebox() helper function which the MessageBox module collaborates to all layouts, views, handlers and interceptors.

    Now hit your helloWorld handler one final time with ?fwreinit=1 in the URL to see it all in action! (Again, your port number will most likely be different.

    127.0.0.1:43272/helloWorld?fwreinit=1

    What's Next?

    Congratulations! In a matter of minutes, you have created a full MVC application. You installed a community module from ForgeBox, created a new handler/view, and tied in business logic from a service model.

    As easy as that was, you're just scratching the surface of what ColdBox can do for you. Continue reading this book to learn more about:

    • Environment-specific configuration

    • Easy SES URL routing

    • Tons of 3rd party modules

    • Drop-in security system

    • Sweet REST web service support

    Getting Help

    If you run into issues or have questions, please jump on our Ortus Community and our Slack team and ask away.

    ColdBox is Professional Open Source under the Apache 2.0 license. We'd love to have your help with the product.

    CommandBox
    Star
    60 minute quick start guide

    Aggregation differs from ordinary composition in that it does not imply ownership. In composition, when the owning object is destroyed, so are the contained objects. - wikipedia

    Dependency Injection

    Your event handlers can be autowired with dependencies from WireBox by convention. By autowiring dependencies into event handlers, they will become part of the life span of the event handlers (singletons), since their references will be injected into the handler's variables scope. This is a huge performance benefit since event handlers are wired with all necessary dependencies upon creation instead of requesting dependencies (usage) at runtime. We encourage you to use injection whenever possible.

    Warning As a rule of thumb, inject only singletons into singletons. If not you can create unnecessary scope-widening injection issues and memory leaks.

    You will achieve this in your handlers via property injection, which is the concept of defining properties in the component with a special annotation called inject, which tells WireBox what reference to retrieve via the WireBox Injection DSL. Let's say we have a users handler that needs to talk to a model called UserService. Here is the directory layout so we can see the conventions

    Here is the event handler code to leverage the injection:

    Notice that we define a cfproperty with a name and inject attribute. The name becomes the name of the variable in the variables scope and the inject annotation tells WireBox what to retrieve. By default it retrieves model objects by name and path.

    Tip: The injection DSL is vast and elegant. Please refer to it. Also note that you can create object aliases and references in your config binder: config/WireBox.cfc

    Requesting Model Objects

    The other approach to integrating with model objects is to request and use them as associations via the framework super type method: getInstance(), which in turn delegates to WireBox's getInstance() method. We would recommend requesting objects if they are transient (have state) objects or stored in some other volatile storage scope (session, request, application, cache, etc). Retrieving of objects is okay, but if you will be dealing with mostly singleton objects or objects that are created only once, you will gain much more performance by using injection.

    Association defines a relationship between classes of objects that allows one object instance to cause another to perform an action on its behalf. - 'wikipedia'

    A practical example

    In this practical example we will see how to integrate with our model layer via WireBox, injections, and also requesting the objects. Let's say that we have a service object we have built called FunkyService.cfc and by convention we will place it in our applications models folder.

    FunkyService.cfc

    Our funky service is not that funky after all, but it is simple. How do we interact with it? Let's build a Funky event handler and work with it.

    Injection

    By convention, I can create a property and annotate it with an inject attribute. ColdBox will look for that model object by the given name in the models folder, create it, persist it, wire it, and return it. If you execute it, you will get something like this:

    Great! Just like that we can interact with our model layer without worrying about creating the objects, persisting them, and even wiring them. Those are all the benefits that dependency injection and model integration bring to the table.

    Alternative wiring

    You can use the value of the inject annotation in several ways. Below is our recommendation.

    Requesting

    Let's look at the requesting approach. We can either use the following approaches:

    Via Facade Method

    Directly via WireBox:

    Both approaches do exactly the same thing. In reality getInstance() does a wirebox.getInstance() callback (Uncle Bob), but it is a facade method that is easier to remember. If you run this, you will also see that it works and everything is fine and dandy. However, the biggest difference between injection and usage can be seen with some practical math:

    As you can see, the best performance is due to injection as the handler object was wired and ready to roll, while the requested approach needed the dependency to be requested. Again, there are cases where you need to request objects such as transient or volatile stored objects.

    Model Layer
    Aggregation
    Association
    WireBox
    http://forgebox.io/view/cbioc

    /photos

    photos.index

    Get all photos

    GET

    /photos/new

    photos.new

    Return the HTML form for creating a photo

    POST

    /photos

    photos.create

    Create a photo

    GET

    /photos/:id

    photos.show

    Show a photo by id

    GET

    /photos/:id/edit

    photos.edit

    Return the HTML form for editing the photo

    PUT/PATCH

    /photos/:id

    photos.update

    Update a photo by id

    DELETE

    /photos/:id

    photos.delete

    Delete a photo by id

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

    Scaffolding Resources

    We have created a scaffolding command in CommandBox to help you register and generate resourceful routes. Just run the following command in CommandBox to get all the help you will need in generating resources:

    API Resourceful Routes

    If you are building mostly API routes and not full HTML app routes, you can use the shortcut method apiResources() method instead. This method will work the same as above BUT it will exclude the new and edit actions for you since we are in API Land.

    Verb
    Route
    Event
    Purpose

    GET

    /photos

    photos.index

    Get all photos

    POST

    /photos

    photos.create

    Create a photo

    GET

    Here is the full method signature:

    GET

    Event Caching

    Event caching is extremely useful and easy to use. ColdBox will act like a cache proxy between your events and the clients requesting the events, much like squid, nginx or HA Proxy. All you need to do is add several metadata arguments to the action methods and the framework will cache the output of the event in the template cache provider in CacheBox. In other words, the event executes and produces output that the framework then caches. Subsequent calls to the same event with the same incoming RC variables will not do any processing, but just output the content back to the user.

    For example, you have an event called blog.showEntry. This event executes, gets an entry from the database and sets a view to be rendered. The framework then renders the view and if event caching is turned on for this event, the framework will cache the HTML produced. So the next incoming show entry event will just spit out the cached HTML. The cache key is created by hashing the incoming request collection.

    Important to note also, that any combination of URL/FORM parameters on an event will produce a unique cacheable key. So event=blog.showEntry&id=1 & event=blog.showEntry&id=2 are two different cacheable events.

    Enabling Event Caching

    To enable event caching, you will need to set a setting in your ColdBox.cfc called coldbox.eventcaching to true.

    Important Enabling event caching does not mean that ALL events will be cached. It just means that you enable this feature.

    Setting Up Actions For Caching

    The way to set up an event for caching is on the function declaration with the following annotations:

    Important Please be aware that you should not cache output with 0 timeouts (forever). Always use a timeout. Also, all events can have an unlimited amount of permutations, so make sure they expire and you purge them constantly. Every event + URL/FORM variable combination will produce a new cacheable entry.

    Examples

    Basic implementation of event caching using annotations:

    Greater Control Over Cache Keys

    You can customize how cache keys are generated using three specialized annotations: cacheInclude, cacheExclude, and cacheFilter.

    How Cache Keys Work

    By default, the cache key includes all keys from the request context (rc). The cache key annotations allow you to modify this behavior by including specific keys, excluding unwanted keys, or applying custom filtering logic.

    This is particularly useful for removing common tracking parameters (like utm_source, utm_medium, etc.) that shouldn't affect caching behavior.

    Available Annotations

    • cacheInclude Specifies which keys from the request context to include in the cache key calculation.

    • cacheExclude Specifies which keys from the request context to exclude from the cache key calculation.

    • cacheFilter Points to a private method that returns a closure for custom filtering logic. The closure receives a struct containing all potential cache key parameters and should return the filtered struct.

    Processing Order

    When multiple annotations are used together, ColdBox processes them in this specific order:

    1. cacheFilter - Apply custom filtering logic

    2. cacheInclude - Include only specified keys

    3. cacheExclude - Remove specified keys

    Understanding this order is important when combining annotations, as each step operates on the results of the previous step.

    Implementation Notes

    • The cacheFilter annotation must reference a private method within the same handler

    • The filter method should return a closure/lambda that accepts one argument (a struct)

    • The closure should return the modified struct to be used for cache key generation

    Examples

    Storage

    All event and view caching are stored in a named cache called template which all ColdBox applications have by default. You can open or create a new configuration object and decide where the storage is, timeouts, providers, etc. You have complete control of how event and view caching is stored.

    Purging

    We also have a great way to purge these events programmatically via our cache provider interface.

    Methods for event purging:

    • clearEvent( string eventSnippet, string querystring="" ): Clears all the event permutations from the cache according to snippet and querystring. Be careful when using incomplete event name with query strings as partial event names are not guaranteed to match with query string permutations

    • clearEventMulti( eventsnippets,string querystring="" ): Clears all the event permutations from the cache according to the list of snippets and querystrings. Be careful when using incomplete event name with query strings as partial event names are not guaranteed to match with query string permutations

    • clearAllEvents( [boolean async=true] )

    this.event_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 so it can add dynamic suffixes to cache keys. This can allow you to incorporate elements into the cache key at runtime instead of statically. This is a great way to incorporate the user's language locale or session identifier to make unique entries.

    OnRequestCapture - Influence Cache Keys

    We have provided an interception point in ColdBox that allows you to add variables into the request collection before a snapshot is made so you can influence the cache key of a cacheable event. What this means is that you can use it to mix in variables into the request collection that can make this event cache unique for a user, a specific language, country, etc. This is a great way to leverage event caching on multi-lingual or session based sites.

    With the simple example above, the user's locale will be added to all your event caching permutations and thus create entries for different languages.

    Life-Cycle Caveats

    Several event interception points are NOT available during event caching.

    When using event caching the framework will NOT execute ANY event at all. It will stream the content directly from the selected cache provider. This means that any interceptors or code that executes in the event is also NOT executed. The only interception points that will execute are:

    • preProcess

    • postProcess

    So please make sure you take note of this when planning for event security.

    Monitoring

    has an intuitive and powerful monitor that can be used via the ColdBox Debugger Module. From the monitor you can purge, expire and view cache elements, etc.

    Rendering Data

    Handler actions can return data back to its callers in many different formats. Either to create RESTFul services, or just send data that's not HTML back to the user. The different usages can be:

    • Complex Data

    • HTML

    • Rendered Data via event.renderData()

    coldbox create app Quickstart
    server start
    component extends="coldbox.system.EventHandler" {
    
    	/**
    	 * Default Action
    	 */
    	function index( event, rc, prc ){
    		prc.welcomeMessage = "Welcome to ColdBox!";
    		event.setView( "main/index" );
    	}
    
    	/**
    	 * Produce some restfulf data
    	 */
    	function data( event, rc, prc ){
    		return [
    			{ "id" : createUUID(), "name" : "Luis" },
    			{ "id" : createUUID(), "name" : "Joe" },
    			{ "id" : createUUID(), "name" : "Bob" },
    			{ "id" : createUUID(), "name" : "Darth" }
    		];
    	}
    
    	/**
    	 * Relocation example
    	 */
    	function doSomething( event, rc, prc ){
    		relocate( "main.index" );
    	}
    
    	/**
    	 * --------------------------------------------------------------------------
    	 * Implicit Actions
    	 * --------------------------------------------------------------------------
    	 * All the implicit actions below MUST be declared in the config/Coldbox.cfc in order to fire.
    	 * https://coldbox.ortusbooks.com/getting-started/configuration/coldbox.cfc/configuration-directives/coldbox#implicit-event-settings
    	 */
    
    	function onAppInit( event, rc, prc ){
    	}
    
    	function onRequestStart( event, rc, prc ){
    	}
    
    	function onRequestEnd( event, rc, prc ){
    	}
    
    	function onSessionStart( event, rc, prc ){
    	}
    
    	function onSessionEnd( event, rc, prc ){
    		var sessionScope     = event.getValue( "sessionReference" );
    		var applicationScope = event.getValue( "applicationReference" );
    	}
    
    	function onException( event, rc, prc ){
    		event.setHTTPHeader( statusCode = 500 );
    		// Grab Exception From private request collection, placed by ColdBox Exception Handling
    		var exception = prc.exception;
    		// Place exception handler below:
    	}
    
    }
    function index( event, rc, prc ){
    	prc.welcomeMessage = "Welcome to ColdBox!";
    	event.setView( "main/index" );
    }
    http://localhost:{port}/?fwreinit=1
    coldbox reinit
    install coldbox-cli
    mkdir playground --cd
    coldbox create app MyPlayground
    ls
    server start
    edit handlers/Main.cfc
    // Default Action
    function index( event, rc, prc ){
        prc.welcomeMessage = "Welcome to ColdBox!";
        event.setView( "main/index" );
    }
    edit views/main/index.cfm
    <h1>#prc.welcomeMessage#</h1>
    prc.welcomeMessage = "This is my new welcome message";
    coldbox create handler helloWorld index,add,edit,list --open
    install cbmessagebox
    list
    
    Dependency Hierarchy for myApp (0.0.0)
    +-- cbmessagebox (1.0.0)
    +-- coldbox (4.0.0)
    coldbox create service GreeterService sayHello --open
    component singleton {
    
        function sayHello(){
            return 'Hey you, have an awesome day!';
        }
    
    }
    edit handlers/helloWorld.cfc
    component {
    
        property name='greeterService' inject='greeterService';
        property name='messageBox' inject='@cbmessagebox';
    
        ...
    }
    function index( event, rc, prc ){
        messageBox.info( greeterService.sayHello() );
        event.setView( "helloWorld/index" );
    }
    #cbMessagebox().renderIt()#
    <div class="container">#view()#</div>
    Directory Layout
    + handlers
      + users.cfc
    + models
      + UserService.cfc
    users.cfc
    component name="MyHandler"{
        
        // Dependency injection of the model: UserService -> variables.userService
        property name="userService" inject="UserService";
    
        function index( event, rc, prc ){
            prc.data = userService.list()
            event.setView( "users/index" );
        }
    
    }
    users.cfc
    component{
    
        function index( event, rc, prc ){
            // Request to use the user service, this would be best to inject instead 
            // of requesting it.
            prc.data = getInstance( "UserService" ).list();
            event.setView( "users/index" );
        }
        
        function save( event, rc, prc ){
            // request a user transient object, populate it and save it.
            prc.oUser = populateModel( getInstance( "User" ) );
            userService.save( prc.oUser );
            relocate( "users/index" );
        }
    
    }
    Directory Layout
     + application
      + models
         + FunkyService.cfc
    component singleton{
    
        function init(){
            return this;
        }
    
        function add(a,b){ 
            return a+b; 
        }
    
        function getFunkyData(){
            var data = [
                {name="Luis", age="33"},
                {name="Jim", age="99"},
                {name="Alex", age="1"},
                {name="Joe", age="23"}
            ];
            return data;
        }
    
    }
    component{
    
        // Injection via property
        property name="funkyService" inject="FunkyService";
    
        function index(event,rc,prc){
    
            prc.data = funkyService.getFunkyData();
    
            event.renderData( data=prc.data, type="xml" );
        }    
    
    
    }
    <array>
        <item>
            <struct>
                <name>Luis</name>
                <age>33</age>
            </struct>
        </item>
        <item>
            <struct>
                <name>Jim</name>
                <age>99</age>
            </struct>
        </item>
        <item>
            <struct>
                <name>Alex</name>
                <age>1</age>
            </struct>
        </item>
        <item>
            <struct>
                <name>Joe</name>
                <age>23</age>
            </struct>
        </item>
    </array>
    // Injection using the DSL by default name/id lookup
    property name="funkyService" inject="FunkyService";
    // Injection using the DSL id namespace
    property name="funkyService" inject="id:FunkyService";
    // Injection using the DSL model namespace
    property name="funkyService" inject="model:FunkyService";
    component{
    
        function index(event,rc,prc){
    
            prc.data = getInstance( "FunkyService" ).getFunkyData();
    
            event.renderData( data=prc.data, type="xml" );
        }    
    
    
    }
    component{
    
        function index(event,rc,prc){
    
            prc.data = wirebox.getInstance( "FunkyService" ).getFunkyData();
    
            event.renderData( data=prc.data, type="xml" );
        }    
    
    
    }
    1000 Requests made to users.index
    
    - Injection: 1000 handler calls + 1 model creation and wiring call = 1001 calls
    - Requesting: 1000 handler calls + 1000 model retrieval + 1 model creation call = 2002 calls
    // Creates all resources that point to a photos event handler by convention
    resources( "photos" );
    
    // Register multiple fluently
    resources( "photos" )
        .resources( "users" )
        .resources( "contacts" );
    
    // Creates all resources to the event handler of choice instead of convention
    resources( resource="photos", handler="MyPhotoHandler" );
    
    // All resources in a module
    resources( resource="photos", handler="photos", module="api" );
    
    // Resources in a ModuleConfig.cfc
    router.resources( "photos" )
      .resources( resource="users", handler="user" )
    /**
     * 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 following rules apply
     * - The name of the resource maps to the name of the event handler
     * - The default paremeter name is called `:id`
     * - The available actions are: index, new, create, show, edit, update, delete
     *
     * 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` : `PUT/PATCH` -> `photos.update` Update a specific photo
     * - `/photos/:id` : `DELETE` -> `photos.delete` Delete a specific photo
     *
     * @resource      The name of a single resource to map
     * @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.
     * @pattern       If passed, the actual URL pattern to use, else it defaults to `/#arguments.resource#` the name of the resource.
     * @meta          A struct of metadata to store with ALL the routes created from this resource
     */
    function resources(
    	required resource,
    	handler,
    	parameterName    = "id",
    	only             = [],
    	except           = [],
    	string module    = "",
    	string namespace = "",
    	string pattern   = "",
    	struct meta      = {}
    ){
    coldbox create resource help
    apiResources( "users" );
    apiResources( "photos" );
    /**
     * Create all API RESTful routes for a resource. It will provide automagic mappings between HTTP verbs and URLs to event handlers and actions.
     *
     * By convention the following rules apply
     * - The name of the resource maps to the name of the event handler
     * - The default paremeter name is called `:id`
     * - The available actions are: index, create, show, update, delete
     *
     * Example: `resource = photos` Then we will create the following routes:
     * - `/photos` : `GET` -> `photos.index` Get a list of photos from the API
     * - `/photos` : `POST` -> `photos.create` Create a new photo
     * - `/photos/:id` : `GET` -> `photos.show` Get a specific photo from the API
     * - `/photos/:id` : `PUT/PATCH` -> `photos.update` Update a specific photo
     * - `/photos/:id` : `DELETE` -> `photos.delete` Delete a specific photo
     *
     * @resource      The name of a single resource to map
     * @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.
     * @pattern       If passed, the actual URL pattern to use, else it defaults to `/#arguments.resource#` the name of the resource.
     * @meta          A struct of metadata to store with ALL the routes created from this resource
     */
    function apiResources(
    	required resource,
    	handler,
    	parameterName    = "id",
    	only             = [],
    	except           = [ "new", "edit" ],
    	string module    = "",
    	string namespace = "",
    	string pattern   = "",
    	struct meta      = {}
    ){

    /photos/:id

    photos.show

    Show a photo by id

    PUT/PATCH

    /photos/:id

    photos.update

    Update a photo by id

    DELETE

    /photos/:id

    photos.delete

    Delete a photo by id

  • Uniform Response Data

  • The last option on the list is to support native REST Applications in ColdBox by leveraging the REST Handler.

    Complex Data

    By default, any complex data returned from handler actions will automatically be marshaled to JSON:

    Simple as that. ColdBox detects the complex object and tries to convert it to JSON for you automatically.

    renderdata Action Annotation

    If you want ColdBox to marshall the content to another type like XML or PDF. Then you can use the renderdata annotation on the action itself. The renderdata annotation can be any of the following values:

    • json

    • jsonp

    • jsont

    • xml

    • html

    • text

    • pdf

    renderdata Component Annotation

    You can also add the renderData annotation to the component definition and this will override the default of JSON. So if you want XML as the default, you can do this:

    $renderData Convention

    If the returned complex data is an object and it contains a function called $renderData(), then ColdBox will call it for you automatically. So instead of marshaling to JSON automatically, your object decides how to marshal itself.

    Native HTML

    By default if your handlers return simple values, then they will be treated as returning HTML.

    event.renderData()

    Using the renderdata() method of the event object is the most flexible for RESTFul web services or pure data marshaling. Out of the box ColdBox can marshall data (structs, queries, arrays, complex or even ORM entities) into the following output formats:

    • XML

    • JSON

    • JSONP

    • JSONT

    • HTML

    • TEXT

    • PDF

    • WDDX

    • CUSTOM

    Here is the method signature:

    Below are a few simple examples:

    As you can see, it is very easy to render data back to the browser or caller. You can even choose plain and send HTML back if you wanted to.

    Render PDFs

    You can also render out PDFs 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; like views, layouts, strings, etc.

    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.

    Renderdata With Formats

    The renderData() method also has two powerful arguments: formats & formatsView. If you currently have code like this:

    Where you need to param the incoming format extension, then do a switch and do some code for marshalling data into several formats. Well, no more, you can use our formats argument and ColdBox will marshall and code all that nasty stuff for you:

    That's it! ColdBox will figure out how to deal with all the passed in formats for you that renderdata can use. By convention it will use the name of the incoming event as the view that will be rendered for HTML and PDF; implicit views. If the event was users.list, then the view would be views/users/list.cfm. However, you can tell us which view you like if it is named different:

    If you need to redirect for html events, you can pass any arguments you normally would pass to setNextEvent to formatsRedirect.

    Custom Data Conversion

    You can do custom data conversion by convention when marshalling CFCs. If you pass in a CFC as the data argument and that CFC has a method called $renderdata(), then the marshalling utility will call that function for you instead of using the internal marshalling utilities. You can pass in the custom content type for encoding as well:

    The CFC converter:

    In this approach your $renderdata() function can be much more customizable than our internal serializers. Just remember to use the right contentType argument so the browser knows what to do with it.

    function showData( event, rc, prc ){
        prc.data = service.getUsers();
        return prc.data;
    }
    function usersAsXML( event, rc, prc ) renderdata='xml'{
        prc.data = service.getUsers();
        return prc.data;
    }
    
    function usersAsPDF( event, rc, prc ) renderdata='pdf'{
        prc.data = service.getUsers();
        return prc.data;
    }
    component renderdata="xml"{
    
    }
    function showUser( event, rc, prc ){
        return service.getUser( 2 );
    }
    function index(event,rc,prc){
        return "<h1>Hello from my handler today at :#now()#</h1>";
    }
    
    function myData( event, rc, prc ){
         prc.mydata = myservice.getData();
         return view( "main/myData" );
    }
    /**
    * Use this method to tell the framework to render data for you. The framework will take care of marshalling the data for you
    * @type The type of data to render. Valid types are JSON, JSONP, JSONT, XML, WDDX, PLAIN/HTML, TEXT, PDF. The deafult is HTML or PLAIN. If an invalid type is sent in, this method will throw an error
    * @data The data you would like to marshall and return by the framework
    * @contentType The content type of the data. This will be used in the cfcontent tag: text/html, text/plain, text/xml, text/json, etc. The default value is text/html. However, if you choose JSON this method will choose application/json, if you choose WDDX or XML this method will choose text/xml for you.
    * @encoding The default character encoding to use.  The default encoding is utf-8
    * @statusCode The HTTP status code to send to the browser. Defaults to 200
    * @statusText Explains the HTTP status code sent to the browser.
    * @location Optional argument used to set the HTTP Location header
    * @jsonCallback Only needed when using JSONP, this is the callback to add to the JSON packet
    * @jsonQueryFormat JSON Only: This parameter can be a Boolean value that specifies how to serialize ColdFusion queries or a string with possible values "row", "column", or "struct".
    * @jsonAsText If set to false, defaults content mime-type to application/json, else will change encoding to plain/text
    * @xmlColumnList XML Only: Choose which columns to inspect, by default it uses all the columns in the query, if using a query
    * @xmlUseCDATA XML Only: Use CDATA content for ALL values. The default is false
    * @xmlListDelimiter XML Only: The delimiter in the list. Comma by default
    * @xmlRootName XML Only: The name of the initial root element of the XML packet
    * @pdfArgs All the PDF arguments to pass along to the CFDocument tag.
    * @formats The formats list or array that ColdBox should respond to using the passed in data argument. You can pass any of the valid types (JSON,JSONP,JSONT,XML,WDDX,PLAIN,HTML,TEXT,PDF). For PDF and HTML we will try to render the view by convention based on the incoming event
    * @formatsView The view that should be used for rendering HTML/PLAIN/PDF. By default ColdBox uses the name of the event as an implicit view
    * @formatsRedirect The arguments that should be passed to relocate as part of a redirect for the HTML action.  If the format is HTML and this struct is not empty, ColdBox will call relocate with these arguments.
    * @isBinary Bit that determines if the data being set for rendering is binary or not.
    */
    function renderData(
        type="HTML",
        required data,
        contentType="",
        encoding="utf-8",
        numeric statusCode=200,
        statusText="",
        location="",
        jsonCallback="",
         jsonQueryFormat="true",
        boolean jsonAsText=false,
        xmlColumnList="",
        boolean xmlUseCDATA=false,
        xmlListDelimiter=",",
        xmlRootName="",
        struct pdfArgs={},
        formats="",
        formatsView="",
        formatsRedirect={},
        boolean isBinary=false
    ){
    // html marshalling
    function renderHTML(event,rc,prc){
        event.renderData( data="<h1>My HTML</h1>" );
    }
    // xml marshalling
    function getUsersXML(event,rc,prc){
        var qUsers = getUserService().getUsers();
        event.renderData( type="XML", data=qUsers );
    }
    //json marshalling
    function getUsersJSON(event,rc,prc){
        var qUsers = getUserService().getUsers();
        event.renderData( type="json", data=qUsers, statusCode=403 );
    }
    // 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=view("views/page"), type="PDF" );
    }
    // from content and with pdfArgs
    function pdf(event,rc,prc){
      var pdfArgs = { bookmark = "yes", backgroundVisible = "yes", orientation="landscape" };
      event.renderData(data=view("views/page"), type="PDF", pdfArgs=pdfArgs);
    }
    event.paramValue("format", "html");
    
    switch( rc.format ){
        case "json" : case "jsonp" : case "xml" : {
            event.renderData(data=mydata, type=rc.format);
            break;
        } 
        case "pdf" : {
            event.renderData(data=view("even/action"), type="pdf");
            break;
        }
        case "html" : {
            event.setView( "event/action" );
            break;
          }
    };
    event.renderData( data=MyData, formats="xml,json,html,pdf" );
    event.renderData( data=MyData, formats="xml,json,html,pdf", formatsView="data/MyView" );
    event.renderData( data=MyData, formats="xml,json,html,pdf", formatsRedirect={event="Main.index"} );
    // get an instance of your custom converter
    myConverter = getInstance("MyConverter")
    // put some data in it
    myConverter.setData( data );
    // marshall it out according to your conversions and the content type it supports
    event.renderData( data= myConverter, contentType=myConverter.getContentType() );
    component accessors="true"{
    
        property name="data" type="mytype";
        property name="contentType";
    
        function init(){ 
            setContentType("text");
            return this; 
        }
    
        // The magical rendering
        function $renderdata(){
            var d = {
                n = data.getName(),
                a = data.getAge(),
                c = data.getCoo(),
                today = now()
            };
    
            return d.toString();
        }
    
    }

    string

    Should reference the name of a private method in the handler that returns a closure.

    cacheInclude

    string

    A comma separated list of keys in the rc to include when creating the cache key. All other keys will be ignored

    cacheExclude

    string

    A comma separated list of keys in the rc to ignore when creating the cache key

    : Can clear ALL cached events in one shot and can be run asynchronously.

    Annotation

    Type

    Description

    cache

    boolean

    A true or false will let the framework know whether to cache this event or not. The default is FALSE. So setting to false makes no sense

    cachetimeout

    numeric

    The timeout of the event's output in minutes. This is an optional attribute and if it is not used, the framework defaults to the default object timeout in the cache settings. You can place a 0 in order to tell the framework to cache the event's output for the entire application timeout controlled by coldfusion, NOT GOOD. Always set a decent timeout for content.

    cacheLastAccesstimeout

    numeric

    The last access timeout of the event's output in minutes. This is an optional attribute and if it is not used, the framework defaults to the default last access object timeout in the cache settings. This tells the framework that if the object has not been accessed in X amount of minutes, then purge it.

    cacheProvider

    string

    The cache provider to store the results in. By default it uses the template cache.

    CacheBox
    CacheBox

    cacheFilter

     coldbox.eventCaching = true;
    // In Script
    function showEntry(event,rc,prc) cache="true" cacheTimeout="30" cacheLastAccessTimeout="15"{
        //get Entry
        prc.entry = getEntryService().getEntry(event.getValue('entryID',0));
    
        //set view
        event.setView('blog/showEntry');
    }
    // CacheInclude: Only use the specified keys in the `rc` when creating the cache key
    function show( event, rc, prc ) cache="true" cacheTimeout="30" cacheInclude="slug,id" {
      ...
    }
    
    // CacheExclude: Use all `rc` keys except those in the annotation
    function show( event, rc, prc ) cache="true" cacheTimeout="30" cacheInclude="utm_source,utm_medium,utm_campaign" {
      ...
    }
    
    // CacheFilter: Filter the `rc` keys based on a private method that returns a closure
    function show( event, rc, prc ) cache="true" cacheTimeout="30" cacheFilter="getCacheKeys" {
      ...
    }
    
    // private method used be CacheFilter. Returns a closure that accepts one argument
    function getCacheKeys() {
      var allowedKeys = [ "slug", "id" ];
      // return a closure/lambda
      return ( rcTarget ) => {
        return rcTarget.filter( ( key, value ) => {
          return allowedKeys.findNoCase( key ); // do custom filtering
        }
      }
    }
    templateCache = cachebox.getCache( "template" );
    //Trigger to purge all Events
    getCache( "template" ).clearAllEvents();
    
    //Trigger to purge all events synchronously
    getCache( "template" ).clearAllEvents(async=false);
    
    //Purge all events from the blog handler
    getCache( "template" ).clearEvent('blog');
    
    //Purge all permutations of the blog.dspBlog event
    getCache( "template" ).clearEvent('blog.dspBlog');
    
    //Purge the blog.dspBlog event with entry of 12345
    getCache( "template" ).clearEvent('blog.dspBlog','id=12345')
    this.EVENT_CACHE_SUFFIX = function( eventHandlerBean ){
      return "a localized string, etc";
    };
    component{
    
        onRequestCapture( event, data, buffer, rc, prc ){
            // Add user's locale to the request collection to influence event caching
            rc._user_locale = getFWLocale();
        }
    
    }
    box install cbdebugger
    ColdBox Site Quickstart
    Introduction | ColdBox Elixircoldbox-elixir.ortusbooks.com
    ColdBox Elixir Docs
    Logo

    What's New With 8.0.0

    Discover the power of ColdBox 8.0.0

    What's New With 8.0.0

    ๐ŸŽ‰ Welcome to ColdBox 8.0.0 - the most powerful and feature-rich release of the ColdBox HMVC platform yet! This major release brings exciting new capabilities, performance improvements, and modern development features that will supercharge your CFML applications.

    ๐Ÿš€ Major Highlights

    ColdBox 8.0.0 introduces groundbreaking features like BoxLang Prime integration, Virtual Thread Executors, enhanced AI-powered error handling, and a completely revamped developer experience. Whether you're building REST APIs, full-stack web applications, or microservices, this release has something exciting for every CFML developer.

    ๐ŸŽฏ Key Features At-a-Glance

    • ๐Ÿ”ฅ BoxLang Prime - Native BoxLang module with BoxLang compilation and optimization (bx-coldbox)

    • โšก Virtual Thread Executors - Modern async programming support

    • ๐Ÿค– AI-Enhanced Whoops Experience - Intelligent error diagnostics

    ๐ŸŽฏ Engine Support

    ColdBox 8.0.0 supports the following CFML engines:

    • โšก BoxLang 1.0.0+ (with native compilation support!)

    • ๐Ÿ“ฆ Adobe ColdFusion 2023+

    • ๐Ÿ”ฅ Lucee 5+

    ๐Ÿšจ Important: Adobe ColdFusion 2021 support has been dropped in this release. Please upgrade to CF 2023 or newer for continued support.

    ๐Ÿ“š Documentation MCP Server

    ColdBox documentation is now accessible via the Model Context Protocol (MCP)! Connect AI assistants like Claude, GitHub Copilot, and other MCP-compatible tools directly to the comprehensive ColdBox documentation for instant access to language references, framework features, and best practices.

    Connect to the MCP Server:

    • https://coldbox.ortusbooks.com/~gitbook/mcp

    • https://cachebox.ortusbooks.com/~gitbook/mcp

    • https://logbox.ortusbooks.com/~gitbook/mcp

    VSCode Connect:

    This enables developers to:

    • ๐Ÿ” Search ColdBox documentation semantically from within AI assistants

    • ๐Ÿ’ก Get instant answers about BIFs, components, and framework features

    • ๐Ÿ“– Access code examples and best practices without leaving your workflow

    • ๐Ÿค– Enhance AI-assisted ColdBox development with authoritative documentation

    ๐Ÿ”ฅ BX-ColdBox - BoxLang Native Edition

    In this release, we now introduce a new version of ColdBox specifically optimized and pre-compiled for BoxLang. Introducing bx-coldbox which you can install via CommandBox or the BoxLang module installer:

    This version of ColdBox is pre-compiled with BoxLang and optimized for performance. It also includes the new BoxLang Prime features for CacheBox, LogBox, and WireBox. It installs into the engine itself instead of your application. This means, you can have ColdBox available to any BoxLang application without needing to install it in each app. It also means that you can leverage the native BoxLang compilation for better performance, startup times, and security.

    โค๏ธโ€๐Ÿ”ฅ ColdBox BoxLang PRIME

    Say hello to BoxLang PRIME โ€” the next evolution of the ColdBox Platform. For the first time ever, you can build and run your ColdBox applications natively in BoxLang โ€” no CFML Compatibility Module required!

    BoxLang PRIME delivers full native integration across CacheBox, LogBox, and WireBox, unlocking a new era of speed, security, and seamless performance.

    • ๐Ÿ”ฅ Experience faster startups.

    • โšก Harness native BoxLang compilation.

    • ๐Ÿง  Build smarter, lighter, and more future-ready ColdBox apps.

    Combined with the new bx-coldbox package, BoxLang PRIME is the ultimate way to build modern JVM applications.

    Please Note: Not all modules are yet BoxLang PRIME compatible. We are working hard to bring you full compatibility across the entire ColdBox ecosystem. Stay tuned for updates!

    ๐Ÿ’ป ColdBox Desktop Applications

    Weโ€™ve been hard at work on something truly game-changing: soon, youโ€™ll be able to run your ColdBox applications as fully functional desktop apps with BoxLang Desktop.

    Thatโ€™s right โ€” build cross-platform desktop experiences powered by ColdBox and BoxLang, all with the same productivity and elegance you already love. With the introduction of bx-coldbox and ColdBox BoxLang PRIME support, you can now leverage the full power of ColdBox in desktop environments.

    • ๐Ÿ–ฅ๏ธ One language.

    • ๐ŸŒ Any platform.

    • โšก Endless possibilities.

    Stay tuned, this is coming real soon.

    ๐Ÿ› ๏ธ ColdBox CLI - Enhanced Developer Experience

    The ColdBox CLI has been completely revamped ๐ŸŽจ to support ColdBox 8 applications with enhanced features:

    • ๐Ÿ†• Migration Creation - Generate database migrations effortlessly

    • ๐Ÿณ Docker Support - Streamlined Docker integration for your applications

    • โšก Vite Support - Modern frontend tooling integration

    • ๐Ÿงช API Testing Tools - Built-in testing capabilities

    Install it via CommandBox:

    What's also powerful is that using our new application templates the CLI can now configure your application for:

    • Docker Creation and support

    • Vite support for modern frontend development

    • Maven support for Java dependencies

    • REST Only applications

    ๐Ÿค– AI First

    All application templates now come with AI assistance via our VSCode BoxLang extension and copilot instructions. You can get code suggestions, event handler code generation, and more. Just install the BoxLang VSCode Extension and start coding: https://marketplace.visualstudio.com/items?itemName=ortus-solutions.vscode-boxlang-developer-pack

    All of our modules, and ColdBox core have been updated with copilot instructions to help you get the most out of your AI assistants.

    ๐ŸฅŠ New Application Layout Templates

    We have been working on these new layouts and experimenting with them for over 2 years now. We are excited to announce that they are now production ready and available for you to use. These new layouts embrace modern development practices, non-root based architectures, and of course BoxLang.

    They are more intuitive, easier to understand, and provide a better developer experience than the traditional flat put everything in the webroot approach. They also embrace modern frontend tooling like Vite, TailwindCSS, and more. Icing on the cake is that now if you are using BoxLang, we include a Build.bx that will allow you to build, validate, pre-compile and package your application for deployment.

    We will also be introducing soon the new coldbox deploy command that will allow you to deploy your application to any Ortus Deployable Server or any CommandBox server. Stay tuned!

    Here are our new default templates:

    • ๐Ÿ”ฅ BoxLang Template - Native BoxLang ColdBox applications https://github.com/coldbox-templates/boxlang

    • ๐ŸŽจ Modern Template - Non-root based architecture (now operational!) https://github.com/coldbox-templates/modern

    ๐Ÿ”ฅ BoxLang Template - The Future is Here

    Pure BoxLang Power - Experience the first native BoxLang ColdBox template designed from the ground up for modern JVM applications!

    What You Get:

    • ๐Ÿš€ Native BoxLang compilation with Build.bx for lightning-fast deployments

    • ๐ŸŽฏ Zero-config Docker support with optimized runtime containers

    • โšก Vite integration for modern frontend development with hot-reload

    Perfect for: Greenfield projects, microservices, desktop applications, and teams ready to embrace the future of JVM development.

    ๐Ÿ”ฅ Key Architecture Benefits:

    • Security First: Application code is completely isolated from web access

    • Modern Tooling: Vite for frontend, Maven for dependencies, Docker for deployment

    • BoxLang Native: Pure .bx and .bxm files with native compilation support

    ๐ŸŽจ Modern Template - Enterprise-Grade Architecture

    Production-Ready Excellence - Built for teams who demand enterprise-level structure without sacrificing developer productivity. This template brings years of production experience into a clean, maintainable architecture.

    What You Get:

    • ๐Ÿ—๏ธ Non-root security architecture keeping your application safe from web-based attacks

    • ๐Ÿณ Complete Docker ecosystem with multi-stage builds and production optimization

    • ๐Ÿ”„ Database migration support with CF Migrations for seamless deployments

    • ๐Ÿ“Š Comprehensive monitoring with structured logging and application metrics

    Perfect for: Enterprise applications, legacy modernization, teams requiring strict security compliance, and applications with complex deployment requirements.

    ๐ŸŽฏ Enterprise Architecture Benefits:

    • Separation of Concerns: Clean MVC with modular HMVC capabilities

    • Database Migrations: Version-controlled schema changes with CF Migrations

    • Docker Ready: Production-optimized containers with development compose

    • Enterprise Tooling: CF Config, linting, formatting, and CI/CD integration

    AI Powered Whoops!

    We have completely revamped the ColdBox Whoops experience to include AI capabilities, enhanced stack traces, improved UI and so much more. This means that when an error happens, you will get not only the stack trace, but also AI generated suggestions on how to fix it, links to documentation, and more.

    โšก Major New Features & Enhancements

    ๐Ÿ”ฅ Virtual Thread Executors Support

    ColdBox 8.0.0 introduces native support for Virtual Thread Executors, bringing modern asynchronous programming capabilities to your CFML applications. Build high-performance, non-blocking applications with ease.

    ๐Ÿค– AI-Enhanced Whoops Experience

    Experience the future of debugging with our AI-powered error handling. Get intelligent suggestions, context-aware debugging tips, and smarter error diagnosis to solve issues faster than ever.

    ๐Ÿ—๏ธ WireBox Enhancements

    • ๐ŸŽฏ Delegates - Reusable component behaviors for cleaner code

    • โฑ๏ธ Lazy Properties - On-demand property initialization for better performance

    • ๐Ÿ‘€ Property Observers - React to property changes automatically

    • ๐Ÿ’พ Transient Request Cache - Optimized request-scoped caching

    ๐Ÿ“‹ Improved Logging Experience

    • ๐ŸŽจ Pretty JSON Output - Beautiful, readable JSON in your logs

    • ๐Ÿ”’ Closure-based Logging - Performance-optimized logging with lambda functions

    • ๐Ÿ”ง Better Exception Handling - Enhanced error serialization and reporting

    ๐Ÿ—„๏ธ CacheBox & BoxLang Prime

    Native BoxLang Prime integration across the entire platform, bringing:

    • โšก Enhanced Performance - Native compilation benefits

    • ๐Ÿ”ง Better Integration - Seamless BoxLang ecosystem support

    • ๐Ÿ“ฆ Optimized Distribution - Engine-level installation options

    ๐ŸŽฏ Developer Experience Improvements

    • ๐Ÿ“… Enhanced Scheduled Tasks - Better task management and scheduling

    • ๐Ÿ›ฃ๏ธ Improved Routing - Enhanced path handling and URL generation

    • ๐Ÿงช Testing Enhancements - Better testing tools and utilities

    • ๐ŸŽจ View Improvements - Enhanced rendering capabilities

    ๐Ÿงน Legacy Cleanup

    ColdBox 8.0.0 removes deprecated features to keep the codebase modern and maintainable:

    • Removed Client Flash - Legacy insecure storage method

    • Updated BeanPopulator - Replaced with ObjectPopulator

    • Router Modernization - Removed deprecated routing methods

    • Environment Variable Handling - Enhanced Env delegate support


    ๐ŸŽถ Release Notes

    ColdBox Core

    New Feature

    Virtual Thread executors support

    Make the build Executor public, for devs that just want executors built and NOT registered

    Executors more stats for issue detection

    New Whoops Experience with AI Capabilities

    Improvement

    Add ability to ignore or include RC keys when caching events

    Incorporate appName into lock names to give better uniqueness

    Bootstrap was not returning false or true on the right location for onRequestStart

    Bugs

    Improve error message for Module Settings in ColdBox DSL

    Module Config override convention depends on file system case sensitivity

    missing replacement of double // on layouts/views on new rendering schemas

    RequestContext StatusCode Should Default to 200

    ColdboxProxy throws "invalid call of the function ReplaceNoCase"

    NotAuthorized catch in RestHandler should return onAuthorizationFailure - not onAuthenticationFailure

    DateTimeHelper timeUnitToSeconds needs to ignore converting seconds if chosen

    Regression view layout relative app mapping paths

    Routing service was not evaluating the coldbox web mapping when public facing app is in another folder than the coldbox app

    Tasks

    Client Flash removal as legacy

    BeanPopulator finally removed

    Util: getSystemSetting, getSystemProperty, getEnv() removed in favor to the Env Delegate

    RequestContext removed methods: isSES(), setSESEnabled()

    Remove ColdBox 4 compat : getModulesRoutingTable(), includeRoutes() in the Router.cfc

    Removeal of Router.with() and endWith() in favor of the group() closures.

    Router addRoute() matchVariables argument finally removed

    ProcessState in the InterceptorService is now finally removed

    CacheBox

    New Features

    BoxLang Prime

    Bugs

    CacheBox CFProvider Only Works with EhCache

    LogBox

    New Features

    BoxLang Prime

    Improvements

    Add new LogBox configuration option to disallow serializing complex objects: serializeExtraInfo

    WireBox

    New Features

    BoxLang prime

    Tasks

    getCacheBoxConfig() on WireBox Binder removed after deprecation

    Binder.getProperty() `default` Argument Removed

    ๐ŸŽจ Enhanced Developer Tools - Updated CLI, VSCode extension, and templates
  • ๐Ÿ”ง CacheBox Updates - Better performance and BoxLang integration

  • ๐ŸŒ Modern Templates - New BoxLang and Modern application templates

  • ๐Ÿงน Legacy Cleanup - Removal of deprecated features for a cleaner codebase

  • https://wirebox.ortusbooks.com/~gitbook/mcp

    ๐Ÿ“‹ Project Scaffolding - Quick application setup

  • ๐Ÿ”ง Enhanced Generators - More code generation options

  • ๐Ÿค– AI Integration - Leverage AI for smarter code suggestions

  • ๐Ÿ“š Documentation - It has also been completely documented here: ColdBox CLI Docs.

  • Much More
    ๐Ÿงช Built-in testing suite with TestBox integration and CI/CD workflows
  • ๐Ÿค– AI-first development with VSCode BoxLang extension and copilot instructions

  • ๐Ÿ“ฆ Maven support for Java dependencies and enterprise builds

  • ๐Ÿ›ก๏ธ Security by design with non-root architecture and DevContainer support

  • ๐ŸŽจ REST-ready with dedicated API structure and OpenAPI documentation

  • Zero Configuration: Everything works out of the box with sensible defaults

  • ๐Ÿงฉ Modular design with clear separation of concerns across all layers

  • ๐Ÿ› ๏ธ Enterprise tooling with CF Config, formatting, and linting pre-configured

  • ๐Ÿš€ CI/CD ready with GitHub Actions for testing, building, and deployment

  • ๐Ÿ“ฑ Frontend flexibility supporting both traditional CFML views and modern JS frameworks

  • ColdBox
    CacheBox
    LogBox
    WireBox
    COLDBOX-1332
    COLDBOX-1333
    COLDBOX-1334
    COLDBOX-1341
    COLDBOX-1331
    COLDBOX-1343
    COLDBOX-1360
    COLDBOX-1328
    COLDBOX-1329
    COLDBOX-1330
    COLDBOX-1338
    COLDBOX-1340
    COLDBOX-1345
    COLDBOX-1350
    COLDBOX-1359
    COLDBOX-1361
    COLDBOX-1346
    COLDBOX-1352
    COLDBOX-1353
    COLDBOX-1354
    COLDBOX-1355
    COLDBOX-1356
    COLDBOX-1357
    COLDBOX-1358
    CACHEBOX-91
    CACHEBOX-90
    LOGBOX-84
    LOGBOX-83
    WIREBOX-156
    WIREBOX-157
    WIREBOX-158
    # CommandBox
    box install bx-coldbox
    
    # BoxLang Module
    install-bx-module bx-coldbox
     โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•—     โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•— โ–ˆโ–ˆโ•—  โ–ˆโ–ˆโ•—      โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•—     โ–ˆโ–ˆโ•—
    โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘     โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•โ•โ•โ–ˆโ–ˆโ•—โ•šโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•”โ•     โ–ˆโ–ˆโ•”โ•โ•โ•โ•โ•โ–ˆโ–ˆโ•‘     โ–ˆโ–ˆโ•‘
    โ–ˆโ–ˆโ•‘     โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘     โ–ˆโ–ˆโ•‘  โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘ โ•šโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘     โ–ˆโ–ˆโ•‘     โ–ˆโ–ˆโ•‘
    โ–ˆโ–ˆโ•‘     โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•‘     โ–ˆโ–ˆโ•‘  โ–ˆโ–ˆโ•‘โ–ˆโ–ˆโ•”โ•โ•โ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘   โ–ˆโ–ˆโ•‘ โ–ˆโ–ˆโ•”โ–ˆโ–ˆโ•—โ•šโ•โ•โ•โ•โ•โ–ˆโ–ˆโ•‘     โ–ˆโ–ˆโ•‘     โ–ˆโ–ˆโ•‘
    โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•”โ•โ–ˆโ–ˆโ•”โ• โ–ˆโ–ˆโ•—     โ•šโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ•—โ–ˆโ–ˆโ•‘
     โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•โ•โ•โ•โ•  โ•šโ•โ•โ•โ•โ•โ• โ•šโ•โ•  โ•šโ•โ•      โ•šโ•โ•โ•โ•โ•โ•โ•šโ•โ•โ•โ•โ•โ•โ•โ•šโ•โ•
    install coldbox-cli
    coldbox --help
    # Use the new boxlang template
    coldbox create app MyBoxLangApp
    
    # Use the new modern template
    coldbox create app MyBoxLangApp skeleton=modern
    coldbox create app MyBoxLangApp --cfml
    MyBoxLangApp/
    โ”œโ”€โ”€ ๐Ÿ“ app/                    # ๐Ÿ”’ Secure ColdBox App
    โ”‚   โ”œโ”€โ”€ config/               # Configuration
    โ”‚   โ”œโ”€โ”€ handlers/             # Event handlers (controllers)
    โ”‚   โ”œโ”€โ”€ interceptors/         # Interceptors
    โ”‚   โ”œโ”€โ”€ layouts/              # Layout templates
    โ”‚   โ”œโ”€โ”€ models/               # Business logic layer
    โ”‚   โ”œโ”€โ”€ modules/               # Custom Modules
    โ”‚   โ”œโ”€โ”€ views/                # Presentation templates
    โ”‚   โ””โ”€โ”€ layouts/              # Page layout templates
    โ”œโ”€โ”€ ๐Ÿ“ modules/                # ๐Ÿ—ณ๏ธ CommandBox Tracked Modules
    โ”œโ”€โ”€ ๐Ÿ“ public/                # ๐ŸŒ Web-accessible directory
    โ”‚   โ”œโ”€โ”€ index.bxm             # Application entry point
    โ”‚   โ”œโ”€โ”€ includes/             # CSS, JS, images
    โ”‚   โ””โ”€โ”€ Application.bx        # Public bootstrap
    โ”œโ”€โ”€ ๐Ÿ“ resources/             # ๐Ÿ› ๏ธ Development assets
    โ”‚   โ””โ”€โ”€ database/migrations/  # Database version control
    โ”œโ”€โ”€ ๐Ÿ“ runtime/               # ๐Ÿƒ Runtime libraries & logs
    โ”œโ”€โ”€ ๐Ÿ“ tests/                 # ๐Ÿงช Testing suite
    โ””โ”€โ”€ Build.bx                  # ๐Ÿš€ BoxLang build automation
    โ””โ”€โ”€ box.json                  # CommandBox project descriptor
    โ””โ”€โ”€ server.json                  # CommandBox server descriptor
    โ””โ”€โ”€ pom.xml                   # Maven project descriptor
    MyModernApp/
    โ”œโ”€โ”€ ๐Ÿ“ app/                    # ๐Ÿ”’ Secure ColdBox Application (above webroot)
    โ”‚   โ”œโ”€โ”€ config/               # Configuration
    โ”‚   โ”œโ”€โ”€ handlers/             # Event handlers (controllers)
    โ”‚   โ”œโ”€โ”€ interceptors/         # Interceptors
    โ”‚   โ”œโ”€โ”€ layouts/              # Layout templates
    โ”‚   โ”œโ”€โ”€ models/               # Business logic layer
    โ”‚   โ”œโ”€โ”€ modules/               # Custom Modules
    โ”‚   โ”œโ”€โ”€ views/                # Presentation templates
    โ”‚   โ””โ”€โ”€ layouts/              # Page layout templates
    โ”œโ”€โ”€ ๐Ÿ“ public/                # ๐ŸŒ Web-accessible directory
    โ”‚   โ”œโ”€โ”€ index.cfm             # Application entry point
    โ”‚   โ””โ”€โ”€ includes/             # Static assets (CSS, JS, images)
    โ”œโ”€โ”€ ๐Ÿ“ docker/                # ๐Ÿณ Container orchestration
    โ”‚   โ”œโ”€โ”€ Dockerfile            # Multi-stage production builds
    โ”‚   โ””โ”€โ”€ docker-compose.yml    # Development environment
    โ”œโ”€โ”€ ๐Ÿ“ resources/             # ๐Ÿ—ƒ๏ธ Application resources
    โ”‚   โ””โ”€โ”€ database/migrations/  # Database version control
    โ”œโ”€โ”€ ๐Ÿ“ lib/                   # ๐Ÿ“š Framework libraries
    โ”‚   โ”œโ”€โ”€ coldbox/              # ColdBox framework files
    โ”‚   โ””โ”€โ”€ testbox/              # Testing framework
    โ””โ”€โ”€ ๐Ÿ“ tests/                 # ๐Ÿงช Comprehensive test suite
    โ””โ”€โ”€ box.json                  # CommandBox project descriptor
    โ””โ”€โ”€ server.json                  # CommandBox server descriptor
    โ””โ”€โ”€ pom.xml                   # Maven project descriptor

    Routing Methods

    Apart from routing by convention, you can also register your own expressive routes. Let's investigate the routing approaches.

    Inline Terminator

    The route() method allows you to register a pattern and immediately assign it to execute an event or a response via the target argument.

    The first pattern registers and if matched it will execute the wiki.page event. The second pattern if matched it will execute the profile.show event from the users

    module and register the route with the
    userprofile
    name.

    Inline Responses

    You can also pass in a closure or lambda to the target argument and it will be treated as an inline action:

    You can also pass just an HTML string with {rc_var} replacements for the routed variables place in the request collection

    Routing to Events

    If you will not use the inline terminators you can do a full expressive route definition to events using the to() method, which allows you to concatenate the route pattern with modifiers:

    Routing To Handler Action Combinations

    You can also route to a handler and an action using the modifiers instead of the to() method. This long-form is usually done for visibility or dynamic writing of routes. You can use the following methods:

    • withHandler()

    • withAction()

    • toHandler()

    • end()

    Routing to Views

    You can also route to views and view/layout combinations by using the toView() terminator:

    Routing to Redirects

    You can also use the toRedirect() method to re-route patterns to other patterns.

    The default status code for redirects are 301 redirects which are PERMANENT redirects.

    Dynamic Routing Redirection

    You can also pass a closure as the target of relocation. This closure will received the parsed parameters, the incoming route record and the event object. You can determine dynamically where the relocation will go.

    This is great if you need to actually parse the incoming route and do a dynamic relocation.

    Happy Redirecting!

    Routing to Handlers

    You can also redirect a pattern to a handler using the toHandler() method. This is usually done if you have the action coming in via the URL or you are using RESTFul actions.

    Routing to RESTFul Actions

    You can also route a pattern to HTTP RESTFul actions. This means that you can split the routing pattern according to incoming HTTP Verb. You will use a modifier withAction() and then assign it to a handler via the toHandler() method.

    Routing to Responses

    The Router allows you to create inline responses via closures/lambdas or enhanced strings to incoming URL patterns. You do not need to create handler/actions, you can put the actions inline as responses.

    If you use a response closure/lambda, they each accepts three arguments:

    1. event - An object that models and is used to work with the current request (Request Context)

    2. rc - A struct that contains both URL/FORM variables merged together (unsafe data)

    3. prc - A secondary struct that is private only settable from within your application (safe data)

    If the response is an HTML string, then you can do {rc_var} replacements on the strings as well:

    Sub-Domain Routing

    You can also register routes that will respond to sub-domains and even capture portions of the sub-domain for multi-tenant applications or SaaS applications. You will do this using the withDomain() method.

    You can leverage the full routing DSL as long as you add the withDomain() call with the domain you want to bind the route to. Also note that the domain string can contain placeholders which will be translated to RC variables for you if matched.

    Tip: Please note that you can leverage Routing Groups as well for domains

    Adding Variables to RC/PRC

    You can also add variables to the RC and PRC structs on a per-route basis by leveraging the following methods:

    • rc( name, value, overwrite=true ) - Add an RC value if the route matched

    • rcAppend map, overwrite=true ) - Add multiple values to the RC collection if the route matched

    • prc( name, value, overwrite=true ) - Add an PRC value if the route matched

    • prcAppend map, overwrite=true ) - Add multiple values to the PRC collection if the route matched

    This is a great way to manually set variables in the incoming structures:

    Routing Conditions

    You can also apply runtime conditions to a route in order for it to be matched. This means that if the route matches the URL pattern then we will execute a closure/lambda to make sure that it meets the runtime conditions. We will do this with the withCondition() method.

    Let's say you only want to fire some routes if they are using Firefox, or a user is logged in, or whatever.

    route( "/wiki:pagename", "wiki.page" );
    route( 
        pattern="/users/:id/profile", 
        target="users:profile.show", 
        name="userprofile" 
    );
    route(
        pattern="/echo",
        target=function( event, rc, prc ){
            return "hello ColdBox!";
        }
    );
    
    route(
        pattern="/users",
        target=function( event, rc, prc ){
            return getInstance( "UserService" ).list();
        }
    );
    route(
        "/echo/:name",
        "<h1>Hello {name} how are you today!</h1>"
    );
    route( "/wiki/:pagename" )
        .to( "wiki.show" );
    
    route( "/users/:id/profile" )
        .as( "userProfile" )
        .to( "users:profile.show" );
    
    route( "/users/:id/profile" )
        .as( "userProfile" )
        .withVerbs( "GET" )
        .withSSL()
        .header( "cache", false )
        .prc( "isActive", true )
        .to( "users:profile.show" );
    route( "wiki/:pagename" )
        .as( "wikipage" )
        .withAction( "show" )
        .toHandler( "wiki" );
    
    route( "wiki/:pagename" )
        .withHander( "wiki" )
        .withAction( "show" )
        .end();
    route( "/contact-us" )
        .toView( 
            view = "view name",
            layout = "layout",
            nolayout = false,
            viewModule = "moduleName",
            layoutModule = "moduleName"
        );
    route( "/my-old/link" )
        .toRedirect( target="/new/pattern", statusCode=301 );
    route( "/my-old/link" )
        .toRedirect( ( route, params, event ) => "/new/route" )
      
    route( "/my-old/link" )
        .toRedirect( โ€‹function( route, params, event ){ 
            return "/new/route"; 
    } ) 
    route( "/old/api/users/:id" )    
        .toRedirect( ( route, params, event ) => { 
            return "/api/v1/users/#params.id#" } 
        )
    // Action comes via the URL
    route( "/users/:action" )
        .toHandler( "users" );
    // RESTFul actions
    route( "/users/:id?" )
        .withAction( {
            GET : "index",
            POST : "save",
            PUT : "update",
            DELETE : "remove"
        } )
        .toHandler( "users" );
    /**
     * Setup a response for a URL pattern
     * @body A closure/lambda or enhanced HTML string
     * @statusCode The status code to send
     * @statusText The status code to send
     */
    function toResponse( 
        required body, 
        numeric statusCode = 200, 
        statusText = "Ok" 
    )
    // Simple response routing
    route( "/users/hello", function( event, rc, prc ){
        return "<h1>Hello From RESTLand</h1>";
    } );
    
    // Simple response routing with placeholders
    route( "/users/:username", function( event, rc, prc ){
        return "<h1>Hello #encodeForHTML( rc.username )# From RESTLand</h1>";
    } );
    
    // Routing with the toResponse() method
    route( "/users/:id" )
        .toResponse( function( event, rc, prc ){
            var oUser = getInstance( "UserService" ).get( rc.id ?: 0 );
            if( oUser.isLoaded() ){
                return oUser.getMemento();
            }
            event.setHTTPHeader( statusCode = 400, statusText = "Invalid User ID provided" );
            return {
                "error" : true,
                "messages" : "Invalid User ID Provided"
            };
        } );
    // Routing with enhanced HTML strings
    route( "/users/:id" )
        .toResponse(
            "<h1>Welcome back user: {id} how are you today!</h1>"
        );
    route( "/" )
      .withDomain( "subdomain-routing.dev" )
      .to( "subdomain.index" );
    
    route( "/" )
      .withDomain( ":username.forgebox.dev" )
      .to( "subdomain.show" );
    route( "/api/v1/users/:id" )
        .rcAppend( { secured : true } )
        .prcAppend( { name : "hello" } )
        .to( "api-v1:users.show" );
    route( "/go/firefox" )
      withCondition( function( requestString ){
        return ( findnocase( "Firefox", cgi.HTTP_USER_AGENT ) ? true : false );
      });
      .to( "firefox.index" );

    ColdBox CLI

    The ColdBox CLI is a powerful command-line interface tool that helps you create, manage, and scaffold ColdBox applications and components with ease.

    Welcome to the ColdBox CLI - your ultimate command-line companion for rapid ColdBox development! ๐Ÿš€ This powerful tool streamlines the creation, management, and scaffolding of ColdBox applications and components for both CFML and BoxLang projects.

    ๐ŸŽฏ BoxLang First: BoxLang is now the default language for all new applications, reflecting the modern direction of ColdBox development.

    ๐Ÿ“ฆ CLI Versions & Compatibility

    The CLI follows semantic versioning aligned with ColdBox major releases:

    ColdBox Version
    CLI Version
    Status
    Installation Command

    ๐Ÿ’ก Pro Tip: Always use the CLI version that matches your ColdBox framework version for the best compatibility and latest features.

    โšก Quick Installation

    Get started in seconds with CommandBox:

    ๐Ÿ”— Source Code: Explore the CLI on GitHub at - contributions welcome!

    ๐ŸŽฏ Getting Started

    The ColdBox CLI supercharges your development workflow with intelligent scaffolding and modern development tools. Whether you're building BoxLang or CFML applications, the CLI has you covered!

    ๐Ÿ“š Help is Always Available: Every command supports the --help flag for detailed usage information.

    ๐ŸฅŠ Application Creation

    Create stunning ColdBox applications from professionally crafted templates. BoxLang leads the way as the default language for modern development:

    ๐Ÿ—๏ธ Application Templates & Features

    Choose from various templates and enhance with powerful features:

    ๐Ÿง™โ€โ™‚๏ธ Interactive App Wizard - Perfect for Beginners!

    New to ColdBox? The App Wizard is your friendly guide to creating the perfect application setup:

    The wizard walks you through every decision with helpful prompts:

    Step
    What It Asks
    Why It Matters

    Example Wizard Session:

    ๐Ÿ’ก Pro Tip: The wizard is perfect for exploring all available options and learning about ColdBox features as you create your app!

    ๐Ÿ“‹ Application Templates - Choose Your Foundation

    Select from professionally crafted templates or bring your own via ForgeBox ID, GitHub repo, local path, ZIP file, or URL. Our modern templates prioritize BoxLang for cutting-edge development:

    ๐ŸฅŠ BoxLang Templates (Recommended for Modern Development)

    These can be used for BoxLang PRIME projects or CFML projects with the bx-cfml-compat module for compatibility.

    Template
    Description
    Best For

    ๐Ÿ“œ FLAT CFML Templates (Traditional Development)

    Can also be used for BoxLang projects but using the bx-cfml-compat modules to ensure compatibility.

    Template
    Description
    Best For

    ๐Ÿš€ Enhanced Template Features

    Modern templates (boxlang, modern) unlock powerful development features through simple flags:

    Feature Flag
    What It Does
    Perfect For

    Power Combinations:

    โšก Vite Integration - Modern Frontend Made Easy

    Transform your frontend development with Vite's lightning-fast build system and hot module replacement:

    ๐ŸŽ What You Get Out of the Box:

    Feature
    Benefit
    Developer Experience

    ๐Ÿš€ Development Workflow:

    ๐Ÿ’ก Pro Tip: Vite's dev server automatically proxies to your ColdBox application, giving you the best of both worlds!

    ๐Ÿณ Docker Integration - Deploy Anywhere, Run Everywhere

    Containerize your ColdBox applications for consistent development and bulletproof deployments:

    ๐ŸŽ Complete Container Solution:

    Component
    What's Included
    Benefit

    ๐Ÿš€ Container Commands:

    ๐ŸŽฏ Production Ready: The Docker setup includes production optimizations like multi-stage builds, security best practices, and health monitoring!

    ๐ŸŽฏ Handlers (Controllers) - Your Application Logic

    Generate powerful MVC controllers with intelligent scaffolding for actions, views, and tests:

    ๐ŸŽ Handler Generation Options:

    Flag
    What It Creates
    Perfect For

    ๐Ÿ’ก Smart Generation: The CLI creates handlers in the correct directory structure and generates appropriate code for your project language (BoxLang/CFML)!

    ๐Ÿ“Š Models & Services - Your Business Logic Powerhouse

    Create robust domain models and business services that form the backbone of your application:

    ๐ŸŽ Model Generation Features:

    Option
    What You Get
    Use Case

    ๐Ÿ’ก Smart Property Generation:

    ๐Ÿš€ Pro Tip: Use --all when you need a complete feature with model, service, handler, database migration, and test seeders!

    ๐ŸŽจ Views & Layouts - Beautiful User Interfaces

    Craft stunning user interfaces with intelligent view and layout generation:

    ๐ŸŽ View Generation Options:

    Component
    Purpose
    Best Practice

    ๐Ÿ’ก Smart Content Generation:

    • Views are placed in the correct directory structure

    • Layouts include proper view rendering calls

    • Helper files provide utility functions for complex views

    • All generated code follows your project's language (BoxLang/CFML)

    ๐ŸŽจ Design Tip: Use layouts for common page structure (header, navigation, footer) and views for specific page content!

    ๐Ÿ”ง Resources & CRUD - Complete Feature Development

    Generate complete, production-ready resourceful components with full CRUD operations:

    ๐ŸŽ What Gets Generated:

    Component
    Purpose
    Files Created

    ๐Ÿš€ Generated CRUD Actions:

    โšก Instant Productivity: Resources give you a complete feature with working CRUD operations in seconds!

    ๐Ÿ“ฆ Modules - Reusable Application Components

    Create powerful, self-contained modules that can be shared across applications or published to ForgeBox:

    ๐ŸŽ Module Architecture:

    Modules are mini-applications within your ColdBox app, complete with their own:

    • ๐Ÿ“ Directory Structure - Organized, self-contained file layout

    • โš™๏ธ ModuleConfig - Independent configuration and settings

    • ๐Ÿ›ฃ๏ธ Routing - Module-specific URL patterns

    • ๐Ÿ“ฆ Dependencies - Isolated dependency management

    ๐Ÿš€ Modular Power: Modules enable microservice architecture, code reuse, and team collaboration on large applications!

    ๐Ÿงช Testing - Quality Assurance Made Easy

    Generate comprehensive test suites to ensure your application works flawlessly:

    ๐ŸŽ Testing Types & Their Purpose:

    Test Type
    What It Tests
    Best For

    ๐Ÿ’ก Testing Best Practices:

    • Fast Feedback - Unit tests run quickly for immediate validation

    • Behavior Focus - BDD tests document how features should work

    • Real Scenarios - Integration tests verify complete user workflows

    • Data Integrity - Model tests ensure business rules are enforced

    ๐Ÿš€ Quality First: Well-tested applications deploy with confidence and maintain themselves over time!

    ๐Ÿ—„๏ธ ORM & Database

    Work with ORM entities and database operations:

    ๐Ÿ”— Interceptors

    Create AOP interceptors:

    ๐Ÿ”„ Development Workflow

    Manage your development environment:

    ๐ŸŽ›๏ธ Global Options - Command Superpowers

    Enhance any CLI command with these powerful options for a customized experience:

    ๐ŸŒŸ Universal Command Options

    Option
    What It Does
    Example Usage

    ๐Ÿ—๏ธ Application Creation Flags

    Feature Flag
    Adds To Your App
    Perfect For

    ๐Ÿ”ฅ Language Control

    The CLI automatically detects your project language but you can override when needed:

    Setting
    Behavior
    When To Use

    ๐ŸŽช Power Combinations:

    ๐Ÿ’ก BoxLang Support

    The CLI automatically detects BoxLang projects and generates appropriate code. You can also force BoxLang mode using the --boxlang flag.

    ๐Ÿ” Automatic Detection

    The CLI detects BoxLang projects using three methods (in order of precedence):

    1. Server Engine Detection: Running on a BoxLang server

    2. TestBox Runner Setting: When testbox.runner is set to "boxlang" in box.json

    3. Language Property: When language is set to "boxlang"

    โš™๏ธ Configuration Examples

    Method 1: Language Property (Recommended)

    Method 2: TestBox Runner Setting

    ๐Ÿš€ Usage Examples

    ๐Ÿ“ Generated Code Differences

    When BoxLang mode is detected or forced:

    • Uses .bx file extensions instead of .cfc

    • Generates class syntax instead of component

    • Uses BoxLang-specific template variants

    ๐Ÿค– AI Coding Assistance

    The CLI now includes Copilot instructions to enhance AI-powered development workflows. These instructions help AI assistants understand ColdBox project structure and generate appropriate code:

    Features

    • Intelligent Code Generation: AI assistants can better understand ColdBox conventions and patterns

    • Template-Aware Suggestions: Context-aware code suggestions based on your project type

    • BoxLang & CFML Support: Appropriate suggestions for both language targets

    • Framework Integration: Deep understanding of ColdBox architecture and best practices

    Copilot Instructions

    The CLI includes specialized instruction sets:

    • Modern Apps: Instructions optimized for contemporary ColdBox applications

    • Legacy Projects: Support for traditional flat-structure applications

    • BoxLang Focus: Enhanced support for BoxLang-specific patterns

    • Framework Patterns: MVC, HMVC, and REST API architectural guidance

    These instructions are automatically included in modern application templates to provide the best AI coding experience out of the box.

    ๐Ÿ“– Getting Help - Never Get Stuck

    The ColdBox CLI has your back with comprehensive help at every level:

    ๐ŸŽฏ Quick Help Commands

    ๐Ÿ†˜ When You Need Help

    Situation
    Command
    What You Get

    ๐Ÿ’ก Pro Help Tips

    • Every command has --help - never hesitate to use it!

    • Help shows examples, options, and flags for each command

    • When reporting issues, always include your CLI version

    • The GitHub repository has extensive documentation and examples

    ๐ŸŽ“ Learning Path: Start with coldbox create app-wizard to explore all options interactively, then use specific commands as you become more comfortable!

    ๐Ÿณ Environment

    Docker containerization?

    Deployment strategy

    ๐Ÿ—ƒ๏ธ Database

    Need migration support?

    Data management

    vite

    CFML app with Vite integration (legacy)

    Legacy frontend modernization

    ๐Ÿ”— Dev Server + Proxy

    Seamless ColdBox integration

    Unified development experience

    ๐ŸŒ Environment Config

    Secure variable management

    Production-ready security

    ๐Ÿ’š Health Checks

    Built-in monitoring

    Reliable deployments

    ๐Ÿงช Tests

    Unit & integration tests (optional)

    tests/specs/

    ๐Ÿ—ƒ๏ธ Migration

    Database table creation (optional)

    resources/database/migrations/

    ๐Ÿ”ง Models & Handlers - Complete MVC architecture (optional)

  • ๐ŸŽจ Views & Layouts - Independent UI components (optional)

  • ๐ŸŽช Interceptor

    AOP & cross-cutting concerns

    Security, logging, caching

    in
    box.json

    Creates BoxLang test files (.bxm extensions)

    ColdBox 8

    @8

    โœ… Current

    box install coldbox-cli@8

    ColdBox 7

    @7.8.0

    ๐ŸŸก Supported

    box install [email protected]

    ColdBox 6

    @6

    ๐Ÿ”ถ Legacy

    ๐Ÿ“ Location

    Create in current folder or new directory?

    Project organization

    ๐Ÿ”ฅ Language

    BoxLang (default) or CFML?

    Development preference

    ๐ŸŽฏ Type

    API/REST service or full web app?

    Architecture choice

    ๐ŸŽจ Frontend

    Include Vite for modern UI?

    boxlang โญ

    Default - Modern ColdBox with latest BoxLang features

    New projects, modern architecture

    modern

    Contemporary app supporting BoxLang + CFML

    Hybrid projects, gradual migration

    flat

    Classic flat-structure ColdBox app

    Traditional CFML projects

    rest

    BoxLang-optimized REST API template

    Microservices, API development

    rest-hmvc

    RESTful app with HMVC architecture

    Complex API systems

    supersimple

    Bare-bones minimal setup

    --vite ๐ŸŽจ

    Modern frontend with hot reload & optimized builds

    Interactive UIs, SPAs

    --rest ๐ŸŒ

    REST API configuration with OpenAPI docs

    Microservices, APIs

    --docker ๐Ÿณ

    Complete containerization setup

    Cloud deployment, consistency

    --migrations ๐Ÿ—ƒ๏ธ

    Database migration system

    ๐Ÿ”ง Pre-configured Setup

    vite.config.mjs ready to go

    Zero configuration needed

    ๐Ÿ”ฅ Hot Module Replacement

    Instant updates without refresh

    Ultra-fast development

    ๐Ÿ“ฆ Optimized Builds

    Code splitting & tree shaking

    Production-ready performance

    ๐ŸŽจ Asset Processing

    CSS, SCSS, JS, TS support

    ๐Ÿ“ฆ Multi-stage Dockerfile

    Optimized for ColdBox apps

    Minimal production images

    ๐Ÿ”ง docker-compose.yml

    Complete dev environment

    One-command setup

    ๐Ÿ—ƒ๏ธ Database Services

    PostgreSQL/MySQL ready

    Consistent data layer

    โšก Redis Caching

    High-performance caching

    --rest

    RESTful endpoints (GET, POST, PUT, DELETE)

    API development

    --resource

    Full CRUD operations

    Data management

    --views

    Corresponding view templates

    Full-stack apps

    --integrationTests

    Test files for actions

    --accessors

    Getter/setter methods

    Clean property access

    --migration

    Database table creation

    Data persistence

    --service

    Business logic layer

    Complex operations

    --all

    Complete MVC stack

    Full feature development

    Views

    Page content & UI components

    Keep focused & reusable

    Layouts

    Page structure & common elements

    Master templates

    Helpers

    View-specific utility functions

    Clean separation of concerns

    ๐ŸŽฏ Handler

    CRUD actions (index, show, create, edit, delete)

    handlers/Photos.cfc

    ๐Ÿ“Š Model

    Data model with validation

    models/Photo.cfc

    ๐ŸŽจ Views

    Complete UI for all actions

    views/photos/*.cfm

    ๐Ÿ›ฃ๏ธ Routes

    RESTful URL patterns

    ๐ŸŽฏ Unit

    Individual methods & functions

    Business logic, utilities

    ๐Ÿ“‹ BDD

    Behavior & requirements

    User stories, acceptance criteria

    ๐ŸŒ Integration

    Component interactions

    Workflows, API endpoints

    ๐Ÿ“Š Model

    Data models & validation

    --force โšก

    Overwrite existing files without prompting

    coldbox create handler Users --force

    --open ๐Ÿ“‚

    Auto-open generated files in your editor

    coldbox create model User --open

    --help โ“

    Show detailed command help

    coldbox create app --help

    --migrations ๐Ÿ—ƒ๏ธ

    Database migration system

    Data-driven applications

    --docker ๐Ÿณ

    Complete containerization

    Cloud deployments, consistency

    --vite โšก

    Modern frontend asset pipeline

    Interactive UIs, SPAs

    --rest ๐ŸŒ

    REST API configuration

    Default ๐ŸŽฏ

    BoxLang for new apps, auto-detect for existing

    Most scenarios

    --boxlang ๐ŸฅŠ

    Force BoxLang generation

    Override detection

    --cfml ๐Ÿ“œ

    Force CFML generation

    Legacy projects, specific requirements

    ๐Ÿค” What can I do?

    coldbox help

    Full command list

    ๐Ÿ“‹ How do I use this command?

    coldbox create app --help

    Detailed usage & examples

    ๐Ÿ› Something's not working

    coldbox --version

    Version info for troubleshooting

    ๐Ÿ“š I want to learn more

    Check the CLI Repository

    coldbox/coldbox-cli

    box install coldbox-cli@6

    Asset management

    Learning, prototyping

    Data-driven apps

    Modern toolchain

    Speed & scalability

    Quality assurance

    Added to config/Router.cfc

    Domain logic, persistence

    Microservices, API development

    Source code & documentation

    # Install the latest ColdBox CLI (v8)
    box install coldbox-cli
    
    # Get help anytime
    coldbox --help
    # ๐ŸŽฏ Quick Start - Create a BoxLang app (default behavior)
    coldbox create app myAwesomeApp
    
    # ๐Ÿ”ฅ Explicitly choose BoxLang (same as above)
    coldbox create app myAwesomeApp --boxlang
    
    # ๐Ÿ“œ Create a traditional CFML app
    coldbox create app myCFMLApp --cfml
    # ๐Ÿ“‹ Modern Templates (Recommended)
    coldbox create app myApp skeleton=boxlang   # Pure BoxLang template
    coldbox create app myApp skeleton=modern     # Contemporary architecture for CFML or BoxLang
    
    # ๐Ÿ”ง Flat Templates (CFML)
    coldbox create app myApp skeleton=rest      # REST API focused
    coldbox create app myApp skeleton=flat      # Traditional flat structure
    coldbox create app myApp skeleton=supersimple  # Minimal setup
    coldbox create app myApp skeleton=vite  # Vite
    
    # โšก Power Features
    coldbox create app myApp --migrations       # ๐Ÿ—ƒ๏ธ Database migrations
    coldbox create app myApp --docker          # ๐Ÿณ Container ready
    coldbox create app myApp --vite           # ๐ŸŽจ Modern frontend assets
    coldbox create app myApp --rest           # ๐ŸŒ REST API configuration
    
    # ๐ŸŽช Combine Multiple Features
    coldbox create app myFullStackApp --migrations --docker --vite --rest
    # Launch the interactive wizard
    coldbox create app-wizard
    ๐Ÿง™โ€โ™‚๏ธ Welcome to the ColdBox App Wizard!
    
    ๐Ÿ“ Are you currently inside the "myapp" folder? [y/n]: n
    ๐Ÿ”ฅ Is this a BoxLang project? [y/n]: y
    ๐ŸŽฏ Are you creating an API? [y/n]: n
    ๐ŸŽจ Would you like to configure Vite as your Front End UI pipeline? [y/n]: y
    ๐Ÿณ Would you like to setup a Docker environment? [y/n]: y
    ๐Ÿ—ƒ๏ธ Are you going to require Database Migrations? [y/n]: y
    
    โœจ Perfect! Creating your customized ColdBox application...
    # ๐ŸŽฏ Full-Stack Modern App
    coldbox create app myApp skeleton=modern --vite --migrations --docker
    
    # ๐ŸŒ Production-Ready API
    coldbox create app myAPI skeleton=rest --docker --migrations
    
    # ๐Ÿ”ฅ BoxLang Powerhouse
    coldbox create app myApp --vite --rest --docker --migrations
    # ๐Ÿ”ฅ Create app with Vite power
    coldbox create app myApp --vite
    
    # ๐ŸŽฏ Works with modern templates
    coldbox create app myApp skeleton=modern --vite
    # Start development with hot reloading
    npm run dev            # โšก Lightning fast updates
    
    # Build for production
    npm run build          # ๐Ÿ“ฆ Optimized & minified
    
    # Preview production build locally
    npm run preview        # ๐Ÿ” Test before deploy
    # ๐Ÿณ Add Docker superpowers
    coldbox create app myApp --docker
    
    # ๐Ÿš€ Ultimate combo - Docker + everything
    coldbox create app myApp --docker --vite --migrations --rest
    # Launch your entire development environment
    docker-compose up -d           # ๐Ÿš€ Start all services
    
    # Monitor your application
    docker-compose logs -f app     # ๐Ÿ‘€ Watch real-time logs
    
    # Clean shutdown
    docker-compose down           # ๐Ÿ›‘ Stop all services gracefully
    
    # Fresh rebuild
    docker-compose up --build     # ๐Ÿ”„ Rebuild & restart
    # ๐ŸŽฏ Basic handler for common tasks
    coldbox create handler UserController
    
    # ๐ŸŽช Handler with specific actions
    coldbox create handler Users index,show,edit,delete,create
    
    # ๐ŸŒ RESTful API handler
    coldbox create handler api/Users --rest
    
    # ๐Ÿ”„ Full CRUD resourceful handler
    coldbox create handler Photos --resource
    
    # ๐ŸŽจ Complete package with views and tests
    coldbox create handler Users --views --integrationTests
    # ๐ŸŽฏ Simple domain model
    coldbox create model User
    
    # ๐Ÿ—๏ธ Rich model with properties and accessors
    coldbox create model User properties=firstName,lastName,email --accessors
    
    # ๐Ÿ—ƒ๏ธ Model with database migration
    coldbox create model Product --migration
    
    # ๐Ÿ”ง Model with accompanying service
    coldbox create model User --service
    
    # ๐ŸŽช The works - model, service, handler, migration, seeder
    coldbox create model Customer --all
    
    # โš™๏ธ Standalone business service
    coldbox create service PaymentService
    # Creates firstName, lastName, email properties with getters/setters
    coldbox create model User properties=firstName,lastName,email --accessors
    # ๐ŸŽจ Create a view template
    coldbox create view users/index
    
    # ๐Ÿ”ง View with helper functions
    coldbox create view users/profile --helper
    
    # ๐Ÿ“ View with initial content
    coldbox create view welcome content="<h1>Welcome to Our App!</h1>"
    
    # ๐Ÿ–ผ๏ธ Create layout template
    coldbox create layout main
    
    # ๐ŸŽฏ Layout with view rendering
    coldbox create layout admin content="<cfoutput>#renderView()#</cfoutput>"
    # ๐ŸŽฏ Single resource (handler, model, views, routes)
    coldbox create resource Photos
    
    # ๐ŸŽช Multiple resources at once
    coldbox create resource Photos,Users,Categories
    
    # ๐ŸŽจ Custom handler name for better organization
    coldbox create resource photos PhotoGalleryController
    
    # ๐Ÿงช Production-ready with tests and migrations
    coldbox create resource Users --tests --migration
    # Your Photos resource creates these endpoints automatically:
    GET    /photos          # index()   - List all photos
    GET    /photos/new      # new()     - Show create form
    POST   /photos          # create()  - Save new photo
    GET    /photos/:id      # show()    - Display photo
    GET    /photos/:id/edit # edit()    - Show edit form
    PUT    /photos/:id      # update()  - Save changes
    DELETE /photos/:id      # delete()  - Remove photo
    # ๐ŸŽฏ Basic module structure
    coldbox create module UserManagement
    
    # ๐ŸŽช Full-featured module with all components
    coldbox create module BlogEngine --models --handlers --views
    # ๐ŸŽฏ Unit tests for business logic
    coldbox create unit models.UserServiceTest
    
    # ๐Ÿ“‹ BDD specs for behavior testing
    coldbox create bdd UserAuthenticationSpecs
    
    # ๐ŸŒ Integration tests for full workflows
    coldbox create integration-test handlers.UsersTest
    
    # ๐Ÿ“Š Model-specific testing
    coldbox create model-test User
    
    # ๐ŸŽช Interceptor testing with action coverage
    coldbox create interceptor-test Security --actions=preProcess,postProcess
    # ORM Entity
    coldbox create orm-entity User table=users
    
    # ORM Service
    coldbox create orm-service UserService entity=User
    
    # Virtual Entity Service
    coldbox create orm-virtual-service UserService
    
    # ORM Event Handler
    coldbox create orm-event-handler
    
    # CRUD operations
    coldbox create orm-crud User
    # Basic interceptor
    coldbox create interceptor Security
    
    # Interceptor with specific interception points
    coldbox create interceptor Logger points=preProcess,postProcess
    
    # With tests
    coldbox create interceptor Security --tests
    # Reinitialize ColdBox framework
    coldbox reinit
    
    # Auto-reinit on file changes
    coldbox watch-reinit
    
    # Open documentation
    coldbox docs
    coldbox docs search="event handlers"
    
    # Open API documentation
    coldbox apidocs
    # ๐Ÿš€ Create a modern app with all the bells and whistles
    coldbox create app myApp --vite --docker --migrations --rest --open
    
    # ๐Ÿ”ง Force CFML for a legacy project with immediate editing
    coldbox create handler Users --cfml --force --open
    
    # ๐Ÿ“‹ Get detailed help for any command
    coldbox create resource --help
    {
        "name": "My BoxLang App",
        "language": "boxlang",
        "testbox": {
            "runner": "/tests/runner.bxm"
        }
    }
    {
        "name": "My App",
        "testbox": {
            "runner": "boxlang"
        }
    }
    # Default behavior (creates BoxLang code)
    coldbox create handler users
    coldbox create model User
    
    # Explicit BoxLang generation (usually not needed)
    coldbox create handler users --boxlang
    
    # Force CFML generation for legacy projects
    coldbox create handler users --cfml
    coldbox create app myApp --cfml
    # ๐Ÿ“‹ See all available commands
    coldbox help
    
    # ๐Ÿ” Get detailed help for any command
    coldbox create handler --help
    coldbox create model --help
    coldbox create app --help
    
    # ๐Ÿ“Š Check your CLI version
    coldbox --version
    ColdBox Starter TemplatesGitHub
    github.com/coldbox-templates
    Logo