So you want to create a ModelGlue:Unity application? ( Part 8 )

In our last series, we moved the ContactTypes from a ColdSpring configured struct, to a database table. This set the stage to move the rest of our persisted data to the database.

As we begin this series our main goal is to have our contacts and lists of contacts stored in our database. Originally, we used in-memory storage as it allowed us a functional application without a database.

In this series, we will introduce two new files, ContactDAO and ContactGW (GW = Gateway). Both components will reside in the *ContactManagerMG.model directory. The ContactDAO will handle the DB work for Creating, Reading, Updating and Deleting our Contacts. Incidentally, this group of functionality is commonly referred to as C.R.U.D. The ContactGW will handle the database work for pulling queries of Contacts. We'll have a function called getContactQuery().

Here is a look at the ContactDAO. Note: we reference the AppConfig inside our ContactDAO so we can use the Application Configuration defined in ColdSpring. While we mostly care about the DSN for now, the flexibility to pull other configuration parameters will come in handy later.

view plain print about
1<cfcomponent>
2
3    <cffunction name="Create" access="public" output="false">
4        <cfargument name="Contact" required="yes" />
5        <cfset var CreateQuery = "" />
6    
7            <cfquery name="CreateQuery" datasource="#getAppConfig().getConfig().dsn#">
8    
9                INSERT INTO Contact
10                ( ContactName, ContactTypeID )
11                VALUES
12                (
13                    <cfqueryparam value="#arguments.Contact.getContactName()#" cfsqltype="cf_sql_varchar">,
14                    <cfqueryparam value="#val( arguments.Contact.getContactTypeID() )#" cfsqltype="cf_sql_numeric">                    
15                )            
16    
17            </cfquery>
18        
19    </cffunction>
20
21    <cffunction name="Read" access="public" output="false">
22        <cfargument name="Contact" required="yes" />
23        <cfset var ReadQuery = "" />
24        
25        <cfquery name="ReadQuery" datasource="#getAppConfig().getConfig().dsn#">
26    
27            SELECT ContactID, ContactName, ContactTypeID
28            FROM Contact
29            WHERE ContactID = <cfqueryparam value="#val( arguments.Contact.getContactID() )#" cfsqltype="cf_sql_numeric">
30    
31        </cfquery>
32
33        <cfset arguments.Contact.setContactID( ReadQuery.ContactID ) />
34        <cfset arguments.Contact.setContactName( ReadQuery.ContactName ) />
35        <cfset arguments.Contact.setContactTypeID( ReadQuery.ContactTypeID ) />
36
37    </cffunction>
38
39    <cffunction name="Update" access="public" output="false">
40        <cfargument name="Contact" required="yes" />
41        <cfset var UpdateQuery = "" />
42        
43        <cfquery name="UpdateQuery" datasource="#getAppConfig().getConfig().dsn#">
44    
45            UPDATE Contact
46                SET
47                    ContactName = <cfqueryparam value="#arguments.Contact.getContactName()#" cfsqltype="cf_sql_varchar">,
48                    ContactTypeID = <cfqueryparam value="#arguments.Contact.getContactTypeID()#" cfsqltype="cf_sql_numeric">
49            WHERE ContactID = <cfqueryparam value="#arguments.Contact.getContactID()#" cfsqltype="cf_sql_numeric">
50                
51        </cfquery>        
52    
53    </cffunction>
54
55    <cffunction name="Delete" access="public" output="false">
56        <cfargument name="Contact" required="yes" />
57        <cfset var DeleteQuery = "" />
58        
59        <cfquery name="DeleteQuery" datasource="#getAppConfig().getConfig().dsn#">
60    
61            DELETE FROM Contact
62            WHERE contactID = <cfqueryparam value="#arguments.Contact.getContactID()#" cfsqltype="cf_sql_numeric">
63    
64        </cfquery>
65    
66    </cffunction>
67
68
69    <cffunction name="getAppConfig" access="public" output="false" returntype="any">
70        <cfreturn variables.instance.AppConfig />
71    </cffunction>
72    
73    <cffunction name="setAppConfig" access="public" output="false" returntype="void">
74        <cfargument name="AppConfig" type="any" required="true" />
75        <cfset variables.instance.AppConfig = arguments.AppConfig />
76    </cffunction>
77    
78    
79    
80
81</cfcomponent>

