Coldfusion "Routines cannot be declared more than once"
Asked Answered
M

3

6

We have the following code in our Application.cfc:

<cffunction name="onError" returnType="void" output="false">
    <cfargument name="exception" required="true">
    <cfargument name="eventname" type="string" required="true">
    <cfset cfcatch = exception>
    <cfinclude template="standalone/errors/error.cfm">
</cffunction>

Within the error.cfm page we have this code (I didn't write it):

<cfscript>
        function GetCurrentURL() {
            var theURL = "http";
            if (cgi.https EQ "on" ) theURL = "#TheURL#s";
            theURL = theURL & "://#cgi.server_name#";
            if(cgi.server_port neq 80) theURL = theURL & ":#cgi.server_port#";
            theURL = theURL & "#cgi.path_info#";
            if(len(cgi.query_string)) theURL = theURL & "?#cgi.query_string#";
            return theURL;  
        }
</cfscript>

This is all part of a script that puts together bunches of details about the error and records it to the database.

When an error occurs, we receive the message "The routine GetCurrentURL has been declared twice in different templates." However, I have searched the entire codebase in several different ways and found "GetCurrentURL" used only twice, both times in error.cfm. The first time is the declaration, and the second is actual use. So I'm not sure why CF is saying "in different templates".

My next thought was that the problem is a recursive call, and that error.cfm is erroring and calling itself, so I attempted these two changes, either of which should have resolved the issue and unmasked the real error:

<cfif StructKeyExists(variables,"GetCurrentURL") IS "NO">
    <cfscript>
            function GetCurrentURL() {
                var theURL = "http";
                if (cgi.https EQ "on" ) theURL = "#TheURL#s";
                theURL = theURL & "://#cgi.server_name#";
                if(cgi.server_port neq 80) theURL = theURL & ":#cgi.server_port#";
                theURL = theURL & "#cgi.path_info#";
                if(len(cgi.query_string)) theURL = theURL & "?#cgi.query_string#";
                return theURL;  
            }
    </cfscript>
</cfif>

And:

<cfscript>
    if (!StructKeyExists(variables,"GetCurrentURL")) {
            function GetCurrentURL() {
                var theURL = "http";
                if (cgi.https EQ "on" ) theURL = "#TheURL#s";
                theURL = theURL & "://#cgi.server_name#";
                if(cgi.server_port neq 80) theURL = theURL & ":#cgi.server_port#";
                theURL = theURL & "#cgi.path_info#";
                if(len(cgi.query_string)) theURL = theURL & "?#cgi.query_string#";
                return theURL;  
            }
    }
</cfscript>

Neither worked. I also tried adding this to the page just before the function call:

<cfoutput>"#StructKeyExists(variables,"GetCurrentURL")#"</cfoutput>

It caused the word "YES" to be printed on screen. This indicates that the above should work, as clearly the contents of the if statement will evaluate to "YES", and thus the if statement will evaluate to false, and thus the function will not be declared, and thus I will retain my sanity. But for some reason this problem persists.

Any thoughts on what might be occuring or how to troubleshoot next? I'm stuck at this point.

Maryettamaryjane answered 2/4, 2012 at 18:6 Comment(2)
Are you certain that error.cfm is not being included elswhere? Is it only included in onError()?Cornie
Yes, it was only in onError().Maryettamaryjane
A
7

ColdFusion still sees the function declaration when it compiles it into bytecode. You can use a cfinclude to include the function declaration:

<cfif StructKeyExists(variables,"GetCurrentURL") IS "NO">
<cfinclude template="udf.cfm" />
</cfif>

Then in the udf.cfm place your function declaration. That should work as you want and prevent CF from throwing the error.

Adnate answered 2/4, 2012 at 19:9 Comment(2)
oh yes!! why didn't I see that? It's not enough to parse out the declaration. I bet you are right Sean... nice!Cornie
I ended up resolving this by moving the declarations to Application.cfc, but that involves some negative repurcussions. Initial testing locally indicates that your solution seems to work much better, so I'll work on getting that QAed and into prod. Thank you so much! :)Maryettamaryjane
G
0

Another solution is to delete the function from scope before the definition. For example...

<cfset StructDelete(variables,'myFunction')>
<cffunction name="myFunction">...</cffunction>
Ginelle answered 19/1, 2017 at 13:2 Comment(2)
Welcome to SO Marius, can you describe where, how and why deleting the OP's function would solve the problem?Ruy
As mentioned in @SeanCoyne's answer, the problem is that the routine declaration error doesn't happen at runtime -- it happens at compile time. That means deleting the function from the variables scope doesn't do anything to fix the problem. While @MariusMaxeiner's approach would work to remove an unwanted function, you couldn't use it to prevent the compile error.Iolite
B
0

ColdFusion also lets you instantiate the same cfc that has the function(s) more than once. In wwwroot/x.cfc

<cfcomponent>
    <cffunction name="fMy">
        <cfreturn "some data">
    </cffunction>
</cfcomponent>

In wwwroot/y.cfm

<cfset oFcns = createObject("component","x")>
<cfset oFcns = createObject("component","x")>
<cfset z = oFcns.fMy()>

Outputs:

some data

The createObject could have been run multiple times by a loop. Point is the second instantiation doesn't bomb.

Beauvoir answered 19/5, 2022 at 19:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.