Is there a way to have a model in a module referen...
# box-products
b
Is there a way to have a model in a module reference a module setting without explicitly using the module mapping? For example I have the following app structure: app -- modules ---- mymodule ------ models -------- _BaseComponent.cfc -------- ComponentA.cfc In my ModuleConfig.cfc configure() method, i have a setting named 'myTestSetting'. I know in my _BaseComponent.cfc I can inject that setting like so:
property name="mySetting" inject="coldbox:moduleSettings:_*mymodule*_:myTestSetting";
But is there some way to do something like this without actually hardcoding 'mymodule' or some other mechanism besides property injection? My '_BaseComponent.cfc' is a component I use in multiple code bases and I copy it from one code base to another as needed (which isn't very much). I'm trying to help my future self out when I copy it and I forget to update the module name.
b
@bdeline2 This question is a bit of a catch-22
If the CFC needs to know a setting from a specific module, then it needs to know what module from which to obtain the setting!
If the CFC is re-usable, then add a property or factory method in the child class which knows what module it's a part of.
There is not necessarily anything in the CFC once it's created that "knows" where it came from, unless perhaps you looked at its CFC path to make a guess
Copy code
getMetaData( this ).name
Another alternative would be to not declare the injection as a mixin inside the CFC, but to explicitly declare the mapping in the module's config via the binder DSL.
Of course, this only really helps you if you're asking WireBox to create base component directly. If
ComponentA.cfc
just has
Copy code
component extends='_BaseComponent.cfc' {}
then that doesn't really help
It would be an interesting feature for there to be a module-aware injection namespace such as
Copy code
property name="mySetting" inject="coldbox:moduleSettings:{thisModule}:myTestSetting";
and have WireBox somehow be aware of the module that the CFC requesting the injection lived inside of. cc/ @lmajano
b
@bdw429s Thanks for the help as always. I think the 'module-aware injection namespace' was what I was hoping against hope for. I did toy with the idea of explicitly declaring the mapping in the module's config via the binder DSL. But the issue I'm going to run into is that within an app, I would have 'mymodule1' and 'mymodule2' using this '_BaseComponent.cfc' and since they both map 'myTestSetting' to different values one of the modules would wind up overwriting the value set by the other module. I think for the time being I'm just going to have to suck it up and explicitly declare the module name.
w
@bdeline2 I think you are focusing too much on the injection syntax because it has to be static. There are other ways to retrieve modulesettings, for example
getModuleSettings( module )
;
The name of the module can also be retrieved dynamically, e.g. in a handler by event.getCurrentModule(). In a component you could inject the requestservice so you can obtain the modulename. e.g:
Copy code
property name="req" inject="coldbox:requestService";

//….
var mySetting = getModuleSettings( req.getContext().getCurrentModule() )["myTestSetting"];
b
@wil-shiftinsert Thanks. Let me do some testing on using the requestservice. The modules I'm trying to implement this for don't use handlers. It's more like a library like Hyper.
w
Well wait. I just realize this might not work, because only your module handlers have some notion of the current module. So if you are calling it from some other place I am afraid it makes no sense. But there should be more ways to do this dynamically
How are you instantiating your
_BaseComponent.cfc
, using wirebox, directly or are you extending it?
and what Brad said: If the CFC is re-usable, then add a property or factory method in the child class which knows what module it’s a part of, so you can configure it in your moduleConfig with the correct settings.
Copy code
var mySetting = getModuleSettings( 'myModule' ).mySetting;

binder.map("myBaseComponent")
  .to("#moduleMapping#.model._BaseComponent").property(
    name="mySetting",
    value=mySetting
  )
Or you can do something simular with initArg if your setting is part of your constructor. There’s no need to hardcode your setting in a injection, instead you should set this up in every module which is using your
_BaseComponent
If you are using your base component multiple times in an application because you are using it in multiple modules, you have to make sure it will have a different alias in every module.
b
@wil-shiftinsert To answer your question about the '_BaseComponent.cfc' I was trying to convey it's a component that other components extend, so it wouldn't be called directly. It's an interesting angle you presented with the initArgs that I'll look at tomorrow. I might be able to pair that with the 'mapDirectory()' method to inject the module setting.
w
In that case you can make a property for the basecomponent and map the other component using the property or initarg method
b
That's what I'm thinking. I changed my mind and i'm looking at it now. I'll keep you posted.
@wil-shiftinsert FYI, I was able to get this working by setting 'this.autoMapModels' to false in ModuleConfig.cfc and do the following in my configure() method
Copy code
binder.mapDirectory(
                packagePath="#moduleMapping#.models", 
                namespace="@#this.modelNamespace#",
                influence=function(binder, path){
                    binder
                        .initArg(name='myTestSetting', value='xyzxyz')
                        .asSingleton()
                        ;
                }
            );
I think this will work pretty nicely. Thanks for the help.