Event.paramValue bug / enhancement

paramValue can only param a variable in the top level of the request
collection. If you pass in a variable name for a location deeper in
the request collection using either dot notation or bracket notation
it instead puts the variable in the root level of the request
collection.

dot notation example:

Event.paramValue('user.email', 'test@test.com');
will result in rc[user.email] = 'test@test.com'
It should be rc[user][email] = 'test@test.com'

bracket notation example:

Event.paramValue('user[email]', 'test@test.com');
will result in rc.user[emai] = 'test@test.com'
it should be rc.user.email = 'test@test.com'

I would love to see this changed in a future version of ColdBox. In
the meantime I think I'll work around this with a cfparam or a UDF.

You can create your own context decorator also.

Luis F. Majano
President
Ortus Solutions, Corp

ColdBox Platform: http://www.coldbox.org
Linked In: http://www.linkedin.com/pub/3/731/483
Blog: http://www.luismajano.com
IECFUG Manager: http://www.iecfug.com

I was wondering about this. I'll look at the documentation on how to
do this.

Luis,

I implemented the following functions in a requestContextDecorator. I
thought I would share them here. You might not find that these are
appropriate for the core requestContext, but at least you (or anyone
else) will have them if you want them. Implementation notes:

- For dynamic variable setting I used the left side expression in
quotes method recommended here:
http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=Expressions_18.html
- For dynamic variable getting I had to use Evaluate(). I see you've
used it in other places in ColdBox, but getValue is likely to be
called many times per request.
- For dynamic variable deleting I also used Evaluate and some list
manipulation functions that I'm not sure existed before CF8. I'm not
sure what releases of ColdFusion are supported for ColdBox.

  <cffunction name="valueExists" returntype="boolean" access="Public"
output="false"
    hint="checks deep in the request collection.">
    <cfargument name="name" hint="Name of the variable to find in the
request collection: String" type="any">
    <cfargument name="private" type="boolean" required="false"
default="false" hint="Use public or private request collection"/>
    <cfscript>
      var collection = instance.context;
      if( arguments.private ){ collection = instance.privateContext; }
      return isDefined('collection.#arguments.name#');
    </cfscript>
  </cffunction>

  <cffunction name="setValue" access="Public" output="false"
returntype="void"
    hint="allow setting values deep in the request collection.">
    <cfargument name="name" hint="The name of the variable to set.
String" type="any" >
    <cfargument name="value" hint="The value of the variable to set"
type="Any" >
    <cfargument name="private" type="boolean" required="false"
default="false" hint="Use public or private request collection"/>
    <cfscript>
      var collection = instance.context;
      if( arguments.private ) { collection = instance.privateContext; }

      'collection.#arguments.name#' = arguments.value;
    </cfscript>
  </cffunction>

  <cffunction name="getValue" returntype="Any" access="Public"
output="false"
    hint="returns a value from deep in the request collection.">
    <cfargument name="name" type="any" required="true"
hint="Name of the variable to get from the request collection">
    <cfargument name="defaultValue" type="any" required="false"
default="NONE" hint="Default value to return if not found.">
    <cfargument name="private" type="boolean" required="false"
default="false" hint="Use public or private request collection"/>
    <cfscript>
      var collection = instance.context;
      var returnVal = '';

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

      if( valueExists(name=arguments.name, private=arguments.private) ){
        return evaluate('collection.#arguments.name#');
      }
      else if ( isSimpleValue(arguments.defaultValue) and
arguments.defaultValue eq "NONE" ){
        $throw("The variable: #arguments.name# is undefined in the request
collection.",
             "Default: #arguments.defaultValue#,
Private:#arguments.private#, Keys
#structKeyList(collection)#","RequestContext.ValueNotFound");
      }
      else{
        return arguments.defaultValue;
      }
    </cfscript>
  </cffunction>

  <cffunction name="removeValue" access="Public" hint="I remove a value
in the request collection" output="false" returntype="any">
    <cfargument name="name" hint="The name of the variable to remove."
type="string" >
    <cfargument name="private" type="boolean" required="false"
default="false" hint="Use public or private request collection"/>
    <cfscript>
      var collection = instance.context;
      var location = listDeleteAt(name, listLen(name, "."), ".");

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

      if( valueExists(arguments.name, arguments.private) ){
        return structDelete(evaluate('collection.#location#'),
listLast(arguments.name, "."), true);
      }
    </cfscript>
  </cffunction>

I don't agree that it should, but it might be nice to pass an attribute to
allow for Associated Arrays when doing this. However by doing this change
like you are asking will break some older applications.

Regards,
Andrew Scott
http://www.andyscott.id.au/

From: coldbox@googlegroups.com [mailto:coldbox@googlegroups.com] On
Behalf Of Seth Feldkamp
Sent: Thursday, 9 December 2010 6:44 AM
To: ColdBox Platform
Subject: [coldbox:7139] Event.paramValue bug / enhancement

paramValue can only param a variable in the top level of the request
collection. If you pass in a variable name for a location deeper in the

request

collection using either dot notation or bracket notation it instead puts

the

variable in the root level of the request collection.

dot notation example:

Event.paramValue('user.email', 'test@test.com'); will result in

rc[user.email]

= 'test@test.com'
It should be rc[user][email] = 'test@test.com'

bracket notation example:

Event.paramValue('user[email]', 'test@test.com'); will result in

rc.user[emai]

While I haven't had this need myself, I do see its value. I'm pretty
leery of Evaluate though.

The other thing I frequently wish for with paramValue is the ability
to pass a list of vars to default to the same value, typically empty
string.

Dave

Just to say it, the problem with the current request context decorator
scheme is that, as I understand it, only a single component can be
used. For instance, if I wanted the features of someone else's
decorator, but also had my own, I'd have to hand-knit a cfc containing
the methods from both. I'd rather be able to specify a list of
decorators, not just a single one.

Another somewhat less elegant possibility is for one to extend
another, but as I understand it, a context decorator has to extend
coldbox.system.beans.requestContextDecorator. Isn't that still true? I
know many other components get framework methods injected dynamically,
so they don't have to extend anything in coldbox, and you can use
inheritance for other purposes, but I don't see anything in the docs
about that being true for context decorators.

Dave