14 Replies Latest reply on Jun 8, 2011 4:44 AM by jimfid45

    Using CFC's

    jimfid45 Level 1

      Hello,

       

      I have a simple CFC defined as such. And named ct.cfc

       

      <cfcomponent>
          <!--- Celsius to Fahrenheit conversion method. --->
          <cffunction name="ctof" output="false">
              <cfargument name="temp" required="yes" type="numeric">
              <cfreturn ((temp*9)/5)+32>
          </cffunction>
      </cfcomponent>

       

      Then I have a .cfm file named test.cfm and both the cfc file and the cfm file are in the same directory. The test.cfm file is below:

      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
      <html>
      <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
      <title>Untitled Document</title>
      </head>
      <body>
      <cfscript>
        obj1 = createObject("component","ct");
        obj1.ctof(temp=100);
      </cfscript>

      </body>
      </html>

       

      I can't seem to figure out how to print the output of obj1 to the screen. I have tried obj1.temp and that does not work. Also all of the code above does not throw an error. It is only when I try to cfoutput the value I run into problems. So how do you print the value? It should be 212.

       

      Thanks,

      Jim

        • 1. Re: Using CFC's
          Owain North Level 4

          You're within a CFSCRIPT block, so you cannot use CFOUTPUT; you need the script version - writeOutput() - instead.

           

          writeOutput(obj1.ctof(temp=100)) ;

           

          Will put the return variable out to the screen.

          • 2. Re: Using CFC's
            jimfid45 Level 1

            Owain thanks for the answer. I should have been more specific. What I want to do is say output the variable later I know obj1 in some way has the value 212.

             

            So what I want to do is get 212 to the screen. I do not want to output the variable as I define it.  Use this as an example.

             

            <cfset x=5>

             

            then 200 lines later I say:

             

            <cfoutput>#x#</cfoutput>

             

            Thanks,

            Jim

            • 3. Re: Using CFC's
              Owain North Level 4
              Use this as an example.

               

              <cfset x=5>

               

              then 200 lines later I say:

               

              <cfoutput>#x#</cfoutput>

               

              Right, so how about:

              <cfset x = obj1.ctof(temp=100) >

               

              then 200 lines later I say:

               

              <cfoutput>#x#</cfoutput>


               

              Is that what you're trying to do? That'll set the variable "x" to be a copy of the value returned from your CFC's method. You can then repeatedly use said variable without actually running the method again.

              • 4. Re: Using CFC's
                henkemike Level 1
                • 5. Re: Using CFC's
                  jimfid45 Level 1

                  Owain thanks!

                   

                  I was trying to learn about objects in CF, was my goal. I am guessing now there is now way

                  to refer to obj1 to get at the 212. Meaning unless you set, as you did with <cfset x = obj1.ctof(temp=100) >

                  there is no other way to get at the 212. I was trying with obj1.temp and obj1 but to no avail.

                   

                  Thanks,

                  Jim

                  • 6. Re: Using CFC's
                    jimfid45 Level 1

                    Mike thanks for the link looking now

                    • 7. Re: Using CFC's
                      Owain North Level 4

                      You *could* make it so obj1.temp became set with the last value of the function, but it would be nonsensical and confusing.

                       

                      When you call a method, it returns something (unless it is set to return void). You then have three choices what to do with it:

                       

                      1) Ignore it. It's not the return variable that means anything, it's what the function does that's important.

                       

                        <cfset obj1.sendMeAnEmail() />

                       

                      2) Output/use it then and there

                       

                        <cfoutput>#obj1.returnSomeNumber()#</cfoutput>

                        or

                        <cfif obj1.returnNumber() GT 100 >

                          do something

                        <cfelse>

                          do something else

                        </cfif>

                       

                      3) Store it for later use

                       

                        <cfset MyReturnValue = obj1.doSomething() />

                       

                      As Mike suggested, have a read through some tutorials to make sure you have a really firm understanding of all the basics before trying to dive too deep into object-oriented programming.

                       

                      O.

                      1 person found this helpful
                      • 8. Re: Using CFC's
                        jimfid45 Level 1

                        Owain thanks again on the follow up. I guess in laymans terms I was thinking somehow obj1 contained some things(like 212) since I created it. Another words I can go back later to that instance and get the temp. Either way I will study this (CFC) area more.

                         

                        Jim

                        • 9. Re: Using CFC's
                          ilssac Level 5

                          Not the way you wrote your CFC (aka object).

                           

                          You sound like you are looking for the ColdFusion version of "Public" object variables.

                           

                          You CAN do that in a CFC using the "THIS" scope.

                           

                          <cfcomponent> 
                              <!--- Celsius to Fahrenheit conversion method. ---> 
                              <cffunction name="ctof" output="false"> 
                                  <cfargument name="temp" required="yes" type="numeric"> 
                                  <cfset this.f = ((temp*9)/5)+32> 
                              </cffunction> 
                          </cfcomponent>

                           

                          You COULD then do this in your code.

                           

                          <cfoutput>#obj1.f#</cfoutput>

                           

                          BUT MOST experienced developers would probably advise that your first code sample was a better practice.

                           

                          Public variables can be very problematic in good OOD practices, albeit for such a simple example is this it is hard to see.

                          1 person found this helpful
                          • 10. Re: Using CFC's
                            jimfid45 Level 1

                            Hello iIssac,

                             

                            That is what I was trying to do, or what I expected would happen. And like you said not the best way to write OO code.

                             

                            So overall it would be as follows:

                             

                             

                            <!--- CFC file named ff.cfc --->

                            <cfcomponent>
                                <!--- Celsius to Fahrenheit conversion method. --->
                                <cffunction name="ctof" output="false">
                                    <cfargument name="temp" required="yes" type="numeric">
                                    <cfset this.f = ((temp*9)/5)+32>
                                </cffunction>
                            </cfcomponent>

                            <!--- End of CFC file --->

                             

                             

                            <!--- Snippet from a CFM  file --->

                            <cfset s= New ff()>   <---- Here is a new instance of the ff object being created named s.
                            <cfset s.ctof(temp=35)>  <----- Here is where I use the ctof method to convert from Celsius to Farenheit.
                            <cfoutput>#s.f#</cfoutput>  <---- Here is where I output the Farenheit temp that is associated with the s instance of the ff object.

                            <!---  End of snippet from CFM file --->

                             

                            Thanks,

                            Jim

                            • 11. Re: Using CFC's
                              Owain North Level 4

                              Jim

                               

                              That's exactly correct, and would work how you say. However I would *strongly* urge you to just forget about the fact that even works, as it goes against pretty much every programming rule going.

                               

                              It also only really works because ColdFusion is so forgiving, in a "proper" programming language you'd have to set up the property beforehand, set its datatype, it'd make no sense as that's not what properties are meant to be used for.

                               

                              So yes it works, but I wouldn't get too carried away with it

                              • 12. Re: Using CFC's
                                ilssac Level 5

                                As Owain said, your code will work as expected and most would advise you to never write code like that.

                                 

                                A more oo compliant example would be to use a getter with the setter you have created and use the private "Variables" scope.

                                 

                                <!--- CFC file named ff.cfc --->

                                <cfcomponent> 
                                    <!--- Celsius to Fahrenheit conversion method. ---> 
                                    <cffunction name="ctof" output="false" return="void"> 
                                        <cfargument name="temp" required="yes" type="numeric"> 
                                        <cfset variables.f = ((temp*9)/5)+32> 
                                    </cffunction> 
                                
                                     <cffunction name="getF" output="false" return="number">
                                          <cfreturn variables.f>
                                     </cffunction>
                                </cfcomponent>
                                

                                <!--- End of CFC file --->

                                 

                                And then you just need a slight modification to your CFM example.

                                 

                                <!--- Snippet from a CFM  file --->

                                <cfset s= New ff()>   <---- Here is a new instance of the ff object being created named s.
                                     ...
                                <cfset s.ctof(temp=35)>  <----- Here is where I use the ctof method to convert from Celsius to Farenheit.
                                     ...
                                <cfoutput>#s.getF()#</cfoutput>  <---- Here is where I output the Farenheit temp that is associated with the s instance of the ff object.
                                

                                <!---  End of snippet from CFM file --->


                                Creating a whole bunch of 'getter' and 'setter' functions for a large, complex object can get tedious.  So the latest CF version includes some ability to automatically have this functionality with Components.  See the documentation for the full details.  (I have not used it enough todate to comment on it yet)

                                • 13. Re: Using CFC's
                                  Adam Cameron. Level 5

                                  As Owain said, your code will work as expected and most would advise you to never write code like that.

                                   

                                  A more oo compliant example would be to use a getter with the setter you have created and use the private "Variables" scope.

                                   

                                   

                                  Irrespective of the merits of exposing variables to calling code via the THIS scope  - which I think is fine in the appropriate situation - it's not an appropriate approach in the given example.  A conversion function should return a result, not set something in the state of the CFC instance.

                                   

                                  I could see how someone might have a Temperature.cfc, which one could init with a temperature like this:

                                   

                                  (let's see if Jive will let me post angle-bracket stuff today...):

                                   

                                  <!--- Temperature.cfc --->

                                  <cfcomponent output="false" hint="Represents a temperature.  Exposes the temperature IN_CELSIUS and IN_FAHRENHEIT">

                                   

                                      <cfset THIS.IN_CELSIUS = 0>
                                      <cfset THIS.IN_FAHRENHEIT = 0>
                                     
                                      <cffunction name="init" returntype="Temperature" access="public" output="false" hint="Sets the temperature in celsius and fahrenheit.">
                                          <cfargument name="temperature" type="numeric" required="false">
                                          <cfargument name="scale" type="string" required="false" default="CELSIUS" hint="One of either CELSIUS or FAHRENHEIT.">
                                          <cfscript>
                                              if (arguments.scale == "FAHRENHEIT"){
                                                  THIS.IN_FAHRENHEIT = arguments.temperature;
                                                  THIS.IN_CELSIUS = ((arguments.temperature - 32) / 9) * 5);
                                              }else{
                                                  THIS.IN_CELSIUS = arguments.temperature;
                                                  THIS.IN_FAHRENHEIT = ((arguments.temperature / 5) * 9) + 32;
                                              }
                                              return this;
                                          </cfscript>
                                      </cffunction>

                                   

                                  </cfcomponent>

                                   

                                  And then call it like this:

                                  <cfset boilingPointOfWaterAtSeaLevel = new Temperature(100)>
                                  <cfoutput>
                                      For Americans, the temperature is #boilingPointOfWaterAtSeaLevel.IN_FAHRENHEIT#<br />
                                      For everyone else, the temperature is #boilingPointOfWaterAtSeaLevel.IN_CELSIUS#<br />
                                  </cfoutput>

                                   

                                  Why on earth one would want a temperature CFC like this, I dunno.  But it's an example of a reasonable use of THIS-scoped variable usage.  One could also implement this with getters and setters, but that often seems like code for the sake of code to me, especially if teh getter/setter is not actually performing any logic beyond setting or returning the variable.

                                   

                                  The difference is that Temperature.cfc represents an object: it's a temperature.  In the OP's case, they've got a conversion function which is basically a UDF, and would be more at home in temperatureLib.cfm, or maybe TemperatureLib.cfc.  But it's a library function, not an object method (in the way they're using it).

                                   

                                  --

                                  Adam