Blog

Dan Card

August 03, 2022

Spread the word


Share your thoughts

Recently, I did a webinar on Refactoring Legacy Code and the question came up about whether or not it was possible to use ColdBox with existing code without converting everything to a ColdBox module or making changes to the existing codebase.

In the first installation in this series, we took a tour of the various elements which make up ColdBox.

In the second installation, we looked at creating layouts, views, and routes in the main site.

In the third, we created a module and did the first integration of our existing code into our ColdBox site.

See the previous posts about setting up the sample code from Forgebox at https://www.forgebox.io/view/coldbox-existing-code-blog.

Method 2: Using ColdBox as a new "view"

Many times (not always, but usually) a site / app gets a facelift as part of a revamp but the accumulated logic / server side code might not change too drastically. Let's say that as part of a new initiative we want to start moving toward using a css framework rather than developing all of our css in-house. To keep things simple, we're going to use the latest Bootstrap which (as of this writing) is 5.2.0. Also to keep this simple, we are going to just do one step up from the include example and have all of our logic in our .cfm page. We'll worry about separation of concerns later.

Note: Check out the file /coldboxsite/modules_app/myco/views/home/byData.cfm and the URL http://myco.local/myco/accountsByData to see the completed page.

There are three steps to this process:

Step 1: Create the Route

In /modules_app/myco/config/Router.cfc, create the route accountsByData which runs the home.byData event. In the previous posts we saw that we can create this by simply adding route("/accountsByData","home.byData") to the configure() method.

Step 2: Create the View

In the /modules_app/myco/views/home/ folder, create the file byData.cfm. Because this is a view, and not a layout, we don't include the html, head, and body tags. We would probably also put the links and script tags to the bootstrap libraries in our layout if this were a "real" project, but for our purposes, we'll put them here.

The key part of this example is this:

<cfset people = createObject("com.mycode.people.Accounts").allClients() />
<cfset balances = createObject("com.mycode.accounting.accounting").allAccounts() />

When we set up our cfmappings, we mapped /com to the com folder in our "existing code" (/mycode in the sample code). Once we did that, we can access those components the same way we would any other code. From there it is just a straightforward project to put in our HTML and then create our rows.

