How to consume component from file in different folder - coldfusion

Working with version: 2016,0,10,314028
I know there are other questions addressing the issue, but since they are a bit old I wonder if anything has changed since then. Here is my problem:
In the "OnRequestStart" function inside Application.cfc (located in root folder), I have this:
<cfset application.cfclogin = "comp.login" />
"comp" begin the folder and login the name of the cfc file.
Inside the same Application I consume the cfc without a problem, like this:
<cfinvoke component="#application.cfclogin#" method="sgice_redirect" >
Even in a logout.cfm file located in root, the same cfinvoke method works.
But if a try the same cfinvoke from a file located in /subfolder/Layout.cfm for example, the cfinvoke throws an Error. Which looks like this:
I tried putting the name of the app in the dot notation declaration (APP.folder.cfcfile) but that doesn't work even in the files located in root invoking the cfc.
Other websites inside the same server are using this method of declaring the dot notation name for the cfc inside OnRequestStart and using that variable throughout the files, but I can't find the reason of this not working in this specific site. If you are wondering about the F:/ route, F:/WebSitesTij/CFSites/sit_tij/ is supposed to be my root folder in this case. Any help is appreciated.

Related

Cannot locate component from cfinvoke statement

I had some ColdFusion code handed to me due to someone leaving the company that I was tasked to maintain. The problem is the last time I looked at some ColdFusion code was around 10 years ago so I'm completely lost and I'm starting from scratch.
My issue is I'm trying to locate the component or code and whatever is being called in the code shown below.
<cfinvoke component="_admin_tools_kms" method="listKMSUsers" returnVariable="getKMSUsers">
<cfinvokeargument name="argFullAccount" value="1" />
</cfinvoke>
I know this is returning a list of users for the system but I cannot locate the exact code making that call. Should that component name, "_admin_tools_kms", be the name of a cfm file somewhere or can that be just a reference name created somehow?
Let's break this down:
<cfinvoke
component="someComponent"
method="someFunction"
returnVariable="someVariable">
<cfinvokeargument name="someArgument" value="foo" />
</cfinvoke>
The attribute component is either name of a file with a .cfc extension or a variable containing an instance of that component. If it was a variable, it would be referenced as #someComponent#.
If there's just a simple value in there, odds are there's a file named someComponent.cfc in the same folder.
If there's a dot-separated value in there, like cfc.services.someComponent,
look for a folder at the web root named /cfc/ that contains another folder /services/ in which you'll find the file someComponent.cfc.
If you don't see that folder, look for a ColdFusion mapping in the root Application.cfc file that creates the alias cfc and maps it to the folders you want.
and if THAT's not there, then check your web server for folder aliases or mappings to see what the heck some psychopath did to hide where that code exists.
BUT, I prefer doing a simple text search for the method referenced instead of the component. That function could exist in another component or file than the one referenced.
Since a CFC can extend another CFC, there could be a parentComponent.cfc that someComponent extends which actually contains the method in question. Worse, the file someComponent.cfc could have other files included where one contains the method. The only downside is if the function is named something common like create.

How to get directory path up to a specific folder only?

