Как принудительно оценить cfif, хранящийся в строке?

Я пытаюсь сохранить код coldfusion в базе данных, который будет использоваться для темы cfmail. Сохраненный код выглядит следующим образом:

"RE: <cfif myData.general.legalName NEQ """">  {{dotlegalname}}<cfelse>{{docketLegalName}}</cfif>,    
DOT## {{dot}}, Docket ##(s)   {{docketString}}" 

Когда я извлекаю строку из базы данных, я использую cfsavecontent, чтобы попытаться ее оценить.

<cfsavecontent variable="subject">
 <cfoutput>#myData.email.subject#</cfoutput>
</cfsavecontent>

я тоже пробовал

<cfsavecontent variable="subject">
     <cfoutput>#evaluate(myData.email.subject)#</cfoutput>
</cfsavecontent>

Затем я заменяю все {{}} соответствующими значениями.

Однако тема письма упорно отказывается содержать оцененный cfif и вместо этого показывает cfif, как если бы это была строка.

Любые идеи?


person dmr    schedule 20.12.2010    source источник


Ответы (10)


Единственный способ динамически оценить код, который вы создаете во время выполнения, — это записать его в файл и затем выполнить.

Проще всего было бы записать его на странице .cfm в виртуальной файловой системе (возможно, назовите файл после UUID, чтобы он был уникальным), а затем там, где вам нужно запустить содержимое.

Обычно я бы не рекомендовал создавать такой код во время выполнения, но в некоторых случаях это может быть самым элегантным решением.

В качестве альтернативы вместо хранения кода CFML в базе данных у вас есть набор файлов шаблонов электронной почты CFML, которые хранятся в каталоге на вашем сервере, и в вашей базе данных вы просто записываете, какой шаблон необходимо включить либо через cfinclude, либо cfmodule.

person Mark Mandel    schedule 20.12.2010
comment
Это не единственное, что нужно для оценки динамического кода. Тем не менее, идея с шаблоном очень хорошая. - person Ben Doom; 22.12.2010

Вы не можете динамически оценивать CFML, хранящийся в базе данных, без предварительной записи его в файл, а затем с помощью <cfinclude> для его включения.

person Todd Sharp    schedule 20.12.2010

В дополнение к ответу Марка вот некоторый псевдокод:

<cfset fileName = createUUID() & ".cfm">
<cfset fileWrite( fileName, [CODE_FROM_DB]>
<cfinclude template="#fileName#">
<cfset fileDelete( fileName )>

Я использовал такой код раньше без проблем. Все в виртуальной файловой системе летает, так как все работает в ОЗУ. Для лучшей практики не забудьте удалить созданные файлы;)

person Sam Farmer    schedule 21.12.2010

Если вам обязательно это нужно сделать, посмотрите на функцию Assessment(). По сути, это запускает новый поток CF, компилирует переданную ему строку, запускает ее и возвращает результат.

Если это вообще возможно, я бы попытался найти способ перенести вашу логику в фактически запускаемый файл, а не в строку из базы данных. Я предполагаю, что вы извлекаете данные на основе какой-то строки, которую вы уже построили, поэтому вы можете подумать о добавлении к ней чего-либо, поэтому вы ищете subjectDotLegal и subjectDocketLegal или что-то подобное.

Помните, что функция Assessment() медленная, уродливая и может быть опасной (она выполнит все, переданное ей!). Если есть способ обойти это, я предлагаю вам использовать его.

person Ben Doom    schedule 20.12.2010
comment
На самом деле это не на 100% правда. evaulate() будет оценивать только некоторые базовые выражения. Вы не можете, например, передать оператор ‹cfif› или ‹cfset›. Он довольно ограничен в своих возможностях. - person Mark Mandel; 22.12.2010
comment
Чтобы использовать статические теги CF в оценке, вам просто нужно использовать DE() (оценка с задержкой), чтобы предотвратить выполнение тегов CF до запуска оценки(). Подобно этому: #evaluate(de(‹cfif true›это правда‹cfelse›false‹/cfif›))#. Однако для передачи строки из БД она вам не нужна, так как строка не определяется во время компиляции. Однако Бог знает, почему вы хотите оценить () статическую строку. :-) - person Ben Doom; 22.12.2010

почему бы просто не использовать что-то вроде усов?

http://mustache.github.com/ https://github.com/pmcelhaney/Mustache.cfc

у него есть возможность не только динамически выполнять некоторую логику, которую вы хотите в своем сценарии. Я бы действительно посоветовал вам проверить проект и, возможно, даже улучшить его и внести свой вклад.

О, и просто для возможности поучаствовать в мыльнице: я много лет писал Adobe по электронной почте, говоря, что нам нужна возможность динамического анализа и рендеринга CFML. К сожалению, мои крики были просто проигнорированы. возможно, если бы больше людей жаловались на необходимость добавления этой функции, она привлекла бы внимание, которого заслуживает.

person rip747    schedule 30.09.2011
comment
Вы подняли его в системе отслеживания ошибок ACF? Если да, разместите URL здесь. Если нет, поднимите запрос на реализацию функции render(code), и — если за нее проголосует достаточное количество людей — надеюсь, они прислушаются и, возможно, добавят ее в CF10. - person Peter Boughton; 01.10.2011
comment
я бы зря дышал. Я отправил этот запрос около дюжины раз. Я закончил просить ACF реализовать вещи. Лучше бы я освежил в памяти Java и сам реализовал бы его в Railo. Извините, если это звучит грубо, но зачем годами умолять Adobe что-то сделать, если теперь я могу сделать это сам. - person rip747; 07.10.2011
comment
просто хотел также упомянуть, что пару месяцев назад я портировал язык шаблонов Liquid на Coldfusion. это должно дать вам две альтернативы, чтобы спуститься. если вам нужен очень скудный, нелогичный язык шаблонов, вы можете использовать Mustache. Если вам нужно что-то более надежное, вы можете использовать Liquid: github.com/rip747/cfml-liquid - person rip747; 16.04.2012

В качестве примера: предположим, что code.txt — это текстовый файл, который содержит следующее (просто для облегчения имитации CFML, хранящегося в базе данных): <cfoutput>#now()#</cfoutput>

Следующий код будет работать:

<cfset q = queryNew("code") />
<cfset queryAddRow(q,1) />
<cfset querySetCell(q, "code", fileRead(expandPath('code.txt')), 1) />
<cfdump var="#q#">
<cfset newCodeFile = expandPath('dynamic.cfm') />
<cfset fileWrite(newCodeFile, q.code[1]) />
<cfinclude template="dynamic.cfm" />
person Todd Sharp    schedule 20.12.2010

В OpenBlueDragon есть рендеринг, которая может это сделать.

Вы можете имитировать эту функцию в Railo, создав пользовательскую встроенную функцию, которая сохраняет файл в ОЗУ, а затем включает его, используя следующий код:

<cffunction name="render" output="Yes" returntype="string"><!--- 
       ---><cfargument name="Code" required="Yes" type="string"><!--- 
       ---><cfset local.mapping = {'/render_ram_resource':'ram://'}><!--- 
       ---><cfapplication action="update" mappings="#local.mapping#"><!--- 
       ---><cfset local.fileName = "/render_ram_resource/_render_" & 
createUUID() & ".cfm"><!--- 
       ---><cffile action="WRITE" file="#fileName#" 
output="#arguments.Code#"><!--- 
       ---><cfinclude template="#fileName#"><!--- 
       ---><cffile action="DELETE" file="#fileName#"><!--- 
---></cffunction> 

(Это выглядит необычно, потому что он должен разрешать вывод, но не допускать лишних пробелов, отсюда и все комментарии. К сожалению, подсветка синтаксиса SO, похоже, сбивает их с толку.)

Если вам нужно решение, совместимое с ACF, вам нужно будет использовать обычную файловую систему и предварительно созданное сопоставление. (Ну, в ACF9 и выше вы можете использовать виртуальную файловую систему RAM, но, на самом деле, вы не можете создавать сопоставления на лету, как это.)

person Peter Boughton    schedule 30.09.2011

Есть лучший способ, а именно использование файлов в памяти. Таким образом, у вас нет ввода-вывода на диске и, следовательно, намного быстрее:

For tags that take logical path, define mapping in Administrator. Execute in-memory CFM pages using the cfinclude tag:

Create a mapping for ram:/// so that it can be used in the tags. In this example, /inmemory is the mapping that points to ram:///.

Для тегов, использующих абсолютный путь, укажите синтаксис, как показано в следующем примере:

You can also delete the file from the ram usinf cffile and action delete.

person Kevinsky    schedule 27.03.2013

Вот как я сохранил верхний и нижний колонтитулы для всех страниц в записи. Этот код может располагаться вверху каждой страницы. Но он у меня есть в APPLICATION.cfm и вроде работает отлично.

Ключевым моментом здесь является не использовать знаки #решётки# в ваших выражениях. Пользователь [квадратные скобки]. Код выберет их, оценит и вернет результат обратно в шаблон.

Он заменит число 0, если не может оценить выражение как средство обработки ошибок.

<CFSET FooterID=1234>  <!-- ID of the record you want to use -->
<CFQUERY NAME="StoredHeader" Datasource="DS1">
  Select Body from templates where id=#FooterID#
</CFQUERY>

<CFSET Parse=StoredHeader.Body>

<CFLOOP CONDITION="FindNoCase('[',Parse,1) GT 0">
    <CFSET STB=FindNoCase('[',Parse,1)>
    <CFSET ENB=FindNoCase(']',Parse,1)>
    <CFIF ENB-STB GT 0>
    <CFSET BracketExp=Mid(Parse,STB+1,ENB-1-STB)>
            <CFTRY>
                <CFSET BracketValue=Evaluate(BracketExp)>
                <CFSET Parse=ReplaceNoCase(Parse,'['&BracketExp&']',Evaluate(#BracketExp#))>                
                <cfcatch type="any">
                    <div>'Using ZERO 0 for missing <cfoutput>#BracketExp#' </cfoutput> </div>
                    <CFSET Parse=ReplaceNoCase(Parse,'['&BracketExp&']','0')>
                </cfcatch>
            </CFTRY>        
    </CFIF>
</CFLOOP>
<CFSET Footer=Parse>

<cfoutput>FOOTER</cfoutput>
person Branson Digital Network    schedule 25.04.2013

Я бы попробовал встроенную функцию QuoteName. .

person Mark SQLDev    schedule 20.12.2010
comment
Проблема на стороне coldfusion, а не на стороне сервера sql, поэтому я не думаю, что ваше предложение поможет... - person dmr; 21.12.2010