Comments on usage of FW/1

68 views
Skip to first unread message

CFer

unread,
Feb 3, 2010, 11:13:25 AM2/3/10
to framework-one
As an FW/1 newbie and applying this on a new project, I was getting
frustrated with having to call the service methods with <cfset
variables.fw.service("x.y", "z") > and having to work around the
workflow since the services are called in order (i.e. after the
startController and controller methods are called). It seemed to
complicate things since I wanted to call some services depending on
the value of the results returned by other services within the
Controller. But since the services are all executed in order, it
doesn't really work that way.

I was planning on abandoning the framework and going back to my old
ways but then realized that I could just do a cfinvoke or create an
object and call the service as I needed and still call the services
with the <cfset variables.fw.service("x.y", "z") > as I needed to. I
was too short-sighted to see this at first but please let me know your
thoughts of this approach. Am I missing something? Do you see any
issues with this approach? Or does this totally fail the MVC
approach?

Hopefully your feedback will help other newbies who go through my same
issues.

i.e. My original code in the controller wanted to do something like

<cffunction name="control" output="false">
....
<cfset rc.isMobile = 0>
<cfset variables.fw.service("test.isMobilePhone", "isMobile")>
<cfif rc.isMobile EQ 1>
<cfset variables.fw.service("test.showOffer", "showOffer")>
<cfelse>
<cfset variables.fw.service("test.showWarning", "showWarning")>
</cfif>
</cffunction>

which wouldn’t work since the service calls are executed in a series
but control has passed from the controller.

So, I am calling it this way now:

<cffunction name="control" output="false">
....
<cfset rc.isMobile = 0>
<cfinvoke component="services.test" method="isMobilePhone"
phone="#phonenum#" returnVariable="local.isMobile">
<cfif local.isMobile EQ 1>
<cfset variables.fw.service("test.showOffer", "showOffer")>
<cfelse>
<cfset variables.fw.service("test.showWarning", "showWarning")>
</cfif>
</cffunction>

spills

unread,
Feb 3, 2010, 12:07:37 PM2/3/10
to framework-one

I am just curious if you could have controlled the timing of your
service method with

<cffunction name="start[itemName]>
<cfarguments name="rc" required="true" type="struct">

</cffunction>

spills

unread,
Feb 3, 2010, 12:10:43 PM2/3/10
to framework-one
OOPS -- hit post with the tab key -- most anoying!

From the docs @ http://fw1.riaforge.org/wiki/index.cfm/DevelopingApplicationsManual#Designing_Controllers


Here is the full list of methods called automatically when FW/1 is
asked for section.item:

controllers/section.cfc:before()
controllers/section.cfc:startitem()
controllers/section.cfc:item()
services/section.cfc:item()
(any additional service calls that were added via the service() API
call)
controllers/section.cfc:enditem()
controllers/section.cfc:after()
Methods that do not exist are not called.


Dutch Rapley

unread,
Feb 3, 2010, 2:00:58 PM2/3/10
to framew...@googlegroups.com
On Wed, Feb 3, 2010 at 11:13 AM, CFer <gea...@gmail.com> wrote:
As an FW/1 newbie and applying this on a new project, I was getting
frustrated with having to call the service methods with <cfset
variables.fw.service("x.y", "z") > and having to work around the
workflow since the services are called in order (i.e. after the
startController and controller methods are called).

Don't ever depend on the services being called in any certain order. The default service method and any services called with fw.service() are meant to be autonomous. All the data for any given service should be available in the rc before a service method is invoked, and any given service method should not rely on the output of another service method.

That being said, it's OK to invoke objects inside controller.item() methods. When it comes to this type of architecture, there is no one true way. My best advice is to do what you are most comfortable with and what you feel makes you the most productive.

I'm outlining a couple of options below. Neither one of these should be portrayed as a best practice, they are only examples to show flexibility in how you can potentially implement this functionality.

1) you know you're already going to be calling test.control() by convention (it's going to populate rc.data). I assume #phonenum# is in the rc, and thus you know it's going to be available inside the services.test.control() method as arguments.phonenum. Any variable in the rc, at the time a service method is invoked,  is available inside that method's argument scope. That being said, you can have services/test.cfc:

function control() {
  if (isMobile(phonenum)) { 
    //show logic
  } else {
    //show warning
  }
}

2) Another option is to place isMobile() inside a non service component, in something like com/pathTo/utilities/Phone.cfc. You can invoke it from here, or optionally use a bean factory.

Bean factories (like ColdSpring) play very nicely with FW/1.  If you load Phone.cfc with a bean factory and have matching getters and setters in your controller, FW/1 will attempt to auto wire that bean into your controller:

controller/test.cfc

function setPhone(phone) {
  variables.phone = phone;
}

function getPhone() {
  return variables.phone;
}

the phone cfc will be autowired into your controller. You can then have a control() method that looks like:

function control() {
  if (getPhone().isMobile(rc.phonenum)) {
    fw.service('test.showOffer', 'showOffer');
  } else {
    fw.service('test.showWarning', 'showWarning');
  }
}

YMMV,

Dutch

CFer

unread,
Feb 3, 2010, 3:35:17 PM2/3/10
to framework-one
Yes, I saw this but since the startItem and Item happen before the
service calls are made - it doesn't help. I didn't find the
"startItem" method too helpful except when there is a lot of code for
just one CFC and to do some validation initially.

