Getting values from THIS scope after init function (persistency inside CFC) - coldfusion

I'm initiating a CFC like this.
<cfscript>
lock scope="application" timeout="5" {
application.mycfc = new mycfc();
}
writeOutput(application.mycfc.readVars());
</cfscript>
In the CFC, I'm setting some properties.
component output="false" accessors="true" {
property name="title";
property name="foo";
this.title = "mycfc";
function init() {
this.foo = "bar";
// I can now properly read this.title, or this.foo.
return this;
}
function readVars() {
// Here, I can read this.title, from the constructor space, but I can't
// read this.foo. It's just blank (because the default value of the
// `default` attribute of `property` is "")
}
}
Because of the implementation (caching in Application), I can instead use application.mycfc.foo in readVars().
Because of this name, it's hard to Google for details. I thought it would be persistent throughout the CFC's life, but apparently it is not?
I surely could do something like
var self = application[this.title]; // or application.mycfc
Or perhaps even
this = application[this.title];
In functions where I want to get/set without typing application.mycfc each time.
Just trying to make sure I'm not doing something wrong, or reinventing the wheel.
In my real implementation, I'm pulling from rows from a database to populate a struct.

Scopes in ColdFusion components (.cfc):
this
is the public scope, read/write from anywhere
properties
is a magical scope, read/write only via accessors (a.k.a. getters/setters) from anywhere
variables
is the private scope, read/write only within your component
All of these scopes can coexist, but this.x is NOT the same field as property name="x"!
Since you are using a component with accessors="true", all your property fields can only be read via getter and written via setter. So if you want to write your title property, use setTitle("mycfc"); instead of this.title = "mycfc";. Same goes for the foo property. Use setFoo("bar"); instead of this.foo = "bar";. If you want to read the properties, use application.mycfc.getTitle() and application.mycfc.getFoo(). If you want to set properties at runtime, use application.mycfc.setTitle("something"). Note that writing to a shared scope such as application should happen in a cflock to avoid race conditions (thread-safety).
If you don't need accessors at all, you can simply use public fields instead (accessors is missing here, i.e. set to false):
component output="false" {
this.title = "mycfc";
this.foo = "";
function init() {
this.foo = "bar";
return this;
}
function readVars() {
return this;
}
}
application.mycfc = new mycfc();
writeOutput(application.mycfc.title); // mycfc
writeOutput(application.mycfc.foo); // bar
application.mycfc.title = "something";
writeOutput(application.mycfc.title); // something
writeOutput(application.mycfc.foo); // bar
Public fields are usually not recommended though as they break encapsulation.

Related

How are these two components different?

Is one of these better than the other? What's the difference? They seem to be interchangeable
component
{
property name="some_thing" type="string" value="";
}
vs
component
{
this.some_thing = "";
}
cfproperty
Post CF8, 'cfproperty' allows one to set an implicit setter/getter.
It is also used in the creation of web services & ORM applications and has a vast array of configuration properties:
https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-tags/tags-p-q/cfproperty.html
Setter/getter
com/foo.cfc
component accessors='true' {
// set properties & variables above any component methods
property name='bar' type='string';
this.setBar('foo');
function init(){
return this;
}
}
Within a template 'foo.cfm':
foo = new com.foo();
WriteDump(var=foo.getBar());
// foo
'this' scope
The 'this' scope can be accessed both internally & externally to the component.
com/foo.cfc
component {
// set properties & variables above any component methods
this.bar = 'foo';
function init(){
return this;
}
}
Within a template 'foo.cfm':
foo = new com.foo();
WriteDump(var=foo.bar);
// foo
'variables' scope within a component
The variables scope within a component cannot be accessed from outside the component.

How do I get a custom element definition without instantiating it?

