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
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
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.
Reader Comments