Confused about Classes, Instances and Methods in ColdFusion - oop

My question is probably best illustrated with an example. In javascript I'm used to being able to do stuff like this:
// create a simple class
function myClass() {
this.attr_example = "attribute";
}
myClass.prototype.do_something = function() {
return "did something";
}
// create an instance of it, and modify as needed
var thing = new myClass();
thing.myMethod = function(arg) {
return "myMethod stuff";
}
// ... so that this works as expected
console.log(thing.myMethod());
console.log(thing.do_something());
console.log(thing.attr_example);
When it comes to doing something similar in ColdFusion, I get stuck. I constantly find myself wanting to do things like this:
<cfscript>
// thing.cfc contains a normal cfcomponent definition with some methods
var thing = createObject("component","Thing");
function formattedcost() {
return "#LSCurrencyFormat(this.cost)#";
}
thing.formattedcost = formattedcost;
</cfscript>
<cfoutput>
#thing.formattedcost()#
</cfoutput>
Let's assume that for this question, it doesn't make sense to add "formattedcost" as a method on the Thing class because it is purely presentational. Let's also assume that simply using #LSCurrencyFormat(thing.cost)# in the <cfoutput> tags wont suffice either because we need the instance of Thing to be evaluated by a templating system (mustache in this case). Even further, I'd like to avoid having to create another .cfc file just to extend my Thing class to add a couple of methods.
What can I do? Is this style of programming possible in ColdFusion?

Yes you can do this:
Thing.cfc
<cfcomponent output="false" accessors="true">
<cfproperty name="cost" type="numeric">
<cffunction name="init" output="false" access="public"
returntype="any" hint="Constructor">
<cfargument name="cost" type="numeric" required="true"/>
<cfset variables.instance = structNew()/>
<cfset setCost(arguments.cost)>
<cfreturn this/>
</cffunction>
</cfcomponent>
test.cfm
<cfscript>
// thing.cfc contains a normal cfcomponent definition with some methods
thing = new Thing(725);
function formattedcost() {
return "#LSCurrencyFormat(getCost())#";
}
thing.formattedcost = formattedcost;
</cfscript>
<cfoutput>
#thing.formattedcost()#
</cfoutput>
Result
$725.00

Related

Assign a value to an attribute of a Microsoft.TeamFoundation.Build.Common.BuildParameter object using XAML

