Changeset 224
- Timestamp:
- 07/08/06 18:00:58 (3 years ago)
- Files:
-
- 1 modified
-
fusebox.org/view/doc/dspFusebox5WhatsNew.cfm (modified) (24 diffs)
Legend:
- Unmodified
- Added
- Removed
-
fusebox.org/view/doc/dspFusebox5WhatsNew.cfm
r218 r224 1 <cfset request.title = "f u s e b o x 5 @ c o r f i e l d . o r g" />2 1 <h1>Fusebox 5</h1> 3 <p>Last updated: Ju ne 25th, 2006</p>2 <p>Last updated: July 8th, 2006</p> 4 3 <p>Fusebox 5 is the next major release of the Fusebox application framework. The timeline for Fusebox 5 is:</p> 5 4 <ul> … … 24 23 <p>Because the core files in Fusebox 5 are ColdFusion Components, you will need to ensure that <em>Report Execution Times</em> is turned <em><strong>off</strong></em> in the ColdFusion Administrator (under <em>Debugging Settings</em>). For some reason, <em>Report Execution Times</em> adds a large performance overhead to CFC execution and reports wildly inaccurate results. For accurate execution time reporting, you will probably find the <a href="#debugmode">Debug / Trace Mode</a> useful - or you could use <code><cftimer></code> (on ColdFusion MX 7) or plain old <code>getTickCount()</code> around code you wish to time.</p> 25 24 <h2>Documentation</h2> 26 <p>This page is the starting point for documentation about Fusebox 5 while I am developing the framework. To stay current with development of the this new release of the framework, join the <a href="http://groups.yahoo.com/group/fusebox5/">Fusebox 5 mailing list</a> on Yahoo! Groups. The documentation will evolve intothree primary sections:</p>25 <p>This page covers all the differences between Fusebox 4.1 and Fusebox 5. For questions about Fusebox 5 and to discuss development of Fusebox 5 applications, join the <a href="http://groups.yahoo.com/group/fusebox5/">Fusebox 5 mailing list</a> on Yahoo! Groups. This documentation has three primary sections:</p> 27 26 <ol> 28 <li>User documentation,covering new features in Fusebox and how to use them in your applications</li>29 <li> Custom lexicon and plugin documentation, aimed at developers who are extending the framework</li>30 <li> Framework documentation,explaining the request lifecycle and how the new core files work </li>27 <li>User Documentation: covering new features in Fusebox and how to use them in your applications</li> 28 <li>Extending the Framework: custom lexicon and plugin documentation, aimed at developers who are extending the framework</li> 29 <li>Inside the Framework: explaining the request lifecycle and how the new core files work </li> 31 30 </ol> 32 <h3>Using the new features</h3> 31 <p>There is also a short section on compatibility, highlighting known differences between the behavior of Fusebox 5 and Fusebox 4.1 (these differences are mostly subtle and likely to affect plugin authors more than regular users of the framework). </p> 32 <p>Both John Quarto-von-Tivadar and Jeff Peters are planning updated books covering this new release of the framework. Those books will go into a lot more detail about the new features and the inner workings of the new core files than this page can cover. </p> 33 <h1>User Documentation - Using the new features</h1> 33 34 <p>We will go through each of the major new features first and then look at all of the smaller changes in turn. </p> 34 <h 4>Multiple applications</h4>35 <h2>Multiple applications</h2> 35 36 <p>Fusebox 4.1 only allowed one Fusebox application per ColdFusion application because it used <code>application.fusebox</code> as the single location for the framework's cached data. Fusebox 5 allows you to specify the key used inside <code>application</code> scope to store that data. By default, the key is <code>fusebox</code>, for backward compatibility. You can change the key by setting <code>FUSEBOX_APPLICATION_KEY</code> in your <code>index.cfm</code> file, prior to including <code>/fusebox5/fusebox5.cfm</code>. </p> 36 37 <p>For example:</p> … … 52 53 <li><code>myFusebox.getApplication()</code> - this is the preferred way to refer to the Fusebox application object </li> 53 54 </ul> 54 <h 4>Application initialization</h4>55 <h2>Application initialization</h2> 55 56 <p>Fusebox 4.1 provides two ways to execute code at the beginning of every request:</p> 56 57 <ul> … … 64 65 </ul> 65 66 <p>The fuseaction specified in <code><appinit></code> is executed only on the first request after the framework is loaded and the framework automatically locks execution to ensure thread safety. The same is true of <code>fusebox.appinit.cfm</code> which is included immediately after the framework is loaded, before the request is compiled and processed, again inside a lock to ensure thread safety. Be aware, however, that<em> </em>the named locks used for <code><appinit></code> and <code>fusebox.appinit.cfm</code> are different. <code>fusebox.appinit.cfm</code> executes as part of the framework load process, even before <code>fusebox.init.cfm</code> is executed, and is thread safe in that context. <code><appinit></code> executes conditionally as part of each request and is thread safe in that context. Care should be exercised when using both <code>fusebox.appinit.cfm</code> and <code><appinit></code> to perform initialization within the same application - it is recommended that you use one form or the other, but not both. </p> 67 <p>If you have per-application initialization that you wish to share between a Fusebox 5 application and a non-Fusebox application, use <code>fusebox.appinit.cfm</code> because that can be included into the non-Fusebox application (although be aware that the non-Fusebox application would need to conditionally lock execution of that file - unless you use the same application name and the non-Fusebox application used <code>onApplicationStart()</code> in <code>Application.cfc</code> to include the file). </p> 68 <p>Otherwise, if you are not sharing initialization with a non-Fusebox application, use the <code><appinit></code> global fuseaction. </p> 66 69 <p>Note that the fuseaction specified in <code><appinit></code> executes outside the normal fuseaction lifecycle: no plugins are executed as part of the application initialization. The <code><appinit></code> fuseaction must therefore not depend on any plugin behavior. However, this allows any and all of the plugin points to safely depend on code that is executed as part of application startup.</p> 67 <h 4>Nested verbs </h4>70 <h2>Nested verbs </h2> 68 71 <p>Fusebox 4.1 placed a number of restrictions on how <code><if></code> and <code><loop></code> verbs could be nested. Fusebox 5 removes those restrictions so you can nest <code><if></code> and <code><loop></code> verbs inside <code><if></code> and <code><loop></code> verbs to any depth you want. Just remember that business logic belongs in <em>fuses</em>, not <em>fuseactions</em>! </p> 69 <h 4>New loop syntax</h4>72 <h2>New loop syntax</h2> 70 73 <p>ColdFusion supports five forms of the <code>cfloop</code> tag: </p> 71 74 <ul> 72 <li>from / to / index </li>75 <li>from / to / index / step </li> 73 76 <li>query</li> 74 77 <li>condition</li> … … 81 84 <li><code><loop list="#someList#" index="someVariable"> .. </loop></code> </li> 82 85 </ul> 83 <h 4>New invoke and instantiate syntax</h4>86 <h2>New invoke and instantiate syntax</h2> 84 87 <p>With Fusebox 4.1, for <code><invoke></code> you had to specify the method name and the list of arguments together as a single attribute, <code>methodcall</code>. Similarly, for <code><instantiate></code> you had to specify the list of arguments as a single attribute, <code>arguments</code>. Several people felt this was not a very natural syntax, given that ColdFusion's <code><cfinvoke></code> tag uses <code>method</code> to specify the method name and then either inline attributes or nested <code><cfinvokeargument></code> tags to specify the arguments in the method call. </p> 85 88 <p>Fusebox 5 adds the ability to specify the method name and the arguments separately, more in line with ColdFusion's syntax, allowing for both named arguments and positional arguments. The following two forms of <code><invoke></code> are now equivalent:</p> … … 93 96 </invoke> </pre> 94 97 </blockquote> 95 <p>In addition, the following two forms of <code><invoke></code> are now equivalent:</p> 98 <p>Note in particular the differences between strings and evaluated arguments in the two different forms of syntax. </p> 99 <p>This is how you can specify positional (unnamed) arguments in the two different forms of syntax:</p> 96 100 <blockquote> 97 101 <pre><!--- Fusebox 4.1 style invocation, also valid in Fusebox 5 ---> … … 113 117 </instantiate> </pre> 114 118 </blockquote> 115 <p>As are the following two forms:</p> 119 <p>Again, note the differences in the way strings and evaluated arguments are specified.</p> 120 <p>You can also specify positional (unnamed) arguments for <code><instantiate></code>:</p> 116 121 <blockquote> 117 122 <pre><!--- Fusebox 4.1 style instantiation, also valid in Fusebox 5 ---> … … 123 128 </instantiate> </pre> 124 129 </blockquote> 125 <p>You can mix positional arguments and named arguments, although all positional arguments must preceded any named arguments, just as in a regular ColdFusion method call using <code><cfinvokeargument></code>. Note that the Fusebox 4.1 forms (<code>methodcall</code> on <code><invoke></code> and <code>arguments</code> on <code><instantiate></code>) are not deprecated in Fusebox 5 - it is possible that those attributes willbe deprecated in a future release of Fusebox. </p>126 <h 4>New do, fuseaction and include syntax</h4>130 <p>You can mix positional arguments and named arguments, although all positional arguments should precede any named arguments, just as in a regular ColdFusion method call using <code><cfinvokeargument></code>. Note that although the Fusebox 4.1 forms (<code>methodcall</code> on <code><invoke></code> and <code>arguments</code> on <code><instantiate></code>) are not deprecated in Fusebox 5 - it is possible that those attributes may be deprecated in a future release of Fusebox. </p> 131 <h2>New do, fuseaction and include syntax</h2> 127 132 <p>The variable namespace in Fusebox 4.1 is completely flat. If you <code><include></code> a fuse (or <code><do></code> a fuseaction), any variables defined at the point of the <code><include></code> (or <code><do></code>) are visible directly inside the fuse (or fuseaction). Similarly, any changes made to those variables inside the fuse (or fuseaction) will leak back into the original fuseaction code. This makes it hard to write modular code.</p> 128 133 <p>Fusebox 5 introduces parameters for the <code><include></code> and <code><do></code> verbs. This lets you protect variables from being overwritten by an included fuse or an executed fuseaction, as well as allowing you to pass variables into a fuse or fuseaction without "polluting" the variables scope in the current fuseaction. You can specify one or more variables (and values) that are active only for the included fuse (or executed fuseaction). Any existing variables of the same name are pushed safely away and restored after the <code><include></code> (or <code><do></code>) is complete. </p> … … 151 156 </blockquote> 152 157 <p>As with <code><do></code> and <code><include></code>, any <code><parameter></code> variables specified for <code><fuseaction></code> will not pollute the main variables scope. </p> 153 <p>It's also worth noting that the following (undocumented) form of <code><include></code> is now officially supported in Fusebox 5:</p>158 <p>It's also worth noting that the following form of <code><include></code> is now officially supported in Fusebox 5 - it was undocumented in Fusebox 4.1:</p> 154 159 <blockquote> 155 160 <pre><include template="somefuse" circuit="somecircuit" /></pre> 156 161 </blockquote> 157 162 <p>This looks in the directory of <code>somecircuit</code> (as specified by the <code>path</code> attribute in <code>somecircuit</code>'s declaration in <code>fusebox.xml</code>) for the fuse <code>somefuse.cfm</code> and includes it. This can be useful in MVC-style applications that would otherwise have a lot of fuseactions that simply <code><include></code> a single fuse but are used (via <code><do></code>) from other circuits. For example, <strong>V</strong>iew circuits often have many simple fuseactions that just <code><include></code> a display fuse (and <strong>M</strong>odel circuits may have simple fuseactions that just <code><include></code> action or query fuses). The <code>circuit=</code> form of <code><include></code> allows the <strong>C</strong>ontroller circuits to <code><include></code> display (or action / query) fuses directly without requiring the intermediate simple fuseaction in the <strong>V</strong>iew (or <strong>M</strong>odel) circuits. </p> 158 <h 4>New execution modes</h4>163 <h2>New execution modes</h2> 159 164 <p>Fusebox 4.1 has the concept of loading, parsing and executing as part of a request. It <strong>loads</strong> the XML files (<code>fusebox.xml</code> and <code>circuit.xml</code>). It <strong>parses</strong> the XML and created the <code>parsed/</code> fuseaction files. It <strong>executes</strong> those files. There are two standard execution modes, set as parameters in <code>fusebox.xml</code>:</p> 160 165 <ul> … … 162 167 <li><code><parameter name="mode" value="production" /></code></li> 163 168 </ul> 164 <p>Development mode causes the framework to load the XML files, if any of them have changed since the last load operation, and parse them on-demand (i.e., generating a <code>parsed/</code> fuseaction file for each request). Production mode causes the framework to load the XML files just once, at application startup, and then only parse each fuseaction the first time it is requested - changes to the XML files are ignored until the framework is restarted or explicitly told to load the XML files and/or parse the fuseaction again.</p>169 <p>Development mode causes the framework to load the XML files, if any of them have changed since the last load operation, and parse them on-demand (i.e., generating a <code>parsed/</code> fuseaction file for each request). Production mode causes the framework to load the XML files just once, on the first request, and then only parse each fuseaction the first time it is requested - changes to the XML files are ignored until the framework is restarted or explicitly told to load the XML files and/or parse the fuseaction again.</p> 165 170 <p>You can specify URL variables that tell Fusebox to load the XML files or just re-parse the requested fuseaction. You can also tell Fusebox not to execute a request (i.e., you might tell it to re-parse a specific fuseaction but not actually execute it). Those URL variables are:</p> 166 171 <ul> … … 179 184 </ul> 180 185 <p>This new mode does not load the <code>fusebox.xml</code> file and does not re-initialize the framework itself, but it does reload any <code>circuit.xml</code> files required by the current request (if they have changed) and re-parse the requested fuseactions. This removes the performance hit involved with re-initializing the framework CFCs during regular development mode and is also thread safe.</p> 181 <p>In keeping with the more explicit name of the new development mode, the basic development mode should be specified as <code>"development-full-load"</code> - the old <code>"development"</code> mode is deprecated (Fusebox 5 still supports it but in strict mode, <code>"development"</code> will cause an exception). </p>186 <p>In keeping with the more explicit name of the new development mode, the basic development mode should now be specified as <code>"development-full-load"</code> - the old <code>"development"</code> mode is deprecated (Fusebox 5 still supports it but in strict mode, <code>"development"</code> will cause an exception). </p> 182 187 <p>The two new URL variables are:</p> 183 188 <ul> … … 186 191 </ul> 187 192 <p>The former is equivalent to <code>fusebox.load</code> but also deletes all existing <code>parsed/</code> files before reloading the framework. This is a good way to ensure that every fuseaction will get re-generated, as well as clearing out any old <code>parsed/</code> files that represent fuseactions that are no longer present in the application. The latter causes every public fuseaction in your entire application to be re-parsed and all the <code>parsed/</code> files re-generated - effectively a pre-compilation option. This can be useful for a production system, after a new release of your application, so that your users do not have to experience the one-off hit of parsing on as each fuseaction is requested. </p> 188 <h 4>Strict Mode </h4>189 <p>As the framework evolves, some ways of doing things are no longer considered best practice as better ways take their place. You will hear the term "deprecated" quite often in these discussions. Deprecated means "still supported but not recommended" and often implies that the feature in question will be removed at some future date (usually a distant future date, to allow people to migrate their code away from the deprecated features). For example, Fusebox 4.1 deprecated using <code><do></code> in a global fuseaction - the more explicit <code><fuseaction></code> verb was introduced instead, to avoid confusion with the regular <code><do></code> verb. The intent is that at some future date, <code><do></code> will no longer be legal inside a global fuseaction. Fusebox 5 deprecates the experimental <code><lexicons></code> declaration, in favor of the new, more powerful XML namespace form of lexicon (see below). Fusebox 4.1 still supported Fusebox 4.0's <code>application.fusebox.rootdirectory</code> but introduced <code>application.fusebox.approotdirectory</code> as the preferred way to refer to that path (and, I believe, may have deprecated the former). Fusebox 5 officially deprecates that Fusebox 4.0 compatibility feature.</p>193 <h2>Strict Mode </h2> 194 <p>As the framework evolves, some ways of doing things are no longer considered best practice as better ways take their place. You will hear the term "deprecated" quite often in these discussions. Deprecated means "still supported but not recommended" and often implies that the feature in question will be removed at some future date (usually a distant future date, to allow people plenty of time to migrate their code away from the deprecated features). For example, Fusebox 4.1 deprecated using <code><do></code> in a global fuseaction - the more explicit <code><fuseaction></code> verb was introduced instead, to avoid confusion with the regular <code><do></code> verb. The intent is that at some future date, <code><do></code> will no longer be legal inside a global fuseaction. Fusebox 5 deprecates the experimental <code><lexicons></code> declaration, in favor of the new, more powerful XML namespace form of lexicon (see below). Fusebox 4.1 still supported Fusebox 4.0's <code>application.fusebox.rootdirectory</code> but introduced <code>application.fusebox.approotdirectory</code> as the preferred way to refer to that path (and, I believe, may have deprecated the former). Fusebox 5 officially deprecates that Fusebox 4.0 compatibility feature.</p> 190 195 <p>In order to help developers migrate code away from deprecated features, Fusebox 5 introduces a new <code>fusebox.xml</code> parameter called <code>strictMode</code>. By default, this is set to <code>false</code> and deprecated features are silently supported. If you set this parameter to <code>true</code>, Fusebox 5 will detect those deprecated features and throw an exception if they are used (well, using <code>application.fusebox.rootdirectory</code> in strict mode will cause an exception in your code since Fusebox 5 only sets that variable when <code>strictMode</code> is <code>false</code>!):</p> 191 196 <ul> 192 197 <li><code><parameter name="strictMode" value="true" /></code></li> 193 198 </ul> 194 <p>In addition, Fusebox 5 performs some additional validation of XML verbs and attributes since it deprecates any undocumented attributes appearing in the XML file that are not declared using an XML namespace. </p> 195 <p>It is possible (and likely) that a future release of Fusebox will change the default of <code>strictMode</code> to <code>true</code> or will simply make the deprecated features illegal. </p> 196 <h4>Implicit Circuits</h4> 197 <p>As mentioned above, Fusebox 5 officially sanctions the "include via circuit alias" syntax that lets you directly include fuses from specified circuits. This makes it easier to build MVC style applications because you don't need to <code><do></code> a fuseaction in another circuit, just to have it include a single fuse. However, in such heavily structured MVC applications, this can lead to a number of empty circuits - circuits that contain no fuseactions but exist simply as a way to organize the fuses that are included from other circuits. In Fusebox 4.1, you would be required to have an actual circuit XML file in the directory containing those fuses. Fusebox 5 allows you to omit empty circuit files by using the <code>allowImplicitCircuits</code> parameter in <code>fusebox.xml</code>: </p> 199 <p>In addition, Fusebox 5 performs some additional validation of XML verbs and attributes since it deprecates any undocumented attributes appearing in the XML file that are not declared using an XML namespace. In other words, in strict mode, any unrecognized attributes in the XML file will cause an exception to be thrown. </p> 200 <p>It is possible (and likely) that a future release of Fusebox will either change the default of <code>strictMode</code> to <code>true</code> or will simply make the deprecated features illegal. </p> 201 <h2>Implicit Circuits</h2> 202 <p>Fusebox 4.1 introduced a form of the <code><include></code> verb that allows you to include a fuse directly from a specified circuit without having to <code><do></code> a fuseaction in that circuit: </p> 203 <ul> 204 <li><code><include template="dspHome" circuit="view" /> </code></li> 205 </ul> 206 <p>This makes it easier to build MVC style applications: you no longer need a <code>view.home</code> fuseaction that only <code><include></code>s the <code>dspHome</code> fuse because the controller circuit can include the view directly. Similarly for fuseactions in the model that only <code><include></code> action or query fuses - again, the controller circuit can include the action or query fuses directly.</p> 207 <p>However, in such heavily structured MVC applications, this can lead to a number of empty circuits - circuits that contain no fuseactions but exist simply as a way to organize the fuses that are included from other circuits. In Fusebox 4.1, you would be required to have an actual circuit XML file in the directory containing those fuses. These circuit XML files would be effectively empty:</p> 208 <ul> 209 <li><code><circuit></circuit></code></li> 210 </ul> 211 <p>or even just:</p> 212 <ul> 213 <li><code><circuit/></code></li> 214 </ul> 215 <p>Fusebox 5 allows you to omit these empty circuit files by using the <code>allowImplicitCircuits</code> parameter in <code>fusebox.xml</code>: </p> 198 216 <ul> 199 217 <li><code><parameter name="allowImplicitCircuits" value="true" /> </code></li> 200 218 </ul> 201 <p>By default, this parameter is <code>false</code> and therefore circuit XML files are required, just as in Fusebox 4.1. Note that the implementation of this feature simply catches the exception that would normally be thrown at application load time when Fusebox cannot find <code>circuit.xml</code> or <code>circuit.xml.cfm</code> and substitutes an empty <code><circuit/></code> declaration. The presence of the circuit file is still checked each time the application is loaded.</p> 202 <h4><a name="debugmode" id="debugmode"></a>Debug / Trace Mode</h4> 203 <p>Fusebox 5 adds a timed trace / debug option so you can see where the time is being taken inside your code. Setting the <code><parameter></code> <code>debug</code> to <code>true</code> in your <code>fusebox.xml</code> file will cause a trace to be displayed at the end of each request, showing the steps in the request lifecycle and the time at which each begins (in milliseconds, relative to the start of the request). At present, the loading of the framework, the compilation of the request, the execution of <code>fusebox.appinit.cfm</code> and <code>fusebox.init.cfm</code> and all <code><do></code>, <code><fuseaction></code> and <code><include></code> verbs are traced. This may change based on developer feedback!</p> 219 <p>You will still need to declare all the circuits in the <code><circuits></code> section of your <code>fusebox.xml</code> file, but you will no longer have to create the empty circuit XML file for those circuits.</p> 220 <p>By default, this parameter is <code>false</code> for compatibility with Fusebox 4.1. </p> 221 <p>Note that the implementation of this feature simply catches the exception that would normally be thrown at application load time when Fusebox cannot find <code>circuit.xml</code> or <code>circuit.xml.cfm</code> and instead substitutes an empty <code><circuit/></code> declaration. The presence of the circuit file is still checked each time the application is loaded so you will still see exceptions logged.</p> 222 <h2><a name="debugmode" id="debugmode"></a>Debug / Trace Mode</h2> 223 <p>Fusebox 5 adds a timed trace / debug option so you can see where the time is being taken inside your code. Setting the <code><parameter></code> <code>debug</code> to <code>true</code> in your <code>fusebox.xml</code> file will cause a trace to be displayed at the end of each request, showing the steps in the request lifecycle and the time at which each begins (in milliseconds, relative to the start of the request). At present, the loading of the framework, the compilation of the request, the execution of <code>fusebox.appinit.cfm</code> and <code>fusebox.init.cfm</code> and all <code><do></code>, <code><fuseaction></code> and <code><include></code> verbs are traced.</p> 204 224 <ul> 205 225 <li><code><parameter name="debug" value="true" /> <br /> … … 212 232 <li><code>Compiler</code> - when <code>fusebox.xml</code> and <code>circuit.xml</code> files are loaded during compilation </li> 213 233 </ul> 214 <h3>Extending the framework</h3> 234 <p> You probably want to use something different, such as <code>"User"</code>, for your own trace output. The <code>message</code> argument can only be a simple value (such as a string). </p> 235 <h1>Extending the framework</h1> 215 236 <p>As in Fusebox 4.1, there are two ways to extend the framework: custom lexicons and plugins. The former method has undergone significant changes in Fusebox 5, the latter method is almost completely unchanged. The next two sections cover the differences between Fusebox 4.1 and Fusebox 5 and the new features offered by Fusebox 5. </p> 216 <h 4>Custom lexicons</h4>237 <h2>Custom lexicons</h2> 217 238 <p>Fusebox 4.1 introduced the concept of custom lexicons as an "experimental" feature that was intended to allow developers to extend the XML grammar of the core Fusebox framework. There were three basic parts to using custom lexicons in Fusebox 4.1:</p> 218 239 <ul> … … 221 242 <li>The actual <code>verb.cfm</code> implementation file </li> 222 243 </ul> 223 <p>The <code><lexicon></code> declaration identified the <code>prefix</code> and the path (relative to the <code>lexicon/</code> directory in your application root) where Fusebox 4.1 expected to find <code>verb.cfm</code> files. You could not nest custom verbs. Any nested verbs (between the opening and closing tags) were silently ignored. A custom verb used several framework-provided UDFs, such as <code>fb_appendLine()</code>, to write CFML code to the <code>parsed/</code> fuseaction file. </p>244 <p>The <code><lexicon></code> declaration identified the <code>prefix</code> and the path (relative to the <code>lexicon/</code> directory in your application root) where Fusebox 4.1 expected to find <code>verb.cfm</code> files. You could not nest anything inside custom verb invocations. Any nested verbs (between the opening and closing tags) were silently ignored. A custom verb used several framework-provided UDFs, such as <code>fb_appendLine()</code>, to write CFML code to the <code>parsed/</code> fuseaction file. </p> 224 245 <p>While Fusebox 5 still supports that machinery, it is considered to be deprecated, i.e., not the recommended way to do things! It is entirely possible some Fusebox 4.1 custom lexicons won't work with Fusebox 5, especially if they relied on the <code>fb_</code> data structure (which, even in the "Discovering Fusebox 4" book was marked as something developers should not rely on!). </p> 225 246 <p>Fusebox 5 supports per-circuit custom lexicons using XML namespace syntax. You declare a custom lexicon using the <code>xmlns</code> attribute in the <code><circuit></code> tag:</p> … … 227 248 <li> <code><circuit xmlns:<em>prefix</em>="<em>path/to/verbs/</em>"></code></li> 228 249 </ul> 229 <p>As with Fusebox 4.1, the path is relative to the <code>lexicon/</code> directory in your application root.</p> 250 <p>As with Fusebox 4.1, the path is relative to the <code>lexicon/</code> directory in your application root. For example:</p> 251 <ul> 252 <li><code><circuit xmlns:cf="cf/"> </code> </li> 253 </ul> 254 <p>This will declare the prefix <code>cf</code> to refer to the <code>lexicon/cf/</code> directory in your application root (assuming you started with the standard Fusebox 5 skeleton application example). </p> 230 255 <p>You invoke custom verbs using XML namespace syntax as follows:</p> 231 <blockquote> 232 <p><code><<em>prefix</em>:<em>verb</em> /></code></p> 233 </blockquote> 256 <ul> 257 <li><code><<em>prefix</em>:<em>verb</em> /></code></li> 258 </ul> 259 <p>For example:</p> 260 <ul> 261 <li><code><cf:dump var="#attributes.myVar#" /></code> </li> 262 </ul> 234 263 <p>Custom verbs can have nested child verbs:</p> 235 <blockquote><pre><<em>prefix</em>:<em>verb</em>> 236 <set name="foo" value="42"/> 237 </<em>prefix</em>:<em>verb</em>></pre> 238 </blockquote> 239 <p>Custom verbs now execute twice - just like custom tags in ColdFusion when you specify a closing slash (<code>/</code>) or an end tag - with an execution mode of <code>"start"</code> at the opening tag and <code>"end"</code> at the closing tag. A Fusebox 5 custom verb implementation file therefore typically looks like this:</p> 264 <blockquote> 265 <pre><cf:timer type="outline" label="actLongCalculation"> 266 <include template="actLongCalculation" circuit="model" /> 267 </cf:timer></pre></blockquote> 268 <p>Custom verbs now execute twice - just like custom tags in ColdFusion when you specify a closing slash (<code>/</code>) or an end tag - with an execution mode of <code>"start"</code> at the opening tag and <code>"end"</code> at the closing tag. In the above example, <code>timer.cfm</code> is executed (with <code>fb_.verbInfo.executionMode</code> equal to <code>"start"</code>) and then the <code><include></code> verb executes and then <code>timer.cfm</code> executes again (with <code>fb_.verbInfo.executionMode</code> equal to <code>"end"</code>). </p> 269 <p>A Fusebox 5 custom verb implementation file therefore typically looks like this:</p> 240 270 <blockquote><pre><cfscript> 241 271 if (fb_.verbInfo.executionMode is "start") { … … 251 281 </blockquote> 252 282 <p>This adds the CFML line to the parsed file, to be executed at runtime. It's important to remember that custom verbs execute at compile time, i.e., when a <code>circuit.xml</code> file is loaded and parsed, but the code that the verbs generate is executed at runtime, i.e., on all requests.</p> 253 <p>You can also specify custom attributes on <code><fuseaction></code> tags (and <code><circuit></code> tags) using the XML namespace notation :</p>254 <blockquote> 255 <pre><circuit xmlns: <em>prefix</em>="<em>path/to/verbs/</em>" <em>prefix</em>:security="enabled">283 <p>You can also specify custom attributes on <code><fuseaction></code> tags (and <code><circuit></code> tags) using the XML namespace notation, for example:</p> 284 <blockquote> 285 <pre><circuit xmlns:security="checkpoint/roles/" security:accessChecking="enabled"> 256 286 ... 257 <fuseaction name="main" <em>prefix</em>:admin="no"></pre>258 </blockquote> 259 <p>A plugin (or custom verb) can then call <code>getCustomAttributes(" <em>prefix</em>")</code> on the fuseaction or circuit objectto retrieve a struct containing any matching attributes. The assumption is that you will generally have custom verbs associated with the prefix / path. Using custom attributes like this is the recommended way to extend the grammar in Fusebox 5 and ensures that you will not conflict with any future built-in attributes. </p>287 <fuseaction name="main" security:admin="no"></pre> 288 </blockquote> 289 <p>A plugin (or custom verb) can then call <code>getCustomAttributes("security")</code> on the fuseaction and circuit objects to retrieve a struct containing any matching attributes. The assumption is that you will generally have custom verbs associated with the prefix / path. Using custom attributes like this is the recommended way to extend the grammar in Fusebox 5 and ensures that you will not conflict with any future built-in attributes. </p> 260 290 <p>You can also specify custom attributes on <code><class></code> declarations in <code>fusebox.xml</code>, and the <code><fusebox></code> tag itself, if you declare the XML namespace on the <code><fusebox></code> tag. Again, <code>getCustomAttributes("<em>prefix</em>")</code> can be called on the class object or Fusebox application object to retrieve any matching attributes.</p> 261 <h 5>Built-in Verbs</h5>291 <h3>Built-in Verbs</h3> 262 292 <p>It is worth noting that built-in verbs are also implemented as a custom lexicon. Built-in verbs exist in a reserved namespace called <code>$fusebox</code>. They are invoked without a prefix. In all other respects, they are just like user-defined custom lexicon verbs. Note that the verbs <code><do></code> and <code><fuseaction></code> are handled inside the framework and do not exist as external verbs (because they require framework 'magic' to accomplish their tasks: they are really compiler directives, rather than actual verbs).</p> 263 <h 5>Writing Custom Verbs</h5>293 <h3>Writing Custom Verbs</h3> 264 294 <p>Fusebox 5 verbs behave somewhat like custom tags. They have an execution mode (<code>start</code>, <code>inactive</code>, <code>end</code>) accessible through the <code>fb_.verbInfo</code> structure. That structure has the following members:</p> 265 295 <ul> … … 295 325 <p>To access the current circuit's object within a verb, use <code>fb_.verbInfo.action.getCircuit()</code>. To access the application object (and, hence, any <code>fusebox.xml</code> parameter values), use <code>fb_.verbInfo.action.getCircuit().getApplication()</code>. </p> 296 326 <p>It's definitely worth looking at the source of both the built-in verbs and the skeleton application's custom verbs for ideas on how to write your own custom verbs. In particular, the <code>argument</code> / <code>instantiate</code> / <code>invoke</code> group of verbs and the <code>include</code> / <code>parameter</code> pair of verbs show how parent and child verbs can communicate using the <code>fb_.verbInfo</code> structure. </p> 297 <h 4>Plugins</h4>327 <h2>Plugins</h2> 298 328 <p>Although nothing has really changed in this area of the framework - most Fusebox 4.1 plugins should continue to work with Fusebox 5 without any changes - there are two changes that will impact the lives of plugin authors:</p> 299 329 <ul> … … 317 347 <p>Locating the XML files is possible using these method calls on the <code>myFusebox</code> object: </p> 318 348 <ul> 319 <li><code> getApplication().getApplicationRoot() &getApplication().getFuseboxXMLFilename()</code> - returns the full filesystem path of the <code>fusebox.xml</code> (or <code>fusebox.xml.cfm</code>) file for this application</li>320 <li><code> getCurrentCircuit().getCircuitRoot() &getCurrentCircuit().getCircuitXMLFilename()</code> - returns the full filesystem path of the <code>circuit.xml</code> (or <code>circuit.xml.cfm</code>) file for the currently executing circuit </li>321 </ul> 322 <p>If a plugin needs to loop over all the circuit s, it can do the following:</p>323 <ul> 324 <li><code><cfloop collection="# getApplication().circuits#" item="circuitName"></code></li>349 <li><code>myFusebox.getApplication().getApplicationRoot() & myFusebox.getApplication().getFuseboxXMLFilename()</code> - returns the full filesystem path of the <code>fusebox.xml</code> (or <code>fusebox.xml.cfm</code>) file for this application</li> 350 <li><code>myFusebox.getCurrentCircuit().getCircuitRoot() & myFusebox.getCurrentCircuit().getCircuitXMLFilename()</code> - returns the full filesystem path of the <code>circuit.xml</code> (or <code>circuit.xml.cfm</code>) file for the currently executing circuit </li> 351 </ul> 352 <p>If a plugin needs to loop over all the circuit objects, it can do the following:</p> 353 <ul> 354 <li><code><cfloop collection="#myFusebox.getApplication().circuits#" item="circuitName"></code></li> 325 355 </ul> 326 356 <p>All of the public methods in the various framework objects are documented (using the <code>hint</code> attribute) so that plugin authors can take advantage of all of the exposed framework functionality. View the <a href="http://corfield.org/cfcdoc/" target="_blank">automatically generated documentation</a>. </p> 327 <h 3>Inside the framework </h3>357 <h1>Inside the framework </h1> 328 358 <p>This section covers how the framework operates under the hood. It is provided purely for the entertainment of the curious out there since, other than some deep, dark corners of how plugins do their job, the internals of the framework should really be of no concern to developers who are using the framework. The most useful piece of this documentation for developers will be <strong>The request lifecycle</strong> below.</p> 329 359 <p>Like previous versions of Fusebox, the core files have a single CFML page that acts as the entry point for all requests and which should be included by your <code>index.cfm</code> file, typically:</p> … … 333 363 <p>That file in turn creates the <code>myFusebox</code> structure and then, if necessary, the <code>application.fusebox</code> structure (or, more correctly, the <code>application[FUSEBOX_APPLICATION_KEY]</code> structure). The requested fuseaction is then compiled - which may or may not cause circuits to be reloaded and may or may not cause a parsed file to be generated, depending on the execution mode of the framework. </p> 334 364 <p>The next two sections cover the request lifecycle in more depth and look inside the core framework to explain how everything works. </p> 335 <h 4>The request lifecycle</h4>365 <h2>The request lifecycle</h2> 336 366 <p>This section explains the detailed steps involved in handling a request inside the Fusebox framework, as well as how a fuseaction itself is handled. </p> 337 <h 5>Executing a request </h5>367 <h3>Executing a request </h3> 338 368 <p>For each request, processed by <code>fusebox5.cfm</code>, the following steps occur: </p> 339 369 <ol> … … 368 398 </li> 369 399 </ol> 370 <h 5>Executing a fuseaction</h5>400 <h3>Executing a fuseaction</h3> 371 401 <p>Each time a fuseaction is executed, either as the top-level requested fuseaction or via a <code><do></code> or <code><fuseaction></code> verb, the following steps occur: </p> 372 402 <ol> 373 403 <li>Execute any <code>preFuseaction</code> plugins that were declared. </li> 374 <li>If a <code>prefuseaction</code> exists for the specified circuit, execute that .</li>404 <li>If a <code>prefuseaction</code> exists for the specified circuit, execute that (after recursively executing any parent <code>prefuseaction</code> if <code>callsuper="true"</code>).</li> 375 405 <li>Execute the fuseaction: 376 406 <ol> … … 378 408 </ol> 379 409 </li> 380 <li>If a <code>postfuseaction</code> exists for the specified circuit, execute that . </li>410 <li>If a <code>postfuseaction</code> exists for the specified circuit, execute that (and then recursively execute any parent <code>postfuseaction</code> if <code>callsuper="true"</code>). </li> 381 411 <li>Execute any <code>postFuseaction</code> plugins that were declared.</li> 382 412 <li>If any exceptions occurred and remain uncaught: … … 386 416 </li> 387 417 </ol> 388 <h 4>How the framework works</h4>389 <p>Fusebox 5 uses components to represent various parts of a Fusebox application: verbs, fuseactions, circuits, plugins, classes and even the application itself. The data from the XML files is used to initialize these components and then the <code>parsed/</code> files are generated by calling a <code>compile()</code> method on those components. Each component knows how to "compile" itself, how to generate ColdFusion code based on the data with which it was initialized. Apart from the <code><do></code> and <code><fuseaction></code> verbs, which are handled directly within the framework, all of the other built-in verbs are implemented as part of a custom lexicon (with a "special" name). A regular verb is "compiled" simply by including its implementation file, executing the ColdFusion code which uses functions such as <code>fb_appendLine()</code> to write to the <code>parsed/</code> file. </p>418 <h2>How the framework works</h2> 419 <p>Fusebox 5 uses components to represent various parts of a Fusebox application: verbs, fuseactions, circuits, plugins, classes and even the application itself. The data from the XML files is used to initialize these components and then the <code>parsed/</code> files are generated by calling a <code>compile()</code> method on those components. Each component knows how to "compile" itself, i.e., how to generate ColdFusion code based on the data with which it was initialized. Apart from the <code><do></code> and <code><fuseaction></code> verbs, which are handled directly within the framework, all of the other built-in verbs are implemented as part of a custom lexicon (with a "special" name). A regular verb is "compiled" simply by including its implementation file, executing the ColdFusion code which uses functions such as <code>fb_appendLine()</code> to write to the <code>parsed/</code> file. </p> 390 420 <p>Here is an overview of the components that make up the core:</p> 391 421 <ul> 392 <li><code>fuseboxAction</code> - This represents a fuseaction: compiling a fuseaction simply compiles its children (the verbs inside the fuseaction). In addition, a fuseaction has access, permissionsand custom attributes. </li>393 <li><code>fuseboxApplication</code> - This represents an application (and was the plain <code>application.fusebox</code> structure in Fusebox 4.1). An application knows how to compile a request (i.e., the requested fuseaction) as well as how to compile an arbitrary fuseaction (i.e., <em>anycircuit</em>.<em>anyaction</em>). An application also hascustom attributes. </li>394 <li><code>fuseboxCircuit</code> - This represents a circuit. A circuit knows how to compile a fuseaction within that circuit and hascustom attributes..</li>422 <li><code>fuseboxAction</code> - This represents a fuseaction: compiling a fuseaction simply compiles its children (the verbs inside the fuseaction). In addition, a fuseaction has <code>access</code>, <code>permissions</code> and custom attributes. </li> 423 <li><code>fuseboxApplication</code> - This represents an application (and was the plain <code>application.fusebox</code> structure in Fusebox 4.1). An application knows how to compile a request (i.e., the requested fuseaction) as well as how to compile an arbitrary fuseaction (i.e., <em>anycircuit</em>.<em>anyaction</em>). An application may also have custom attributes. </li> 424 <li><code>fuseboxCircuit</code> - This represents a circuit. A circuit knows how to compile a fuseaction within that circuit and may have custom attributes..</li> 395 425 <li><code>fuseboxClassDefinition</code> - This represents a class declaration. Class declarations can have custom attributes. </li> 396 <li><code>fuseboxDoFuseaction</code> - This represents the basic <code><do></code> verb and the <code><fuseaction></code> verb (fora global fuseaction). Compiling a <code><do></code> (or <code><fuseaction></code>) verb also compiles any <code>preFuseaction</code>, <code>postFuseaction</code> and <code>fuseactionException</code> plugin points. </li>426 <li><code>fuseboxDoFuseaction</code> - This represents the <code><do></code> and <code><fuseaction></code> verbs (the latter is used in a global fuseaction). Compiling a <code><do></code> (or <code><fuseaction></code>) verb also compiles any <code>preFuseaction</code>, <code>postFuseaction</code> and <code>fuseactionException</code> plugin points. </li> 397 427 <li><code>fuseboxFactory</code> - This component creates all of the verb objects. It knows how to create a <code><do></code> / <code><fuseaction></code> object or a lexicon object for all other verbs. </li> 398 428 <li><code>fuseboxLexiconCompiler</code> - This provides the dynamic context for compiling a verb, including the <code>fb_*</code> functions that allow verbs to write to the parsed file. </li> … … 403 433 </ul> 404 434 <p>For more detailed information about each component, you can look at the <a href="http://corfield.org/cfcdoc/" target="_blank">raw CFC documentation for Fusebox 5</a>.</p> 405 <h 2><a name="compatibility"></a>Compatibility</h2>435 <h1><a name="compatibility"></a>Compatibility</h1> 406 436 <p>The goal of Fusebox 5 is that all Fusebox 4.1 applications and almost all Fusebox 4.0 should run unchanged with the new core files. Most plugins written for Fusebox 4.x should run identically on Fusebox 5. However, there are some compatibility issues that you may need to be aware of:</p> 407 437 <ol> … … 433 463 <li>The <code><class></code> declaration no longer requires the <code>type</code> attribute. If you omit it, it defaults to <code>"component"</code>. </li> 434 464 <li><code>fusebox.init.cfm</code> is executed before <code>attributes.fuseaction</code> is defaulted in Fusebox 4.1 but after in Fusebox 5. Some magic happens to ensure this does not affect any processing done by <code>fusebox.init.cfm</code> but it means that, going forward, <code>fusebox.init.cfm</code> can (and should) rely on the presence of <code>attributes.fuseaction</code>, which was not true in Fusebox 4.1. </li> 435 <li>Fusebox 5 reserves the structure <code>request.__fusebox</code> for certain purposes during compilation and runtime. This structure should not be modified . </li>465 <li>Fusebox 5 reserves the structure <code>request.__fusebox</code> for certain purposes during compilation and runtime. This structure should not be modified nor relied on in any manner. </li> 436 466 </ol> 437 467 <p>This list will be updated with any known compatibility issues that are uncovered. </p>
