Did you know that ColdFusion 8 adds "component" as a valid type to both the returnType attribute of cffunction and the type attribute of cfargument? What does this mean? The default "rule" for types is that if you do not specify a type recognized by ColdFusion (list provided at the bottom of this post), then ColdFusion assumes you mean a component. So for example:
<cfargument name="app" type="apple">
This line means that the app argument must be a component of type apple. It is also valid to pass in a component that extends apple, like greenapple.cfc. But again - what happened here was that ColdFusion didn't recognize apple and therefore considers it the name of a component.
ColdFusion 8 adds to the list of the supported types by adding "component". When you use component, you can pass any CFC instance. In the past, the only way to allow for any CFC would be to use "any". If we wanted to change that app argument to allow any CFC, we could use this:
<cfargument name="app" type="component">
For your reference, here is the list of supported types for cfargument/cffunction.
any | Any variable type is allowed. |
array | An array is required. |
binary | Binary data is required. |
boolean | Boolean data is required. |
component | A component instance is required. |
date | Date data is required. |
guid | A valid GUID value is required. |
numeric | Numeric data is required. |
query | Query data is required. In case it isn't obvious, a query with no rows is still a valid query. |
string | String data is required. |
struct | Structure data is required. |
uuid | A ColdFusion UUID is required. |
variableName | The value must be a string and must be a valid ColdFusion variable name. It doesn't mean the variable has to exist, just that the variable name is valid. |
void | Speficies that no value is used. This only works in cffunction, not cfargument. |
XML | XML data is required. |
One last note - you can also specify a component name and brackets. For example, apple[]. This means that an array of apple components is required. Do note though that ColdFusion only checks the first item in the array.
Archived Comments
"In the past, the only way to allow for any CFC would be to use 'any'."
This isn't entirely accurate. I've been doing this since MX 6.1, this is how I require a component of any type:
<cfargument name="bean" type="WEB-INF.cftags.component" required="yes" />
Ah - good one there Dustin!
Ray - could you give an example of why (and maybe how) I would do this?
Cheers,
Davo
There is a function up on CFLib that generates documentation for CFCs. That could be switched to use component.
I can't think of much more - my creativity today is low. ;)
Personally, I use beans to pass data around. A bean is basically a component that stores data and has getters/setters for each data element in the bean. What I've done is created a validation object that I pass the bean to for validation. The reason I do this is because I can set up my validation rules inside a centralized validation XML file. This way, whenever my validation rules change, I don't have to search through all my code to find out where all it's being validated. I can simply change the validation rules for the mapping of the bean.
HTH
Not sure why this was there in the first place. "Any" was much too loose.
I'm pretty sure I've been using typed components as arguments and return values since cfmx6.1. I'll have to go back and check. The short hand for arrays and structures is definitely new, though.
I did a blog entry a few weeks back about the type checking feature/issue with sample code if you want to see it in action. http://mrmx.blogspot.com/20...
Depending on the application's setup, sometimes you have to use the full dot path to the component to properly type it.
I am using a "Query Factory" component for all queries for my big Application. I want to know is it good or bad to use this in place of CFquery as performance wise.
I am using same kind of process for Object Factory. so its good or bad performance wise?
Pls advice.
Here is the code for QueryFactory, this is rough code may need some corrections, goal is to find execting all queries with queryFactory is good or not? thanks always for suggestions.
--------------------------------------------------
<cfcomponent output="false" hint="query factory"
extends="exception.load">
<cfscript>
init();
</cfscript>
<cffunction name="init" access="public" output="false"
returntype="any" hint="Initialize the query factory object">
<cfargument name="DSN" required="false" type="any"
default="DSNOfApp" hint="DSN for query" />
<cfset var dsn = Arguments.DSN>
<cfscript>
if (trim(dsn) eq "")
{
dsn="defaultdsnforyourapplication";// default dsn for ur
application
}
setDSN(DSN);
setQueryString("");
</cfscript>
</cffunction>
<cffunction name="getType" access="public" returntype="any"
output="false" hint="Returns the objects type">
<cfreturn "utility.queryFactory" />
</cffunction>
<cffunction name="setDSN" access="private" output="false"
returntype="void" hint="Sets DSN for query">
<cfargument name="newDSN" type="string" required="true" />
<cfSet Variables.DSN = Arguments.newDSN />
</cffunction>
<cffunction name="getDSN" access="private" output="false"
returntype="any" hint="Gets DSN for query">
<cfscript>
if (isDefined('Variables.DSN')){
return Variables.DSN;
}else{
return '';
}
</cfscript>
</cffunction>
<cffunction name="setQueryString" access="public" output="false"
returntype="void" hint="Sets sql statements for query">
<cfargument name="newQueryString" type="string" required="true" />
<cfSet Variables.QueryString = Arguments.newQueryString />
</cffunction>
<cffunction name="getQueryString" access="public" output="false"
returntype="any" hint="Gets sql statements for query">
<cfscript>
if (isDefined('Variables.QueryString')){
return Variables.QueryString;
}else{
return '';
}
</cfscript>
</cffunction>
<cffunction name="getResultSet" access="public" output="false"
returntype="any" hint="Gets the resultset">
<cfscript>
if (isDefined('variables.resultSet')){
return variables.resultSet;
}else{
return '';
}
</cfscript>
</cffunction>
<cffunction name="setResultSet" access="private" output="false"
returntype="any" hint="Sets the resultset">
<cfargument name="newResultSet" type="any" required="true" />
<cfset variables.resultSet = Arguments.newResultSet>
</cffunction>
<cffunction name="execute" access="public" output="false"
hint="executes the query">
<cfset variables.qry="">
<cfquery name="qry" datasource="#getDSN()#">
#getQueryString()#
</cfquery>
<cfscript>
setResultSet(variables.qry);
</cfscript>
</cffunction>
</cfcomponent>
Do we need to specify the dot notation path to the component: type="com.services.apple" or will type="apple" suffice?
It's actually really important, if you are using an explicit setter that is injected with a component via a service factory, to specify the component name. The reason for this, is that setters are publicly accessible. This could lead to the wrong component being set from outside the CFC. Encapsulation should be maintained, wherever possible.
Going on my memory from 9 years ago, I think either works, but the "full" version is more specific and may be appropriate in a situation where you have framework code and your code intermingled.
Thanks Ray. I was thinking that just the name of the component might be more portable. The dot notation might require more updating, if components get moved into different folders etc. What do you think?
I'd say it depends. If I'm building something and it has a certain structure, than I think it is safe to assume that structure will exist, and if it doesn't, that's bad. :)
I see what you mean, so your idea is that dot notation enforces more specificity, and therefore provides more security? Hmmm...decisions, decisions, decisions...
Yes... but is it necessary? I don't think you can say so 100%.
(And I wouldn't say 'more security', just more reliability.
Also, is the dot notation relative to the web root? Like:
/com/services/apple.cfc
/com/services/pear.cfc
pear.cfc
<cffunction name="setApple">
<argument name="fruit" type="com.services.apple"/>
<cfset variables.apple="arguments.fruit">
</cffunction>
It follows the same rules as when CF makes a new component via createObject("component", "X")
My understanding is that it looks for mappings that match the name, so
blog.user
would make CF look for a cf mapping called blog.
*Then* it should look for a relative directory from the code calling it... or the code creating it.
Not 100% sure. Sorry. My CF is rusty.
I don't understand why it is more reliable. Surely, just using the name, would work 100% of the time, because the argument matches the name metadata of the component object passed in, with the name provided in its type attribute?
What I mean about security, is that the component passed in, would have to reside in a specific directory, so less chance of spoofing.
As I said, my specific example was for framework code, or code you include in other projects. So imagine I've got an open source blog you drop into your project and it looks for a component "user". Is it user for the blog, or your site as a whole? That's what I mean about how specificity could benefit you.
Yes - it is a bit of an edge case, but it's the first thing I thought of.
I guess it depends how the type attribute resolves itself? I presumed it would use the component object metadata passed in. So 'name' would match 100% of the time, but 'dot notation' would only match if the metadata component path matches as well?
Yeah this is where I have to bow out. :)
For years I can remember wanting the ability to supply a relative path, ie
../utils/etc
to ensure a 100% precise connection.
Shrug. Good luck. :)
Fair enough, Ray. I will play around with this tomorrow. The truth is out there...
Hi!
I'm back to coldfusion from Java. But how could I Map an Typed Array, such as a List of specific Object, like User.cfc List<user.cfc>() ? What's the workarround for?
As far as I know, you can't.
After a while, refining Google Searches I found this:
http://help.adobe.com/en_US...
:)
How does that relate to using an array of a particular type? As far as I can see, that's for CF's ORM integration.
Actually you can use the same way
component name="Checklist" implements="Adapter" {
property name="id" type="String"; // ID da Avaliação
property name="itens" type="Array" fieldtype="one-to-many" cfc="ChecklistItem";
So your component will use a Typed Array.
Ah, ok.