event.getvalue issue in 3.1?

I'm converting my production application from 2.6 to 3.1 and I think I
am seeing an issue with using event.getvalue when the value I am
trying to get is inside of a struct in the rc.

I've created the below sample code from a my production scenario but I
think it can show what I am seeing. I think the below example should
result in both output items in the view being the same but when I use
event.getvalue it can't find userid inside of the rsUser struct. Am I
wrong? Similar code works in 2.6, I say similar because I use the 3.1
rc shortcut in the index function.

My model: userService.cfc

component {
  THIS.userStruct = structNew();
  THIS.userStruct.firstname="Jonathan";
  THIS.userStruct.lastname="Perret";
  THIS.userstruct.userid=1;
}

My handler: home.cfc
component {
  function index(event,rc)
  {
    LOCAL.userSVC = CreateObject("component",
"model.service.userService");
    getPlugin("sessionStorage").setVar("userService", LOCAL.userSVC);
    rc.rsUser =
getPlugin("sessionStorage").getVar("userService").userStruct;
    event.setView("index");
  }
}

My view: index.cfm
<cfoutput>
  using getValue #event.getvalue('rsuser.userid',0)#
  using rc #rc.rsuser.userid#
</cfoutput>
<cfdump var="#rc#">

Thanks for feedback.

Jonathan

Not sure why that is not working, have you tried dumping rc.rsuser as soon as you pull it out to see what the structure might look like?

And can I ask why you would be storing an object in the session scope? I can think of better design patterns than doing it that way.

I also noticed that you are passing the rc into the event, I am not aware that this works. You are better of using

var rc = event.getCollection();

inside your handler method.

Andrew, thanks for reponse. Here are answers to your questions:
1.Yes, I dumped it out. I have the sample code running at
http://domain.evengame.com/index.cfm/home/index
2. Session: it's because I copied some code from my production site
and that is doing much more than the example.
3. Passing the RC in, this is a new feature of 3.1. It sees rc as a
reserved word and basically does the even.getcollection for you.

Point is it seems that event.getvalue('structname.item') worked in 2.6
and doesn't work in 3.1. event.getvalue('structname') does work.
event.getvalue('structname').item also works but it kinda defeats the
ability to use the default value feature.

Cool I haven’t looked at the new changes into CFB3.1 as yet, so thanks for pointing that out to me.

As for the object in the session scope, I am more inclined to use the DI to create the object in your handler as a singleton and use it that way rather than running code to create it, store it, retrieve it etc.

It means your approach is more problematic down the track.

Now by going to the URL in question, if you look at your rc struct you can tell that it is not an object but a normal struct. So the call you are doing to a method will fail, and is what I suspected and just wanted to make sure that you had dumped rs.user to confirm that. Sorry to be point blank, but it should have rang your bell by looking at it. But then again it can be very easy at times to not see the obvious.

btw can I also point out something else that is obvious too.

LOCAL.userSVC = CreateObject(“component”,
“model.service.userService”);

Will not return the object, you will need to do one of two things.

  1. Create an init method to return this
  2. As you are using ColdFusion 9, you could do the following and I would prefer this over the createObject()

local.userSVC = new model.service.userService();

Which will return the object as you are needing it.

I'm actually in the middle of adding DI and rewriting the application
and haven't got to that portion yet when I uncovered my current issue.
This app was around before wirebox was invented and hasn't been
refactored until what I've started doing now.

I don't understand your comment regarding a normal struct vs an
object. I'm still not seeing the obvious.

Before ColdFusion introduced the new operator if you wanted to create a component and then use its methods, you had to create a method/function like this.

public any init() {
return this;
}

Otherwise it is not a true object, so when you dump it like you have all you see is a struct and not an object.

I checked and in my prod app I have an init function. I created an
init function in my sample app and I still don't see what you are
talking about.

my userService now reads

component {
    THIS.userStruct = structNew();
    THIS.userStruct.firstname="Jonathan";
    THIS.userStruct.lastname="Perret";
    THIS.userstruct.userid=1;

public any function init() { return this; }

}

my home handler now reads
component {
  function index(event,rc)
  {
    local.userSVC = new model.service.userService().init();
    getPlugin("sessionStorage").setVar("userService", LOCAL.userSVC);
    rc.rsUser = getPlugin("sessionStorage").getVar("userService").userStruct;
    event.setView("index");
  }
}

In ColdFusion 9 you no longer need the init()

Let me create a sample page for you to see what I mean.

Provided you use the new operand.

Sorry I was thinking about ColdFusion 8, the new operand and the createObject do the same thing. I thought I saw you calling a method from the struct, which wouldn’t work in ColdFusion 8 from memory without the init() method as I said earlier.

So as you are on CF9 forget the init method for here.

So what problem are you having now?

I am sure the setVar will not work with objects by looking at the plugin sessionStorage.

