How to dynamically write implicit getters and setters in ColdFusion / Lucee components?

I want to be able to dynamically write a set of getters and setters in CFML / LUCEE components ( No hardcoded cfproperty tags ).

<!--- MyComp.cfc ---> <cfcomponent displayname="MyComp" hint="MyComp" accessors="true"> <cffunction name="init"> <cfargument name="dynamicprops" type="array"> <cfloop array="#dynamicprops#" index="item"> <!--- Now what? I cannot do a cfsavecontent and write props here. It demands cfproperty just after the cfcomponent begins. I tried to do with closures but they are not acually setters and getters. Does anyone know how to better do it? ---> </cfloop> </cffunction> </cfcomponent> <!--- example call ---> <cfset mc = CreateObject("component","MyComp").init( [{"name"="a","default"=1}] ) /> 

Then I want to be able to call mc.setA (100) and mc.getA () . But this does not happen.

So my humble question is: how can I dynamically write setters and receivers on a component?

PS: Please remember that I tried to close the path:

  variables[item.name] = item.default; variables["set"&item.name] = function(_val){ variables[item.name] =_val; } variables["get"&item.name] = function(){ return variables[item.name; } 

Failed to get a job. How can I do it? Thanks:)

+5
source share
2 answers

You can use onMissingMethod() for this.

 component name="myComponent" hint="myComponent.cfc"{ function init( struct dynamicProperties={} ){ dynamicProperties.each( function( name, default ){ variables[ name ] = default; } ); return this; } function onMissingMethod( name, args ){ if( name.Left( 3 ) IS "get" ) return get( name ); if( ( name.Left( 3 ) IS "set" ) AND ( args.Len() IS 1 ) ) return set( name, args[ 1 ] ); cfthrow( type="NonExistentMethod", message="The method '#name#' doesn't exist" ); } public any function get( required string accessorName ){ var propertyName = parsePropertyName( accessorName ); if( !variables.KeyExists( propertyName ) ) cfthrow( type="NonExistentProperty", message="The property '#propertyName#' doesn't exist" ); return variables[ propertyName ]; } public void function set( required string accessorName, required any value ){ var propertyName = parsePropertyName( accessorName ); if( !variables.KeyExists( propertyName ) ) cfthrow( type="NonExistentProperty", message="The property '#propertyName#' doesn't exist" ); variables[ propertyName ] = value; } private string function parsePropertyName( accessorName ){ return accessorName.RemoveChars( 1, 3 ); } } 

Pass in your property / default name structure and it will โ€œlistenโ€ for getters / setters that match. Anything that does not result in an exception.

 <cfscript> myDynamicProperties = { A: 0, B: 0 }; // this is a struct of names and default values mc = new myComponent( myDynamicProperties ); mc.setA( 100 ); WriteDump( mc.getA() ); // 100 WriteDump( mc.getB() ); // 0 WriteDump( mc.getC() ); // exception </cfscript> 

UPDATE 1: the array of property names is replaced with the name name / default value struct as an argument to init to allow the setting of default values.

UPDATE 2: If you want to pass an array of structures containing name / value pairs by default, for example.

dynamicProperties = [ { name: "A", default: 1 }, { name: "B", default: 2 } ];

then the init () method will be:

 function init( array dynamicProperties=[] ){ dynamicProperties.each( function( item ){ variables[ item.name ] = item.default; } ); return this; } 

UPDATE 3: If you must use tags and <cfloop> to set dynamic properties, then this is all you need in the init method:

 <cfloop array="#dynamicProperties#" item="item"> <cfset variables[ item.name ] = item.default> </cfloop> 

onMissingMethod will not fire if you try to call dynamic methods as properties like this:

 method = mc[ "set#property#" ]; method( value ); 

Instead, simply create the set() and get() methods in a public component and call them directly:

 mc.set( property, value ); mc.get( property ); 
+7
source

Consider the use of accessories

 <cfcomponent displayname="MyComp" hint="MyComp" accessors="true"> 

Source: https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-tags/tags-c/cfcomponent.html

+2
source

Source: https://habr.com/ru/post/1275328/


All Articles