Difference between cfc and cfm - coldfusion

I'm trying to create basically a library of UDFs (User Defined Functions) for a web site run in ColdFusion. While doing this I am trying to find out what the differences are between cfc and cfm files. Which would be more helpful in creating this library of functions? I know that I can use
<cfinclude template="mytemplate.cfm>
to include it in a page but that will run the entire contents of that cfm on that page every time. I don't know and easier way to use cfc other than to create an object of the cfc and call the function that way.
<cfobject type="component" action="create" name="test">
Any ideas?

The way that I do it is to create all my UDF in a cfc. I then initialize that cfc on application start:
public function onApplicationStart() {
// Application settings
application.util = createObject("component","cfc.util");
return;
}

use a cfc you can call more easily from more places, if its not too huge put it into your application scope

Related

How to call OnRequestStart from Application.cfm

I am a new to ColdFusion. I have Application.cfm and would like to add an onRequestStart function, but it is not working. By not working I mean, when a page calls some application variables (that were set inside `onRequestStart) an error is generated because those variable don't exist.
I can't use Application.cfc. Is there a solution or another way to use onRequestStart with Applciation.cfm?
So I'm not really sure what your trying to do with the Application.cfm, but like Ageax said, the Application.cfm runs on every request ( whatever workflow you had in mind for the onRequestStart() function you can just do in the Application.cfm)
If you really want an onRequestStart function in Application.cfm you can make your own function and explicitly call it after like this
Application.cfm
<cfset Application.test = " AND IS USING AN Application Var :D!! ">
<cfscript>
function onRequestStart(){
RETURN "THIS HAPPENS AT THE START OF EVERY REQUEST! #Application.test#";
}
</cfscript>
<cfoutput> #onRequestStart()# </cfoutput>
This question and article might be an intresting read for you if your not forced to use an Application.cfm
ColdFusion: Are there any use cases where an Application.cfm is preferable to an Application.cfc
Migrating from Application.cfm to Application.cfc
If you need to using Application.cfm (not sure why this would be a requirement as Application.cfc has been around a very long time), it handles the basic onRequestStart functionality and is loaded before every *.cfm file.
You can add onRequestEnd functionality by creating a OnRequestEnd.cfm file.
Better reference: Coldfusion using onRequestEnd() with Application.cfm files
Please add requestStart.cfm file to you project, put your code in this file. It will run on every request (start).

cfc that bring in additional functions via include

My application.cfc starts with:
<cfcomponent extends="org.corfield.framework">
later on void function setupApplication() output="false" {
I have
// tools
include "initapp.cfm";
initapp.cfm has nothing but functions in it. Things like:
<!--- Helper functions --->
<cfscript>
string function stripHTML(str) output="false" {
return REReplaceNoCase(arguments.str,"<[^>]*>","","ALL");
}
application.stripHTML = stripHTML;
</cfscript>
The nature of the functions is NOT associated with a session. Is there a better way to make functions available globally?
If you're trying to put helper functions together for use in CFCs, one option may be to use the component.cfc file.
Using the component.cfc file
All CFCs automatically extend the ColdFusion
WEB-INF/cftags/component.cfc component. (The WEB-INF directory is in
the cf_root/wwwroot directory on ColdFusion configured with an
embedded J2EE server. It is in the cf_root directory when you deploy
ColdFusion on a J2EE server.) This CFC is distributed as a zero-length
file. You can use it for any core methods or properties that you want
all CFCs in your ColdFusion application server instance to inherit.
Note: When you install a newer version of ColdFusion, the installation
procedure replaces the existing component.cfc file with a new version.
Therefore, before upgrading, you should save any code that you have
added to the component.cfc file, and then copy the code into the new
component.cfc file.
If that solution is TOO global you can extend your helper cfc, but it has to be done in every cfc and doesn't answer your one-time-set-it-and-forget-it idea. See Using CFCs effectively
If your helper functions are for use in .cfm files, I'd do like Adam suggested. I usually put my helper functions in a "tools" cfc located in a CFC folder and make it an application scoped cfc.
function onApplicationStart(){
application.tools = createObject("component", "cfc.tools");
}
One of my helper functions logs the time it takes to index a solr collection. Using it looks like
<cfset application.tools.logSolrIndex('collectionName',getTickCount()-start,qFileList.recordCount)>
Last resort:
If you had to stick with an include for use outside of the application.cfc, I might simply include initapp.cfm onRequest() before you include your page.
Put the functions in a library CFC, and then put an instance of that CFC in the application scope in onApplicationStart().
That said, you'd be kinda breaking encapsulation if you then referenced this application-scoped CFC within other CFCs, which is a consideration (not necessarily a deal breaker, but a consideration).
You could look at some sort of dependency injection approach to mitigate this (eg: ColdSpring)
Whichever way I ended up doing it, I would not be doing it the way you're doing it, I'm afraid.

Store and use ColdFusion templates outside of the web root

I have been tasked with researching the possibility of storing .cfm files outside of the web root as a further security measure. (I'm not talking about CFCs, but the files that will appear in the URL string.)
I figured that I could use the properties of OnRequest() in the Application.cfc to do this, but no luck.
I've tried this:
<cffunction name="OnRequest" access="public" returntype="void" output="true">
<cfargument name="TargetPage" type="string" required="true"/>
<cfinclude template="C:/test#arguments.TargetPage#"/>
<cfreturn/>
</cffunction>
I then put a test.cfm inside C:\test and attempted http://localhost/test.cfm. That gives me a "file not found" error.
So then I created a ColdFusion mapping to C:\test called "test" and changed my CFINCLUDE thusly:
<cfinclude template="/test#arguments.TargetPage#"/>
Unfortunately I got the same error.
So, is what I'm after even possible? (Windows Server 2008 and IIS in case it matters. ColdFusion 9.)
I know that I could put a CFINCLUDE in my index.cfm and pass around URLs like http://www.example.com/?file=test.cfm, but I'd prefer not to do that.
Well here's something: If I put an empty test.cfm in my web root then this works. Obviously I'd really rather not put empty stubs for every one of my files (which, for this project, will end up being in the hundreds).
Rather than spinning your wheels down this path, let me point you in a possible better direction which may solve the original issue, but from a more preferred/best practices standpoint:
ColdFusion Sourceless Deployment
Rather than trying to jimmy-rig the site to read files outside of root, you simply never put the source code out into the world.
I think you would have better luck using onMissingTemplate rather than onRequest. http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7d2a.html

CFC extends sibling folder

I've seen all kinds of solutions for extending cfcs in parent folders with access to parent files or the CF administration, but I have not seen a workable solution to extend a cfc in a "shared"/sibling folder without access to parent folders.
This solution requires access to parent folders? (Not sure what these mappings are, but I have no access to Application.cfc anyway)
This solution requires being able to create an application.cfc which doesn't work for me (creating one in myApp does nothing because the environment I'm in includes the index page in myApp and builds the from there... the client never directly calls it to fire recognition of Application.cfc)
For instance:
wwwroot/some/path/myApp/Shared/Base.cfc
wwwroot/some/path/myApp/Function/Function.cfc
I'm looking to be able to call functionality in the Base.cfc (which contains common methods used in the application) from the Function.cfc via super and extension.
I have access to all files within myApp, but not "wwwroot", "some", or "path."
In order to extend Base.cfc within Function.cfc I have to extend the full path of "some.path.myApp.Shared.Base" This would cause problems if someone renamed the myApp folder since I would have to hand edit every Function.cfc that extends that Base.cfc
What I'm looking to do it create an application specific "barrier" so if the app folder name changes it will not cause mass havoc that requires I edit all the CFC files that use functionality from the Base.cfc.
Since I can't use relative paths to the Base ("..Shared.Base") I'm wondering if there's a way to create a CFC in the myApp folder that I can extend from and alleviate the renaming headache if it were to occur or a way to give it a generic name like "myApp" and extend from there. (myApp.Shared.Base)
I do not have access to Application.cfm, nor the Coldfusion administration.
Personally I would go simpler way: incapsulate the Base into the Function.
Looks like you want to use the set of core components for some common functionality. If this is true -- incapsulation even more applicable.
Paths to objects can be built dynamically, for example (step-by-step process for easier reading):
<cfscript>
path1 = GetDirectoryFromPath(cgi.SCRIPT_NAME);
path2 = ListToArray(path1, "/");
path3 = path2;
path3[ArrayLen(path3)] = "shared";
path4 = ArrayToList(path3, ".");
path5 = ArrayToList(path2, ".");
myBase = CreateObject("component", "#path4#.Base");
myFunction = CreateObject("component", "#path5#.Function").init(myBase);
</cfscript>
In the Function create function init:
<cffunction name="init">
<cfargument name="base">
<cfset variables.Base = arguments.base />
<cfreturn this />
</cffunction>
Of course, you may have strong reasons for extending, but at least this approach is not sensitive to the parent directories renaming.
If Base.cfc doesn't extend another cfc then you may be able to include the Base.cfc file into another cfc file in your function folder.
For example create a cfc file in the function folder with content:
<cfinclude template="../shared/base.cfc" />
Then extend the new file instead of the cfc in the shared folder.
The easiest way I can see to do this is to create a symlink or junction point to the base directory in the extension function directory.
Unfortunately, it's not a pure CF solution, nor portable if you need to move your code. Hopefully, someone will have a better answer, but this could be a fallback point if none is presented.
Generate the code on app start/reset...
For example the component tag could be like so in a file that should not be run directly...
<cfabort>
<cfcomponent extends="{sharedpath}.Base">
...
then in a function in or called from application.cfc do something like this...
<cfdirectory name="codetemplates" action="list" directory="wwwroot/some/path/myApp/codetemplates" />
<cfloop query="codetemplates">
<cffile name="temp" action="read" path="#tempfilepath##filename#" />
<cfset newfilecontent = replace(temp.filecontent, '{sharedpath}', configvarwithrightpath) />
<cfset filecontent = replace(newfilecontent , '<cfabort>', '') />
<cffile name="temp" action="write" path="#livefilepath##filename#" />
</cfloop>
The other approach is to have a build process locally that you run to create the necessary code but my example above would allow you to update a config variable and update the cfc's as needed in a live environment.
Why bother putting the shared code in a separate folder? If you just put it in the same folder as your "functions" cfcs then they can all extend it using a relative path.
So instead of:
wwwroot/some/path/myApp/Shared/Base.cfc
wwwroot/some/path/myApp/Function/Function.cfc
Use:
wwwroot/some/path/myApp/Function/Base.cfc
wwwroot/some/path/myApp/Function/Function.cfc
and:
<cfcomponent extends="Base"></cfcomponent>
However, if you have/need multiple "function"-level folders, then you can do something similar. Put a Proxy.cfc inside each "function"-level folder, with this code:
<cfcomponent extends="some.path.myApp.shared.Base"></cfcomponent>
And then each cfc in the "function"-level folders would extend their local Proxy.cfc (extends="proxy"). This gives you 1 Proxy per folder, which is still not ideal, but less of a hassle than updating every cfc.

Extend a CFC using a relative path

I want to extend a CFC in a different directory and I have a couple of options, but can't figure out how to do this:
A) Use a dynamic mapping (this will have to be dynamic based on the site, e.g. for the live site it would be cfc.myPackage.MyCFC but on a dev site it would be myCfcRoot.myPackage.MyCFC) - I've tried putting expressions into the extends bit but obviously CF doesn't like that, e.g. :
<cfcomponent name="MyComponent" extends="#config.cfcRoot#.BaseComponent">
or
<cfcomponent name="MyComponent" extends="#GetRealPath(../BaseComponent.cfc)#">
B) Provide a relative path (somehow) to the CFC to extend.
I fear that I can't do this, but I'm hoping that there is something I've missed.
Daniel is basically correct, you need a mapping. However, there are 3 workarounds.
CFCs will pick the current path as a relative root mapping, so if your CFCs are all in the same directory, you can just say
<cfcomponent name="MyComponent" extends="Example">
Or if your components are in subdirectories from the current cfc, you can access it:
<cfcomponent name="MyComponent" extends="subdirectory.Example">
Second, if you are running on ColdFusion 8, you can define a mapping in your application.cfc using the mappings struct like this:
<cfset this.mappings["/MyApp"] = expandPath(".") />
There are two good references for Application.cfc, first, Ray Camden's example Application.cfc which just gives a nice view of what goes where, then the CF8 Live Docs application settings page, which has a section on mappings along with some good comments.
Finally, you can use the built-in mapping of your web root, so if your application is in a subdirectory named "MyApp" off the web root, your root mapping will be "MyApp". Let's say you correctly put your components in:
wwwroot\MyApp\com\MyApp\example.cfc
The mapping to this cfc in this case will be:
MyApp.com.MyApp.Example
And using your example, you can extend like this:
<cfcomponent name="MyComponent" extends="MyApp.com.MyApp.Example">
Anything else, such as if your components are outside of the web root, or if you are not sure what the folder structure of your finished application will be, and you will need to set a mapping in the CF Administrator.
Now this is only tested in cf8 so other engine could differ.
if you want to use relative paths to extend applications you can but your have to start them with a "/.". For instance you can do this to extend an application.cfc from your web root into directory below you webroot:
<cfcomponent output="false" extends="/.application">
<!--- whatever code you have --->
</cfcomponent>
now let's say I have the following paths in my application:
[webroot]/1/1a
[webroot]/2
let's say that the application.cfc in [webroot]/1/1a extends the application.cfc in [webroot]. now I want to place an application.cfc in [webroot]/2 and extend the application.cfc in [webroot]/1/1a. all i would have to do in my [webroot]/2/application.cfc is the following:
<cfcomponent output="false" extends="/./1/1a/application">
<!--- whatever code you have --->
</cfcomponent>
hope this makes sense.
Unless the CFC is in the same directory as the calling script the CFC must be located and referenced from a path relative to a "Mapping".
I have found that sometimes you need to make sure that "/" is mapped to your document root of your webserver and that becomes the base for all relative paths. Or you can setup a mapping for a CFC directory that hold all of your common CFCs.
This screen is found in the ColdFusion Admin under "Server Settings" -> "Mappings".
In regards to Method B. It can be done using an additional file in your example. It's one extra file per cfc that you want to extend per directory that you want to extend from.
The 3 files that are required.
/somepathtobasecomponent/basecomponent.cfc (your base component file)
/pathtoworkingcfc/function.cfc (the file with the extends attribute)
/pathtoworkingcfc/basecomponent_extend.cfc (the new file that will do the extending)
/somepathtobasecomponent/basecomponent.cfc
Nothing to change here. This stays the same.
/pathtoworkingcfc/function.cfc
in the cffunction tag set the extends to extends="basecomponent_extend"
/pathtoworkingcfc/basecomponent_extend.cfc
Sole content of the file is a cfinclude
<cfinclude template="/somepathtobasecomponent/basecomponent.cfc">