1 2 Previous Next 53 Replies Latest reply on Oct 26, 2012 12:38 PM by Carl Von Stetten

    Stumped - Variable exists, then does not.

    Aegis Kleais Level 3

      Whew!  This is a new one on me!  One of those times CF simply isn't making any logical sense to how I understand it.  I've even gone through CF10 Application Server and IIS Admin service restarts and still getting the same problem.

       

      In short, I have a template component which has a variable called rawCode.  It is the current request's generated HTML that is to be output to the buffer.  I am inside a method inside the template component, and I dump: THIS.rawCode.

       

      Sure enough, it contains what I expect.

       

      I then call a method from within this method (that method exists in the template component as well)

       

      <cfinvoke component="#THIS#" method="writeOutputToBuffer">

       

      All that method does right now is:

       

      <cfoutput>#THIS.rawOutput#</cfoutput>

       

      But guess what?  At that point, there's nothing!  Nothing is presented to the user.  I had it dump THIS.rawCode and BOOM, the rawCode is there and populated with what I wante returned to the user.  Has anyone seen something like this before?  I'm sure there's some rare thing I'm doing wrong here, like some recently unknown "CF10 can only support referencing a variable 20 times per request" rule or something as crazy.

        • 1. Re: Stumped - Variable exists, then does not.
          Carl Von Stetten Adobe Community Professional & MVP

          You say "THIS.rawCode" at the top of your post, but refer to "THIS.rawOutput" in the method call.

          -Carl V.

          • 2. Re: Stumped - Variable exists, then does not.
            Aegis Kleais Level 3

            Good catch.  Sorry, they all say the same thing.  'THIS.rawCode'.  Sorry 'bout that.

            • 3. Re: Stumped - Variable exists, then does not.
              12Robots Level 4

              Show us more code. What does this "template component" look like?  How does it get populated with the "rawCode". How are you invoking the Component? 

               

              Jason

              • 4. Re: Stumped - Variable exists, then does not.
                Adam Cameron. Level 5

                Dunno.  But two things.

                 

                1. If you're within the same CFC, you don't need to specify the COMPONENT attribute of the <cfinvoke> tag.  Perhaps because you are passing it THIS, it's doing something other than you expect?  Not sure.
                2. For pity's sake, don't use <cfinvoke>.  Just go <cfset writeOutputToBuffer()>

                 

                --

                Adam

                • 5. Re: Stumped - Variable exists, then does not.
                  Aegis Kleais Level 3

                  @12Robots—

                  Man, it's such an extensive setup I have.  I'll try to provide some code without giving all the exta.

                   

                  By default, the code is created in the template.cfc's pseudo constructor:

                   

                  <cfparam name="THIS.rawCode" type="string" default="">

                   

                  In the onRequest(), we create an instances of the template component by doing the following: (this component extends the root application.cfc)

                   

                  <cfset REQUEST.template = createObject( 'component', 'www.app.coms.template' )>

                   

                  We then call a method in the REQUEST.template component to start creating the output code:

                   

                  <cfinvoke component="#REQUEST.template#" method="generateRequestOutput">

                   

                  It goes through many steps, populating the THIS.rawCode with content until we get to the very end of the generateRequestOutput() method.  There are 2 closing functions:

                   

                  processTemplateVars() - Before AND after this method is called, we can dump THIS.rawCode and we see what we expect.  The last function,

                   

                  writeOutputToBuffer() - When I do the dump of THIS.rawCode in that function, I get nothing.  But when it returns back to the generateRequestOutput() after the writeOutputToBuffer(), and I dump it, it DOES exist.

                   

                  That's where I'm confused.

                   

                  @Adam Cameron—

                  1. Cool; didn't know that.  CF must assume a local invoke when the component is not specified.  I'll try to remove that.

                  2. Really?  I love how you can use argument names as attributes in a <CFINVOKE>.  I hate writing like writeOutputToBuffer( arg1, arg2, arg3 ).

                  • 6. Re: Stumped - Variable exists, then does not.
                    Aegis Kleais Level 3

                    Scrap some of that.

                     

                    It seems after I call the writeOutputToBuffer() method and return back to the generateRequestContent() method, outputing or dumping the THIS.rawCode results in NOTHING being there.  The variable just seems to empty out somewhere.

                    • 7. Re: Stumped - Variable exists, then does not.
                      12Robots Level 4

                      cfinvoke is an evil beast that serves a dark master. It is of occasional use, but in 99 out of 96 cases, it is ugly, ugly, and ugly.

                       

                      You know you can name variables the other way too, right?

                       

                      writeOutputToBuffer( arg1=arg1, arg1=arg2, arg1=arg3 )

                       

                      jason

                      1 person found this helpful
                      • 8. Re: Stumped - Variable exists, then does not.
                        12Robots Level 4

                        Does writeOutputToBuffer() have output="true"?

                         

                        Jason

                        • 9. Re: Stumped - Variable exists, then does not.
                          Aegis Kleais Level 3

                          No I did not know that, 12Robots.

                           

                          You guys are like goldmines of cool info.  Well if I can write it as <cfset functionName( argName=value, argName=value, etc.) then I'll try to go through and get rid of the invokes in my setup.

                           

                          As for the writeOutputToBuffer(), the output is set to false.  To my understanding (which can be wrong), when true, the function is processed as if wrapped in a CFOUTPUT (and vice versa for false)  I have:

                           

                          <cfoutput>#THIS.rawCode#</cfoutput>

                           

                          in the function with output=false in the method hoping that would suffice to get that content to the buffer, but there's just nothing.

                          • 10. Re: Stumped - Variable exists, then does not.
                            Adam Cameron. Level 5

                            To my understanding (which can be wrong), when true, the function is processed as if wrapped in a CFOUTPUT (and vice versa for false)  I have:

                             

                            Nope.  The OUTPUT attribute looks like it's boolean, but it's actually got three distinct states.

                             

                            TRUE = as if the code within is wrapped in <cfoutput> tags

                            FALSE = as if the code within is wrapped in <cfsilent> tags

                            [not specified at all] = just like any other CFML code: text will output, CF expressions will be processed if if surrounded in pound signs and <cfoutput> tags.

                             

                            --

                            Adam

                            • 11. Re: Stumped - Variable exists, then does not.
                              Aegis Kleais Level 3

                              So as it is in the documentation.  Wow.  ColdFusion documentation that's RIGHT.  Who'd have guessed it, eh?    *elbows ribbingly*

                               

                              Good deal.  So what I was doing was operating as <CFSILENT>  But even as such, wrapping my code in <CFOUTPUT> should have still output it to the buffer right?  Gotta find out why this thing is disappearing.

                               

                              I've been testing it and it seems if I CFABORT in the writeOutputToBuffer() after CFOUTPUT-ing it, it shows up!..... What the funk 'n wagnalls is going on here?

                              • 12. Re: Stumped - Variable exists, then does not.
                                12Robots Level 4

                                Aegis Kleais wrote:

                                 

                                But even as such, wrapping my code in <CFOUTPUT> should have still output it to the buffer right?

                                 

                                No, that's not right.  Why don't you try it.  You could have typed output="true" a thousand times since I suggested it, instead you keep arguing back and forth. Try it.

                                 

                                 

                                Aegis Kleais wrote:

                                 

                                I've been testing it and it seems if I CFABORT in the writeOutputToBuffer() after CFOUTPUT-ing it, it shows up!..... What the funk 'n wagnalls is going on here?

                                <cfabort> flushes the output buffer (or some techno jargon like that) and so it does nto matter if output="true".  No matter where you are (cfsilent, etc) if you do a dump + abort it will always show up.

                                 

                                Jason

                                • 13. Re: Stumped - Variable exists, then does not.
                                  Aegis Kleais Level 3

                                  Jason

                                   

                                  You should step back a little at this point.  I'm not sure if this was on my side or not, and I'm a proponent in the belief that communication through text-only mediums can often lead to miscues and inferred inflection of emotion that isn't there, but nobody is arguing with you.

                                   

                                  My application.cfc has the OUTPUT set to FALSE, and my onRequestStart() has the OUTPUT set to FALSE, and in it, I just put

                                   

                                  <cfoutput>Hello</cfoutput>

                                  <cfabort>

                                   

                                  And sure enough, code was output to the user.  There's obviously a misunderstanding here, as you're very obviously skilled in ColdFusion, but try not to read my posts in any preconceived argumentative tone; because there isn't one.  Thanks to what you've just stated, you helped me understand that the <cfabort> was forcibly flushing the buffer, so the way I had envisioned how things were working was faulty due to <cfabort> forcing the content rendering.  Learned another new thing;  During my development, I used cfabort so often in halting progress, that I never thought about what it was doing to the content generated already or how that was affected by the component and function output attributes.

                                   

                                  I'm always appreciative of people who help me understand these things; and as I've shown in previous posts in this thread, I'm not just waiting for an answer; I am still trying things locally in the meantime.

                                  • 14. Re: Stumped - Variable exists, then does not.
                                    Aegis Kleais Level 3

                                    With the info Jason gave me, it now makes sense as to why the code exists while I am performing a CFABORT.

                                     

                                    Let me state the following in hopes it might help.  In the template.cfc I defined the THIS-scoped variables not via <CFSET> but via <CFPARAM>, ie:

                                     

                                    <cfparam name="THIS.var1" type="string" default="value">

                                     

                                    rather than

                                     

                                    <cfset THIS.var1 = 'value'>

                                     

                                    Usually, I use <cfparam> while in functions after declaring the local scope like:

                                     

                                    <cfset var LOCAL = {}>

                                    <cfparam name="LOCAL.varName" type="string" default="value">

                                     

                                    I'm just stating this in hopes that using cfparam in the component's pseudo-constructor isn't a problem (seemed to work fine for application.cfc, but I'm just stating it nonetheless)

                                    • 15. Re: Stumped - Variable exists, then does not.
                                      12Robots Level 4

                                      So did you add output="true" to writeOutputToBuffer() or not?  How about you try what people suggest, and then if it works you ask why? 

                                       

                                      I'm glad that you think that this is a great way for you to learn, but you have to understand that when you don't even try what is suggested then you only serve to frustrate those who are trying to help you.

                                       

                                      To my knowledge you still have not tried the 2 second fix that I suggested. I'm done trying to help you.

                                       

                                      Stepping all the way back,

                                       

                                      Jason

                                      • 16. Re: Stumped - Variable exists, then does not.
                                        Aegis Kleais Level 3

                                        Jason

                                         

                                        I've tried being respectful, I've even made mention that I did what you said and got the result you said I'd get as verification that I comprehended a new concept.

                                         

                                        The last thing I need is this attitude.  The forum doesn't have an ignore feature, otherwise you'd rightfully be on it.  But if this is how you help people on the forums, then go pound some dirt, because millions of teachers before you have been able to get someone to comprehend something without the pissant attitude that comes with your posts.

                                        • 17. Re: Stumped - Variable exists, then does not.
                                          12Robots Level 4

                                          And where did you tell me that you added output="true" to your function? And where did you tell me that that worked and that your problem was solved?

                                           

                                          I missed it amongst all the other learning.

                                           

                                          Jason

                                          • 18. Re: Stumped - Variable exists, then does not.
                                            12Robots Level 4

                                            Listen, I'm sorry that I got so upset. I strive to help people and I got frustrated. I apologize for that.

                                             

                                            In all seriousness, I suggested several times that you try adding output="true" to your function and I can see no where in this thread where you actually said you tried that. I see where you tell me that it is set to false, but I don't see where you tell me that you tried my suggestion. That is frustrating.  I tried helping you and it just seemed that you were repeatedly ignoring my advice. I understand that you don't just want an answer and that you want to learn. I respect that. But couldn't you try what I suggested, report back and ask questions about it?  I'm more than happy to answer questions. But when I feel like my advice is being completely ignored, I tend to get a little irritated. I suspect that I am not alone in that feeling.

                                             

                                            Jason

                                            • 19. Re: Stumped - Variable exists, then does not.
                                              Aegis Kleais Level 3

                                              Don't assume everyone is adept as you might be to learning things.  I don't like having it called to light because it's as frustrating for me as I'm sure it is for others, but I don't learn the same way others do.  I'm the type of person, when learning something, has to take things step by step and comprehend them at each step, or I lose focus and the concept is lost completely to me.

                                               

                                              Secondly, due to how rare it is, I want to commend you on at least being man enough to apologize.  I don't mean to cause anyone frustration, and if I do, I'm sorry for doing so.

                                               

                                              I have set the output on the onRequest(), generateRequestContent() and writeOutputToBuffer() all to TRUE for the time being.

                                               

                                              In writeOutputToBuffer() I am merely doing a:

                                               

                                              <cfoutput>#THIS.rawCode#</cfoutput>

                                               

                                              And I have removed all <CFABORT> tags.  Upon running a request, I do not see any output on screen nor in the view source.

                                               

                                              ** UPDATE ** I might have another temporary issue that is skewing my results, so don't take what I just said to heart yet.  I was going through my code changing CFINVOKE's to <cfset path.to.functionName( arg='value' ) as suggested by Adam, and I noticed that when I request my hostname, I don't see it redirecting to the login page, like it should.

                                               

                                              Let me see if I can fix THAT issue, and then see if having turned all those OUTPUT to true made a difference.  I'll let you know...

                                              • 20. Re: Stumped - Variable exists, then does not.
                                                12Robots Level 4

                                                Cool. Thank you for accepting my apology.

                                                 

                                                 

                                                Aegis Kleais wrote:

                                                 

                                                ** UPDATE ** I might have another temporary issue that is skewing my results, so don't take what I just said to heart yet.  I was going through my code changing CFINVOKE's to <cfset path.to.functionName( arg='value' ) as suggested by Adam, and I noticed that when I request my hostname, I don't see it redirecting to the login page, like it should.

                                                 

                                                 

                                                As Jason suggested

                                                 

                                                Jason

                                                • 21. Re: Stumped - Variable exists, then does not.
                                                  Aegis Kleais Level 3

                                                  Ooh!  Sorry man.  I didn't mean to mix you two up.  You're right.  YOU were the one telling me how evil the CFINVOKE was.  Something about a dark master if I recall.

                                                   

                                                  And hey!  Once I resolved the snafu on my part as I was going through and changing those invokes over, my page started redirecting to the login, the template component got called AND THE CODE DUMPED TO THE BUFFER!!!

                                                   

                                                  Jason, if you were local, I'd buy you a Steak Dinner and some beers.  I learned a lot of things here; how <CFABORT> dumps generated code to the buffer, how to properly determine the OUTPUT attribute on my components and functions.  That seems to be it!  The onRequest had a output='true' but both my generateRequestContent() and writeOutputToBuffer() had output='false' under the bad understanding that using <cfoutput> would override that.  (I now know better, since output='false' is like using a <CFSILENT> and when not aborting, a silent tag keeps all output out of the buffer (which was why the code wasn't showing)

                                                   

                                                  Jason, you the man!  My thanks for helping me comprehend ColdFusion.

                                                  • 22. Re: Stumped - Variable exists, then does not.
                                                    12Robots Level 4

                                                    You're welcome.  Glad it worked out.

                                                     

                                                    jason

                                                    • 23. Re: Stumped - Variable exists, then does not.
                                                      Adam Cameron. Level 5

                                                      I was going through my code changing CFINVOKE's to <cfset path.to.functionName( arg='value' ) as suggested by Adam, and I noticed that when I request my hostname, I don't see it redirecting to the login page, like it should.

                                                       

                                                       

                                                      As Jason suggested

                                                       

                                                       

                                                      Whilst we're splitting hairs (and, seriously, I don't care), but it was me who suggsted getting rid of the <cfinvoke> tags in favour of just using method calls.  You (Jason) blathered on about evil and that sort of nonsense, but did clarify the name=value pairing thing.

                                                       

                                                      --

                                                      Adam

                                                      • 24. Re: Stumped - Variable exists, then does not.
                                                        12Robots Level 4

                                                        Of course, you are aright. I thought about that last night as I was trying to sleep. You beat me to the correction.

                                                         

                                                        Jason

                                                        • 25. Re: Stumped - Variable exists, then does not.
                                                          Adam Cameron. Level 5

                                                          You should step back a little at this point.  I'm not sure if this was on my side or not, and I'm a proponent in the belief that communication through text-only mediums can often lead to miscues and inferred inflection of emotion that isn't there, but nobody is arguing with you.

                                                           

                                                          Hey guys, I know you've kissed and made up 'n' all, but just from someone on the periphery...

                                                           

                                                          Aegis, Jason did have a point that you tend to waffle a bit about your explorations and go off on tangents rather than either just doing what we've asked, or if you have: letting is know that you've done what we asked.  The findings and wafflings are good (I do mean this), but TBH, it'd be great if you could just focus on the problem you've raised, let us help you with it, get it sorted, then we can cover the peripheral musing or asides or what-have-you separately.  It's difficult to work out where we are at with getting the problem solved some times.  I was in exactly the same position as Jason was last night, not knowing whether you'd actually tried what was suggested or not.

                                                           

                                                          Jason: yeah, slightly surly there mate (and, yes, pot-kettle etc).  But TBH, I thought it wasn't entirely misplaced.  Well the message was correct if not perhaps the delivery. 

                                                           

                                                          Anyway: this post is motly pointless, but it was my reading of the latter part of the thread, anyhow.

                                                           

                                                          Cheers.

                                                           

                                                          --

                                                          Adam

                                                          • 26. Re: Stumped - Variable exists, then does not.
                                                            12Robots Level 4

                                                            Someone just asked me offline, because of this thread, why I thought cfinvoke was evil. I figure I would post my response here to answer for anyone else that may be interested.

                                                             

                                                            Two reasons

                                                             

                                                            1. It is terribly, terribly, terrible verbose. Consider these two equivilent code blocks:

                                                             

                                                            <!--- non-cfinvoke version --->

                                                            <cfset myvar =  myObject.myCustomFunction(arg1=arg1, arg2=arg2)  />

                                                             

                                                            <!--- cfinvoke version --->

                                                            <cfinvoke component="#myobject#" method="myCustomeFunction" returnvariable="myvar">

                                                                 <cfinvokeargument name="arg1" value="#arg1#" />

                                                                 <cfinvokeargument name="arg2" value="#arg2#" />

                                                            </cfinvoke>

                                                             

                                                            This extremely simple function takes almost 4x more characters to type as a cfinvoke than otherwise. Extrapolate that to larger functions and you get an ugly, ugly, hard-to-read mess. All that code just runs together in my eyes and it's hard ot tall where the arguments are, what the return variable will be etc. The non-cfinvoke version is so much cleaner and to anyone that has programmed using any other language, it is obvious what is going on.

                                                             

                                                            2. cfinvoke cannot create persistent objects

                                                             

                                                            If you use cfinvoke to create an object, you cannot reuse that object. So in most cases, you're going to have to use createObject() anyway to create the object for cfinvoke to use which removes half of the once perceived benefit of cfinvoke.

                                                             

                                                            Hope that clears it up,

                                                             

                                                            cfinvoke is just ugly syntax. ColdFusion gets enough grief about being verbose and ugly. Let's not make it worse by using cfinvoke when there are better, easier, more useful and effective options.

                                                             

                                                            Jason

                                                            • 27. Re: Stumped - Variable exists, then does not.
                                                              Adam Cameron. Level 5

                                                              I agree with everything you say.

                                                               

                                                              Bear in mind, though, that it's a fairly common practice to have an init() method in a CFC these days, so one can do this:

                                                               

                                                              <cfinvoke component="Foo" method="init" returnvariable="myFoo">

                                                               

                                                              Still, that's a bit rubbish compared to:

                                                               

                                                              <cfset myFoo = new Foo()>

                                                               

                                                              There's also another reason: <cfinvoke> is a peculiarity of CFML, and will be meaningless to anyone from outwith CF.

                                                               

                                                              Whereas these syntaxes (below) are going to be either familiar or easily inferable to most people coming from other popular languages:

                                                               

                                                              myFoo = new Foo();

                                                              myFoo = createObject("Foo");

                                                               

                                                              --

                                                              Adam

                                                              • 28. Re: Stumped - Variable exists, then does not.
                                                                Aegis Kleais Level 3

                                                                You've hit the nail on the head with 1 key word; Focus.

                                                                 

                                                                My learning condition is unique in that I have a hard time maintaining focus, and as studies into the 'working memory' (the area responsible for short-term memory) have shown, people like myself who others would consider are 'absent minded' have a core problem with focus, which is vital to maintaining a high-functioning working/short-term memory.  This is the reason why you see me 'waffling'.

                                                                 

                                                                I know it's a fault of mine, and situations like this one on the forum (and HUNDREDS at work) constantly remind me of my short-coming, causing me to have to bring it to attention over and over if I were to preface all forum posts with it.  What compounds that sad state of affairs is, being a perfectionist, and realizing my memory is FAR from perfect (and causes others this kind of distress), causes me to hate myself for something I really have little control over.

                                                                 

                                                                So for what it's worth, I'm sorry if it seems I'm going off key.  You guys remind me of co-workers I have who don't have those focus issues, and when they try to teach me something, they present multiple new ideas and things I don't yet have a firm grasp on (or as we saw here, THOUGHT I knew, but found out I didn't know how they actually worked) which just derails me completely and forces me to ask them to present the topics in a single-threaded approach.

                                                                 

                                                                On the other side of people like myself who have focus issues, the good thing they say about them is that the lack of focus makes them hyper vigilant about their surroundings (the very same surrounding-generated cues which cause them to lose focus)  I have saved my own life and others thanks to how aware I am of my environment along with quick reflexes; but there have been many more times where I'd gladly give all that up just to have more focus.

                                                                • 29. Re: Stumped - Variable exists, then does not.
                                                                  Aegis Kleais Level 3

                                                                  I was having an issue with converting some of my INVOKES but using what I learned I changed:

                                                                   

                                                                  <cfinvoke component="#APPLICATION.paths.appAbsComsFQDN#app" method="processXMLPathingVars" data="#LOCAL.moduleConfigData#" returnvariable="LOCAL.moduleConfigData">

                                                                   

                                                                  to this:

                                                                   

                                                                  <cfset LOCAL.moduleConfigData = createObject( 'component', APPLICATION.paths.appAbsComsFQDN & 'app' ).processXMLPathingVars( data = LOCAL.moduleConfigData )>

                                                                   

                                                                  And it seemed to do the job.  (Plus, like you guys are saying, is much less verbose.  I think when you first start off in CF, the ability to be verbose eases you into using it; but after you get better at CF, you just want your code to take the least amount of space (and processing time) to be as optimal as possible.

                                                                   

                                                                  Jason, on the second point you made, I'm looking for clarification.  You stated that when you use CFINVOKE to create an object, that object cannot be reused.  So, if I do something like this:

                                                                   

                                                                  <cfset REQUEST.template = createObject( 'component', 'www.app.coms.template' )>

                                                                   

                                                                  vs.

                                                                   

                                                                  <cfinvoke component="www.app.coms.template" returnvariable="REQUEST.template">

                                                                   

                                                                  Now, I hopefully understand that the REQUEST scope is only existing for as long as the request; it's persistence is that long, right?  Unlike an APPLICATION scope, which is persistent over multiple requests.  But during the request, would not the application be able to reference REQUEST.template (and all the methods it has) via either of the code examples above?  I admit, I was using the latter, but you guys have taught me some new things and I'd like to tighten up my coding practices to be more optimal.

                                                                  • 30. Re: Stumped - Variable exists, then does not.
                                                                    BKBK Adobe Community Professional & MVP

                                                                    Just a little addition to Adam's points on cfinvoke. I think that Jason is being too hard on cfinvoke.

                                                                     

                                                                    Why focus just on the invocation of methods? Take a look at cfinvoke's list of attributes. It contains additional functionality that is beyond the reach of any one single type of createobject() or <cfobject>. Also, with cfinvoke we can invoke a method stored in a dynamic variable more elegantly than with createobject, for example, like this:

                                                                     

                                                                    <cfinvoke component="Foo" method="#someDynamicVar#" returnvariable="myFoo">

                                                                     

                                                                     

                                                                    [edited emphasis: any one single type]

                                                                    • 31. Re: Stumped - Variable exists, then does not.
                                                                      12Robots Level 4

                                                                      I will agree that cfinvoke is useful for invoking methods when the methods name is stored in a variable.

                                                                       

                                                                      I will not, however, concede that there is anything else that cfinvoke can do that createObject() cannot do more eloquently and with less code.

                                                                       

                                                                      Jason

                                                                      • 32. Re: Stumped - Variable exists, then does not.
                                                                        12Robots Level 4

                                                                        >> <cfinvoke component="www.app.coms.template" returnvariable="REQUEST.template">

                                                                         

                                                                        Where is the method you are invoking?  If infact you meant:

                                                                         

                                                                        <cfinvoke component="www.app.coms.template" returnvariable="REQUEST.template" method="init">

                                                                         

                                                                        Where init() returns an instance of the object, then yes, you could reuse that object, but it only works if you have an init method and the init method returns an instance of the object. Not all objects are guaranteed to have such a method. createObject() will create an instance of the object and return it regardless of the availability of an init() method.

                                                                         

                                                                        Jason

                                                                         


                                                                        • 33. Re: Stumped - Variable exists, then does not.
                                                                          Aegis Kleais Level 3

                                                                          I have to admit that when it comes to the whole 'objects returning THIS' area of OOP, I'm not fully 'there' yet.  I am attempting to learn CF in an OOP-oriented as possible.  Maybe if I give you a background into what I've done so far, you can say "That's fine" or "That's a bad coding habit".

                                                                           

                                                                          I have 5 components which have such commonly accessed functions in them, I store them into the APPLICATION scope in a structure called 'coms' (APPLICATION.coms)  These are : data.cfc, error.cfc, security.cfc, template.cfc and utility.cfc.  So after application initialization, I have the following 5 objects in a persistent scope:

                                                                           

                                                                          • APPLICATION.coms.data
                                                                          • APPLICATION.coms.error
                                                                          • APPLICATION.coms.security
                                                                          • APPLICATION.coms.template
                                                                          • APPLICATION.coms.utility

                                                                           

                                                                          When I create them, I basically do a CFDIRECTORY of all '.cfc' files in the designated folder, and I loop over them in the following fashion:

                                                                           

                                                                          <cfloop query="LOCAL.fwComponents">

                                                                               <cfset structInsert( APPLICATION.coms, listFirst( name, '.' ), createObject( 'component', 'www.apps.coms.' & listFirst( name, '.' ) ), true )>

                                                                          </cfloop>

                                                                           

                                                                          So if I understand things, so far, I've created 5 persistent component objects, right?  Even though I'm delving into comprehending them as objects, I have a later function called "instantiate FWComponentInstances" where I pass params off to that object's init() function in order to customize its instance. 

                                                                           

                                                                          Having assumed this is all good, I realized I don't need to send the THIS.datasource variable to the APPLICATION.coms.data component object's init() function, because since that component extends the root application, it shares the THIS.datasource variable, and has access to it anyways.

                                                                           

                                                                          Anyways, onRequestStart() I create 2 request-based instances off the APPLICATION instance components, namely:

                                                                           

                                                                          <cfset structInsert( REQUEST, 'error', APPLICATION.coms.error, true )>

                                                                          <cfset structInsert( REQUEST, 'template', APPLICATION.coms.template, true)>

                                                                           

                                                                          My mindset behind this was that 'For every user who makes a request, they need an instance copy of these 2 components because the request could have it's own error (while someone elses does not) so I don't want to share that, and the same with the template component (it uses a variable called 'rawCode' that is the request's generated code, and since each user has their own request, we use an instance rather than the object in the APPLICATION scope.

                                                                           

                                                                          I am reading through: http://objectorientedcoldfusion.org/ right now (answers some questions, raises others), in hopes I have the right methodology going forward.

                                                                           

                                                                          (UPDATE: I have completely revoked the invoke on my site!  I understand BKBK's note that CFINVOKE can do more than just component instantiation, and that's where it gets its power, but since component invokation was all I was currently using it for on my site, I have replaced it with CFSET-based calls.)

                                                                          • 34. Re: Stumped - Variable exists, then does not.
                                                                            12Robots Level 4

                                                                            Aegis Kleais wrote:

                                                                             

                                                                            Anyways, onRequestStart() I create 2 request-based instances off the APPLICATION instance components, namely:

                                                                             

                                                                            <cfset structInsert( REQUEST, 'error', APPLICATION.coms.error, true )>

                                                                            <cfset structInsert( REQUEST, 'template', APPLICATION.coms.template, true)>

                                                                             

                                                                            No, you aren't creating 2 request-based instances off the APPLICATION scope. You are adding two references to the object in the application scope. The objects that are shared by all users. Your users are not gettign their own instance of the objects per request, they are all sharing the same objects.

                                                                             

                                                                            structInsert() does nto make a copy of an object, it creates a new reference to the object. If you want each user to have their own instance of the objects on every request, then you need to createObject() on every request, probably in onRequestStart().

                                                                             

                                                                            If however all you need is for each user to have access to these singletons, then you can access them directly from the APPLICATION scope, there is no need to make a reference in the request scope.

                                                                             

                                                                            What you need depends on what those objects are actually doing.

                                                                             

                                                                            Jason

                                                                            • 35. Re: Stumped - Variable exists, then does not.
                                                                              Aegis Kleais Level 3

                                                                              So, what I'm doing is creating pointers to the same object then, right?  Unless I specifically say:

                                                                               

                                                                              <cfset REQUEST.template = createObject( 'component', 'www.app.coms.template' )>

                                                                               

                                                                              then doing it in the previous way I showed was simply pointing back to the APPLICATION.coms.template object.

                                                                               

                                                                              Looks like I'll need to change my code (but I'm going to continue reading about OOP before doing so to see if I better grasp these concepts)

                                                                               

                                                                              Of the 5 components (data, error, security, template and utility), I segregated them as follows:

                                                                               

                                                                              REQUEST-scoped components (because these components deal with user-based requests and functionality, I stored them into the REQUEST scope)

                                                                              • REQUEST.error - deals with handled exceptions
                                                                              • REQUEST.template - deals with template generation (generates output of each user request)

                                                                               

                                                                              APPLICATION-scoped components (because these hold non-user-based functionality, things that all users make use of and are not based on the user's unique request needs)

                                                                              • APPLICATION.coms.data - data access, such as calling queries, writing logs, etc.
                                                                              • APPLICATION.coms.security - user authentication/authorization functions
                                                                              • APPLICATION.coms.utility - miscellaneous functions, like conversions and other commonly-needed UDFs

                                                                               

                                                                              Jason, I think I see what you mean with my code.  structInsert() was making a key that POINTED to something that was instantiated into the APPLICATION, so in effect, it was not going to be uniquely instanced to the user's request.  I think I really need to read up on the OOP functionality of CF to catch myself from doing these types of mistakes where I'm assuming I"m getting one thing, but in fact, getting another.  Thanks for the catch there.  I will update my site accordingly.

                                                                              • 36. Re: Stumped - Variable exists, then does not.
                                                                                Aegis Kleais Level 3

                                                                                This has been an interesting read on objectorientedcoldfusion.org, but it raised a couple questions.

                                                                                 

                                                                                1. To my knowledge, when a component extends another (like our template.cfc extending the root application.cfc), then the child has access to the parent's private functions and variables.  Currently, my template.cfc had variables that I placed into the THIS scope, but after reading the article, I think I need to change them to the VARIABLES scope, making them private to the component.  If I create a instance of this component via: <cfset REQUEST.template = createObject( 'www.app.coms.template' ).init()>, do I have to create "Getters" and "Setters" in order to simply get the value of VARIABLES-scoped variables in that component?  ie, if there was a VARIABLES.myName = 'Aegis', is it possible to just get its value by saying <cfoutput>#REQUEST.template.myName#</cfoutput> or is that variable so private that I would have to call a function in the template.cfc that returns that value?  like <cfoutput>#REQUEST.template.getName()#</cfoutput>?  The site doesn't really say.

                                                                                 

                                                                                It DID, however show me what the init() function is, and how it can customize the instantiated copy of that component.  Very powerful.  A lot of things are beginning to click, and it's been thanks to you guys explaining these rather advanced intricacies.  If I understand it correctly, if you had a component called dog.cfc, and it had a variable which held the name of the dog (defaulted to nothing), I could instantiate 2 dogs like:

                                                                                 

                                                                                <cfset REQUEST.dog1 = createObject( 'www.app.coms.dog' ).init( name='HeyYou' )>

                                                                                <cfset REQUEST.dog2 = createObject( 'www.app.coms.dog' ).init( name='Mr.ChewyBiteUms' )>

                                                                                 

                                                                                Each has it's own copy of internal variables and access to that component's methods, which can reference those unique instance variables to perform in different ways.

                                                                                • 37. Re: Stumped - Variable exists, then does not.
                                                                                  Adam Cameron. Level 5

                                                                                   

                                                                                  • APPLICATION.coms.data
                                                                                  • APPLICATION.coms.error
                                                                                  • APPLICATION.coms.security
                                                                                  • APPLICATION.coms.template
                                                                                  • APPLICATION.coms.utility

                                                                                   

                                                                                  [...]

                                                                                   

                                                                                  Having assumed this is all good, I realized I don't need to send the THIS.datasource variable to the APPLICATION.coms.data component object's init() function, because since that component extends the root application, it shares the THIS.datasource variable, and has access to it anyways.

                                                                                   

                                                                                   

                                                                                  I meant to comment on this.  Those CFCs you mention should not extend Application.cfc.  Only other Application.cfcs should extend an Application.cfc.  When using OO inheritance, you ought to follow the "is a" rule.  An Apple IS A Fruit, so Apple.cfc can extend Fruit.cfc.  An Apple is NOT an Orange, so Apple.cfc should not extend Orange.cfc.

                                                                                   

                                                                                  Data is not an Application, so it should not extend Application.cfc.

                                                                                   

                                                                                  You are using inheritance to make variable access more convenient, which is something one ought not do.

                                                                                   

                                                                                  There is another rule "has a" which would work (kind of) here.  A Data.cfc might HAVE A application context (ie: some settings from the Application.cfc), so this suggests Data.cfc should get initialised with an applicationContext object (or perhaps just a struct, to save too much horsing around), which would hold DSN values etc.

                                                                                   

                                                                                  But to be honest, Data.cfc probably just needs the DSN passed into it, yes?  So don't mess around with application context objects/structs; just give its init() a DSN argument, and initialise it accordingly.

                                                                                   

                                                                                  Or use ColdSpring to manage all of this sort of thing for you.

                                                                                   

                                                                                  --

                                                                                  Adam

                                                                                  • 38. Re: Stumped - Variable exists, then does not.
                                                                                    BKBK Adobe Community Professional & MVP

                                                                                    Aegis Kleais wrote:

                                                                                     

                                                                                    It DID, however show me what the init() function is, and how it can customize the instantiated copy of that component.  Very powerful.  A lot of things are beginning to click, and it's been thanks to you guys explaining these rather advanced intricacies.  If I understand it correctly, if you had a component called dog.cfc, and it had a variable which held the name of the dog (defaulted to nothing), I could instantiate 2 dogs like:

                                                                                     

                                                                                    <cfset REQUEST.dog1 = createObject( 'www.app.coms.dog' ).init( name='HeyYou' )>

                                                                                    <cfset REQUEST.dog2 = createObject( 'www.app.coms.dog' ).init( name='Mr.ChewyBiteUms' )>

                                                                                     

                                                                                    Each has it's own copy of internal variables and access to that component's methods, which can reference those unique instance variables to perform in different ways.

                                                                                    That might indeed be so. However, there is one point I hope you will pay attention to. It relates to maintenance and is variously called "The Law of Demeter", "Principle of Least Knowledge", "Only talk to your friends" or "Don't talk to strangers".

                                                                                     

                                                                                    This is a software design rule that says that an object should avoid invoking the methods of a member object returned by another method. In other words, the rule says your code should, when invoking a method, use as few dots as possible, ideally just one. Thus, a.methodA() is preferable to a.b.methodB().

                                                                                     

                                                                                    The following pseudocode illustrates this:

                                                                                     

                                                                                    component A{

                                                                                    methodA () {

                                                                                    b = createobject("B").init();

                                                                                    return b;

                                                                                    }

                                                                                    }

                                                                                     

                                                                                    component B{

                                                                                    methodB () {

                                                                                    // functionality needed by A

                                                                                    }

                                                                                    }

                                                                                     

                                                                                    Consider the code a.b.methodB(). The object a creates the object b by a method call, and uses b to call methodB(). This kind of chaining makes a component to be dependent on the internal structure of others. If you wish to change a component in such circumstances, you will have to rework all its callers.

                                                                                     

                                                                                    I'll borrow this line of code from you:

                                                                                     

                                                                                    REQUEST.dog = createObject( 'www.app.coms.dog' ).init( name='HeyYou' );

                                                                                     

                                                                                    Let us combine it with an often quoted Demeter example. 

                                                                                     

                                                                                    REQUEST.dog.getBody().getTail().wag();

                                                                                     

                                                                                    Programmers are advised to avoid writing code-chains like that. This is bad because that one line depends on the structure of three different objects. This style of coding creates structural dependencies (coupling) between unrelated objects. If you use it throughout, your software will be a nightmare to maintain.

                                                                                     

                                                                                    The solution is to re-engineer the example as follows:

                                                                                     

                                                                                    REQUEST.dog.expressHappiness();

                                                                                     

                                                                                    This leaves it up to the implementation of the dog to decide what to do when the bone appears.

                                                                                    • 39. Re: Stumped - Variable exists, then does not.
                                                                                      Aegis Kleais Level 3

                                                                                      Adam.  That makes complete sense now that I have a futher grasp.  I will cut off all extension of those 5 core components and then see if I can change the framework/applicaiton so that they pass what is needed.  I have successfully already modified my REQUEST.template component and moved certain vars that are needed by other components into its THIS scope, leaving the rest in its private VARIABLES scope, and after adjusting code where it was needed, was able to remove the "getPrivateVar()" function I made in the template component.  Much cleaner.  I'll try to remember these "is a" and "has a" rules for more structured. development.

                                                                                       

                                                                                      BKBK.  I'm trying to wrap my ahead around your info.  I've gone so far as to create substructures with a semantic name to them (increasing the 'dot count'), for example.

                                                                                       

                                                                                      <cfset structInsert( APPLICATION, coms, {}, true)>

                                                                                      <cfset structInsert( APPLICATION.coms, createObject( 'www.app.template' ), true )>

                                                                                       

                                                                                      Now I can call APPLICATION.coms.template (though 'coms' is more of a placeholder than calling 'APPLICATION.template'.  I think this has to do with my overly aggressive nature to "organize" things.  Having everything be in the root APPLICATION scope just seems messier to me vs this 'coms' structure, which I know "holds application components".

                                                                                       

                                                                                      What I took from your post (and correct me if I'm wrong) is that we should take as direct as possible route from object to method, without the need to transverse from one to the other for the same task.  Am I "barking" up the right tree there?

                                                                                      1 2 Previous Next