Objectives

This unit covers the fundamental building blocks of any FarCry application: the Content Type. By the end of this unit you should be able to create and deploy your own content types.

Super Hero Handbook

In a bid to test the theory that FarCry is indeed a framework, we're building the Super Hero Handbook application. It's a somewhat frivolous application that has the benefit of not tying us down to a specific set of functionality. Plus it should be a lot of fun.

We can invent things as we need them to showcase aspects of the technology without being constrained by the more traditional, user focused goals of a typical application. It also has the potential of being a lot more complex than your average "build a blog in 10 minutes" exercise which appears to be the benchmark for determining the viability of many frameworks.

FarCry is accused of being an extensible, cutting edge, content management system (CMS). Ok so that's true. But the CMS functionality is actually built on the FarCry Framework. It's a framework that just happens to be suitable for building many other sorts of web based applications. In fact, we're firm believers that content management is really a commodity service that just about every application needs, so its great to be able to build an application that has immediate access to such rich CMS tools.

Content Types

The central building block of the farcry framework is the content type. Think of a content type as the definition of a table in a relational database as this is exactly what they are.

A content type is defined by a ColdFusion component (CFC), and depending on its complexity a variety of auxiliary files. A content type can be just about any sort of persistent data; for example, a news item, product, log table, transaction record, user profile and so on. For example, the pages currently on your site are stored in the content type called dmHTML.

More about the mechanics of content types later - for now we need to think about the basic content types that constitute the Super Hero Handbook, what "content objects" will model the data we have in our application and how they fit together. Lets start relatively simple, and evolve from there.

The Super Hero

We need a central profile to capture our catalogue of super powered beings, their properties and relationships.

The Super Power

Super powers are generally not unique (with some exceptions). It would be nice to have a library of super powers we can assign to super heroes as we add them to the system.

The Super Group

We're not talking ABBA here. The super group is a league or association of super heroes; for example, the Sovereign 7, Fantastic Four, and the League of Justice. A super hero could potentially belong to several groups over their lifetime.

Building a Content Type

The FarCry content type is a central building block for the FarCry Framework. Developers can extend and change the behaviour of existing content types, create their own content types and group related content types into libraries.

We start by creating a content type component and defining the properties that exist for the content objects it manages. Content types are saved in your projects ./packages/types sub-directory.

<!--- ./packages/types/superHero.cfc --->
<cfcomponent name="superHero" extends="farcry.core.packages.types.types" output="false" displayname="Super Hero">

	<cfproperty
		name="title" type="string" default="" hint="Super hero title." />
	<cfproperty
		name="secretHideout" type="string" hint="The secret hideout location of the super hero" />
	<cfproperty
		name="teaser" type="longchar" default="" hint="Mini intro for super hero biography." />
	<cfproperty
		name="biography" type="longchar" default="" hint="Super hero biography." />
	<cfproperty
		name="imgHero" type="string" hint="The image of the hero" />

</cfcomponent>

Hooking Into the Framework

The component must extend FarCry's core abstract class "types" in order to engage with the FarCry Framework. This abstract class provides both additional system properties and methods necessary for the content type to work within the framework.

Advanced developers might find it useful to build their own abstract classes for collections of content types. However, the component must ultimately extend "types" in order to work.

Content Object API (COAPI)

The cfproperty tag doesn't really do a great deal other than define meta data for the component in ColdFusion. FarCry leverages this fact to allow developers to define the default behaviour of the component within the framework.
In the superHero.cfc example we're using the cfproperty tags to define the name and FarCry data type for each property of our Super Hero content type.

Next we use the FarCry type deployment interface to build a data persistence model for the content items or records associated with the component.

FarCry detects that a component exists but hasn't got a corresponding persistence model in the database - the "deploy" options creates all the tables required for this content type. The columns are mapped to their relevant data types, depending on the FarCry data type nominated and the specific relational database you are using.

The integrated FarCry ORM differs from other frameworks that might ordinarily rely on the database schema for metadata, for example Reactor and Transfer. Typically these frameworks will generate components to manage interactions with the database. In contrast, FarCry generates a data schema to manage the data represented by its components.

