Coldfusion 10 invoke cfc error - coldfusion

Anyone have any idea on how to fix this?
"Unable to invoke CFC - The value returned from the getAllContacts function is not of type Contacts[].
If the component name is specified as a return type, it is possible that either a definition file for the component cannot be found or is not accessible."
Thank You.
[UPDATE]
Sure thing: Here's the code within ContactsService.cfc:
<cfcomponent output="false">
<!--- [irrelevant code removed] --->
<cffunction name="getAllContacts" returntype="Contacts[]" access="remote">
<cfreturn entityload("Contacts") />
</cffunction>
<!--- [irrelevant code removed] --->
    
And code within Contacts.cfc:
<cfcomponent persistent="true" table="Contacts" output="false">
<cfproperty name="id" column="id" type="numeric" ormtype="int" fieldtype="id" />
<cfproperty name="company" column="company" type="string" ormtype="string" />
<cfproperty name="Sub_Heading" column="Sub_Heading" type="string" ormtype="string"/>
<cfproperty name="Department" column="Department" type="numeric" ormtype="int" />
<cfproperty name="boss" column="boss" type="string" ormtype="string" />
<cfproperty name="Room" column="Room" type="string" ormtype="string" />
<cfproperty name="Phone" column="Phone" type="string" ormtype="string" />
</cfcomponent>