Using: CF10 and IIS7.5
I have a section within my website called "Bookings". It is located like this:
c:\inetpub\wwwroot\mysite\bookings
Within this folder will be sub-folders and eventually webpages themselves. Heres an example:
c:\inetpub\wwwroot\mysite\bookings\holidays\new.cfm
c:\inetpub\wwwroot\mysite\bookings\carhire\edit.cfm
I include (using <cfinclude>) another page within each webpage that displays different links depending on which page is calling it. All I want to know is the directory up to the "bookings" folder. Something like this (pseudo code):
<cfset whereAmI = #GetDirectoryFromPath(GetBaseTemplatePath())#>
<cfif #whereAmI# EQ "C:\inetpub\wwwroot\mysite\bookings">
<h1>Booking Section Links</h1>
</cfif>
The above code works only if the user visits the bookings/index.cfm page of the "bookings" folder. But if they go to the bookings/holidays/new.cfm page, it is now in the holidays folder so the <h1> content will not appear. I really only want to check for any page that is in the bookings folder, even if it is within a subfolder within the bookings folder. A bit like in SQL where I could say IF #GetDirectoryFromPath(GetBaseTemplatePath())# LIKE 'c:\inetpub\wwwroot\mysite\bookings%' so it has a wildcard on the end.
I know this question is going to irritate the MVC framework advocates but please excuse me on this!
Here is a quick, easy way to solve your problem (may not work as system expands - but should get you started down the right path).
<cfset whereAmI = GetDirectoryFromPath(GetBaseTemplatePath())>
<cfif whereAmI CONTAINS "C:\inetpub\wwwroot\mysite\bookings">
<h1>Booking Section Links</h1>
</cfif>
Note, I removed the # from inside the cfset and cfif you do not need them there.
You could even scale back the path to use just 'mysite\bookings'.
Ideally, this should be wrapped up into a function so that you can easily pass different paths into it to determine if you are on a given page. Or, possibly, even determine the 'parent' folder in onRequestStart in Application.cfc and set it as a request scope variable.
This will need to be tweaked if you run the code on a *nix based system.
It is more easier with CGI variables. You can use "CF_TEMPLATE_PATH". Try this
<cfoutput>The value of CF_TEMPLATE_PATH is: </cfoutput><cfdump var="#CF_TEMPLATE_PATH#">

Mapping to a CFC in ColdFusion