FarCry relies on the component to define the required data model definition and has tools to keep the database model in sync with changes to the component property set. Not only will the framework deploy tables it will also alter columns and data-types to match changes in the underlying component as required. The COAPI is even clever enough to set precision on table columns and build indices for better performance.

All properties in the component map to a specific column in the content type table, with the exception of array properties (discussed later on).

types is an abstract class that contains a number of system attributes/properties that are inherited by any custom content type.

Walkthrough: Creating Super Hero

We'll kick off our sample application by creating a content type for the Super Hero.

  1. Create a new file called superHero.cfc and save this into your project's ./packages/types directory.
  2. Copy the following code into this file, save and review with the instructor
    <cfcomponent name="superHero" extends="farcry.core.packages.types.types" output="false" displayname="Super Hero">
    
    	<cfproperty
    		name="title" type="string" default="" hint="Super hero title." />
    	<cfproperty
    		name="secretHideout" type="string" hint="The secret hideout location of the super hero" />
    	<cfproperty
    		name="teaser" type="longchar" default="" hint="Mini intro for super hero biography." />
    	<cfproperty
    		name="biography" type="longchar" default="" hint="Super hero biography." />
    	<cfproperty
    		name="imgHero" type="string" hint="The image of the hero" />
    
    </cfcomponent>
    
  3. Go to the FarCry Webtop and deploy the content type: ADMIN > Developer Utilities > COAPI Tools > Types
  4. Locate your new content type, "superHero" and select DEPLOY.
  5. Click on the [Scaffold] button now to create an Administration scaffold
  6. Select the checkbox next to "Create type admin interface",
    1. put in a title for your administration list
    2. select label and imgHero as the fields to appear in your list

      The Scaffold option for deployed content types generates some sample code you can use to get started right away.
      "Create type admin interface" creates a small XML file that generates a menu item for you in the FarCry webtop.
      The framework provides a default edit handler and display view so no need to add anything else here just yet.

  7. Reload your Application. This time you will need to update the [Webtop] option
  8. Go to the Custom Content Tab. Locate your Super Hero admin and create some Heroes (or Villains!)

    When you created your first superHero object you may have noticed a rudimentary edit handler allowing you to key in details, save and update. That's not actually part of the scaffold code that was generated at all. The edit handler is dynamically generated at run time based on the metadata associated with the superHero component's cfproperty tags. Ok. So its pretty minimalist now but wait.. it's only the beginning.

    Make sure you understand the concept of extends, displayname and property type before the instructor starts babbling on about something else.

Formtools

Formtools is essentially a library of clever UI controls that react dynamically to the metadata encapsulated in your content type definition.

There's an extensive number of configuration options for every UI control. You can bypass FarCry's automated layout engine and hand code your forms using the controls if required. You can also override the behaviour of the default controls or create your own controls entirely.

So without going into the detail behind how formtools works - what's in it for the FarCry developer? Well most of the time you will never have to build an administration interface for your content types. Seriously.

Next we will extend our simple superHero content type to leverage these "formtool" features. We're focusing on a selection of the individual property tags in superHero.cfc for the sake of brevity so be sure to fill in the gaps.

Check out the code sample on this page, and pay particular attention to the attributes starting with "ft".

<cfcomponent name="superHero" extends="farcry.core.packages.types.types" output="false" displayname="Super Hero">

	<cfproperty
		name="title" type="string" default="" hint="Super hero title."
		ftSeq="1" ftFieldset="General Details" ftLabel="Title" />
	<cfproperty
		name="secretHideout" type="string" hint="The secret hideout location of the super hero"
		ftSeq="2" ftFieldset="General Details" ftLabel="Secret Hideout" />
	<cfproperty
		name="teaser" type="longchar" default="" hint="Mini intro for super hero biography."
		ftSeq="3" ftFieldset="General Details" ftLabel="Teaser" />
	<cfproperty
		name="biography" type="longchar" default="" hint="Super hero biography."
		ftSeq="4" ftFieldset="General Details" ftLabel="Biography"
		ftType="richtext" />
	<cfproperty
		name="imgHero" type="string" hint="The source image to upload"
		ftSeq="10" ftFieldset="Imagery" ftLabel="Hero Image"
		ftType="image" ftDestination="/images/superHero/imgHero" ftImageWidth="120" ftImageHeight="120" ftAutoGenerateType="fitInside" />
