• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

CFCs -- using variables from other CFC's in queries

New Here ,
Aug 26, 2007 Aug 26, 2007

Copy link to clipboard

Copied

I am working on a click tracking program for emailings, well I want to exclude our IP address, and the clients IP address to show up in the click details, and I want to omit them from being counted when the number of hits are displayed, these are shown on 2 different pages, here is the code I am working with

Filter.cfc this component takes care of all the filtering of the IPs, and because of the problems I was having w/ the variable not working, I went a head and put all the functions to display the details which shows the ip addy, referrer, and user agent for each click


<!--- -THis method takes out the IPs in the list that are in the Filtered table --->
<cffunction name="noShowFilterList" returntype="any" access="remote">
<cfset filterList = "69.15.59.174">
<cfoutput query="getFilterIPInfo">
<cfset filterList = filterList & "," & getFilterIPInfo.ipAddress>
</cfoutput>
</cffunction>



<!--- This method sets everything up for the table that displays the click information --->
<cffunction name="getFilteredLinkDetail" access="remote" returntype="any">
<cfparam name="PageNum_queryDetails" default="1">
<cfquery name="queryDetails" datasource="clickTrackSystem">
SELECT *
FROM Clicks
WHERE linkID = #url.l# AND NOT (FIND_IN_SET(Clicks.ipAddy, "#filterList#"))
</cfquery>...


here is clickDetail.cfm...just the calling of this functionality


<!--- Create a Filter Object --->
<cfset newFilter=CreateObject('component', 'Filter')>
<!--- Query all Filtered IPs --->
<cfinvoke component="#newFilter#" method="displayFilteredIPs" returnvariable="getFilterIPInfo">
<cfinvoke component="#newFilter#" method="noShowFilterList" returnvariable="filterList">



Links.cfc (this is just a query in the fucntion that displays the projects links, thier name, target, track link, and the hits, this is the query for the hits, and it works to exclude the detail. The fuction is called linkInfo)

<cfquery name="countHits" datasource="clickTrackSystem">
SELECT Clicks.linkID
FROM Clicks
WHERE Clicks.linkID = #getLinkInfo.linkID# AND NOT (FIND_IN_SET(Clicks.ipAddy, "#filterList#"
)) </cfquery>
Hits:#countHits.recordcount#<br>


And here is me calling all this in Campaign.cfm, where all the links for the project are displayed


<!--- Create an Object of type Links from Links.cfc--->
<cfset newLink = CreateObject('component', 'Links')>
<!--- Query the link info--->
<cfinvoke component="#newLink#" method="displayLinks" returnvariable="getLinkInfo">
<!--- Create a Filter Object --->
<cfset newFilter=CreateObject('component', 'Filter')>
<!--- Query all Filtered IPs --->
<cfinvoke component="#newFilter#" method="displayFilteredIPs" returnvariable="getFilterIPInfo">
<cfinvoke component="#newFilter#" method="noShowFilterList" returnvariable="filterList">


So what is going on, filterList is a variable that holds a comma delimited list of the IPs we don't want to show or count, it is created in the filter component and called in a query in a function in the Links component, everything works where I just use it from the filter component, but when I call it in the link component with in the query, it throws an undefined error:

Variable filterList is undefined.


The error occurred in /Links.cfc: line 57

55 : SELECT Clicks.linkID
56 : FROM Clicks
57 : WHERE Clicks.linkID = #getLinkInfo.linkID# AND NOT (FIND_IN_SET(Clicks.ipAddy, "#filterList#"))
58 : </cfquery>
59 : Hits:#countHits.recordcount#<br>

THis is my first program ever outside of school, and I learned about OOP with JAVA in school, but never really got to apply it, I know there is some rule I am breaking or something for CFC's and maybe even the OOP concept all together...even if I put that query out of the Links component and hardcode it in the Campaign.cfm page, I still get the error, but it works for the clickDetail page and I know it is because all the fuctions it needs to do so are all done in the same cfc: Filter. If I can't get this to work, then I will have to hard code all this in two different pages, and that defeats the purpose of using cfc's, eventually we want to make a whole mass emailing system and just have the clicktracking as a feature, so cfcs are going to be important...someone please make me understand where I am going wrong

