I have recently started using a cfc component to store user information in the Session variable. I used to store them as individual variables in Session, such as Session.UserId, Session.Firstname, or Session.Lastname. This new component nicely wraps that all up for me into a component with get methods for each value I need (i.e. Session.User.getUserId(), Session.User.GetName(), etc).
But when I do a cfdump of the session variable for debugging, it displays the object structure's metadata. I'd like to see the values returned by the component's get methods. Any way of using a cfdump to output the function values with the object metadata?
<cfdump> isn't magic, all it does is output the value you give it. As your CFC instance doesn't expose any public properties reflecting these values, <cfdump> hasn't got any way of knowing what they are.
If you need to extract all the private properties reflecting your former session scope in one hit, then you need to create a method to do so, and then <cfdump> that. EG:
public struct function getVariables(){
return variables;
}
If you are abstracting the values you want further, eg into variables.sessionStuff (variables.sessionStuff.userId, variables.sessionStuff.name etc), then write a method getSessionStuff() which returns variables.sessionStuff.
Any way of using a cfdump to output the function values with the object metadata?
Yes, use accessors.
<cfcomponent accessors="true">
<cfproperty name="userID">
<cfproperty name="firstName">
<cfproperty name="lastName">
</cfcomponent>
Try to <cfdump> this object, you'll see the property values.
Not sure if Adobe continued support for this, but in ColdFusion 8 any variable within the THIS scope is automatically considered public (and thus visible in cfdump) while using VARIABLES scope explicitly is considered private (and thus invisible in cfdump). This way you can also avoid having stack overflows when you keep component references in your component (cfdump used to solve them recursively ending in an infinite loop). But then again: this was probably fixed in ColdFusion 9 and above.
Related
I have a collection of requests I'm trying to improve and want to be able to use the Key-Value Editing UI in Postman, but I need to pass an object.
rest_data = {
"session_id":"{{sessionId}}",
"dealer_number":{{integralinkCode}},
"customer_id":"12345",
"vehicle_id":null,
"phone":"5555555555",
"amount":"0.01",
"reference_no":"test1234",
"asm_user_id":"{{userId}}",
"message":"test"
}
Currently, I have the key set as "rest_data", and the value holds the object. This works, but I feel like it makes it a bit hard to read. Ideally, I'd like to have the properties of the object as key-value pairs in Postman.
I tried setting the keys in Postman like this rest_data["session_id"] and the value equal to the relevant value, but that didn't work.
My reasoning is so that when making changes to the body, it's easier and I can fill in the description for values and what they should be. Also, you're not able to hover over environmental variables to see their values or use environmental variable autofill within the object.
Can this be done, and if so, how? I'm also open to alternative solutions.
I'd like to pass specific values to various custom tags, like thus:
<cfif someerror>
<cfset mytag.bordercolor = "red">
</cfif>
<cf_input id="mytag">
Is this possible in some way?
According to the documentation, what you have should work EXCEPT that you forgot to enclose the variable name between hashtags #. Try this instead:
<cf_input id="#mytag#">
There are some important things to keep in mind on how the variables get passed to custom tags.
From the documentation - Passing variables to custom tags and UDFs
Passing variables to CFML tags and UDFs
When you pass a variable to a CFML custom tag as an attribute, or to a user-defined function as an argument, the following rules determine whether the custom tag or function receives its own private copy of the variable or only gets a reference to the calling page's variable:
Simple variables and arrays are passed as copies of the data. If your argument is an expression that contains multiple simple variables, the result of the expression evaluation is copied to the function or tag.
Structures, queries, and cfobject objects are passed as references to the object.
If the tag or function gets a copy of the calling page's data, changes to the variable in the custom tag or function do not change the value of the variable on the calling page. If the variable is passed by reference, changes to the variable in the custom tag or function also change the value of the variable in the calling page.
To pass a variable to a custom tag, you must enclose the variable name in number signs. To pass a variable to a function, do not enclose the variable name in number signs.
I'm not sure I follow your question, so I'll toss out some possibly relevant information.
The syntax that you typed will work.
In the input.cfm file, you would reference Attributes.id. The value of which would be "mytag".
I would suggest using cfparam to set up a default value.
<cfparam name="Attributes.id" type="string" default="tag">
for example.
If you want to pass in the "mytag" structure instead of the string "mytag" then you would use the following sytax:
<cf_input id="#mytag#">
That would allow you to get the color using Attributes.mytag.bordercolor.
In which case, your cfparam would be more like:
<cfparam name="Attributes.id" default="#StructNew()#">
If you are wanting to pass in the string, but still get the color from the variables scope of the page then it would be something like this:
<cfif StructKeyExists(Caller,Attributes.id) AND StructKeyExists(Caller[Attributes.id],"bordercolor")>
<cfset Variables.bordercolor = Caller[Attributes.id].bordercolor>
</cfif>
This is because the variables scope of the calling page is available within the custom tag as "Caller" scope. I would advise being careful in using this, however, as you are breaking encapsulation. If you are reaching out to variable names that are specifically passed in that is probably OK, but it wouldn't generally be a good idea to get non-specified variables from Caller scope.
I'm using the CreateObject() method to create an instance of a CFC and then interacting with this newly created 'instance'. I'm doing this because that's how it seems to be done, but I don't understand why we do this.
Why can't we just interact with the CFC directly instead of creating an instance of it?
A CFC is just a file with some code in it, so it makes little sense to suggest "interacting" with it, just the same as you might suggest "interacting" with a CFM file without <cfinclude>-ing it or similar.
A CFC defines a component, and to use a component, one creates an instance of it. In some languages - eg Java - one can have static properties and methods, and one can access them via the class rather than necessarily object, but CFML does not have this concept. CFCs define components which are used as objects, just the same as in other languages a class defines what it is to be an object, and to use an object, one first needs to create an instance of it.
You can call the cfc directly using cfinvoke. You just have to realize that cfinvoke creates an object of the cfc first, then executes the method you invoked. Also, once the method is invoked, the object is no longer available.
If your .cfm page is only going to use one method of the component, cfinvoke is ok because there is less code for you to write. However, if you use two or more, it's less efficient because a new object has to be created each time.
In other word, while you don't have to create an instance of the cfc first, it's often a good idea to do so.
I hope you have read OOPs and its practices. CFC is your 'blueprint' (say a car design) and object is your own data model (say a car of blue color (method to set color), with nitrogen filled tires (method to set pressure in tires) and runs on LPG (method for fuel type)). CF allow you interact directly with CFC (CFINVOKE) and you do not have to create an instance each time but it just only make sense that you would not want to go to workshop/design lab each time you want to change a configuration for your car.
I'm running my applications on CF 9. I created a CFC to concentrate my cookie handling instead of all the tags strewn about. It is simple. It has two attributes (name, value), and has 5 methods (setCookie, deleteCookie, verifyCookie, clearAllCookies, and init).
Since I wanted this method to be available throughout the application, I put this code in the onApplicationStart method of my application.cfc file:
application.oCookie = createObject("com.mycookie").init();
When I need to set a cookie in any code file I just call it like so:
application.oCookie.name="testCookieName";
application.oCookie.value="testCookieValue";
application.oCookie.setCookie();
My question is: Do I need to put a lock on this code each time I do this? If two separate users were to be on pages accessing this code at the same exact instant, can I end up with mixed up cookie values being set?
To make your oCookie thread-safe, it has to be a singleton (with no state) that only acts as a thin layer to the <cfcookie> or the cookie scope.
Therefore you should design your com.mycookie so that it accepts application.oCookie.setCookie(name, value) instead. And make sure you var-scope everything and don't store anything in the variables scope of mycookie.
And I don't think you need to use cflock.
If you haven't already, you may want to checkout WireBox.
So, I'm trying to learn and utilize components to make my code better...
I understand what getters and setters are...however, I'm not sure where to put them in respect to how my component works. My component is a faculty which has a unique id and department. I want all my information in a struct form because each faculty has a lot of information. My init method would initialize the id and the department of the specific instance and then proceed to call a query that will populate the rest of the information into a struct. I'm just not sure how to do the getters and setters for the id and department...do I just init a "blank" instance and then use a getter/ setter to actually do the input?
Also another thought/ question regarding components:
Should my component only have methods that deal with single entities (individuals) or can I also have methods in my component that deals with the whole (like a search function for all individuals).
...or should I separate the two?
Thanks!
Here's a CF8 way of setting up the faculty CFC. Notice that I didn't use the 'instance' scope 'cause when it's time to upgrade to CF9, u can remove the getters/setters and add accessor=true to the cfcomponent and you're done. However, you may find adding an artificial 'instance' scope useful when you need to get the data out of the CFC as a struct for DAO to persist your object.
<cfcomponent>
<!--- does nothing in CF8 other then for documentation purposes --->
<cfproperty name="id">
<cfproperty name="department">
<!--- if you want to type your param and return type for functions in CF8, use CFML --->
<cfscript>
function init (id, department)
{
setId(id);
setDepartment(department);
return this;
}
function getId() {
return variables.id;
}
function setId(id) {
variables.id = arguments.id;
}
// do the same for dept
// make use of Snippet in CFEclipse / CF Builder to gen for you
</cfscript>
</cfcomponent>
can I also have methods in my
component that deals with the whole
(like a search function for all
individuals). ...or should I separate
the two?
Usually in the CF world (inspired by the Java world), we'd separate them into FooService with no state, and cache your FooService as singleton in Application scope. Then implement the Create Read Update Delete (CRUD) methods that talk to the DB in FooDAO (data access object) layer. Your FooService would then call the CRUD methods in FooDAO to read (and populate) a Foo object for you.