Is it possible to configure object mappings in ModuleConfig and have all apps that includes the module to be able to use the mappings without having to remap them in the app’s Wirebox?
For example, say I have an app called JohnnyBookshop, and it’s including the Bookshop module.
In the Bookshop module there’s a service called BookService: /modules/bookshop/services/BookService.cfc
Is it possible that, simply by defining the mapping in ModuleConfig.cfc, that the BookService be made automatically available for injections into JohnnyBookshop’s models and handlers, like so:
Bookshop module’s ModuleConfig.cfc
What you are describing is definitely possible and is, in fact, the expected behavior. With just the module and that ModuleConfig.cfc
you should be able to inject bookService
.
Without the local app WireBox mapping, what does the bookService
inject? Does it error? Is it possible the module isn’t being loaded?
A couple tips I’d point out as well is to 1) use #moduleMapping#
in the ModuleConfig.cfc
as the base path. This avoids having to wait for mappings to be available. And 2) use a custom namespace for your mapping. This makes it easy to identify it came from a module. The default in ColdBox is to append an @
with the module name. With that change, your binding would look as follows:
binder.map("bookService@Bookshop").to("#moduleMapping#.services.BookService");
I’m a little confused why you’re wanting to create mappings at all. ColdBox automatically creates mappings for all model CFCs in all modules. The name is “nameOfCFC@nameOfModule”. So you should be able to reference the mapping ID Eric mentioned ( bookService@Bookshop ) with no additional configuration at all.
You can dump out all the mappings that WireBox already has like so:
writeDump( wirebox.getBinder().getMappings().keyArray() )
One caveat to Brad’s automatic model mapping is that it only happens for models in the module’s models
folder in the root of the module. In your example your component was under a services
folder in the root, so it would NOT be automatically picked up. That’s fixed by either an explicit mapping or by restructuring your folder layout to match the conventions.
Ahh, good catch Eric-- I hadn’t noticed that. I agree the easiest thing to do here is actually follow the conventions for models and put them under the models folder so they will get picked up automatically. If there’s some pressing reason why you can’t do that, this one line in your moduleconfig would also do the trick:
binder.mapDirectory( packagePath=’#moduleMapping#.services’, namespace=’@moduleName’ );
That will recursive scan the folder and map all the CFCs based on their name with the module namespace added to it. That’s basically what ColdBox does behind the scenes for your models folder.
Thanks guys. Ok, just found out it’s not the injection into handlers that failed, it’s actually the AuditAdvice.cfc. I’ve got an advice set up in my Wirebox.cfc:
mapAspect("AuditAdvice").to("advices.AuditAdvice").asSingleton();
And in AuditAdvice.cfc I’m trying to inject BookService. I’ve tried both:
<cfproperty name="bookService" inject="BookService@Bookshop"/>
(with binder.map(“bookService”).to("#moduleMapping#.services.BookService")
and:
<cfproperty name="bookService" inject="BookService"/>
Both are returning error:
The DSL Definition {JAVACAST={null},REF={null},SCOPE={variables},REQUIRED={true},VALUE={null},DSL={id:BookService},TYPE={any},ARGNAME={},NAME={bookService}} did not produce any resulting dependency
The target requesting the dependency is: ‘AuditAdvice’
Your core WireBox config runs prior to any modules being loaded. So the error message is correct in that that mapping doesn’t exist yet at the time it’s being asked for. In ColdBox 5 we’ve make wirebox.cfc an interceptor so you can add in an afterConfigurationLoad method where you add mappings that are dependent on modules being loaded. Another workaround is to use a provider for the injection that doesn’t exist yet so long as as it won’t actually be used until after the module has loaded.
inject=“provider:mappingThatDoesNotExistYet”
That will defer the actual resolution of the mapping ID until the point where you try and use it which will likely be after the framework is up and processing requests.
Thanks. Looks like the provider approach works.