views:

290

answers:

5

Problem: When requesting the WSDL for a CFC, I get the following error: Variable FORM is undefined. It happens in this line of code, in the OnRequestStart method in application.cfc

<cfif structKeyExists(form,'resetappvars')>
  <cfset OnApplicationStart() />
</cfif>

If I request a specific method, it works fine. I have considered using cfparam to create a default form struct if none exists, but that seems like an ugly hack and I worry it will actually create the form struct in the variables or this scope of the CFC. Maybe this is a legitimate bug as well?

Note: This only happens when I request the WSDL, if I invoke a method directly - the code executes as expected without problems.

Update: Application.cfc code sample - just add any CFC to your app and request it with ?wsdl to see the issue. This has been tested (and failed) on CF7 and CF8.

<cfcomponent output="false">

  <cffunction name="OnApplicationStart" access="public" returntype="boolean" output="false" hint="Fires when the application is first created.">
    <cfset application.dsn = "my_dsn" />
    <cfreturn true />
  </cffunction>

  <cffunction name="OnRequestStart" access="public" returntype="boolean" output="false" hint="Fires at first part of page processing.">
    <cfargument name="TargetPage" type="string" required="true" />
    <cfif structKeyExists(form,'resetappvars')>
      <cfset OnApplicationStart() />
    </cfif>
    <cfreturn true />
  </cffunction>

</cfcomponent>
+6  A: 

Maybe try adding a:

 <cfif IsDefined("form")>...</cfif>

around the above code?

AlexJReid
+1. This is the one time I would use IsDefined().
Al Everett
IsDefined("form.resetappvars") is what the poster wants, I think.
Henry
+3  A: 

You could also cfparam the variable you're looking for then just change your logic a little (assuming resetAppVars is a boolean:

<cfparam name="form.resetAppVars" default="false" />
...
<cfif form.resetAppVars>
  <cfset OnApplicationStart() />
</cfif>

Edit: I'm not sure if the above code could be considered a hack, but it seems pretty standard CF, to me.

Hooray Im Helping
+2  A: 

I've heard it's just a matter of opinion, but it seems to me that it is improper to reference your form scope within a CFC, as there is no guarantee that the form scope will be available when your cfc is invoked and when your method is called. It is better to ensure that any data that needs to be available to the method is provided explicitly to your object. This can be done either by including an argument:

<cfargument name="resetAppVars" type="boolean" required="false" default="false" />

Then you check arguments.resetAppVars, and it is always defined, but defaulted to false.

Or by creating an attribute on your object and creating an explicit set method:

(at the top of your cfc)

<cfset this.resetAppVars = false />


<cffunction name="setResetAppVars" access="public" returnType="void" output="false">
   <cfargument name="flagValue" type="boolean" required="true" />

   <cfset this.resetAppVars = arguments.flagValue />
</cffunction>

In which case you will check against this.resetAppVars. You can also scope this locally using <cfset var resetAppVars = false /> as the declaration, which makes it a private attribute of your object, and is probably proper, so code that invokes the object cannot improperly overwrite this variable with a non-boolean type. In that case, you would simply refer directly to resetAppvars in your test, instead of using this scope.

I would generally agree that it is not appropriate to reference the form scope inside a CFC. However, in the application.cfc onRequestStart method it seems like a legitimate place to consider referencing the form scope. Also of note, this error ONLY happens when I try to retrieve the WSDL for a cfc with remote methods.
Goyuix
+1  A: 

This post of Ben Nadel gives detailed list of scopes available for different types of requests.

By reading it you can easily find out that form scope is not available in given context, but url is.

Sergii
Thanks for the post - but how do I know I am getting a WSDL request? Parse the URL scope?
Goyuix
Yeah... Seems that StructKeyExists(url, "wsdl") can be the simplest way. Personally I don't have such problems with identification because using separate CFC's for services, they simply extend needed core components. It gives clearer project structure, say /api/api.cfc?wsdl is better than /components/core/model/webServiceLayerManager.cfc?wsdl in some ways.
Sergii
+1  A: 

You could also do this:

<cfif NOT isSoapRequest()>...

and stick your remaining logic inside that chunk.

marc esher
There are issues using isSoapRequest in the onRequestStart method: http://www.petefreitag.com/item/733.cfm
Goyuix
GAH. Thanks Goyuix
marc esher