How to use Coldbox functionality in my model

Hi,

I am learning Coldbox (v 2.6.3). and rewriting a small application to
ColdBox. I use the CB functionality in my controllers and views by
just calling CB functions - getDatasource(), getColdBoxOCM(), getPlugin
('sessionManager') etc. That works fine. However, I don't succeed in
using the CB functionality also in my model cfc's.

For example: In my text.cfc in the model directory I call a method
'getContentObject' which reads from a DB table. I want to pass the dsn
name to the cfquery tag using getDataSource
('myDataSourceAlias').getName() instead of hardcoding it but all I get
is a CB error message:

'Variable GETDATASOURCE is undefined.'

along with a stack trace up to the location in my componient where the
error occurred.

If I do this:

<cfdump var="#getDataSource('myDataSourceAlias').getName()#">
<cfabort>

in my event-handler (handlers/myEventHandler.cfc) or in a view (views/
myView.cfm) it prints the name of the data source as expected.

I don't have access to the CB functionality in some parts of my
application although I deployed my app in the directorystructure as CB
expects it to.

I figured: Since the event handler extends the
coldbox.system.eventhandler component,my model should extend
coldbox.system.eventhandler as well in order to be able to use CB
functionality here. Is this correct?

Problem is, I already extended this component (it is a rewrite of an
existing app) and CF does not know multiple inheritance. What is the
best way to get access to CB functionality in my model cfc's?
I probably miss some knowledge of CB that may solve this problem so
please educate me :wink:

Thanks,

Marc

Hi Marc,

(Just as a best practice)
1: Your model layer should not extend to coldbox.system.eventhandler.
2: Model component can have <cfproperty> then ColdBox will inject the
objects/string etc accordingly.

I would suggest you to read this comprehensive guide about Model-
Integration
http://ortus.svnrepository.com/coldbox/trac.cgi/wiki/cbModelGuide

Also you are looking to have coldbox feature to be available in model
components that is really easy.
<cfproperty name="ColdBox" type="coldbox"
scope="variables">

In your controller just simply call this getModel('Name of Component')

Please ask us if anything is confusing.

Thanks
Sana

Marc,

In your Text.cfc, add this to the top (after , but before function declarations):

where myDSN in “type” is the alias you declared in your ColdBox configuration, then when using cfquery, you can do

For more on how this works, I recommend reading:

Model Integration Guide
http://ortus.svnrepository.com/coldbox/trac.cgi/wiki/cbModelGuide

Autowire Interceptor documentation
http://ortus.svnrepository.com/coldbox/trac.cgi/wiki/cbAutowireGuide

-Dutch

Thanks for rthe quick reply.

@Sana:
If I put this in the constructor area of my component:

<cfproperty name="ColdBox" type="coldbox" scope="variables">

then in the handler (in that same component) that I request from the
view do

<cfdump "#VARIABLES.GetDataSource()#">
<cfabort>

I get

Application Execution Exception
Error Type: Object : [N/A]
Error Messages: The GetDataSource method was not found.
Either there are no methods with the specified method name and
argument types, or the GetDataSource method is overloaded with
argument types that ColdFusion cannot decipher reliably. ColdFusion
found 0 methods that matched the provided arguments. If this is a Java
object and you verified that the method exists, you may need to use
the javacast function to reduce ambiguity.

@ Dutch:
my model looks like this:

<cfcomponent output="true" extends="base">

  <cfproperty name="dsn" type="coldbox:setting:Datasource"
scope="VARIABLES">

  <cffunction name="getContentObject" returntype="query" hint="Return
contentobject for display in website">
    <cfargument name="contentContainerId" type="String">
    <cfset var qry_result="">

<cfdump var="#dsn#">
<cfabort>

    <cfquery
      name="qry_result"
      datasource="#VARIABLES.dsn#"

If I run this I get:

Application Execution Exception
Error Type: Expression : [N/A]
Error Messages: Variable DSN is undefined.

Seems like the cfproperty did not do much... btw I did use fwreinit=1.

Am I missing out something?

Marc

Hi Marc,

GetDataSource() its a object. So this would be getDatasource(‘alias name’).getName()

Or you can do this as well.

As I said, model integration guide is really useful for understanding and implementation.

Thanks
Sana

I apologize, I goofed on my explanation earlier. I actually haven’t used cfquery with ColdBox yet since I’ve abstracted out my connectivity with Reactor and Transfer.

Instead of this:

you can declare a coldbox datasource based on an alias:

What this gets you is a datasource bean object, then you your tag, you would get the datasource name as such:

Thanks for the help, Sana.
When <cfproperty name="ColdBox" type="coldbox" scope="variables">
makes the coldbox framework accessible to my model, <cfdump
var="#getDataSource()#"> (or getDataSource('myDatasourceAlias'))
should not give me the error "The GetDataSource method was not
found.". Instead it should dump the model.

If I do this in my model:

<cfproperty name="oDatasource" type="coldbox:datasource:irama"
scope="variables" />
<cfdump var="#variables.oDatasource#">
<cfabort>

the dump should not give me the error "The oDatasource method was not
found.". Instead it should dump the object.