Kacie
TOPICS
Advanced techniques

Views

599

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Aug 27, 2007 Aug 27, 2007

Copy link to clipboard

Copied

> THis is my first program ever outside of school, and I learned about OOP with
> JAVA in school, but never really got to apply it, I know there is some rule I
> am breaking or something for CFC's and maybe even the OOP concept all
> together...

Right. First things first then: you might need to brush up a bit on what
you're trying to achieve. Given yourself a refreshed in OO concepts.
Here's one link:
http://en.wikipedia.org/wiki/Object-oriented_programming

And Google will have plenty more, if the Wikipedia article is a bit dry (be
warned: almost all coverage of OO concepts will be a bit dry!)

Next, read the docs on CFCs that Adobe very kindly expose to the public,
here:
http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=buildingComponents_01.html

Specifically, read and understand the coverage of the different variables
scopes available to CFC instances, and how to use them:
http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=buildingComponents_01.html


> <cffunction name="noShowFilterList" returntype="any" access="remote">
> <cfset filterList = "69.15.59.174">

You should be VARing this variable. And all variables local to a method.
If it IS actually your intent for the variable to be global to the CFC
instance, SCOPE IT as variables.filterList. CF will work out what you mean
without the scoping, but you can make the life easier of humans reading the
code if you scope your variables as much as possible, whether they "need"
it or not.


> <cfoutput query="getFilterIPInfo">

