Hi Kurt/Peter,
Thanks for the reply! I have moved forward with this over the last 24 hours. In the server change over a number of different things have flushed up and I have isolated each one down except one now (for all the MachII sites).
1) The UNC paths would cause an issue in the framework when using expandRelativePath() and having the "\\" missing from the start of the path. Easy fix and MachII is happy.
2) The environment issue was handled with a change to the server config as suggested.
3) The event issue was caused by the other change I had introduced - moving from CF8 to CF10 (I could not even find CF8 hosted anymore so simply downloaded the latest version). After several hours of frustrating debugging in both my code and the MachII code I isolated why the error was being reported as "undefined event in arguments" when no code had been altered. Turns out I had a base listener/filter (which extended from the MachII listener/filter) which provided some utility functions other site listener/filters would extend from. This had a method "getDependancies()" which like:
<cffunction name="getDependancies" access="private" returntype="struct" output="false">
<!--- get references to the required model functionality --->
<cfset var local = {
i18nFacade = getEngine().getI18NFacade(),
sessionFacade = getEngine().getSessionFacade(),
logService = getEngine().getServiceFactory().getLogService(),
user = getEngine().getSessionFacade().getUser(),
role = getEngine().getSessionFacade().getUserRole()
} />
<cfreturn local />
</cffunction>
Then for example a listener extending the base and using this method like:
<cffunction name="getHomePage" access="public" returntype="void" output="false"
hint="Get home page content.">
<cfargument name="event" type="MachII.framework.Event" required="true" />
<cfscript>
// get required dependancies
var local = getDependancies();
// set event args
arguments.event.setArg("metaTitle", local.i18nFacade.getResource("publicHomeMetaTitle"));
arguments.event.setArg("metaDescription", local.i18nFacade.getResource("publicHomeMetaDescription"));
arguments.event.setArg("metaKeywords", local.i18nFacade.getResource("publicHomeMetaKeywords"));
arguments.event.setArg("titleContent", local.i18nFacade.getResource("publicHomeTitle"));
arguments.event.setArg("headerContent", local.i18nFacade.getResource("publicHomeHeader"));
</cfscript>
</cffunction>
This had always worked fine and suddenly I'm informed that arguments.event is undefined?! Makes no sense right. Well it turns out that in CF8 "local" is simply a common practice for "var scoped" function memory. In CF10 it is a CF scope - this I had even read about and knew had been added. Except I never suspected that the new "local" scope would now also by default have an "arguments" key which contained a reference to the function's arguments scope also. What this in turn resulted in was code that *had* been totally fine was broken as "var local = getDependancies();" would return all the other common variables needed just fine, but would store them back into the local scope and the empty "arguments" key/value in the struct from "getDependancies()" was overwriting the populated "arguments" scope from the main function! As such "event" was now gone - hence "undefined" errors".
I thought I would share that as it was quite unsuspected an may help someone out to know that. Below was the simple change which sorted that issue out:
<cffunction name="getDependancies" access="private" returntype="struct" output="false">
<!--- get references to the required model functionality --->
<cfset var dependancies = {
i18nFacade = getEngine().getI18NFacade(),
sessionFacade = getEngine().getSessionFacade(),
logService = getEngine().getServiceFactory().getLogService(),
user = getEngine().getSessionFacade().getUser(),
role = getEngine().getSessionFacade().getUserRole()
} />
<cfreturn dependancies />
</cffunction>
To just not use the "local" scope in the "getDependancies()" method, which avoids the "arguments" scope ever being returned (more elegant IMO than using "var local = { ... };" and then structDelete(local, "arguments"); as another possible solution).
This was also why, depending on the exact execution cycle per site, some would error in a filter and some in a listener - depending on whether it was a filter or listener run first (as they both have a similar "getDependancies()" helper).
4) Once all these were sorted the MachII sites were all happy - save for one particular issue. This I believe is another thing which has occurred because of going from CF8 to CF10. This relates to sessions and persistance of them; the code which had been working with CF8 was now not allowing sessions to persist from page to page.
The code the MachII sites are all currently using which relates to sessions is:
Applicaion.cfc
...
<cfset this.sessionManagement = true />
<cfset this.setClientCookies = false />
<cfset this.setDomainCookies = false />
...
<cffunction name="onSessionStart" access="public" returntype="void" output="false"
hint="Only runs when a session is created.">
<!--- Run super --->
<cfset super.onSessionStart() />
<!--- When the session starts, run the session facade's session start --->
<cfset getProperty("appManager").getEngine().getSessionFacade().onSessionStart() />
</cffunction>
<cffunction name="onRequestStart" access="public" returntype="void" output="true"
hint="Run at the start of a page request. (Output must be set to true).
In this case the super will run after the request start, rather than before it
as the request start contains certain processes such as security and request throttling
which should execute before anything else happens (including the mach-ii request cycle).">
<cfargument name="targetPage" type="string" required="true" />
<!--- When the request starts, run the request facade's request start --->
<cfset getProperty("appManager").getEngine().getRequestFacade().onRequestStart(arguments.targetPage) />
<!--- Run super --->
<cfset super.onRequestStart(targetPage = arguments.targetPage) />
</cffunction>
...
Then from the RequestFacade:
...
<cffunction name="onRequestStart" access="public" output="false" returntype="void"
hint="Should be fired when the request starts from the Application bootstrapper.">
<cfargument name="targetPage" type="string" required="true" />
<!--- run specific actions --->
<cfset requestsManager() />
<cfset manageIllegalRequests(arguments.targetPage) />
<cfset ensureSessionCookiesExistIfNeeded() />
<cfset manageUrlRedirect() />
<cfreturn />
</cffunction>
...
<cffunction name="ensureSessionCookiesExistIfNeeded" access="private" returntype="void" output="false"
hint="I ensure that whenever a page is visited, if required, cookies will be set to memory
if they do not exist. This is to make sure that the session will persist multiple page requests
without writing cookies to the client machine (which has some security implications). This is
not required if J2EE session management is enabled as that form of session management works differently.">
<!--- Set per session cookies if not using J2EE session management --->
<cflock type="exclusive" name="#getUniqueLockId('sessionCookies')#" timeout="10">
<cfif structKeyExists(session, "cfid") and (not structKeyExists(cookie, "cfid") or not structKeyExists(cookie, "cftoken"))>
<cfcookie name="cfid" value="#session.cfid#" />
<cfcookie name="cftoken" value="#session.cftoken#" />
</cfif>
</cflock>
</cffunction>
...
Notice how the when onRequestStart() is called in the Application.cfc file and in turn calls for the facade to handle this, a private method ensureSessionCookiesExistIfNeeded() is then run. Also notice how "this.setClientCookies" is false in the Application.cfc
This is the code which now no longer works on CF10, although I am not certain why as the code which handles the session cookie differences - ensureSessionCookiesExistIfNeeded() was not devised by us, but rather found as a "best practice" someone online. I was *certain* I had long ago found this someone on the MachII wiki as a suggestion and had followed the recommendation, however I can find no record of it on there, or in google. I figured posting it here, if it had come from someone who contributed in the MachII team maybe some light can be shed on it - it seemed self explanatory to me up till this point; especially with the comments, yet now it is not working with CF10 I looked into why it was there further.
It seems that with this code running every page request gets new CFID/CFTOKENs on each request and as such the session is not passed page to page. If I change "this.setClientCookies" to true in the Application.cfc sessions now *seem* at a quick glance to work ok. Any thoughts on this point? Is the code contained in ensureSessionCookiesExistIfNeeded() now redundant in CF10? Or was it possibly always unneeded? I was just hesitant to make changes to what worked in CF8, without exploring possible consequences as the sites are still all live in production environments using CF8 and will continue to remain this way for the foreseeable future. Thus any code changes to ensure workability for the CF10 setup could possibly throw out working live sites if uploaded.
Hope all that makes sense!
Best,
Shaun
On Friday, June 1, 2012 1:57:17 PM UTC+10, Shaun wrote: