How do I force evaluation of a cfif stored in a string?

二次信任 提交于 2019-12-02 09:58:40

The only way to dynamically evaluate code that you are creating at runtime is via writing it out to a file, and then executing it.

The easiest way would be to write it a .cfm page in the Virtual File System (probably name the file after a UUID, so it's unique), and then it where you need to run the contents.

I wouldn't normally advocate generating code at runtime like this, but it can be the most elegant solution in some cases.

As an alternative, instead of storing the CFML code in the database, you have a set of CFML email template files that get stored in a directory on your server, and in your database you simply record which template needs to be included either via cfinclude or cfmodule.

You can't dynamically evaluate CFML stored in a database without first writing it to file and then using <cfinclude> to include it.

If you absolutely have to do this, look at the evaluate() function. This, essentially, fires up a new CF thread, compiles the string passed to it, runs it, and returns the result.

If at all possible, I would try to find a way to move your logic to the actual file being run, not the string from the database. I assume you are pulling the data based on some string you've already built, so you might consider appending something to it, so you are looking up subjectDotLegal and subjectDocketLegal or something similar.

Remember, evaluate() is slow, ugly, and can be dangerous (it will run anything passed to it!). If there's a way around it, I suggest you use it.

Further to Mark's answer here is some psuedo code:

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

I have used code like this before with no problems. Anything in the Virtual File System flies as it is all run in RAM. For best practice do remember to delete the files created ;)

why not just use something like mustache?

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

it has the ability to not only do some of the logic that you want in your script dynamically. i really would suggest you check out the project and maybe even improve and contribute on it.

OH and just for the chance to be on a soapbox: I've been emailing Adobe for years saying that we need the ability to dynamically parse and render CFML. Sadly my cries have only gotten ignored. maybe if more people complained that this feature needs to be added, it would get the attention it deserves.

To give an example: Assume code.txt is a text file that contains the following (just to facilitate simulating CFML stored in a db): <cfoutput>#now()#</cfoutput>

The following code would work:

<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" />

In OpenBlueDragon there is the render function, which can do this.

You can mimic this function in Railo by creating a custom built-in function that saves the file into RAM then cfincludes it, using the following code:

<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> 

(This looks unusual because it needs to allow output, but prevent extra whitespace, hence why all the comments. Unfortunately SO's syntax highlighting seems to be confused by them.)

If you need an ACF-compatible solution, you'll need to use the regular filesystem and a pre-created mapping. (Well, in ACF9 and above you can use the RAM virtual filesystem, but afaik you can't create mappings on the fly like this.)

There's a better way, namely using in memory files. This way you don't have any I/O on the disk and therefore much faster:

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:///.

For tags that take absolute path, specify the syntax as provided in the following example:

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

Branson Digital Network

Here's how I stored my header and footers for all pages in a record. This code can go at the top of each page. But I have it in the APPLICATION.cfm and it seems to be working great.

The key here is not use #pound# signs on your expressions. User [square braces]. The code will pick them and evaluate them and return the result back to the template.

It will substitute the number 0 if it can not evaluate an expression as a means of error handling.

<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>

I would try the built-in QuoteName function.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!