I am trying to cache a block of code that instantiates two objects (the primary object extends the generic abstract one.
Without the cache-specific code everything works fine. But when I run the below code I only get a blank page. I'm unsure if this is expected behavior but I doubt it.
I'm calling this like so:
test.cfm
<cfset foobar = CreateObject("foo") />
<cfset foobar.pushLeads(
a = 1,
b = 2
) />
foo.cfc
<cffunction name="pushLeads" access="public" returntype="void">
<cfargument name="a" required="true" />
<cfargument name="b" required="true" />
<cfset local.cachedVendorData = cacheGet("vendorExport") />
<cfif IsNull(local.cachedVendorData)>
<cfsavecontent variable="local.vendorCFC">
<cfset local.leadsObj = createobject("baz").init() />
<!--- Take leads and pass into cfc for pushing to remote server --->
<cfset test = local.leadsObj.pushLeadData(
a = arguments.a,
b = arguments.b
) />
<cfdump var="#test#">
</cfsavecontent>
<cfoutput>#local.vendorCFC#</cfoutput>
<cfset cachePut("vendorExport", local.vendorCFC, CreateTimeSpan(0,0,1,0))>
</cfif>
</cffunction>
Edit - I forgot to add before that, before caching I had a CFDUMP that would show all results returned. Now that I added caching the dump results are not appearing.
Related
I am looping over a query, building an array of structures
<cffunction name="QueryConvert" returntype="any" output="false">
<cfargument name="q" type="query" required="yes">
<cfargument name="page" type="numeric" required="no" default="1">
<cfargument name="rows" type="numeric" required="no" default="500">
<cfset var result = structnew()>
<cfset var rowStruct = structnew()>
<cfset var col = "">
<cfset result["page"] = arguments.page>
<cfset result["total"] = ceiling(arguments.q.TotalrecordCount/arguments.rows)>
<cfset result["records"] = arguments.q.TotalrecordCount>
<cfset result["rows"] = arraynew(1)>
<cfset queryDeleteColumn(arguments.q,'TotalrecordCount')>
<cfset queryDeleteColumn(arguments.q,'rowNum')>
<cfset columnLabels = QueryColumnArray(arguments.q)>
<cfset rowStruct = [:]><!--- Tada an ordered struct --->
<cfloop array="#columnLabels#" item="col">
<cfset rowStruct[col] = q["#col#"]>
</cfloop>
<cfdump var="#result#" abort>
<cfreturn result />
</cffunction>
but when I view the nested structures, the order of the keys is all mixed up. I expected them to match the order of the column names in the database table.
The short answer is you need to use a ordered struct. The long version looks like this:
First we need to look at some sample data
<cfscript>
q = queryNew("id,name,category","Integer,Varchar,Varchar",
[{id=1, name="One", category="Cat"},{id=2, name="Two", category="Dog"}]
);
writedump(q);
</cfscript>
Let's look at out sample data. Note that the columns are not as expected.
Now let's get our columnLabels ready to go. Note that we are creating an array.
</cfscript>
result.rows = [];
columnLabels = q.getMeta().getColumnLabels();
writedump(columnLabels);
</cfscript>
<cfloop query="q">
<cfset rowStruct = [:]><!--- Tada an ordered struct --->
<cfloop array="#columnLabels#" item="col">
<cfset rowStruct[col] = q["#col#"]>
</cfloop>
<cfset arrayappend(result.rows, rowStruct)>
</cfloop>
<cfdump var="#result.rows#">
Tada
Furthermore
This is all easier to read with cfscript
<cfscript>
for (row in q) {
rowStruct = [:];
for (col in columnLabels) {
rowStruct[col] = q["#col#"];
}
result.rows.append(rowStruct);
}
</cfscript>
For a live version see: CFFiddle.com
i to come out two string using struct but the data are not in ascending order. Besides that, i also want to for loop it using from to like loop from 1 to 50 but i only know to for loop using the array dunno how to for loop the struct. Anyone can help? I am in rush to finish it. TQ.
My code code is like below
<cfprocessingdirective pageEncoding="utf-8" />
<cfset lang = structNew() />
<cfset lang.ch = structNew() />
<cfset lang.en = structNew() />
<cfset lang["ch"]["dealer1"] = "代理 1">
<cfset lang["ch"]["dealer2"] = "代理 2">
<cfset lang["ch"]["dealer3"] = "代理 3">
<cfset lang["ch"]["dealer4"] = "代理 4">
......
<cfset lang["en"]["dealer1"] = "Dealer 1">
<cfset lang["en"]["dealer2"] = "Dealer 2">
<cfset lang["en"]["dealer3"] = "Dealer 3">
<cfset lang["en"]["dealer4"] = "Dealer 4">
.....
If you are using the latest release of ColdFusion, ColdFusion 2016, you can use structNew("ordered").
For ColdFusion 11 or earlier...
You can maintain order of your structures by using Java's LinkedHashMap. One difference though is that LinkedHashMap is case sensitive so when defining a struct within a struct, you must use bracket notation (ie: struct1["struct2"]). It's good to also note that you can treat them much like a CFML structure in that you can use functions like structKeyExists() etc. on them.
<cfset LinkedHashMap = createObject("java", "java.util.LinkedHashMap") />
<cfset lang = LinkedHashMap.init() />
<cfset lang["ch"] = LinkedHashMap.init() />
<cfset lang["en"] = LinkedHashMap.init() />
<cfset lang["ch"]["dealer1"] = "代理 1">
<cfset lang["ch"]["dealer2"] = "代理 2">
<cfset lang["ch"]["dealer3"] = "代理 3">
<cfset lang["ch"]["dealer4"] = "代理 4">
<cfset lang["en"]["dealer1"] = "Dealer 1">
<cfset lang["en"]["dealer2"] = "Dealer 2">
<cfset lang["en"]["dealer3"] = "Dealer 3">
<cfset lang["en"]["dealer4"] = "Dealer 4">
<!--- Example to see structure --->
<cfdump var="#lang#">
To loop over a structure, you can use the collection and item attributes...
<!--- Loop Example --->
<h3>CH Dealers</h3>
<cfloop collection="#lang['ch']#" item="dealer">
<cfoutput><li>#dealer#: #lang['ch'][dealer]#</li></cfoutput>
</cfloop>
<h3>EN Dealers</h3>
<cfloop collection="#lang['en']#" item="dealer">
<cfoutput><li>#dealer#: #lang['en'][dealer]#</li></cfoutput>
</cfloop>
You can test the above example at trycf.com -> http://trycf.com/gist/c54d309a6012c97cb29a
I have a website that I need to redirect almost everything to another domain, except for a few directories/paths. The server is running ColdFusion and IIS in a hosting environment.
Functionality:
a) http://example1.com redirects to http://example2.com
b) http://example1.com/special stays put
c) http://example1.com/anydir redirects to http://example2.com
Any suggestions for how I can accomplish this?
I considered doing it in ColdFusion, but this won't handle case c). URL Rewrite in IIS isn't possible, because this is a limitation in the hosting provider.
edit:
I just realized that the functionality above does not explicitly state this case:
d) http://example1.com/anydir/anydir redirects to http://example2.com
I created this a while back to redirect an existing application from an old path to its new path. I believe it relies on subfolders to be in existence, for example "anydir/anydir/" must actually be real folders. I essentially just paste it into an existing application folder so config, application and index files are overwritten and then redirects take place based on definitions in config.
The redirect definitions are regex so can actually get quite complicated if necessary. It is an ordered array so you can put more specific redirects first and the more general ones at the end. You can either include a "last resort" redirect at the end or allow an error to occur if no definitions match--just depends on how precise you want to be.
config/config.cfm
<cfset config = {
debug=true
, redirects = [
{find="^/path/temp/dir2/(.+)$", replace="http://temp.domain.com/dir2\1"}
, {find="^/path/temp/(.+)$", replace="http://temp.domain.com/\1"}
]
} />
index.cfm
[blank file]
Application.cfc
<cfcomponent>
<cfset this.name="Redirect#hash(getCurrentTemplatePath())#"/>
<cfinclude template="config/config.cfm" />
<cffunction name="onRequestStart">
<cfset redirect(cgi.path_info) />
</cffunction>
<cffunction name="onMissingTemplate">
<cfargument name="targetPage" required="true" />
<cfset redirect(arguments.targetPage) />
</cffunction>
<cffunction name="redirect">
<cfargument name="targetPage" required="true" />
<cfset var i = 0 />
<cfset var newpath = "" />
<cfloop from="1" to="#arraylen(variables.config.redirects)#" index="i">
<cfif refindnocase(variables.config.redirects[i].find, arguments.targetPage)>
<cfset newpath = rereplacenocase(arguments.targetPage, variables.config.redirects[i].find, variables.config.redirects[i].replace) />
<cfif len(cgi.query_string)>
<cfset newpath &= "?" & cgi.query_string />
</cfif>
<cfif variables.config.debug>
<cfoutput>#newpath#</cfoutput>
<cfabort>
</cfif>
<cflocation url="#newpath#" addtoken="false" />
</cfif>
</cfloop>
<cfthrow type="custom.redirect.notfound" />
<cfabort>
</cffunction>
</cfcomponent>
You're better handling redirects with the server if you can, but if you can you could do it with CF with something like this.. how you structure really depends on what the actual URLs you need to handle are..
You could likely handle case (c) with Regular Expressions..
<!---get the current URL--->
<cfset currentURL = "#cgi.server_name##cgi.path_info#" >
<!---based on the URL, redirect accordingly--->
<cfif FindNoCase("example1.com/special", currentURL)>
<!---do nothing--->
<cfelseif FindNoCase("example1.com", currentURL)>
<cflocation url="http://www.example2.com" >
</cfif>
I have the following code
<cffunction name="getObjTag" returnType="string" output="false">
<cfargument name="obj" Type="string" required="true">
<cfargument name="tagname" Type="string" required="true">
<cfreturn obj.split("<" & tagname.toUpperCase() & ">")[2]>
</cffunction>
Which results in the following error
Invalid CFML construct found on line 96 at column 63.
ColdFusion was looking at the following text:
[
The CFML compiler was processing:
A cfreturn tag beginning on line 96, column 10.
A cfreturn tag beginning on line 96, column 10.
Why is this? This happens on compile, not run.
CF 9 added the ability to access the results of the split as an array directly from the function call. The following works as expected on my local install of 9.0.1:
<cfset foo = "this is a string" />
<cfdump var="#foo.split(" ")[1]#" />
The dump shows 'this' in this example.
CF can't access the results of the split as an array directly from the function call. You need an intermediate variable.
<cfset var tmpArray = arrayNew(1)/>
<cfset tmpArray = arguments.obj.split("<" & arguments.tagname.toUpperCase() & ">")/>
<cfif arrayLen(tmpArray) gt 1>
<cfreturn tmpArray[2]/>
<cfelse>
<cfreturn ""/>
</cfif>
You also need to watch your indexes. Although the java array underneath is 0 index'ed, using coldfusion to get at it makes it indexed by 1.
I have tried to use ColdFusion 9 to build search engine in my site. The key is Verity which I read it is the best tool to do the indexing and searching in my database content.
But I search around with no luck about any tutorial to tell me how to done this, even a tutorial is missing, or I think I don't found it.
I am using ColdFusion 9 with MySQL server. Could you advice me how to do this? or any tutorial, article, or e-book is also welcome.
Actually, you have two great engines for CF9: Verity (classic) and Solr (modern).
Both of them implement the idea of collections. Creating and maintanence of the collection is pretty obvious and can be found in manual (see previous links).
The main hint for you can be found on cfindex tag manual page: you can populate (update) the collection with query data. Set type custom, enter the query name and all columns you need (combinations may vary).
All you need after that is to use cfsearch.
Also I can recommend to set up the script executed by scheduler to refresh your collection periodically.
EDIT
Sample code (note: code not tested, just the simplified cut from my old component). These are two methods of the CFC.
<cffunction name="index" access="public" returntype="any" output="true" hint="Rebuild search index">
<cfargument name="collection" type="string" required="true" hint="Target collection name">
<cfset var local = {} />
<cftry>
<!--- pull the content --->
<cfquery datasource="#variables.dsn#" name="local.getContent">
SELECT C.id, C.title, C.content, P.name AS page
FROM #variables.tableContent# C
INNER JOIN #variables.tablePages# P
ON C.id_page = P.id
</cfquery>
<!--- update collection --->
<cflock name="cfindex_lock" type="exclusive" timeout="30">
<cfindex collection="#arguments.collection#"
action="refresh"
type="custom"
query="local.getContent"
key="id"
custom1="page"
title="title"
body="title,content"
>
</cflock>
<cfreturn true />
<cfcatch type="any">
<!--- custom error handler here --->
<cfreturn false />
</cfcatch>
</cftry>
</cffunction>
<cffunction name="search" access="public" returntype="any" output="true" hint="Perform search through the collection">
<cfargument name="collection" type="string" required="true" hint="Target collection name">
<cfargument name="type" type="string" required="true" hint="Search type">
<cfargument name="criteria" type="string" required="true" hint="Search criteria">
<cfargument name="startrow" type="numeric" required="false" default="1" hint="Select offset">
<cfargument name="maxrows" type="numeric" required="false" default="50" hint="Select items count">
<cfset var local = {} />
<cftry>
<!--- pull the data from collection --->
<cfsearch collection="#arguments.collection#"
name="local.searchResults"
type="#arguments.type#"
criteria="#LCase(arguments.criteria)#"
startrow="#arguments.startrow#"
maxrows="#arguments.maxrows#"
>
<cfset local.resultsArray = [] />
<!--- convert data into the array --->
<cfloop query="local.searchResults">
<cfscript>
local.res = StructNew();
local.res["id"] = local.searchResults.key;
local.res["summary"] = Left(local.searchResults.summary, 500) & "...";
// highlight the search phrase
local.res["summary"] = ReplaceNoCase(local.res["summary"], arguments.criteria, "<strong>" & arguments.criteria & "</strong>", "ALL");
local.res["page"] = local.searchResults.custom1;
local.res["title"] = local.searchResults.title;
ArrayAppend(local.resultsArray, local.res);
</cfscript>
</cfloop>
<cfreturn local.resultsArray />
<cfcatch type="any">
<!--- custom error handler here --->
<cfreturn false />
</cfcatch>
</cftry>
</cffunction>