176 custom url parser in rest_api_helper

This commit is contained in:
2025-11-22 17:20:23 +03:00
parent 66248c2081
commit 1f93e137d6
3 changed files with 106 additions and 4 deletions
+102
View File
@@ -6,6 +6,7 @@
<!--- v0.03 2024-11-27 --->
<!--- v0.04 2025-11-20 columns--->
<!--- v0.05 2025-11-20 multiple field entries in filter, filter became array instead of structure--->
<!--- v0.06 2025-11-22 custom url parser used to prevent comma collision in lists--->
<cffunction name="empty2null"
access="public"
@@ -77,6 +78,62 @@
<cffunction name="parseFilterParams"
returntype="array"
output="true"
hint="Parse and collect filter params from URL. For operators see filter_build">
<cfargument name="params" type="struct" required="true" />
<!--- используется альтернативный парсер query_string, чтобы не путать запятые в значении с разделителями списка list --->
<!--- имена полей в URL в snake_case или camelCase, имена колонок в snake_case --->
<!--- token example minSize=NEQ:2--->
<cfset var local = {}/><!--- *** --->
<cfset var out = []/>
<cfset var urlParams = parseQs()/>
<cfloop collection=#params# index="local.item">
<cfset var urlParamName=snake2camel(lCase(local.item))/>
<cfif structKeyExists(urlParams,urlParamName)>
<cfloop array=#urlParams[urlParamName]# item="local.rawValue"><!--- when parameter occures in URL more than once, its values compose a comma delimited list --->
<cfset var operator="EQ"/>
<cfset var value=#local.rawValue#/>
<cfif listLen(local.rawValue,":") GT 1>
<cfset var operator=listGetAt(local.rawValue,1,":")/>
<cfset var value=listGetAt(local.rawValue,2,":")/>
</cfif>
<cfif !isValid(ARGUMENTS.params[local.item].type,value)>
<cfthrow type="invalidParamValue" message="Filter parameter #urlParamName# value is not a valid #ARGUMENTS.params[local.item].type#"/><!---не выводим значение, чтобы исключить XSS--->
</cfif>
<cfif structKeyExists(ARGUMENTS.params[local.item], "expression") AND len(ARGUMENTS.params[local.item].expression)>
<cfset var expr="#ARGUMENTS.params[local.item].expression#"/>
<cfelse>
<cfset var expr=local.item/>
</cfif>
<cfif structKeyExists(ARGUMENTS.params[local.item], "prefix") AND len(ARGUMENTS.params[local.item].prefix)>
<cfset var fieldName="#ARGUMENTS.params[local.item].prefix#.#expr#"/>
<cfelse>
<cfset var fieldName=#expr#/>
</cfif>
<cfif structKeyExists(ARGUMENTS.params[local.item], "list") AND ARGUMENTS.params[local.item].list GT 0>
<cfset var list=ARGUMENTS.params[local.item].list />
<cfelse>
<cfset var list=false />
</cfif>
<cfset var rec={field=#fieldName#, val=#value#, ftype=#ARGUMENTS.params[local.item].type#, compare=#operator#, list=#list#}/>
<cfset arrayAppend(out, rec)/>
</cfloop>
</cfif>
</cfloop>
<cfreturn out/>
</cffunction>
<cffunction name="parseFilterParamsV1"
returntype="array"
output="true"
hint="parse and collect filter params, for operators see filter_build">
@@ -411,4 +468,49 @@
<cfreturn false/>
</cffunction>
<cffunction name="parseQsToNVArray"
returntype="array"
output="false"
hint="Parse query string. Returns an array of name-value pairs">
<cfargument name="qs" type="string" default=#CGI.QUERY_STRING#/>
<cfreturn
arrayMap(
CreateObject("java", "org.apache.http.client.utils.URLEncodedUtils")
.parse(
CreateObject("java", "java.net.URI").init("http://localhost?#arguments.qs#"),
'UTF-8'
),
function(v) {
return {"name"=v.getName(),"value"=v.getValue()}
}
)
/>
</cffunction>
<cffunction name="parseQs"
returntype="struct"
output="false"
hint="Parse query string. Returns a map of arrays instead of lists to prevent delimiter problem">
<cfargument name="qs" type="string" default=#CGI.QUERY_STRING#/>
<cfreturn
arrayReduce(
CreateObject("java", "org.apache.http.client.utils.URLEncodedUtils")
.parse(
CreateObject("java", "java.net.URI").init("http://localhost?#arguments.qs#"),
'UTF-8'
),
function(struct, nvPair) {
if (structKeyExists(struct, nvPair.getName())) {
arrayAppend(struct[nvPair.getName()],nvPair.getValue())
} else {
structInsert(struct, nvPair.getName(), [nvPair.getValue()])
}
return struct;
},
{}
)
/>
</cffunction>
</cfcomponent>