Here is a look at the ContactGW. Once again we reference the AppConfig.

view plain print about
1<cfcomponent>
2
3
4 <cffunction name="getContactQuery" access="public" output="false" returntype="query">
5 <cfset var ContactQuery = "" />
6
7 <cfquery name="ContactQuery" datasource="#getAppConfig().getConfig().dsn#">
8 SELECT C.ContactID, c.ContactName, c.ContactTypeID, ct.ContactType
9 FROM Contact c LEFT JOIN ContactType ct ON c.ContactTypeID = ct.ContactTypeID
10 </cfquery>
11
12 <cfreturn ContactQuery />
13
14 </cffunction>
15
16 <cffunction name="getAppConfig" access="public" output="false" returntype="any">
17 <cfreturn variables.instance.AppConfig />
18 </cffunction>
19
20 <cffunction name="setAppConfig" access="public" output="false" returntype="void">
21 <cfargument name="AppConfig" type="any" required="true" />
22 <cfset variables.instance.AppConfig = arguments.AppConfig />
23 </cffunction>
24
25</cfcomponent>

Now we add each component to our ColdSpring configuration. Each component takes one Property, the AppConfig object. Add both beans as new property tags to the existing ContactService bean definition. We will also remove the references to the old Array based ContactList. Let's do a little housecleaning on our ColdSpring file shall we?

Add the definitions for the components

view plain print about
1<bean id="ContactDAO" class="ContactManagerMG.model.ContactDAO">
2 <property name="AppConfig"><ref bean="AppConfig" /></property>
3 </bean>
4
5 <bean id="ContactGW" class="ContactManagerMG.model.ContactGW">
6 <property name="AppConfig"><ref bean="AppConfig" /></property>
7 </bean>

Remove the following lines from the existing ContactService definition:

view plain print about
1<property name="ContactList">
2    <list></list>
3</property>

Add in the property tags for our new components.

view plain print about
1<bean id="ContactService" class="ContactManagerMG.model.ContactService">
2        <property name="ContactTypeGW"><ref bean="ContactTypeGW" /></property>
3        <property name="ContactDAO"><ref bean="ContactDAO" /></property>
4        <property name="ContactGW"><ref bean="ContactGW" /></property>        
5    </bean>

Once complete, ColdSpring will run setContactDAO() and setContactGW() on the ContactService component and stuff the proper object in our service for us. We need to change the service a little now to account for this new functionality. Open up the ContactService and make the following changes:

Remove the getContactList() and setContactList() functions. These functions used to manage our Array based contact list from ColdSpring, with our new Database driven Contact-O-Matic, we won't need them any longer.

Remove:

view plain print about
1<cffunction name="setContactList" access="public" returntype="void" output="false">
2        <cfargument name="ContactList" type="array" required="true" />
3        <cfset variables.instance.ContactList = arguments.ContactList />
4    </cffunction>
5    <cffunction name="getContactList" access="public" returntype="array" output="false">
6        <cfreturn variables.instance.ContactList />
7    </cffunction>

Now add in the get/set functions for each component. While we are in here, also add in a new function to get our ContactList from our new ContactGW. The function on the ContactGW is called getContactQuery(). When complete, you'll have removed two functions and added five. Examples of the new functions are below:

view plain print about
1<cffunction name="getContactList" output="false" access="public" returntype="query" hint="I return a list of contacts">
2        <cfreturn getContactGW().getContactQuery() />
3    </cffunction>
4    
5    <cffunction name="getContactDAO" access="public" output="false" returntype="any">
6        <cfreturn variables.instance.ContactDAO />
7    </cffunction>
8    
9    <cffunction name="setContactDAO" access="public" output="false" returntype="void">
10        <cfargument name="ContactDAO" type="any" required="true" />
11        <cfset variables.instance.ContactDAO = arguments.ContactDAO />
12    </cffunction>
13
14    <cffunction name="getContactGW" access="public" output="false" returntype="any">
15        <cfreturn variables.instance.ContactGW />
16    </cffunction>
17    
18    <cffunction name="setContactGW" access="public" output="false" returntype="void">
19        <cfargument name="ContactGW" type="any" required="true" />
20        <cfset variables.instance.ContactGW = arguments.ContactGW />
21    </cffunction>