On Feb 3, 12:10 pm, spills <spillsmi...@yahoo.com> wrote:
> OOPS -- hit post with the tab key -- most anoying!
>

> From the docs @http://fw1.riaforge.org/wiki/index.cfm/DevelopingApplicationsManual#D...

spills

unread,
Feb 3, 2010, 5:24:18 PM2/3/10
to framework-one

Here is what I was thinking:

<cffunction name="startcontrol">


<cfarguments name="rc" required="true" type="struct">

<cfset variables.fw.service("test.showOffer", "showOffer")>

</cffunction>

spills

unread,
Feb 3, 2010, 5:31:48 PM2/3/10
to framework-one
I HATE GOOGLE SOMETIMES! Sorry for the spastic posts today too much
coffee apparently!

Here is what I was(really) thinking:

In Controller:


<cffunction name="startcontrol">
<cfarguments name="rc" required="true" type="struct">

<cfset variables.fw.service("test.isMobilephone", "rc.phonenum")>
</cffunction>

In Services:
some function returns true/false of isMobile you can return a struct
if needed

In Controller:


<cffunction name="control" output="false">
....

<cfif rc.data.isMobile>

Ryan Cogswell

unread,
Feb 3, 2010, 5:54:13 PM2/3/10
to framew...@googlegroups.com
I'm curious to know the gist of what the "showOffer" and "showWarning"
methods are doing (i.e. what kind of data is being returned) and how
the information returned by those services is eventually being used by
the view. There isn't necessarily anything wrong with calling the
service methods directly, but I suspect that there is a different way
to organize the code such that the responsibilities of the different
layers are handled in a cleaner fashion such that this order
dependency between the services completely goes away. But I need to
understand the context a little further to be able to propose an
alternative way of doing this.

Ryan

spills

unread,
Feb 3, 2010, 6:07:56 PM2/3/10
to framework-one
Apologies on previous posts === does not solve problem and you can not
return rc.data as my idiotic code suggests -- not enough sleep today!

Sean Corfield

unread,
Feb 3, 2010, 7:59:17 PM2/3/10
to framew...@googlegroups.com
On Wed, Feb 3, 2010 at 8:13 AM, CFer <gea...@gmail.com> wrote:
> As an FW/1 newbie and applying this on a new project, I was getting
> frustrated with having to call the service methods with <cfset
> variables.fw.service("x.y", "z") > and having to work around the
> workflow since the services are called in order (i.e. after the
> startController and controller methods are called).

Perhaps some philosophy here will help:

FW/1 has a set of conventions that are intended to remove the need for
explicit calls _in many cases_ but you should not try to shoehorn your
code into that pattern if your needs are greater than the conventions.

The general patterns of usage that are expected are:

controller: section.item()
service: section.item()

or:

controller: section.startitem()
service: section.item()
controller: section.enditem()

You can optional queue up additional (non-default) service calls if
that is convenient.

Those are just the conventions.

It's perfectly reasonable to have component-level service calls inside
your controller methods too and that's the non-convention way to do
things:

controller: section.item() -> rc.stuff =
variables.myService.someMethod( rc.something );

where section.cfc sets up variables.myService in its constructor -
init() - or has it passed in via injection.
--
Sean A Corfield -- (904) 302-SEAN
Railo Technologies US -- http://getrailo.com/
An Architect's View -- http://corfield.org/

"If you're not annoying somebody, you're not really alive."
-- Margaret Atwood

CFer

unread,
Feb 3, 2010, 10:28:32 PM2/3/10
to framework-one
@Dutch - Thanks for your detailed reply. I needed some time to go over
it a couple of times to make sure I absorbed everything.

Option 1 - I was also wondering why I didn't just do the option 1 you
listed and then realized that I needed to set more "rc" variables
within the controller and that’s why I wanted the info back in the
controller (since the service only returns 1 value back unless I used
a struct - which thinking about now - may have worked).

Option 2 - This is what I had in mind and was doing although I left my
functions within a helper CFC in the "services" folder or within the
"services.test.cfc" named uniquely.

I am not yet familiar with Coldspring or other bean factories though I
have a good idea of what it does. I hope to sink my teeth into it
soon. The XML configuration bean is what is intimidating me more than
the coldfusion code.

@spills - we all have those days and when it rains, it pours :-)

@Ryan - The showOffer and showWarning are just random functions I came
up with and not what I actually used/needed to do and tried to obscure
it due to job privacy concerns. There may have been a better way to do
this but as the job functions kept changing throughout this project I
had to sort of keeping patching it up.

@Sean - Thanks again for reminding me to do as I see fit. Like I said,
I was a little short-sighted initially and remembered your philosophy
of doing things as the user saw fit and that’s why I finally went with
this approach and at the end appreciate this framework since it still
keeps the views free of any complicated code. I plan to use this for
another bigger and more complex project and fortunately know most of
the requirements for this project. But I am sure I will have more
questions for all of you soon.


I just hope this post will clarify the usage and benefits for other
newbies who are on the fence.

> Railo Technologies US --http://getrailo.com/
> An Architect's View --http://corfield.org/

Reply all
Reply to author
Forward
0 new messages