Clearly, using <cfproperty name="ColdBox" type="coldbox"
scope="variables"> has no effect in my model. I think there is more to
using DI in a model than just adding the cfproperty tag.

I read the model integration guide section on the CB site. It is very
verbose on what DI is and how to architecture an application, use UML,
how to use a service object, bean etc but I miss a quick guide like
"How to enable DI in your model".
I suppose I have to make some adjustments elsewhere in my application
so I added this in Coldbox.config.xml.xfm

<Interceptors>
   <Interceptor class="coldbox.system.interceptors.autowire">
        <Property name="debugMode">true</Property>
        <Property name="completeDIMethodName">onDICOmplete</Property>
        <Property name="enableSetterInjection">false</Property>
    </Interceptor>
</Interceptors>

Also I use the <Setting name="ApplicationStartHandler"
value="main.onApplicationStart"/> setting. Does this override the /
Application onApplicationStart method?

Another issue:

I do this in an event my event handler (which is extending
coldbox.system.eventhandler):

<cffunction name= ... etc>
<cfset var reqC= getPlugin("ioc").getBean(beanName="requestContext") /

<cfdump var="#reqC#">
<cfabort>
...(other code)
</cffunction>

I get:

"Error Messages: The getBean method was not found."

If I do:
<cfdump var="#getPlugin('ioc')#">
<cfabort>

I get a dump of the coldbox.system.plugins.ioc object including the
getBean method. Why is the getBean method not found? I don't
understand what I am doing wrong here.

The error messages ColdBox formatted so the framework is set up
correctly.

I am sorry to bother you with these beginners questions but I really
want to get up to speed with ColdBox and these issues are taking too
much time.

Marc

I really need to proof read what I write, ok try this

-Dutch

Ok, I made some progress! Turns out Sana was right, adding cfproperty
_does_ inject my model with the requested bean, but Variables.bean is
not accessible outside of a function.

What do I mean?

I tried this:

<cfcomponent displayname="cms" autowire="true" output="false">

  <cfproperty name="myDsn" type="coldbox:datasource:irama"
scope="variables">
  <cfproperty name="zip" type="coldbox:plugin:zip" scope="variables">
  <cfdump var="#myDsn#">

This gives me the error: "there is no instance of a bean in the
Variabes scope.

If I do this:

<cfcomponent displayname="cms" autowire="true" output="false">

  <cfproperty name="myDsn" type="coldbox:datasource:irama"
scope="variables">
  <cfproperty name="zip" type="coldbox:plugin:zip" scope="variables">

  <cffunction name=...>
    <cfdump var="#myDsn#">
  </cffunction>

I get a nice dump of the bean.

In my previous issue :

<cfproperty name="ColdBox" type="coldbox" scope="variables">

then in the handler (in that same component) that I request from the
view do

<cfdump "#VARIABLES.GetDataSource()#">
<cfabort>

gave Error Messages: The GetDataSource method was not found.

That sould be

<cfdump "#VARIABLES.Coldbox#">

That gives me a dump of the CB object (I guess the whole framework?).

Same with the zip bean: accessible inside function, unknown in
constructor area. I thought scope =scope, no matter where I am but
that seems not to be the case. Would be intereseting to know why.
Anyway thanks to both of you for your help and quick replies!

Marc

in somewhat regards to this...

how could I build a link (to an event handler) in my model similar to
buildLink()? What Service would I have to inject?

thanks in advance

Ohh, interesting.

That functionatlity is inside the event object (request context). Tricky since you would be passing it in direclty.

I recommend you create your own utility to do this as part of your model. Maybe a LinkBuilder or something. That way you don’t couple to the event request context.

Good point for maybe having a coldbox utility object.

Luis

right on! good advice.

yea Im trying to dynamically build my rss links and permilinks...

thanks Luis!

I found this while looking for a solution to the same problem: how to
get access to buildLink() from within a model object. Now I'm trying
to add my own linkBuilder method to a custom utility plugin, but I
noticed that the existing buildLink() in requestContext.cfc makes use
of the getSESbaseURL() method, which is also in requestContext.cfm.
So how do I get access to getSESbaseURL() (or duplicate its
functionality) from within a plugin? We're using "ColdBox 2.6.2
FAITH".

@Bryan, Does coldbox really belong in the _model_?? My thinking is that it most deff does not. I do use a buildlink overload in my RCDs but would not tie my core model to coldbox as I interpret your description.

@Luis, a coldbox utility object sounds interesting, to say the least.

The base url’s are settings, and you have access to settings in the model by using the DSL

coldbox:setting:{name}

You can inject it anywhere you like.

Luis

I'm not trying to put coldbox in the model, but I do need a access to
a function like buildLink() in the model. I was going to create a new
plugin that includes a similar function, but that plugin would then
need access to getSESbaseURL(). What's the best way to do this? I
hope that clarifies my request. Thanks.

Ahh ok, so just a plugin then. Well, plugins have access to the event object:

var event = getController().getRequestService().getContext();

and also to settings: getSetting(), etc.

Read the super type guide.

Excellent; that makes it much easier. In my plugin, my linkBuilder()
method can use Event.buildLink(). Thank you.