coldfusion onrequestend.cfm - coldfusion

Is there a way to make onrequestend.cfm call conditional.
i.e if I call a template through ajax, I don't want that onrequestend.cfm should be executed on ajax requests.
As in my case this is generating some header info like meta tags etc.

You have a few options:
Place a blank onRequestEnd.cfm in the directory containing the AJAX services you're connecting to, as Daniel recommends.
Switch to Application.cfc and the onRequestEnd() event instead of onRequestEnd.cfm; and inside your onRequestStart() event method, tell ColdFusion not to do anything for the onRequestEnd event.
Since you didn't specify, I'll guess and say that your AJAX requests use a CFC, like so:
/foo/bar.cfc?method=getSomething&param=value
In which case, you can easily identify all requests being routed to a CFC like this:
function onRequestStart(targetPath){
if (listLast(arguments.targetPath, ".") eq "cfc"){
structDelete(this, "onRequestEnd");
}
}
Note that the function is only deleted for the current request, so you don't have to worry about it not being there for future requests. It will be.

There is not that I am aware of. However if you place all the templates you will be calling in a sub-directory and place a blank onRequestEnd.cfm in the sub-directory that should give you the same effect.

We handle this with URL variables. Call any page with
?NoHeaderFooter=true
and then conditional logic in onRequestStart like this:
<cfif NOT StructKeyExists(URL,"NoHeaderFooter")>
output header/footer etc. here
</cfif>
Can be used in both onRequestStart and onRequestEnd or create two variables so you can control each. Then all our ajax calls submit to something like:
report/FormController.cfc?Method=DoSomething&NoHeaderFooter=true

Related

CFInclude vs Custom Tag vs CFC for Presentation and Security

I'm just starting out with ColdFusion OOP and I am wanting to make a DIV which shows different links to users depending on what page they are on and what login rights (role) they have. Basically a 'context' menu.
Should I put this toolbar/navigation DIV in a .cfm or .cfc file?
To reiterate; The cfm or cfc file needs to know what page the user is on and will also check what role they have. Depending on these two pieces of information it will display a set of links to the user. The role information comes from the database and stored in a SESSION variable, and to find out what page they are on I guess it could use #GetFileFromPath(GetBaseTemplatePath())#.
My first thought was to have a normal .cfm file, put all the presentation and logic in that file (the HTML and lots of <cfif> statements) to ensure the correct information is displayed in the DIV, and then use <cfinclude> to display it on the page. Then I started thinking maybe I should make a Custom Tag and ask the calling page to pass in the user's credentials and the #GetFileFromPath(GetBaseTemplatePath())# as arguments and then have that Custom Tag return all the presentational data.
Finally I guess a CFC could do the above as well, but I'd be breaking the 'rule' of having presentational and logic data in a CFC.
Any suggestions on the best practice to achieve what I'm trying to do? It will eventually serve thousands of customers so I need to make sure my solution is easy to scale.
Anything that outputs HTML to the screen should be in a .cfm file.
That being said, depending on your need, you could have methods in a CFC that generate HTML, but the method simply returns the HTML as a string.
In programming, there are very few absolutes, but here is one: You should NEVER directly output anything inside of a function or method by using output="true". Instead, whatever content is generated, it should be returned from the method.
If you will have a need to use this display element more than once, a custom tag might be the best way to go rather than an include.
I see security as being a combination of what menu items I can see and what pages can be ran.
The main security function is inside of the main session object
On the menus
I call a function called
if (session.objState.checkSecurity(Section, Item) == 1)
then ...
For page security
function setupRequest() {
...
if (session.objState.checkSecurity(getSection(), getItem()) == 0) {
location("#request.self#?message=LoginExpired", "no");
return;
}
...
}
The particulars of what checkSecurity can do varies from application to application, but it is tied into how FW/1 works. The following security variations exist:
session.objState.checkSecurity(getSection())
session.objState.checkSecurity(getSection(), getItem())
session.objState.checkSecurity(getSection(), getItem(), Identifier)
None of the presentation files know anything about security.
Rules by which I live:) :
No CF business logic in CFM files. Just use some service which will serve template and provide needed data.
navService = com.foobar.services.Navigation(form, url);
and later output #navService.GetNavConent()#
No direct output from CFC files, functions should always return content. For example, make one function which makes one link based on some logic, second which wraps that and returns to cfm template.
Also one more hint, avoid using application and session scopes in your services.
This makes refactoring, testing and debugging too difficult.
For session you can make session.currentUser , CurrentUser.cfc which provides all things you need. e.g. session.currentUser.isAuthorized("backend/administration") and if true, show link to backend/administration.
Same for application, if you need locale, applicaiton wide setting or some singleton, make application.applicationSettings, ApplicationSettings.cfc and use that to retrieve all info you need in cfc's.
These rules will make your application to be easier to test and debug, and really easy to migrate tomorrow on some javascript based UI like Angular or backbone.js since all th edata you need is already in CFC and theoretically you just need to put remote in CFC or make some remote facade in the middle and you're done.

Access Variable in CFC using URL Invocation Method