<cfset people.each(function(item, index){
   writeOutput("
        <tr>
          <td>#index#</td>
          <td>#item.id#</td>
          <td>#item.first#</td>
          <td>#item.last#</td>
          <td>#balances.keyExists(item.id) ? balances[item.id] : ''#</td>");
}) />

In case this looks odd to anyone, we're using the member function people.each(). Member functions are functionality that are built directly into the data structure, in this case, an array. (The data structure itself is obviously a class which is why it can have methods). We also could have used the more verbose ArrayEach(people, function() ). Either way, inside the function, we can use script syntax which is why we have writeOutput("") surrounding our HTML. Whichever format you use, each() will loop over the array and pass each element into the function submitted. We are using each because we aren't expecting anything back from our loop. If we were expecting a return, we could use map() but there is no need in this case.

We also used the ternary operator in the <td>. Instead of typing

If( balances.keyExists( item.id ) ){
    WriteOutput( "#balances[ item.id ]#" )
} else {
    writeOutput( '' );
}

We can write #balances.keyExists( item.id ) ? balances[ item.id ] : ''. The first section is what is evaluated. The second section (after the ? ) is what happens if the first part is true and the third (after the : ) is what happens if the first part if false.

Open this example at http://myco.local/myco/accountsByData and compare it to the original at http://mycooriginal.local/ and you can see the difference.

Method 3: Using a Handler

In method 2, we had our logic (all the createObject() code) and the view (our HTML table) on the same.cfm page. We want to actually separate them to have a better separation of concerns, in this case, Horizontal Separation of Concerns. A handler is a method in a cfc that is run in response to an event such as a route being accessed.

Step 1: Create the route

In the /config/Router.cfc of our myco module, add route( "/accountsWithHandler", "myCo.accountBalances" );

Step 2: Create the Handler

Since a handler is, at its core, a cfc, all we need to do is create a .cfc. However, we can also use CommandBox to create our handler for us. Navigate to /modules_app/myco and then type coldbox create handler name=myco. For our purposes, we're simply going to create a cfc.

component {
}

In our component, we're going to add this function:

public function accountBalances( event, rc, prc ){

    event.setPrivateValue( "people", createObject( "com.mycode.people.Accounts" ).allClients() );
    event.setPrivateValue("balances",createObject("com.mycode.accounting.accounting").allAccounts() );
    event.setView( "home/withHandler" );
}

To unpack this, we need to look at the arguments which are being sent in

event – On every request to a ColdBox event, the framework creates an object that models the incoming request. This object is called the Request Context Object.

rc – The Request Collection which contains the FORM/REMOTE/URL data merged into a single structure. This is considered to be unsafe data as it comes from any request.

prc – The Private Request Collection which is a structure that can be used to safely store sensitive data. This structure cannot be modified from the outside world.

In this method, we are still using our createObject() code but we are putting the results into the event component as a privateValue. This is available to our code, including the view, for the rest of the request.

As a final act, we are setting the view to be home/withHandler. Since this is in our module, ColdBox will look in our module's view folder for this .cfm file.

Step 3: Create the view

Duplicate the byData.cfm file in the sample code and call it withHandler.cfm. Remove the two createObject() lines and change people.each() to prc.people.each().

This is much better separation of concerns.

Method 4: Passing in Variables

This isn't so much of a new method but a consideration that is going to be important. We pass in variables from the browser all the time via forms, links, and so on. How does ColdBox handle that?

Step 1:

Duplicate the Handler method accountBalances and call it passingVariables

Step 2:

Create the route route( "/accountsWithVariables", "myCo.passingVariables" );

Step 3:

Duplicate /views/home/withHandler.cfm and call it passingVariables.cfm in the same folder.

In the passingVariables.cfm file, change the ID to a link using either

href="/myco/passingVariables?activeReview=2 or event.buildLink("myco.accountsWithVariables","activeReview=2")

Option A will send the user to http://myco.local/myco/accountsWithVariables?activeReview=2

Option B will send the user to http://myco.local/myco/accountsWithVariables/activeReview/2.

In both of these formats, the variables activeReview will be in the event.rc.activeReview with the value of 2.

In our table, add some simple logic such as:

var emphasis = event.getValue("activeReview","") == item.id ? "font-weight:1000;" : "";

and then adapt the table row to be <tr style="#emphasis#">

The row which was chosen will appear emboldened. Perhaps not the most useful functionality but it illustrates our purposes.

Conclusion

We've now looked at three ways we can start using ColdBox as a new view to our existing data while keeping the data in place in old file structure so it is accessible by our existing site and we are not stuck maintaining two code bases. These methods include:

  • A simple include referencing our old .cfm files,
  • Creating a new layout and view and using createObject() in our view to obtain data from our existing code, and
  • Adding a handler which accesses the data and adds it to the event object which is then available to the view.

In the next (and final?) post in this series, we'll look at few ways we can use a tool which is integrated into ColdBox called WireBox to reference our data. This will allow us to remove the createObject() calls completely from our handlers and get rid of more code clutter.

Did you miss the June Webinar - Getting started with the Legacy Migration with Dan Card

We will look at the process of converting legacy .cfm based sites into a more modern coding design which has less overall code, is easier to maintain and manage, mistakes and errors can more readily and speedily identified and fixed, and is easier to read.

Recording: https://cfcasts.com/series/ortus-webinars-2022/videos/getting-started-with-the-legacy-migration-with-dan-card

Did you miss: Legacy Migration Follow Up: Using Coldbox with an Existing Code Base with Dan Card

July 29th 2022: Time 11:00 AM Central Time ( US and Canada )

Dan Card will present a follow-up to his June webinar: Getting started with the Legacy Migration. Dan received some good questions, so July's Webinar: Legacy Migration Follow Up: Using Coldbox with an Existing Code Base with Dan Card. If you have a more traditional/legacy codebase and want to modernize with ColdBox but don't know where to start, this webinar is just for you!

Recording: https://cfcasts.com/series/ortus-webinars-2022/videos/legacy-migration-follow-up:-using-coldbox-with-an-existing-code-base

Find out more about Dan Card's workshop at Into the Box - Legacy Code Conversion to the Modern World

This one-day workshop will focus on converting legacy .cfm based sites into a more modern coding design that has less overall code, is easier to maintain and manage, mistakes and errors can be more readily and speedily identified and fixed, and is easier to read.

https://intothebox.org/#workshops-2022

Add Your Comment

Recent Entries

TestBox Latest Updates and News!

TestBox Latest Updates and News!

We’re thrilled to have launched the new TestBox website and TestBox 6.0! If you haven’t had a chance to explore yet, visit TestBox to discover updated documentation, powerful resources, and features that make testing more efficient than ever.

Maria Jose Herrera
Maria Jose Herrera
November 21, 2024
The Hidden Costs of In-House Database Management

The Hidden Costs of In-House Database Management

The Hidden Costs of In-House Database Management


Opting for in-house database management involves more than just a salary. Here are some often-overlooked costs associated with maintaining your own DBA team.



1. High Salaries and Benefits


Hiring skilled DBAs is expensive. According to industry reports, the average salary of a DBA in the U.S. can range from $85,000 to over $130,000 per year, depending on experience and expertise. When you add ...

Cristobal Escobar
Cristobal Escobar
November 20, 2024
5 Signs It’s Time to Modernize Your ColdFusion / CFML Application

5 Signs It’s Time to Modernize Your ColdFusion / CFML Application

ColdFusion has long been a reliable platform for building web applications, but like any technology, it requires maintenance and modernization over time. Whether you're using Lucee or Adobe ColdFusion, it’s critical to recognize the signs that your application is no longer meeting today’s standards in performance, security, and scalability. Let’s explore five clear indicators that it’s time to modernize your ColdFusion application and how ColdFusion consulting can help breathe new life into y...

Cristobal Escobar
Cristobal Escobar
November 19, 2024