I am trying to access Coldbox getSetting within a model.
In the docs, and on Coldbox Google Group posts, it clearly states
The model is a completely isolated layer of your application and has no
access to anything ColdBox unless you inject dependencies into them.
We suggest you look at our WireBox dependency injection so you can see
how to inject the models with what they need.
They point to this doc: http://wiki.coldbox.org/wiki/WireBox.cfm#The_WireBox_Injector
But other than the somewhat confusing doc and Google Group posts repeating that quote above, there is no real good example on how to do it.
I have attempted property injection at the top of my model:
<cfcomponent displayname="myComponent" output="false">
<cfproperty name="mySetting" inject="coldbox:setting:mySetting" />
<cffunction name="myFunction" output="false" hint="index">
<cfset value = getProperty('mySetting') />
...
This returns Error Messages: Variable GETPROPERTY is undefined.
I also attempted an argument injection in the function of my model, but I knew that wouldn't work.
<cffunction name="myFunction" output="false" hint="index">
<cfargument name="mySetting" inject="coldbox:setting:mySetting">
Can anyone show me how to pass getSetting to a model via wirebox injection, or really any method?
How do you inject a dependency in the model of Coldbox?
Your injection looks fine. The issue is that you are trying to use "getProperty()" which is not defined in your component. It comes from the framework supertype and only exists in frameworks objects like handlers, etc. Property injection places the reference to the injected object directly into the "variables" scope by default, so you just access it as variables.mySetting.
You can also control the scope that the property is injected into with the scope attribute:
http://wiki.coldbox.org/wiki/WireBox.cfm#Property_Annotation
Argument injection DOES work, but only for constructors (init) since they are called automatically by the DI engine.
Also, this ref card may be a bit simpler to read through than the full WireBox docs, but it obviously doesn't cover as much information:
https://github.com/ColdBox/cbox-refcards/raw/master/WireBox/WireBox-Refcard.pdf
Disclaimer: I am part of Team ColdBox.
In /config/WireBox.cfc, you set up aliases for your model objects:
map('KungFooDAO').to('model.path.to.KungFooDAO');
You can inject a ColdBox setting as a property right here:
map('KungFooDAO').to('model.path.to.KungFooDAO')
.property(name='myDsn', dsl='coldbox:datasource:myDsn');
Now, inside of KungFooDAO.cfc, you can reference variables.myDsn, which has the value of the ColdBox setting.
Alternately, you can leave off the .property() call in the WireBox config and add a CFPROPERTY inside of KungFooDAO.cfc like this:
<cfproperty name="myDsn" inject="coldbox:datasource:myDsn" />
These examples are taken from live code (DSN names changed to protect the innocent).
What does your WireBox entry for your model CFC look like?
Related
Sorry about the question phrase. I couldn't find better way to describe it. But my problem is as follows:
I have 3 cfc's namely settings.cfc, prices.cfc and helpers.cfc. These cfc's extend 4th cfc controller.cfc.
The helper.cfc is as follows:
<cfcomponent extends="Controller">
<cffunction name="formatCurrency">
<cfset formattedCurrency = 1 />
<cfreturn formattedCurrency>
</cffunction>
<cffunction name="processTemplateVariables">
<cfargument name="templateText" default="defaultText" >
<cfset formatCurrency() />
<cfreturn formattedCurrency >
</cffunction>
</cfcomponent>
The settings.cfc has a setApplicationVariables method which we use to set the application level variables. In this cfc, i have created an object of helpers.cfc and put that object into the application scope. The settings.cfc is as follows:
<cfcomponent extends="Controller">
<cffunction name="setApplicationVariables">
<cfset application.helpers = createObject("component","controllers.Helpers") />
</cffunction>
</cfcomponent>
The settings.cfc gets invoked on application start which in turn creates a object of helpers.cfc and put it into the application scope.
We create a reference to the method ProcessTemplateVariables in the controller.cfc as follows:
<cfcomponent extends="Wheels">
<cfset getFormattedCurrency = application.helpers.processTemplateVariables >
</cfcomponent>
In the prices.cfc, we use this reference to call the function processTemplateVariables, which it does. But it does not call the function formatCurrency that is called inside from the processTemplateVariables and it throws error "variable formatCurrency is undefined".
But if i use the application.helpers.processTemplateVariables(templateText="someText"), it works.
It also works, when i use cfinvoke as bellow:
<cfinvoke method="processTemplateVariables" component="controllers.helpers" templateText="someText" returnvariable="content">
The prices.cfc is as follows:
<cfcomponent extends="Controller">
<cffunction name="index">
<!--- does not work, throws 'the formatCurrency() variable is undefined' --->
<cfdump var="#getFormattedCurrency("someText")#"><cfabort>
<!--- works --->
<cfinvoke method="processTemplateVariables" component="controllers.helpers" templateText="someText" returnvariable="content">
<!--- works --->
<cfset application.helpers.processTemplateVariables("someText") />
</cffunction>
</cfcomponent>
I am not sure why using reference is not working.
Sorry about the earlier confusion but your comments made me dig deeper and i could found out that it was reference that was culprit. Is there any way to make this work with reference, that would be cool?
Update:
This blog entry (by Adam Cameron) has a better description. To summarize:
.. it pulls the method out of the CFC, so it will be running in the
context of the calling code, not the CFC instance. Depending on the
code in the method, this might or might not matter.
In your specific case it does matter. The function has a dependency on formatCurrency, which does not exist in the "context" of the calling page, and that is why you get an "undefined" error.
(From comments)
Yeah, I am pretty sure you cannot do that. Each function is compiled into an individual class: specifically a static inner class. (You can see the inner class names if you dump out the function name without parenthesis ie #application.helpers.formatCurrency#) In other words, it is disconnected from any specific instance - and by extension - the other functions.
When you create an instance of the component, all of the functions are stored its variables scope. So when you invoke "processTemplateVariables" - from within the instance - it has access to the other functions via the component's variables scope. When your code creates a reference to that function, what you are actually getting is completely disconnected from the parent instance ie application.helpers. So it won't have access to any of the other functions. Hence why you get an "undefined" error.
The limitation is understood well from the answer by Leigh.
To focus on your requirement here: using a short name alias for the functions, You can still use your original code, with a little trick of adding all the dependent functions as a reference, so that they are available inside the controller.cfc scope similar to the getFormattedCurrency.
Edit 1:
<cfcomponent extends="Wheels">
<cfset getFormattedCurrency = application.helpers.processTemplateVariables />
<cfset formatCurrency = application.helpers.formatCurrency />
</cfcomponent>
Now, for the fun part, it's quite possible to access a function from another cfc and still preserve all the dependencies. I was surprised as well when I recalled an amazing post by Bennadel here. This is simply amazing. But to warn you this practice is discouraged. So I took up with your setup and went ahead anyway. And it all worked like a charm with no issues encountered so far(but I'm quite sure there could arise some complications).
The point of problem with original usage was that the function has a dependency on formatCurrency, which does not exist in the "context" of the calling page as educated by Leigh in his answer.
So what if you can just copy scoped objects or even the functions from another component to you controller.cfc, sounds weird and amazing at the same time but it's possible using the <cfinclude> tag inside the controller.cfc (note: not encouraged) based upon the idea what Bennadel used for his example.
Edit2:
Your controller.cfc should look something like this:
<cfcomponent extends="Wheels">
<!--- Placed inside the controller's scope itself, outside every other function --->
<cfinclude template="helpers.cfc" />
....<rest of your code>....
...........
</cfcomponent>
Note that you don't even need to create a short-hand alias for the functions now. All the components and views can directly use the function name as you intended.
No need to point out that there would be chances of Naming collision if any other component extending the Controller.cfc has a function with the same name as any of the function inside the component library that is being imported. But those can be solved by following more specialization for the functions into multiple components OR as simple as using a prefix as a part of the coding standard to the function names to avoid any such future scenarios.
I have a “best-practices” question in regards to the correct way to instance CFCs that all need to talk to each other in a given project.
Let’s say for example you have a web application that has a bunch of different modules in it:
Online Calendar
Online Store
Blog
File Manager (uploading/downloading/processing files)
User Accounts
Each of these modules is nicely organized so that the functions that pertain to each module are contained within separate CFC files:
Calendar.cfc
Store.cfc
Blog.cfc
Files.cfc
Users.cfc
Each CFC contains functions appropriate for that particular module. For example, the Users.cfc contains functions pertaining to logging users on/off, updating account info etc…
Sometimes a CFC might need to reference a function in another CFC, for example, if the store (Store.cfc) needs to get information from a customer (Users.cfc). However, I'm not sure of the correct way to accomplish this. There are a couple ways that I've been playing with to allow my CFC's to reference each other:
Method 1: Within a CFC, instance the other CFC’s that you’re going to need:
<!--- Store.cfc --->
<cfcomponent>
<!--- instance all the CFC’s we will need here --->
<cfset usersCFC = CreateObject("component","users") />
<cfset filesCFC = CreateObject("component","files") />
<cffunction name="storeAction">
<cfset var customerInfo = usersCFC.getUser(1) />
This approach seems to work most of the time unless some of the instanced CFC’s also instance the CFC’s that instance them. For example: If Users.cfc instances Files.cfc and Files.cfc also instances Users.cfc. I’ve run into problems with occasional dreaded NULL NULL errors with this probably because of some type of infinite recursion issue.
Method 2: Instance any needed CFCs inside a CFC’s function scope (this seems to prevent the recursion issues):
<!--- Store.cfc --->
<cfcomponent>
<cffunction name="storeAction">
<!--- create a struct to keep all this function’s variables --->
<cfset var local = structNew() />
<!--- instance all the CFC’s we will need here --->
<cfset local.usersCFC = CreateObject("component","users") />
<cfset local.filesCFC = CreateObject("component","files") />
<cfset var customerInfo = local.usersCFC.getUser(1) />
My concern with this approach is that it may not be as efficient in terms of memory and processing efficiency because you wind up instancing the same CFC’s multiple times for each function that needs it. However it does solve the problem from method 1 of infinite recursion by isolating the CFCs to their respective function scopes.
One thing I thought of based on things I've seen online and articles on object oriented programming is to take advantage of a “Base.cfc” which uses the “extends” property of the cfcompontent tag to instance all of the CFC's in the application. However, I've never tested this type of setup before and I'm not sure if this is the ideal way to allow all my CFCs to talk to each other especially since I believe using extends overwrites functions if any of them share a common function name (e.g. "init()").
<!--- Base.cfc --->
<cfcomponent extends="calendar store blog users files">
What is the correct "best-practices" method for solving this type of problem?
If each of your CFC instances are intended to be singletons (i.e. you only need one instance of it in your application), then you definitely want to looking into Dependancy Injection. There are three main Dependancy Injection frameworks for CF; ColdSpring, WireBox and DI/1.
I'd suggest you look at DI/1 or WireBox as ColdSpring hasn't been updated for a while.
The wiki page for DI/1 is here:
https://github.com/framework-one/di1/wiki/Getting-Started-with-Inject-One
Wirebox wiki page is here:
http://wiki.coldbox.org/wiki/WireBox.cfm
Essentially what these frameworks do is to create (instantiate) your CFCs (beans) and then handles the dependancies they have on each other. So when you need to get your instantiated CFC it's already wired up and ready to go.
Dependancy Injection is also sometimes called IoC (inversion of control) and is a common design pattern used in many languages.
Hope that helps and good luck!
If your cfcs not related to each other the base.cfc concept does not fit. The inheritance is for classes have common things that can inherit from each other. For example if you have User.cfc and you want to added new cfc called customer.cfc I would inherit from User and override some functionality or add some without touching the actual user.cfc.
So, back to your question, since the CFC are not related or have common between each other and to avoid cross referencing, I will create serviceFactory holds instances of cfcs like this
component name="ServiceFactory"
{
function init(){
return this;
}
public User function getUserService(){
return new User();
}
public Calendar function getCalendar(){
return new Calendar();
}
}
and referencing it by
serviceFactory= new ServiceFactory();
userService = serviceFactory.getUserService();
Keep in mind this approach works only if you have sort of another CFC to manage your logic
you can do the same for all other services. If your functions are static you can save your services in application scope and instantiate it only one time (like singleton).
The third option you have is DI(dependency Injection) framework
We currently use CF8 and don't have access to any ORM functionality. However, I'm hoping someone out there can give me any tips on how to create all my crud actions more quickly than we are doing them right now.
Right now we create a cfc with the functions we need for each new component, hardcoded all the db field names into each function which feels like it takes forever to do.
Unfortunately the bosses wont allow us to use anything like CFWheels and we are forever creating each function manually.
I'm not looking for the scripts to self create based on what's in the DB, just a quicker way of creating the necessary crud actions for any script we write.
Below is a basic function we write for all out apps.. So I'm hoping someone out there can give me some pointers on creating all these things much more quickly.
<cfcomponent extends="master.cfc">
<cffunction name="users" access="public" returntype="query">
<cfargument name="dsn" type="string" required="yes">
<cfargument name="id" type="numeric" required="yes">
<cfquery name="get_users" datasource="#arguments.dsn#">
SELECT ID,firstname,lastname,email
FROM users
WHERE ID = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.id#">
</cfquery>
<cfreturn get_users >
</cffunction>
</cfcomponent>
I prefer DataMgr for CRUD. It is compatible with many CF versions and database engines. It automatically applies cfqueryparam, too.
Example query using DatMgr:
<cfset get_users = Application.DataMgr.getRecords("users", {id: arguments.id})>
This doesn't replace your CFC, but it might save you same typing. I've found it especially helpful for insert and update actions.
Have you tried CFBuilder?
Use Adobe CFC Generator (in ColdFusion Builder 2.0) -> Create CFC
http://help.adobe.com/en_US/ColdFusionBuilder/2.0/Using/WS0ef8c004658c1089-1b4fc34c122964e1318-8000.html
I have not used Woodi, but I used Illudium PU-36 Code Generator # http://cfcgenerator.riaforge.org/ back in the CF7/8 days and it worked well.
At first glance, what I feel is you need a code generator. Try Woodi.
Also,
Say if you a table called 'user', create two components.
user.cfc
w_user.cfc
user extends w_user. This way, always put your code generator code in 'w_user' and any customization in code in the 'user'. So, your MODEL object will be just the 'user.cfc'.
Ex: Getting User records
let the function be named as 'get_users()'. This can be generated with Woodi. So, the code should be in w_user cfc.
While you may have a case where you need some filter on it. Lets call it get_userWithFilter(). This will be in the 'user'. Now, You can be referring to the 'get_users()' function from inside this function.
If you have no filters needed, then you can directly call the get_users() function from 'user.cfc' (available by inheritance).
Does anyone know if its possible to invoke a fuseaction within a coldfusion template?
(You haven't specified which Fusebox version; this answer applies to Fusebox 5.x)
Your title and question is asking two different things - a fuse and a fuseaction are two distinct things. A fuse is simply a CFML template, whilst a fuseaction represents a bundle of logic that performs a particular action (similar to a function).
Fuses:
To invoke a fuse, simply include the file as you would normally - there's no special FB functionality required for this.
Fuseactions:
To invoke a fuseaction, use the do verb, like so:
<cfset myFusebox.do('circuit.fuseaction') />
To store the result, use the second argument for the content variable:
<cfset myFusebox.do('circuit.fuseaction',varname) />
This is the equivalent of this XML:
<do action="circuit.fuseaction" contentvariable="varname" />
There are other arguments available, see this Fusebox cheat sheet which contains plenty of other useful info too.
With MVC, you should be working through a single entry-point. So only a single fuseaction should be called during your request.
BUT that fuseaction can call some of the other model and view templates as needed. And I believe that Fusebox allows you to refactor that logic into something that can be used by multiple actions. (I'm a bit rusty on my Fusebox functionality though, but I bet some Googling will lead you the way.)
As a dire last resort, you could use <cfhttp> to call a URL within your app that invokes that fuseaction. But why not just run some of the code directly without needing to burden your server with another HTTP call?
I have written a gateway to get a result set from my database. How do i store every row in a separate dao so that i can manipulate every record further? Or can i access the result set directly to get the records?
This is my Gateway (btw, should i write the conditional logic within the cfquery into a seperate cfc that extends this one?)
<cfcomponent name="MaterialDao" hint="data access object" output="false">
<cffunction name="init" hint="constructor" access="public" output="false" returntype="MaterialDao">
<cfargument name="dsn" type="String" required="true" hint="datasource" />
<cfset variables.instance.dsn = arguments.dsn />
<cfreturn this />
</cffunction>
<cffunction name="readMaterial" hint="read" access="public" output="false" returntype="Query">
<cfargument name="district" type="String" />
<cfset var qReadMaterial = "" />
<cfquery name="qReadMaterial" datasource="#variables.instance.dsn#">
<cfif StructKeyExists(arguments,"district")>
SELECT A.NR, A.BEZ, D.BES, D.STA
<cfelse>
SELECT A.NR, A.BEZ
</cfif>
FROM DEK AS D INNER JOIN ART AS A
ON D.NR = A.NR
WHERE 0=0
<cfif StructKeyExists(arguments,"district")>
AND D.BEZ = #arguments.district#
</cfif>
ORDER BY A.BEZ
</cfquery>
<cfreturn qReadMaterial />
</cffunction>
</cfcomponent>
I have already read a lot of articles and it seems that there are different opinions about this matter (DAO vs. Gateway, DAO & Gateway etc.). What is the best practice, what do the pros do?
The pros use just one pattern for the database access layer. The use of both a DAO and Gateway is a misnomer that I'm not really sure where it got started, but seems to only exist in the ColdFusion crowd. The DAO and Gateway patterns can pretty much serve the same function, but I think the DAO fits the bill more when talking about database interaction.
DAOs should include functionality for CRUD methods plus returning sets of records. Since CRUD and basic sets of records is highly repetitive, I use a code generator to create the code for this interaction and then customize what I need. This is a good place for conditional logic for selecting the records you need.
As Aaron mentioned, returning an array of objects for a set of records in your database is unfeasible in ColdFusion due the the performance overhead of creating objects. I typically just use the basic query returned from the DAO in my views. However, if the thing I'm modeling needs some behavior in a view, then I will put the query in an object using something similar to what Peter Bell does.
Peter Bell had a great presentation some months ago on his release of the Iterating Business Object CFC which allows you to take multiple records and iterate over one record at a time using this simple framework: http://ibo.riaforge.org/. Until CF is a little faster at generating objects, recycling a single instance of an object and repopulating the properties is likely your best best. Perhaps this can help you load one record at a time into your DAO.
Conditional logic can go in the Gateway or in a Manager CFC. Typically, I would include logic that is simple like the logic outlined in your post directly in the CFC.
A bit of advice, you may wish to make the arguments.distinct NOT required and do a simple check with if (structKeyExists(arguments, "distinct") ) { do something }.
Regards,
-Aaron Greenlee
At our company we thought long and hard about this stuff for a few months, trying the Adobe CF DAO creator via RDS and some other older ones (anyone remember CFPowerTools?).
We decided in the end to write our own DAO code generator and I thought I'd share our thoughts here. The reason we decided was because we needed to add locking hints to out SQL, we wanted to make it more efficient, more secure and cleaner.
The setup we decided on was to create a pre-defined base DAO object (called DAO.cfc) which all generated 'table' DAOs extended. All it had was a few utility methods, but the key thing thing is we can add any other functions in there that we need all our generated DAOs to have access to.
So we auto-generate code by selecting a table from the database (using the CF admin API) and create the [TableName].cfc DAO with the usual init, setters and getters, so the basic CRUD stuff.
In addition to this, we also generate a [TableName]GatewayBase.cfc and a [TableName]Gateway.cfc. [TableName]Gateway.cfc extends [TableName]GatewayBase.cfc.
So for a sample DAO run on a table called 'Customers', the files created are:
Customers.cfc /* extends DAO.cfc [not created, already exists] */
CustomersGateway.cfc
CustomersGatewayBase.cfc /* extends CustomersGateway */
So, the idea is that the gateway provides a way to deal with many 'Customer' records - the DAO is used when dealing with one and only one. All methods in the gateway will generally return a CF query object. CF is too inefficient to create massive arrays of DAO objects and in our mind the query object in CF is really flexible, so we're happy to use it.
When coding, the sub-class CustomerGateway.cfc is the only one instantiated and used. However, the base class it extends has some very useful generic functions that come for free, such as getFieldListByProperty() which based on passed parameters will return certain fields (i.e. table columns) by a certain property (i.e. a column value), so for example:
myGateway.getFieldListByProperty(property="status", value="1", fieldList="customerName,customerID", orderBy="createdOn") />
That call will return the 'customerName' and 'customerID' values for all customers with a status of 1, ordered by the date they were created on. The code is also hardened against SQL injection and validated so sensible exceptions are thrown.
This function will provide 99% (we hope!) of the multi-record querying you do on a table. If you need a more sophisiticated query then the CustomerGateway.cfc is there for you to add functions to.
Finally, we allow you add functions to CustomerGateway CFC only because if you change the customers table (say add a column), you will need to recreate the table, and tha will overwrite the Customers.cfc and the CustomersGatewayBase.cfc. However, your custom code (if any) is safe in the sub-class.
Anyway, this might be slightly off topic, but sure I thought someone might find our experience useful.