views:

112

answers:

5

UPDATE: Seems that railo doesn't have this issue at all.

UPDATE: I'm voting to close this issue as i as feel people are focusing more on the whole "does someone have a better idea splitting up large components" part of this question (which i should never have put in) then the real problem of using cfincludes with cfcomponent.

Note: this is just a simplified example of what i'm trying to do to get the idea across.

The problem I'm having is that I want to use cfinclude inside cfcomponent so that i can group like methods into separate files for more manageability. The problem I'm running into is when i try to extend another component that also uses cfinclude to manage it's method as demonstrated below. Note that ComponentA extends ComponentB:

ComponentA
==========
<cfcomponent output="false" extends="componentb">
    <cfinclude template="componenta/methods.cfm">
</cfcomponent>

componenta/methods.cfm
======================
<cffunction name="a"><cfreturn "componenta-a"></cffunction>
<cffunction name="b"><cfreturn "componenta-b"></cffunction>
<cffunction name="c"><cfreturn "componenta-c"></cffunction>
<cffunction name="d"><cfreturn super.a()></cffunction>

ComponentB
==========
<cfcomponent output="false">
    <cfinclude template="componentb/methods.cfm">
</cfcomponent>

componentb/methods.cfm
======================
<cffunction name="a"><cfreturn "componentb-a"></cffunction>
<cffunction name="b"><cfreturn "componentb-b"></cffunction>
<cffunction name="c"><cfreturn "componentb-c"></cffunction>

The issue is that when i try to initialize ComponentA I get an the error: "Routines cannot be declared more than once. The routine a has been declared twice in different templates."

The whole reason for this is because when you use cfinclude it's evaluated at RUN TIME instead of COMPILE TIME.

Short of moving the methods into the components themselves and eliminating the use of cfinclude, how can i get around this or does someone have a better idea splitting up large components?

A: 

My advice is: reanalyze your objects, try to apply to all the OOP rules and best practices (abstraction, encapsulation, modularity, polymorphism, inheritance, DRY etc.).

So basically you want component B to have method isCrunchable(), then component A extends B, and isCrunchable() is available from inheritance. Both A and B will return different states so I don't see any problem with this. If you make one class "above" which has all the methods and components A and B extend that one, you'd get your solution for "large components", but again, I'd try to crunch this a little bit more.

If this answer doesn't help, you can post real example, maybe we'll get better idea why you need this done like that.

zarko.susnjar
the problem is that using cfinclude inside of cfcomponent results in the routine error stated above. this is because the cfinclude isn't executed until runtime and at that point because one component is extending the other, coldfusion is executing the cfincludes which contain the same method names, resulting in the error. my question is there a way around this?
rip747
I understood your question and I understood it as "I tried to shoot myself in leg, didn't work because my gun sucks and can't blow both legs in same time, how can I do this?"I have in the office one method with 66 arguments and 2k lines of code, located in cfc of 7k lines of code, Eclipse doesn't like it, I don't like it, my manager doesn't like it, but I don't think I should make it "better" by splitting it into 7 different files and spit into face of elders which spent their lives trying to find the best way to program :)
zarko.susnjar
the reason for this is because i'm trying to implement something similar to ActiveModel in CFWheels. if you'd like to take a look at the source and give me some advice it would MUCH appreciated. http://github.com/rip747/cfwheels. particularly take a look at how we implement the model portion http://github.com/rip747/cfwheels/tree/master/wheels/model/
rip747
I planned to check out cfwheels' code but didn't have time until now. If I understood well they have one model which has all the looong includes and your models extend that one. I guess wheels also doesn't work if you make model User and then extend it with FemaleUser and try to include some of the model's includes...
zarko.susnjar
For others here's how I understood it, I have User and inside included method create(), I have FemaleUser which extends User and when I try to include method create which is different than User.create() CF doesn't allow it...So it would work if you wrote those methods properly because parent's create would be overriden. Am I right ? Shit : Doesn't matter!So...In the end, I give up :) I'd just rename methods to ^a or $a (not sure about the second) and move on.
zarko.susnjar
A: 

I'm with zarko on this, you should rearrange your objects, but if you must...

In CF5 I used a trick of putting functions in the request scope. This can be done by assigning the function name to a request variable of the same name, ie for a function called getLatestUpdate:

Request.getLatestUpdate = getLatestUpdate

then, before including the file with the functions, do a chech for the existence of the variable in the request scope. Only cfinclude the functions file if the request scoped variable doesn't exist.

Downside is you need to refer to the functions with the request scope prefix, and also this will only work in the traditional metaphor of a page request, it will most likely break in things like remoting calls.

I haven't tested this and YMMV.

David Collie
A: 

I haven't tested it, but what about wrapping your cfinclude with something like:

<cfif NOT structKeyExists(this,"someMethodNameInIncludeFile")>
      <cfinclude....>
</cfif>
marc esher
What about override then? Think this breaks the whole inheritance idea.
Sergii
+2  A: 

Not tested, but I would try putting the contents of each function in an include, but defining the functions within the component file itself. `

<cfcomponent name="a">
    <cffunction name="aa">
        <cfinclude template="componenta/functiona.cfm" />
    </cffunction>
</cfcomponent>

Good luck.

Ben Doom
A: 

If your issue is purely about avoiding huge unwieldy objects, maybe you can break your objects down into several smaller objects. Component A could still contain methods ABCD, but Method A calls ComponentA_A method A, Method B calls ComponentA_B method B etc. Best if each subcomponent is not based on an arbitrary grouping, but a sensible grouping based on functionality. Another thing to experiment with (this is a wild stab in the dark) functions are usually described as structures attached to some scope. You can for instance delete functions from an Application.cfc by structDelete(this, onRequestStart). Maybe you can use the same approach to delete the functions previously attached to the request scope in the include?

John M