Geeky Stuff that isn't my novels

Inheriting CFC functionality from components outside the webroot

I’ve been working on setting up a common set of components at my workplace which we can leverage in some of the dozens of one-off applications we have developed in-house. In the current environment, each application lives largely in its own world, with separate application settings. Yet many of them share a great deal of code, access the same database, merely presenting a different view to the users depending on their roles in or out of the company.

This is a ripe opportunity to develop some more rigorously controlled components which would allow us to reuse code and reduce the number of bugs.

Here’s the problem. I’ve got a structure like this:

/ webroot – this contains a base, public facing application with it’s own application.cfm (not cfc)

Each of these has their own application cfm functionality which I can’t disturb on an overall level (it’s fifty or more working apps). We’ll be replacing them and updating them a few at a time, at which time I intend to work them into the overall framework.

So, my constraints are that when I create a new app, it resides below the webroot, and its application.cfc will exist at it’s own level. But I want to be able to have components which can inherit methods from parent classes available to all the apps.

Here’s the structure I’m looking for. First, in my shared component store, I’m creating a CFC which has a lot of shared functions in it. For purposes of our example, I’m only including on function, init()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

<cfcomponent output="no"

hint="

/component-store/com/app/functions.cfc

This component handles utility functions which are non-application specific.

So basically my component here doesn’t actually do anything other than initialize itself. But the real component has a bunch of useful utility functions which will be called from multiple applications, each of which will create a new instance of the object in its own scope. Now, remember my requirement is that I be able to instantiate this even though it’s not in the path of my application. So at the webroot level — above my application directory, I’ll create a /component-store directory which is not accessible through the webserver.

Now, inside my application directory, I’m going to create a functions.cfc intended to extend that global function cfc. Inside my local one, I’m going to have some local application only functions. Let’s create that cfc:

Okay, so this is a very simple component. It extends my already existing cfc, and adds a new function called ReportProblem() which emails a problem report based on whatever information is passed to it. So let’s go ahead and create this object and see what happens. I’m going to create the functions object in the application scope:

test

1

<cfdump var="#variables#">

So here’s the output:

test

struct

applicationname

ElectronicDeliveryReceipts

functions

undefined

Huh. What we should have seen under functions is a structure representing the component, and it should have included our ReportProblem method as well as the init() method inherited from the base component. Let’s see what happens if we call a method on it. I’ll add this line to the page. I’m expecting this to generate an error:

Element FUNCTIONS is undefined in a Java object of type class [Ljava.lang.String;.

Resolvedname

[empty string]

Basically, what’s happening here is when I create the object, coldfusion can’t instantiate it, because it can’t find the cfc it’s extending. So I need to go back to the drawing board. I’ll revert index.cfm back to it’s state where it’s dumping the application scope. But how can I get my functions.cfc to extend the global functions.cfc?

In my Google search from there, I came across this post from Ben Nadel, talking about extending application.cfc with a proxy component. Light bulb! You can include, inside a CFC, a cfinclude to another path.

So, here’s what I did. First, I created a proxy directory below my application path:

/webroot/subdirectory/MYAPPLICATION/com/app/proxy/

In the proxy directory, I’ll create a proxy functions.cfc. It only contains one line that actually does anything..

Remember our initial code. The original global version of the cfc has the init function. The local application specific cfc contains the ReportProblem function. Because we’ve got inheritance working now, it’s indistinguishable to the application which one you are calling.

There’s a probably a much more elegant way to accomplish this, but this did the trick!