I've got a set of processes I frequently do to a model that I keep redoing in the controller, and I'm wondering if there is a way to implement it through a function in the model, so that I can just call the model function pass some parameters and get the right query.
I've got a linked list, and there's a bit of repetition that I want to avoid.
figured it out...
in model:
<cffunction name="getCustomResults" returntype="query">
<cfset all = findAll()>
<!--- do stuff --->
<cfreturn myQuery>
</cffunction>
getting the custom results
<cfset mySelection = model('myModel').getCustomResults()>
if there is a way to do implement it through a function in the model
Can you please tell what stops you from doing exactly this? Simply create CFC like /models/Foo.cfc where foo is name of your model and extend it with methods. Just don't forget to extend the Model.cfc. See this docs section. Inside the model you have this scope which holds all properties.
Related
I am trying to set a coldfusion user object for each person as they log in. Similar to how rails has devise and I can call current_user.id or current_user.username from wherever I am in the site. I have a users table that stores roles and other user information. I want to query that and assign all of the fields to a sort of global user object. I can then use that for components, page display etc.
I am trying to figure out where and how to do this. I have tried initializing a component like this in onsessionstart, onrequeststart etc, but when I try to reference globalUser.id in a component for instance it hits a 500 error because globalUser is not defined.
<cfset globalUser = CreateObject( "component",
"controllers.user" ).globalUser(empidname= '#getauthuser()#') />
Any recommended ways to do this? Any plugins that provide functionality like this?
You want to use session variables.
<cffunction name="onSessionStart">
<cfset session.globalUser = CreateObject( "component",
"controllers.user" ).globalUser(empidname= '#getauthuser()#') />
...
</cffunction>
In order for sessions to be enabled, you have to alter application.cfc
component {
this.name = "AppName";
this.sessionManagement = true;
I have a datasource called "cforms" which has access to two database
"cforms" and "cquizes"
I wish to create the following query:
select * from cquizes.tb_depts;
I have a model for table "tb_depts":
<cfcomponent extends="Model">
<cffunction name="init">
<cfset table("tb_depts")>
</cffunction>
</cfcomponent>
And my controller:
list = model("tb_depts").findAll(order="id");
When I run this controller/action. It gives me the following error:
[Macromedia][Oracle JDBC Driver][Oracle]ORA-00942: table or view does not exist
And it generates the following query:
SELECT * FROM tb_depts
I understand what the problem is because since "tb_depts" doesn't exist in database "cforms" it throws that not found error. However is there are way to tell the model that using the datasource "cforms" access database "cquizes". For example
cquizes.tb_depts
Its seems to use the database that matches the datasource name. Is there a way to work around this functionality.
If you need to get data from another database, There is an alternative way. For that you need to create a datasource for your second database cquizes. Then use that datasource name in the model file. This will override default datasource for that model.
For example, If you name your second datasource as cquizdatasource then in your model would be like
<cfcomponent extends="Model">
<cffunction name="init">
<cfset dataSource("cquizdatasource")>
<cfset table("tb_depts")>
</cffunction>
</cfcomponent>
Your query should work fine with the said scenario in the question. There are limitations to this, check out the link to know more.
I am submitting a form to a CFC which in turn invokes a method in a different CFC. The initial CFC will then send an e-mail to the user confirming its all done. Its a bit like this:
<cfcomponent>
<cffunction name="FinalDemand" access="remote">
<cfinvoke component="AnotherCFC" method="AddToAudit" argumentCollection="#Arguments#">
<!--- I need to wait for confirmation from AnotherCFC here before continuing --->
<cfset APPLICATION.SendMail.ThankYou()/>
<cfset var Success = true>
<cfreturn Success>
</cffunction>
</cfcomponent>
The AnotherCFC is doing an update to a database. I'd really like that method to be able to tell the calling CFC that its done its work. At the moment it just returns a boolean like the CFC above to say all went well. If it doesn't return the boolean then we know it went wrong.
Is this possible at all? I don't mind using JQuery to acomplish it if need be.
I was curious if there is a way to force a ColdFusion tag to hold an attribute as default, such as the datasource in cfquery.
For example instead of writing
<cfquery datasource="mydatasource">
I can write
<cfquery>
and the system automatically knows that the datasource is "mydatasource".
Would be really cool if this was possible.
It is actually possible for datasource, but not for everything.
You may set a this.datasource="mydatasource" as the default datasource in your Application.cfc
https://wikidocs.adobe.com/wiki/display/coldfusionen/Application+variables
The practical answer to your question are the custom tags. You can extend the features of ColdFusion tags to match your needs.
Taking into example the cfquery tag and wrapping a custom tag around it. Provide all the default values you want for the parameters of the cfquery into the tag's attribute default.
So essentially your custom tag page would be something like:
flexiquery.cfm
<cfif THISTAG.ExecutionMode EQ 'end'>
<cfparam name="Attributes.datasource" default="someDSN">
<cfparam name="Attributes.cacheWithin" default="#CreateTimeSpan(0,6,0,0)#">
<cfparam name="Attributes.maxRows" default="25">
<cfparam name="Attributes.timeOut" default="600">
<!--- some logic you want to perform --->
<cfquery datasource="#Attributes.datasource#"
cacheWithin="#Attributes.cacheWithin#"
maxRow="#Attributes.maxRows#"
timeOut="#Attributes.timeOut#"
<cfoutput>#THISTAG.GeneratedContent#</cfoutput>
</cfquery>
<!--- Caller assignment and other processing --->
</cfif>
And now you can use it and re-use it across your project, the way you wanted and even overriding the value you want to be different:
<cf_flexiquery>
<!--- you query here --->
</cf_flexiquery>
or
<cf_flexiquery maxRows="100" timeOut="1200">
<!--- you query here --->
</cf_flexiquery>
It gives you a fair idea of how to go with it. I have extended the custom tags features to leverage the features of cfhttp, cfpdf, cffile etc.
This is only way you can adopt the flexibility you want with ColdFusion tags and it works perfectly.
I am using the technique detailed in this answer to manage a library of small utility functions. (Essentially, each function is loaded as a "mix-in" using cfinclude.)
I have need, however, to know the names of the functions that the object has (once instantiated). A cfdump on the object only shows the init function which is written directly in the CFC.
Some more detail:
I am creating the object in the application scope in OnApplicationStart().
<cfset application.udfs=createObject("component","extensions.udfs").init()>
However, to save the developers from having to constantly write application.udfs.foo(), I thought I'd grab all of the functions and drop them in to the variables scope in OnRequestStart(), so that these hypothetical developers could just write foo().
<cfset foo=application.udfs.foo>
Obviously, though, this needs to be dynamic and to happen for each of the functions in the object, no matter how many there are. If I repeat this line for every function I've lost whatever I'd gained by having a library that is dynamically generated.
I thought perhaps I could use a collection loop, but that was invalid. I am fairly certain there's a way to get the list of methods in an object, but I have not yet been able to find it.
Any clues?
By the by, my fallback is going to be to copy the application.udfs object to a local object with a nice short name (like "u") so that the developers can simply type u.foo(), so no need to suggest that if what I want to do can't be done.
This should allow you to import all your udfs into the global variables scope:
StructAppend(variables, application.udfs);
I think GetMetaData should help you.
Here another interesting option suggested by Ben Nadel:
Check out the detail in his blog entry: http://www.bennadel.com/blog/1776-Creating-Globally-Accessible-User-Defined-Functions-In-ColdFusion-Safer-Version-.htm
UDF.cfc
<cfcomponent
output="false"
hint="I define user defined functions.">
<cffunction
name="getMessage"
access="public"
returntype="string"
output="false"
hint="I return a test message.">
<cfreturn "I am defined in the UDF component" />
</cffunction>
</cfcomponent>
Application.cfc
<!--- Define the application. --->
<cfset this.name = hash( getCurrentTemplatePath() ) />
<cfset this.applicationTimeout = createTimeSpan( 0, 0, 5, 0 ) />
<!---
Add all of our "global" methods to the URL scope. Since
ColdFusion will automatically seach the URL scope for
non-scoped variables, it will find our non-scoped method
names.
--->
<cfset structAppend(
url,
createObject( "component", "UDF" )
) />