[coldbox-3.6.0] configure coldbox to split model and domain objects?

Just curious if there is a way to configure coldbox to have a separate directory for domain classes and services, a la grails? In looking at the documentation it looks like you can just configure the name of the model directory, but im wondering if I may be missing another way. My ideal setup would be something like:

/app
/model
userService.cfc
/domain
User.cfc

Please let me know if I can clarify anything.

Absolutely. WireBox will let you do whatever you want in your models.

The models folder is essentially the default convention folder for your CFCs, just like handlers and views are the default convention folders for controllers and rendered output. In WireBox, we call the models convention folder the “scan location”. WireBox can have unlimited scan locations-- “models” is just the default. You can also create subdirectories inside of the models directory or create entirely new directories in your web root (or out of it).

If you are using explicit mappings in your WireBox.cfc binder config like so:

map(“user”).to(“domain.user”);
map(“userService”).to(“model.userService”);

Then you are done! Explicit mappings don’t bother with scan locations and simply resolve the full component path with ColdFusion’s mappings.

getModel(“user”)
getModel(“userService”)

If you are using mapDirectory like so:

mapDirectory(“model”)
mapDirectory(“domain”);

Then you are also good. This is the same as the explicit mappings, and recursively scans the folder and creates mappings based on the CFC name (which can be overridden with metadata inside the CFC).

getModel(“user”)
getModel(“userService”)

If you are using scan locations, that means you have not added any mappings in your WireBox.cfc binder config and you are asking for the models using a path relative to one of your scan location folders. Since userService is in the root of the models directory, this will still work since WireBox will scan “models.userService” looking for it:

getModel(“userService”)

To make WireBox scan your domain folder, all you need to do is add a line of code in the WireBox.cfc binder config to add the domain folder as a scan location:

scanLocations = [“models”,“domain”]

That will check for “models.user” and “domain.user” in that order.

getModel(“user”)

One note about using scan locations-- if you have a subdirectory, you must include the full path relative to the root of the scan location:

/app
/model
userService.cfc
/security
securityService.cfc

getModel(“security.securityService”)

Hope this helps. Here’s some reading for you:

http://wiki.coldbox.org/wiki/WireBox.cfm

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

E-mail: brad@coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com

Perfect, thank you!

So I think I have found what I consider to be a bug with this functionality. If you are using an appMapping, meaning your application is in a subfolder under your root, the scanLocations do not look relative to your appMapping, they only look relative to your web root.

In my specific example, I have an application that is in a folder called FMMAdmin, so for example my webroot might be http://localhost/ that points to c:\home\root but my application is actually in http://localhost/FMMAdmin/ which is c:\home\root\FMMAdmin. My appMapping gets set properly to FMMAdmin, but if I have the scanLocations = [“model”,“services”,“domain”] and I have a userService.cfc in services, it is not found, because the scan location paths are resolving to c:\home\root\services\ instead of c:\home\root\FMMAdmin\services like it should be.

Changing the scanLocations to scanLocations = [“FMMAdmin.model”,“FMMAdmin.services”,“FMMAdmin.domain”] does fix the problem and is a viable workaround, but in my opinion that should not be necessary. The scan locations should be relative to the appMapping, not the webroot.

As far as a fix, I can see several places in the code where this could be fixed, but I am unsure of the proper place. It seems that the default mapping of model does come through as FMMAdmin.model and gets set properly, so I don’t think it is appropriate to check for an appMapping in the Binder.cfc:scanLocations() method. The scanLocations are passed in from the wirebox config in Binder.cfc:loadDataDSL() on line 818. Would it be appropriate to change this code to do a check if there is an appMapping, and then loop over the scan locations provided and append the appMapping to the beginning of it if it does not already exist? Can anyone think of a reason that would break existing code or expectations?

To that end - if I was going to submit a fix for this, is a pull request on https://github.com/ColdBox/coldbox-platform the appropriate place to do this, or is there another process I should follow?

Thanks for the feedback. I’ve never considered that a bug, per se. Scan locations follow the typical rules of CFML class resolutions-- same folder > web root > app mapping > server mappings. Scan locations can be anywhere on the drive-- even outside the web root, so the path must resolve and it’s always been up to the developer to hand ColdBox a path for those that will resolve taking into account things like the app mapping. There’s even an AppMapping variable available in the WireBox Binder for you to use in your mappings so the binder will automatically adjust to being in a sub directory.

I haven’t fully thought through it yet, but it seems like one issue with trying to automatically append the app mapping would be if you had a scan location that pointed directly to a CF mapping, or to a location outside of the web root-- those would all break if the app mapping was blindly appended to the front of them. Perhaps you can add a ticket to enhance implicit mappings to try searching appMapping & scanLocation if it doesn’t find it directly in a scan location and we can look into it.

In the mean time, just use the appMapping variable in the binder-- it’s not a hack, it’s why we included it.

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

E-mail: brad@coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com

I’m not certain I follow what you mean by using the appMapping variable in the binder. Do you mean for me to alter the binder.cfc in some way?

The reason I consider this a bug is that if you dump out the scanLocations after they have been processed, because I am using an appMapping, coldbox is already recogizing FMMAdmin.model by default and resolving it properly.

I agree, blindly adding the appMapping does seem like it would cause issues. Perhaps it could pre-process the list and add the appMapping version to the end of the array for each non-appMapping prefixed version, and then once the paths are resolved we could use directoryExists to cull the non-existant directories from the list? So in my example, [“services”,“domain”,“model”] would turn into [“services”,“domain”,“model”,“FMMAdmin.services”,“FMMAdmin.domain”,“FMMAdmin.model”] and then when adding them to instance.locations, the non-existant directories would be thrown out.

I’m not certain I follow what you mean by using the appMapping variable in the binder

Sorry I wasn’t clear. The binder config is just the config/WireBox.cfc file where you put your mappings and scan locations. So instead of this:

scanLocations = [“models”,“domain”]

Do something like this:

scanLocations = [“#appMapping#.models”,“#appMapping#.domain”]

The reason I consider this a bug is that if you dump out the scanLocations after they have been processed, because I am using an appMapping, coldbox is already recogizing FMMAdmin.model by default and resolving it properly.

That doesn’t make it a bug though. Basically, when ColdBox creates WireBox, it sets up the default scan location and since ColdBox knows about its app mapping, it adjust for it. Once you specify the app mapping manually, you are taking over and you need to provide fully resolvable component paths for WireBox to use.

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

E-mail: brad@coldbox.org
ColdBox Platform: http://www.coldbox.org
Blog: http://www.codersrevolution.com