cfwheels nested properties issue - coldfusion

I'm trying to get this to work...
I have a five tables that I"m trying to tie together: properties, languages, propertyLanguages, buildings and buildingTranslations
properties,languages and propertylanguages is a typical many-to-many relationship that I have working. What I'm trying to do next is have the buildings, which are linked to the property and have text fields for each language that will go inside the buildingtranslations.
I've setup the foreign keys for the propertylanguages, buildings and buildingtranslations
I'm just not sure how to setup the model and the controller when creating/updating building records
edit
I've managed to create a view in mssql that represents the relationship
hopefully this makes it easier to see the relationships.
I want to create and edit Buildings with the translation fields included (and updated in the database)
The languages are assigned at the property level. The building that is linked to the property through the propertyid uses the languages available (through propertylanguages[where propertyid = building.propertyid]) to determine the buildingTranslations required for the building

Hopefully this helps some:
models/Building.cfc
hasMany(name="BuildingTranslations", foreignKey="yrhBuildingId");
belongsTo(name="Property", foreignKey="yrhPropertyId");
controllers/Buildings.cfc
function new () {
building = model("Building").new();
building.yrhPropertyId = params.yrhPropertyId; //assuming this was passed in
requiredLanguages = model("PropertyLanguages").findAll(where="yhrPropertyId=#building.yhrPropertyId#");
}
function create () {
building = model("Building").new(params.Building);
building.save();
requiredLanguages = model("PropertyLanguages").findAll(where="yhrPropertyId=#building.yhrPropertyId#");
for (var i = 1; i <= requiredLanguages.recordCount; i++)
{
buildingTranslation = model("BuildingTranslation").new();
buildingTranslation.yrhBuildingId = building.id;
buildingTranslation.yrhLanguageId = requiredLanguages.yrhLanguageId[i];
buildingTranslation.langName = params.BuildingTranslations[requiredLanguages.yrhLanguageId[i]];
buildingTranslation.save();
}
redirectTo(action="list");
}