In my application I have all my CFC's in a cfc folder. From the site root I can access them without any trouble by simply referring to them in my <cfinvoke> tag as component=cfc.mycomponent method=mymethod
The trouble is, when I want to access the cfc from another page that's not in the root I can't use component=../.cfc.mycomponent to get in touch with that cfc.
What am I doing wrong here?
There are a handful of options for getting this to work. Unfortunately, learning them has taken me a good amount of trial and error. Let me share what I've learned.
First, you can use the classic method of creating a mapping in your CF Administrator. Specify the exact path to your components (e.g. c:\wwwroot\cfc), and the mapping (pseudo-folder) that you want to call it by (e.g. MyCFCs). Now from anywhere in your application, you can reference create a new MyCFCs.mycomponent() (using CF9+'s new keyword, you can substitute for createObject("component","MyCFCs.mycomponent") to be compatible back to CF6).
The downsides to using a server mapping are that you have to configure this on every server your application runs on. I typically have a local development server which has a radically different configuration from my production servers, and making changes on production servers is a pain for me, so I try to avoid server mappings whenever possible.
Second, you can reference your CFCs from a web-root-relative path, meaning that if your application is in the root of your server and the /cfc path is directly off of the web root, you can always do new cfc.mycomponent() from anywhere in your application. ColdFusion 6.1 and up will correctly map to the root of your web site. This is like referencing an image using /images/mypicture.jpg, anywhere in your web site, /images will will go straight to the same directory.
The downside of using the web-root-relative path is that if your application will ever be in a different folder off of the web root, or will ever be in a subdirectory and sometimes be at the web root, the relative path from the web root will change, breaking these links.
Third, you can create an application-specific mapping. This was introduced in CF8 and requires that you have an Application.cfc file. It is simple to add. Raymond Camden has a great reference. The syntax is essentially like this.
<cfset this.name = "MyAppName"/>
<cfset this.mappings = structNew() />
<cfset this.mappings["/cfc"] = getDirectoryFromPath(getCurrentTemplatePath()) & "cfc/" />
The only downside to this method is that your Application.cfc can't extend a CFC in a mapped folder. It's an obscure problem, which probably won't affect you. Also, you will need to have an Application.cfc, which is good practice, but I don't know if you are doing that yet.
Fourth, you can instantiate your CFC into your application scope, probably from within the aforementioned Application.cfc, inside an OnApplicationStart() method. This moves any compile/instantiation time into your application's first hit, and removes it from subsequent hits. The code is very simple.
<!--- from Application.cfc, inside onApplicationStart() --->
<cfset application.myComponent = new cfc.myComponent() />
<!--- from anywhere else in your application --->
<cfset application.myComponent.callMyMethod() />
The downside to this one is that once your component is in Application memory, any changes you make to it while you are developing your application will not be reflected until you clear the application memory or call onApplicationStart() again. It's not hard to get around, but it's just more code, and more to manage.
One final note, you may want to think about moving from <cfinvoke> to createObject("component",...) or, if you are on CF9, new. The cfinvoke syntax is fine, but every time you invoke a component from a path, you are re-instantiating it, and it also is not a very object-oriented way to call your components. Food for thought, take it or leave it :)
You can't use relative paths with components.
What you need is a ColdFusion mapping. There are two ways to do this.
The first is to go into your ColdFusion administrator, go into the mappings section and add a /cfc mapping that points to your cfc folder.
The other way is to use application specific mappings;
In the Application.cfc for your application you can add application mappings as you would under the ColdFusion administrator mapping. At the top of your application cfc add a cfset of this.mappings as an array. In this array set the mapping with the directory path.
<cfset this.mappings["/cfc"] = GetDirectoryFromPath( GetCurrentTemplatePath() )&"cfc">
with the mapping of /cfc to your cfc folder any component calls to cfc.objectname will load the appropriate component in your cfc folder.
You absolutely can extend a cfc with mappings. I had to do it myself.
One of the most frustrating things that I have had to deal with in ColdFusion is trying to create an external application that is open to the general public and having to secure a portion of that site with an application within a subfolder and extending the logic from base application.cfc. I'll walk you through the current approach that developers use to solve this as well as showing you how to additionally use mapping when there may be a hosting provider that uses virtual directories.
This is a rather long article, if you want to jump to the condensed summary, scroll down to the bottom of this page.
Many years ago, the first time that I tried to perform this, I received the following message no matter what I tried: "Could not find the ColdFusion component or interface xxx'. In a nutshell, the problem using this approach is that both the root and the subfolders have the same name, i.e. Application.cfc, and ColdFusion can't properly identify what component to extend. Finally, after some serious investigation, someone came up with the idea to create a proxy.cfc that resides in the same root directory as the root Application.cfc, and the Application.cfc in the subfolder extends an empty proxy.cfc that extends the root cfc like so:
root directory: Application.cfc
This root Application.cfc does not extend anything
Also in the root directory: Proxy.cfc
Proxy.cfc has the following code, it's essentially empty. The only thing that the Proxy.cfc does is to extend the Application.cfc that is in the same directory:
<cfcomponent extends="Application">
</cfcomponent>
Subdirectory such as a folder named admin.
This subdirectory has another Application.cfc. Let's say that this component is responsible for securing the application and has login logic as well as debugging settings for example. This Application.cfc will extend the Proxy.cfc to gain the methods and properties of the Application.cfc in the root directory like so:
<cfcomponent displayname="Admin" extends="Proxy.cfc">
This approach was a godsend and it was heavily blogged about. Ben Nadel has made a number of very helpful posts which I will share at the bottom of this article.
This works quite well unless you're on a hosted domain or a server that uses virtual directories. In this case, we are in the same original boat in which we started from. Now we are back into the "Could not find the ColdFusion component or interface xxx' hell!
There is a solution for this tricky problem though, we need to also use mapping!
It is a common misnomer that you can't use mapping to extend components. I am not quite sure where this misconception originally came about, but it has been proven that this is just not true. There are occasions where we must use mapping to solve some annoying problems, like here.
This particular site is hosted by hostek.com. They are a fine company to deal with, but the server that my site is hosted on has some idiosyncrasies due to the directory structure. Here, when I use the Proxy.cfc method to extend the logic from the base Application.cfc to the Application.cfc in the admin folder I receive the dreaded 'could not find the ... component' error. When I first saw it I was dismayed thinking not this again, so I turned to ColdFusion CFC mapping. Mapping tells ColdFusion where to find the file and what the file relationships are.
Let's review CFC structure that was just discussed. For example, imagine the following directory structure:
root directory: i.e. www.gregoryalexander.com/
subdirectory: www.gregoryalexander.com/admin/
As discussed, we have an Application.cfc and the Proxy.cfc in the root directory, and we have the Application.cfc in the 'admin' subdirectory.
The Proxy.cfc extends the Application.cfc, also in the root directory, and the Application.cfc in the subdirectory (admin) extends the Proxy.cfc in the root directory.
root directory: contains both Application.cfc and Proxy.cfc (that extends the root Application.cfc).
subdirectory: Application.cfc (that extends Proxy.cfc).
Now we need to also add the following mapping in the root Application.cfc. This mapping logic should be near the top of the root Application.cfc, and it should not be within any of the Application.cfc event handlers (onApplicationStart, onApplicationRequest, etc). This mapping code does not need to be anywhere else other than the root Application.cfc:
<cfset this.mappings = structNew() />
<cfset this.mappings["rootCfc"] = getDirectoryFromPath(getCurrentTemplatePath()) />
<cfset this.mappings["adminCfc"] = getDirectoryFromPath( getCurrentTemplatePath() & "/admin" ) />
I used rootCfc to identify the Application.cfc in the root directory, whereas adminCfc applies to the Application in the admin directory. These variables can be named anything. Note that the "/admin" string at the end of the adminCfc mapping points to the 'admin' folder, which is a subdirectory.
Now that we have the mappings in the root Application.cfc, we need to apply them to the extends statement in Application.cfc located in the subdirectory. In the /admin/Application.cfc template use:
/admin/Application.cfc
<cfcomponent displayname="xxx" sessionmanagement="xx" clientmanagement="xx" extends="rootCfc.Proxy">
Of course, rootCfc tells the Application.cfc in the subdirectory to look for the Proxy.cfc template in the root directory. Like other 'extend' statements, you don't need to specify '.cfc' at the end of Proxy.
You don't need to use this 'extend' mapping in either the root Proxy.cfc or Application.cfc templates. They can already find each other as they are both in the same root directory.
/Proxy.cfc
<cfcomponent extends="Application">
</cfcomponent>
Summary
For the sake of absolute clarity:
root Application.cfc
Contains the mapping logic. Has the mappings for both of the root and subdirectory.
Does not use an 'extend' statement
<cfset this.mappings = structNew() />
<cfset this.mappings["rootCfc"] = getDirectoryFromPath(getCurrentTemplatePath()) />
<cfset this.mappings["adminCfc"] = getDirectoryFromPath( getCurrentTemplatePath() & "/admin" ) />
root Proxy.cfm
A simple 'extends="Administrator" works.
No mapping logic.
<cfcomponent extends="Application">
</cfcomponent>
subdirectory Application.cfc
The extends statement must be the mapping variable name of the folder (rootCfc), a dot (.), and finally the name of the Proxy.cfc template without the .cfc prefix (Proxy)
<cfcomponent displayname="Admin" sessionmanagement="yes" clientmanagement="yes" extends="rootCfc.Proxy">
My apologies for being so verbose. I annoyed myself while writing this- but not as annoyed when I was while trying to solve this problem!
Take care!
Make sure if your components extend other components the full path is used.
ie a Products controller
<cfcomponent displayname="Products" hint="Handles all product requests" extends="core.controller.controller" output="false">

