Skip to content
Sean Corfield edited this page Nov 3, 2013 · 79 revisions

Reference Manual

This page provides a description of all the APIs and components involved in a FW/1 application. Please also read the Roadmap to see how things may change in the future.

FW/1 Controllers

A controller in a FW/1 application does not need to extend any base component.

A controller method is passed a single struct called rc (request context). This structure initially contains all the URL and form scope variables passed into the request. Form scope takes precedence (i.e., when the same key appears in both URL and form scope, the value for that key in the request context is taken from form scope).

A controller communicates data to other parts of a FW/1 application by adding data to rc.

The following public methods are significant in a controller (and are all optional):

  • void before(struct rc) – called at the start of each request to this section
  • void startItem(struct rc) – called next, for section.item
  • void item(struct rc) – called next, for section.item
  • void endItem(struct rc) – called after services have executed, for section.item
  • void after(struct rc) – called at the end of each request to this section before views are rendered.

As of FW/1 2.0, your Application.cfc is also considered a controller and if it defines before() or after() methods, those will be called at the start and end of the controller lifecycle. Unlike other controllers, it does not need an init() method and instead of referring to the FW/1 API methods via variables.fw… you can just use the API methods directly – unqualified – since Application.cfc extends the framework and all those methods are available implicitly.

If the controller needs to invoke FW/1 API methods (see org.corfield.framework below), the controller must have a constructor (a method called init()) that accepts an instance of the FW/1 CFC and saves it for use in other methods. The following is the recommended way to write your controller’s constructor:

<cfscript>
function init(fw) {
  variables.fw = fw;
}
</cfscript>

Within other controller methods, you can then invoke FW/1 API methods using variables.fw.apimethod(args)

A controller is instantiated on the first request to an item in that section and is cached in application scope. You can ask FW/1 to reload the cache at any point (by default, you add ?reload=true to the URL).

As of release 2.0, you can abort processing of controllers and services by calling variables.fw.abortController() which throws an exception that is caught by the framework. Execution of the current controller is immediately aborted and execution continues with setupView(). If your controller code catches and swallows the exception, execution of your controller code will proceed from your catch statement until it returns but at that point the framework will not execute any further controllers or services and execution continues with setupView().

FW/1 Services

A service in a FW/1 application does not need to extend any base component.

A service method is passed a collection of named arguments, based on whatever is in the request context after the controller methods have executed (i.e., after before(), startItem() and item() ). A service method may return a result, which is placed into the request context by FW/1. By default, FW/1 1.x stores the result of the (initial) service method call in rc.data.

A service is instantiated on the first request to an item in that section and is cached in application scope. You can ask FW/1 to reload the cache at any point (by default, you add ?reload=true to the URL).

FW/1 Views

All views execute as included files within the context of a FW/1 request, i.e., inside the current request’s instance of Application.cfc. That means that all methods inside FW/1 and inside your Application.cfc are available directly inside your views. See the public and private API documentation below for what you can and should use of those methods! This means that you can have view helper methods in your Application.cfc, either directly or via an include of a library file.

This process also means that you are mostly free of thread safety issues (because each request automatically has its own context). That said, you need to cognizant of two things when storing data in the variables scope of a view:

  • The variables scope of a view is the variables scope of FW/1 / Application.cfc – so don’t overwrite anything the framework might need!
  • Data stored in variables scope by one view is accessible to other views executed in the same request such as those views rendered by calls to view() in layouts.

You can avoid those concerns by using local scope for any new variables introduced inside the view. This is actually a struct created by the view() method (so it works on all versions of all CFML engines).

Each view has the following two important variables available to it:

  • local – A struct that can be safely used for new variables created by the view. See above.
  • rc – The request context struct. This is the recommended way for views to communicate if they have a need to do so (e.g., setting a page title in a view so that a layout or later view can render it). rc contains whatever data the controller and service(s) have provided, as well as what was originally in the URL and/or form scopes.

The following variables are also available but should not be relied upon as they are implementation details that may change in the future:

  • path – The path to the view (as passed to the view() method).
  • pathInfo – A struct containing the base directory (containing the views/ folder) and the path to the view (below the views/ folder).
  • response – Another local variable that will be overwritten by the output of the rendered view.

Any other variables assigned to by a view (without a scope qualifier – or explicitly with variables scope) are part of the FW/1 instance.

If no matching view file exists for a request, onMissingView() is called and whatever is returned is used as the text of the view, and layouts are applied (unless they are suppressed). The default implementation is to throw an exception but by overriding this method you can create any behavior you want for requests that have no specific view, e.g., you can return a JSON-encoded version of certain data or a default view or pretty much anything you want.

As noted in the Developing Applications Manual, onMissingView() will be called if your application throws an exception and you have not provided a view for the default error handler (main.error – if defaultSection is main). This can lead to exceptions being masked and instead appearing as if you have a missing view!

FW/1 Layouts

Everything that applies to views above also applies to layouts. The variables that are available to layouts are the same as for views with just one addition:

  • body – This contains the rendered views / layouts so far (as the layouts cascade).

Layouts have exactly the same access to the FW/1 API as views and all the same considerations apply.

FW/1 and Bean Factories

FW/1 can be used without a bean factory. It does not depend on ColdSpring or any other sort of object factory. One of the examples that ships with FW/1 uses a simple object factory to manage its CFCs as an example of how FW/1 can leverage a bean factory.

By default, i.e., without a bean factory, FW/1 will create your controller and service CFCs and cache them automatically (in application scope). If you want to access / manage other CFCs, you can do so manually in the init() method of your controller and/or service CFC. Storing references to those other CFCs into the variables scope of your controller and/or service CFC will effectively cache those other CFCs in application scope. When FW/1 is reloaded, the cache is cleared and the controller, service and those other CFCs will all be recreated on demand as new requests come in.

