tags:

views:

386

answers:

2

I'm somewhat new to ColdFusion and I'm trying to understand the best way to use cfinclude'd files. The thing that I find limiting is that files are included in-line as if they were part of the including template. That's nice and simple but that means that any relative paths inside the included file are resolved relative to the includer, not the included file. This becomes a problem in the following file layout:

a.cfm   <--- cfincludes b.cfm
b.cfm   <--- cfincludes c.cfm
c.cfm
somedir/d.cfm   <--- cfincludes ../b.cfm

When a.cfm includes b.cfm, all works well. When d.cfm includes ../b.cfm, the include within b.cfm of c.cfm will fail since it is resolved relative to d.cfm. So, two questions for my edification:

  • Is there a best practice for CF along the lines of "files that you expect to be included from other files shouldn't include relative links"?

  • I'm trying to understand the design decision. I understand the notion that the effect of a cfinclude is as if the included file were part of the includer - there's an elegant simplicity to that. But are there non-pathological cases where one prefers to have relative links resolved this way? I can think of cases where I want them resolved "traditionally", i.e. relative to the file they are located in. Maybe I'm missing something.

+1  A: 

Basically this subject covered by manual. But just to show the idea of using. Assume our application is located at http://localhost/myapp/

It's just special ColdFusion paths feature: "absolute" path here is web-root's "/myapp/".

Then in Application.cfc (Application.cfm) you can define the base URL:

<!--- hardcoded --->
<cfset application.basePath = "/myapp/" />
<!--- more intelligent --->
<cfset application.basePath = GetDirectoryFromPath(CGI.SCRIPT_NAME) />

and include templates each time as

<cfinclude template="#application.basePath#b.cfm" />

It's just gives the baseic idea how to make including independent from current template location.

Other way is using mappings, server or dynamic (CF8+), but it's a bit another story.

Other way is using single dispatcher (index.cfm, page.cfm etc) -- used in most modern applications, but it is also another story.

Sergii
Maybe my question wasn't clear. I understand how include files work. I'm wondering *why* they work that way. I can't see a case where you would want relative paths in included files resolved relative to the parent or "including" file yet that's how they work (see my example above). I'm hoping by asking that someone will point out a use case that does justify that behavior. Like I said, I'm somewhat new to CF so perhaps I'm missing something.
DaveBurns
Ah, ok. Think the old-school CF developers will tell you about some kind of legacy reasons of having such paths system trailing from Alliare products. Suppose you're comparing experience with PHP or something, where includes work in context of initial template -- if I remember it correctly. But it works like it works, as many "odd" things for CF-newcomers.
Sergii
CFINCLUDE basically just takes the chunk of code from the included file and puts it into the "parent" at compile time. It need not be in the web root nor does it need to be a .cfm file. As for the design reasoning, you'd probably need to ask Jeremy Allaire. One should be careful with CFINCLUDE.
Al Everett
+2  A: 

The best way to explain this is to treat includes (in any language) as server-side copy/paste. That's the case for ColdFusion, ASP, PHP, .NET, you name it... The included file is considered to be running in the context of it's parent page. The server essentially takes the content of the included file and pastes it into the parent file.

Your best bet with includes is to use root-relative paths to ensure that paths always point to the proper location if you're going to include files that have their own includes.

Dan

Daniel Short
Thanks, Dan. I guess my confusion has been that ColdFusion blurs the line between code and HTML. In my mind, CF breaks the convention re relative paths that HTML uses but if I treat cfinclude more like an SSI than that makes sense. All that said though, I think the usefulness of cfinclude is severely limited because of this and could increase dramatically if this one thing were changed. But, too late now.
DaveBurns
Well you just need to realize that cfinclude *IS* an SSI, it's not "like" one :). Use <cfmodule> or a custom tag if you want the child page to honor include paths from the child page's location. Just know that if you use cfmodule you won't have access to the parent page's variables unless you use the Caller scope to reach out and grab variables from the parent.
Daniel Short