Inside the Fusebox framework

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 The request lifecycle below.

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 index.cfm file, typically:

<cfinclude template="/fusebox5/fusebox5.cfm">

That file in turn creates the myFusebox structure and then, if necessary, the application.fusebox structure (or, more correctly, the application[FUSEBOX_APPLICATION_KEY] 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.

The next two sections cover the request lifecycle in more depth and look inside the core framework to explain how everything works.

The request lifecycle

This section explains the detailed steps involved in handling a request inside the Fusebox framework, as well as how a fuseaction itself is handled.

Executing a request

For each request, processed by fusebox5.cfm, the following steps occur:

Create the myFusebox object.

  1. If this is the first request for this application or the application needs to be reloaded (development-full-load mode or the user specified fusebox.load=true) then:

Create the application.fusebox object if necessary (i.e., application[FUSEBOX_APPLICATION_KEY]).

  1. Include and execute fusebox.appinit.cfm if it exists.
  2. Include and execute fusebox.init.cfm if it exists.
  3. Generate the parsed/ file if necessary (either it doesn't exist or we are not in production mode), by calling compileRequest() on the Fusebox application object.

Execute the parsed/ file:

  1. If this is the first request for this application or the application was reloaded (above), execute the <appinit> global fuseaction if it was declared. Note that no plugins execute during this step. Except that no plugins execute, the specified fuseaction behaves per Executing a fuseaction below.
  2. Execute any preProcess plugins that were declared.
  3. Execute the <preprocess> global fuseaction if it was declared. The specified fuseaction behaves per Executing a fuseaction below.
  4. Execute the specified fuseaction per Executing a fuseaction below.
  5. Execute the <postprocess> global fuseaction if it was declared. The specified fuseaction behaves per Executing a fuseaction below.
  6. Execute any postProcess plugins that were declared.

If any exceptions occurred and remain uncaught:

  1. Execute any processError plugins that were declared.

If any fusebox.* exceptions still remain uncaught:

  1. Execute any matching errortemplates/ file.

Executing a fuseaction

Each time a fuseaction is executed, either as the top-level requested fuseaction or via a <do> or <fuseaction> verb, the following steps occur:

  1. Execute any preFuseaction plugins that were declared.
  2. If a prefuseaction exists for the specified circuit, execute that.

Execute the fuseaction:

  1. Execute each of the verbs declared in that fuseaction. Any <do> verbs cause their specified fuseaction to be executed per this same Executing a fuseaction process, recursively.

If a postfuseaction exists for the specified circuit, execute that.

  1. Execute any postFuseaction plugins that were declared.

If any exceptions occurred and remain uncaught:

  1. Execute any fuseactionException plugins that were declared.

How the framework works

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 parsed/ files are generated by calling a compile() 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 <do> and <fuseaction> 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 fb_appendLine() to write to the parsed/ file.

Here is an overview of the components that make up the core:

  • fuseboxAction - This represents a fuseaction: compiling a fuseaction simply compiles its children (the verbs inside the fuseaction). In addition, a fuseaction has access, permissions and custom attributes.
  • fuseboxApplication - This represents an application (and was the plain application.fusebox 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., anycircuit.anyaction). An application also has custom attributes.
  • fuseboxCircuit - This represents a circuit. A circuit knows how to compile a fuseaction within that circuit and has custom attributes..
  • fuseboxClassDefinition - This represents a class declaration. Class declarations can have custom attributes.
  • fuseboxDoFuseaction - This represents the basic <do> verb and the <fuseaction> verb (for a global fuseaction). Compiling a <do> (or <fuseaction>) verb also compiles any preFuseaction, postFuseaction and fuseactionException plugin points.
  • fuseboxFactory - This component creates all of the verb objects. It knows how to create a <do> / <fuseaction> object or a lexicon object for all other verbs.
  • fuseboxLexiconCompiler - This provides the dynamic context for compiling a verb, including the fb_* functions that allow verbs to write to the parsed file.
  • fuseboxPlugin - This represents a plugin declaration and knows how to compile a plugin.
  • fuseboxVerb - This represents a verb from any custom lexicon (including the built-in Fusebox lexicon). Verbs are compiled in the dynamic context of a fuseboxLexiconCompiler object.
  • fuseboxWriter - This manages the creation of the parsed files.
  • myFusebox - This is the per-request data structure (and was a plain struct in Fusebox 4.1).