Now our service has references to the ContactDAO and the ContactGW, in turn both the ContactDAO and ContactGW have references to our AppConfig. All the plumbing for the database interaction is complete.

Previously, we stored the ContactType in our ContactFormBean. This was acceptable when referential integrity was not on our list. Now, we need to modify the Contact Form and the Contact Form Bean to refer to the ContactTypeID instead of simply the ContactType. In the form itself, all we need to do is switch the reference. Inside the Bean there is a tiny bit more to it. We will start with the form.

The select tag block should be changed as follows

view plain print about
1Type: <select name="ContactTypeID">
2    <cfloop query="ContactTypes">
3 <option value="#ContactTypeID#" <cfif ContactFormBean.getContactTypeID() IS ContactTypeID>selected</cfif>>#ContactTypes.ContactType#</option>
4 </cfloop>
5    </select>

Now open the ContactFormBean and change all the ContactType references to ContactTypeID. A find and replace would be nice here. A simply Find and Replace should make 11 changes...

There are two references in the Init() function, one in the validate function and also a get/set block at the bottom. Each of these should be changed to ContactTypeID.

The completed ContactFormBean is here:

view plain print about
1<cfcomponent
2    displayname="ContactFormBean"
3    output="false"
4    hint="A bean which models the ContactFormBean form.">

5
6
7    <!---
8    PROPERTIES
9    --->

10    <cfset variables.instance = StructNew() />
11
12    <!---
13    INITIALIZATION / CONFIGURATION
14    --->

15    <cffunction name="init" access="public" returntype="ContactManagerMG.model.ContactFormBean" output="false">
16        <cfargument name="ContactID" type="string" required="false" default="" />
17        <cfargument name="ContactName" type="string" required="false" default="" />
18        <cfargument name="ContactTypeID" type="string" required="false" default="" />
19
20        <!--- run setters --->
21        <cfset setContactID(arguments.ContactID) />
22        <cfset setContactName(arguments.ContactName) />
23        <cfset setContactTypeID(arguments.ContactTypeID) />
24
25        <cfreturn this />
26     </cffunction>
27
28    <!---
29    PUBLIC FUNCTIONS
30    --->
    
31    <cffunction name="getMemento" access="public"returntype="struct" output="false" >
32        <cfreturn variables.instance />
33    </cffunction>
34
35    <cffunction name="validate" access="public" returntype="boolean" output="false">
36        <cfargument name="Errors" type="struct" required="true" />
37        <cfset tempErrors = structNew() />
38
39        <cfif NOT len( trim( getContactName() ) ) >
40            <cfset tempErrors['ContactName'] = "Please enter a name for your contact" />
41        </cfif>
42        <cfif NOT len( trim( getContactTypeID() ) )>
43            <cfset tempErrors['ContactTypeID'] = "Please enter a contact type for your contact" />
44        </cfif>        
45        
46        <cfif structCount( tempErrors ) >
47            <cfset structAppend( arguments.Errors, tempErrors ) />
48            <cfreturn false />
49        <cfelse>
50            <cfreturn true />        
51        </cfif>
52        
53    </cffunction>
54
55    <!---
56    ACCESSORS
57    --->

58    <cffunction name="setContactID" access="public" returntype="void" output="false">
59        <cfargument name="ContactID" type="string" required="true" />
60        <cfset variables.instance.ContactID = arguments.ContactID />
61    </cffunction>
62    <cffunction name="getContactID" access="public" returntype="string" output="false">
63        <cfreturn variables.instance.ContactID />
64    </cffunction>
65
66    <cffunction name="setContactName" access="public" returntype="void" output="false">
67        <cfargument name="ContactName" type="string" required="true" />
68        <cfset variables.instance.ContactName = arguments.ContactName />
69    </cffunction>
70    <cffunction name="getContactName" access="public" returntype="string" output="false">
71        <cfreturn variables.instance.ContactName />
72    </cffunction>
73
74    <cffunction name="setContactTypeID" access="public" returntype="void" output="false">
75        <cfargument name="ContactTypeID" type="string" required="true" />
76        <cfset variables.instance.ContactTypeID = arguments.ContactTypeID />
77    </cffunction>
78    <cffunction name="getContactTypeID" access="public" returntype="string" output="false">
79        <cfreturn variables.instance.ContactTypeID />
80    </cffunction>
81
82</cfcomponent>

