How can I make a WireBox injected dependency available to a constructor method?

821 views Asked by At

In this example, I have a model object called test.cfc which has a dependency testService.cfc.

test has WireBox inject testService through a property declaration. The object looks like this:

component {

     property name="testService" inject="testService";

     /**
     *  Constructor
     */
     function init() {

         // do something in the test service
         testService.doSomething();

         return this;

     }

 }

For reference, testService has a single method called doSomething() which dumps out some text:

component
     singleton
{

     /**
     *  Constructor
     */
     function init() {

         return this;

     }


     /**
     *  Do Something
     */
     function doSomething() {

         writeDump( "something" );

     }

 }

The problem is, WireBox doesn't seem to inject testService until after the constructor init() method fires. So, if I run this in my handler:

prc.test = wirebox.getInstance(
     name = "test"
);

I get the following error message: Error building: test -> Variable TESTSERVICE is undefined.. DSL: , Path: models.test

Just for sanity sake, if I modify test so that testService gets referenced after the object is constructed, everything works fine. The problem seems to be isolated to constructor methods.

How can I make sure my dependencies can be referenced in my object constructor methods? Thanks for your assistance!

1

There are 1 answers

0
Brad Wood On BEST ANSWER

Due to the order of construction, you can't use property or setter injections in the init() method. Instead, you can access them in the onDIComplete() method. I realized the WireBox docs only had a passing reference to this, so I have added this excerpt:

https://wirebox.ortusbooks.com/usage/injection-dsl/id-model-empty-namespace#cfc-instantiation-order

CFC Building happens in this order.

  1. Component is instantiated with createObject()
  2. CF automatically runs the pseudo constructor (any code outside the a method declaration)
  3. The init() method is called (if it exists), passing any constructor args
  4. Property (mixin) and setting injection happens
  5. The onDIComplete() method is called (if it exists)

So the proper version of your CFC would be as follows:

component {

     property name="testService" inject="testService";

     /**
     *  Constructor
     */
     function init() {
         return this;
     }

     /**
     *  Called after property and setter injections are processed
     */
     function onDIComplete() {
         // do something in the test service
         testService.doSomething();
     }

 }

Note, it would also be acceptable to switch to constructor injection, but my personal preference is property injection due to the reduced boilerplate of needing to receive the argument and persist it locally.

https://wirebox.ortusbooks.com/usage/wirebox-injector/injection-idioms