Ok let's make this even easier. Let's just create a struct and
populate it into the RC and try to grab a value contained in the
struct using getvalue because that's is where my problem is.

the new simple handler code:
  function index2(event)
{
    rc=event.getcollection();
    THIS.userStruct = structNew();
    THIS.userstruct.userid=1;
    rc.rsUser=this.userStruct;
    event.setView("test");
}

my view:
<cfoutput>
  executing event.getvalue('rsuser.userid',0) returns
#event.getvalue('rsuser.userid',0)# <br>
  executing rc.rsuser.userid returns #rc.rsuser.userid#
</cfoutput>
<br>
dumping rsuser struct
<cfdump var="#event.getvalue('rsuser')#">
<br>
now dump the RC
<cfdump var="#rc#">

When I run this code on 2.6 both outputs are the same value. When I
run this code on 3.1 they do not because getvalue doesn't seem to
understand the struct.value as a valid variable name. So my question
is, is this by design or is it a bug? If by design then why?

Thanks

This is not something that I can answer, maybe because it is not really considered good practice with CB3.0/3.1 to store objects into the session scope like this anymore.

Sorry I don’t know the answer to this.

Also I would like to mention that the way you are using the view is also not really considered good practice either, there are two ways that you can do this. One is with the handler doing the work getting what it needs and then returning that variable in the RC/PRC, the other method is to look at viewLets. And use that to runEvent() to get what it needs, but the way you have it here is considered to be bad coding.

I know you are coming from a legacy app written for CB2.6, but even then this should not have been done that way either. You really should be thinking about segregating your code and views.

One more thing, this is just a quick way to do structures now in CF9.

THIS.userStruct = { userid = 1};

And is much better and quicker to type as well.

Just also had a quick thought, have you tried using this instead of passing the rc via the event argument?

var rc = event.getCollection();

With your test code, the reason I am thinking about this is that there might be a bug where the RC is being trashed for some reason. Another thing to also try here is the rsuer that is not scoped, try scoping that fully as well. Because you just might have another scope with rsuser in it, and that could be getting read first.

Ok I have an answer for you now.

When setting and getting values out of the Event, it is stored as a key value pair. That means that this is illegal in CB3.0+

event.getvalue(‘rsuser.userid’,0);

And the correct code is

event.getvalue(‘rsuser’,0);

I don’t have any CB2.6 version at the moment to see what the difference is, but I can tell you that this is not how you think it works in CB now. I found this out by going into the core of the code and looking at the requestContext and looking into the setValue() and you can see that it creates a structure by name, and then looks this up later.

So I am guessing that this will not set the key right.

event.getvalue(‘rsuser.userid’,0);

Does that make sense?

event.getvalue('rsuser',0); will return the entire rsuser structure
and works in both versions as expected.

if I do event.getvalue('rsuser.userid',0) in effort to get a specific
value out of the structure located in the RC I get

from 3.1 - the default value of 0 because getvalue doesn't recognize
rsuser.userid
from 2.6 - it gives me the value located in that part of the struct as
my expectations

I still don't understand why. If I call it directly instead of using
getvalue, rc.rsuser.userid it works the same in both versions.

Because the code that handles the requestCollection has had some serious make overs, and like I said here is the code from setValue if this doesn’t answer your question then I can’t help you any further… Sorry.

var collection = instance.context; if( arguments.private ) { collection = instance.privateContext; }

collection[arguments.name] = arguments.value;
return this;

And for your info here is how it used to be done in CB2.6

So you can see that there have been some major overhauling here.

Here are the getValue() method from 2.6.4 and 3.0

As you can see, the framework used to do this:
if ( isDefined(“instance.context.#arguments.name#”) ){ return Evaluate(“instance.context.#arguments.name#”);}Now, it does this:if( structKeyExists(collection, arguments.name) ){ return collection[arguments.name];}“rsuser.userid” is now being processed as the full key name. In other words, instance.context.rsuser.userid != instance.context[“rsuser.userid”]The changed can be blamed on the following commit:https://github.com/ColdBox/coldbox-platform/commit/320331a2c55ca90fad1c6a34742cc3fee6af90d0I’m unclear on whether or not Luis was originally aware of the functional change by switching the syntax, but there’s a good chance you were using an undocumented “feature” of the way the request context worked that was never guarunteed. It may also perform faster without evaluate(), but I haven’t tested it.No sense going on and on about it though. If you wait, Luis can probably give you a more specific answer when he’s on the list next.Thanks!~Brad

Thanks. Maybe I will need a ticket to get my undocumented feature back.

You can easily build a context decorator to get what you want. The functionality was
Changed for performance.

Luis Majano
President
Ortus Solutions, Corp
Toll free phone/fax: 1-888-557-8057
Mobile: 909-248-3408

www.coldbox.org