[coldbox-3.8.1] assistance moving from fw1/coldspring to coldbox/wirebox

We’ve got an existing project done with FW/1 and ColdSpring. For the most part it’s well laid out - it was this groups first FW/1 project so there are some issues but overall it’s a step in the right direction :slight_smile:

We’re getting ready to start a new project and we’re evaluating ColdBox/Wirebox…

I’ve got a very basic CB site setup which I cobbled together from one of the sample apps and my own hacking.

The main issue I’ve run into is how to handle things like DSN with some sort of environment check.

Currently we have this ‘common’ library of services we’re trying to develop and those touch several different datasources.

The person here before I was setup ColdSpring and while I sort of understand it I’m no expert. I greatly prefer convention over configuration :slight_smile:

So I’m trying to figure out the best way to replace a bunch of ColdSpring beans like this:

With it’s ColdSpring (or more likely Wirebox?) equivalent.

I’m digging through the docs (there are a lot of docs!) and at this point I’m a bit overwhelmed.

I know there are probably 101 ways to wire this up and none of them are ‘right’ but I just need some suggestions on a simple solution that will get me moving forward and I can refactor later :slight_smile:

Thanks!
Jim

Ohh, forgot about this:

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

More examples:

map("ColdboxFactory").to("coldbox.system.extras.ColdboxFactory");
map("ColdBoxController").toFactoryMethod(factory="ColdBoxFactory",method="getColdBox");
map("BeanInjector")
	.toFactoryMethod(factory="ColdBoxFactory",method="getPlugin")
	.methodArg(name="plugin",value="BeanFactory")

signature0.jpg

Luis F. Majano
CEO
Ortus Solutions, Corp
www.ortussolutions.com

ColdBox Platform: http://www.coldbox.org
Linked In: http://www.linkedin.com/pub/3/731/483
Blog: http://www.luismajano.com
IECFUG Manager: http://www.iecfug.com

Social: twitter.com/lmajano facebook.com/lmajano

Hi Jim, I see Luis already replied but I’d like to toss in some advice too. Firstly, I’m excited you’re giving ColdBox a try. I don’t think you’ll want to go back once you see how trivial it makes things like environment tier control. We understand that apps need more than just MVC conventions and you have better things to do than reinvent the wheel. There’s a difference between a framework that “gets out of your way” and one that runs and hides when you need help :slight_smile:

So generally speaking, the FW/1 conventions are pretty much a copy of the ColdBox conventions which is good because it means you don’t have much to learn there. In fact, a simple, minimalistic “hello world” app is surprisingly similar to the same in FW/1. The main difference is now you have an entire development platform of tools at your disposal to build upon the blindly simple MVC conventions.

For starters, I’d like to point out that many of the docs on wiki.coldbox.org are what I call “comprehensive” docs that attempt to cover all espects of our libraries. These are great to dig into when you’re ready to go deeper, but might be a bit too much if you’re starting out. (I’m a little weird, I guess. I read them top to bottom to familiarize myself and then check back regularly jumping down to the part I want to reference)
I would recommend you start with our PDF ref cards These are a high-level introduction into our libraries and leaves plenty uncovered for you to discover later:
http://wiki.coldbox.org/wiki/Dashboard.cfm#PDF_Ref_Cards

If you webinars, we have dozens of recorded sessions here. Check out the ColdBox developers week 2012/2013 recordings.
http://www.coldbox.org/media

There’s also a collection of “Tips of the Week” on the ColdBox blog:
http://blog.coldbox.org/__search?q=Tip%20of%20the%20Week

This list is also excellent to get an immediate sounding board for questions and advice.

So, to address your specific questions a bit more directly…

> The main issue I’ve run into is how to handle things like DSN with some sort of environment check.

Luis mentioned this, but environment control has been part of ColdBox since the early days. Its something everyone needs! Start with this tip to get you started:
http://blog.coldbox.org/blog/tip-of-the-week-using-environment-control-in-coldbox

> The person here before I was setup ColdSpring

I’m sorry. ColdSpring is like beating yourself to death with XML :-/

Here’s our WireBox ref card:
https://github.com/ColdBox/cbox-refcards/raw/master/WireBox/WireBox-Refcard.pdf

