We have an application that we would like to migrate from using Application.cfm to Application.cfc. It's a management application that is set up on different web sites (all of which we host) with a common 'app directory' that is set up as a virtual directory off of each site, with some site specific variables (mostly just a couple of unique client IDs) located in an XML file off each site definition's root. In other words:
www.site1.com is client A's web app and has /configfolder/appvars.xml
www.site2.org is the same web app for client B and has /configfolder/appvars.xml
The actual application is a virtual directory, let's say:
This /mgmt/ folder contains all of the actual application code - the only thing that the root directories do is hold the handful of client-specific variables.
Historically, what we've done is to have an Application.cfm file in the /mgmt/ app folder do a <cfinclude template="../Application.cfm"> so that the same code executes for all the sites but pulls the unique site's credentials from that site's parent folder. But Application.cfm is a bit long in the tooth.
The problem is that the server doesn't seem to 'find' the Application.cfc in the parent folder and I'm not sure there's an equivalent 'cfinclude the file from one directory up' (unless you can cfinclude a CFC, which I don't think you can do?). 'extends' won't cut it either because we'd have to set up a mapping and know which specific Application.cfc we're extending, when the only thing we know is that the data we want is in /configfolder/.
The only solution I can think of is to use a single Application.cfc and to put it in /mgmt/, transfer our client-specific variables from the XML file we read in via cffile to a CF page that can be included in the Application.cfc (so we don't need to know the absolute directory name, as we do now), and then set things like Application.name dynamically, but I'm not sure if this is kosher. I'd prefer that each site had its own Application.cfc but (perhaps by dint of it being a virtual directory?) when you go to login at www.site1.com/mgmt/, it just doesn't seem to use www.site1.com/Application.cfc. I have other traditional sites where Application.cfc does 'filter' down to subdirectories, but there it's located in the root folder, you login in the root folder, and when you navigate to a subdirectory, CF seems to be aware that you're still in the same application.
I apologize if I haven't explained this well and am happy to clarify anything -- would appreciate any advice on how to best implement Application.cfc in a multiple-sites-on-one-codebase scenario.
Think I get you, and the recommended workaround is to create an ApplicationProxy.cfc (name is arbitary) in the root, with just the following:
So is literally just an empty proxy to your root App.cfc. From your subfolders, you can then do:
<cfcomponent extends="ApplicationProxy.cfc"> and it'll keep searching until it finds your uniquely-named proxy in the root.
If that's what you meant to do, of course...
This solution has the same problem that simply using Application.cfc does -- the subdirectory can't find the parent directory's ApplicationProxy.cfc without an explicit mapping (e.g. if I just 'extends="ApplicationProxy.cfc", it comes up not found, and I can't extend ../ApplicationProxy.cfc, and I can't put in an explicit mapping) - unless I am misunderstanding you. What I have just tried is:
each parent site has Application.cfc
each parent site now has ApplicationProxy.cfc which extends Application.cfc
the single subdirectory that contains the app has an Application.cfc that has tried but cannot extend either Application.cfc or ApplicationProxy.cfc.
The only thing I can think of is that it's not finding it because the subdirectory containing the app is a virtual directory set up from IIS, because I know in other instances CF will simply 'search up,' but in this case, it's got to be crawling the file system and not the web root.
Ah, if it's a virtual directory you'll have problems. The ApplicationProxy is "the way" it's done, but (as you've realised) CF looks at a file-level, and is not aware of any IIS mappings.
Any reason they can't just by physical directories? Even using something like a Windows Junction is they're physically located in a different place?
That's a good question. The only thing I can think off off the top of my head is that I wonder if CrashPlan is smart enough not to back up the whole directory every time it encounters it, but that's not a CF issue.
I guess I'd ask the reverse: Is there any reason why you would ever prefer an IIS virtual directory to a file system hard link?
I can see why your solution makes sense, but just to consider one other alternative: all of the Application.cfcs we have (one for each site) are exactly the same except for two things:
1) The application.name is slightly different for each one
2) The XML file they read that contains things like DB logins and passwords is located somewhere else for each one
I wonder if the answer here is not to have an Application.cfc for each site and muck around with the proxy, but to have a single one that just figures out these two things based on the hostname or something in the CGI scope.
I appreciate the help!
Whilst an interesting idea, I'm not sure the one App.cfc to rule them all will work. One app.cfc = one Application. Therefore there's no way of all your different "applications" of having separate settings, as CF will consider them just normal subdirectories.If each site doesn't actually need different App settings that'd work, but you're combining different peoples' data into one app, which is a bit risky.
If it were me, I'd look into the physical directory idea as I suspect it'll get you the result you desire the quickest.
Well, that's just it - the applications don't have different settings, except for a couple of custom app variables and the name of the application, but I guess the problem I'd run into would be that logging in to one app would log you in to all of them, assuming CF even tolerated having a dynamically-set application name.
I'll go your route. Thank you!
Not sure what the protocol for adding comments to old questions is, but I found this question while trying to find a solution to this problem. Couldn't find one anywhere, so here is the solution I have come up with:
Essentially I have multiple applications that use multiple modules, and the only differences in the module use will be determined based on the application that is pulling it in and the user session variables, etc:
I want them both to pull in: mymodule1 which sits outside their physical directory, so I have a virtual mapping that allows them to be used in each:
My physical directories are:
When I am inside mymodule1 it needs to use the Application file of myapp1 or myapp2 in order to continue to use the correct session variables etc. As noted above, the search for Application cfc is done by physical directory and will not allow you to reference it by relative or full paths either if you try to use 'extends'. So, basically it's impossible for the module to pull in a different Application.cfc unless you place physical copies under each app. I really don't like code duplication, so if I can't get the physical file, I need to dynamically change the Application.cfc. Here is the solution:
Create a file in each app called ApplicationSettings.xml. Add items for whatever settings are unique to the application.
So in the xml file I have applicationSettings containing applicationName, applicationID, etc.
Before I do anything in the Application.cfc I call the xml file using:
appXML = XmlParse("ApplicationSettings.xml");
appSettings = appXML.ApplicationSettings;
I then set my unique variables using the data from the xml file rather than hard coded in the Application.cfc:
THIS.name = appXML.ApplicationSettings.applicationName.xmlText;
Application.appID = appXML.ApplicationSettings.applicationAppID.xmlText;
In the module1 directory, the Application file just needs an extra bit to determine which ApplicationSettings.xml to pull:
appSettingsPath = "http://#CGI.HTTP_HOST#/";
appXML = XmlParse("#appSettingsPath#ApplicationSettings.xml");