Cannot find CFML template for custom tag

I am not a ColdFusion coder. Doing a favor for a friend who ported his CF site from a Windows server to Unix on GoDaddy.
Site is displaying error:
Cannot find CFML template for custom tag jstk. ColdFusion
attempted looking in the tree of installed custom tags but did not
find a custom tag with this name.
The site as I found it has at document root /CustomTags with the jstk.cfm file and a set of files in cf_jstk
My Googling located this:
You must store custom tag pages in any one of the following:
The same directory as the calling page;
The cfusion\CustomTags directory;
A subdirectory of the cfusion\CustomTags directory;
A directory that you specify in the ColdFusion Administrator
So I have:
Tried creating placing /CustomTags in /cfusion/CustomTags
Tried copying /cfusion/CustomTags to above document root
Tried copying jstk.cfm and subfolders into same directory as calling file(index.cfm)
Update: Per GoDaddy support I have also tried adding the following to no effect: <cfmodule template="CustomTags/jstk.cfm">
Can any one give me some tips on this or should I just tell my guy to look for a CF coder?
Thanks!
I don't know how GoDaddy is setup, so as a quick test, please do the following:
Create file test.cfm in the webroot with contents:
<cf_testtag/>
<cfoutput>test</cfoutput><cfabort/>
Create file testtag.cfm in the webroot with contents:
<cfdump var=#ThisTag# />
Then in a browser visit the test.cfm page.
You should get two debug dumps, followed by the 'test'; this will confirm that custom tags in general are working.
If that works move the testtag.cfm to the CustomTags directory, and see if you get the same behaviour or an error.
If this produces an error, for CF8 and above, you can add <cfset This.CustomTagPaths = "/CustomTags" /> inside the Application.cfc file (assuming there is a App cfc and not an Application.cfm) to ensure that directory is checked for tags.
It is possible to convert Application.cfm to Application.cfc - how easy this is depends on how complex the code is in there - might be something you could figure out, or might need an experienced CF dev, it depends.
Depending on the outcome of this, we can attempt to debug why the jstk tag isn't working (unless one of the above solves it).
In an effort to check the simple things before worrying about complex things:
Remember that filenames on *nix systems are case sensitive, but on windows are not.
For example, a windows server will pick up "application.cfm" but a linux server won't. It requires "Application.cfm".
Check to make sure all filenames/paths are the correct case.
Normally, CFML check every custom tags in current directory first, if not found, second is in CFMX8/customtags/.

