coldfusioncfmlcoldbox

How can you add dynamic ColdBox routes after configuration loads?


I'd like to create some routes based on data in a database table. I assume this will need to be done after the framework initializes so what I've done so far is created a new interceptor that runs on: afterConfigurationLoad.

My interceptor receives a service from my model which will query the data I need to create the routes. However, I'm not sure how to add routes at this point. When I try and call addRoute() directly I get an error Variable ADDROUTE is undefined. so I guess addRoute() doesn't exist in the framework Supertype.

Here's some sample code from my interceptor:

component {

     property name="myService" inject="myService"; // injects my model which will get some data

     /**
     * afterConfigurationLoad
     * Runs after the framework configucation loads
     */
     void function afterConfigurationLoad( event, interceptData, buffer, rc, prc ){

         // get some data which will be converted into routes
         var myDataList = myService.list();

         // loop through the data
         for ( var data in myDataList ) {

             // add our route. NOTE: I'll also want to populate the prc scope with a value
             addRoute( pattern="/#data.slug#", handler="data", action="index" );

         }

     }

 }

Edit 1: Using ColdBox v5.1.1

Update 1: Brad's answer put me on the right track. I was unable to inject the router in my interceptor because it generated an error. However, I was able to get an instance of the router from within the function using getInstance( "router@coldbox" ) and then call route() methods as needed to create my routes.

Important: Routes by default are appended to the routing table. You will likely need to prepend the routes if you want them to work.

Here's an updated version of the code which will work:

Solution 1:

component {

    property name="myService" inject="myService"; // injects my model which will get some data


    /**
    * afterConfigurationLoad
    * Runs after the framework configucation loads
    */
    void function afterConfigurationLoad( event, interceptData, buffer, rc, prc ){

        // instance the router
        var router = getInstance( "router@coldbox" );

        // get some data which will be converted into routes
        var myDataList = myService.list();

        // loop through the data
        for ( var data in myDataList ) {

            // prepend our route
            router.route( "/#data.slug#" ).prcAppend( { id : #data.id# } ).to( "data.index" ).prepend();

        }

    }

}

Additionally, there may be a simpler way to solve this problem by simply injecting the model service into the `config/router.cfc' configuration file and adding any dynamic routes that way.

Solution 2:

component {

    property name="myService" inject="myService"; // inject the model

    function configure() {

        setFullRewrites( true );

        // get the data I need from the model for dynamic routes
        var myDataList = myService.list();

        // loop through the data
        for ( var data in myDataList ) {

            // add the dynamic route
            router.route( "/#data.slug#" ).prcAppend( { id : #data.id# } ).to( "data.index" );

        }

        route( ":handler/:action?" ).end();
    }

}

Solution 3:

As it turns out, when the framework initializes, the interceptors get loaded first so not all dependencies will be available yet. Brad suggested using the provider namespace in the property which should also be an acceptable solution.

component {

    property name="myService" inject="myService"; // injects my model which will get some data
    property name="router" inject="provider:router@coldbox";


    /**
    * afterConfigurationLoad
    * Runs after the framework configucation loads
    */
    void function afterConfigurationLoad( event, interceptData, buffer, rc, prc ){

        // get some data which will be converted into routes
        var myDataList = myService.list();

        // loop through the data
        for ( var data in myDataList ) {

            // prepend our route
            router.route( "/#data.slug#" ).prcAppend( { id : #data.id# } ).to( "data.index" ).prepend();

        }

    }

}

Solution

  • Inject the ColdBox Router

    property name='router' inject='router@coldbox';
    

    and call its methods detailed here in the API docs:

    http://apidocs.ortussolutions.com/coldbox/5.2.0/index.html?coldbox/system/web/routing/Router.html

    The addRoute() method is part of that CFC.