Model Integration

We have a complete section dedicated to the Model Layer 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 (Aggregation)
  • Request Model Objects (Association)

ColdBox offers its own dependency injection framework, WireBox, which allows you by convention to talk to your model objects. However, ColdBox also allows you to connecto to third-party dependency injection frameworks via our IOC module: http://forgebox.io/view/cbioc

Dependency Injection

Your event handlers can be autowired with dependencies from any dependency injection framework. By autowiring dependencies into event handlers, they will become part of the life span of the event handlers (singleton) and thus gain on the performance that an event handler is wired with all necessary parts upon creation. This is a huge benefit and we encourage you to use injection whenever possible.

Info As a rule of thumb, injection only singletons into singletons.

Please note that injection aggregates model objects into your event handlers. The Injection DSL can be applied to:

  • cfproperty
  • constructor arguments
  • setter methods

It will be your choice to pick an approach, but we mostly concentrate on property injection as you will see from our examples.

Info 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'

Requesting Model Objects

The other approach to integrating with model objects is to request them and use them as associations. We would recommend requesting objects if they are transient objects or stored in some other volatile storage scope. Retreiving of objects is ok, 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.

Info 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.

 + application
  + models
     + FunkyService.cfc

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;
    }

}

Our funky service is not that funky after all, but it is simple. So how do we interact with it? Let's build a Funky event handler and work with it.

Injection

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");
    }    


}

So by convention, I can create a property and annotate it with a inject attribute and 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:

<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>

Great! Just like that we can interact with our model layer without worrying about creating the objects, persisting them and even wiring them. That is exactly 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.

// 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";

Requesting

Let's look at the requesting approach. We can either use the following approaches:

Via Facade Method

component{

    function index(event,rc,prc){

        prc.data = getModel( "FunkyService" ).getFunkyData();

        event.renderData( data=prc.data, type="xml" );
    }    


}

Directly via WireBox:

component{

    function index(event,rc,prc){

        prc.data = wirebox.getInstance( "FunkyService" ).getFunkyData();

        event.renderData( data=prc.data, type="xml" );
    }    


}

Both approaches do exactly the same, in all reality getModel() does a wirebox.getInstance() callback (Uncle Bob), 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 can be seen with some practical math:

1000 Requests made
- 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

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.

results matching ""

    No results matching ""