Fusebox installation without access to webroot

Previously (and locally) I've placed the fusebox5 directory in the web root, and then applications from anywhere in the tree have been able to access it. I'd previously also used Application.cfm rather than .cfc.
In this environment I don't have access to the webroot and the FB files don't really need to be that far down anyway, so I had planned to store them alongside the applications. Am I right in thinking that index.cfm is overlooked if Application.cfc is in use (and therefore there's no point changing the cfinclude value to be eg. ../fusebox5/)? If so, how can I include the framework without having Fusebox in the root or in a mapping? Error is:
Could not find the ColdFusion Component or Interface fusebox5.Application.
No, your app is still going to need index.cfm. What you'll need is a cf application mapping for Fusebox in your Application.cfc. Look at Ray Camden's Application.cfc template for an example of setting application specific mappings.
You can run Fusebox 5+ in a subfolder of your app root. It just may not be the most obvious thing to make it work.
Unfortunately, you cannot create a dynamic mapping for extending Application.cfc because your Application.cfc has not yet been instantiated - you get a chicken vs. egg scenario. You can't create the mapping to Fusebox because your Application.cfc didn't start, you can't start your Application.cfc because it can't find the component it's supposed to extend.
THIS IS A BUG IN COLDFUSION 8. ColdFusion should look for mappings in this order:
Mapped folders from the CF Administrator
Sub directories off the current directory
Sub directories off the web root called
It does this when you use CreateObject(), but not when you use the Extends attribute on cfcomponent.
The easiest solution is to use your Application.cfc like you would for any application, then include fusebox from your index.cfm. Your folder structure would look like this:
/myapp/fusebox5/
/myapp/index.cfm
-- consists of <cfinclude template="fusebox5/fusebox5.cfm" />
Your index.cfm file will not be ignored as long as you don't intercept the request with Application.cfc's OnRequest, or if you use OnRequest, make sure you include the intended target (which will almost always be index.cfm anyway).
If you want to not require index.cfm to do the include, you can have your Application.cfc's OnRequest method do the cfinclude.
<cffunction name="onRequest">
<cfinclude template="fusebox5/fusebox5.cfm">
</cffunction>
You still may need an index.cfm so your web server won't give a directory listing or 404, but it's ok if the file is empty.
In Application.cfc:
<cfscript>
this.mappings = {}; //create a new structure to store app-specific mappings
this.mappings["Fusebox"] = expandPath('./Fusebox'); //add mapping
</cfscript>