Where should I instantiate my models in a ColdFusion Model Glue controller?

346 views Asked by At

Let's say I have a client who has a list of orders and a wishlist. In my model, I have a ClientRepo, OrderRepo, and WishListRepo. In the controller, where should I be instantiating these repositories? Is it a good idea to make them class-level instances?

component ClientController
{
    ClientRepo = new ClientRepo();
    OrderRepo = new OrderRepo();
    WishListRepo = new WishListRepo();

    public void function HomePage(any event)
    {
        var clientId = event.getValue("id");
        var client = ClientRepo.getClientById(clientId);
        var orders = OrderRepo.getOrdersForClientId(clientId);

        // put the variables into the event object for the view to access
    }
}

Or would a better design be to instantiate them within the function?

public void function HomePage(any event)
{
    var ClientRepo = new ClientRepo();
    var orderRepo = new OrderRepo();
    var wishListRepo = new WishListRepo();

    // rest of the code is the same
}

The assumption here is that other functions in ClientController need access to the same repositories.

Also, what is the lifetime of the controller? Is it once-per-request, once-per-session, or once-per-application?

1

There are 1 answers

0
Boomerang Fish On BEST ANSWER

Disclosure: I'm a contributor to the Model-Glue project so I probably know what I'm talking about :-)

CFML doesn't have true class-level instances like Java. If you want singletons (a single instance shared across many parts of an application) you need to either put it in a shared scope (yuk!) or use a bean container. Fortunately Model-Glue has tight integration with ColdSpring (a popular bean container for CFML), and Model-Glue 3 makes it easier than ever to use ColdSpring beans in your controllers.

First, edit your ColdSpring.xml to include definitions for your singletons:

<bean id="ClientRepo" class="MyApp.model.client.ClientRepo"/>
<bean id="OrderRepo" class="MyApp.model.order.OrderRepo"/>

This is only a simple example of course. ColdSpring is a powerful dependency injection framework based on Java's Spring. Check out the ColdSpring Quickstart for some of the other things you can do with it.

Once the beans are defined in ColdSpring, you could have your controller explicitly ask for them via getModelGlue().getBean() calls. However a better way is to declare your controller's dependency on those beans and let Model-Glue inject them into your controller for you. The dependency can be declared either in ModelGlue.xml or in your controller CFC. Here's how to declare bean dependencies in your controller:

component ClientController beans="ClientRepo,OrderRepo"
{
    public void function HomePage(any event)
    {
        var clientId = event.getValue("id");
        var client = beans.ClientRepo.getClientById(clientId);
        var orders = beans.OrderRepo.getOrdersForClientId(clientId);

        // put the variables into the event object for the view to access
    }
}

Any declared beans are injected into the "beans" scope of your controller by the framework so they're ready to use by any listener functions. Note however that bean injection occurs after initialization, so you cannot use them an init() function.

ColdSpring beans are singletons by default, so if the same ColdSpring bean is injected into multiple controllers they will all end up with the same instance of the bean. If you add singleton="false" to the bean definition then each controller will each end up with a different instance; I can't think of why you would want to do that though.

For more information on bean injection in Model-Glue, check out the Bean Injection HOWTO on the Model-Glue Wiki.

Model-Glue 3.1 instantiates all its controllers at framework initialization time as singletons, so each controller is created once-per-application. Future versions may delay the instantiating of controllers until they are first needed, so it's best to not make assumptions on when they are initialized. If you really need to have some code in a controller executed on application initialization time, I suggest you add an onApplicationStart listener to it.