I am having an issue with functions inside my cfc. They are acting funny when I try to introduce conditional logic to assign a query to the grid. Basically in the URL I will have ?GRIDID=x and it will tell the cfc which function to run, but when I nest the closing cffunction tag inside of the if statements, it throws an error. Here is the code.
<cffunction name="grabInfo" access="remote" output="false" returntype="any">
<cfargument name="page" required="yes">
<cfargument name="pageSize" required="yes">
<cfargument name="gridsortcolumn" required="yes">
<cfargument name="gridsortdirection" required="yes">
<cfargument name="filtercolumn" required="no" default="">
<cfargument name="filter" required="no" default="">
<cfargument name="gridID" required="yes">
<cfif arguments.gridsortcolumn eq "">
<cfset arguments.gridsortcolumn = "PatientsName" />
<cfset arguments.gridsortdirection = "asc" />
</cfif>
<cfif ARGUMENTS.gridID EQ "1">
<cfquery name="x" datasource="#dsn#">
<!--- .... --->
</cfquery>
<cfreturn QueryConvertForGrid(qGrabInfo, Arguments.page, Arguments.pagesize)>
</cffunction>
</cfif>
<cfif ARGUMENTS.gridID EQ "2">
<cfquery name="x" datasource="#dsn#">
<!--- .... --->
</cfquery>
<cfreturn QueryConvertForGrid(qGrabInfo, Arguments.page, Arguments.pagesize)>
</cffunction>
</cfif>
This will give me the error Context validation error for the cfif tag. but as you can see, all the cfif statements are closed. If I take the first argument and place it with the closing cffunction tag outside of the if statement it will work, like so
<cfif ARGUMENTS.gridID EQ "1">
<cfquery name="x" datasource="#dsn#">
<!--- .... --->
</cfquery>
<cfreturn QueryConvertForGrid(qGrabInfo, Arguments.page, Arguments.pagesize)>
</cfif>
<cfif ARGUMENTS.gridID EQ "2">
<cfquery name="x" datasource="#dsn#">
<!--- .... --->
</cfquery>
<cfreturn QueryConvertForGrid(qGrabInfo, Arguments.page, Arguments.pagesize)>
</cfif>
</cffunction>
The reason I need to do this is because I need several other functions run when GridID EQ 2 as well, so I need to close the function and open another as follows
<cfif ARGUMENTS.gridID EQ "2">
<cfquery name="x" datasource="#dsn#">
<!--- .... --->
</cfquery>
<cfreturn QueryConvertForGrid(qGrabInfo, Arguments.page, Arguments.pagesize)>
</cffunction>
<cffunction name="otherFunction">
<!--- .... --->
</cffunction>
</cfif>
Add additional functions in your component.
<cffunction name="grabInfo" access="remote" output="false" returntype="any">
<cfargument name="page" required="yes">
<cfargument name="pageSize" required="yes">
<cfargument name="gridsortcolumn" required="yes">
<cfargument name="gridsortdirection" required="yes">
<cfargument name="filtercolumn" required="no" default="">
<cfargument name="filter" required="no" default="">
<cfargument name="gridID" required="yes">
<cfif arguments.gridsortcolumn eq "">
<cfset arguments.gridsortcolumn = "PatientsName" />
<cfset arguments.gridsortdirection = "asc" />
</cfif>
<cfif ARGUMENTS.gridID EQ "1">
<cfquery name="x" datasource="#dsn#">
<!--- .... --->
</cfquery>
<cfreturn QueryConvertForGrid(qGrabInfo, Arguments.page, Arguments.pagesize)>
</cfif>
<cfif ARGUMENTS.gridID EQ "2">
<cfquery name="x" datasource="#dsn#">
<!--- .... --->
</cfquery>
<!--- call your other functions --->
<cfset otherFunction(arg1, arg2)>
<cfset anotherFunction(arg1, arg2)>
<cfreturn QueryConvertForGrid(qGrabInfo, Arguments.page, Arguments.pagesize)>
</cfif>
</cffunction>
New functions in same component
<cffunction name="otherFunction" access="remote" output="false" returntype="any">
<cfargument name="arg1">
<cfargument name="arg2">
<!--- do things --->
</cffunction>
<cffunction name="anotherFunction" access="remote" output="false" returntype="any">
<cfargument name="arg1">
<cfargument name="arg2">
<!--- do things --->
</cffunction>
The chief problem you have is a lack of understanding how code compiles. Your code is not executed at runtime, which is when stuff like conditions are evaluated, it needs to be compiled first. And to be compiled, the code needs to be syntactically valid. Which yours is not.
Functions are discrete units of processing, and need to be self contained. What you're trying to do makes absolutely no sense at all from a code perspective. It also demonstrates a lack of understanding of how functions work. They do not execute when they are declared (ie: the <cffunction>/</cffunction> block, they run when they're called.
Matt has got you on the right track, but to reiterate, you don't do this:
<cffunction name="mainFunction">
<!--- some stuff --->
<cfif someCondition>
<!--- some other stuff --->
<!--- finish off --->
</cffunction>
<cfelse>
<!--- different stuff --->
<cffunction name="theOtherFunction">
<!--- different function --->
</cffunction>
</cffunction><!--- this is for the outer function --->
</cfif>
That's... well it's not right.
What you want is this:
<cffunction name="mainFunction">
<!--- some stuff --->
<cfif someCondition>
<!--- some other stuff --->
<!--- different function --->
<cfset something = theOtherFunction()>
</cfif>
<!--- finish off --->
</cffunction>
<cffunction nname="theOtherFuction">
<!--- different stuff --->
</cffunction>
Note how each coding structure is self-contained.
I think you could benefit from reading through the CFML docs, and also some basic programming tutorials (any language) before you go too much further into it.
Also note: try to avoid using tag-based code for business logic: tags are really better suited for views, and it's a throw-back to earlier, ill-informed times that one can even define a function with tags. As a rule of thumb: tags for views; script for logic.
It's also important to read and understand the comments below. Even if your code was syntactically correct and could compile, it still wouldn't do what you want it to do because functions are compiled separately to the rest of the code, so your conditionality still wouldn't work.
I have a page that accepts user images, renames them and returns the new filename for further processing
<cffunction name="uploadfile" access="public" returntype="string">
<!--- TODO files should not be uploaded to web accesible directories - use #GetTempDirectory()# to use the temporary directory--->
<cfargument name="forma" type="struct" required="yes">
<cfargument name="db" type="string" required="yes">
<cfargument name="user_id" type="string" required="yes">
<cfparam name="new_filename" default="">
<cfset mediapath = expandpath('/ugc_images/images')>
<cfset thumbpath = expandpath('/ugc_images/images/thumbs')>
<cfif structKeyExists(forma,"fileUpload") and len(forma.fileUpload)>
<cffile action="upload" filefield="FileUpload" destination="#MediaPath#" nameconflict="makeunique" accept="image/jpeg,image/gif,image/png">
<!---<cfset serverfile.extension = right(file.serverFile, 3)> --->
<cfset new_filename= "#user_id#_#DateFormat(Now(), "mm-dd-yyyy")#.jpg">
<cffile action="rename" source="#MediaPath#/#file.serverFile#" destination="#MediaPath#/#new_filename#"/>
<cfimage source="#MediaPath#/#new_filename#" name="myImage">
<cfset ImageSetAntialiasing(myImage,"on")>
<cfif myImage.width gt 1000 or myImage.height gt 1000><cfset ImageScaleToFit(myImage,1000,1000)> </cfif>
<cfset ImageWrite(myImage,"#MediaPath#/#new_filename#")>
<cfif myImage.width gt 300 or myImage.height gt 300><cfset ImageScaleToFit(myImage,300,300)></cfif>
<cfset ImageWrite(myImage,"#thumbpath#/#new_filename#")>
</cfif>
<cfreturn "#new_filename#">
</cffunction><!---EO uploadfile--->
after calling that function (which does indeed upload and save the file and its thumbnail as intended, all coldfusion fucntions seem to hang. The webserver still serves plain text, but any coldfusion tag no matter how simple, timesout
for example, after the above I have this:
This text is served to the browser
<hr>
and this
<hr>
<cfoutput >but this times out</cfoutput>
and it never gets here
<hr>
It all works well on my local machine for development but on the remote (production) server it crashes. It's on a shared hosting so I have limited access to settings
any idea what's going on?
I know this has been asked, but I cannot seem to find the solution that works.
I have a CFM page that uses the following to pass data to a CFC
<cfinvoke
component="common.cfcs.geotrails"
method="UpdateGeoTrail">
<cfinvokeargument name="title" value="#form.title#"/>
<cfinvokeargument name="Description_short" value="#form.Description_short#"/>
<cfinvokeargument name="Description" value="#form.description#"/>
<cfinvokeargument name="GTID" value="#form.gtid#"/>
<cfinvokeargument name="CatID" value="#form.catid#"/>
<cfif structKeyExists(form,"fileUpload") and len(form.fileUpload)>
<cfinvokeargument name="fileUpload" value="#form.fileUpload#"/>
</cfif>
</cfinvoke>
In the CFC that receives the data, I followed the direction at the Adobe Cookbook
<cffunction name="UpdateGeoTrail" access="public" returntype="void">
<cfargument name="title" type="string" required="yes">
<cfargument name="Description_short" type="string" required="yes">
<cfargument name="Description" type="string" required="yes">
<cfargument name="GTID" type="numeric" required="yes">
<cfargument name="CatID" type="numeric" required="yes">
<cfargument name="fileUpload" type="string" required="no">
<!--- IF THE IMAGE HAS BEEN UPLOADED --->
<!--- set the full path to the images folder --->
<cfif isdefined("arguments.fileUpload") AND len(arguments.fileUpload)>
<cfset tempmediapath = "#expandPath('/')#media/gtimages/temp/">
<cfset mediapath = "#expandPath('/')#media/gtimages/">
<cfset var cffile = "">
<cffile action="upload"
filefield="#ARGUMENTS.fileUpload#"
destination="#TempMediaPath#"
nameconflict="makeunique">
...
But I still get the dreaded error message...
"The form field /data/disk01/opt/coldfusion9/runtime/servers/coldfusion/SERVER-INF/temp/wwwroot-tmp/neotmp5003883285207133802.tmp did not contain a file."
If I follow the directions at StackExchange
( CFFILE - Uploading a file using a component )
<cffile action="upload"
filefield="fileUpload"
destination="#TempMediaPath#"
nameconflict="makeunique">
It passes without error, but a <CFDUMP> shows: [empty string].
What am I missing.
Thanks.
Phil
I know it isn't part of your cfc but did you make sure that the form has the enctype set?
<cfform action="/upload.cfm" enctype="multipart/form-data">
By removing the cffile scope, I was able to get it to work.
I have a text field that I want to autosuggest values based on a query. I have a main file along with a separate file (getdata.cfc) that holds my query.
Here is the text field portion of my main file:
<cfinput name="search_query" autosuggest="url:getdata.cfc?suggestvalue={cfautosuggestvalue}" maxResultsDisplay="10" showAutoSuggestLoadingIcon="true" size="10" />
Here is the code in getdata.cfc:
<cfcomponent>
<cffunction name="get_data" access="remote" output="false">
<cfargument name="suggestvalue" required="true">
<cfquery name="get_data" datasource="#application.DSN#">
SELECT DISTINCT myItem
FROM myTable
WHERE myItem LIKE <cfqueryparam value="#suggestvalue#%"
cfsqltype="cf_sql_varchar">
ORDER BY myItem
</cfquery>
<cfif get_data.recordCount eq 1>
<cfreturn ",#get_data.myItem#">
<cfelse>
<cfreturn ValueList(get_data.myItem)>
</cfif>
</cffunction>
</cfcomponent>
The text field shows up fine, but when I type a word no autosuggest values show up. Nothing happens. The text is just displayed as I type it.
Any suggestions? Thank you!
I switched away to using jquery plugins from a lot of CF stuff, but here is an example I have that works in some old production code
<cfinput type="text" name="email" id="email" autosuggest="cfc:cfc.users.lookupEmail({cfautosuggestvalue})" maxresultsdisplayed = "25">
<cffunction name="lookupEmail" access="remote" returntype="array">
<cfargument name="search" type="any" required="false" default="">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(1)>
<!--- Do search --->
<cfquery name="data" datasource="datasource" maxrows="25" cachedwithin="#CreateTimeSpan(0,0,30,0)#">
SELECT distinct email
FROM users
WHERE email LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.search#%">
ORDER BY email
</cfquery>
<!--- Build result array --->
<cfloop query="data">
<cfset ArrayAppend(result, email)>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
maybe this helps
also make sure you have your cfform tags around your form, and make sure that your /cfide folder is mapped to your website.
looking at your code and comparing it... it may be the way your calling the cfc (filename)
try: autosuggest="cfc:getdata.get_data.({cfautosuggestvalue})"
Getting something really strange that I just can't work out.
I have 3 methods within a CFC (guest.cfc):
- save
- create
- update
I pass an argumentCollection to the save method.
saveGuest = objGuest.save(argumentcollection=guestStruct)
If it includes an Identier, it passes the argumentCollecion to the update method, if it doesn't then it passes the collection to the create method.
This is working fine when called from one place int the app, but when I created a new call to the save method, the create method works fine, but if an ID is passed in the update method is called I receive an error that the UPDATE variable does not exists.
But, if I change the way I call it by creating an object of the cfc, it works..
so..
saveObject = update(argumentCollection = arguments;
Does not work. Receive an error that the update variable does not exist.
saveObject = createObject("component",'guest').update(argumentCollection = arguments);
DOES work.
note that both these calls are occuring within the guest.cfc itself.
This issue doesn't occur when I pass a form struct to the save method, but does occur when I pass it a standard struct (constructed from an XML import).
Very strange.
Anyone have any ideas on what might causing this?
EDIT 24 April - Added Code for guest.cfc
<cffunction name="save" output="false" access="remote" hint="save guest">
<cfargument name="title" type="any" required="false" default="" />
<cfargument name="first_name" type="any" required="false" default="" />
<cfargument name="surname" type="any" required="false" default="" />
<cfargument name="dob" type="any" required="false" default="NULL" />
<cfargument name="partner_first_name" type="any" required="false" default="" />
<cfargument name="partner_surname" type="any" required="false" default="" />
<cfargument name="partner_dob" type="any" required="false" default="NULL" />
<cfargument name="address_1" type="any" required="false" default="" />
<cfargument name="address_2" type="any" required="false" default="" />
<cfargument name="address_3" type="any" required="false" default="" />
<cfargument name="city" type="any" required="false" default="" />
<cfargument name="state" type="any" required="false" default="" />
<cfargument name="postcode" type="any" required="false" default="" />
<cfargument name="country" type="any" required="false" default="" />
<cfargument name="phone_bh" type="any" required="false" default="" />
<cfargument name="phone_ah" type="any" required="false" default="" />
<cfargument name="phone_mob" type="any" required="false" default="" />
<cfargument name="fax" type="any" required="false" default="" />
<cfargument name="email" type="any" required="false" default="" />
<cfargument name="business" type="any" required="false" default="" />
<cfargument name="notes" type="any" required="false" default="" />
<cfargument name="referer" type="any" required="false" default="" />
<cfargument name="prospect" type="any" required="false" default="" />
<cfargument name="occasion" type="any" required="false" default="" />
<cfargument name="occasion_date" type="any" required="false" default="NULL" />
<!---pass to Create or Save--->
<cfif NOT isdefined("arguments.guest_id") OR arguments.guest_id EQ "0">
<cfset saveObject = create(argumentCollection = arguments) />
<cfelse>
<cfset saveObject = update(argumentCollection = arguments) />
</cfif>
<cfreturn saveObject>
</cffunction>
<!---CREATE--->
<cffunction name="create" output="false" access="private" returntype="struct" hint="Create a New Item">
<cfargument name="provider_id" type="any" required="false" default="#session.providerID#" />
<cfargument name="ext_ref_id" type="any" required="false" default="NULL" />
<cfargument name="tstamp" type="any" required="false" default="#session.tStamp#" />
<cfif isValid('date',arguments.occasion_date)>
<cfset iOccasionDate = createODBCDateTime(arguments.occasion_date)>
<cfelse>
<cfset iOccasionDate = "NULL">
</cfif>
<cfset returnStruct = StructNew()>
<cfquery name="insertGuest" datasource="#Application.ds#">
INSERT INTO guest (provider_id, ext_ref_id, title, first_name, surname, full_name, partner_first_name, partner_surname, partner_full_name, address_1, address_2, address_3, city, state, postcode, country, phone_bh, phone_ah, phone_mob, fax, email, company, notes, referer, prospect, occasion, occasion_date, tstamp)
VALUES (#provider_id#, #ext_ref_id#, '#arguments.title#', '#arguments.first_name#', '#arguments.surname#', '#arguments.first_name# #arguments.surname#', '#arguments.partner_first_name#', '#arguments.partner_surname#', '#arguments.partner_first_name# #arguments.partner_surname#', '#arguments.address_1#', '#arguments.address_2#', '#arguments.address_3#', '#arguments.city#', '#arguments.state#', '#arguments.postcode#', '#arguments.country#', '#arguments.phone_bh#', '#arguments.phone_ah#', '#arguments.phone_mob#', '#arguments.fax#', '#arguments.email#', '#arguments.company#', '#arguments.notes#', '#arguments.referer#', '#arguments.prospect#', '#arguments.occasion#', #iOccasionDate#, #CreateODBCDateTime(tstamp)#)
</cfquery>
<cfquery name="guest" datasource="#Application.ds#">
SELECT max(guest_id) as id
FROM guest
WHERE provider_id = #provider_id#
</cfquery>
<cfset returnStruct.id = #guest.id#>
<cfreturn returnStruct>
</cffunction>
<!---UPDATE--->
<cffunction name="update" output="false" access="private" returntype="struct" hint="Update an existing item">
<!---general details--->
<cfquery name="update" datasource="#Application.ds#">
UPDATE guest
SET provider_id = provider_id
<cfif isdefined("arguments.title")>
,title = '#arguments.title#'
</cfif>
<cfif isdefined("arguments.first_name")>
,first_name = '#arguments.first_name#'
</cfif>
<cfif isdefined("arguments.surname")>
,surname = '#arguments.surname#'
</cfif>
<cfif isdefined("arguments.full_name")>
,full_name = '#arguments.full_name#'
</cfif>
<cfif isdefined("arguments.dob")>
,dob = #formDate2odbcDate(arguments.dob)#
</cfif>
<cfif isdefined("arguments.partner_first_name")>
,partner_first_name = '#arguments.partner_first_name#'
</cfif>
<cfif isdefined("arguments.partner_surname")>
,partner_surname = '#arguments.partner_surname#'
</cfif>
<cfif isdefined("arguments.partner_full_name")>
,partner_full_name = '#arguments.partner_full_name#'
</cfif>
<cfif isdefined("arguments.partner_dob")>
,partner_dob = #formDate2odbcDate(arguments.partner_dob)#
</cfif>
<cfif isdefined("arguments.address_1")>
,address_1 = '#arguments.address_1#'
</cfif>
<cfif isdefined("arguments.address_2")>
,address_2 = '#arguments.address_2#'
</cfif>
<cfif isdefined("arguments.address_3")>
,address_3 = '#arguments.address_3#'
</cfif>
<cfif isdefined("arguments.city")>
,city = '#arguments.city#'
</cfif>
<cfif isdefined("arguments.state")>
,state = '#arguments.state#'
</cfif>
<cfif isdefined("arguments.postcode")>
,postcode = '#arguments.postcode#'
</cfif>
<cfif isdefined("arguments.country")>
,country = '#arguments.country#'
</cfif>
<cfif isdefined("arguments.phone_bh")>
,phone_bh = '#arguments.phone_bh#'
</cfif>
<cfif isdefined("arguments.phone_ah")>
,phone_ah = '#arguments.phone_ah#'
</cfif>
<cfif isdefined("arguments.phone_mob")>
,phone_mob = '#arguments.phone_mob#'
</cfif>
<cfif isdefined("arguments.fax")>
,fax = '#arguments.fax#'
</cfif>
<cfif isdefined("arguments.email")>
,email = '#arguments.email#'
</cfif>
<cfif isdefined("arguments.subscribe_email_broadcast")>
,subscribe_email_broadcast = '#arguments.subscribe_email_broadcast#'
</cfif>
<cfif isdefined("arguments.company")>
,company = '#arguments.company#'
</cfif>
<cfif isdefined("arguments.notes")>
,notes = '#arguments.notes#'
</cfif>
<cfif isdefined("arguments.prospect")>
,prospect = '#arguments.prospect#'
</cfif>
<cfif isdefined("arguments.occasion")>
,occasion = '#arguments.occasion#'
</cfif>
<cfif isdefined("arguments.occasion_date")>
,occasion_date = #formDate2odbcDate(arguments.occasion_date)#
</cfif>
WHERE guest_id = #arguments.guest_id#
</cfquery>
<cfset returnStruct = structNew()>
<cfset returnStruct.id = arguments.guest_id>
<cfreturn returnStruct>
</cffunction>
In CF, when inside a function and you write things like <cfset iOccasionDate = ... > and <cfquery name="insertGuest" ...> you are creating these in the global variables scope of that CFC/template.
You need to write either <cfset var iOccasionDate = ... > or <cfset local.iOccasionDate = ... > or <cfquery name="local.insertGuest" ...> to ensure they are created in the local variable scope for the function, and don't overwrite other variables.
Your specific problem is because you have this:
<cfquery name="update" datasource="#Application.ds#">
So you're overwriting your update function with an update query.
A few quick things to note:
The local scope works in CF9 and above. If you're in CF8 or below you need to mimic it by writing <cfset var local = StructNew() /> at the top of your function.
If you use Railo or OpenBD there are settings to change the default behaviour to always create in local scope (which avoids the need for var/local scoping), but ACF does not have this option (yet?)
Use cfqueryparam! - Simon has already mentioned this, but it's important enough to be repeated. You should always handle data based on where it will be used - to prevent intentional and accidental injection attacks - and for cfquery that means using cfqueryparam.
It's a bit hard to be more precise without samples of the CFC code and the calling code, however I'd be inclined to suggest that you check the init() of your component. Have you got an init() method, and are you calling it? For example, outline of a component definition
<cfcomponent>
<cffunction name="init" access="public">
<cfreturn this>
</cffunction>
<cffunction name="save" access="public">
<!--- logic --->
</cffunction>
<cffunction name="create" access="public">
<!--- logic --->
</cffunction>
<cffunction name="update" access="public">
<!--- logic --->
</cffunction>
</cfcomponent>
This would then be called by either of the following
<cfscript>
// This will work in CF9 upwards
objCFC = new guest(/* add any arguments you have in the init() method here */);
objCFC.update(......);
// This also works
objCFC = CreateObject('component','guest').init(/* add any arguments you have in the init() method here */);
objCFC.update(......);
</cfscript>
edit following your example
That CFC is nasty. There are various glaring issues.
You are relying on application/session scope within the CFC thus forcing it to rely on global variables. This is what an init() method is used for among other things, as you could init(datasource, provider_id, ext_ref_id, tstamp), store those in variables. scope, and thus it will no longer be vulnerable to variables being undefined outside the CFC
You are using a LOT of VARCHAR fields with NO escaping whatsoever with a cfc with remote access permitted. This is quite vulnerable to SQL injection. Mr Bobby Tables can show you why this is bad ( http://bobby-tables.com/ )
You keep using string value NULL. If you pass this through into a database within a varchar/quotes then it will be stored as 'NULL' and not as a database NULL value
All in all, the best course of action would be to rewrite this component. The code changes on anything that uses the component will be minimal to the point of having to add in an init() and maybe removing some arguments however you will find the stability of it improved and all being well this odd issue will disappear.