tags:

views:

1168

answers:

3

I have the following two files and would like the second to extend the first:

  1. wwwroot\site\application.cfc
  2. wwwroot\site\dir\application.cfc

However, when I go to declare the component for the second file, I'm not sure what to put in the extends attribute. My problem is that several dev sites (with a shared SVN repository) are running off the same instance of ColdFusion, so I can't just create a mapping in the CF admin like so:

<cfcomponent extends="site.application">

However, ColdFusion doesn't like:

<cfcomponent extends="..application">

or any dynamic input like:

<cfcomponent extends="#expandpath('..').#application">

Creating a runtime mapping (like here) doesn't seem possible either. Creating it in the base application.cfc is useless because that code hasn't yet executed by the time the inheriting cfc is being declared; and I can't create the mapping before the inheriting component is defined because there isn't yet an application to attach it to.

Is there any way I can reference the parent directory to accomplish my extends?

Edit to clarify: The ApplicationProxy solution doesn't work because of the bolded text above. Right now, as a workaround, we're simply not checking the \dir\application.cfc into SVN so that each developer can keep a version that extends his/her own root application.cfc. Obviously, this is not ideal.

+6  A: 

Sean Corfield has a blog entry explaining how to extend a root Application.cfc.

Below is the relevant information copied from that entry.


Here's your root CFC /Application.cfc:

<cfcomponent name="Application">

    <cfset this.name = "cf7app" />
    <cfset this.sessionmanagement = true />

</cfcomponent>

Here's your proxy CFC /ApplicationProxy.cfc:

<cfcomponent name="ApplicationProxy" extends="Application">
</cfcomponent>

It's completely empty and serves merely to create an alias for your root /Application.cfc. Here's your subdirectory CFC /app/Application.cfc:

<cfcomponent name="Application" extends="ApplicationProxy">

    <cffunction name="onSessionStart">
        <cfoutput><p>app.Application.onSessionStart()</p></cfoutput>
        <cfset session.counter = 0 />
    </cffunction>

    <cffunction name="onRequestStart">
        <cfoutput><p>app.Application.onRequestStart()</p></cfoutput>
        <cfdump label="application" var="#application#"/>
    </cffunction>

</cfcomponent>


The root of each individual site should have its own Master App:

/site1/Application.cfc
/site2/Application.cfc
/site3/Application.cfc

All these applications are separate individual apps with nothing shared between them.

If any of these individual sites need to have sub-applications, then there should be ApplicationProxy.cfc alonside the Master,

e.g.
/site1/ApplicationProxy.cfc
/site2/ApplicationProxy.cfc

Then, for each sub-application you have the one that extends the proxy:

e.g.
/site1/subA/Application.cfc
/site1/subB/Application.cfc
/site2/subA/Application.cfc
Peter Boughton
Doesn't this assume that the site root is the web root? It doesn't seem to work for me.
Soldarnal
Soldernal, if the site root is not the web root, you will need a mapping to the site root. If your mapping name is foo, then you extend "foo.application".
Adam Tuttle
It seems like I just run into my original problem again, though. If I create a mapping for foo to \devsite1\, then \devsite2\dir\application.cfc will extend \devsite1\application.cfc
Soldarnal
Don't create the mapping to `/devsite1`. Create a `/common` mapping, and refer to `common.ApplicationProxy` in both `/devsite1/application.cfc` and `/devsite2/dir/application.cfc`
Peter Boughton
I'm not following you. Wouldn't this just mean the `/dir/application.cfc` files are extending a common `application.cfc`? The whole point is so that I can edit `\application.cfc` without having to worry about breaking other dev sites while doing so.
Soldarnal
I just edited the answer to try and explain how this would work for multiple sites with their own sub-apps, although I'm still not sure if I understand what you're trying to achieve.
Peter Boughton
+3  A: 

The following code is working for me. One thing I noticed though is that the application.cfc seems to get cached, so changes to the parent application cfc might not be reflected. I got around this by doing a trivial change to the child application cfc.

<cfcomponent output="false">
     <cfset variables.higherPath = ReReplace(GetMetaData(this).name,"\.[^\.]+\.[^\.]+$","") />
     <cfset variables.extendApp = CreateObject("component", "#variables.higherPath#.Application") />

     <cfloop item="variables.key" collection="#variables.extendApp#">
      <cfif IsCustomFunction(variables.extendApp[variables.key])>
       <cfset super[variables.key] = variables.extendApp[variables.key]>
      <cfelse>
       <cfset this[variables.key] = variables.extendApp[variables.key] >
      </cfif>
     </cfloop>
        <cffunction name="onApplicationStart" output="false">
      <cfset super.onApplicationStart() />
     </cffunction>
Lucas Moellers
+1  A: 

I know this is an old topic, but I found a way to do it (that seems to work in my testing) without using the CF Administrator mappings.

You can do this by adding a per-application mapping in your child Application.cfc using an expanded relative path:

<cfcomponent extends="cms.Application" output="false">
<cfset this.mappings["/cms"] = expandPath(getDirectoryFromPath(getCurrentTemplatePath()) & "../../../../")>
<cflog text="#getMetadata(this).extends.path#">
</cfcomponent>

Yeah, it feels little hacky, but it seems to work.

Edward M Smith