How to access a scope if its name is being used as

2019-02-18 19:13发布

问题:

Dealing with some legacy code we came across a rather annoying situation. We are looping through a query with the <cfoutput query="x"> tag. That query has a column named 'url'. Within that loop we need to check if a key exists within the url scope. Since CF puts a priority on what's in the query over general page scopes I can't use a structKeyExists(url,"key") since as far as CF is concerned at this point, url is a string with the value from the current row of the query.

How can I break out of the query scope and inspect what's in my url?

As a temporary we are using isDefined("url.key"), but I would still like to know if there is a way to break out of the query scope.

Also can't really change the column, or even the column name in the query without a few hours of work tracking down an changing all references to it, so we're going to avoid that if at all possible.

EDIT: There seems to be some confusion as to how this code is set up, and why the simple solutions don't apply. It would be hard for me to give a thorough example but I will try to clarify the situation.

There are many pages that would count as 'pageA' for the following example. Enough that changing how things work would require a change in scope and investment in time that's just not going to happen in the time allotted.

PageA runs a query with one of the columns being named url, then starts an output loop via cfoutput, inside that loop PageB is included. One PageA may have different variables in the URL scope than another PageA, actually they are the same, but may be named differently(varID=x in one case vid=x in another). Inside of PageB I need to use the value from that url scope, so I want to run through the different possible names (if key 'varID' exists in url, use it, otherwise use 'vid').

This is why I want to "punch through" the query scope to get the url structure, and not the url column from the query. Any other method seems to require modifying the many PageAs.

So the question is not how to solve this problem specifically, as there are many ways to do it, I would just really like to avoid them as they all add a lot of time in implementation and testing. The question remains, is there a way to access the url scope as a variable if url exists as a query column and you are in the query scope.

回答1:

I thought it might work to create a function that returned the url scope, but upon testing it, even with a local-scoped query (which prevents the function using the query itself) the use of url inside the function is still corrupted:

<cffunction name="getUrlScope"><cfreturn Url /></cffunction>
...
<cfoutput query="x">
<cfif StructKeyExists( getUrlScope() , 'key' )>
    <!--- still fails :( --->


There is however an undocumented (meaning unsupported and liable to change) option. If you dump getPageContext() you will see a bunch of functions that do interesting things, including dealing with scopes.

You can use getPageContext().SymTab_findBuiltinScope('URL') to get at the URL scope.

You can also use getPageContext().getCfScopes() to get an array of scopes. I'm not sure if the order is guaranteed fixed but it seems to be [cgi,?,url,form,cookie,?] checking on both CF10 and cflive (CF9), so possibly is.

(In CF8 there was the method getBuiltinScopes, which returned a struct instead of an array - this no longer appears to exist, reinforcing the whole unsupported and changeable nature of these methods.)

On Railo those don't work, but there is getPageContext.UrlScope() and similarly-named functions for the other scopes.



回答2:

One solution would be to assign the url struct to a new variable outside of the cfoutput tag and then reference that variable instead of url. Example:

<cfset urlScope = url>

<cfoutput query="x">
  <cfset keyExists = structKeyExists(urlScope, "key")>
</cfoutput>


回答3:

My solution for this is always to alias the url column in the query as int

SELECT URL as qURL FROM myTable ...

IF you don't have access to the query (it's a stored precedure or used elswhere etc) you can always use query of a query to reselect it with your alias.

I don't care for the idea of creating a separate reference to URL outside the output - but that would also work. I just want to KNOW what is user input (i.e. comes from the URL or FORM) and what is generated internally (i.e. comes from a query).



回答4:

Couldn't you move structKeyExists(url,"key") outside of the cfoutput block, and store that into a variable? Or do a structAppend to copy the url struct into another struct named something else?



回答5:

Another approach is to replace your cfoutput block with a cfloop block.

<cfloop from="1' to = "#YourQuery.recordcount#" index = "idx">
<cfif StructKeyExits(url,"key")>
<cfoutput>
#url.key# is not the same as #YourQuery.url[idx]#
which can also be referenced like this #YourQuery["url"][idx]
etc