You've not giving us much to go on! About as much as one can say is "the error message explains very clearly what's probably wrong". If you post some code, then we can give you a better idea.
But basically your method is expecting to return an array of Contact objects, but that's not what you're trying to return.
If you expand your question to contain enough info to answer properly, I'll update the answer to be more thorough...
Update 1
I still cannot answer your question, but I can build on this answer a bit.
It looks to me like your entityLoad() is not actually finding anything. Do you have any Contacts stored?
Can you change your method to be like this:
<cffunction name="getAllContacts" returntype="ANY" access="remote">
<cfset var allContacts = entityload("Contacts")>
<cfdump var="#allContacts#">
<cfreturn allContacts>
</cffunction>
And then call the method and see what it outputs. This should give you a clue.
[TO BE CONTINUED... if you're a StackOverflow policeman, please leave this be. I know it's not a full answer yet, but by the time we get to the bottom of this it will be. I know what I'm doing]

Related

How to handle a request in ColdFusion

I am a newbie to ColdFusion, I created a result.cfm page, now I just want to do some actions in Application.cfc when the user calls /result.cfm. Something like below:
<cfif 'if the request is for result.cfm'>
<!-- do some action -->
</cfif>
Is there any way to handle the request?
A CFC is what Coldfusion calls a component, but it's essentially an object with methods. When any page on your site is requested coldfusion sends the name of your page to the onRequest method of your Application.cfc. By default that method looks something like this...
<cffunction name="OnRequest" access="public" returntype="void" output="true">
<cfargument name="TargetPage" type="string" required="true" />
<cfinclude template = "#arguments.targetPage#" />
</cffunction>
The TargetPage is the relative path to the page that has been requested.
I'm not sure what you're trying to do do, but you can either just create the page result.cfm and do your coding in there, or if you need to you can intercept the call by creating your own onRequest method and putting it in your application.cfc
<cffunction name="OnRequest" access="public" returntype="void" output="true">
<cfargument name="TargetPage" type="string" required="true" />
<cfif arguments.targetPage is "requestresult.cfm">
<!--- Do something else --->
<cfelse>
<cfinclude template = "#arguments.targetPage#" />
</cfif>
</cffunction>
Note that onRequest isn't the only method in Application.cfc, so that's worth looking up.
Also note you might want to output arguments.targetPage when you try this to just double check if the slash comes with the request or not (can't remember)
<cfif REFindNoCase("^/result.cfm", CGI.SCRIPT_NAME)>
<!--- do some action --->
</cfif>
or if you want to match more pages and subfolders you could do:
<cfset patterns = [
"^/foo/",
"^/bar/",
"^/etc/",
"^/login.cfm",
"^/baz.cfm"
] />
<cfif REFindNoCase("(" & ArrayToList(patterns, ")|(") & ")", CGI.SCRIPT_NAME)>
<!--- do some action --->
</cfif>

Retrieve email and phone number via Google API

I am working with Google API using Coldfusion, So making a call to the following URL:
https://www.googleapis.com/plus/v1/people/{userID}?key={MyGoogleKey}
I am able to get the details of the user. Whatever they have shared in their google plus account. One thing that is missing is their email address and phone numbers (if available).
I think, I need to make another call to the API to get the email and phone numbers, but I am struggling with how to do that. Here is the code I am trying to use:
<cfset objGoogPlus = createObject("component","services.auth").init(apikey="#application.google_server_key#",parseResults=true)>
<cfdump var="#objGoogPlus.people_get(userID='#data.id#')#">
<cffunction name="init" access="public" output="false" hint="I am the constructor method.">
<cfargument name="apiKey" required="true" type="string" hint="I am the application's API key to access the services." />
<cfargument name="parseResults" required="false" type="boolean" default="false" hint="A boolean value to determine if the output data is parsed or returned as a string" />
<cfset variables.instance.apikey = arguments.apiKey />
<cfset variables.instance.parseResults = arguments.parseResults />
<cfset variables.instance.endpoint = 'https://www.googleapis.com/plus/v1/' />
<cfreturn this />
</cffunction>
<cffunction name="getparseResults" access="package" output="false" hint="I return the parseresults boolean value.">
<cfreturn variables.instance.parseResults />
</cffunction>
<cffunction name="people_get" access="public" output="false" hint="I get a person's profile.">
<cfargument name="userID" required="true" type="string" hint="The ID of the person to get the profile for. The special value 'me' can be used to indicate the authenticated user." />
<cfargument name="parseResults" required="false" type="boolean" default="#getparseResults()#" hint="A boolean value to determine if the output data is parsed or returned as a string" />
<cfset var strRequest = variables.instance.endpoint & 'people/' & arguments.userID & '?key=' & variables.instance.apikey />
<cfreturn getRequest(URLResource=strRequest, parseResults=arguments.parseResults) />
</cffunction>
<cffunction name="getRequest" access="private" output="false" hint="I make the GET request to the API.">
<cfargument name="URLResource" required="true" type="string" hint="I am the URL to which the request is made." />
<cfargument name="parseResults" required="true" type="boolean" hint="A boolean value to determine if the output data is parsed or returned as a string" />
<cfset var cfhttp = '' />
<cfhttp url="#arguments.URLResource#" method="get" />
<cfreturn handleReturnFormat(data=cfhttp.FileContent, parseResults=arguments.parseResults) />
</cffunction>
<cffunction name="handleReturnFormat" access="private" output="false" hint="I handle how the data is returned based upon the provided format">
<cfargument name="data" required="true" type="string" hint="The data returned from the API." />
<cfargument name="parseResults" required="true" type="boolean" hint="A boolean value to determine if the output data is parsed or returned as a string" />
<cfif arguments.parseResults>
<cfreturn DeserializeJSON(arguments.data) />
<cfelse>
<cfreturn serializeJSON(DeserializeJSON(arguments.data)) />
</cfif>
</cffunction>
<cffunction access="public" name="getProfileEmail" returntype="any" returnformat="json">
<cfargument name="accesstoken" default="" required="yes" type="any">
<cfhttp url="googleapis.com/oauth2/v1/userinfo"; method="get" resolveurl="yes" result="httpResult">
<cfhttpparam type="header" name="Authorization" value="OAuth #arguments.accesstoken#">
<cfhttpparam type="header" name="GData-Version" value="3">
</cfhttp>
<cfreturn DeserializeJSON(httpResult.filecontent.toString())>
</cffunction>
I do not what to say, but i used the following method and its seems to bring the email-address, not with new way but with old way:
<cfset googleLogin = objLogin.initiate_login(
loginUrlBase = "https://accounts.google.com/o/oauth2/auth",
loginClientID = application.google_client_id,
loginRedirectURI = application.google_redirecturl,
loginScope = "https://www.googleapis.com/auth/userinfo.email"
)>
I discuss Google+ and Sign In via this blog post (http://www.raymondcamden.com/index.cfm/2014/2/20/Google-SignIn-and-ColdFusion), and yes, I know it is bad to just point to a blog post so none of my hard work there will be appreciated by SO (sigh). As Prisoner said, what you get is based on the scopes initially requested. Here are the docs on additional scopes: https://developers.google.com/+/api/oauth#login-scopes. Email is there, but not phone as far as I see. And to be honest, I don't see a place to enter my phone # at Google+ anyway.
Based on the "getProfileEmail" function that you've added, it looks like you're using the userinfo scope and access point. Google has announced that this method is deprecated and will be removed in September 2014.
You should switch to using the people.get method and adding the email scope to the G+ Sign-in button that Raymond has outlined on his blog.
Update
In your call to objLogin.initiate_login you should change the loginScope parameter to use both the profile and email scopes at a minimum (see https://developers.google.com/+/api/oauth#scopes for a more complete list of scopes you may wish to use). So it might look something like:
<cfset googleLogin = objLogin.initiate_login(
loginUrlBase = "https://accounts.google.com/o/oauth2/auth",
loginClientID = application.google_client_id,
loginRedirectURI = application.google_redirecturl,
loginScope = "profile email"
)>
You can then use the people.get API call to get the information you need. Looking at your getRequest function, however, this appears to call people.get using the API Key, which is insufficient to get email - all it can do is get public information. You need to call people.get in the same way you called userinfo in the getProfileEmail function. I don't know ColdFusion well enough, but you should be able to adapt this function to call the people.get endpoint instead.

Per subsystem error files in FW/1

I am trying to get per subsystem error files in FW/1. I know the following does not work.
variables.framework = {
...
error = getSubsystem() .error',
...
UPDATE
I tried
<cffunction name="onError">
<cfargument name="Exception" type="Struct" required />
<cfargument name="Event" type="String" required />
<cfif Arguments.Exception.Type EQ 'missinginclude' >
<cfoutput>#layout('#getSubsystem()#:default',view('login/error'))#</cfoutput>
<cfreturn false />
</cfif>
<cfreturn super.onError(ArgumentCollection=Arguments) />
</cffunction>
And I get an error of:
The EXCEPTION argument passed to the onError function is not of type Struct.
If the component name is specified as a type of this argument, it is possible that either a definition file for the component cannot be found or is not accessible.
The error occurred in /Applications/ColdFusion10/cfusion/wwwroot/Pluma/Application.cfc: line 189
187 : </cffunction>
188 :
189 : <cffunction name="onError">
190 : <cfargument name="Exception" type="Struct" required />
191 : <cfargument name="Event" type="String" required />
What you can do is override the onError method in your Application.cfc to manually call the relevant per-subsystem files.
Here's an example of handling missinginclude errors with a layout in a non-default subsystem:
<cffunction name="onError">
<cfargument name="Exception" type="Struct" required />
<cfargument name="Event" type="String" required />
<cfif Arguments.Exception.Type EQ 'missinginclude' >
<cfoutput>#layout('subsys2:default',view('main:errors/404'))#</cfoutput>
<cfreturn false />
</cfif>
<cfreturn super.onError(ArgumentCollection=Arguments) />
</cffunction>
Returning super.onError will result in the standard error handling being invoked.
For making it completely per-subsystem you could do something like view(getSubsystem()&':errors') or similar.
If you're doing potentially complex logic, remember to use appropriate try/catch - tracking errors in your error handling can be awkward.

Looking for Struct Keys in Session

I am trying to write a session helper and facing to problem to test if a Struct key in session exists?
I am trying like
<cffunction name="Exists" access="public" output="false" returntype="boolean" >
<cfargument name="Key" required="true" type="Any" />
<cfreturn Evaluate( "StructKeyExists( Session, #Arguments.Key# )" ) />
</cffunction>
Where I am calling the function like
<cfif Exists("data.fromdate") >
...
</cfif>
How should I write it?
Thanks
if you are checking to see if key "Test" exists in the session struct, try something like this:
<cffunction name="Exists" access="public" output="false" returntype="boolean" >
<cfargument name="Key" required="true" type="String" />
<cfreturn StructKeyExists(session, arguments.Key) />
</cffunction>
<cfif Exists("Test") >
....
</cfif>
Another concept, or two, since you are looking for a struct within the session would be:
<cffunction name="Exists" access="public" output="false" returntype="boolean" >
<cfargument name="Key" required="true" type="String" />
<cfreturn (structKeyExists(session, listFirst(arguments.Key,"."))
AND structKeyExists(session[listFirst(arguments.Key,".")], listLast(arguments.Key, "."))) />
</cffunction>
<cfif Exists("data.Test") >
....
</cfif>
and
<cffunction name="Exists" access="public" output="false" returntype="boolean" >
<cfargument name="struct" required="true" type="String" />
<cfargument name="Key" required="true" type="String" />
<cfreturn (structKeyExists(session, arguments.struct)
AND structKeyExists(session[arguments.struct], arguments.key)) />
</cffunction>
<cfif Exists("data", "Test") >
....
</cfif>
Hope all this helps point you in the right direction, good luck!
The following code will check any depth struct, and also correctly locks the Session scope.
<cffunction name="Exists" access="public" output="false" returntype="boolean">
<cfargument name="Key" required="true" type="string">
<cfset local.mainKeyList = ListChangeDelims(ListDeleteAt(Arguments.Key, ListLen(Arguments.Key, "."), "."), ",", ".")>
<cfset local.StructChain = "Session">
<cfloop list="#local.mainKeyList#" index="local.CurrentKey">
<cfset local.StructChain &= '["#local.CurrentKey#"]'>
</cfloop>
<cflock scope="session" type="readonly" timeout="3">
<cftry>
<cfset local.Exists = StructKeyExists(Evaluate(local.StructChain), ListLast(Arguments.Key, "."))>
<cfcatch>
<cfset local.Exists = false>
</cfcatch>
</cftry>
</cflock>
<cfreturn local.Exists>
</cffunction>
<cflock scope="session" type="exclusive" timeout="3">
<cfset Session.data.log.deep = "I'm here!">
</cflock>
<cfoutput>#Exists("data.log.deep")#</cfoutput>
Hopefully the amount of code in this function will justify why a helper function would be useful, to those pondering your reasons. This doesn't currently, but could be enhanced to, deal with Structs inside of Arrays as well. This also doesn't deal with an empty Arguments.Key, or fail gracefully on a cflock timeout, but should get you started.
Additionally, those that want to comment that cflock isn't required, please read the ColdFusion cflock docs first.
Simplified, but may provide inaccurate results in extremely rare conditions
Doing an IsDefined inline in your code will provide the opportunity for false positives, however having the IsDefined inside a udf or cfc method reduces this risk greatly to the point it may not need be a consideration. If you're happy to take that chance then you can simplify the function using IsDefined as Peter Boughton suggests.
<cffunction name="Exists" access="public" output="false" returntype="boolean">
<cfargument name="Key" required="true" type="string">
<cflock scope="session" type="readonly" timeout="3">
<cfset local.Exists = IsDefined("Session." & Arguments.Key)>
</cflock>
<cfreturn local.Exists>
</cffunction>
As Al Everett mentioned above, I don't remember the last time I had an app that didn't have session enabled. I guess if you can't be sure of that, then it makes sense to see if Session exists. My code for this would include:
<!--- in the application.cfc --->
<cffunction name="onSessionStart" output="false">
<!--- default session structure, you can also add default values to the data
structure here to ensure they exist later --->
<cfset session.data = {} />
</cffunction>
<!--- then in code use structKeyExists instead of a whole new function --->
<cfif structKeyExists(session.data, myKey)>
<!--- if you really wanted the "exists" function --->
<cffunction name="dataKeyExists" returntype="boolean" output="false">
<cfargument name="key" required="true" />
<cfreturn structKeyExists(session.data, arguments.key) />
</cffunction>
Depending on what's going on, I might choose to pass in the session to maintain encapsulation. But it doesn't always make sense to be a slave to OO and introduce complexity just for the sake of maintaining a pattern. Passing in the session structure and evaluating the key is really just a big workaround to using the "structKeyExists" function.
I also dislike having a function called "exists" because it tells me nothing about what it's really evaluating. I'd assume a function like that was like "isDefined" and more generic than just testing for a key in a specific structure.
<cfif structkeyexists(session, "data") and structkeyexists(session["data"], key)>
...
</cfif>
Why not just call <cfif isNull(session.data.fromdate)>
If the key data does not exist in session it will not throw, just returns false.

What's the most efficient way to redirect a user to the home page if the requested page doesn't exist?

I am using ColdFusion 9.1.
I am rebuilding a site from scratch and pointing an existing domain name to it. The site is still getting a few hits each day and I want to take advantage of that. I want to redirect those page requests to the home page, and not the error that is currently being served.
I am looking ONLY for a ColdFusion solution to move the bad request to the home page. So, if they request domain.com/BadPage.cfm?QString=XYZ, they will be moved to domain.com/.
I tried using the following method in the Application.cfc, but I couldn't get to work as described. It seemed to have no effect.
<cffunction name="OnError" access="public" returntype="void" output="true">
<cfargument name="Exception" type="any" required="true" /">
<cfargument name="EventName" type="string" required="false" default="" />
<cfif Exception>
<cflocation url="http://www.MyDomain.cfom/">
</cfif>
<!--- Return out. --->
<cfreturn />
</cffunction>
In short, what is the simplest ColdFusion means to redirect bad requests?
onError will not catch missing templates. Add an onMissingTemplate Handler to Application.cfc:
<cffunction name="onMissingTemplate" returntype="Boolean" output="false">
<cfargument name="templateName" required="true" type="String" />
<!--- Put your home page file name here --->
<cflocation url="/index.cfm" />
<cfreturn true />
</cffunction>
Use onMissingTemplate()
<cffunction name="onMissingTemplate">
<cfargument type="string" name="targetPage" required=true/>
<cflocation url="http://www.MyDomain.cfom/">
</cffunction>