How do I scope a variable so that its available to other functions in the same CFC (a CFWheels plugin)?

StackOverflow https://stackoverflow.com/questions/8370109

  •  27-10-2019
  •  | 
  •  

Question

I want to add a variable that can be accessed by all functions in a plugin, but I'm getting a variable undefined error. Here's my plugin:

component
    mixin="Controller"
{
    public any function init() {
        this.version = "1.0";
        return this;
    }

    public void function rememberMe(string secretKey="rm_#application.applicationName#") {
        this.secretKey = arguments.secretKey;
    }

    public void function setCookie(required string identifier) {
        // Create a cookie with the identifier and encrypt it using this.secretKey
        // this.secretKey is not available, though, and an error is thrown
        writeDump(this.secretKey); abort;
    }
}

I call the plugin from my Sessions.cfc controller:

component
    extends="Controller"
{
    public void function init() {
        // Call the plugin and provide a secret key
        rememberMe("mySecretKey");
    }

    public void function remember() {
            // Call the plugin function that creates a cookie / I snipped some code
            setCookie(user.id);
        }
}
  1. When I dump this.secretKey inside the plugin, I get a variable undefined error. The error tells me that this.secretKey is not available in Sessions.cfc controller. But I'm not dumping from Sessions.cfc, I'm dumping from the plugin's CFC, as you can see. Why?

  2. How can I scope this.secretKey in my plugin so that it can be accessed by setCookie()? So far variables and this have failed, whether I add the definitions in a function, a pseudo-constructor, or the init(). For good measure, I threw in variables.wheels.class.rememberME, to no avail.

Here's the error:

Component [controllers.Sessions] has no acessible Member with name [secretKey]
Was it helpful?

Solution

What you're doing in init() isn't going to work when in production mode. A controller's init() is only run on the first request for that controller because it get cached after that.

So this.secretKey will be set on the very first run of that controller but never for subsequent runs.

You have a few options to make this work...

I. Use the pseudo-constructor, which does run on every controller request:

component
    extends="Controller"
{
    // This is run on every controller request
    rememberMe("mySecretKey");

    // No longer in `init()`
    public void function init() {}

    public void function remember() {
        // Call the plugin function that creates a cookie / I snipped some code
        setCookie(user.id);
    }
}

II. Use a before filter to call on every request:

component
    extends="Controller"
{
    // No longer in `init()`
    public void function init() {
        filters(through="$rememberMe");
    }

    public void function remember() {
        // Call the plugin function that creates a cookie / I snipped some code
        setCookie(user.id);
    }

    // This is run on every request
    private function $rememberMe() {
        rememberMe("mySecretKey");
    }
}

III. Store the key in a persistent scope so that calling it only once from the controller's init() is OK.

component
    mixin="Controller"
{
    public any function init() {
        this.version = "1.0";
        return this;
    }

    public void function rememberMe(string secretKey="rm_#application.applicationName#") {
        application.secretKey = arguments.secretKey;
    }

    public void function setCookie(required string identifier) {
        // This should now work
        writeDump(var=application.secretKey, abort=true);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top