Work in Progress
Updating the course for FarCry 6.x. If you can help let us know! Put your notes in the comments for the page.
Changes should include:
- updated validation options to reflect shift to jquery/jqueryui
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 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.
FarCry 5.x supports mySQL, MS SQL, Postgresql and Oracle.
So in this respect 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.
All properties in the component map to a specific column in the content type table, with the exception of array properties (discussed later on).
Missing: notes on system attributes/properties inherited from types required.
Walkthrough: Creating Super Hero
We'll kick off our sample application by creating a content type for the Super Hero.
- Create a new file called superHero.cfc and save this into your project's ./packages/types directory.
- Copy the following code into this file, save and review with the instructor
<!--- ./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>
- Go to the FarCry Webtop and deploy the content type: ADMIN > Developer Utilities > COAPI Tools > Types
- Locate your new content type, "superHero" and select DEPLOY.
- Click on the [Scaffold] button now to create an Administration scaffold
- Select the checkbox next to "Create type admin interface",
- put in a title for your administration list
- select label and imgHero as the fields to appear in your list
Basic Scaffolding
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.
- Reload your Application. This time you will need to update the [Webtop] option
- Go to the Content Tab. Locate your Super Hero admin and create some Heroes (or Villains!)
Editing Content Types
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.
Wait Up!
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're going to extend our simple superHero example to leverage these new features. I'm 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".
<!--- ./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" 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 he 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.
ftHelpTitle and ftHelpSection
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
The standard formtool library leverages Dexagogo's Really Easy Field Validation, based on the prototype library. The basic method is to attach to the form's onsubmit event, read out all the form elements' classes and perform validation if required. If a field fails validation, reveal field validation advice and prevent the form from submitting.
ftValidation with a comma separated list of validation requirements.
- required (not blank)
- validate-number (a valid number)
- validate-digits (digits only)
- validate-alpha (letters only)
- validate-alphanum (only letters and numbers)
- validate-date (a valid date value)
- validate-email (a valid email address)
- validate-date-au (a date formatted as; dd/mm/yyyy)
- validate-currency-dollar (a valid dollar value)
- validate-selection (first option e.g. 'Select one...' is not selected option)
- validate-one-required (At least one textbox/radio element must be selected in a group)
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="aObjectIDs" ftImageTypename="dmImage" ftImageField="StandardImage" ftTemplateTypeList="dmImage,dmFile,dmNavigation,dmHTML" ftTemplateWebskinPrefixList="insertHTML" ftTemplateSnippetWebskinPrefix="insertSnippet" /> <cfproperty name="aObjectIDs" type="array" hint="Holds objects to be displayed at this particular node. Can be of mixed types." required="no" default="" ftSeq="13" ftFieldset="Relationships" ftWizardStep="Body" ftLabel="Associated Media" ftJoin="dmImage,dmFile,dmFlash" 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:
- date time pickers
- list boxes
- tree controls
- checkboxes
- radio buttons
- And more
A complete compendium of formtool controls can be found on the FarCry Developer WIKI at:
- http://farcry.jira.com/wiki/display/FCDEV40/Form+Tool+Property+Metadata
- http://farcry.jira.com/wiki/display/FCDEV50/Formtools
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:
- Edit builds the form control with associated smarts.
- Display describes the semantic markup required to render a display for the property. For example, an ftType="url" will activate the URL as a link by default.
- Validation provides some server side validation, and in the case of complex controls mangles the data into the format the underlying database model expects.
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
- Update your superHero component metadata using the example code above as a guide.
Restarting Your Application
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.
- Reload the edit form for your "Super Hero" and make sure things are going according to plan.
- Try uploading a few images and discuss with your instructor.
Image Quality
The image quality of the basic image manipulation in FarCry can be relatively poor. The system is designed to work with ColdFusion 7.0.1 by default. However, you can drastically improve image quality by installing one of several image plugins, freely available from the community. For example, if you are running on ColdFusion 8 consider using the farcrycfimage plugin. Image and other plugins are available here: http://farcry.jira.com/wiki/display/FCPLUG/Home
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.
- Open the ./packages/superHero.cfc
- 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="fitInside" /> </cfcomponent>
- Make sure that each <cfproperty> has a relevant ftWizardStep entry
- Reload the formtool metadata and test that your wizard works.
"Wizard Overkill"
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.
- Create a new ColdFusion component called ./packages/types/SuperPower.cfc
- Create the following properties
- title (string; required... think ftValidation="required")
- description (longchar; try limiting the total characters to 512)
- imgPower (image; 100x100 dimensions, destination: /images/superPower/imgPower)
- Deploy the content type into the database
- Use the Scaffold tool in the COAPI area to create an administration page
- Add a bunch of super powers to your application (ColdFusion, Flex, Flash, Photoshop, etc. ) You will find some content for powers in your media folder