Where did this query come from? You didn't pass it in to the method. Is
it an argument? (You should have a <cfargument> tag for it, and you should
scope it. Is it a instance-wide variables (variables scope)? Scope it for
clarity. Similarly if it is THIS-scoped.


> <cfset filterList = filterList & "," & getFilterIPInfo.ipAddress>
> </cfoutput>

You don't need to have this loop. Just use valueList().


> <cffunction name="getFilteredLinkDetail" access="remote" returntype="any">
> <cfparam name="PageNum_queryDetails" default="1">

I suspect this should be a VAR statement.


> <cfquery name="queryDetails" datasource="clickTrackSystem">

This should be VARed.


> SELECT *

Using SELECT * is generally poor practice. Do you actually WANT every
column from the query, irrespective of what those columns are? I suspect
not. SELECT only the columns you intend to use; it's much less work for
the DB server and the CF server.


> WHERE linkID = #url.l# AND NOT (FIND_IN_SET(Clicks.ipAddy, "#filterList#"))

In referring to a URL-scoped variable directly in your CFC code, you are
limiting the reusability of the CFC. This value should be passed in.

And you should NEVER EVER use a URL-scope variable directly in a query
anyhow. Google "SQL injection".

Always use <cfqueryparam> tags in your queries, when using dynamic values.
Otherwise all your SQL will be treated as dynamic SQL by the DB server, and
you'll end up with 100s of individually compiled and never-reused queries
sitting on your DB server. Initial compilation has quite an overhead which
you'll want to minimise. Parameterising queries also prevents the chance
of SQL injection.


> <cfset newFilter=CreateObject('component', 'Filter')>
> <!--- Query all Filtered IPs --->
> <cfinvoke component="#newFilter#" method="displayFilteredIPs"
> returnvariable="getFilterIPInfo">

Right. So this is where that query comes from. However...


> <cfinvoke component="#newFilter#" method="noShowFilterList"
> returnvariable="filterList">

... you're never passing it in to the method call, are you? So how's the
method supposed to know about it? Code in CFCs know ONLY about their own
VARIABLES scope; they have no idea about the calling-code's VARIABLES
scope. You need to pass in calling-code variables that you wish the CFC
method to have access to.


> <cfinvoke component="#newLink#" method="displayLinks"
> returnvariable="getLinkInfo">

Can I recommend that instead of using all these clunky <cfinvoke> tags, you
simply:

<cfset getLinkInfo = newLink.displayLinks()>

It's much cleaner.

<cfinvoke> is a bit of a lemon of a tag, for most of its "recommended" (in
the docs, that is) uses.


> Variable filterList is undefined.
> The error occurred in /Links.cfc: line 57
>
> 55 : SELECT Clicks.linkID
> 56 : FROM Clicks
> 57 : WHERE Clicks.linkID = #getLinkInfo.linkID# AND NOT

I hope you understand why this is, now?

--
Adam

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Aug 27, 2007 Aug 27, 2007

Copy link to clipboard

Copied

"... you're never passing it in to the method call, are you? So how's the
method supposed to know about it? Code in CFCs know ONLY about their own
VARIABLES scope; they have no idea about the calling-code's VARIABLES
scope. You need to pass in calling-code variables that you wish the CFC
method to have access to."

I understand what you are saying, but I don't know how. I thought since the cfm page had filterlist as a return variable then the page would pass that variable to the cfc when the method was called. Obiviously I was wrong, I even tried, knowing it was not right, to create and object of Filter and invoke that method with the query in the Links cfc, and of course I was right it didn't work. That was basically my question...how do I get Links.cfc to know what filterlist is? Note I will take your better practices suggestions once I get this all figured out, I put variables.filterList and it just threw and error that filterList was undefined in variables, and that threw me off, so once I get this going I will go back and fix it, but I am confused enough for now

Here is what I have tried:

a new fucntion in Links.cfc
<cffunction name="passFilterList">
<cfargument name="filterList" required="no" type="string">
<cfset this.filterList = arguments.filterList>
</cffunction>

the query in the function that does the output
...
<cfquery name="countHits" datasource="clickTrackSystem">
SELECT Clicks.linkID
FROM Clicks
WHERE Clicks.linkID = #getLinkInfo.linkID# AND NOT (FIND_IN_SET(Clicks.ipAddy, "#filterList#"))
</cfquery>
...


new code for campaign.cfm

<!--- Create a Filter Object --->
<cfset newFilter=CreateObject('component', 'Filter')>
<!--- Query all Filtered IPs --->
<cfinvoke component="#newFilter#" method="displayFilteredIPs" returnvariable="getFilterIPInfo">
<cfinvoke component="#newFilter#" method="noShowFilterList" returnvariable="filterList">
<cfdump var = "#filterList#"> <!--- Its there! --->
<!--- Create an Object of type Links from Links.cfc--->
<cfset newLink = CreateObject('component', 'Links')>
<!--- Query the link info--->
<cfset newLink.passFilterList('#filterList#')>
<cfinvoke component="#newLink#" method="displayLinks" returnvariable="getLinkInfo">
.....
I even pass it down here
<!--- Display Link information--->
<cfset newLink.linkInfo('#filterList#')>



Still filterList is undefined, I even tried putting filterList into another variable and passing it using the new variable, but no, no no I can't get Links.cfc to comply
btw I need cfinvoke when my functions have queries in them....right?

"> <cffunction name="getFilteredLinkDetail" access="remote" returntype="any">
> <cfparam name="PageNum_queryDetails" default="1">

I suspect this should be a VAR statement."

funny you mention that because I get an error for that as well, I use it in the table in the page, and it is undefined, I changed it like this:
<cfset VAR PageNum_queryDetails = "1">
and still undefined, is that not what you meant?

"> <cfquery name="queryDetails" datasource="clickTrackSystem">

This should be VARed.
"
How do you VAR a query?

"> <cfset filterList = filterList & "," & getFilterIPInfo.ipAddress>
> </cfoutput>

You don't need to have this loop. Just use valueList().
"

I found syntax for this and I understand it, but how can I tell it to start out with a value and add the list to that value the way we have it set up now? We need to put our IP address in the list first and then tack on what it finds in the database, if we put it in the Database, we will have to put it in there for every client.

Thanks in advance for you patience and help

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Aug 27, 2007 Aug 27, 2007

Copy link to clipboard

Copied

> I understand what you are saying, but I don't know how.

Right.

Did you read all that bumpf I gave you the link for, before (about CFCs)?
That was an awful lot of it to:
a) read over;
b) investigate and experiment with.