And here is a couple simple runnable examples you can play with in your browser:
http://runnable.com/Usp0hdiR7RMpAAAR/use-wirebox-to-create-objects-in-coldbox-for-coldfusion-cfml-mvc-and-railo
http://runnable.com/UssCLbsLBpIvAAAj/use-wirebox-to-autowire-objects-in-coldbox-for-coldfusion-cfml-mvc-and-railo

You’ll find WireBox has very simple conventions. The simplest of which is just to drop a CFC in your /model directory and then call getModel( ‘myCFC’ ) in a handler or view. That simple! You can use WireBox with zero configuration if you use the model’s convention folder. Now, explicit mappings are possible like Luis showed, but it uses a nice DSL, not XML. You can give WireBox additional folders to look in with the “scanLocations” setting in WireBox.cfc but CFCs in nested folders must be refernced with their “path.to.cfc”. That’s why my favorite WireBox feature is the mapDirectory() command in the WireBox config. Just call mapDirectory( ‘/placeIKeepMyModels’ ) and it will recursivley scan that entire folder and map everything based on the name of the CFC at startup.

Now, as far as specifying your dependencies, it looks like you’re using constructor args. These actually work out of the box if you just add inject=“name” to your init()'s args. WireBox will see the constructor args, go find those dependencies, and pass them in all automatically. If you prefer convention over config, this is great!

component {
/**

  • @myService.inject myService
    */
    function init( myService ) {}
    }

Note, it’s up to you to take arguments.myService in your init and set it somewhere. I actually use an even simpler method called mixin injection. All you do is place a cfproperty at the top of the component with an inject attribute and your dependency will automatically be made available to you in the variables scope (by default).

component {
property name=‘myService’ inject=‘myService’;
}

It really doesn’t get any easier then that. You can also inject all sorts of things from ColdBox settings, loggers, caches, Java object, constants, you name it. And all of this makes the config optional. Another note, ColdSpring is very limited and only provides singleton persistence. WireBox, by default, will create everything as transients (recreated each time they are asked for). You can use our mapping DSL to do this, but again, I prefer the handy “singleton” annotation:

component singleton {}

Boom! Now this CFC will only be created once and the entire application will share a single instance.

That should get you started on your way. Just ask if you have any questions.

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

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

Luis and Brad - thanks for all the help!!!

The refcards are much easier to digest :slight_smile: I have the ColdBox and Wirebox cards bookmarked!

I think I have things working - I messed around with mapping and injecting last night and got something that pulled from my remove common model and today I cleaned up, removed the mapPath stuff and am just using injection.

I really didn’t have to change my remote model that much.

Need to reap up on MapDirectory() vs scanLocation() and a few other things but I feel much better now that I have the basics wired up and working :slight_smile:

Jim

Quick question - what takes precedence - scanLocations or mapDirectory? Can I define both - I’d like to do scanLocations for the local model (we won’t have much there) and then mapDirectory to scan all our objects in our common folder.

My initial stabs at this aren’t working and I’m wondering what I’m missing.

I had:
scanLocations = [“com.mydomain.security”,“model”]

which points to a specific model directory - and that worked with doing

But now I’m trying to do something like:

mapDirectory( “com.mydomain” )

And it’s not working?

Jim

Jim, I’m glad to hear the pieces are falling in place!

I see you started a new thread on the scan locations and map directory so I’ll reply to that there.

Thanks!

~Brad

Wirebox stores its runtime configuration in an object called the binder. The binder keeps a list of all the objects it “knows” about in a list of mappings. You can view these mappings at any time with this code:

WireBox has to have a mapping for an object before it can create it. You can create these explicitly (via map().to() DSL or mapDirectory()) or let WireBox create the mappings for you on the fly the first time you ask it for an object.

Here are the two main differences between scan locations and mapping a directory.

1)

When you use scan locations, the mappings are not created until the first time you ask for that CFC. WireBox goes and looks in each of your scan locations until it (hopefully) finds the CFC, and then it creates a mapping for it so it never has to look again (until you reinit, of course). However, when you use mapDirectory() (or map().to(), or mapPath()) the mapping is created right up front when WireBox is loaded. That way WireBox never has to do any searching.

2)