here's the approach I've taken
<cfset viewBuildingNames = model("yrhBuildingNamesView").findAll(where="yrhBuildingId=#params.key#")> <!--- FIND ALL BUILDING NAMES --->
<cfset yrhbuilding = model("Yrhbuilding").findByKey(key=params.key)> <!--- CREATE BUILDING MODEL --->
<cfset yrhproperty = model("YrhProperty").findByKey(key=yrhbuilding.yrhPropertyId, include="YrhPropertyLanguages")> <!--- language info through property--->
<cfset yrhbuilding.yrhproperty = yrhproperty>
<cfset yrhbuilding.yrhBuildingTranslations = ArrayNew(1)>
<cfloop query="viewBuildingNames">
<cfset yrhBuildingTranslation = model("yrhBuildingTranslation").new(yrhBuildingId=#yrhBuildingId#, yrhLanguageId=#yrhLanguageId#, langName=#LANGNAME#)>
<cfset ArrayAppend(yrhbuilding.yrhBuildingTranslations, yrhBuildingTranslation)>
</cfloop>
it's sort of half cfwheels way. it relies on the view created in the database
once the mode; is created, the updating works, but I don't get an error message on the empty langNames, just an error, Which I can live with.
I'm planning on adding another layer of items residing under the building, that will require the same connection to the propertyLanguages, While it should still work OK I'm getting increasingly queasy about the cfwheels magic taking care of these things. I might be switching to handling complex relationships directly.

Related

cfinvoke with two different methods

I have two cfinvoke, I need to use them in one cfm
<cfinvoke component="cfc/queries" method="getProjects" searchString="#Session.Auth.pref_name#" view="#Session.Auth.view#" returnvariable="Projects">
<cfinvoke component="cfc/queries" method="projectDetails" searchString="#URL.id#" projectsuffix="#URL.suffix#" returnvariable="Details">
to return two queries, but when I coding like this way it's not working.
I'm still new to the ColdFusion and I don't know how to fix that.
Since both functions are in the same CFC, you wouldn't want to use cfinvoke since it recreates the object each time it's called. Instead, use a new or a createObject().
<cfset queries = new location.to.cfc.queriesCFC()>
Then you can just reference the functions.
<cfset Projects =
queries.getProjects(
searchString=session.Auth.pref_name,
view = session.Auth.view
)
>
<cfset Details =
queries.projectDetails(
searchString=url.id,
projectsuffix=url.suffix
)
>
You may want to sanitize url.id and url.suffix before you pass them through. This will help with injection issues.
What does getProjects() do?
We can write like as below,
<!--- Object creation --->
<cfset query = CreateObject("component", "cfc.queries")/>
<!--- Function call --->
<cfset Projects = query.getProjects( searchString = session.Auth.pref_name, view = session.Auth.view )>
<cfset Details = query.projectDetails( searchString = session.Auth.pref_name, view = session.Auth.view )>

Best way to dynamically set host server in ColdFusion 10

I use the following to dynamically detect the host server. The importance for making it dynamic is that currently there are too many hard coded redirect such as:
http:s//mysite.com/hr/index.cfm
within my app.
When I'm moving from production site to development site and then back to production site, I have to manually change/comment out this http/https one by one and it is not only time consuming but also dangerous.
Here is the code I found that can detect the host server. Then I do the following:
<CFSET inet = CreateObject("java", "java.net.InetAddress")>
<CFSET inet = inet.getLocalHost()>
<CFSET HostServer = "#inet.getHostName()#">
<CFSET ThisHostServer = "#LEFT(HostServer,6)#">
<CFSWITCH expression="#Trim(ThisHostServer)#"><!--- Prod or Dev server --->
<CFCASE value="myprodsite.com">
<CFSET UseThisURL = "http://myprodsite.com">
</CFCASE>
<CFCASE value="mydevsite.com">
<CFSET UseThisURL = "http://myDevsite.com">
</CFCASE>
</CFSWITCH>
Then on each page where links or redirection exist, I just need to use:
#UseThisURL#/hr/index.cfm
My question is:
Where is the best way to set #UseThisURL# in the application?
I'm using ColdFusion 10 and Application.cfc in Linux env.
Should I set it as an application or a session scope?
Since everything will be in an application or session scope, when users are idle on a certain page and the application/session scope is expired, when user click on a link will it generate an error? How to prevent users from seeing error caused by using this technique? Please advice, thank you!
Best practice that I used is creating config.cfc which can contain function like getServerSpecificVariables() to return structure. this structure will be saved in your application scope since you don't want to create USEThisURL for every session start. When you need to reset simply clear your application scope. instantiate below config component inside onApplicationStart event in Application.cfc
Example
Config.cfc:
component{
public struct function getServerSpeceficVariables(){
var config = {};
var inet = CreateObject("java", "java.net.InetAddress");
inet = inet.getLocalHost();
HostServer = inet.getHostName();
ThisHostServer = LEFT(HostServer,6);
switch(Trim(ThisHostServer)){
case 'myprodsite.com':{
config.useThisURL = '';
break;
}
case 'mydevsite.com':{
config.useThisURL = '';
break;
}
}
return config;
}
}

ColdFusion: Trying to query database in CFScript

My boss wants me to use cfscript instead of tags for database interaction. Does anybody know of any good tutorials? I bought the Adobe ColdFusion application development book, vol 2. But it does not have much on scripting. I did google and found this site, but it did not explain much.
Does any body know of any good tutorials on accessing the data base in CFScript?
Basically I have to convert the following to using CFScript:
<cfquery name="drafts" datasource="ICEchat">
SELECT * from Messages where IsTemp=1 and LinkA=#FORM.LinkA# and LinkB=#FORM.LinkA#
</cfquery>
<cfif drafts.recordcount GT '0'>
<cfquery name="Attachments" datasource="ICEchat">
SELECT * FROM Attachments where id=2
</cfquery>
{ Message:"<cfoutput query="drafts">#Message#</cfoutput>", Attachments:[<cfoutput query="attachments">
"#url#"<cfif attachments.currentRow LT attachments.recordcount>,</cfif>
</cfoutput>]}
<cfelse>
<cfquery name="addrecord" datasource="ICEchat">
INSERT INTO Messages
VALUES(1,1,' ',1)
</cfquery>
{ Message:"NA", Attachments:[]}
</cfif>
From the 4th link on google for "cfscript query tutorial":
<CFSCRIPT>
myQry = new Query(); // new query object
myQry.setSQL("select bookid, title, genre from app.books where bookid = :bookid"); //set query
myQry.addParam(name="bookid",value="5",CFSQLTYPE="CF_SQL_INTEGER"); // add query param
qryRes = myQry.execute(); // execute query
writedump(qryRes.getResult().recordcount, true); // get resultcount
writedump(qryRes.getResult(), false); // dump result
writeoutput('<BR>');
</CFSCRIPT>
That ought to tell you everything you need to know.
Also, you really should not be creating JSON manually, no matter how simple it is. Use serializeJson().
Didn't test this, but this should do it.
<cfscript>
local.drafts = new Query();
local.drafts.setDatasource("ICEchat");
local.drafts.addParam(name="linkA", value="#form.linkA#", cfsqltype="CF_SQL_VARCHAR");
local.drafts.addParam(name="linkB", value="#form.linkB#", cfsqltype="CF_SQL_VARCHAR");
local.drafts.setSQL("SELECT * from Messages where IsTemp=1 and LinkA = :linkA and LinkB = :linkA");
local.drafts.execute().getResult();
if (local.drafts.recordcount GT 0) {
local.attachments = new Query();
local.attachments.setDatasource("ICEchat");
local.attachments.setSQL("SELECT * FROM Attachments where id=2");
local.attachments.execute().getResult();
WriteOutput("{ Message: ");
for (i=1; i LTE local.drafts.recordcount; i=i+1) {
WriteOutput(local.drafts.message[i]);
}
WriteOutput(", Attachments: ");
for (i=1; i LTE local.attachments.recordcount; i=i+1) {
WriteOutput(local.drafts.url[i]);
if (i LT local.attachments.recordcount) {
WriteOutput(", ");
}
}
WriteOutput("}");
} else {
local.q = new Query();
local.q.setDatasource("ICEchat");
local.q.setSQL("INSERT INTO Messages VALUES(1,1,' ',1)");
local.q.execute();
WriteOutput("{ Message:"NA", Attachments:[]}");
}
</cfscript>
I have been searching for a solution for the same error. I get not defined errors or construct errors. Have been chatting with Ray Camden for the past day, but everything he has suggested is not doing what I need either. I have been working on a website conversion from the standard CF tags to cfscript.
Ray suggested that the .execute(); is what pulls the recordcount and suggested this is all was needed: x=queryExecute(); would fetch the recordcount, with (x) being the query. He suggested not to use getPrefix(); but I read that the .getPrefix(); is what pulls the recordcount. He is experienced I am sure you know Ray Camden, but I keep getting the same error no matter what I try doing inside of my code.

Best practice for Datasource use in a CFC

I have an application which uses context sensitive datasources. Currently I keep the datasource information stored a such
reqeust.DB.Datasource = "DatasourceName";
request.DB.Username = "DatasourceUsername"
request.DB.Password = "DatasourcePassword"
I then overwrite the variables depending on the context, so each cfquery tag has the attributes datasource="#request.DB.Datesource#" ... etc ...
I want to start moving to more CFC centric frameworks like Coldbox, but I just don't see how this would work.
Do I need to pass in a datasource object into the init statement of the CFC? This seems like it would be a super PITA.
With CF9, you can this.datasource in Application.cfc as the default datasource. Unfortunately, it doesn't seem to have a way to set username/password
Either
A.) use an Dependency Injection framework such as ColdSpring (only suitable for singleton Services), Lightwire or Coldbox's own DI solution (Wirebox). and inject the datasource/username/password through the init constructor or setters.
B.) set <Datasources> in Coldbox.xml.cfm, see: http://wiki.coldbox.org/wiki/ConfigurationFile.cfm
<!--Datasource Setup, you can then retreive a datasourceBean
via the getDatasource("name") method: -->
<Datasources>
<Datasource alias="MyDSNAlias"
name="real_dsn_name"
dbtype="mysql"
username=""
password="" />
</Datasources>
Even if your objects only get initialized at request level, it seems like it should be less of a pain to work with in this fashion.
<cfscript>
request.DB.Datasource = "DatasourceName";
request.DB.Username = "DatasourceUsername";
request.DB.Password = "DatasourcePassword";
request.randomDAO = createObject('component','DAOStuff.randomDAO');
request.randomDAO.init(DBObject = request.DB);
request.someQuery = request.randomDAO.someGetter();
request.someOtherQuery = request.randomDAO.someOtherGetter();
request.aThirdQuery = request.randomDAO.aThirdGetter();
</cfscript>
As opposed to:
<cfscript>
request.DB.Datasource = "DatasourceName";
request.DB.Username = "DatasourceUsername";
request.DB.Password = "DatasourcePassword";
</cfscript>
<cfquery name="request.someQuery"
datasource=request.DB.Datasource
username=request.DB.Username
password=request.DB.Password>
--SOME SQL HERE
</cfquery>
<cfquery name="request.someOtherQuery"
datasource=request.DB.Datasource
username=request.DB.Username
password=request.DB.Password>
--SOME SQL HERE
</cfquery>
<cfquery name="request.aThirdQuery"
datasource=request.DB.Datasource
username=request.DB.Username
password=request.DB.Password>
--SOME SQL HERE
</cfquery>
If it is safe for your data objects to exist at an application level (assuming here that the data source for the object will not change at run-time and that you have written thread-safe CFCs) You can store and initialize DAOs at application level and then each request has wonderfully simple code like:
<cfscript>
request.someQuery = application.randomDAO.someGetter();
request.someOtherQuery = application.randomDAO.someOtherGetter();
request.aThirdQuery = application.randomDAO.aThirdGetter();
</cfscript>

