Skip to content

Add data type checking to URI mappings #1

Description

@dswitzer

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>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions