Scope of a Local variable in a cfm page? - coldfusion

The following is on a test.cfm page:
<cfscript>
Local.myString = "Hello";
</cfscript>
What is the scope of myString? Will it be visible in other parts of the cfm page or just between the <cfscript>tags where it was defined?

Outside of a function, that assigment sets a variable variables.local.myString, and the scoping rules of the variables scope are well documented: About scopes: variables. From the docs:
The default scope for variables of any type that are created with the
cfset and cfparam tags. A Variables scope variable is available only
on the page on which it is created and any included pages (see also
the Caller scope).Variables scope variables created in a CFC are
available only to the component and its functions, and not to the page
that instantiates the component or calls its functions.
The local scope is likewise document on that page, btw.
Consulting the docs is always a good place to start when having questions about the language.

Related

Best practice to explicitly scope a cffunction defined in cfm

I understand that in ColdFusion, explicit scoping is a Good Thing. Since learning this, I try to explicitly scope all variables, even for variables like queries, for example, <cfquery name="local.myQuery"> or <cfquery name="variables.myQuery">.
My question is how to do explicit scoping when defining a function inside a .CFM page, which will be used only on the same page. Can I do <cffunction name="variables.myFunction"> or something similar?
The best practice would be to take that function out of the cfm page and put it into a cfc class, then create an instance of the class from your page and use it.
Everything else will eventually lead to tears. Coldfusion will throw an error if you try to define a function with the same name twice (so if you ever replicate this function in some other cfm that includes or is included by this page, it will crash).
Roughly speaking, this should be your Thing.cfc file:
<cfcomponent>
<cffunction name="myFunction">
</cffunction>
</cfcomponent>
and this should be your cfm:
<cfset thing = new Thing()>
<cfset thing.myFunction()>
myFunction will be scoped only to the Thing class, and you will be able to define a function of the same name in other classes, or even override it in descendant classes.
Posting my own answer with what I've found so far. The link from #Ageax's comment led me to this ColdFusion documentation on Specifying the scope of a function. It says:
When you define a UDF, ColdFusion puts it in the Variables scope.
You can assign a UDF to a scope the same way you assign a variable to a scope, by assigning the function to a name in the new scope. For example, the following line assigns the MyFunc UDF to the Request scope:
1: <cfset Request.MyFunc = Variables.MyFunc>
The way I understand this, it means that I should simply use <cffunction name="myFunction"> to define the function, but I should use explicit scoping when calling it, like variables.myFunction().
Despite the fact that functions in ColdFusion are able to live in different scopes (default is variables) you should not change that or play with it. Just use components to apply encapsulation or leave then in the variables scope. If you try to define a function with the same name (in the same .cfm or in included ones), you will get an error and that should be fine, so you can't overwrite a function like that.
You should scope the variables inside a function. You don't do that scoping the name of the function but scoping the variables inside then. Good practice would be using the local scope or the var prefix.
<cffunction name="foo">
<cfset var a = 123>
<cfset local.b = 345>
</cffunction>
In Lucee you can define globally the whole scope of a function using localmode="modern"
function foo()localmode="modern"{...}

Could not find value of VARIABLE from The Puppet Template

I'm having trouble to get Variable from the Puppet template.
es_deploy.pp class
class elasticsearch::es_deploy inherits elasticsearch {
$cluster_name = 'cluster'
notify { "Cluster_Name Value: $cluster_name": }
$keys_cluster = keys($elasticsearch)
deploy_on_host { $keys_cluster: es => $elasticsearch; }
define deploy_on_host ($es) {
$keys_node = keys($es[$title])
deploy_instances { $keys_node: node_info => $es[$title], es_hosts => $es['node_list']; }
define deploy_instances ($node_info, $es_hosts) {
file {"/etc/elasticsearch/elasticsearch.yml":
ensure => file,
mode => 644,
owner => root,
group => root,
content => template("elasticsearch/elasticsearch.erb");
}
$network_host = $node_info['ip_address']
notify { "Network_Host Value: $network_host": }
}
}
Template elasticsearch.erb
cluster.name: <%= scope.lookupvar("elasticsearch::es_deploy::cluster_name") -%>
network.host: <%= #network_host %>
I don't know why I'm not able to get values from es_deploy class directly. I used a workaround by scope.lookupvar() to get cluster_name but it's not working with network_host in the same way. The elasticsearch template was included from define block where I set network_host variable so it should be accessible but it's not. Notify show correct both values.
Puppet shows an error:
Error: Could not retrieve catalog from remote server: Error 400 on SERVER: Failed to parse template elasticsearch/elasticsearch.erb:
Filepath: /usr/lib/ruby/vendor_ruby/puppet/parser/templatewrapper.rb
Line: 82
Detail: Could not find value for 'network_host' at /etc/puppet/environments/testing/modules/elasticsearch/templates/elasticsearch.erb:74
at /etc/puppet/environments/testing/modules/elasticsearch/manifests/es_deploy.pp:123 on node es1
I will appreciate any help, thanks
Your template is unable to directly access the variables of class elasticsearch::es_deploy because it is not being invoked in that class's scope. Instead, it is being invoked in the scope of defined type elasticsearch::es_deploy::deploy_instances, which is unrelated to the scope of elasticsearch::es_deploy, naming and lexical nesting notwithstanding.
The Puppet Language Reference contains a section on scoping rules, which explains this. Since Puppet 3.0, all variable references are (supposed to be) looked up according to the static scoping rules, though there was at one time a bug in that regard with respect to references from templates. Relevant provisions from the reference include (emphasis in the original):
Code inside a class definition or defined type exists in a local scope.
Variables and defaults declared in a local scope are only available in that scope and its children.
[...]
[Version 3] of Puppet uses static scope for variables
[...]
In static scope, parent scopes are only assigned by class inheritance (using the inherits keyword). Any derived class receives the contents of its base class in addition to the contents of node and top scope.
All other local scopes have no parents — they only receive their own contents, and the contents of node scope (if applicable) and top scope.
If you want the template to be able to retrieve data via the expression #cluster_name when invoked from a defined-type instance, that needs to correspond to a local variable of that type. You could achieve that by passing it as a parameter, or just by making a local copy of the class's variable:
$cluster_name = $elasticsearch::es_deploy::cluster_name
My suggestion, however, would be to continue having the template look up the variable in the appropriate scope if that scope indeed can be viewed as a canonical source for the information.
I should say also that nesting class or defined type definitions inside class bodies has widely been considered poor form since well before the release of Puppet 3. Even in Puppet 2 and earlier, with their exclusive reliance on dynamic scope, lexically nesting definitions produced scope confusion. The Puppet 3 (and 4) docs specifically note that the practice is not deprecated in that version, but warn that it is a candidate for future deprecation. Also, they explicitly say:
Defined resource types can (and should) be stored in modules. Puppet
is automatically aware of any defined types in a valid module and can
autoload them by name.
Definitions should be stored in the manifests/ directory of a module
with one definition per file, and each filename should reflect the
name of its defined type.
I should be clear that in context, it is evident that the docs are distinguishing "should" from "must" in those comments.

CFWheels - Should I be locally scoping my Wheels actions?

Say I have a very simple controller like so:
<cfcomponent extends="Controller">
<cffunction name="hello">
<cfset time = Now()>
</cffunction>
</cfcomponent>
In straight ColdFusion / Railo, I would be locally scoping all variables within this...but every wheels example I see does not.
This is probably going to earn me the dumbest question of the year award, but it was something I was thinking about, since nobody ever seems to demonstrate their Wheels code scoped correctly?
I would write it as follows:
<cfcomponent extends="Controller">
<cffunction name="hello">
<cfset local.time = Now()>
</cffunction>
</cfcomponent>
I am just not sure if Wheels perhaps does something to remedy this regardless, and that's why I see what I do everywhere...or is it just a case of bad programming?
Thanks!
Mikey
Yes, you should be scoping it.
In your first example, you are (by not scoping) in most cases setting variables.time, which is local to the component instance, not to the function - if this is intended as a function-local variable (i.e. local.time) but is in the component's variable scope, and that component is shared/persisted, this may cause issues (though perhaps ones that only reveal themselves under heavy load).
If putting the variable in the variables scope is deliberate, it should still be explicitly scoped (as variables.time) otherwise it may cause issues if used on a Railo server with the localmode setting enabled.
Due to a cfWheels design decision (see links in comments), putting variables in the variables scope is required to pass variables to the view, even though they may technically be local to the function/view. (The controller instance lives for a single request, avoiding the issues this normally entails.) As mentioned in the previous paragraph, the localmode setting (described below) means it is still recommended to explicitly scope when you are not in control of all servers the code will be deployed to.
Railo's localmode setting
Railo (since v1) has had an admin setting called "localmode" which defines whether assigning an unscoped variable will go to the local scope, rather than the component's variables scope - making explicit var/local scoping not required (if you know your code will only be run on Railo servers with that setting enabled).
Since that setting is off by default, and ColdFusion does not have such a setting, cross-engine-compatible code should always scope such variable assignments to avoid this being an issue.
It depends. If you want the variable to be shown in the view, scope it to variables. If you want the variable to be only in the controller, scope it to local.

How to put UDF library into the APPLICATION scope?

I am using ColdFusion 9.0.1.
Right now, we are including our UDF library in the onRequest() method in our application.cfc. Here's how we include it:
<cfscript>
// INCLUDE LIBRARY
include "udf/udf_library.cfm";
</cfscript>
I am wondering if there is a way to put the entire library into the APPLICATION scope so that it's created just once. Would we do this the same way as we put our orders.cfc into the APPLICATION scope, like this:
APPLICATION.AppInfo.objOrders = createObject("component", "globaladmin.orders");
Should the UDF library be converted to a CFC to make this happen?
How would we reference the function in the CFC?
Currently we call the UDF functions with no fuss, like this:
<cfscript>
createButton("Canada Postal Codes", "ShowSection", "ShippingCanadaPostalCodes");
wrapCell(Buttons);
wrapRow(Cells, "TableSubHead"));
</cfscript>
It would be really ugly to have to add "APPLICTION.AppInfo" before each function.
So, would there be any advantage to moving the UDF library to the APPLICATION scope or loading it only once somewhere else?
I think scoping your UDFs is a good idea. As it is you just have them as part of the REQUEST scope, so there's room for name clashes if methods of the same names are declared in .cfm pages in other parts of your application.
If you do add them and object in the APPLICATION scope, in onApplicationSart() for instance, then you'll have to be aware of thread safety issues. Presumably your UDFs are fairly self contained, so your APPLICATION scoped object won't hold any internal state as such, so you should be safe enough in that respect.
If you just want it created once then add your functions to a CFC and create it in your Application.cfc's onApplicationStart() function, assigned to the APPLICATION scope as you've described above.
Should the UDF library be converted to a CFC to make this happen?
YES
How would we reference the function in the CFC?
APPLICATION.AppInfo.yourObj.createButton("Canada Postal Codes", "ShowSection", "ShippingCanadaPostalCodes")

Why do local variables in Magento have an underscore prefix?

As a follow up to an earlier question I wonder if anyone knows why Magento templates all declare their variables with an underscore. Templates are .phtml files include-ed from Mage_Core_Block_Template::fetchView(), their local variables are disposed of by the end of the function and never become global.
So what's the point of an underscore?
I think it's to respect ZF's naming convention:
http://framework.zend.com/manual/en/coding-standard.naming-conventions.html#coding-standard.naming-conventions.variables
For instance variables that are declared with the "private" or "protected" modifier, the first character of the variable name must be a single underscore. This is the only acceptable application of an underscore in a variable name. Member variables declared "public" should never start with an underscore.
No certain answer here, but I believe it's just an internal magento team coding convention. I'm sure you're aware of the underscore prefix's history in programming in general. It's not too much of a stretch to think that
local variables used in a view script that are loosely coupled with an object are similar to private or protected variables
In other words, the underscore serves as a warning that
hey, the contents of this variable doesn't just belong to this view, it's owned by something else
Part of the problem is there's no "official" recommendations from Zend, or anyone else, what sort of naming conventions should be used in phtml files.