</cfcomponent>

Form Layout

By modifying the ftSeq and ftFieldset attributes we can order form fields and group them into specific field sets. Every field sharing the same fieldset value will appear in a correctly formatted field grouping in the edit handler.

If you are feeling really adventurous you could add ftHelpTitle and ftHelpSection to the very first cfproperty of each fieldset and you'll get a nicely formatted inline help message allowing you to describe what the fieldset is all about.

Form UI Controls

There are several ft attributes that are common across all formtools, such as ftLabel which provides a text label for the form field.

General Formtool Property Options

Attribute

Description

Value

ftType

Type of form control

Defaults to the type value

ftLabel

Text label for the form element

Defaults to property name if absent

ftShowLabel

Flag to show/hide text label for the form element

Defaults to true

ftSeq

Numeric value for form field display order

No default value

ftFieldset

Text used as a title to group a set of fields

No default value

ftWizardStep

Allows you to create multi-step forms; set to the title of the step as you would ftFieldset

No default value

ftStyle

Inline style to apply to form element

No default value

ftClass

Class to apply to form element

No default value

ftDisplayOnly

Boolean that prevents the field from being editable

Defaults to false

ftDefault

Default form field value

No default value

ftDefaultType

The type of default value: "value", "expression" or "evaluate"

Defaults to "value"

ftHelpTitle

Title of a fieldset-related inline help section; only works on the first property in a fieldset

No default value

ftHelpSection

Section text for inline help related to fieldset; only works on the first property in a fieldset

No default value

ftValidation

A comma-separated list of validation requirements

No default value

ftHint

A small inline hint that appears below the field to assist users

No default value

Formtool Validation

Client side validation options reflect the move to jquery/jqueryui as the standard UI for the webtop

ftValidation with a comma separated list of validation requirements.

ftType: Specialised Form Controls

The specific type of UI control is determined by the ftType attribute. If you specify nothing it defaults to the same value as the type attribute, that is the underlying data type. On the other hand if you nominate something more exciting like ftType="richtext" formtools will automatically load all the relevant JavaScript libraries to render the tinyMCE rich text editor to capture input for your property.

<cfproperty
	name="Body" type="longchar" hint="Main body of content." required="no" default=""
	ftSeq="12" ftFieldset="Body" ftWizardStep="Body" ftLabel="Body"
	ftType="richtext"
	ftImageArrayField="aMedia" ftImageTypename="dmImage" ftImageField="StandardImage"
	ftTemplateTypeList="dmImage,dmFile" ftTemplateWebskinPrefixList="insertHTML"
	ftTemplateSnippetWebskinPrefix="insertSnippet" />
<cfproperty
	name="aMedia" type="array" hint="" required="no" default=""
	ftSeq="13" ftFieldset="Relationships" ftWizardStep="Body" ftLabel="Associated Media"
	ftJoin="dmImage,dmFile" bSyncStatus="true" />

It won't surprise you to learn that the ftType attribute options begin to describe a whole library form controls that you can leverage to do your bidding including:

A complete compendium of formtool controls can be found on the FarCry Developer WIKI at:

Anatomy of a Formtool

Each ftType corresponds to a specific formtool component that comprises of at least an edit, display and validation method.
The edit method defines the relevant form element, any additional semantic markup that might be relevant (such as a label) and any associated JavaScript or UI cleverness needed to render the control.

Standard formtool methods:

Best of all if you don't like the core library of widgets then you can always make your own. The core formtools can be overridden, and/or supplemented with brand new controls by deploying them through both plugins and your own project. But lets just stick to the basics for now.

Walkthrough: Using Formtools Metadata

  1. Update your superHero component metadata using the example code above as a guide.

    Every time you update component metadata you will need to reinitialise the application for FarCry to recognise the change. This can be done by adding updateapp=1 to the end of your projects URL or using the [Reload Application] utility in the webtop or the admin "tray" option.

  2. Reload the edit form for your "Super Hero" and make sure things are going according to plan.
  3. Try uploading a few images and discuss with your instructor.