When a CFC is “discovered” via a scan location, the mapping ID (which you must use to access it) is the full path starting in the root of the scan location. Imagine an app with a scan location of /model that has this CFC:
/model/com/foo/bar/user.cfc

If you ask for getModel( ‘user’ ), WireBox will look for /mode/user.cfc and then give up. You must ask for getModel( ‘com.foo.bar.user’ ) and then WireBox will find it and create a mapping ID for it of “com.foo.bar.user”. Think of scan location as a convention location just like handlers and views. They behave the same way and you must specify the entire path starting at the root of the convention folder.

Now, when you use MapDirectory(), all that does is pull a recursive file listing from the folder, loop over it and do a mapPath() on each CFC. Of course, mapPath() uses the name of the CFC as the name of the mapping. (Make sure your CFC names are unique!) Because of this, a mapping is created when your app starts up with an ID of “user” that points to model.com.foo.bar.user. This means all you have to ask for is getModel( ‘user’ ). This is my preferred method because it is less typing and lets you move your models around with zero refactoring.

So now, on to your questions:

> what takes precedence - scanLocations or mapDirectory

Since mapDirectory() explicitly creates mappings when WireBox loads, I guess you could say it takes “precedence”. A more correct way to put it is, whatever ID you ask WireBox for-- if a mapping for that already exists, it uses it. If not, it goes searching through your scan locations to try and find it. The mapping IDs created by mapDirectory() will only overlap the IDs created in your scan locations for CFCs in the root folder though since explicit mappings only use the CFC name, but scan locations require the full path.

> mapDirectory( “com.mydomain” ) And it’s not working?

You’ll need to be more specific than “not working”.

I know the docs show both dot notation and slashes, but I always use slashes for what it’s worth.

mapDirectory(’/shared/model’);

If userManager exists in a subfolder of /com/mydomain/ then that should work. And to confirm, your mapDirectory() call in in your WireBox binder located here, right?
/config/WireBox.cfc

Post back the error message you are receiving.

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 have: \com\mydomain\security\usermanager.cfc - this contains a simple ‘load’ method which will pull a user from the db giving a userID.

\com is setup as a Railo mapping (/com c:\inetpub\wwwroot\common\com)

My config:

handler:

I can call my datasource setting in my ColdBox config and correctly pass that in (woot!)

wirebox.config:
scanLocations = [“com.mydomain.security”,“model”],

And this setup works. I can correctly get results from that remote method.

If I switch my wirebox.config to:
scanLocations = [“model”],
mapDirectory( “com.shortstravel” ); (i’d think this should recursively find my usermanager)

I get this error:

Application Execution ExceptionError Type: Builder.DSLDependencyNotFoundException : [N/A]
Error Messages: The DSL Definition {REF={null}, REQUIRED={true}, ARGNAME={}, DSL={id:userManager}, JAVACAST={null}, NAME={userManager}, VALUE={null}, SCOPE={variables}} did not produce any resulting dependency
The target requesting the dependency is: ‘vi.handlers.user’

I’m sure I’m missing something simple or doing something stupid :slight_smile:

Thanks!!
Jim

Bump!

Brad/Luis - any thoughts on what I’m doing wrong here?

Thanks!
Jim

Did you try looking at the mappings inside WireBox like I suggested in my last E-mail?

Also, did you reinit after making changes?

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

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

try a direct mapping to see if your scan location is not finding the cfc.

binder.map(“userManager”).to(“com.mydomain.security.userManager”).asSingleton();

I was hoping not to have to map every directory / object??

As I said in my earlier post - scanLocations[] works fine. But I have to specify directories:

scanLocations = [
“com.mycfcs.security”,“com.mycfcs.account”,“model”],

If I do that - and dump

I do see my objects:

accountManager var.accountManager
coldbox.system.EventHandler var.coldbox.system.EventHandler

userManager var.userManager
WireBoxValidationManager var.WireBoxValidationManager

But again I don’t want to map every directory/object within my common folder. Reading the docs it seems like I should be able to use mapDirectory() and Wirebox should scan my entire com.mycfc directory struct?

But if I switch my wirebox.config to:
scanLocations = [“model”],
mapDirectory( “com.mycfcs” ); (i’d think this should recursively find my usermanager)