Finally, we need to change how the contacts are saved. In the beginning, we simply appended the ContactFormBean object into an Array of ContactFormBean object and iterated over the array for our ContactList. Now, we need to change the controller function to call the service. We will let the service decide how to handle the save. In the controller located at *ContactManagerMG.controller modify the isvalid branch to call a ContactService method called saveContact()

view plain print about
1<cfif isValid >
2         <cfset ContactService.saveContact( ContactFormBean ) />
3         <cfset arguments.event.addResult("Success") />
4     <cfelse>
5         <cfset arguments.event.setValue("ErrorStruct", ErrorStruct) />
6          <cfset arguments.event.addResult("Failure") />
7     </cfif>

Now add the saveContact() function into your ContactService. This function will accept a Contact object, being our ContactFormBean, and check to see if the ContactID has been assigned. If so, we will update the record, if not, we will create the record. Your saveContact() function should look like this:

view plain print about
1<cffunction name="saveContact" access="public" returntype="void" output="false">
2        <cfargument name="Contact" type="any" required="true"/>
3        
4        <cfif val( Contact.getContactID() ) GT 0 ><!--- Update --->
5            <cfset getContactDAO().update( arguments.Contact ) />
6        <cfelse><!--- Insert --->
7            <cfset getContactDAO().create( arguments.Contact ) />
8        </cfif>
9
10 </cffunction>

After changing the save contact flow, we have closed the circle for adding / updating the individual contacts. Remaining, is the ContactList page.

We will now be returning a query and ourcontact list page used to operate on an array. Thus, we must adjust.

Change your dspContactList.cfm page to use a query. Your completed list page will look as follows:

view plain print about
1<cfset myself = viewstate.getValue("myself") />
2<cfset ContactList = viewstate.getValue("ContactList") />
3
4<cfoutput>
5    <cfif ContactList.recordcount IS 0 >
6        -No Saved Contacts-<br />
7    <cfelse>
8        <table>
9            <tr>
10                <th>Name</th>
11                <th>Type</th>
12            </tr>    
13        <cfloop query="ContactList">
14            <tr>
15                <td>#ContactName#</td>
16                <td>#ContactType#</td>
17            </tr>
18        </cfloop>
19        </table>    
20    </cfif>
21</cfoutput>

Reset your application and run your new Database Powered Contact-O-Matic. If you've followed all the steps, (and I haven't left any out) you now have a proper application.

We touched a good chunk of the application and I trust this has been a good refresher into the inner workings of our Contact-O-Matic. In our next series, we will include the mechanics to delete contacts from the database.

Download Download

So you want to create a ModelGlue:Unity application? ( Part 7 )

We are going to break this up into phases starting with the contact types. At the end of this series, our contact types will come from the database and we will have an even greater appreciation for ModelGlue and ColdSpring.

The last article gave the spec for your database tables, Contact and ContactType. Add in 3 dummy records to the ContactType table. I used Friend, Enemy and Co-worker.

Set up your datasource in the ColdFusion administrator. I used the data source name of 'ContactOMatic'. Test the connection and move on.

Now we will need this datasource name inside of our cfqueries. Can anyone guess where we will keep the DSN? Thats right, in ColdSpring. Give yourself a cookie if you got that one right.

Before we begin, change the ColdSpring.xml ModelGlueConfiguration reload setting to true.

ModelGlue has a standard component called a SimpleConfig. The purpose of the simple config is to hold on to a collection of values and this component is easily configured in ColdSpring. The path for SimpleConfig is ModelGlue.bean.CommonBeans.SimpleConfig, so add a configuration to ColdSpring for this. We will refer to this as AppConfig and it will hold our DSN and an AppTitle.

