Skip to content
Sean Corfield edited this page Aug 28, 2014 · 39 revisions

This documentation covers FW/1 2.5 (and earlier, to some extent). See the FW/1 3.0 Documentation for the latest Getting Started Guide (for release 3.0).

Introducing FW/1 – Framework One

Why FW/1? Read the introductory blog post about the framework.

Once you’ve read this Getting Started guide, you’ll want to move on to the Developing Applications Manual and when you need to look things up, use the Reference Manual. You may also want to learn about Using Subsystems which allows FW/1 applications to be combined as modules of a larger FW/1 application.

You probably also want to join the FW/1 mailing list on Google Groups or follow the #FW1 twitter stream; you may also find help and inspiration in the FW/1 Site Showcase, a directory of sites created with FW/1. To read about what’s coming in the future, take a look at the Roadmap.

Requirements / Supported Platforms

  • v2.x supports:
    • ColdFusion 9.0.1 or later
    • Railo 3.2.2 or later (Railo 3.3 or later is recommended)
  • v1.x supports:
    • ColdFusion 8.0.1 / 9.0.
    • Railo 3.1.x
    • OpenBD 1.2 nightly build 11/30 or later! * note: user manager example will not run on OpenBD *

Getting Started

FW/1 consists of a single CFC: org.corfield.framework (will be framework.one in 3.0):

If you check out FW/1 from git, it’s a complete web application. The org folder should be in your webroot (or accessible via a mapping).

Note: do not install FW/1 into a subfolder that contains . in the name as this will prevent CFC resolution from working!

The simplest FW/1 application comprises:

  • Application.cfc which extends org.corfield.framework (will be framework.one in 3.0)
  • Empty index.cfm
  • views folder containing a main subfolder containing default.cfm – your initial application view

Pages are accessed using ?action=section.item in the URL which will display the views/section/item.cfm file. The default action is main.default, as you might have guessed from the simplest FW/1 example above! If you specify just the section name – ?action=section then the item has the default of default, in other words, ?action=section is equivalent to ?action=section.default.

If your application server supports it, so-called SES URLs can be used with FW/1:

  • index.cfm/section – equivalent to ?action=section
  • index.cfm/section/item – equivalent to ?action=section.item
  • index.cfm/section/item/name/value – equivalent to ?action=section.item&name=value

To use name/value pairs in SES URLs, you must specify both the section and item parts of the action. A trailing name with no value is treated as &name= in a normal URL.

Create Application.cfc containing:

component extends="org.corfield.framework" { // will be framework.one in 3.0
}

Create an empty index.cfm file.

Create views/main/default.cfm containing:

Hello FW/1!

When you access the application, it should say Hello FW/1!

Adding a Controller

When you ask for action=section.item FW/1 looks for section.cfc in a controllers folder and, if present, invokes the item() method on it (and then displays the matching view). Since the default action is main.default, here’s what we need to do to add our default controller:

Change views/main/default.cfm to contain:

<cfoutput>Hello #rc.name#!</cfoutput>

Add controllers/main.cfc with a method, default(), that takes a single struct argument called rc (for request context) like this:

component {
    function default( struct rc ) {
        param name="rc.name" default="anonymous";
    }
}

Note that controller CFC names must be all lowercase.

When you access the application now, it should say Hello anonymous! but if you put ?name=Sean on the URL, it should say Hello Sean! The request context passed to the controller contains all the URL and form variables from the browser and is also made available to the view directly.

Controllers are cached. Add ?reload=true to the URL to reload your controllers.

Adding a Layout

When you ask for action=section.item FW/1 looks for layouts/section/item.cfm to find a specific layout (it also knows how to look for default layouts for sections and for applications, I’ll cover that later). The basic view is passed in as a variable called body. Let’s try this for our default action, main.default:

Create layouts/main/default.cfm containing:

<h1>Welcome to FW/1!</h1>
<cfoutput>#body#</cfoutput>

Layout filenames, like view filenames, must be all lowercase.

When you access the application now, it should have Welcome to FW/1! as a heading above the previous output.

Adding a Service

Whilst you can keep adding functionality to your controllers, a well-structured MVC application tries to keep the controllers lightweight and delegate all the business logic to the “Model” of your application. The Model is generally exposed to your controllers through a service layer, including smart objects that represent the problem domain, known as domain objects.

Prior to Release 2.5, FW/1 had conventions for dealing with service CFCs but most users quickly outgrew those conventions and moved on to managing and calling services themselves.

You can manage service CFCs yourself if you want but FW/1 ships with an easy to use “bean factory” that makes it easy to create service CFCs, have them automatically wired into your controllers, and then call their methods directly.

Let’s create a greeting service that we can call from our controller. Create a model folder, with a services subfolder, and inside that we’ll put our greeting.cfc:

component {
    function greet( string name ) {
        return "so-called " & name;
    }
}

Now we’ll update Application.cfc to tell FW/1 to use a bean factory to manage services. Add setupApplication() like this:

    function setupApplication() {
        var bf = new framework.ioc( "model" );
        setBeanFactory( bf );
    }

This creates an instance of framework.ioc (DI/1) and tells it to look in the model folder for CFCs to manage, then it tells FW/1 to use that as the “bean factory”.

The next step is to modify our controller so that any services (or other managed CFCs) will be automatically wired in. We update the component declaration to have accessors like this:

component accessors="true" {
    ...
}

and we add a declaration that the controller depends on the new greeting.cfc:

    property greeting;

These small changes tell FW/1 to use the bean factory (from setupApplication()) to find something called greeting and inject it into the controller. We could have used:

    property greetingService;

since the greeting.cfc is in the services folder but since that’s a convention that is specific to DI/1 we’ll learn about that later.

Finally we’ll update our controller default function to call this newly injected service:

    function default( struct rc ) {
        param name="rc.name" default="anonymous";
        rc.name = variables.greeting.greet( rc.name );
    }

The main.cfc controller should now look like this:

component accessors="true" {
	property greeting;
	function default( struct rc ){
	        param name="rc.name" default="anonymous";
		rc.name = variables.greeting.greet( rc.name ); 
	}
}

Your views/main/default.cfm file should already contain this:

<cfoutput>Hello #rc.name#!</cfoutput>

When you access the application now with ?name=Sean on the URL, it should say Hello so-called Sean!

Next Steps

Read the Developing Applications with FW/1 and Using Subsystems with FW/1 sections below. The Reference Manual is a work in progress.

Developing Applications with FW/1

For an example-based approach to building applications with FW/1, read the Developing Applications Manual.

Using Subsystems with FW/1

FW/1 allows you to combine applications in a modular fashion to create a larger application. This feature was primarily contributed by Ryan Cogswell with documentation by Dutch Rapley. Read about Using Subsystems to combine your FW/1 applications.

Reference Manual

For a detailed description of the framework’s API, read the Reference Manual.