I didn't mean just the single pages I referenced, I meant the ensuing
section (there's about 30-odd pages in it). There are next/prev arrows @
the top right of each page.

I recommend you ditch your immediate requirement, and work on the examples
given in the docs for a bit until you get your head around them. And then
return to your specific problem once you've done that.


> cfm page had filterlist as a return variable then the page would pass that
> variable to the cfc when the method was called.

Only if you tell it to. You need to pass in these values into CFC methods
just like you would any other function.

You'd not have code like this:

<cfset stringToTrim = "Hello World">
<cfset charactersWanted = 5>
<cfset newString = left()>

And expect newString to contain "Hello". No, you need to pass the values
to the function:

<cfset newString = left(stringToTrim, charactersWanted)>

CFC methods are the same. They're just functions. For them to receive a
value, you have to pass them in.

This IS all covered in the docs I pointed you to.


> Note I will take your better practices suggestions once I get
> this all figured out,

Makes sense. Like I suggested: I'd back off even further and try the more
simple examples in the docs first.


> funny you mention that because I get an error for that as well, I use it in
> the table in the page, and it is undefined, I changed it like this:
> <cfset VAR PageNum_queryDetails = "1">
> and still undefined, is that not what you meant?

Just as a practice, one should always VAR variables used in functions. I
was not meaning to suggest it'd fix your issue, just something you should
be doing.


>>> <cfquery name="queryDetails" datasource="clickTrackSystem">
>> This should be VARed.

> How do you VAR a query?

A query is just a variable, like any other variable. So one vars it in the
same way.

<cfset var queryDetails = ""><!--- any old value is fine --->
...
<cfquery name="queryDetails" datasource="clickTrackSystem">


>>> <cfset filterList = filterList & "," & getFilterIPInfo.ipAddress>
>> You don't need to have this loop. Just use valueList().

> I found syntax for this and I understand it, but how can I tell it to start
> out with a value and add the list to that value the way we have it set up now?

Right. You have a string (filterList) and you want to preprend it to a
list (the result of your valueList() call).

You could either treat your valueList() as a string and prepend filterList
in exactly the same way as you are above (just without the loop), or you
could approach it from the "list" perspective and investigate which list
functions might help you there.

http://livedocs.adobe.com/coldfusion/8/htmldocs/functions-pt0_13.html#1099435


> Thanks in advance for you patience and help

No prob. Sorry to not just be answering your questions directly (ie: "the
answer to your problem is [this]"), but I don't believe that approach is
very helpful, in the long run. I think it's best to learn what the answer
is, rather than to be told it.

--
Adam

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Aug 27, 2007 Aug 27, 2007

Copy link to clipboard

Copied

you are absolutely right, I will be studying on this for the rest of the day and more tomorrow, and post sometime tomorrow afternoon

Thanks

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Aug 31, 2007 Aug 31, 2007

Copy link to clipboard

Copied

LATEST
I got it ironed out using the variables scope, I still need to wrap my head around some stuff but I am just glad it works, thanks for the help!

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Aug 27, 2007 Aug 27, 2007

Copy link to clipboard

Copied

Thank you Adam, I will get to work on this right now, and let you know how it goes...

"> <cfoutput query="getFilterIPInfo">

Where did this query come from? You didn't pass it in to the method. Is
it an argument? (You should have a <cfargument> tag for it, and you should
scope it. Is it a instance-wide variables (variables scope)? Scope it for
clarity. Similarly if it is THIS-scoped."

The query getFilterInfo, is in another method in the same CFC

'THIS' is something I just don't understand, I can never find any OO examples where there is interaction with databases.

I will take a look at those websites you gave me and begin trying to work all this out, you should be hearing more from me later on in the day...

Thanks

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Aug 27, 2007 Aug 27, 2007

Copy link to clipboard

Copied

> Specifically, read and understand the coverage of the different variables
> scopes available to CFC instances, and how to use them:
> http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=buildingComponents_01.html

Sorry, that should read
http://livedocs.adobe.com/coldfusion/8/htmldocs/buildingComponents_29.html.

--
Adam

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Resources
Documentation