2 Replies - 1467 Views - Last Post: 09 April 2011 - 01:07 AM Rate Topic: -----

#1 AldoRaine  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 17-January 11

cfparam and component question

Posted 08 April 2011 - 03:23 PM

I am working on a simple login for a site I am building. It works, I just want to make sure I have everything in order, especially the cfparams in the logIn.cfc. I did have them placed in the loginCheck page... I am very new to ColdFusion, but I am slowly learning. Here is the code:

LoginForm.cfm

<!---include login check to validate user--->
<cfif isDefined("form.user_name")>
	<cfinclude template="loginCheck.cfm">
</cfif>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body onload="document.loginForm.user_name.focus();">

<!---start login form--->
<cfform action="#cgi.SCRIPT_NAME#?#cgi.query_string#" name="loginForm" method="post">

<!---use html table for formatting--->
<table border="0">

<tr>
<th colspan="2" bgcolor="silver">Please Log In</th>
</tr>
<tr>
<th>Username:</th>
<td>
<!---text field for username--->
<cfinput type="text" name="user_name" size="20" value="" maxlength="100" required="true" message="please type your username first">
</td>
</tr>
<tr>
<th>Password:</th>
<td>
<!---text field for username--->
<cfinput type="text" name="user_password" size="20" value="" maxlength="100" required="true" message="please type your password first">
<!---submit button--->
<input type="submit" value="Enter">
</td>
</tr>

</table>

</cfform>

</body>
</html>



loginCheck:
<!---make sure login and password is present--->
<cfinvoke component="logIn" method="basicLogin" returnvariable="get_user">


<!---if the user and password are correct--->
<cfif get_user.RecordCount eq 1>
<!---remember that status--->
<cfset session.auth = structNew()>
<cfset session.auth.isLoggedIn = "yes">


<!---now that user is logged in, send him where he wants to go--->
<cflocation url="#cgi.SCRIPT_NAME#?#cgi.QUERY_STRING#">
</cfif>


LogIn.cfc

<cfcomponent>
	<cffunction name="basicLogin" access="package" returntype="Query" hint="log in users - admin, parent, and leader">
		<cfparam name="form.user_name" type="string">
		<cfparam name="form.user_name" type="string">
		
		<cfquery name="get_user" datasource="boyscouts">
			SELECT user_name, user_password
			FROM get_user
			WHERE user_name = 
			<cfqueryparam cfsqltype="cf_sql_varchar" value="#form.user_name#">
			AND user_password =
			<cfqueryparam cfsqltype="cf_sql_varchar" value="#form.user_password#"> 
		</cfquery>
			<cfreturn get_user>
	</cffunction>
</cfcomponent>


Also, I am having a bear of a time trying to get straight returnvairable and cfreturn... maybe I am just over complicating things.

Is This A Good Question/Topic? 0
  • +

Replies To: cfparam and component question

#2 Craig328  Icon User is offline

  • I make this look good
  • member icon

Reputation: 1912
  • View blog
  • Posts: 3,448
  • Joined: 13-January 08

Re: cfparam and component question

Posted 08 April 2011 - 04:06 PM

Hey Aldo, welcome back!

Looking at your code, I see one or two things that immediately jump out that are almost certainly causing you problems. Let's start with the lowest level and work up.

Your login.cfc looks like this:
<cfcomponent>
	<cffunction name="basicLogin" access="package" returntype="Query" hint="log in users - admin, parent, and leader">
		<cfparam name="form.user_name" type="string">
		<cfparam name="form.user_name" type="string">
		
		<cfquery name="get_user" datasource="boyscouts">
			SELECT user_name, user_password
			FROM get_user
			WHERE user_name = 
			<cfqueryparam cfsqltype="cf_sql_varchar" value="#form.user_name#">
			AND user_password =
			<cfqueryparam cfsqltype="cf_sql_varchar" value="#form.user_password#"> 
		</cfquery>
			<cfreturn get_user>
	</cffunction>
</cfcomponent>


Okay, you have the right idea for building a component method (cfcomponent/cffunction). However, to get your user's user_name and user_password into a component method in CF, you would use the CFARGUMENT tag rather than cfparam as you have here. Incidentally, you have identical cfparams on lines 3 & 4 in your cffunction...even though cfparam isn't the correct tag to use here anyway.