I get this error:
Application Execution ExceptionError Type: Builder.
DSLDependencyNotFoundException : [N/A]
Error Messages: The DSL Definition {REF={null}, REQUIRED={true}, ARGNAME={}, DSL={id:userManager}, JAVACAST={null}, NAME={userManager}, VALUE={null}, SCOPE={variables}} did not produce any resulting dependency
The target requesting the dependency is: ‘vi.handlers.user’

Am I just mis-understanding how mapDirectory() works and do have to map everything?

Thanks much!!
Jim

Jim
Scan locations just puts a pointer in that directory. Meaning that you request the object via the path without the scan location prefix. Basically by convention.

Map directory actually scans recursively the directory and registers all the CFCs it finds. Then creates aliases for them according to cfc name. You can pass closures to yeh function to influence the mapping and naming if you like as well.

Luis Majano
CEO
Ortus Solutions, Corp

P/F: 1-888-557-8057
Direct: (909) 248-3408

ColdBox Platform: http://www.coldbox.org
ContentBox Platform: http://www.gocontentbox.org
Linked In: http://www.linkedin.com/pub/3/731/483
Social: twitter.com/ortussolutions | twitter.com/coldbox | twitter.com/lmajano | twitter.com/gocontentbox

OK thats how I thought it worked.

I still can’t get mapDirectory() to map anything though. :frowning:

Do I need to do anything in addition to declaring that line in the Wirebox config? Do my CFC’s in my common directory need to be setup in a certain manner? I’m looking at the validation example in the sample apps which uses MapDirectory() and I don’t see anything special.

Will keep tinkering with it tomorrow!

Thanks!
Jim

Jim it should be straight forward. If you want I could do a connect session with you and help you tomorrow

Luis Majano
CEO
Ortus Solutions, Corp

P/F: 1-888-557-8057
Direct: (909) 248-3408

ColdBox Platform: http://www.coldbox.org
ContentBox Platform: http://www.gocontentbox.org
Linked In: http://www.linkedin.com/pub/3/731/483
Social: twitter.com/ortussolutions | twitter.com/coldbox | twitter.com/lmajano | twitter.com/gocontentbox

Jim, you shouldn’t need to map every object and I don’t think you’re misunderstanding anything. It’s just not working and we need to figure out why. Remove the scan location and put the mapDirectory() back. Then reinit, and dump out the mappings and see if your mapping exists. The exact struct key name is the “ID” of the mapping. If it’s not resolving, it means that the mapping isn’t being created OR it’s being created with a different ID than you’re expecting.

Also, perhaps you can attach your entire WireBox.cfc binder config just to see 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 will throw this up on Github later this morning!

Thanks guys!
Jim

Here is my current code, sanitized, commented and put on Github:
https://github.com/jimpriest/cbtest

In the root is an example of my modified UserManager.cfc which I copy to my common folder of cfcs.

This all works fine with scanLocation[] but when I attempt to switch the mapDirectory() it bombs out with the error I’ve posted in a previous thread.

Thanks!

Jim

I just plugged your code in and the mapDirectory() is working great. I had to make a couple changes to get it working.

  • Dropped code in folder
  • installed ColdBox (via CommandBox!)
  • Refactored ColdBox paths to remove com.framework.
  • Commented out references to accountManager and its data in user.cfc
  • Created \com\thecrumb\security folders and put Usermanager in there.
  • Confirmed scan locations worked
  • Removed scan locations, uncommented mapDirectory and reinitted.
  • Still correctly finds the usermanager
    I think you have something else going on with your CF mappings. Did you dump out the mappings with mapDirectory enabled like I asked?

Also, put this code in your WireBox.cfc

writeDump( directorylist( “\com\thecrumb”, true ) );abort;

That will help determine if the \com\thecrumb mapping is resolving where you think it is.

Thanks!

~Brad

ColdBox Platform Evangelist
Ortus Solutions, Corp

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

WOOT! SUCCESS!

It appears to be an issue with where I had dumped the coldbox files.

I moved it and created a mapping for it - restarted Railo and it took forever to load and I had my mapping dump in there and it was full of my CFCs!

Now that I’ve mastered ColdBox 3 it’s time to try ColdBox 4!

Thanks for all the help! (but don’t go anywhere I’m sure I’ll have more questions)

Jim