Neptune 1.0 Beta 3 Documentation: Manage Data

Neptune Information

Download from RIA Forge

Manage Data

Based on Dan Wilson's "So you want to build a ModelGlue:Unity application (Part 3)" (and the CFWheels version).

Now that we have a "Hello World" page, it is time to start building our Contact-O-Matic program.

Our program will be in the "contacts" folder, so (unless otherwise specified) all of the files mentioned below will be in the root of the "contacts" folder (that is, in "/contacts/").

Component

First we need to create a component to manage the data. We will create a "ContactOMatic" component that extends com.sebtools.ProgramManager. We will define a simple contacts table in the component.

We will build our program in a "contacts" folder, but we will put any model components in the "model" folder of our program. So, this will be /contacts/model/ContactOMatic.cfc.

<cfcomponent extends="com.sebtools.ProgramManager" output="no">

<cffunction name="xml" access="public" returntype="void" output="yes">
<tables>
	<table entity="Contact">
		<field name="ContactType" Label="Type" type="text" Length="20" />
	</table>
</tables>
</cffunction>

</cfcomponent>

This will create a table (though only in memory for now) named "Contacts" with the following fields:

Read Manager.cfc documentation for more about the XML syntax.

We aren't using a real database yet, so it doesn't matter if we set up our data model incorrectly. Feel free to experiment

This is actually the full code for our ContactOMatic.cfc. When we hook this up to a database, it will create the table from the definitions in the XML. It will also have a child "Contacts" component which will have the following methods (among others) automatically created:

Program.cfc

We need a way to tell the framework about the program we are creating and any components it is using. Although this could be done in components configuration, we will create a Program.cfc (/contacts/Program.cfc) to handle this. It is just as easy and will let us easily distribute the program later if we want (even if only from development to production).
<cfcomponent extends="_config.Program" display="Contact-O-Matic" output="false">
</cfcomponent>

Since the only component that we are loading matches the name of the program (in the display attribute of Program.cfc's cfcomponent tag), we don't need to include any other information in our Program.cfc.

Now just dump the component on the page to verify that it loaded.

<cfdump var="#Application.ContactOMatic#">

Form

So, let's jump right into a form to add a contact:

<cf_PageController>

<cf_Template showTitle="true">

<cf_sebForm />

</cf_Template>

Here, we have put in a cf_sebForm tag and referenced the page controller. Since we didn't actually create a page controller for this page, the framework gave us one - which was able to figure out what component we needed based on the file name of the page "contact-edit.cfm" (/contacts/contact-edit.cfm). The cf_sebForm tag used getMetaStruct() to discover the methods to use getFieldsArray() to find out about the fields.

This syntax is simple and very flexible as any fields added to the XML later will automatically show up on the form. Still, we will often want a bit more control over our form. Here is a more explicit syntax:

<cf_PageController>

<cf_Template showTitle="true">

<cf_sebForm>
	<cf_sebField name="ContactName">
	<cf_sebField name="ContactType">
	<cf_sebField type="Submit/Cancel/Delete">
</cf_sebForm>

</cf_Template>

The resulting HTML will be the same, but we have a bit more control. The cf_sebForm tag gets all of the information that it needs about the fields from getFieldsStruct, which allows us to define our fields in one centralized place. DRY indeed!

List

It would be handy to have a list page to show all of our contacts as well:

<cf_PageController>

<cf_Template showTitle="true">

<cf_sebTable />

</cf_Template>

Here the page controller provided by the framework tells cf_sebTable about the component and where to find the edit page (it uses the same methods as above to find out about the methods and fields). Note that the contacts showing up on the page are created by the simulated database (used for prototyping like we are doing now) and are dynamically generated every time we load the page (no way to edit them or anything).

Once again, this is short and flexible, but arguably lacking in control. So let's use a bit more of an expanded syntax:

<cf_PageController>

<cf_Template showTitle="true">

<cf_sebTable>
	<cf_sebColumn dbfield="ContactName">
	<cf_sebColumn dbfield="ContactType">
</cf_sebTable>

</cf_Template>

Now with very little code, we have a prototype of managing contacts in Contact-O-Matic. Of course, it doesn't have any validation, but we'll get to that....

Next: Validation

Code So Far:

<cfcomponent extends="com.sebtools.ProgramManager" output="no">

<cffunction name="xml" access="public" returntype="void" output="yes">
<tables>
	<table entity="Contact">
		<field name="ContactType" Label="Type" type="text" Length="20" />
	</table>
</tables>
</cffunction>

</cfcomponent>
<cfcomponent extends="_config.Program" display="Contact-O-Matic" output="false">

</cfcomponent>
<cf_PageController>

<cf_Template showTitle="true">

<cf_sebForm>
	<cf_sebField name="ContactName">
	<cf_sebField name="ContactType">
	<cf_sebField type="Submit/Cancel/Delete">
</cf_sebForm>

</cf_Template>
<cf_PageController>

<cf_Template showTitle="true">

<cf_sebTable>
	<cf_sebColumn dbfield="ContactName">
	<cf_sebColumn dbfield="ContactType">
</cf_sebTable>

</cf_Template>

The Framework Perspective

(Where we see how this compares to other ColdFusion frameworks)

Where's the Gateway and DAO?

The purpose of a Gateway and DAO is to isolate variability - specifically against changing your database engine (or data storage mechanism). That variability is already handled by DataMgr, which is built into the framework. Moreover, Neptune aims for a simpler route of direct service rather than a full blown OO approach. This should be well suitable for most ColdFusion applications.