view plain print about
1<bean id="AppConfig" class="ModelGlue.Bean.CommonBeans.SimpleConfig">
2        <property name="Config">
3            <map>
4                <entry key="AppTitle"><value>Contact-O-Matic</value></entry>
5                <entry key="dsn"><value>ContactOMatic</value></entry>                
6            </map>
7        </property>
8    </bean>

Run your application. If you have an error at this point, check the exact path to the SimpleConfig component. No errors? Perfect!

Simple enough so far, right? Now we shall write our ContactTypeGW. This component will pull a query of ContactTypes from the database. There are three functions in the ContactTypeGW.

  1. setAppConfig - this function provides the way for ColdSpring to stick the AppConfig component in the ContactTypeGW
  2. getAppConfig - this function provides a way for us to reference the AppConfig component inside the ContactTypeGW
  3. getContactTypeQuery - this function returns the ContactTypes from the database

Your ContactTypeGW should look like this:

view plain print about
1<cfcomponent>
2
3
4 <cffunction name="getContactTypeQuery" access="public" output="false" returntype="query">
5 <cfset var ContactTypeQuery = "" />
6
7 <cfquery name="ContactTypeQuery" datasource="#getAppConfig().getConfig().dsn#">
8 SELECT ContactTypeID, ContactType
9 FROM ContactType
10 </cfquery>
11
12 <cfreturn ContactTypeQuery />
13
14 </cffunction>
15
16
17
18
19 <cffunction name="getAppConfig" access="public" output="false" returntype="any">
20 <cfreturn variables.instance.AppConfig />
21 </cffunction>
22
23 <cffunction name="setAppConfig" access="public" output="false" returntype="void">
24 <cfargument name="AppConfig" type="any" required="true" />
25 <cfset variables.instance.AppConfig = arguments.AppConfig />
26 </cffunction>
27
28</cfcomponent>

Note for the DSN we used 'getAppConfig().getConfig().dsn', when we want to access the AppTitle later, we'll use 'getAppConfig().getConfig().AppTitle'. (If you haven't seen this syntax before, getAppConfig() returns a reference to the AppConfig Object, which has a getConfig() function returning a struct. Then we access a property of the struct using dot notation.)

Now, adjust the ContactService to call ContactTypeGW. Remove the following functions: init, getContactTypes and setContactTypes. Add get and set functions for our ContactTypeGW. Then add the proper function for getContactTypes. It should return a query so be sure to adjust the returntype to 'query'

Your ContactManangerService should look like this:

view plain print about
1<cfcomponent>
2
3
4    <!---
5    PROPERTIES
6    --->

7    <cfset variables.instance = StructNew() />
8
9
10    <cffunction name="getContactTypes" access="public" returntype="query" output="false">
11 <cfset var ContactTypes = getContactTypeGW().getContactTypeQuery() />
12 <cfreturn ContactTypes />
13 </cffunction>
14
15 <cffunction name="getContactTypeGW" access="public" output="false" returntype="any">
16 <cfreturn variables.instance.ContactTypeGW />
17 </cffunction>
18
19 <cffunction name="setContactTypeGW" access="public" output="false" returntype="void">
20 <cfargument name="ContactTypeGW" type="any" required="true" />
21 <cfset variables.instance.ContactTypeGW = arguments.ContactTypeGW />
22 </cffunction>
23
24    <cffunction name="setContactList" access="public" returntype="void" output="false">
25        <cfargument name="ContactList" type="array" required="true" />
26        <cfset variables.instance.ContactList = arguments.ContactList />
27    </cffunction>
28    <cffunction name="getContactList" access="public" returntype="array" output="false">
29        <cfreturn variables.instance.ContactList />
30    </cffunction>
31
32</cfcomponent>

Now adjust ColdSpring to account for the new gateway functionality. Configure the bean definition for ContactTypeGW and add the AppConfig property. Replace the ContactType map with the ContactTypeGW bean The changed lines should look like this:

view plain print about
1<bean id="ContactService" class="ContactManagerMG.model.ContactService">
2        <property name="ContactList">
3            <list></list>
4        </property>
5        <property name="ContactTypeGW"><ref bean="ContactTypeGW" /></property>
6    </bean>
7    
8 <bean id="ContactTypeGW" class="ContactManagerMG.model.ContactTypeGW">
9 <property name="AppConfig"><ref bean="AppConfig" /></property>
10 </bean>

