将CFScript语法的会话转换为ColdFusion标签语法

5

应用程序: 一个JavaScript函数监听表单元素(输入框和选择框)的变化,并将数据提交给CFC方法,该方法将它们分配给Session结构。该结构返回,使表单数据在会话的整个生命周期内可用。该应用程序是从Raymond Camden的使用服务器或会话存储持久保存表单值代码进行调整的。

问题:原始的CFC代码是用CFScript编写的。因为我们使用的是ColdFusion 8,在调用该方法时出现错误。因此,我将该方法转换为ColdFusion标记语法并停止了收到该错误。在Chrome的开发工具中,我可以看到每次输入表单元素时数据通过JSON对象传递到CFC。所以我知道JavaScript函数正在工作。尽管我没有收到任何返回错误,但有一些行为让我相信我的翻译是不正确的。例如,会话结构的转储仅显示最后一个输入元素,而不是所有输入元素(这是Ray演示中的情况)。

以下是原始的CFScript版本和我的标记翻译。除了对我的翻译错误的任何评论外,我想了解这行<cfset s.name = [s[name]] />,特别是[s[name]]的构造,因为我无法表达其中发生的事情。谢谢。

脚本语法:

component {
    remote void function preserveSession(string awardData) {
        if(!isJSON(arguments.awardData)) return;
        arguments.awardData = deserializeJSON(arguments.awardData);

        //convert the array into a name based struct
        var s = {};
        for(var i=1; i<=arrayLen(arguments.awardData); i++) {
            var name = arguments.awardData[i].name;
            if(!structKeyExists(s, name)) {
                s[name] = arguments.awardData[i].value;    
            } else {
                //convert into an array
                if(!isArray(s[name])) {
                    s[name] = [s[name]];
                }
                arrayAppend(s[name], arguments.awardData[i].value);
            }    
        }
        session.awardFormData = s;    
    }
}

标签语法:

<cfcomponent>
    <cffunction name="preserveSession" access="remote" returntype="void" output="no">

        <cfargument name="awardData" type="string" />

        <cfset var s = {} />

        <cfif NOT isJSON(arguments.awardData)>
            <cfreturn />
        </cfif>

        <cfset arguments.awardData = #deserializeJSON(arguments.awardData)# />

        <cfloop index="i" from="1" to="#arrayLen(arguments.awardData)#">
            <cfset name = #arguments.awardData[i].name# />

            <cfif NOT structKeyExists(s, name)>
                <cfset s.name = #arguments.awardData[i].value# />   
            <cfelse>
                <cfif NOT isArray(s.name) >
                    <cfset s.name = [s[name]] />
                </cfif>
                <cfset arrayAppend(s.name, arguments.awardData[i].value) />
            </cfif>
        </cfloop>

        <cfset session.awardFormData = s />

        <cfreturn />
    </cffunction>
</cfcomponent>
2个回答

5
首先,你并不需要将所有的内容都翻译过来。CF8不支持使用cfscript中的组件/函数,但除此之外,你可以按原样使用它:
<cfcomponent>
  <cffunction name="preserveSession" access="remote" returntype="void" output="no">
    <cfargument name="awardData" type="string" />
      <cfscript>
        var s = {};
        var name = '';
        var i = 0;
        if(!isJSON(arguments.awardData)) return false;
        arguments.awardData = deserializeJSON(arguments.awardData);
        for(i=1; i<=arrayLen(arguments.awardData); i++) {
          name = arguments.awardData[i].name;
          if(!structKeyExists(s, name)) {
            s[name] = arguments.awardData[i].value;
          } else {
            if(!isArray(s[name])) {
              s[name] = [s[name]];
            }
            arrayAppend(s[name], arguments.awardData[i].value);
          }
        }
        session.awardFormData = s;
        return true;
    </cfscript>
  </cffunction>
</cfcomponent>

尝试简单地重新包装内部,而不是重写代码,看看是否能够进一步进行。

通常来说,解释符号如下: s[name] 通过存储在 name 中的键来寻址 s 的结构;这有时被称为数组符号。 它相当于已知名称时的点符号 s.theValueStoredInName。 要通过变量名动态地寻址结构,最容易的方法是通过数组符号实现。

嵌套集合也是同样的道理: s[name] = [s[name]] 这行代码将一个键的值设置为存储在 name 中的内容,并将其值设置为 s[name] 的命名键中存储的内容。通过将该设置包装在 [] 中,它就成为了一种数组类型。

这将有助于澄清此处发生的具体情况:

如果该名称键名尚未被分配为结构体,则将其存储为结构体(简单的名称键值)。 如果已经存在,则名称键值中的任何内容都会转换为具有该名称键名的数组。 然后,如果是第二个项目的连续传递(它将是,if!仅检查此数组转换是否已经至少发生一次),则第二个项目将附加到具有相同名称键的数组中。

个人而言,我只会直接设置为数组以简化操作。这样,您始终知道如何访问存储的值。


如果我没记错的话,在CF8中你需要做的一件事是将var移到脚本块的顶部。但除此之外,cfscript应该支持所有现代对象符号。CF9允许您在任何地方使用var,因为hoisting显然现在发生在CF9+中。我会编辑以反映这一点。 - williambq
1
@ williambq - 或许最好将最后一部分作为编辑添加,这样更加显眼。然后删除该评论。 - Leigh
1
我不得不改变一些细节,例如将循环的“var i = 1;”子句移到脚本顶部,并删除关闭的“return true;”子句(因为我已经声明了“returntype = void”)。现在,在我的会话转储中获取所有表单元素。谢谢! - rickp
1
感谢你们两位对 s[name] = [s[name]] 的解释,现在更加清晰了。 - rickp

2

<cfset s.name = ... />

您需要动态地访问键名。上面的代码每次都使用相同的静态键(即name),因此每次循环都会覆盖先前的值。这就是为什么最终只有一个值 - 最后一个值。

 <!--- this creates a dynamic key named "apple" (correct) --->
 <cfset name = "apple" />
 <cfset s[name] = "..." />

 <!--- this creates a key literally named "name" (wrong) --->
 <cfset name = "apple" />
 <cfset s.name = "..." />

为了解决这个问题,在你使用s.name的任何地方,都要用s[name]代替。此外,不要忘记将所有函数局部变量的作用域设置为var
更新: williambq的回答也提出了一个很好的观点。你不必全部转换成CFML,更简单的方法是在大部分代码周围加上cfscript标签。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接