You may choose to leverage a bean factory in order to automate the management of those other CFCs and, if you wish, your controller and service CFCs. FW/1 accepts anything as a bean factory as long as it implements these two methods:

  • public boolean function containsBean( string name ) – returns true if the factory contains that named bean, otherwise false
  • public any getBean( string name ) – returns the named bean

Default Bean Factory

This applies to a top-level FW/1 application, i.e., in the absence of subsystems or for the home application that controls a set of subsystems.

You tell FW/1 about your bean factory by calling the setBeanFactory( factory ) API method, passing in an instance of your bean factory. If you call getBeanFactory(), you’ll get back that same instance – and this is how FW/1 accesses the bean factory internally.

Once FW/1 has been told about a bean factory, it uses it in three situations:

  • When a controller CFC is needed, it will look for sectionController as a bean first, and if that does not exist it will attempt to create the controllers.section CFC (as would be the case when no bean factory is present).
  • When a service CFC is needed, it will look for sectionService as a bean first, and if that does not exist it will attempt to create the services.section CFC (as would be the case when no bean factory is present).
  • When a controller or service CFC instance has been obtained (from the bean factory or by creating it directly), it uses the bean factory to autowire dependencies into the controller or service CFC instance.

Auto Wiring

FW/1 looks at all the public methods of a controller or service CFC for methods that begin with set (aka setters) and if there is a matching bean in the factory, invokes that method passing the bean as an argument. Release 2.0 supports property-based autowiring as well as explicit setters. For example:

If your controller has a public method called setUserManager(), the framework will call containsBean(“UserManager”) on the bean factory and if that returns true, it will call getBean(“UserManager”) on the bean factory to get the bean, and then setUserManager(bean) on controller. With FW/1 2.0, you could omit the setter and use property-based injection instead: declare a property called userManager and specify accessors=“true” on your controller CFC.

Note that FW/1 does not check the arguments on the setters nor the type (or even presence) of the value returned from the bean factory – it’s just follows the conventions and it expects you to follow them too!

Subsystem Bean Factories

If you are using subsystems, you can tell FW/1 about a separate bean factory for each subsystem using the setSubsystemBeanFactory( subsystem, factory ) method. See the UsingSubsystems chapter for details on ways to call this method conveniently to set up your subsystem-specific bean factories.

When you are using subsystems, FW/1 will only look in the subsystem-specific bean factory for sectionController or sectionService beans. This ensures that a subsystem can only ‘see’ the controller and/or service beans that it is expecting and it cannot accidentally be slipped a controller and/or service from another subsystem in the overall application.

Autowiring is handled slightly differently. If a subsystem-specific bean factory is present, autowiring is done using only that bean factory. If no subsystem-specific bean factory is present, autowiring will be done using the default, top-level bean factory if one is present. This allows for FW/1 subsystems to have beans plugged into them by convention when they are used as part of a large application but also ensures that if a subsystem-specific bean factory is present, no unexpected beans will be autowired. This lets you use conventions to locate controllers and services while still relying on a single bean factory for the entire application for autowiring.

One thing to be aware of here is that the complete application also needs to use a subsystem-specific bean factory – there is no parent application as such, just a default subsystem. When you are using subsystems, FW/1 does not look in the default bean factory for controllers or services. This makes sense because the overall application itself relies on a specific subsystem as its default. The default convention is that the overall application is the home subsystem and therefore controllers, services and autowiring will be done against the home bean factory. You can still have a default bean factory but it is a separate bean factory that can be retrieved explicitly using the getDefaultBeanFactory() API method (and will only be used for autowiring if no subsystem-specific bean factory is present).

Parent Bean Factories

A useful pattern with subsystems that use bean factories may be to set the default bean factory as the parent bean factory for all of the subsystem-specific bean factories. This is only possible with a bean factory that supports the concept of a parent, such as ColdSpring. This allows beans to be common across multiple subsystems so that a single instance can be shared, rather than each subsystem having its own instance.

Since parent bean factories are only checked when a child factory does not contain the requested bean, the parent factory cannot override the child factory, but if you are refactoring subsystems as you assemble them, it is an opportunity to remove beans from the subsystem factory configurations and place them in the default, parent factory instead.

This should encourage pluggable subsystems to be created, where the subsystem is not a fully-functional standalone application but instead expects certain beans to be provided by the overall application. For example, a security subsystem could be written that relies on “userManager” and “roleManager” beans, for example, provided by the overall application as a standard way to access user information and permissions.

Request Scope

FW/1 uses the request scope fairly extensively to pass data between parts of the application in order to keep things simple and decoupled (from a developer’s point of view). This section documents all of the request scope variables used by the framework. In general, you should not reference any of these request scope variables: there are supported API methods that you should use instead for the data that you might want to access (and those are documented in the following list).

