Я не могу проверить это, потому что у меня нет примера файла XML / CEP для тестирования, но здесь есть небольшая перезапись, которая затрагивает четыре вещи:
- Вместо использования cfparam и какой-то странной структуры "params", вы должны передать CEP в функцию в качестве аргумента.
- Функция не должна напрямую изменять данные сеанса. Вместо этого вы должны вернуть результат и позволить вызывающему коду назначить его сеансу (или там, где это может понадобиться). Я покажу это во втором примере кода.
- Кэшируйте результат xml для каждого CEP - при условии, что это меняется не часто. (Вам нужно будет улучшить его, если вы хотите, чтобы основанная на времени ручная аннулирование кэша, но я могу помочь добавить это при необходимости)
- Не используйте StructInsert. В этом нет необходимости, и вы просто пишете это долгий путь ради написания этого долгий путь. нет выгоды .
Опять же, это не проверено, но, надеюсь, это полезно:
<cffunction name="getAddress" access="remote" returntype="any" output="false">
<cfargument name="cep" type="string" default="00000000" /><!--- (cep (Brazilian zip-code) string webservice would look for) --->
<cfset var searchResult = "">
<cfset var nodes = "">
<cfset var cfhttp = "">
<cfset var stateid = 0 />
<cfset var tmp = structNew()>
<!--- Validate cep string --->
<cfif IsNumeric(arguments.cep) AND Len(arguments.cep) EQ 8>
<cfif not structKeyExists(application.cepCache, arguments.cep)><!--- or cache is expired: you'd have to figure this part out --->
<!--- Consume webservice --->
<cftry>
<cfhttp method="get" url="http://www.bronzebusiness.com.br/webservices/wscep.asmx/cep?strcep=#arguments.cep#" />
<cfset searchResult = xmlparse(cfhttp.FileContent)>
<cfset nodes = xmlSearch(searchResult, "//tbCEP")>
<!--- If result insert address data into session struct --->
<cfif arrayLen(nodes)>
<cfset tmp.streetType = nodes[1].logradouro.XmlText />
<cfset tmp.streetName = nodes[1].nome.XmlText />
<cfset tmp.area = nodes[1].bairro.XmlText />
<cfset tmp.city = nodes[1].cidade.XmlText />
<cfset tmp.state = nodes[1].uf.XmlText />
<cfset tmp.cep = arguments.cep />
<!--- Get state id and add to struct --->
<cfset stateid = model("state").findOneByStateInitials(session.addressData.state)>
<cfset tmp.stateid = stateid.id />
</cfif>
<cfreturn duplicate(tmp) />
<!--- Display error if any --->
<cfcatch type="any">
<h3>Sorry, but there was an error.</h3>
<p>#cfcatch.message#</p>
</cfcatch>
</cftry>
<cfelse>
<!--- cache exists and is not expired, so use it --->
<cfreturn duplicate(application.cepCache[arguments.cep]) />
</cfif>
</cfif>
<!---
<!--- Redirect to page two of the sign up process --->
<cfset redirectTo(controller="assine", action="perfil")>
--->
</cffunction>
Обратите внимание, что я прокомментировал редирект, который вы имели в конце. Это потому, что с моей функцией вы будете возвращать значение, и после этого следует выполнить перенаправление, например:
<cfset session.addressData = getAddress("some-CEP-value") />
<cfset redirectTo(controller="assine", action="perfil")>
Если вы собираетесь пропустить кэширование (как вы скажете в комментарии, то это будет), то вот версия, которая не пытается кэшировать:
<cffunction name="getAddress" access="remote" returntype="any" output="false">
<cfargument name="cep" type="string" default="00000000" /><!--- (cep (Brazilian zip-code) string webservice would look for) --->
<cfset var searchResult = "">
<cfset var nodes = "">
<cfset var cfhttp = "">
<cfset var stateid = 0 />
<cfset var tmp = structNew()>
<!--- Validate cep string --->
<cfif IsNumeric(arguments.cep) AND Len(arguments.cep) EQ 8>
<!--- Consume webservice --->
<cftry>
<cfhttp method="get" url="http://www.bronzebusiness.com.br/webservices/wscep.asmx/cep?strcep=#arguments.cep#" />
<cfset searchResult = xmlparse(cfhttp.FileContent)>
<cfset nodes = xmlSearch(searchResult, "//tbCEP")>
<!--- If result insert address data into session struct --->
<cfif arrayLen(nodes)>
<cfset tmp.streetType = nodes[1].logradouro.XmlText />
<cfset tmp.streetName = nodes[1].nome.XmlText />
<cfset tmp.area = nodes[1].bairro.XmlText />
<cfset tmp.city = nodes[1].cidade.XmlText />
<cfset tmp.state = nodes[1].uf.XmlText />
<cfset tmp.cep = arguments.cep />
<!--- Get state id and add to struct --->
<cfset stateid = model("state").findOneByStateInitials(session.addressData.state)>
<cfset tmp.stateid = stateid.id />
</cfif>
<cfreturn duplicate(tmp) />
<!--- Display error if any --->
<cfcatch type="any">
<h3>Sorry, but there was an error.</h3>
<p>#cfcatch.message#</p>
</cfcatch>
</cftry>
</cfif>
<!---
<!--- Redirect to page two of the sign up process --->
<cfset redirectTo(controller="assine", action="perfil")>
--->
</cffunction>
Обратите внимание, что я оставил в использовании duplicate()
. Это возвращает дубликат объекта (в данном случае, структуру). Это гораздо важнее, когда вы начинаете работать с приложениями, в которых вы снова и снова передаете сложные значения в функции и из функций. Использование duplicate()
приводит к тому, что вещи передаются по значению вместо по ссылке . Это может не кусать вас в этом случае, но это хорошая привычка.
Я бы все еще использовал аргумент функции и возвращал значение - но, возможно, это мое личное предпочтение. В некотором смысле это так. Я считаю, что функция должна быть полностью инкапсулирована; общий «черный ящик». Вы даете ему некоторую информацию, и она возвращает вам некоторую информацию. Он не должен ничего изменять вне себя. (Опять же, только мое мнение.)
Итак, если вы используете эту функцию как часть большого многошагового процесса, вы все равно должны использовать ее так же, как я описал выше. Разница лишь в том, что вы устанавливаете переменную сеанса вне тела функции. Как и ранее:
<cfset session.addressData = getAddress("some-CEP-value") />
<cfset redirectTo(controller="assine", action="perfil")>