Model Integration
Last updated
Last updated
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:
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
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.
Association defines a relationship between classes of objects that allows one object instance to cause another to perform an action on its behalf. - 'wikipedia'
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.
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.
You can use the value of the inject
annotation in several ways. Below is our recommendation.
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.
Your event handlers can be autowired with dependencies from 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 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 . 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
Tip: The is vast and elegant. Please refer to it. Also note that you can create object aliases and references in your : config/WireBox.cfc
The other approach to integrating with model objects is to request and use them as 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.