i have one table called content where in I am adding top level pages and child pages. The top level page will have parent__id as the id of page title home and child pages will have their respective parent__id. when i add pages it something look like this.
id parent__id title and so on.
1 0 Home
2 1 About
3 2 services
4 1 contact us
here I want to display it like
Home
>About
>>services
>contact
i have tried this
<cfquery name="d" datasource="mydata">
SELECT p.id as parentid,
p.title as parent,
p.nav_depth,
c.id as childid,
c.title as child,
c.parent__id as child_parentid
from content p
left join content as c on c.parent__id = p.id
where p.site__id = "8432381492061036983"
group by p.id, c.id
order by p.id, c.id, c.nav_order
</cfquery>
<cfdump var="#d#">
<cfoutput query="d" group="parentid">
<cfif d.nav_depth EQ 0>
#d.parent#<br />
<cfif d.parentid EQ d.child_parentid>
<cfoutput>> #d.child#<br /></cfoutput>
</cfif>
</cfif>
<cfif d.nav_depth GT 0>
<cfif d.childid EQ d.child_parentid>
<cfoutput> >> #d.child<br /></cfoutput>
</cfif>
</cfif>
</cfoutput>
I got the output like this. when i look into the dump it shows correct result.
Home
> About US
> Services
can any help me out what should i do in the query or cfoutput to mark the child of child differently and to display it just below the parent?
here is my complete table structure with data http://sqlfiddle.com/#!2/a29fc/1/0. Thanks
I don't see where child is coming from, but what you need is a nested group output. This should get you on the right track. The biggest thing to watch is that your query is ordered in the order they should display on the screen. Your current SQL Fiddle isn't doing that part correctly.
<cfoutput query="d" group="parentid">
#d.parent#<br />
<cfoutput group="child"><!--- group based on child --->
> #d.child#<br /><!--- output child header --->
<cfoutput>
>> #d.child<br /><!--- all matching children for current d.child --->
</cfoutput>
</cfoutput>
</cfoutput>
This would output
Home
> About Us
>> Our Works
> Contact Us
Related
I have a CFQuery to pull data from a table which I would like to output to the screen in a format that groups the data according to one of the columns, 'Company Name'. I can't seem to wrap my head around the logic for this.
Currently I'm just looping through the data to output it to the screen and separating it by a horizontal rule tag. Not the best looking way to do it and it generates a really long list of results that the user needs to scroll through. I am hoping that by grouping the data, it will be more readable.
Here is my code:
<!--- Feedback Query --->
<cfquery name="getFeedback" datasource="#datasource#">
select ticket_id, service_satisfaction, customer_notes, response_date, company_name
from service_verification
order by company_name
</cfquery>
<br />
<cfoutput query="getFeedback" group="company_name"><strong>Company Name: #getFeedback.company_name#</strong><br />
<cfquery dbtype="query" name="parsed">
select company_name
from getFeedback
where company_name = '#getFeedback.company_name#'
</cfquery>
(#parsed.recordcount# Responses)<br />
<cfoutput>
Ticket Number: <cfif #getFeedback.ticket_id# eq 0>No ticket associated with this feedback. This was solicited feedback.<cfelse>#getFeedback.ticket_id#</cfif><br />
Date: #DateFormat(getFeedback.response_date, 'mm/dd/yyyy')# at #TimeFormat(getFeedback.response_date, 'hh:mm:ss')#<br /><br />
Rating: <cfif #getFeedback.service_satisfaction# eq 'thumbs-up'><img src="images/thumbs-up-small.png" /><cfelse><img src="images/thumbs-down-small.png" /></cfif><br />
Customer Notes: <cfif #getFeedback.customer_notes# eq ''>No additional comments provided.<cfelse>#getFeedback.customer_notes#</cfif><br /><br />
<hr style="border-top: 1px dashed ##8c8c8c;" />
</cfoutput>
<br />
</cfoutput>
Here is a sample of my CFDUMP from the above query:
company_name service_satisfaction response_date ticket_id customer_notes
1 AmerTech thumbs-up {ts '2014-10-22 10:25:14'} 22667 Jeff was great. thanks
2 AmerTech thumbs-up {ts '2015-01-20 12:02:34'} 23795 Rich was good. Thanks. He needs to send out a another drive that we would like as backup to take home at night. Also, he missed one machine for backups that I need to discuss. Have someone please call . Thanks
3 AmerTech, Inc thumbs-up {ts '2015-04-16 13:56:44'} 25066
4 AmerTech, Inc thumbs-down {ts '2015-10-22 11:23:40'} 27293 Brian, I understand from Dave that you could not solve the problem and that he had to call the OEM to solve the problem. This is what I was informed. I do not know any of the details surrounding the issue. but it shouldn't take that long to install a printer on a new laptop. Why did this occur and how do I make sure it doesn't happen again. thanks mark
5 AMIB thumbs-down {ts '2014-10-02 12:18:27'} 22463 Representative did not call me upon arrival at group home as instructed and implemented changes without approval from HR
6 AMIB thumbs-up {ts '2015-06-08 09:58:03'} 25599
7 AMIB thumbs-up {ts '2016-03-10 14:10:01'} 28777
8 AMIB thumbs-up {ts '2016-03-28 09:10:37'} 29193 Michael is a great tech! Extremely helpful and responsive to our needs!
9 AMIB thumbs-up {ts '2016-03-28 10:19:19'} 28777
Update:
When I add the group attribute to the cfoutput tag, it only shows the first result from the group
<cfloop query="getFeedback">
<cfoutput><cfoutput query="getFeedback" group="company_name">
Company Name: #getFeedback.company_name# <cfif #getFeedback.service_satisfaction# eq 'thumbs-up'><img src="images/thumbs-up-small.png" /><cfelse><img src="images/thumbs-down-small.png" /></cfif><br />
Ticket Number: <cfif #getFeedback.ticket_id# eq 0>No ticket associated with this feedback. This was solicited feedback.<cfelse>#getFeedback.ticket_id#</cfif><br />
Date: #DateFormat(getFeedback.response_date, 'mm/dd/yyyy')# at #TimeFormat(getFeedback.response_date, 'hh:mm:ss')#<br /><br />
Customer Notes: #getFeedback.customer_notes# <br /><br />
<br />
<hr></cfoutput>
</cfloop>
Get rid of the loop tag. Then use this:
<cfoutput query="getFeedback" group="company_name">
<!--- OUTPUT EACH GROUP --->
Company Name: #getFeedback.company_name# <cfif #getFeedback.service_satisfaction# eq 'thumbs-up'><img src="images/thumbs-up-small.png" /><cfelse><img src="images/thumbs-down-small.png" /></cfif><br />
<cfoutput>
<!--- OUTPUT EACH RECORD --->
Ticket Number: <cfif #getFeedback.ticket_id# eq 0>No ticket associated with this feedback. This was solicited feedback.<cfelse>#getFeedback.ticket_id#</cfif><br />
Date: #DateFormat(getFeedback.response_date, 'mm/dd/yyyy')# at #TimeFormat(getFeedback.response_date, 'hh:mm:ss')#<br /><br />
Customer Notes: #getFeedback.customer_notes# <br /><br />
<br />
</cfoutput>
<hr>
</cfoutput>
It's the second/nested CFOUTPUT tag that goes through each record.
Note the HR is within the GROUP, not each record.
If you want to get fancy, you can make this an accordion with jQuery. Each GROUP is the head, and each record is the contents.
Here is my final verson of the working code. Thanks #Leigh
<!--- Feedback Query --->
<cfquery name="getFeedback" datasource="#datasource#">
select ticket_id, service_satisfaction, customer_notes, response_date, company_name
from service_verification
order by company_name
</cfquery>
<br />
<cfoutput query="getFeedback" group="company_name">
<strong>Company Name: #getFeedback.company_name#</strong><br />
<cfquery dbtype="query" name="parsed">
select company_name
from getFeedback
where company_name = '#getFeedback.company_name#'
</cfquery>
(#parsed.recordcount# Responses)<br />
<cfoutput>
Ticket Number: <cfif getFeedback.ticket_id eq 0>No ticket associated with this feedback. This was solicited feedback.<cfelse>#getFeedback.ticket_id#</cfif><br />
Date: #DateFormat(getFeedback.response_date, 'mm/dd/yyyy')# at #TimeFormat(getFeedback.response_date, 'hh:mm:ss')#<br /><br />
Rating: <cfif getFeedback.service_satisfaction eq 'thumbs-up'><img src="images/thumbs-up-small.png" /><cfelse><img src="images/thumbs-down-small.png" /></cfif><br />
Customer Notes: <cfif getFeedback.customer_notes eq ''>No additional comments provided.<cfelse>#getFeedback.customer_notes#</cfif><br /><br />
<hr style="border-top: 1px dashed ##8c8c8c;" />
</cfoutput>
<br />
</cfoutput>
Lately I've been messing around with a ColdFusion forum script, and I'm trying to add pagination to it so that it only displays 10 comments per page instead of all of them. Sadly, I've only found complicated solutions to do this and no simple solution like I was used to in PHP. Currently, this is my code for getting the comments out of my database:
<cfquery name = "comments" datasource = "#DSN#">
SELECT *
FROM `forum_comments`
WHERE topicid = #id#
</cfquery>
Because I don't want to overload my processor while fetching 1000+ comments per topic, I want to seperate all the comments into pages of 10 comments per page. Is this possible with just some little modifications to my page? My best guess to do this is by using the URL.page statement and the LIMIT function in MySQL, but I have no idea how.
Update
All of my current code:
<cfif IsDefined('URL.page')> // Pagination
<cfset page = URL.page>
<cfelse>
<cfset page = 1>
</cfif>
<cfset howManyRecsToShow = 10>
<cfset startRec = page*howManyRecsToShow>
<cfquery name = "comments" datasource = "#DSN#"> // Get all comments
SELECT *
FROM `forum_comments`
WHERE topicid = #id#
LIMIT #startRec#, #howManyRecsToShow#
</cfquery>
<cfset colour ="post_uneven"> // Required for CSS
<cfloop query="comments"> // Loop over comments
<div id="post_text">
<div id="post_text_edit" title="Edit"></div>
<div id="post_text_delete" title="Delete"></div>
<div id="post_text_title">
RE: #gettopic.title#
</div>
<div id="post_text_date">
#DateFormat(dateAdd("s", comments.timestamp, "01/01/1970"))# #TimeFormat(dateAdd("s", comments.timestamp, "01/01/1970"))#
</div>
<div id="post_text_text">
#comments.text#
</div>
</div>
</div>
</cfloop>
</cfoutput>
<cfif colour is "post_uneven"><cfset colour="post_even"><cfelse><cfset colour="post_uneven"></cfif> // Required for CSS
<div id="topic_info_balk">
<div id="forum_paginas">
<cfif page gt 1>
PREVIOUS 10 |
</cfif>
NEXT 10
</div>
You said you want a SIMPLE example so here it is. By SIMPLE I mean this will just show NEXT and PREVIOUS links. If you want slightly more complicated pagination that shows the number of pages then you have to get the total record count before hand. (I quickly free-hand typed this, not on my CF server right now, so not sure if this is 100% accurate)...
(pageTest.cfm)
<cfif IsDefined("url.page")>
<cfset page = url.page>
<cfelse>
<cfset page = 1>
</cfif>
<cfset howManyRecsToShow = 10>
<cfset startRec = page*howManyRecsToShow>
<cfquery name="q1">
select id, username, email
from users
order by id limit #startRec# , #howManyRecsToShow#
</cfquery>
<cfoutput>
<table border="1">
<cfloop query="q1">
<tr>
<td>#q1.id#</td>
<td>#q1.username#</td>
<td>#q1.email#</td>
</tr>
</cfloop>
</table>
<cfif page gt 1>
PREVIOUS 10 |
</cfif>
NEXT 10
</cfoutput>
I've been trying to create my own forum script in ColdFusion, but sadly, it's a lot more difficult then I thought that it would be. I'm getting stuck when trying to display ALL the comments from the database, because ColdFusion throws me errors.
The following information is meant for the website developer for debugging purposes.
Error Occurred While Processing Request
Element USERNAME is undefined in REAGEER.
The error occured in C:/inetpub/wwwroot/content/1-Home/topicview.cfm: line 197
195:
196: <div id="pers_info">
197: #reageer.username# <cfif #reageer.online# is 1><img src="http://www.wonderhotel.nl/archive/icons/mini/habbo_online_anim.gif"></img><cfelse><img src="http://www.wonderhotel.nl/archive/icons/mini/habbo_offline.gif"></img></cfif></strong>
198: <p>Berichten: 55</p>
199:
The code I wrote for this script is the following:
<cfif IsDefined('URL.id') and URL.id neq ""> // Get the topic ID
<cfquery name = "comments" datasource = "#DSN#">
SELECT *
FROM `forum_comments`
WHERE topicid = #id#
</cfquery> // Get the comments
<cfif #comments.RecordCount# is 1>
<cfquery name = "reageer" datasource = "#DSN#">
SELECT *
FROM `users`
WHERE id = #comments.poster#
</cfquery> // Get the comment posters
</cfif>
<cfset colour ="post_uneven">
<cfloop query="comments">
<div id="#colour#">
<div id="pers_info">
#reageer.username# <cfif #reageer.online# is 1><img src="http://www.wonderhotel.nl/archive/icons/mini/habbo_online_anim.gif"></img><cfelse><img src="http://www.wonderhotel.nl/archive/icons/mini/habbo_offline.gif"></img></cfif>
<p>Berichten: 55</p>
<cfquery name = "reageer_badge_one" datasource = "#DSN#">
SELECT *
FROM `user_badges`
WHERE user_id = '#reageer.id#'
AND badge_slot = 1
</cfquery>
<cfquery name = "reageer_badge_second" datasource = "#DSN#">
SELECT *
FROM `user_badges`
WHERE user_id = '#reageer.id#'
AND badge_slot = 2
</cfquery>
<div id="pers_info_habbo">
<img src="http://habbo.nl/habbo-imaging/avatarimage?figure=#reageer.look#.gif">
</div>
<div id="pers_info_grbadge">
<cfif #reageer_badge_one.RecordCount# is 1>
<img src="http://wonderhotel.nl/Public/Images/badges/#reageer_badge_one.badge_id#.gif">
</cfif>
</div>
<div id="pers_info_badge">
<cfif #reageer_badge_second.RecordCount# is 1>
<img src="http://wonderhotel.nl/Public/Images/badges/#reageer_badge_second.badge_id#.gif">
</cfif>
</div>
<div id="pers_info_missie">
#reageer.motto#
</div>
</div>
<div id="post_text">
<div id="post_text_edit" title="Bericht aanpassen"></div>
<div id="post_text_delete" title="Bericht verwijderen"></div>
<div id="post_text_title">
RE: #gettopic.title#
</div>
<div id="post_text_date">
#DateFormat(dateAdd("s", comments.timestamp, "01/01/1970"))# #TimeFormat(dateAdd("s", comments.timestamp, "01/01/1970"))#
</div>
<div id="post_text_text">
#comments.text#
</div>
</div>
</div></div>
<cfif colour is "post_uneven"><cfset colour="post_even"><cfelse><cfset colour="post_uneven"></cfif>
</cfloop>
</cfoutput>
<div id="topic_info_balk"> // Useless
<div id="forum_paginas">
Bekijk pagina:
1
2
3
4
5
6
7
8
9
10
>>
</div>
<div id="reageer-topic">
Reageer
</div>
</div>
</div>
I really don't know what I'm doing wrong, and why ColdFusion gives me this error. I would appreciate all the help! My only guess is that ColdFusion tries to get all the data (again) from the poster of the first comment, but that would be wrong because I want to get comment 1, comment 2, and afterwards 3, 4, 5, etcetera.
Also, when adding the first comment to the topic, everything works fine. But after adding the second, I get the error that you can see above.
Regards,
Yannick
My guess is that since you have a <cfif> around the "reageer" query, the error is occurring because there is more than 1 comment, but the output for the username is not wrapped in a <cfif> as well. Therefore, ColdFusion is trying to get the value of username from a query that doesn't exist (because the <cfif> prevented it from executing), hence the error.
I have dynamic checkboxes that are generated as such
<cfset counter = 0>
<form name="setPermissions" class="setPermissions" action="" method="post">
<cfoutput>
<cfloop query="getUserAccess">
<input name="Meetings_#Counter#" type="checkbox" />
<cfset counter = counter + 1>
</cfloop>
</cfoutput>
</form>
The getUserAccess query has 6 rows, which means that 6 of these checkboxes will be outputted.
To read these and update the table respectively, I'm running the following query
<cfloop from="0" to="#getUserAccess.RecordCount#" index="i">
<cfquery datasource="#Request.dsn#">
UPDATE table SET
<cfif structKeyExists(FORM, 'Meetings_#i#')>
Meetings = <cfif FORM['Meetings_#i#'] EQ "on">1,<cfelse>0,</cfif>
</cfif>
WHERE ID = '#an_ID_that_is_specified#'
</cfquery>
</cfloop>
Apologies if this code isn't correct, it works when I'm running it on my page, but there are about 20 of these checkboxes being generated, so I've snipped my code so you can see only one.
Now, this code works great, when I check a box and submit the form, this code will update the database to set the value to 1.
The only problem is, when I uncheck the box, it won't change the value to a 0. This is where I am stuck. Why is it not changing the value to 0 when there is no on specified as a form value?
I've done a <cfdump> to see if anything was still being passed, but there isn't.
With all of the boxes ticked I get this dump
MEETINGS_0 on
MEETINGS_1 on
MEETINGS_2 on
MEETINGS_3 on
MEETINGS_4 on
MEETINGS_5 on
With some ticked, the ones which I haven't ticked are not showing up.
However the value is still not updating from a 1 to a 0.
Checkbox simply wont submit any value when unchecked (that's how it works). So your query should look closer to this:
UPDATE table SET
Meetings = <cfif structKeyExists(FORM, 'Meetings_#i#')>1,<cfelse>0,</cfif>
WHERE ID = '#an_ID_that_is_specified#'
Sergii already answered the original question. But just to throw another approach out there ...
You could also use lists. Assuming your id's are numeric, give all checkboxes the same name and store the original id's in a hidden field.
<cfoutput query="getUserAccess">
#meetingID#
<input name="SelectedMeetings" type="checkbox" value="#meetingID#" />
</cfoutput>
<cfoutput>
<input name="OriginalMeetings" type="hidden" value="#valueList(getUserAccess.meetingID)#" />
</cfoutput>
On the action page FORM.SelectedMeetings will contain a list of all ID's that were selected. Simply take the difference of the two lists to find ID's that were "de-selected".
<cfparam name="FORM.SelectedMeetings" default="" / >
<cfset FORM.DeSelectedMeetings = replaceList( FORM.OriginalMeetings
, FORM.SelectedMeetings
, "") />
Then you only need two queries to updates the database instead of six (or however many checkboxes you have). Obviously whichever method you choose, you should wrap all queries in a transaction to ensure they all succeed or fail together.
<cfif listLen(trim(FORM.selectedMeetings))>
<cfquery datasource="#Request.dsn#">
UPDATE table
SET Meetings = 1
WHERE ID IN (
<cfqueryparam value="#FORM.selectedMeetings#" list="true" cfsqltype="cf_sql_integer">
)
</cfquery>
</cfif>
<cfif listLen(trim(FORM.DeSelectedMeetings))>
<cfquery datasource="#Request.dsn#">
UPDATE table
SET Meetings = 0
WHERE ID IN (
<cfqueryparam value="#FORM.DeSelectedMeetings#" list="true" cfsqltype="cf_sql_integer">
)
</cfquery>
</cfif>
I have a search page with the following scenarios listed below. I was told using so many conditional statements degrades performance, but I don't know if any other way to achieve the same objective.
Search.cfm will processes a search made from a search bar present on all pages, with one search input (titleName).
If search.cfm is accessed manually (through URL not through using the simple search bar on all pages) it displays an advanced search form with three inputs (titleName, genreID, platformID (dynamically generated, but not in this example code) or it evaluates searchResponse variable and decides what part of the page to show.
If simple search/advanced search query is blank, has no results, or less than 3 characters it displays an error
If any successful search returns results, they come back normally. There is one function handling the queries.
The top-of-page logic is as follows:
<!---DEFINE DEFAULT STATE--->
<cfparam name="variables.searchResponse" default="">
<!---CHECK TO SEE IF SEARCH A FORM WAS SUBMITTED AND EXECUTE SEARCH IF IT WAS--->
<cfif IsDefined("Form.simpleSearch") AND Len(Trim(Form.titleName)) LTE 2>
<cfset variables.searchResponse = "invalidString">
<cfelseif IsDefined("Form.simpleSearch") AND Len(Trim(Form.titleName)) GTE 3>
<cfinvoke component="gz.cfcomp.search" method="searchTitles" titleName="#Form.titleName#" genreID="" platformID="" returnvariable="searchResult">
<cfset variables.searchResponse = "hasResult">
</cfif>
<!---CHECK IF ADVANCED SEARCH FORM WAS SUBMITTED--->
<cfif IsDefined("Form.advancedSearch") AND (Len(Trim(Form.titleName)) LTE 2 AND Len(Form.genreID) IS 0 AND Len(Form.platformID) IS 0)>
<cfset variables.searchResponse = "invalidString">
<cfelseif IsDefined("Form.advancedSearch") AND variables.searchResponse IS NOT "invalidString">
<cfinvoke component="gz.cfcomp.search" method="searchTitles" returnvariable="searchResult" titleName="#Form.titleName#" genreID="#Form.genreID#" platformID="#Form.platformID#">
<cfset variables.searchResponse = "hasResult">
</cfif>
<!---CHECK IF ANY RECORDS WERE FOUND--->
<cfif IsDefined("variables.searchResult") AND searchResult.RecordCount IS 0>
<cfset variables.searchResponse = "noResult">
</cfif>
I'm using the searchResponse variable to decide what the the page displays, based on the following scenarios:
<!---ALWAYS DISPLAY SIMPLE SEARCH BAR AS IT'S PART OF THE HEADER--->
<form name="simpleSearch" action="search.cfm" method="post">
<input type="hidden" name="simpleSearch" />
<input type="text" name="titleName" />
<input type="button" value="Search" onclick="form.submit()" />
</form>
<!---IF NO SEARCH WAS SUBMITTED DISPLAY DEFAULT FORM--->
<cfif searchResponse IS "">
<h1>Advanced Search</h1>
<!---DISPLAY FORM--->
<form name="advancedSearch" action="search.cfm" method="post">
<input type="hidden" name="advancedSearch" />
<input type="text" name="titleName" />
<input type="text" name="genreID" />
<input type="text" name="platformID" />
<input type="button" value="Search" onclick="form.submit()" />
</form>
</cfif>
<!---IF SEARCH IS BLANK OR LESS THAN 3 CHARACTERS DISPLAY ERROR MESSAGE--->
<cfif searchResponse IS "invalidString">
<cfoutput>
<h1>INVALID SEARCH</h1>
</cfoutput>
</cfif>
<!---IF SEARCH WAS MADE BUT NO RESULTS WERE FOUND--->
<cfif searchResponse IS "noResult">
<cfoutput>
<h1>NO RESULT FOUND</h1>
</cfoutput>
</cfif>
<!---IF SEARCH MADE AND RESULT WAS FOUND--->
<cfif searchResponse IS "hasResult">
<cfoutput>
<h1>Search Results</h1>
</cfoutput>
<cfoutput query="earchResult">
<!---DISPLAY QUERY DATA--->
</cfoutput>
</cfif>
Is my logic a) not efficient because my if statements/is there a better way to do this? And b) Can you see any scenarios where my code can break? I've tested it but I have not been able to find any issues with it. And I have no way of measuring performance. Any thoughts and ideas would be greatly appreciated.
Here is my function, for reference:
<!---SEARCH--->
<cffunction name="searchTitles" hint="This functions searches for a title based on multiple categories" access="public" output="false">
<cfargument name="titleName" required="no" type="string" hint="Search by title">
<cfargument name="genreID" required="no" type="string" hint="Search by genre">
<cfargument name="platformID" required="no" type="string" hint="Search by platform">
<!--- DEFINE LOCAL VARIABLES - NOTE VARIABLE NAME IS QUERY NAME --->
<cfset var searchResult = "">
<!---GET RESULTS--->
<cfquery name="searchResult" datasource="myDSN">
SELECT
games.gameID,
games.gameReleaseDate AS rDate,
titles.titleName AS tName,
titles.titleShortDescription AS sDesc,
platforms.platformName AS pName,
genres.genreName AS gName
FROM
games
INNER JOIN titles ON titles.titleID = games.titleID
INNER JOIN platforms ON games.platformID = platforms.platformID
INNER JOIN genres ON games.genreID = genres.genreID
WHERE
0=0
<cfif ARGUMENTS.titleName IS NOT "">
AND titles.titleName LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="%#ARGUMENTS.titleName#%">
</cfif>
<cfif ARGUMENTS.genreID IS NOT "">
AND games.genreID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#ARGUMENTS.genreID#">
</cfif>
<cfif ARGUMENTS.platformID IS NOT "">
AND games.platformID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#ARGUMENTS.platformID#">
</cfif>
ORDER BY
rDate DESC,
tName;
</cfquery>
<cfreturn searchResult>
</cffunction>
Many thanks
If you add default values of "" to your genreID and platformID arguments, then I think you can refactor your top code to:
<cfif StructKeyExists(url, "titleName") and Len(Trim(url.titleName)) lte 2>
<cfset variables.searchResponse = "invalidString">
<cfelseif StructKeyExists(url, "titleName")>
<cfinvoke component="gz.cfcomp.search" method="searchTitles" returnvariable="searchResult" argumentcollection="#url#">
<cfset variables.searchResponse = "hasResult">
</cfif>
<cfif searchResponse eq "hasResult" and searchResult.recordCount eq 0>
<cfset variables.searchResponse = "noResult">
</cfif>
Note: I recommend switching your form methods to "get" for a search like this to improve the user's experience navigating your site. I've switched all the form references to url in the code.
Have you thought about using a Full-Text search rather than just specific things like title, genre and platform? Full text is much faster that a normal table query at the cost of a bit more disk space usage, and allows very flexible Google style searches on all your data. Have a look at the link below.
http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
Perhaps if you did this, you could just implement a pass though user input to the Full text search, since it provides all the advanced search expressions through it's own syntax. By doing this you probably would not need to branch your front end logic based on what they are searching for, this would make the solution cleaner and faster.
Just a preference I suppose, but since the advent of Google, people expect the one search box to do everything. You could provide some advanced search capabilities directly from the simple box by testing the input and conditionally running separate queries and returning the combined results. To make the results clearer you can highlight the matching portion with Coldfusion or javascript.
I would also init the component rather than using cfinvoke multiple times, but I'm not sure if that's a requirement or a preference.
<!--- By setting a default, we don't have to test for this var's existence repeatedly --->
<cfparam name="form.simpleSearch" default="" />
<cfscript>
// Using cfscript for compactness in this little box, could use tag based cf also
// Init myComponent so that it's ready to receive searches
searcher = createObject('component','myComponent');
// init query results
simpleResult = queryNew("id");
genres = queryNew("id");
platforms = queryNew("id");
titles = queryNew("id");
// q: shorthand 'Query' var that's trimmed and prechecked for length
q = "";
if (len(trim(form.simpleSearch)) GTE 3) {
q = trim(form.simpleSearch);
}
// Run simple search - Should returns a query object regardless of result count
if (len(q) {
simpleResult = searcher.simpleSearch(q);
/* Not sure what the difference between this and simpleSearch() is unless
this only looks for exact matches, and simpleSearch() uses LIKE and %
wildcards for looser results. */
titles = searcher.titleSearch(q);
/* Conditionally run advanced searches
- assumes that genreID and platformID are numeric
- IF genreID and platformID are not numeric, you could use regex to test for their signature or just run them anyway knowing they wouldn't match in many cases. (BUT you must, must MUST use cfqueryparam if you attempt that)
- Requires that advancedSearch is split into three separate functions
- Alternately, the simpleSearch(q) or advancedSearch() could do this all internally
- All of these functions should return an empty query if no results are found
if (isNumeric(q)) {
genres = searcher.genreSearch(q);
platforms = searcher.platformSearch(q);
}
}
</cfscript>
...
<!---ALWAYS DISPLAY SIMPLE SEARCH BAR AS IT'S PART OF THE HEADER--->
<cfoutput>
<form action="#cgi.script_name#" method="post">
<input type="text" name="simpleSearch" value="#form.q#" />
<input type="submit" value="Search" name="submit" />
</form>
<cfif titles.recordcount>
<h3>Matching Titles</h3>
<cfloop query="titles">
..html to output the titles
</cfloop>
</cfif>
<cfif genres.recordcount>
<h3>Matching Genres</h3>
<cfloop query="genres">
..html to output the genres
</cfloop>
</cfif>
<cfif platforms.recordcount>
<h3>Matching Platforms</h3>
<cfloop query="platforms">
..html to output the platforms
</cfloop>
</cfif>
<cfif simpleResult.recordcount>
<h3>Results</h3>
<cfloop query="simpleResult">
..html to output the simpleResult
</cfloop>
</cfif>
</cfouput>
Granted, there are many, many different ways to do this. This is simply one method to reduce the complexity of a simple search vs an advanced search. The advanced results would only be shown if they had a match and you can tune those results with your query inside your myComponent function - just remember to return a blank query if there is no result.
My coworkers told me, that we should simplify the CFIF-Statements:
From 'CFIF something EQ ""' we moved to 'CFIF Not Len(something)' and we work more with booleans for NoResult and HasResult we would use a boolean.
Anyway, the other answers are some great inspiration, I need to check my own search page ;)