FarCry 6.x leverages the underlying ColdFusion 8 CFIMAGE tools.

Wizards

But what about a multi-step wizard you say? So far the content types have been simple, but what if we have a component with properties up the wazoo or just plain like this wizard caper? Wizards can be defined with simple formtool (aka "ft") metadata as well.

Walkthrough: Formtool Wizards

Lets separate the image upload onto a step of its own.

  1. Open the ./packages/superHero.cfc
  2. Add Wizard Steps using the ftWizardStep formtool metadata
    <!--- ./packages/types/superHero.cfc --->
    <cfcomponent name="superHero" extends="farcry.core.packages.types.types" output="false" displayname="Super Hero">
    
    	<cfproperty
    		name="title" type="string" default="" hint="Super hero title."
    		ftSeq="1" ftFieldset="General Details" ftWizardStep="Teaser Information" ftLabel="Title" ftValidation="required" />
    	<cfproperty
    		name="secretHideout" type="string" hint="The secret hideout location of the super hero"
    		ftSeq="2" ftFieldset="General Details" ftWizardStep="Teaser Information" ftLabel="Secret Hideout" />
    	<cfproperty
    		name="teaser" type="longchar" default="" hint="Mini intro for super hero biography."
    		ftSeq="3" ftFieldset="General Details" ftWizardStep="Teaser Information" ftLabel="Teaser" />
    	<cfproperty
    		name="biography" type="longchar" default="" hint="Super hero biography."
    		ftSeq="4" ftFieldset="General Details" ftWizardStep="Biography Details" ftLabel="Biography"
    		ftType="richtext" />
    	<cfproperty
    		name="imgHero" type="string" hint="The source image to upload"
    		ftSeq="10" ftFieldset="Imagery" ftWizardStep="Imagery" ftLabel="Hero Image"
    		ftType="image" ftDestination="/images/superHero/imgHero" ftImageWidth="120" ftImageHeight="120" ftAutoGenerateType="center" />
    
    </cfcomponent>
    
  3. Make sure that each <cfproperty> has a relevant ftWizardStep entry
  4. Reload the formtool metadata and test that your wizard works.

I think you'll agree that this example is slight overkill for the sake of demonstrating the wizard functionality. However, if you had a content type with 30 fields grouped into 10 fieldsets and maybe even editable by different security levels, wizards come into their own.

Lab: Build A Super Power Content Type

Put into practice everything you've just learnt and build a super power content type. We'll hook this up with the Super Hero later in the course.

  1. Create a new ColdFusion component called ./packages/types/SuperPower.cfc
  2. Create the following properties
  3. Deploy the content type into the database
  4. Use the Scaffold tool in the COAPI area to create an administration page
  5. Add a bunch of super powers to your application (ColdFusion, Flex, Flash, Photoshop, etc. )

Bonus Lab: Image Sourced from Library

You can easily source images from the global image library. If you have some time on your hands, try implementing the an image sourced from the library with custom crops for your local content item.

<cfproperty name="imageSourceID" type="string"
	ftSeq="2" ftFieldset="General Details" ftLabel="Source Image"
	ftType="uuid" ftJoin="dmImage"
	ftHint="Select an image from the image library or create a new image.">

<cfproperty name="imageCarousel" type="string"
	ftSeq="3" ftFieldset="General Details" ftLabel="Carousel Image"
	ftType="image" ftDestination="/images/dmCarouselItem/imageCarousel"
	ftAllowUpload="false" ftSourceField="imageSourceID:SourceImage"
	ftAutoGenerateType="center" ftImageWidth="620" ftImageHeight="200"
	ftQuality="0.8" ftInterpolation="blackman">

<cfproperty name="imageThumbnail" type="string"
	ftSeq="4" ftFieldset="General Details" ftLabel="Thumbnail Image"
	ftType="image" ftDestination="/images/dmCarouselItem/imageThumbnail"
	ftAllowUpload="false" ftSourceField="imageSourceID:SourceImage"
	ftAutoGenerateType="center" ftImageWidth="95" ftImageHeight="30"
	ftQuality="0.8" ftInterpolation="blackman"
	ftHint="">