Request variables:

  • request._fw1 – An opaque structure introduced in version 2.1 to hide most of the internal request scope variables that FW/1 uses.
  • request.action – The action specified in the URL or form (after expansion to the fully qualified form). This can be obtained by calling getFullyQualifiedAction().
  • request.base – The canonical path to the application directory (where the views/ and layouts/ folders are). There is no API method to access this.
  • request.cfcbase – The dot-separated path prefix for the controller and service CFCs. There is no API method to access this.
  • request.context – The request context, the main “data bus” through the application. This is available in controller methods as the argument rc and in the views and layouts as the (local) variable rc. It is also available in lifecycle extension point methods as rc in variables scope.
  • request.event – When an error action is executed, this holds the Application.cfc event in which the exception occurred (it is the argument to the onError() method). An API method may be added in future to access this.
  • request.exception – When an error action is executed, this holds the original exception that occurred (it is the argument to the onError() method). An API method may be added in future to access this.
  • request.failedAction – When an error action is executed, this holds the original action being processed when the exception occurred (it is the argument to the onError() method). If the exception occurred before the point at which the action is determined, request.failedAction will not be defined. An API method may be added in future to access this.
  • request.failedCfcName – If an exception occurs during execution of a controller or service, this holds the name of the failed controller or service CFC. This can be accessed in the error action to provide more details of where the exception occurred. An API method may be added in the future to access this.
  • request.failedMethod – If an exception occurs during execution of a controller or service, this holds the name of the failed method (on the controller or service CFC). This can be accessed in the error action to provide more details of where the exception occurred. An API method may be added in the future to access this.
  • request.item – The item portion of the action. This can be obtained by calling getItem() (with no argument).
  • request.layout – This is a boolean that indicates whether layouts should be rendered. It can be set in a view or layout to prevent any further layouts from being processed. This is the only request scope variable which a developer should be updating directly. An API method may be added in future for this.
  • request.missingView – When onMissingView() is triggered, this hold the name of the view that was not found. An API method may be added in future to access this.
  • request.section – The section portion of the action. This can be obtained by calling getSection() (with no argument).
  • request.subsystem – The subsystem portion of the action, if appropriate. This can be obtained by calling getSubsystem() (with no argument).
  • request.subsystembase – The path from the main application directory to the current subsystem’s directory (where the views/ and layouts/ folders are). This can be obtained by calling getSubsystemBase().

The following request variables have been removed as of version 2.1:

  • request.controllerExecutionComplete – This is present (and true) when the controllers have all been executed in a request. This is used to prevent subsequent calls to the layout() and view() API methods. There is no API method to access this.
  • request.controllers – This holds the sequence of controllers that have been requested. There is no API method to access this (and you shouldn’t touch it!).
  • request.generateSES – If an SES URL was used for the requested action, this is true and causes FW/1 to attempt to generate SES URLs automatically. See also variables.framework.generateSES which overrides this.
  • request.layouts – This holds the cascade of layouts that have been discovered by convention, to be rendered in order (from most specific to site-wide). There is no API method to access this (and you shouldn’t touch it!).
  • request.overrideLayoutAction – This holds the action specified by setLayout() to override the default convention for locating the layouts. There is no API method to access this (and you shouldn’t touch it!).
  • request.overrideViewAction – This holds the action specified by setView() to override the default convention for locating the view and layouts. There is no API method to access this (and you shouldn’t touch it!).
  • request.serviceExecutionComplete – This is present (and true) when the services have all been executed in a request. This is used to prevent subsequent calls to the service() API method. There is no API method to access this.
  • request.services – This holds the sequence of services that have been requested (the initial default service and those added via the service() API call). There is no API method to access this (and you shouldn’t touch it!).
  • request.view – The path to the view (relative to the views/ folder). There is no API method to access this (and you shouldn’t touch it!).

Where there is no API method, there is generally an underlying assumption that a developer should not need access to that data. If it turns out that developers are commonly referring to the underlying request scope variables due to various needs, the addition of API methods might be considered.

org.corfield.framework

This section documents every method in FW/1’s core file. Public methods are listed first, then private methods.

Public API Methods

These methods are callable from outside the framework and are intended to be used with controllers, layouts and views or may be intended to be overridden in you Application.cfc. Technically, methods in FW/1 do not need to be public to be called from within layouts, views or Application.cfc but for the most part, the convention is: if it’s public, it’s documented and guaranteed to remain part of the API; if it’s private, it may be documented (or it may not) and it may be called within layouts, views and Application.cfc but it is not recommended.

public void function abortController()

Attempts to immediately abort execution of the current controller by throwing an exception (which is caught by the framework). If your controller catches this exception, execution will continue until your controller returns. No further controller or service methods will be called. Execution will continue with the setupView() lifecycle method and views and layouts will then be rendered. Added in 2.0.

public boolean function actionSpecifiesSubsystem( string action )

Returns true if the application is using subsystems and the action contains a colon : (default – framework.subsystemDelimiter). Returns false if the application is not using subsystems or the action does not contain a colon : (default – framework.subsystemDelimiter).

public string function buildURL( string action = ‘.’, string path = see below, any queryString = ’’ )

Used in views and layouts to generate links to FW/1 actions. Produces “traditional” links if variables.framework.generateSES is false and the current request used a “traditional” URL. Produces “SES” links if variables.framework.generateSES is true or the current request used an “SESURL. The optional path argument allows you to override the default base URL used for links in the same way that redirect() allows below. Note that specifying path will disable generation of “SES” links! As of FW/1 2.0, path will default to the result of calling getBaseURL() which in turn defaults to variables.framework.baseURL, unless overridden by a subsystem-specific configuration.

The optional queryString argument allows to specify URL variables (and values) that should be added to the generated URL. In general, variable / value pairs should be specified with an equals = and separated with an ampersand & and they will be appended either as-is, for “traditional” link generation, or converted to “SES” format as appropriate. The “SES” conversion can be overridden by preceding a sequence of variable / value pairs with ? in which case such arguments will be appended as-is for both forms of generated link. Finally, an HTML anchor may be specified, preceded by # and that will be appended to the final URL.