So, your function should actually look more like this:
<cfcomponent>
	<cffunction name="basicLogin" access="public" returntype="Query" hint="log in users - admin, parent, and leader">
		<cfargument name="user_name" default="" required="true" type="string">
		<cfargument name="user_password" default="" required="true" type="string">
		
		<cfquery name="get_user" datasource="boyscouts">
			SELECT user_name, user_password
			FROM get_user
			WHERE user_name = 
			<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.user_name#">
			AND user_password =
			<cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.user_password#"> 
		</cfquery>
			<cfreturn get_user>
	</cffunction>
</cfcomponent>


You'll notice I only changed a couple of things here. The first is the access attribute of your cffunction. Package would have made the function available only within the component itself and would not have been available to executing page in the same application. More on where this comes in in a moment. Another change was moving from cfparam to cfargument. The use of cfargument is important. It's the way you explicitly declare the data a calling (or invoking) object must pass in in order for the function to do its thing. Some variables scopes are available in a component method and others are not. Application, server, session, client...those are all available (mostly) in a component method like this. Local variables typically used on the invoking page (in your case, loginCheck.cfm) such as variables, request, URL, form...they're not available in the component method. This is where cfargument comes in. If there is a local variable like say form variables that you need to have your component method work with, you pass them in explicitly, like I've done here. From there, they are available inside the function/method in something known as the arguments scope. You CAN declare local variables in the component method but again, they are segregated from the rest of the application and are not available. Global variables however typically ARE available to the invoking page and the rest of the app even when declared in a function/method. This will take getting used to so you can remember which is which. However, for now, what you have there is what you'll need for your component function/method.

Next thing: your invoking page. This is what you'll want to do here:
<!---make sure login and password is present--->
<cfinvoke component="logIn" method="basicLogin" returnvariable="get_user">
	<cfinvokeargument name="user_name" value="#form.user_name#">
	<cfinvokeargument name="user_password" value="#form.user_password#">
</cfinvoke>


<!---if the user and password are correct--->
<cfif get_user.RecordCount eq 1>
<!---remember that status--->
<cfset session.auth = structNew()>
<cfset session.auth.isLoggedIn = "yes">


<!---now that user is logged in, send him where he wants to go--->
<cflocation url="#cgi.SCRIPT_NAME#?#cgi.QUERY_STRING#">
</cfif>



You'll notice the only change I made was to add the CFINVOKEARGUMENT tags. Because the form scope isn't going to be available to the function method, you need to pass it in as an explicit function variable and you do that with these tags. Now, while what you have here is just fine, you CAN actually do the session.auth variable settings within the basicLogin method itself (because the session state is accessible to the method as well). You'd might consider doing this as the reason you typically build a component and method is to encapsulate certain related functionality into an object that you can invoke anywhere from within your app (or even expose as a web service later on). In this case, what you have will work but what I'm mentioning here has more to do with application architecture and code reusability than strict functionality. What you have here will work fine.

Other than that, I believe everything you have here is good to go. There are some logic gates that I'd build differently but that's more a matter of personal preference and style than anything else.

Give those a try and see how they work for you. If you have further trouble, post back here.

Good luck!

This post has been edited by Craig328: 08 April 2011 - 04:09 PM

Was This Post Helpful? 0
  • +
  • -

#3 AldoRaine  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 17-January 11

Re: cfparam and component question

Posted 09 April 2011 - 01:07 AM

First of all, much thanks for your reply.

I thought since the method was only returning a query, I wouldn’t have to use the cfargument tag. But what I didn’t take into consideration was that not only did the basicLogin method send a query, it also had to receive the form variables to complete the query. The assumption was that the method would magically, I guess, have access to the form variables.

The cfparam tags were used in the loginCheck page to make sure the user_name and user_password variables existed. My thinking was that I could perform this same function within the basicLogin method. Obviously, that’s not the case.


Quote

It's the way you explicitly declare the data a calling (or invoking) object must pass in in order for the function to do its thing.


I'm not sure I completely follow exactly what this means. The cfargument allows the function to deal directly with the form variables - lets the function know that it is dealing with form variables? Sorry if this should be obvious to me.

I'm going to apply the changes, and I will let you know how it goes. Again thanks!
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1