access JRUN jndi environment vaiables from coldfusion (java)

I want to put some instance specific configuration information in JNDI. I looked at the information here:
http://www.adobe.com/support/jrun/working_jrun/jrun4_jndi_and_j2ee_enc/jrun4_jndi_and_j2ee_enc03.html
I have added this node to the web.xml:
<env-entry>
<description>Administrator e-mail address</description>
<env-entry-name>adminemail</env-entry-name>
<env-entry-value>admin#mystore.com</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
In coldfusion I have tried several different approaches to querying the data:
<cfset ctx = createobject("java","javax.naming.InitialContext") >
<cfset val = ctx.lookup("java:comp/env") >
That lookup returns a jrun.naming.JRunNamingContext. If i preform a lookup on ctx for the specific binding I am adding I get an error.
<cfset val = ctx.lookup("java:comp/env/adminemail") >
No such binding: adminemail
Preforming a listBindings returns an empty jrun.naming.JRunNamingEnumeration.
<cfset val = ctx.listBindings("java:comp/env") >
I only want to put a string value (probably several) into the ENC (or any JNDI directory at this point).
Never used it, but I got curious so I decided to try ... with no success.
I found this though, hopefully it helps you.
http://www.adobe.com/livedocs/coldfusion/7/htmldocs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=ColdFusion_Documentation&file=00001570.htm