Finally, our contact form was expecting a struct, it will now get a query so adjust the ContactType section accordingly

view plain print about
1<cfloop query="ContactTypes">
2 <option value="#ContactType#" <cfif ContactFormBean.getContactType() IS ContactType>selected</cfif>>#ContactTypes.ContactType#</option>
3</cfloop>

Remember to reinitialize your application and now run your code. You should now see the ContactTypes defined in your database

It seems like we touched a few files to make this change. We altered the ColdSpring.xml file to have an application configuration object, added in our ContactTypeGW and then stitched them together. We also had to adjust our form to account for a query in place of the struct. Note we did not touch our Controller nor our ModelGlue.xml file. Since the flow of the application did not change, those files remain the same and happily work with the new functionality of the application. This is an example of the benefits of compartmentalized, or encapsulated, code.

A zip of all files is included with this article.

Next, we will create the contact persistance and write our contacts to the database

Download Download

So you want to create a ModelGlue:Unity application? ( Part 6 )

In the next few series, our Contact-O-Matic will persist data in a database. The queries and relationships are simple and should translate over to any database. Our code will be organized into two types of components the DAO (Data Access Object) and the Gateway. These two components are common structures used in many Object Oriented systems and a quick google search will land you on endless descriptions for each. For our purposes, all we need to know is the DAO and Gateway will help us organize our code into sections. The DAO is for pulling back a single object, the Gateway for a query of objects.

Another architectural feature of our Contact-O-Matic is our ContactService.cfc component. Service components help tie your other components together. Note how simple it will be to add in new database functionality.

At the end of series 5 of our Contact-O-Matic, we had a ContactService component which returned the ContactType data , a single contact object and a list of contact objects. Even though we are going to add a DAO component as well as a Gateway component, they will be tied together within the service component.

Some of you might be asking yourselves why we have all of these components. After all, there are huge and complex ColdFusion applications written without a single component. Couldn't we just put our queries in the Controller and be done with it? That is a very valid question to ask. You should be proud of thinking of it. Question Everything!!!

The main point of these separations in our code is to isolate variability. Meaning, when the application needs a feature, or a new data column, the affected sections in our code are compartmentalized and perhaps only one section of code needs to change in order for the entire application to be upgraded with the newest feature.

The complete source code up to the end of series 5 is attached to this article. It will be easier to follow along if you use this code.

A few quick notes before we begin:

  1. Remember that the application files will be cached if the ModelGlue reload setting is 'false'. Any changes to Controllers, components created with ColdSpring, or stored in the Controllers will NOT change until you reload the application. This trips me up sometimes and my first step is to ALWAYS reload the framework
  2. The <include /> tag is processed by BlogCFC as a cfinclude. Thus, whenever I paste in an event-handler section with an <include tag, I always have to use the entity symbol '& lt;' or i'll get an error when I post it. I try to leave a small note at the end of the code block about changing this in your code. If I forget, just know an XML tag will never actually start with '& lt;'
  3. I am writing this tutorial with MSSQL server (delete derogatory note about Microsoft Products). Your database might have a slightly different syntax and I trust you to convert it over

Lastly, our database will have two tables:

Contact
ColumnName ColumnType Other
ContactID int Primary Key
ContactName varchar( 255 ) not null
ContactType int null
ContactType
ColumnName ColumnType Other
ContactTypeID int Primary Key
ContactType varchar(100) not null

Without further ado, let us get to the next piece in our Series, database support.

Download Download

Sometimes it is the obvious......

I spent several hours going over a new ModelGlue:Unity + Transfer set up and had an error that stumped me. For the life of me I couldn't get any scaffolds to work. ModelGlue and Transfer loaded up perfectly, Directly querying the database worked perfectly. All signs pointed to GO, except for the lack of any scaffolded events working.

Oops!

Message Model-Glue: There is no known event handler for "skiresort.list".

Now, I've set this up several times so I was sure I misconfigured something. I checked every possible thing I could think of that could be holding this up and then started cfdumping the internals of the frameworks. Getting nowhere fast, I started complaining about it in the IRC channel and the second I started explaining it, the answer came to me. So for public humiliation and for posterity, here is the answer.