my BuildParameter is defined in my xaml build as follows:
<Activity this:Process.AdvancedBuildSettings=
"[New Microsoft.TeamFoundation.Build.Common.BuildParameter(
" { ""Attribute1"": """",
""Attribute2"": ""Value2"",
""Attribute3"": ""Value3"" } "
)]">
Now I want to update the value of Attribute1 of my BuildParameter but I can't figure out how to do it.
It doesn't look like I can use an Assign block because these attributes names are not known by the compiler, so I want to use BuildParameter's SetValue method but I'm not sure how to call this VB code in my xaml.
<Assign DisplayName="Update That Attribute">
<Assign.To>
<OutArgument x:TypeArguments="x:String">[AdvancedBuildSettings.Attribute1]</OutArgument><!-- this throws a compiler error because it doesn't know what Attribute1 is -->
</Assign.To>
<Assign.Value>
<InArgument x:TypeArguments="x:String">""NewValue""</InArgument>
</Assign.Value>
</Assign>
Not familiar with XAML, but here is a code snippet that using TFS API in C# to update the parameter name. You can use WorkflowHelpers.DeserializeProcessParameters Method and WorkflowHelpers.SerializeProcessParameters Method to get parameter name, remove it, and add the new parameter name, maybe it can help you something:
string argumentName = "Attribute1";
var process = Microsoft.TeamFoundation.Build.Workflow.WorkflowHelpers.DeserializeProcessParameters(BuildDefinition.ProcessParameters);
if (process.ContainsKey(argumentName))
{
process.Remove(argumentName);
process.Add(argumentName, attributeValue);
BuildDefinition.ProcessParameters = WorkflowHelpers.SerializeProcessParameters(process);
BuildDefinition.Save();
}
I was right, the "Assign" workflow tool was not the tool I wanted. I needed to use the "InvokeMethod" workflow tool in order to invoke the SetValue() method of my BuildParameter object in my XAML build.
MSDN InvokeMethod documentation
More details about the properties of InvokeMethod
So my solution looks like this:
<InvokeMethod DisplayName="Invoke That Method" MethodName="SetValue">
<InvokeMethod.GenericTypeArguments>
<x:Type Type="x:String" />
</InvokeMethod.GenericTypeArguments>
<InvokeMethod.TargetObject>
<InArgument x:TypeArguments="mtbc:BuildParameter">[AdvancedBuildSettings]</InArgument>
</InvokeMethod.TargetObject>
<InArgument x:TypeArguments="x:String">Attribute1</InArgument>
<InArgument x:TypeArguments="x:String">[NewValue]</InArgument>
</InvokeMethod>

NHibernate -How to conditionally load data from a column

We are not using Fluent Nhibernate. We have a table with a blob column which we would like to load conditionally. We already have specified it as 'lazy' and lazy loading is working fine. Is there a way to not load data for that column at all on a certain condition ? (hence for the property in respective class)
For example, here is the mapping
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Blah.blah.blah" assembly="Blah.blah">
<class name="MyDocument" table="HEAVY_DOCS">
<id name="Id" column="docnum" type="decimal"> </id>
<property name="docname" column="docname" />
<property name="details" column="details" />
<property name="doc_data" column="document_data" lazy="true" />
</class>
</hibernate-mapping>
and below is the code getting document
private IList<MyDocument> FetchDocuments(IList<string> docId, bool laodData)
{
if(!laodData)
{
docs = (from doc in Session.Query<MyDocument>()
where docId.Contains(doc.docnum)
select doc).ToList();
}
else
{
//if laodData is false dont load column document_data
}
return docs ;
}
The way, how to drive column selection by our code, is to use projections. Adjusted code could look like this:
if(!laodData)
{
docs = (from doc in Session.Query<MyDocument>()
where docId.Contains(doc.docnum)
select doc // complete object
).ToList();
}
else
{
docs = (from doc in Session.Query<MyDocument>()
where docId.Contains(doc.docnum)
select new MyDocument // in NHibernate world
{ // that would be called
docname= doc.docname, // projection
details = doc.details,
// no "doc_data" for LARGE document
Id = doc.Id,
}
).ToList();
}
With QueryOver the projections can profit from NHibernate built in powerful Result Transformers, which can fill even protected properties. Maybe see this custom transformer example for deep (relations including) transformations of QueryOver projections...

Orchard CMS: How to display different views for summary and detail display type of Tags_ShowTags shape?

I need to display different views for summary and detail display type for TagsPart, but it contains only one shape Tags_ShowTags for both views.
protected override DriverResult Display(TagsPart part, string displayType, dynamic shapeHelper) {
return ContentShape("Parts_Tags_ShowTags",
() => shapeHelper.Parts_Tags_ShowTags(Tags: part.CurrentTags.Select(x => new ShowTagViewModel { TagName = x })));
}
Is there way to create different views for shape Tags_ShowTags? Like this:
Tags.ShowTags-MyContentType.Detail.cshtml
Tags.ShowTags-MyContentType.Summary.cshtml
Marco Serralheiro's tip to use Atlernates allows to use different views for summary and detail display type without creating extra shapes. See following example:
<Match ContentType="MyContentType">
<Match DisplayType="Summary">
<Place Parts_Tags_ShowTags="Content:4;Alternate=Parts_Tags_ShowTag_MyContentType_Summary"/>
</Match>
<Match DisplayType="Detail">
<Place Parts_Tags_ShowTags="Content:4;Alternate=Parts_Tags_ShowTag_MyContentType_Detail"/>
</Match>
</Match>
View names:
/Views/Parts.Tags.ShowTag.MyContentType.Summary.cshtm
/Views/Parts.Tags.ShowTag.MyContentType.Detail.cshtml
Yes. Have you tried the Shape Tracing tool, to find what are the available alternates for that shape (http://docs.orchardproject.net/Documentation/Customizing-Orchard-using-Designer-Helper-Tools)? You can also take a look at http://docs.orchardproject.net/Documentation/Alternates - Parts_Tags_ShowTags is used as example to explain alternates.
Edit:
I managed to increase the number of available alternates (that are available without the need to explicitly designate them in the placement.info file) following this tip: http://kobowi.co.uk/blog/2012/11/content-display-type-alternates-for-content-parts-in-orchard
In my own module I placed this "PartContentTypeAlternateFactory.cs":
using Orchard.DisplayManagement.Implementation;
using System;
namespace MyModule.Name {
public class PartContentTypeAlternateFactory : ShapeDisplayEvents {
public override void Displaying(ShapeDisplayingContext context) {
context.ShapeMetadata.OnDisplaying(displayedContext => {
var shapeType = displayedContext.ShapeMetadata.Type;
var contentItem = displayedContext.Shape.ContentItem;
if (contentItem == null) return;
var displayType = displayedContext.ShapeMetadata.DisplayType;
var contentType = contentItem.ContentType;
// add a couple more alternates
displayedContext.ShapeMetadata.Alternates.Add(
String.Format("{0}__{1}", shapeType, displayType));
displayedContext.ShapeMetadata.Alternates.Add(
String.Format("{0}__{1}__{2}", shapeType, (string)contentType, displayType));
});
}
}
}
This gives me a few more alternates to chose from, "out of the box". They even show up in the Shape Tracing tool, and one can use it to create the appropriate cshtml files.

Coldfusion cfset and variable scope

I am trying to do this
<cfset noncooperativevariable = #serverfile#>
and I get a serverfile not defined error. When I try to use the correct variable scope
<cfset noncooperativevariable = #CFFILE.serverfile#>
which returns the error.
You have attempted to dereference a scalar variable of type class java.lang.String as a structure with members.
Edit:
<cffile action="upload" filefield="fileUpload" destination="#destination#" nameConflict="makeUnique" result="upload">
<cfset noncooperativevariable = #fileUpload.serverfile#>
When using the cffile tag, the results are defaulted to the cffile struct in your Variables scope. Therefore, if you are uploading a file with the following code:
<cffile action="upload" filefield="fileUpload" destination="#destination#" nameConflict="makeUnique" />
The results are accessible via the cffile struct in your Variables scope. The filename would be referenced as follows:
<cfset cooperativeVariable = cffile.serverfile />
In the snippet posted, you are using the 'result' attribute which would place your cffile results in the struct named upload instead of cffile, so you would get the filename like so:
<cfset cooperativeVariable = upload.serverfile />

ColdFusion 9 ORM - Securing an object at a low level

I'm looking at securing a low level object in my model (a "member" object) so by default only certain information can be accessed from it.
Here's a possible approach (damn sexy if it would work!):
1) Add a property called "locked" - defaulting to "true" to the object itself.
It appears that the only option to do this, and not tie it to a db table column, is to use the formula attribute that takes a query. So to default locked to TRUE I've got:
<cfproperty name="locked" formula="select 1" />
2) Then, I overwrite the existing set-ers and get-ers to use this:
e.g.
<cffunction name="getFullname" returnType="string">
<cfscript>
if (this.getLocked()) {
return this.getScreenName();
} else {
return this.getFullname();
}
</cfscript>
</cffunction>
3) When i use it like this:
<p> #oMember.getFullName()# </p>
shows the ScreenName (great!)
but... When I do this:
<cfset oMember.setLocked(false)>
<p> #oMember.getFullName()# </p>
Just hangs!!! It appears that attempting to set a property that's been defined using "formula" is a no-no.
Any ideas? Any other way we can have properties attached to an ORM object that are gettable and settable without them being present in the db?
Ideas appreciated!
Any other way we can have properties
attached to an ORM object that are
gettable and settable without them
being present in the db?
Yes,
<cfproperty name="locked" persistent=false>
http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSB7BEC0B4-8096-498d-8F9B-77C88878AC6C.html
Is it because in the else statement of your function, you are calling the same function name again? So its just recurring.
Try renaming the function name so its not overriding the implicit getter and see what happens. For example
<cffunction name="getNewname" returnType="string">
<cfscript>
if (this.getLocked()) {
return this.getScreenName();
} else {
return this.getFullname();
}
</cfscript>