As a shortcut, the action may include the queryString value, separated by ? like this: ‘section.item?arg=val’ (with all the same considerations for embedded & and ? and # characters).

As of release 2.0:

  • queryString also accepts a structure, which is converted to an HTML escaped query string.
  • action can be ‘.’, in which case a link to the current section and item is returned.

Here are some examples:

buildURL( 'product.list' )

Will generate:

  • /index.cfm?action=product.list – in “traditional” mode
  • /index.cfm/product/list – in “SES” mode
  • /product/list – in “SES” mode with SESOmitIndex set to true
buildURL( action = 'product.detail', queryString = 'id=42?img=large##overview' )

Will generate:

  • /index.cfm?action=product.detail&id=42&img=large#overview – in “traditional” mode
  • /index.cfm/product/detail/id/42?img=large#overview – in “SES” mode
  • /product/detail/id/42?img=large#overview – in “SES” mode with SESOmitIndex set to true
buildURL( 'product.detail?id=42?img=large##overview' )

Will also generate:

  • /index.cfm?action=product.detail&id=42&img=large#overview – in “traditional” mode
  • /index.cfm/product/detail/id/42?img=large#overview – in “SES” mode
  • /product/detail/id/42?img=large#overview – in “SES” mode with SESOmitIndex set to true

As of release 2.0:

buildURL( '.list' )

Will generate a URL based on the current section – a section-relative link to the current section’s list item.

buildURL( action = 'product.detail', queryString = { id = 76, img = 'small' } )

Will generate:

  • /index.cfm?action=product.detail&id=76&img=small – in “traditional” mode
  • /index.cfm/product/detail/id/76/img/small – in “SES” mode
  • /product/detail/id/76/img/small – in “SES” mode with SESOmitIndex set to true

public void function controller( string action )

Call this from your Application.cfc methods to add to the queue of controllers that will be called by the framework. The action is used to identify the controller that should be called, e.g., “app1:section.item”, “section.item” or “section” (which will call the default item with that section).

A typical example is to trigger a security controller method invoked from setupRequest(), e.g.,

controller( 'security.checkAuthorization' );

You may only queue up additional controller prior to the start of controller execution (in onRequest()). If you attempt to queue up additional controllers in controller methods (or later in the request), you will get an exception because at that point all controllers have been queued up and/or executed.

Just like the implicit controller invocation, before(), startItem(), item(), endtItem() and after() are all invoked appropriately if present. If multiple methods are queued up from a single controller, before() and after() are executed just once (for each controller).

public string customizeViewOrLayoutPath( struct pathInfo, string type, string fullPath )

By default, this simply returns fullPath.

It can be overridden to provide customized handling of view and layout locations. Everywhere that FW/1 needs to figure out the location of a view or layout based on conventions, it calls this method. See the skinning example in the FW/1 distribution that shows how this method can be used to provide automatic overrides of the default conventions.

The arguments are as follows:

  • pathInfo – This struct contains two keys: base which is the application-relative path to the location of the (default) views and layouts folders; path which is the relative path below those folders. For example, for a request of “sub:section.item”, this structure will contain: base=“sub/”, path=“section/item”. The base will have already been adjusted to wherever the views / layouts are supposed to be if you have framework.base set.
  • type – Either “view” or “layout”.
  • fullPath – The default location of the view or layout: “#pathInfo.base##type#s/#pathInfo.path#.cfm”. For the example above, this would be “sub/views/section/item.cfm” for a view.

Additional documentation will be provided for this feature in due course. Probably an entire section on skinning applications with FW/1.

public string function getAction()

Returns the name of the action variable in the URL or form post (variables.framework.action).

public string function getBaseURL()

Returns the configured variables.framework.baseURL value. Can be overridden in Application.cfc to provide a customized value, e.g., per request. Added in FW/1 2.0.

public any function getBeanFactory( string subsystem = "" )

Returns whatever the framework has been told is a bean factory. If you are using subsystems, this will return a subsystem-specific bean factory if one exists for the specified subsystem, or for the subsystem of the current request if no subsystem is specified in the call. Otherwise it will return the default bean factory.

More specifically, if you are not using subsystems:

  • getBeanFactory() – returns the bean factory for the application.
  • getBeanFactory(subsystem)subsystem is ignored and this returns the bean factory for the application.
    If you are using subsystems:
  • getBeanFactory() – returns the subsystem bean factory for the subsystem of the current request if one exists, otherwise the default bean factory for the application.
  • getBeanFactory(subsystem) – returns the subsystem bean factory for the named subsystem if one exists, otherwise the default bean factory for the application.

If no application bean factory can be found, this will throw an exception. Use hasBeanFactory() and/or hasSubsystemBeanFactory( subsystem ) to determine whether this call will successfully return a bean factory.

public struct function getConfig()

Returns a copy of the framework structure containing the configuration settings specified in Application.cfc. This allows controllers to inspect the FW/1 configuration settings if necessary.

public any function getDefaultBeanFactory()

Returns whatever the framework has been told is a bean factory. This will return the default, top-level bean factory for the application. If no such bean factory exists, this will throw an exception. Use hasDefaultBeanFactory() to determine whether the default, top-level bean factory exists for the application.

public string function getDefaultSubsystem()

If the application is not using subsystems, this returns an empty string. If the current request’s action specifies a subsystem, return that. Otherwise return the default subsystem configured for the application.

If the application is using subsystems and the current request’s action does not specify a subsystem and there is no default subsystem configured, this will throw an exception.

public string function getEnvironment()

Returns an empty string by default. If you want to use the Environment Control feature, you should override this in Application.cfc and have it return the “tier” or “tier-server” string. See Environment Control in the Developing Applications Manual for more detail. Added in 2.1

public string function getFullyQualifiedAction( string action = request.action )

If the application is not using subsystems, this behaves the same as getSectionAndItem( action ).

If the application is using subsystems, this returns the specified action formatted as subsystem:section.item.

public string function getHostname()

Returns the server’s local hostname (via Java’s InetAddress class). Intended to be used with Environment Control. Added in 2.1

public string function getItem( string action = request.action )

Returns the item portion of the specified action – or of the current request’s action if no action is specified. Returns the default item if no item is present in the specified action.

public string function getSection( string action = request.action )

Returns the section portion of the specified action – or of the current request’s action if no action is specified. Returns the default section if no section is present in the specified action.

public string function getSectionAndItem( string action = request.action )

Returns the specified action formatted as section.item. Automatically strips the subsystem from the action, if present. Automatically adds the default section if not present. Automatically adds the default item if not present.

public string function getServiceKey( string action )

Returns the request context key to be used for the default service call’s result – if suppressImplicitService is false. This returns “data”. You can override this in Application.cfc to customize how that default service call behaves (i.e., where that result is stored). For example, you might return getSection( action ) so that service calls in the user section of the site are stored in rc.user and service calls in the product section of the site are stored in rc.product.

public string function getSubsystem( string action = request.action )

Returns the subsystem portion of the specified action – or of the current request’s action if no action is specified. Returns the default subsystem if no subsystem is present in the specified action. If the application is not using subsystems, this returns the default subsystem name (which is an empty string by default).

public string function getSubsystemBase()

Returns the path to the folder where the current request’s subsystem views/ and layouts/ subfolders can be found. This can be useful for customer versions of buildURL() etc. Added in version 2.1

public any function getSubsystemBeanFactory( string subsystem )

Returns whatever the framework has been told is a bean factory. This will return the bean factory for the named subsystem. If no such bean factory exists, this will throw an exception. Use hasSubsystemBeanFactory( subsystem ) to determine whether a bean factory exists for the named subsystem. If this is the first reference to this subsystem, the subsystem will be initialized.

public struct function getSubsystemConfig( string subsystem )

Returns the configuration for the named subsystem, as a copy of variables.framework.subsystems[subsystem]. If no configuration exists for the named subsystem, an empty struct is returned. FW/1 uses this to retrieve the per-subsystem baseURL value, if any, as part of buildURL() and redirect(). Added in FW/1 2.0.

public boolean function hasBeanFactory()

Returns true if a default, top-level bean factory exists. If using subsystems, returns true if a bean factory exists for the subsystem of the current request. Otherwise returns false. If hasBeanFactory() returns true, calling getBeanFactory() will return a bean factory.

public boolean function hasDefaultBeanFactory()

Returns true if a default, top-level bean factory exists. Otherwise returns false. If hasDefaultBeanFactory() returns true, calling getDefaultBeanFactory() will return a bean factory.

public boolean function hasSubsystemBeanFactory( string subsystem )

Returns true if a bean factory exists for the named subsystem. Otherwise returns false. If hasSubsystemBeanFactory( subsystem ) returns true, calling getBeanFactory( subsystem ) and getSubsystemBeanFactory( subsystem ) will both return a bean factory (for the named subsystem).

public string function layout( string path, string body )

This function renders a layout and could be called inside a view or a layout, although it is recommended to rely on the conventions for layouts where possible. If you decide you need to render a layout directly, you can invoke it like this:

writeOutput( layout( 'main/nav-template', nav_menu ) );

Rendering views, using the view() method, is supported, documented and the recommended way to build composite pages. Layouts should simply wrap views, in a cascade from item to section to site.

public function onApplicationStart()

Part of the standard CFML lifecycle, this method is called automatically by the CFML engine at application startup. You should not override this (even tho’ it is public). Use setupApplication() to perform application-specific initialization.

If you override this method, you must call super.onApplicationStart().

public function onError( any exception, string event )

The standard CFML error handler, this method is called automatically by the CFML engine in the event of an uncaught exception. By default, FW/1 will try to execute the action specified by variables.framework.error. The action that caused the exception, if known, will be available in request.failedAction. The exception and event are available as request.exception and request.event respectively. If the error action fails, FW/1 tries to display the original exception and event in a simple error view (using the failure() method in the private API below).

You may override this method in Application.cfc if you wish to provide different error handling behavior. You may call super.onError( exception, event ) if appropriate. You may also consider overriding the failure() method.

public string function onMissingView( struct rc )

Called when a view is not found for a request. The default behavior is to call viewNotFound() which throws an exception.

You may override this method to provide alternative behavior when a view is not found. You should either throw an exception or return a string that represents the view that should be rendered instead. For example:

function onMissingView( rc ) {
  return view( 'page/notFound' );
}

public void function onPopulateError( any cfc, string property, struct rc )

Called when a exception occurs during an attempt to populate the named property of the specified cfc if no keys were specified for populate() and those keys were trusted. This method does nothing, effectively causing the exception to be ignored.

If you intend to call populate() with no keys specified and you tell it to trust what it finds in the request context, you may wish to override onPopulateError() and do something like log such failed attempts. See populate() below.

public function onRequest( string targetPage )

Part of the standard CFML lifecycle, this method is called automatically by the CFML engine to handle each request. You should not override this (even tho’ it is public).

If you override this method, you must call super.onRequest( targetPage ).

public function onRequestStart( string targetPage )

Part of the standard CFML lifecycle, this method is called automatically by the CFML engine at the beginning of each request. You should not override this (even tho’ it is public). Use setupRequest() to perform request-specific initialization.

If you override this method, you must call super.onRequestStart( targetPage ).

public function onSessionStart()

Part of the standard CFML lifecycle, this method is called automatically by the CFML engine when each new session is created. You should not override this (even tho’ it is public). Use setupSession() to perform session-specific initialization.

If you override this method, you must call super.onSessionStart().

public any function populate( any cfc, string keys = "", boolean trustKeys = false, boolean trim = false )

Automatically populates an object with data from the request context. For any public method setKey() on the object, if rc.key exists, call the method with that value. If the optional list of keys is provided, only attempt to call setters for the specified keys in the request context. Mainly useful for populating beans from form posts. Whitespace is permitted in the list of keys for clarity, e.g., “firstname, lastname, email”. This approach relies on setter methods in the object. It won’t detect and use onMissingMethod(). In FW/1 1.x, it won’t detect property-based setter methods. FW/1 2.0 does detect property-based setters.

As of 1.2, you can specify trim = true and FW/1 will call trim() on each item before calling the setter. In 1.1 and earlier, the trim argument was not present.

For populate() to work with onMissingMethod() (or property-based setters in FW/1 1.x), you need to specify trustKeys = true. If you specify the list of keys, populate() will not test whether the setter exists, it will just call it – which means that onMissingMethod() and property-based setters will be invoked automatically. If you omit the keys, be careful because populate() will cycle through the entire request context and attempt to set properties on the object for everything! A try/catch is used to suppress any exceptions in this case but you need to be aware that this may be a little dangerous if you have a lot of data in your request context that does not match the properties of the object! If an exception is caught, onPopulateError() is called with the object, property name and the request context structure as its three arguments. The default behavior is to simply ignore the exception but you can override that if you want – see onPopulateError() above.

As of 1.2, populate() returns the cfc passed in. In 1.1 and earlier, the return type was void.

Populating Child Objects (Added In Version 2.1)

If trustKeys = true or if deep = true the populate method will try to populate data on child objects of the cfc argument. In order to populate a child component “dot” notation is used in the request context’s properties. For example, to set the firstName property on a Contact component that is a child of the cfc that is being passed into populate the following key would be added to the request context:

contact.firstname

This would cause populate to traverse the cfc argument like so:

cfc
|-- getContact
|    |-- setFirstName

Child properties can also be nested many levels deep. The following key would populate the line 1 property of an address cfc that is a child of the contact cfc that is a child of the cfc argument passed into the populate method:

contact.address.line1

This would cause populate to traverse the cfc argument like so:

cfc
|-- getContact
|    |-- getAddress
|    |    |-- setLine1

public void function redirect( string action, string preserve = “none”, string append = “none”, string path = see below, string queryString = ‘’, string statusCode = ’302’ )

This constructs a URL based on the action and optional path and redirects to it. If preserve is “all”, the entire contents of the request context are saved to session scope across the redirect (and restored back to the request context automatically after the redirect). If preserve is a list of keys, just those elements of the request context are preserved. If append is “all”, all simple values in the request context are appended to the constructed URL as a query string before the redirect. If append is a list of keys, just those elements of the request context are appended (if they are simple values). statusCode was added in version 2.1.

If path is specified, that base URL is used instead of the default, as per buildURL() above.

The queryString argument may be used to append additional URL variables / values to the constructed URL, as explained in buildURL() above. Or the query string value may be combined with the action also as explained in buildURL() above.

For example:

variables.fw.redirect( action = 'blog.entry', append = 'id', queryString = '##comment' )

Will generate:

  • /index.cfm?action=blog.entry&id={rc.id}#comment – in “traditional” mode
  • /index.cfm/blog/entry/id/{rc.id}#comment – in “SES” mode
  • /blog/entry/id/{rc.id}#comment – in “SES” mode with SESOmitIndex set to true

public void function renderData( string contentType, any resultData )

Call this from your controller to tell FW/1 to skip views and layouts and instead render resultData in the specified contentType format. contentType may be “json”, “xml”, or “text”.

For “json”, FW/1 calls serializeJSON( resultData ) to generate the result of the HTTP request and sets the Content-Type header to application/javascript; charset=utf-8.

For “xml”, the resultData value must be either a valid XML string or an XML object (constructed via CFML’s various xml…() functions). If resultData is an XML object, FW/1 calls toString( resultData ) to generate the result of the HTTP request, otherwise the XML string is used as the result of the request. In both cases, FW/1 sets the Content-Type header to text/xml; charset=utf-8.

For “text”, the resultData value must be a string and that is the result of the HTTP request. FW/1 sets the Content-Type header to text/plain; charset=utf-8.

When you call renderData(), processing continues in your controller (so use return; if you want processing to stop at that point), and subsequent calls to setView() or setLayout() will have no effect (since FW/1 will ignore views and layouts for this request).

Added in FW/1 2.2.

public void function service( string action, string key, struct args = { } )

Call this from your controller to add to the queue of services that will be called by the framework. The action is used to identify the service that should be called, e.g., “app1:section.item”, “section.item” or “section” (which will call the default item with that section). The key specifies which request context variable should receive the result of the service call. If the key is an empty string, the result of the service call, if any, will be ignored. The optional args struct specifies additional values that will be supplied as arguments to the service call without being part of the request context, e.g.,

service( 'product.get', 'product', { id = rc.productid } );

You may only queue up services in the before(), startItem() and item() methods in your controller. If you attempt to queue up services in other controller methods (endtItem() or after()), you will get an exception because at that point all services have been called.

There is an optional fourth argument, enforceExistence, which defaults to true. The intent is that when you explicitly queue up a service call, it should be an error if the named service does not exist. When FW/1 1.x used to queue up the initial convention-based service call, it used service( action, getServiceKey( action ), { }, false ) so that the service was allowed not to exist. If you want to provide optional, pluggable services, you might specify false as a third argument to allow for this.

public void function setBeanFactory( any factory )

Call this from your setupApplication() method to tell the framework about your primary (default) bean factory. Any bean factory will work as long as it implements the following two methods:

  • public boolean function containsBean( string name ) – returns true if the factory contains that named bean, otherwise false
  • public any getBean( string name ) – returns the named bean

public void function setLayout( string action )

Call this to tell the framework to use a new action subsystem:section.item as the basis of the lookup process for the layouts for the current request. This allows you to override the default convention for choosing the layouts. Added in version 2.0.

public void function setSubsystemBeanFactory( string subsystem, any factory )

Call this to tell the framework about a subsystem-specific bean factory. Again, the bean factory must support containsBean( name ) and getBean( name ). You would typically call this method from your setupSubsystem() method.

public void function setupApplication()

Override this in Application.cfc to provide application-specific initialization. If you want the framework to use a bean factory and autowire controllers and services, this is where you should call setBeanFactory( factory ). You do not need to call super.setupApplication().

public void function setupEnvironment( string env )

Override this in Application.cfc to provide environment-specific initialization. See Environment Control in the Developing Applications Manual for more detail. Added in 2.1

public void function setupRequest()

Override this in Application.cfc to provide request-specific initialization. You do not need to call super.setupRequest().

public void function setupResponse()

Override this in Application.cfc to provide request-specific finallization. This is called after all views and layouts have been rendered or immediately before a redirect. You do not need to call super.setupResponse(). Added in FW/1 2.0.

public void function setupSession()

Override this in Application.cfc to provide session-specific initialization. You do not need to call super.setupSession().

public void function setupSubsystem( string subsystem )

Override this in Application.cfc to provide subsystem-specific initialization. If you want the framework to use subsystem-specific bean factories and autowire controllers and services for each subsystem, this is where you should call setSubsystemBeanFactory( subsystem, factory ). See the example in UsingSubsystems for more details. You do not need to call super.setupSubsystem().

public void function setupView()

Override this in Application.cfc to provide pre-rendering logic, e.g., putting globally available data into the request context so it is available to all views. You do not need to call super.setupView(). Added in FW/1 2.0.

public void function setView( string action )

Call this to tell the framework to use a new action subsystem:section.item as the basis of the lookup process for the view and layouts for the current request. This allows you to override the default convention for choosing the view and layouts. A common use for this is expected to be when redisplaying a form view when errors are present.

For example:

  • user.form would display a form to allow a user to be created / edited
  • user.save would be the submit action which does validation and can call setView( ‘user.form’ ) to redisplay the user form with errors or call redirect() to a confirmation page if there are no errors and the user has been saved.

public boolean function usingSubsystems()

Returns true if the application is using subsystems, i.e., variables.framework.usingSubsystems is true. Otherwise returns false.

public string function view( string path, struct args = { }, any missingView = { } )

This renders a view and returns the output of that view as a string. It is intended to be used primarily inside layouts to render fragments of a page such as menus and other common elements. As of 1.2, elements of the args structure are appended to the local scope accessible inside the view file. For example:

<cfoutput>
<div>#view( 'common:site/header' )#</div>
<div>#view( 'nav/menu', { selected = 'home' } )#</div>
<div>#body#</div>
<div>#view( 'common:site/footer' )#</div>
</cfoutput>

This renders the header and footer items (views) from the common subsystem’s site section and the menu item (view) from the current subsystem’s nav section. Inside menu, local.selected would be available containing the string ‘home’.

As of 2.0, a controller may call view() after service execution has completed (i.e., if no services are queued up or from the *end*item controller method).

As of 2.2, missingView was added to the arguments and if not specified, and the specified view does not exist, onMissingView() will be called. If a string is passed as missingView and the specified view does not exist, the value of that argument will be returned. This allows for programmatically calculated views to be silently rendered as empty strings if they are not present. This can be useful for programmatic skins with optional elements.

Private API Methods

These methods are not intended to be called (except in special circumstances detailed under each method), nor should they be overridden in Application.cfc. The private API of FW/1 is generally only loosely documented and is subject to change without notice.

private void function autowire( any cfc, any beanfactory )

This internal method is used by the framework to wire dependencies into controllers and services using the specified bean factory.

This method should not be called, nor overridden. It may be renamed in the future.

private void function buildLayoutQueue()

This internal method is used by the framework to setup the layout queue for the request.

This method should not be called, nor overridden. It may be renamed in the future.

private void function buildViewQueue()

This internal method is used by the framework to setup the view queue for the request.

This method should not be called, nor overridden. It may be renamed in the future.

private string function cfcFilePath( string dottedPath )

This internal method is used by the framework to convert a dot-separated CFC path into a filesystem path.

This method should not be called, nor overridden. It may be renamed in the future.

private void function doController( struct tuple, string method )

This method is used to execute the specified method of a controller CFC instance.

This method should not be called, nor overridden. It may be renamed in the future.

If you want to call methods on a specific controller, such as for a security controller method invoked from setupRequest(), use the controller() method, e.g.,

controller( 'security.checkAuthorization' );

private any function doService( struct tuple, string method, struct args, boolean enforceExistence )

This method is used to execute the specified method of a service CFC instance.

This method should not be called, nor overridden. It may be renamed in the future.

private void function dumpException( any exception )

This is a wrapper for the tag and is used by the failure() method to display an exception. If you want exceptions to be displayed in a nicer format, you could override this method although a cleaner, supported way to handle uncaught exceptions may be provider in the future.

This method should not be called. It may be renamed in the future.

private void function ensureNewFrameworkStructExists()

This was introduced to provide a smooth upgrade path when subsystems were introduced. That upgrade introduced new structures inside FW/1. This method ensures that if you have an earlier version of FW/1 running and you replace the framework CFC, those structures are automatically created in application scope so you don’t get an exception.

At present, this method is actually public but it should not be called, nor overridden. It may become private or be renamed in the future.

private void function failure( any exception, string event )

This is called if an exception occurs and FW/1 is unable to execute the error action successfully. This outputs a simple view of the exception that occurred and includes a stacktrace. The HTTP response status is set to 500 (error) instead of 200 as of version 2.1 If you wish to change the output of an exception, you could override this method in Application.cfc. See also onError() above.

At present, this method is actually public but it should not be called. It may become private in the future.

private void function frameworkTrace( string message, string subsystem = ‘’, string section = ’’, string item = ’’ )

This is called by the framework at various points to trace the lifecycle of a request.

private void frameworkTraceRender()

This is called at the end of the request to render the trace information, if variables.framework.trace is true.

private any function getCachedComponent( string type, string subsystem, string section )

This is the core convention-based creation routine for controllers and services.

This method should not be called, nor overridden. It may be renamed in the future.

private any function getController( string section, string subsystem = getDefaultSystem() )

This returns the controller CFC instance for the specified section (and subsystem, if specified).

This method should not be called, nor overridden. It may be renamed in the future.

private void function getNextPreserveKeyAndPurgeOld()

This internal method is part of the machinery to preserve the request context across redirects.

This method should not be called, nor overridden. It may be renamed in the future.

private string function getPreserveKeySessionKey( string preserveKey )

This internal method is part of the machinery to preserve the request context across redirects.

This method should not be called, nor overridden. It may be renamed in the future.

private any function getService( string section, string subsystem = getDefaultSystem() )

This returns the service CFC instance for the specified section (and subsystem, if specified). Since controllers may call the public, documented service() method to queue up service invocations, this method should never be called.

At present, this method is actually public but it should not be called, nor overridden. It may become private or be renamed in the future.

private string function getSubsystemDirPrefix( string subsystem )

This is an internal utility (that returns a directory prefix for subsystems).

At present, this method is actually public but it should not be called, nor overridden. It may become private or be renamed in the future.

private void function injectFramework( any cfc )

This is called by the framework to inject itself into controllers that are managed by bean factories.

This method should not be called, nor overridden. It may be renamed in the future.

private string function internalLayout( string layoutPath, string body )

This is used to render a layout. It is called by the layout() method and internally by FW/1.

This method should not be called, nor overridden. It may be renamed in the future.

private string function internalView( string viewPath, struct args = { } )

This is used to render a view. It is called by the view() method and internally by FW/1.

This method should not be called, nor overridden. It may be renamed in the future.

private boolean function isFrameworkInitialized()

This returns true if the framework has been initialized. Otherwise it returns false.

At present, this method is actually public but it should not be called, nor overridden. It may become private or be renamed in the future.

private boolean function isFrameworkReloadRequest()

If the framework is configured to reload on every request, this returns true. If the current request includes the URL parameters to reload the framework, this returns true. Otherwise it returns false.

At present, this method is actually public but it should not be called, nor overridden. It may become private or be renamed in the future.

private boolean function isSubsystemInitialized( string subsystem )

If the specified subsystem has been initialized, this returns true. Otherwise it returns false.

At present, this method is actually public but it should not be called, nor overridden. It may become private or be renamed in the future.

private struct function parseViewOrLayoutPath( string path )

This utility method allows the framework to automatically adjust layout and view paths to real paths, whether subsystems are in use or not.

At present, this method is actually public but it should not be called, nor overridden. It may become private or be renamed in the future.

private void function raiseException( string type, string message, string detail = "" )

This is a wrapper for the tag and is used in several places within the framework to throw custom exceptions.

This method should not be called, nor overridden. It may be renamed in the future.

private string renderDataWithContentType()

This is used to set the appropriate Content-Type header and to perform the actual rendering of the data that was provided in an earlier call to renderData().

This method should not be called, nor overridden. It may be renamed in the future.

private void function restoreFlashContext()

This internal method is part of the machinery to preserve the request context across redirects. It restores data from session scope back into the request context.

This method should not be called, nor overridden. It may be renamed in the future.

private string function saveFlashContext( string keys )

This internal method is part of the machinery to preserve the request context across redirects. It saves data from the request context into session scope. If keys is “all”, every element of the request context is saved. If keys is a list of keys, only those elements are saved.

This method should not be called, nor overridden. It may be renamed in the future.

private void function setupApplicationWrapper()

This performs framework-specific initialization when an application starts up or the framework is reloaded. It calls setupApplication() (which you can override).

At present, this method is actually public but it should not be called, nor overridden. It may become private or be renamed in the future.

private void function setupFrameworkDefaults()

This sets up default values for the framework conventions. You define the framework conventions by setting key/value in the variables.frameworks struct in the pseudo-constructor of your Application.cfc. This method fills in defaults for any conventions you did not specify. It also sets the version key in that struct.

At present, this method is actually public but it should not be called, nor overridden. It may become private or be renamed in the future. It is called from a number of places within the framework to ensure that the conventions are setup correctly.

private void function setupRequestWrapper()

This performs framework-specific initialization when a request starts. It calls setupRequest() (which you can override).

At present, this method is actually public but it should not be called, nor overridden. It may become private or be renamed in the future.

private void function setupSessionWrapper()

This performs framework-specific initialization when a new session starts. It calls setupSession() (which you can override).

At present, this method is actually public but it should not be called, nor overridden. It may become private or be renamed in the future.

private void function setupSubsystemWrapper( string subsystem )

This performs framework-specific initialization when a subsystem is initialized. It calls setupSubsystem( string subsystem ) (which you can override).

At present, this method is actually public but it should not be called, nor overridden. It may become private or be renamed in the future.

private void function viewNotFound()

This is a utility method to throw an exception when a view cannot be found. You could override this method to handle a missing view. You could output a view of your choice, for example, with:

writeOutput( view( 'missing/template' ))

At present, this method is actually public but it should not be called. It may become private in the future. A better way to handle missing views may be provided in future.

Clone this wiki locally