I've a variable in my Application.cfm that stores the datasource for cfqueries.
<cfset mydatasource= 'somedatasorce'>
I can use it in any normal cfm page as below:
<cfset any_var = #mydatasource#>
I've a cfm page that calls a cfc which builds a query dynamically. This is the URL Invocation Method of CFC.
I'm not able to access "mydatasource" in the CFC using the above statement. It says "mydatasource" is undefined. I tried storing this in Application scope & accessed in CFC but again it says "mydatasource" is undefined in "Application".
On a bit of search, I found that the CFC needs to be instantiated in order to access the Application scope. But the URL Invocation method doesn't create an instance.
I can pass the datasource using query string but I'm looking for a better & more secure alternative.
Any suggestions are highly appreciated.
Thanks!! :)
I have been adding a number of ajax calls to an old application here and in order to get some application specific settings I created a file I called App.cfc. The contents of it are simply:
<cfcomponent>
<cfscript>
this["datasource"] = "something";
..... and so on .....
</cfscript>
</cfcomponent>
Then the CFC files I am making my URL calls to they simple extend App. So within those CFCs I can do datasource="#this['Datasource']#"
May not be the most "pretty" of ways to get the job done but it has been working here without issues.
UPDATE
I should have also mentioned that in order to avoid having settings in both that CFC and in the Application.cfm, I have something like this in my Application.cfm:
<cfscript>
objApp = CreateObject("component", "Components.App");
StructAppend(App, objApp);
</cfscript>
These old applications I am working with have a structure withing VARIABLES called App that is a copy of all Application variables. I see no reason why in this case you could not just do a structure appending to VARIABLES since appears that is where you are expecting things like the datasource to be on in your CFM pages.

Fusebox invoking a fuse within the code

Does anyone know if its possible to invoke a fuseaction within a coldfusion template?
(You haven't specified which Fusebox version; this answer applies to Fusebox 5.x)
Your title and question is asking two different things - a fuse and a fuseaction are two distinct things. A fuse is simply a CFML template, whilst a fuseaction represents a bundle of logic that performs a particular action (similar to a function).
Fuses:
To invoke a fuse, simply include the file as you would normally - there's no special FB functionality required for this.
Fuseactions:
To invoke a fuseaction, use the do verb, like so:
<cfset myFusebox.do('circuit.fuseaction') />
To store the result, use the second argument for the content variable:
<cfset myFusebox.do('circuit.fuseaction',varname) />
This is the equivalent of this XML:
<do action="circuit.fuseaction" contentvariable="varname" />
There are other arguments available, see this Fusebox cheat sheet which contains plenty of other useful info too.
With MVC, you should be working through a single entry-point. So only a single fuseaction should be called during your request.
BUT that fuseaction can call some of the other model and view templates as needed. And I believe that Fusebox allows you to refactor that logic into something that can be used by multiple actions. (I'm a bit rusty on my Fusebox functionality though, but I bet some Googling will lead you the way.)
As a dire last resort, you could use <cfhttp> to call a URL within your app that invokes that fuseaction. But why not just run some of the code directly without needing to burden your server with another HTTP call?

Which is the right scope to use?

I am using ColdFusion 9.0.1
I am running a page that will include other pages. The main purpose of this page is to determine which page to include. The pages that will be included will make use of the variable that I use in the page, which will be the MovieID (in this case).
My question is which is the best scope to use on this page? Would it be VARIABLES?
<cfscript>
Lookup = CGI.QUERY_STRING;
Query = CFC.doLookup(Lookup);
if (Query.RecordCount == 0) {
include "Content/Home.cfm";
} else {
// MOVIE PAGE
MovieID = Query.MovieID; // WHAT SCOPE SHOULD I USE HERE? FOR MOVIEID?
include "Content/Movie.cfm";
}
</cfscript>
Yes:
Variables
Maybe:
Application, Cookie, Request, Server, Session
No:
Arguments, Attributes, Caller, CGI, Client, Flash, Form, Local, This
ThisTag, Thread, thread local, URL
For info about each scope, check the CF9 documentation: scope types.
Sounds like you're implementing a Front Controller pattern.
Implement an Application.cfc, with an onRequest() that runs your code snippet. That way, it would intercept all incoming requests and include the appropriate cfm. Skipping the need for a handler index.cfm which simply includes the other cfm templates.
A further optimisation. Have your doLookup() method return a Struct containing just the recordCount + movieId as it appears that is all you are using. Returning a whole query is slower than just a struct of two numbers.
CF9 documentation: Application.cfc.
Variables (which is what you have now) certainly works. Another reasonable option would be Request, but I would lean toward variables over request.
Although either Variables scope or Request scope will be available to an included page, using Request scope could be helpful inasmuch as it is a scope that is intended to be available to any file in the request, whereas Variables scope is generally perceived to be specific to a given page.
In fact, Request scope was originally introduced for Allaire Spectra for the purpose of sharing variables across custom tags.
So, while both will do what you want, I would say that Request scope may have a small advantage of clarifying intent just a bit more.

Passing variables to cfinclude

How can I pass a variable to a cfm page that I'm including from another page?
Example:
<cfset a.name = "me">
<cfset a.age = 135>
<cfinclude template="displayNameAndAgeFrom_A.cfm">
and displayNameAndAgeFrom_A.cfm is
<cfoutput>#a.name# #a.age#</cfoutput>
Thanks!
AFAIK, this should work, exactly the way you posted it, without having to pass anything at all. Any values available in the outside/calling page are available in the included page.
Also worth noting that you also have <cfmodule ... /> available. cfmodule will let you call the same template but you can pass in different values for the same attributes.
Check out ColdFusion 9 documentation on cfmodule.
This template/module however will only have access to a handful of scopes that the caller template has access to: request, session and application