If you want to access the event-handlers generated by the scaffolding feature, the <scaffold /> tag in the modelglue.xml file MUST be contained in the <event-handlers /> tag.

This is Bad

view plain print about
1<scaffold object="skiresort" type="list,view,edit,commit,delete">
2    <results>
3        <result do="view.template" />
4    </results>        
5</scaffold>
6
7<event-handlers>

This is Good

view plain print about
1<event-handlers>
2
3<scaffold object="skiresort" type="list,view,edit,commit,delete">
4    <results>
5        <result do="view.template" />
6    </results>        
7</scaffold>

I shall hang my head in shame for the next 5 minutes....

MG:U series, interlude

I am planning out the next few steps in our ModelGlue:Unity series and would like to tally a vote. Currently our Contact-O-Matic is barebones. We went over how to use portions of ColdSpring to manage our service and to pass in configuration parameters. We also went over adding ModelGlue results to change the programmatic flow of the application. Following this pattern, you should have a good base on ModelGlue:Unity.

However, apart from the tabs, it has a plain-jane look and feel. Heck, it doesn't even save the contacts for very long ;). Before all is said and done, we will add in database persistance, security, the Transfer ORM and some Ajax.

We are going to need to put database persistance really soon as it is keeping us from our larger goals. After that, there are three different paths we can go.

In the spirit of Choose Your Own Adventure ( man, I loved those books ) which would you rather we tackle next? The choices once again:

  1. Easy MG:U Security
  2. MG:U scaffolding with Transfer ORM
  3. Ajax Enhancements

Also, if you are following along with the series, please leave a comment or send me an email with the database you use on your development server. I am going to make an effort to be as cross-DB as I can....

So you want to create a ModelGlue:Unity application? ( Part 5 )

Previously in this series, we installed the ModelGlue:Unity framework and the ColdSpring framework. We used the ModelGlueApplicationTemplate as the skeleton, added our basic flow and navigation. We can save and list contacts and our validation is working nicely,

In this section of our Contact-O-Matic, we will pull out the contact types values from coldspring and used them to add defined categories to our contacts. In a previous segment, we added the Contact Types as a 'map' in ColdSpring, now we will pull out the values and add them to our form.

[More]

So you want to create a ModelGlue:Unity application? ( Part 4 )

Previously in this series, we installed the ModelGlue:Unity framework and the ColdSpring framework. We used the ModelGlueApplicationTemplate as the skeleton, added our basic flow and navigation. Finally we can save and list contacts Our Contact-O-Matic is moving right along.

In the last segment, we tested the 'failure' path and were routed back to the form. We also tested the 'success' path and were routed to the contact list. Open the ContactFormBean.cfc located in *ContactManagerMG/Model and edit the validate function (You did check the validate box in the rooibos generator like the last series said, didn't you ;) )

Our validate function should have the returntype of boolean. We will pass in a structure to hold any error messages and check the lengths of our two properties ContactName and ContactType. Your validate function should look like this:

[More]

So you want to create a ModelGlue:Unity application? ( Part 3 )

Previously in this series, we installed the ModelGlue:Unity framework and the ColdSpring framework. We used the ModelGlueApplicationTemplate as the skeleton then we added our basic flow and navigation. Our Contact-O-Matic is moving right along.

In this segment of our regularly scheduled programming, we look a bit deeper into ColdSpring, add the contact form and contact list.

[More]

Download Download

So you want to build a ModelGlue:Unity application (Part 2)

Previously in this series, we installed the ModelGlue:Unity framework and the ColdSpring framework. We used the ModelGlueApplicationTemplate as the skeleton for our new Contact-O-Matic 1.0 alpha (don't worry, we'll eventually make this a Web 2.0 application). We rejoiced when we ran our application and now will look at some essential information about our new set-up.

Let's begin with opening the Application.cfm file and giving our application a name. Set the name attribute of the application tag to 'ContactManagerMG'. If for some reason, you already have another application on your server with the name of ContactManagerMG, put another name here.

Next, as ModelGlue uses ColdSpring for configuration, let us look at some key sections of the framework config. Open the *ContactManagerMG/config/ColdSpring.xml file in your editor. There are two beans defined by default, one with the id of 'modelGlueConfiguration' and one with the id of 'reactorConfiguration'. The 'reactorConfiguration' bean is for yet another framework you could use with ModelGlue. We won't need the 'reactorConfiguration' for this series and you may delete that bean from your ColdSpring.xml file.

Ok, now look closer at the 'modelGlueConfiguration'. The property tags define how your application will behave.

[More]

So you want to create a ModelGlue:Unity application? ( Part 1 )

In this series, we will create a ModelGlue:Unity application. Our example application will manage contacts. We will start with a blank canvas and by the end of the series, have a functional application.

Lets begin:

Firstly, you should have the ModelGlue:Unity and Coldspring framework installed. If the framework is not installed, have a look at this post.

Our application will reside in a directory just under the webroot. We will access our application at http://LocalHost/ContactManagerMG. With that in mind, lets open the ModelGlueApplicationTemplate Directory.

This directory serves as an application skeleton for which to begin a new ModelGlue:Unity application.

There are two ways to get a new application up quickly. The first way is to copy the contents of the ModelGlueApplicationTemplate into a new directory just under your webroot called ContactManagerMG. Do a find and replace on 'modelglueapplicationtemplate' and change it to 'ContactManagerMG'.

The second way assumes you have cfeclipse or some other ANT environment. The directions below are specifically for cfeclipse.

Inside the ModelGlueApplicationTemplate directory is a file called build.xml. Build.xml is an ANT script. ANT scripts are sets of commands used to perform file and directory tasks. There are certain parts of the ModelGlueApplicationTemplate that need to be changed to our application name ( ContactManagerMG ).

We will now make the modifications to the build.xml file for the purpose of creating our new application.

Open the build.xml file. On a default install of ModelGlue:Unity the file will look like so:

view plain print about
1<project name="New Model-Glue Application" default="build">
2    <property name="source" value="c:\inetpub\wwwroot\modelglue\modelglueapplicationtemplate"/>
3    <property name="target" value="c:\inetpub\wwwroot\"/>
4
5    <target name="build">
6        <copy todir="${target}">
7            <fileset dir="${source}" />
8        </copy>
9    
10         <replace
11     dir="${target}"
12     token="modelglueapplicationtemplate"
13     value=""
14     />

15    </target>
16</project>

In plain English, the build.xml file will copy the contents from the 'source' directory and place them into the 'target' directory then replace each instance of the 'token' and replace it with 'value'.

Make the following changes to the file and then run it.

IIS

view plain print about
1<project name="New Model-Glue Application" default="build">
2    <property name="source" value="C:\inetpub\wwwroot\modelglueapplicationtemplate"/>
3    <property name="target" value="C:\inetpub\wwwroot\ContactManagerMG"/>
4
5    <target name="build">
6        <copy todir="${target}">
7            <fileset dir="${source}" />
8        </copy>
9    
10         <replace
11     dir="${target}"
12     token="modelglueapplicationtemplate"
13     value="ContactManagerMG"
14     />

15    </target>
16</project>

Apache

view plain print about
1<project name="New Model-Glue Application" default="build">
2    <property name="source" value="C:\httpd\Apache2\htdocs\modelglueapplicationtemplate"/>
3    <property name="target" value="C:\httpd\Apache2\htdocs\ContactManagerMG"/>
4
5    <target name="build">
6        <copy todir="${target}">
7            <fileset dir="${source}" />
8        </copy>
9    
10         <replace
11     dir="${target}"
12     token="modelglueapplicationtemplate"
13     value="ContactManagerMG"
14     />

15    </target>
16</project>

Once your edits are complete, save the file and locate it in the navigator. Right click on the file and choose Run As -> ANT Build. You can see the progress in the console. Assuming no errors, you now have a new ModelGlue application and can begin coding.

Via Find and ReplaceANT build, you now have a new directory called ContactManagerMG. Run this in your browser and you should get a page showing the following:

Model-Glue 2.0: Unity

Model-Glue is up and running!

Voila. A new ModelGlue:Unity application. In the next series, we will add some functionality to our application.