Author: Steven Neiland
Published:

Warning: This blog entry was written two or more years ago. Therefore, it may contain broken links, out-dated or misleading content, or information that is just plain wrong. Please read on with caution.

I am currently in the process of rewriting a rather large spagetti code application to use FW/1 and ColdSpring. While its a relief to finally start bringing this beast into the 21st century its not without its challenges.

One of the problems I encountered is that the old application makes extensive use of component binding for different cfui components such as cfgrid. Unfortunately converting to a third party grid plugin such as datatables is not possible at this point in time due to the way the application is coded (don't ask).

This means that as I convert each component from being invoked transiently to being persisted in memory I have to create proxies for any remote methods used for the cfgrid bindings.

Solution 1: ColdSpring Remoting

Now ColdSpring has the ability to create proxies for this specific purpose using the RemoteFactoryBean. If you are interested here is a good article on how to Configure ColdSpring Remoting.

Solution 2: Manually Create The Remote Proxies

Personally though I prefer to manually create my remote proxy components and its actually very easy.

What we need to do is first refactor our existing code from a standalone component to a service component. Then we create the proxy component that the cfgrid can bind to which can in turn call the service component.

Aside: This may seem like a lot of unnecessary work and if the end goal was to continue to use cfgrid in the application you would be right. However the reason for doing this is as an intermediary step to allow the application to continue to use cfgrid while being refactored into FW/1 and eventually switching to a different datagrid plugin.

Example: Users Grid

To demonstrate lets take a users cfgrid which is bound to a component "users.cfc" method "getUsersForGrid" in a directory "/components/".

Existing Code

<cfform>
      <cfinput type="text" name="userslike" id="userslike" value=""><input type="submit" value="Go">

      <cfgrid name="usersGrid"
            format="html"
            pageSize="10"
            stripeRows="true"
            height="250"
            width="400"
            bind="cfc:components.users.getUsersForGrid({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection},{userslike})">

      
            <cfgridcolumn name="userId" header="User Id">
            <cfgridcolumn name="username" header="Username">
            <cfgridcolumn name="dob" header="Birthdate" mask="m/d/Y" type="date">
            <cfgridcolumn name="email" header="Email">
      </cfgrid>
</cfform>
<cfcomponent displayname="Users Component" output="false">

      <cffunction name="getUsersForGrid" access="remote" output="false" verifyclient="true">
            <cfargument name="page" type="numeric" required="true">
            <cfargument name="pagesize" type="numeric" required="true">
            <cfargument name="sortcol" type="string" required="true">
            <cfargument name="sortdir" type="string" required="true">
            <cfargument name="userslike" type="string" required="yes">
            
            <cfset var usersQuery = "">

            <cfquery name="usersQuery">
                  SELECT
                        userId
                        , username
                        , dob
                        , email
                  FROM
                        users
                  WHERE
                        username LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.userslike#%">
            </cfquery>

            <cfreturn QueryConvertForGrid(usersQuery, arguments.page, arguments.pagesize)>
      </cffunction>

</cfcomponent>

Note: You will of course notice that this uses the ColdFusion function QueryConvertForGrid(). Please don't do this, it's really very very bad practice. Instead you should use database pagination.

Refactor into a service

First lets create the service cfc based off the existing users.cfc file and place it in our "/model/services/" folder.

<cfcomponent displayname="Users Service" output="false">

      <cffunction name="getUsersForGrid" access="public" output="false">
            <cfargument name="page" type="numeric" required="true">
            <cfargument name="pagesize" type="numeric" required="true">
            <cfargument name="sortcol" type="string" required="true">
            <cfargument name="sortdir" type="string" required="true">
            <cfargument name="userslike" type="string" required="yes">
            
            <cfset var usersQuery = "">

            <cfquery name="usersQuery">
                  SELECT
                        userId
                        , username
                        , dob
                        , email
                  FROM
                        users
                  WHERE
                        username LIKE <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.userslike#%">
            </cfquery>

            <cfreturn QueryConvertForGrid(usersQuery, arguments.page, arguments.pagesize)>
      </cffunction>

</cfcomponent>

As you can see all we did was copy the file and change the access attribute from remote to public.

Create a proxy utility

With the service function created we now strip out the logic from the old "/components/users.cfc" file and replace it with a call to the users service after first getting a reference to the service using the FW/1 bean factory getBean() function.

<cfcomponent displayname="Users Proxy" output="false">
      
      <cffunction name="getUsersForGrid" access="remote" output="false" verifyclient="true" returnType="struct">
            <cfargument name="page" type="numeric" required="true">
            <cfargument name="pagesize" type="numeric" required="true">
            <cfargument name="sortcol" type="string" required="true">
            <cfargument name="sortdir" type="string" required="true">
            <cfargument name="userKeyword" type="string" required="yes" default="All Types">

            <!--- Get a reference to the users service --->            
            <cfset var usersService = application["org.corfield.framework"].factory.getBean("usersService")>

            <!--- Return the data from the service --->
            <cfreturn usersService.getUsersForGrid(argumentCollection=arguments)>
      </cffunction>
      
</cfcomponent>

With these changes the cfgrid will continue to function as normal but our main logic is now encapsulated in our model service layer ready for further refactoring.

What Do You Think?

Reader Comments

Post a Comment

Comment Etiquette:

  • Please keep comments on-topic.
  • Please do not post unrelated questions or large chunks of code.
  • Please do not engage in flaming/abusive behaviour.
  • Comments that contain or appear to be advertisments, will not be published.
  • Comments that appear to be created for the purpose of linkbuilding to commercial sites will be removed.

We are all adults here so play nice.

*
*



Archives Blog Listing

Tag Listing

Learn CF In A Week

Treehouse

 
Fork me on GitHub