After looking at the custom element spec, it's not immediately obvious how I get a reference to a custom element definition without first instantiating it (which can be problematic). Is there a way to directly reference a custom element's prototype?
More concretely, if I have:
var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() { // some heavy operation };
document.registerElement('x-foo', {prototype: proto});
At some point later, I would love to reference the prototype with something like:
// wish
var XFoo = document.getElementDefinition('x-foo');
But instead the only way I've come up with is:
// reality
var XFoo = document.createElement('x-foo').__proto__;
This is especially problematic when trying to write tests against heavy components - as there's no way to stub out the heavy behavior (with something like XFoo.createdCallback = // stub; before the original method is actually called.
If you have reference to the constructor of the custom element, you can use it to access the prototype.
var XFoo = document.registerElement('x-foo', {prototype: proto});
XFoo.prototype // this will give u access to the prototype object.
there's no way to stub out the heavy behavior
Use a function reference rather than an anonymous function:
proto.createdCallback = model.foo;
define it:
var model = {};
model.foo = function(){/*some heavy operation*/};
then stub it by redefining it:
var XModel = {};
XModel.foo = function(){/*stub*/};
and reference it in the test:
XFoo.createdCallback = XModel.foo;
References
AOP Aspect of JavaScript
AJAX Interception
Intro to Aspect Oriented Programming

NULL POINTER error when using ObjectLoad(ObjectSave())

Update this has been filed as a bug in ColdFusion, https://bugbase.adobe.com/index.cfm?event=bug&id=3546237
I've been having a problem with CF9 and NULL POINTER errors that do not appear to be an issue within Railo. I created a simple CFC and associated mxunit unit test to confirm this with.
On Railo (4.0.4) both unit tests pass. On Coldfusion (9.0.1), the unit test getMetaDataBeforeMethodInvocation fails with NULL POINTER error on the GetMetaData call.
At present I can only surmise that CF9 does not have access to the full metadata following ObjectLoad until a method within that component is called. Is anyone able to shed more light on this problem, and/or offer a better solution than to ensure that a method within the object is called prior to doing getMetaData?
Here is the CFC
// NullError.cfc
component {
public NullError function init() {
variables.uuid = CreateUUID();
return this;
}
public string function getUUID() {
return uuid;
}
}
and associated unit test
// NullErrorTest.cfc
component extends='mxunit.framework.TestCase' {
private any function setupTheTests() {
var o = new NullError();
debug(o.getUUID());
// Dump meta data
debug(GetMetaData(o));
// Save and load it, and return
return ObjectLoad(ObjectSave(o));
}
public void function getMetaDataBeforeMethodInvocation() {
var o = setupTheTests();
// Get meta data, and then get uuid, expecting this to ERROR (NULL POINTER)
debug(GetMetaData(o)); // CF FAILS HERE, RAILO DOES NOT
debug(o.getUUID());
}
public void function getMetaDataAfterMethodInvocation() {
var o = setupTheTests();
// Get uuid, and then get meta data, expecting this to be ok
debug(o.getUUID());
debug(GetMetaData(o));
}
}
I can confirm this buggy behaviour in both CF 9.0.2 and 10.0.9.
I'd raise a bug if I was you.
The repro case can be simplified a lot from what you have:
// C.cfc
component {}
<!--- test.cfm --->
<cfscript>
o1 = new C();
writeDump(getMetaData(o1)); // OK
o2 = objectLoad(objectSave(o1));
writeDump(getMetadata(o2)); // breaks
</cfscript>
I don't know what to suggest by way of work-around, given it's so clearly and fundamentally broken.

Spark List in Actionscript: Passing Layout & itemRenderer in construtctor

I am trying to create a generic List, where I can pass the layout & item renderer as parameters.
Since it is not possible to pass parameters to a MXML component's Constructor, I figured I should create my List in Actionscript.
I figured it would go something like this:
public class GenericList extends List {
public function GenericList(iR:ItemRenderer, ac:ArrayCollection, layout:LayoutBase) {
super();
this.dataProvider = ac;
this.layout = ... // don't even have access to this.layout
this.itemRenderer = iR // Cannot pass itemRender
}
I would prefer to have the List in MXML (because It will be easier using states later), but If I am forced to use pure Actionscript so I can instantiate it and pass in parameters, any help would go a long way.
You cannot set the itemRenderer property of a list must implement IClassFactory. So your assignment would look like this:
public function GenericList(cf:ClassFactory, ac:ArrayCollection, layout:LayoutBase) {
And the instantiation would be:
var myList:GenericList = new GenericList( new ClassFactory( com.company.renderers.MyItemRenderer, ....);
Regarding the layout:
List essentially wraps DataGroup, so it is the datagroup's layout that you need to access. However, dataGroup will not necessarily be instantiated yet. So you might have to create a private property that you then utilize in commitProperties.
private var _myLayout:LayoutBase; (populate in constructor via getter/setter)
protected var layoutInvalidated:Boolean;
public function set myLayout( layout:LayoutBase):void {
_myLayout = layout;
layoutInvalidated = true;
}
override protected function commitProperties():void {
super.commitProperties();
if( layoutInvalidated && dataGroup && dataGroup.layout ) {
layoutInvalidated = false;
dataGroup.layout = _myLayout;
}
}

Mocking SQL output parameter

I mocked a couple of methods of my Data Access layer, but in some methods the value of an SQL output param is set. How can I mock this ?
Method:
var wrappedParameters = new SqlParameter[3];
wrappedParameters[0] = new SqlParameter("#username",username);
wrappedParameters[1] = new SqlParameter("#password",password);
wrappedParameters[2] = new SqlParameter("returnValue",SqlDbType.Int) { Direction =ParameterDirection.ReturnValue };
dal.ExecuteUsingStoredProcedure("GetUser", wrappedParameters);
Mocking (I tried using "OutRef", but that doesn't work):
using (mocks.Record())
{
Expect.Call(dal.ExecuteUsingStoredProcedure("",> null)).Return(true).IgnoreArguments().OutRef(1);
}
But that didnt work. When I excute the SP GetUser the param return value is set, but I have no idea how to mock this
I think you're going about this the wrong way. Your DAL interface should look like this:
/// <summary>
/// Models a service which holds the user information.
/// </summary>
public interface IUserRepository
{
/// <summary>
/// Gets the user with the given name, or <c>null</c> if no user with
/// that name and password exists.
/// </summary>
/// <exception cref="IOException">
/// An I/O problem occurred while accessing the repository.
/// </exception>
User TryGetUser(string name, string password);
}
The DAL abstraction now hides the fact that a stored procedure is used. In fact, the DAL might not even be a database: it could be a text file on disk, a webservice, a mock or anything else.
Mocking the DAL in order to test code which uses the DAL now becomes trivial. I've chosen the view model (aka presentation model)of a login screen as the system under test in these examples:
[Test]
public void Login_sets_user_and_goes_to_main_screen_when_TryGetUser_not_null()
{
var userRepositoryStub = MockRepository.GenerateStub<IUserRepository>();
var user = new User(...);
userRepositoryStub.Stub(x=>x.GetUserByName("foo","bar")).Return(user);
var sessionStub = MockRepository.GenerateStub<ISession>();
var loginScreenViewModel =
new LoginScreenViewModel(sessionStub, userRepositoryStub);
loginScreenViewModel.UserName = "foo";
loginScreenViewModel.Password = "bar";
loginScreenViewModel.Login();
userRepositoryStub.AssertWasCalled(x=>x.TryGetUser("foo","bar"));
sessionStub.AssertWasCalled(x=>x.ShowMainScreen());
Assert.AreEqual(user, session.User);
}
.
[Test]
public void Login_shows_error_when_TryGetUser_returns_null()
{
var userRepositoryStub = MockRepository.GenerateStub<IUserRepository>();
var sessionStub = MockRepository.GenerateStub<ISession>();
var loginScreenViewModel =
new LoginScreenViewModel(sessionStub, userRepositoryStub);
loginScreenViewModel.UserName = "foo";
loginScreenViewModel.Password = "bar";
loginScreenViewModel.Login();
Assert.AreEqual(loginScreenViewModel.Error,
"User 'foo' does not exist or password is incorrect"));
userRepositoryStub.AssertWasCalled(x=>x.TryGetUser("foo","bar"));
sessionStub.AssertWasNotCalled(x=>x.ShowMainScreen());
Assert.IsNull(session.User);
}
I don't think you can mock it, because it is a normal SqlParameter (concrete class), and its not an out/ref parameter in .Net sense. What I would try is to simply set the value of the parameter in the mocked call to dal (I haven't checked the syntax, but I am sure you get the idea):
using (mocks.Record())
{
Expect.Call(dal.ExecuteUsingStoredProcedure("",null)).Return(true).IgnoreArguments().Do(x => wrappedParameters[2].Value = 1; true);
}
I stubbed this using the "WhenCalled" method.
In my code (to be tested) I first create the connection and command and add three parameters, the third of which is my output parameter. I then call "ExecuteCommand" on this....I won't go through the code for this as I think it's fairly standard (ExecuteCommand takes the command object as its parameter).
In my test, I create a stub for my sql data service and program it so that this sets the value of the parameter:
var sqlService = MockRepository.GenerateStub<ISqlDataService>();
sqlService.Stub(s => s.ExecuteCommand(null))
.IgnoreArguments()
.WhenCalled(s => ((SqlCommand)s.Arguments[0]).Parameters[2].Value = expectedValue)
.Return(0);
The answer's probably a bit late for your project, but hope this helps someone...
Griff