I should write a proper pull request for this, but I'm short on time today and wanted to make sure I at least contributed this code in some manor before I forget.
I was able to add data type check to my resources, so that I could do:
<cfset map().get().uri("/user/{userId:int}").to("UserResource").calls("getUserById") />
Only if the "userId" variable is an integer would this rule now match. The parameter name would still be "userId" in your code.
You can also use a regex pattern:
<cfset map().get().uri("/user/{userId:[\d]}").to("UserResource").calls("getUserById") />
Data type checking is obviously completely optional.
The majority of changes came in the setURIVarArray(), which now loops through the array and creates a mapping of regex patterns to check for. The performance impact should be extremely minimal.
Here's the code:
<cfcomponent extends="powernap.core.Map" output="false">
<!---// tracks the regex used to find the patterns in uri //--->
<cfset variables.URLDataTypes = {} />
<!---// gets uris, but allows for data type mapping //--->
<cffunction name="buildURIVarArray" access="private" returntype="array">
<cfreturn rematch("(\{\w*(:[^}]+)?})", variables.URI) />
</cffunction>
<cffunction name="setURIVarArray" access="private" returntype="void">
<cfargument name="URIVarArray" type="array" required="true" />
<cfset var pattern = "" />
<!---// map data types to the correct regex //--->
<cfloop index="pattern" array="#arguments.URIVarArray#">
<!---// check that datatype is an integer //--->
<cfif reFindNoCase(":int}$", pattern)>
<cfset variables.URLDataTypes[pattern] = "\d" />
<!---// check that datatype is a regex pattern //--->
<cfelseif reFindNoCase(":\[[^\]]+\]}$", pattern)>
<cfset variables.URLDataTypes[pattern] = listGetAt(pattern, 2, ":}") />
<cfelse>
<cfset variables.URLDataTypes[pattern] = "[\w*-]" />
</cfif>
</cfloop>
<cfset variables.URIVarArray = arguments.URIVarArray />
</cffunction>
<cffunction name="buildDynamicRegexMatcher" access="private" returntype="string">
<cfargument name="URIVarArray" type="array" required="true" />
<!--- // variables.URI is a reference to the "configuration" URI, not actual path info // --->
<cfset var matcher = variables.URI />
<cfset var currentReference = false />
<cfset var prefix = "^" />
<cfset var keysList = structKeyList(variables.appReference.getFormatRegistry(), "|") />
<cfset var suffix = "?(#keysList#)?$" />
<cfset var idx = "" />
<cfloop from="1" index="idx" to="#arrayLen(arguments.URIVarArray)#">
<cfset currentReference = URIVarArray[idx] />
<!--- if this regex includes a period, we can't get formats from URIs like /resource/ID.xml --->
<cfset matcher = rereplace(matcher, currentReference, "(#variables.URLDataTypes[currentReference]#*)") />
</cfloop>
<cfset matcher = prefix & matcher & suffix />
<cfreturn matcher />
</cffunction>
<cffunction name="createURIVarReference" access="private" returntype="array">
<cfset var template = getURIVarArray() />
<cfset var currentReference = false />
<cfset var populatedURIVars = arrayNew(1) />
<cfset var idx = "" />
<!--- //
populate the var array, but make sure to strip out
all curly braces
// --->
<cfloop from="1" index="idx" to="#arrayLen(template)#">
<cfset currentReference = URIVarArray[idx] />
<cfset arrayAppend(populatedURIVars, listFirst(rereplace(currentReference, "[\{*}*]", "", "all"), ":")) />
</cfloop>
<cfreturn populatedURIVars />
</cffunction>
</cfcomponent>
I should write a proper pull request for this, but I'm short on time today and wanted to make sure I at least contributed this code in some manor before I forget.
I was able to add data type check to my resources, so that I could do:
Only if the "userId" variable is an integer would this rule now match. The parameter name would still be "userId" in your code.
You can also use a regex pattern:
Data type checking is obviously completely optional.
The majority of changes came in the setURIVarArray(), which now loops through the array and creates a mapping of regex patterns to check for. The performance impact should be extremely minimal.
Here's the code: