We've seen how to convert data list and data detail pages from procedural code to Mach-II events. Now we need to refactor how we build form and action pages.

Create a Company

From a data list page, we generally have the options to Add a New Item, View Item Deatils or Edit Item.

Clicking on "Add a Company", we get a new Company form.

Here's the procedural version of this page:

/mach-ii-primer/classic/company_form.cfm
view plain print about
1<html>
2    <head>
3        <title>Classic CF Demo - Company Form</title>
4    </head>
5
6    <body>
7
8    <cfinclude template="includes/header.cfm">
9
10    <cfparam name="url.COMPANY_ID" type="numeric" default="0" />
11
12    <table width="770" cellspacing="0" cellpadding="4" align="center" border="0">
13        <tr>
14            <td valign="top" bgcolor="Silver" width="100">
15                <cfinclude template="includes/lhs_navigation_menu.cfm">
16            </td>
17            <td valign="top">
18                <h2>Company Form</h2>
19
20                <cfquery name="qCompanies" datasource="#request.DSN#">
21                    SELECT
22                        COMPANY_ID,
23                        COMPANY_NAME,
24                        COMPANY_ADDRESS_ONE,
25                        COMPANY_ADDRESS_TWO,
26                        COMPANY_CITY,
27                        COMPANY_STATE,
28                        COMPANY_ZIP,
29                        COMPANY_PHONE_MAIN
30                    FROM
31                        CF_COMPANIES
32                    WHERE
33                        COMPANY_ID = '#url.COMPANY_ID#'
34                </cfquery>
35
36                <script type="text/javascript">
37                function validateCompany()
38                {
39                    var f = document.companyData;
40                    var err = "";
41
42                    if (f.COMPANY_NAME.value == "")
43                    {
44                        err += "Please enter a Company Name.\n";
45                    }
46                    if (f.COMPANY_ADDRESS_ONE.value == "")
47                    {
48                        err += "Please enter an Address.\n";
49                    }
50                    if (f.COMPANY_CITY.value == "")
51                    {
52                        err += "Please enter the City.\n";
53                    }
54                    if (f.COMPANY_STATE.value == "")
55                    {
56                        err += "Please enter the State.\n";
57                    }
58                    if (f.COMPANY_ZIP.value == "")
59                    {
60                        err += "Please enter the Zip Code.\n";
61                    }
62                    if (f.COMPANY_PHONE_MAIN.value == "")
63                    {
64                        err += "Please enter the Main Phone Number.\n";
65                    }
66
67                    if (err != "")
68                    {
69                        alert(err);
70                        return false;
71                    }
72
73                    return true;
74                }
75                </script>
76
77                <cfoutput>
78                <form name="companyData" action="company_form_process.cfm" method="post" onSubmit="return validateCompany()">
79
80                    <input type="hidden" name="COMPANY_ID" value="#qCompanies.COMPANY_ID#" />
81
82                    <p>Company Name: <input type="text" name="COMPANY_NAME" value="#qCompanies.COMPANY_NAME#" /></p>
83                    <p>Address Line 1: <input type="text" name="COMPANY_ADDRESS_ONE" value="#qCompanies.COMPANY_ADDRESS_ONE#" /></p>
84                    <p>Address Line 2: <input type="text" name="COMPANY_ADDRESS_TWO" value="#qCompanies.COMPANY_ADDRESS_TWO#" /></p>
85                    <p>City: <input type="text" name="COMPANY_CITY" value="#qCompanies.COMPANY_CITY#" /></p>
86                    <p>State: <input type="text" name="COMPANY_STATE" value="#qCompanies.COMPANY_STATE#" /></p>
87                    <p>Zip: <input type="text" name="COMPANY_ZIP" value="#qCompanies.COMPANY_ZIP#" /></p>
88                    <p>Main Phone: <input type="text" name="COMPANY_PHONE_MAIN" value="#qCompanies.COMPANY_PHONE_MAIN#" /></p>
89
90                    <p>
91                        <cfif url.COMPANY_ID eq 0>
92                            <input type="submit" name="addCompany" value="Add Company" />
93                        <cfelse>
94                            <input type="submit" name="editCompany" value="Edit Company" />
95                            <input type="submit" name="deleteCompany" value="Delete Company" />
96                        </cfif>
97                        <input type="button" name="cancel" value="Cancel" onClick="history.back();" />
98                    </p>
99
100                </form>
101                </cfoutput>
102            </td>
103        </tr>
104    </table>
105
106    <cfinclude template="includes/footer.cfm">
107
108    </body>
109</html>

The link to "Add a new Company" passes COMPANY_ID=0 in the querystring, so the query qCompanies returns an emtpy record set, so the form fields are all populated with empty strings.

We've already refactored the layout HTML into Mach-II <page-view>s. All that's left are three major sections of code:

  1. The query qCompanies.
  2. Javascript to validate the form's contents.
  3. The form itself.

Creating the showCompanyForm event

First we need a query that returns a single company record. We already have this code in the CompanyListener, which uses the Company bean and CompanyDAO.

view plain print about
1<notify listener="CompanyListener" method="getCompanyDetail" resultArg="companyBean" />

mach-ii-primer/m2/model/companies/05/CompanyListener.cfc
view plain print about
1<cffunction name="getCompanyDetail" access="public" output="false" returntype="Company" hint="returns a populated Company Bean.">
2
3    <cfargument name="event" type="MachII.framework.Event" required="true" />
4
5    <cfset var company = createObject("component", "Company").init( arguments.event.getArg("COMPANY_ID") ) />
6    <cfset var companyDAO = createObject("component", "CompanyDAO").init( DSN = request.DSN ) />
7
8    <cfset companyDAO.read(company) />
9
10    <cfreturn company />
11
12</cffunction>

Next we need to move the Company form and Javascript to its own CFM file.

view plain print about
1<page-view name="companyForm" page="/views/companies/05/company_form.cfm" />

The values of the form fields are now being populated by the contents of the Company bean.

mach-ii-primer/views/companies/05/company_form.cfm
view plain print about
1<cfset company = event.getArg("companyBean") />
2
3<cfoutput>
4<form name="companyData" action="index.cfm?event=processCompanyData" method="post" onSubmit="return validateCompany()">
5
6    <input type="hidden" name="COMPANY_ID" value="#company.getCompanyID()#" />
7
8    <p>Company Name: <input type="text" name="COMPANY_NAME" value="#company.getName()#" /></p>
9    <p>Address Line 1: <input type="text" name="COMPANY_ADDRESS_ONE" value="#company.getAddressOne()#" /></p>
10    <p>Address Line 2: <input type="text" name="COMPANY_ADDRESS_TWO" value="#company.getAddressTwo()#" /></p>
11    <p>City: <input type="text" name="COMPANY_CITY" value="#company.getCity()#" /></p>
12    <p>State: <input type="text" name="COMPANY_STATE" value="#company.getState()#" /></p>
13    <p>Zip: <input type="text" name="COMPANY_ZIP" value="#company.getZip()#" /></p>
14    <p>Main Phone: <input type="text" name="COMPANY_PHONE_MAIN" value="#company.getPhoneMain()#" /></p>
15
16    <p>
17        <cfif company.getCompanyID() eq 0>
18            <input type="submit" name="addCompany" value="Add Company" />
19        <cfelse>
20            <input type="submit" name="editCompany" value="Edit Company" />
21            <input type="submit" name="deleteCompany" value="Delete Company" />
22        </cfif>
23        <input type="button" name="cancel" value="Cancel" onClick="history.back();" />
24    </p>
25
26</form>
27</cfoutput>

Optionally, we can move the Javascript to an external file.

mach-ii-primer/js/05/companies.js
view plain print about
1function validateCompany()
2{
3    var f = document.companyData;
4    var err = "";
5
6    if (f.COMPANY_NAME.value == "")
7    {
8        err += "Please enter a Company Name.\n";
9    }
10    if (f.COMPANY_ADDRESS_ONE.value == "")
11    {
12        err += "Please enter an Address.\n";
13    }
14    if (f.COMPANY_CITY.value == "")
15    {
16        err += "Please enter the City.\n";
17    }
18    if (f.COMPANY_STATE.value == "")
19    {
20        err += "Please enter the State.\n";
21    }
22    if (f.COMPANY_ZIP.value == "")
23    {
24        err += "Please enter the Zip Code.\n";
25    }
26    if (f.COMPANY_PHONE_MAIN.value == "")
27    {
28        err += "Please enter the Main Phone Number.\n";
29    }
30
31    if (err != "")
32    {
33        alert(err);
34        return false;
35    }
36
37    return true;
38}

If we use an external JS file, then we need to reference it in company_form.cfm.

view plain print about
1<cfif event.getArge("jsFile") is not "">
2    <script src="#event.getArge("jsFile")#" type="text/javascript"></script>
3</cfif>

The event-handler for showCompanyForm

mach-ii.05.xml
view plain print about
1<event-handler event="showCompanyForm" access="public">
2
3    <event-arg name="pageTitle" value="Manage Company" />
4    <!-- Optional external JS file -->
5    <event-arg name="jsFile" value="/mach-ii-primer/m2/js/05/companies.js" />
6
7    <notify listener="CompanyListener" method="getCompanyDetail" resultArg="companyBean" />
8
9    <view-page name="header" />
10    <view-page name="lhsMenu" contentArg="sidebar" />
11    <view-page name="companyForm" contentArg="mainContent" />
12    <view-page name="template" />
13    <view-page name="footer" />
14
15</event-handler>

Filtering data

The showCompanyForm event will be starting point for Creating, Updating and Deleting Company records.

The form is setup to show different submit actions based on url.COMPANY_ID.

view plain print about
1<cfif company.getCompanyID() eq 0>
2    <input type="submit" name="addCompany" value="Add Company" />
3<cfelse>
4    <input type="submit" name="editCompany" value="Edit Company" />
5    <input type="submit" name="deleteCompany" value="Delete Company" />
6</cfif>

When you have multiple submit buttons in a form, whichever one you click will be the name/value pair that exists on the action page. (This is basic HTML functionality.)

Procedural version

In the procedural version, the form submits to a processing page.

view plain print about
1<form name="companyData" action="company_form_process.cfm" method="post" onSubmit="return validateCompany()">

A different query is run based on which submit button was used to submit the form.

mach-ii-primer/classic/company_form_process.cfm
view plain print about
1<cfif structKeyExists(form, "addCompany")>
2
3    <cfquery name="qAddCompany" datasource="#request.DSN#">
4        INSERT INTO
5            CF_COMPANIES
6        (
7            COMPANY_NAME,
8            COMPANY_ADDRESS_ONE,
9            COMPANY_ADDRESS_TWO,
10            COMPANY_CITY,
11            COMPANY_STATE,
12            COMPANY_ZIP,
13            COMPANY_PHONE_MAIN
14        )
15        VALUES
16        (
17            '#form.COMPANY_NAME#',
18            '#form.COMPANY_ADDRESS_ONE#',
19            '#form.COMPANY_ADDRESS_TWO#',
20            '#form.COMPANY_CITY#',
21            '#form.COMPANY_STATE#',
22            '#form.COMPANY_ZIP#',
23            '#form.COMPANY_PHONE_MAIN#'
24        )
25    </cfquery>
26
27</cfif>
28
29<cfif structKeyExists(form, "editCompany")>
30
31    <cfquery name="qEditCompany" datasource="#request.DSN#">
32        UPDATE
33            CF_COMPANIES
34        SET
35            COMPANY_NAME = '#form.COMPANY_NAME#',
36            COMPANY_ADDRESS_ONE = '#form.COMPANY_ADDRESS_ONE#',
37            COMPANY_ADDRESS_TWO = '#form.COMPANY_ADDRESS_TWO#',
38            COMPANY_CITY = '#form.COMPANY_CITY#',
39            COMPANY_STATE = '#form.COMPANY_STATE#',
40            COMPANY_ZIP = '#form.COMPANY_ZIP#',
41            COMPANY_PHONE_MAIN = '#form.COMPANY_PHONE_MAIN#'
42        WHERE
43            COMPANY_ID = #form.COMPANY_ID#
44    </cfquery>
45
46</cfif>
47
48<cfif structKeyExists(form, "deleteCompany")>
49
50    <cfquery name="qDeleteCompany" datasource="#request.DSN#">
51        DELETE
52        FROM
53            CF_COMPANIES
54        WHERE
55            COMPANY_ID = #form.COMPANY_ID#
56    </cfquery>
57
58</cfif>
59
60<cflocation URL="companies.cfm" />

Mach-II version

Now we're going to submit the form to an event instead of a page.

view plain print about
1<form name="companyData" action="index.cfm?event=processCompanyData" method="post" onSubmit="return validateCompany()">

mach-ii.05.xml
view plain print about
1<event-handler event="processCompanyData" access="public">
2
3    <filter name="FilterCompanyAction"/>
4
5    <announce event="home" />
6
7</event-handler>

What is a Mach-II Event Filter?

Definition

An event filter is an object (component/CFC) that allows you to run some logic, then return true or false based on the results. Any filter that you create extends MachII.framework.EventFilter.

view plain print about
1<cfcomponent displayname="FilterCompanyAction" output="no" extends="MachII.framework.EventFilter" hint="Processes Company data based on the Submit button clicked.">

The required function filterEvent takes 3 arguments.

filterEvent()
view plain print about
1<cffunction name="filterEvent" access="public" output="false" returntype="boolean">
2
3    <cfargument name="event" type="MachII.framework.Event" required="yes" />
4    <cfargument name="eventContext" type="MachII.framework.EventContext" required="yes" />
5    <cfargument name="paramArgs" type="struct" required="yes" />
6
7</cffunction>

You can optionally create a configure() method to handle anything that needs to run when the Filter is created. This works the same as a Listerner's configure() method.

All Filters are created when the application loads for the first time. They are placed into the application scope, so be aware of your variable scopes.

Usage

When a filter returns true, then Mach-II continues processing the event-handler. In the event-handler processCompanyData, if the filter FilterCompanyAction returns true, then the announce command is run and we proceed to the "home" event.

FilterCompanyAction returns true
view plain print about
1<filter name="FilterCompanyAction"/>
2    <announce event="home" />

When a filter returns false, Mach-II stops processing the rest of the current event-handler and goes to the next one. Usually you'll announce the next event before returning false.

mach-ii-primer/m2/filters/05/FilterCompanyAction.cfc
view plain print about
1<cfcomponent displayname="FilterCompanyAction" output="no" extends="MachII.framework.EventFilter" hint="Processes Company data based on the Submit button clicked.">
2
3    <cffunction name="filterEvent" access="public" output="false" returntype="boolean">
4
5        <cfargument name="event" type="MachII.framework.Event" required="yes" />
6        <cfargument name="eventContext" type="MachII.framework.EventContext" required="yes" />
7        <cfargument name="paramArgs" type="struct" required="yes" />
8
9        <cfif event.getArg("addCompany") is not "">
10            <cfset announceEvent("processCompanyCreate", arguments.event.getArgs()) />
11            <cfreturn false />
12        </cfif>
13
14        <cfif event.getArg("editCompany") is not "">
15            <cfset announceEvent("processCompanyUpdate", arguments.event.getArgs()) />
16            <cfreturn false />
17        </cfif>
18
19        <cfif event.getArg("deleteCompany") is not "">
20            <cfset announceEvent("processCompanyDelete", arguments.event.getArgs()) />
21            <cfreturn false />
22        </cfif>
23
24        <cfreturn true />
25
26    </cffunction>
27
28</cfcomponent>

In the above code, if the "addCompany" submit button was clicked, then event.getArg("addCompany") will not be an empty string, so the Filter then announces the event processCompanyCreate and copies all of the current event Args to that event. Then it returns false, telling Mach-II to stop processing the current event-handler (processCompanyData).

So far, we have replaced part of the functionlity of the procedural file "company_form_process.cfm". Now we just need to handle the database interactions.

Chaining Events

So we start off at showCompanyForm.

view plain print about
1<event-handler event="showCompanyForm" access="public">
2    <event-arg name="pageTitle" value="Manage Company" />
3    <notify listener="CompanyListener" method="getCompanyDetail" resultArg="companyBean" />
4    <view-page name="header" />
5    <view-page name="lhsMenu" contentArg="sidebar" />
6    <view-page name="companyForm" contentArg="mainContent" />
7    <view-page name="template" />
8    <view-page name="footer" />
9</event-handler>

The form in that event submits to the event processCompanyData.

view plain print about
1<event-handler event="processCompanyData" access="public">
2    <filter name="FilterCompanyAction"/>
3    <announce event="home" />
4</event-handler>

Based on the action (button) we chose in showCompanyForm, the filter FilterCompanyAction then announces the next event.

If we chose to CREATE a Company

view plain print about
1<event-handler event="processCompanyCreate" access="private">
2    <notify listener="CompanyListener" method="createCompany" />
3    <announce event="showCompanies" />
4</event-handler>

The event processCompanyCreate notifies the Listener CompanyListener to call the method createCompany.

The method createCompany creates an instance of the CompanyDAO, then creates and populates an instance of the Company bean with the form data and finally passes the Company bean to the create() method of the DAO.

mach-ii-primer/m2/model/companies/05/CompanyListener.cfc - New function: createCompany()
view plain print about
1<cffunction name="createCompany" access="public" output="false" returntype="boolean" hint="Creates a new Company record.">
2
3    <cfargument name="event" type="MachII.framework.Event" required="true" />
4
5    <cfset var companyDAO = createObject("component", "CompanyDAO").init( DSN = request.DSN ) />
6    <cfset var company = createObject("component", "Company").init(
7                                CompanyID = arguments.event.getArg("COMPANY_ID"),
8                                Name = arguments.event.getArg("COMPANY_NAME"),
9                                AddressOne = arguments.event.getArg("COMPANY_ADDRESS_ONE"),
10                                AddressTwo = arguments.event.getArg("COMPANY_ADDRESS_TWO"),
11                                City = arguments.event.getArg("COMPANY_CITY"),
12                                State = arguments.event.getArg("COMPANY_STATE"),
13                                Zip = arguments.event.getArg("COMPANY_ZIP"),
14                                PhoneMain = arguments.event.getArg("COMPANY_PHONE_MAIN")
15                                ) /
>

16
17    <cfreturn companyDAO.create( company ) />
18
19</cffunction>
mach-ii-primer/m2/model/companies/05/CompanyDAO.cfc - New function: create()
view plain print about
1<cffunction name="create" access="public" returntype="boolean" output="false" hint="Create a new Company record.">
2    <cfargument name="company" type="Company" required="true" hint="Company bean" />
3    <cfset var qAddCompany = "" />
4    <cftransaction>
5        <cftry>
6            <cfquery name="qAddCompany" datasource="#variables.DSN#">
7                INSERT INTO
8                    CF_COMPANIES
9                (
10                    COMPANY_NAME,
11                    COMPANY_ADDRESS_ONE,
12                    COMPANY_ADDRESS_TWO,
13                    COMPANY_CITY,
14                    COMPANY_STATE,
15                    COMPANY_ZIP,
16                    COMPANY_PHONE_MAIN
17                )
18                VALUES
19                (
20                    <cfqueryparam value="#arguments.company.getName()#" cfsqltype="cf_sql_varchar" />,
21                    <cfqueryparam value="#arguments.company.getAddressOne()#" cfsqltype="cf_sql_varchar" />,
22                    <cfqueryparam value="#arguments.company.getAddressTwo()#" cfsqltype="cf_sql_varchar" />,
23                    <cfqueryparam value="#arguments.company.getCity()#" cfsqltype="cf_sql_varchar" />,
24                    <cfqueryparam value="#arguments.company.getState()#" cfsqltype="cf_sql_varchar" />,
25                    <cfqueryparam value="#arguments.company.getZip()#" cfsqltype="cf_sql_varchar" />,
26                    <cfqueryparam value="#arguments.company.getPhoneMain()#" cfsqltype="cf_sql_varchar" />
27                )
28            </cfquery>
29            <cfcatch type="database">
30                <cftransaction action="rollback" />
31                <cfreturn false />
32            </cfcatch>
33        </cftry>
34    </cftransaction>
35    <cfreturn true />
36</cffunction>

Once all of this has processed, the event showCompanies is loaded.

If we chose to UPDATE a Company

view plain print about
1<event-handler event="processCompanyUpdate" access="private">
2    <notify listener="CompanyListener" method="updateCompany" />
3    <announce event="showCompanies" />
4</event-handler>

The event processCompanyUpdate notifies the Listener CompanyListener to call the method updateCompany.

The method updateCompany creates an instance of the CompanyDAO, then creates and populates an instance of the Company bean with the form data and finally passes the Company bean to the update() method of the DAO.

mach-ii-primer/m2/model/companies/05/CompanyListener.cfc - New function: updateCompany()
view plain print about
1<cffunction name="updateCompany" access="public" output="false" returntype="boolean" hint="Updates a Company record.">
2
3    <cfargument name="event" type="MachII.framework.Event" required="true" />
4
5    <cfset var companyDAO = createObject("component", "CompanyDAO").init( DSN = request.DSN ) />
6    <cfset var company = createObject("component", "Company").init(
7                                CompanyID = arguments.event.getArg("COMPANY_ID"),
8                                Name = arguments.event.getArg("COMPANY_NAME"),
9                                AddressOne = arguments.event.getArg("COMPANY_ADDRESS_ONE"),
10                                AddressTwo = arguments.event.getArg("COMPANY_ADDRESS_TWO"),
11                                City = arguments.event.getArg("COMPANY_CITY"),
12                                State = arguments.event.getArg("COMPANY_STATE"),
13                                Zip = arguments.event.getArg("COMPANY_ZIP"),
14                                PhoneMain = arguments.event.getArg("COMPANY_PHONE_MAIN")
15                                ) /
>

16
17    <cfreturn companyDAO.update( company ) />
18
19</cffunction>
mach-ii-primer/m2/model/companies/05/CompanyDAO.cfc - New function: update()
view plain print about
1<cffunction name="update" access="public" returntype="boolean" output="false" hint="Updates a Company record.">
2    <cfargument name="company" type="Company" required="true" hint="Company bean" />
3    <cfset var qEditCompany = "" />
4    <cftransaction>
5        <cftry>
6            <cfquery name="qEditCompany" datasource="#variables.DSN#">
7                UPDATE
8                    CF_COMPANIES
9                SET
10                    COMPANY_NAME = <cfqueryparam value="#arguments.company.getName()#" cfsqltype="cf_sql_varchar" />,
11                    COMPANY_ADDRESS_ONE = <cfqueryparam value="#arguments.company.getAddressOne()#" cfsqltype="cf_sql_varchar" />,
12                    COMPANY_ADDRESS_TWO = <cfqueryparam value="#arguments.company.getAddressTwo()#" cfsqltype="cf_sql_varchar" />,
13                    COMPANY_CITY = <cfqueryparam value="#arguments.company.getCity()#" cfsqltype="cf_sql_varchar" />,
14                    COMPANY_STATE = <cfqueryparam value="#arguments.company.getState()#" cfsqltype="cf_sql_varchar" />,
15                    COMPANY_ZIP = <cfqueryparam value="#arguments.company.getZip()#" cfsqltype="cf_sql_varchar" />,,
16                    COMPANY_PHONE_MAIN = <cfqueryparam value="#arguments.company.getPhoneMain()#" cfsqltype="cf_sql_varchar" />
17                WHERE
18                    COMPANY_ID = <cfqueryparam value="#arguments.company.getCompanyID()#" cfsqltype="cf_sql_integer" />
19            </cfquery>
20            <cfcatch type="database">
21                <cftransaction action="rollback" />
22                <cfreturn false />
23            </cfcatch>
24        </cftry>
25    </cftransaction>
26    <cfreturn true />
27</cffunction>

Once all of this has processed, the event showCompanies is loaded.

If we chose to DELETE a Company

view plain print about
1<event-handler event="processCompanyDelete" access="private">
2    <notify listener="CompanyListener" method="deleteCompany" />
3    <announce event="showCompanies" />
4</event-handler>

The event processCompanyDelete notifies the Listener CompanyListener to call the method deleteCompany.

The method deleteCompany creates an instance of the CompanyDAO, then creates and populates an instance of the Company bean with the COMPANY_ID only and finally passes the Company bean to the delete() method of the DAO.

mach-ii-primer/m2/model/companies/05/CompanyListener.cfc - New function: deleteCompany()
view plain print about
1<cffunction name="deleteCompany" access="public" output="false" returntype="boolean" hint="Updates a Company record.">
2
3    <cfargument name="event" type="MachII.framework.Event" required="true" />
4
5    <cfset var companyDAO = createObject("component", "CompanyDAO").init( DSN = request.DSN ) />
6    <cfset var company = createObject("component", "Company").init(
7                                CompanyID = arguments.event.getArg("COMPANY_ID") ) /
>

8
9    <cfreturn companyDAO.update( company ) />
10
11</cffunction>
mach-ii-primer/m2/model/companies/05/CompanyDAO.cfc - New function: delete()
view plain print about
1<cffunction name="delete" access="public" returntype="boolean" output="false" hint="Updates a Company record.">
2    <cfargument name="company" type="Company" required="true" hint="Company bean" />
3    <cfset var qDelCompany = "" />
4    <cftransaction>
5        <cftry>
6            <cfquery name="qDelCompany" datasource="#variables.DSN#">
7                DELETE
8                FROM
9                    CF_COMPANIES
10                WHERE
11                    COMPANY_ID = <cfqueryparam value="#arguments.company.getCompanyID()#" cfsqltype="cf_sql_integer" />
12            </cfquery>
13            <cfcatch type="database">
14                <cftransaction action="rollback" />
15                <cfreturn false />
16            </cfcatch>
17        </cftry>
18    </cftransaction>
19
20    <cfreturn true />
21</cffunction>

Once all of this has processed, the event showCompanies is loaded.

Ack! Carpel Tunnel!

Yes, that's a heck of a lot of code for such a small application. If this was a real world app, I'm sure I'd just create it the procedural way. However, the concepts and techniques shown so far are the building blocks used in many high traffic and mission critical applications.

You can see these changes in action by using the version 5 files.

  1. Rename the version 4 mach-ii.xml file to mach-ii.04.xml
  2. Rename mach-ii.05.xml to mach-ii.xml
  3. Reload the application and click the Companies link in the left-hand navigation.

Next chapter

The Mach-II Primer has now caught up with the Object Oriented ColdFusion Primer. I'm working on a post for that primer which will cover a Complex DAO (working with multiple tables or data sources). After that, I'll get into the Service Object and Object Factory. Once those are done, I'll come back to the Mach-II Primer to show how to implement those objects in the sample application.

But before then: We've been converting this application to an MVC framework in an effort to reduce the amount of redundant code. You should have noticed by now that there are a lot of the same objects being created in the Listeners. They're being created every time a function is called. That's redundant code too.

Next time we'll use a Plug-in or a new feature of Mach-II 1.5 to turn some objects into Mach-II Properties.