Gregory's Blog

CfBlogs.org - A New ColdFusion Blog Aggregator

www.cfblogs.org is meant to replace the popular 'ColdFusion Bloggers' blog aggregator that was so popular in the ColdFusion community in the last ten years. Unfortunately, the ColdFusion Bloggers platform is no longer active at this time due to the unfortunate demise of Wil Genovese, who maintained Cfbloggers after Raymond Camden provided Wil with the keys.

The new cfblogs.org aggregator can be found here: http://www.cfblogs.org

History

I have always wanted to get involved in this project. The aggregator that Raymond developed was an integral part of our ColdFusion community, and it is a core requirement for my continued efforts in developing Galaxy Blog.

When I noticed that the CfBloggers site went down, I immediately contacted Raymond Camden and asked him for the most recent code. Raymond entrusted me with his most recent ColdFusion codebase, but it was from 2013. In the last two weeks, I was able to rewrite and modernize Raymonds' original CfBloggers code, and I believe that I have all of the original functionality intact.

The following features are available in this version of the code:

  • Updated server side logic in ColdFusion using modern API's and twitter post sharing functionality
  • Vastly improved mobile device handling
  • A modern responsive HTML5 single page application with Kendo grids
  • Full search capabilities
  • All of the current feeds have been personally reviewed and are current
  • Blog Posts are posted on the CfBlogs twitter feed
  • Twitter logic has been completely rewritten in ColdFusion 2018
  • RSS options from google Feedburner
  • CfBlogs RSS feed allowing the user to extract a certain amount of posts
  • Blog posts are aggregated every 20 minutes or so.

CfBlog RSS options

CfBlogs uses the CfBlogs FeedBurner for the main RSS feed. You can find it here: http://feeds.feedburner.com/CfblogsFeed.

You may also use our local CfBlogs feed located at http://gregoryalexander.com/cfblogs/rss.cfm?max=50.

Our local CfBlogs feed allows for options:

By default the local RSS feed will return the last 50 items. You can change this by adding ?max=N to the URL, where N is a number from 1 to 100. To show the last 5 entries, use:
http://gregoryalexander.com/cfblogs/rss.cfm?max=5

Filtering the local feed has not been implemented at this time. If requested, I will gladly implement it at a later time.

How to add your own site to this feed

If you wish to send me feedback about the site or get your blog added, please send me an email at gregory at gregoryalexander dot com. Include your blog's name, URL, and RSS URL if you want me to include your blog.

I can also work with other blog owners to see if we can archive all of their existing blog posts. Contact me if you're interested.

Please follow us on Twitter

CfBlogs tweets any new blog postings on the CfBlogs Twitter feed found at https://twitter.com/CfBlogsFeed. The twitter functionality should mirror the original twitter functionality of the ColdFusion Bloggers site.

I hope to also develop simiar functionality with Facebook soon.

CfBlogs Future

In the future, I hope to add Facebook social media sharing, make major improvements and fix some of the bugs that were found, and to contact Hostek, CfWebTools, and other potential partners to see if they will sponsor this site. I also hope to gather a few other folks and provide them the keys so that our ColdFusion community will be able to rely upon this site if one of us goes down.

I also hope to put the new full codebase into an upcoming Galaxie Blog version so that other blog owners can adopt this type of functionality.

The CfWebTools team may be able to resurrect the original ColdFusion Bloggers code (in node.js). If they are able to do so, I hope that the resurrected site can be complimentary. That said, I fully intend on making this code much more functional in the future.

Please don't hesitate to contact me if you have any ideas or suggestions!

Special Thanks

Many thanks go out to Raymond Camden, who assisted me and provided me his updated code, Adam Euans who helped compile a new active feed list, and Charlie Arehart who is, as always, a trusted person to bounce ideas off of and to ask for advice.

This entry was posted on February 13, 2021 at 12:56 AM and has received 527 views.

Extending Application.cfc's using mappings and proxies

One of the most frustrating things that I have had to deal with in ColdFusion is trying to create an external application that is open to the general public and having to secure a portion of that site with an application within a subfolder and extending the logic from base application.cfc. I'll walk you through the current approach that developers use to solve this as well as showing you how to additionally use mapping when there may be a hosting provider that uses virtual directories.

This is a rather long article, if you want to jump to the condensed summary, scroll down to the bottom of this page.

Many years ago, the first time that I tried to perform this, I received the following message no matter what I tried: "Could not find the ColdFusion component or interface xxx'. In a nutshell, the problem using this approach is that both the root and the subfolders have the same name, i.e. Application.cfc, and ColdFusion can't properly identify what component to extend. Finally, after some serious investigation, someone came up with the idea to create a proxy.cfc that resides in the same root directory as the root Application.cfc, and the Application.cfc in the subfolder extends an empty proxy.cfc that extends the root cfc like so:


root directory: Application.cfc
This root Application.cfc does not extend anything


Also in the root directory: Proxy.cfc
Proxy.cfc has the following code, it's essentially empty. The only thing that the Proxy.cfc does is to extend the Application.cfc that is in the same directory:
view plain about
1<cfcomponent extends="Application">
2</cfcomponent>


Subdirectory such as a folder named admin.
This subdirectory has another Application.cfc. Let's say that this component is responsible for securing the application and has login logic as well as debugging settings for example. This Application.cfc will extend the Proxy.cfc to gain the methods and properties of the Application.cfc in the root directory like so:
view plain about
1<cfcomponent displayname="Admin" extends="Proxy.cfc">
2<!--- Lots of code --->


This approach was a godsend and it was heavily blogged about. Ben Nadel has made a number of very helpful posts which I will share at the bottom of this article.

This works quite well unless you're on a hosted domain or a server that uses virtual directories. In this case, we are in the same original boat in which we started from. Now we are back into the "Could not find the ColdFusion component or interface xxx' hell!

There is a solution for this tricky problem though, we need to also use mapping!

It is a common misnomer that you can't use mapping to extend components. I am not quite sure where this misconception originally came about, but it has been proven that this is just not true. There are occasions where we must use mapping to solve some annoying problems, like here.

This particular site is hosted by hostek.com. They are a fine company to deal with, but the server that my site is hosted on has some idiosyncrasies due to the directory structure. Here, when I use the Proxy.cfc method to extend the logic from the base Application.cfc to the Application.cfc in the admin folder I receive the dreaded 'could not find the ... component' error. When I first saw it I was dismayed thinking not this again, so I turned to ColdFusion CFC mapping. Mapping tells ColdFusion where to find the file and what the file relationships are.


Let's review CFC structure that was just discussed. For example, imagine the following directory structure:

root directory: i.e. www.gregoryalexander.com/
subdirectory: www.gregoryalexander.com/admin/

As discussed, we have an Application.cfc and the Proxy.cfc in the root directory, and we have the Application.cfc in the 'admin' subdirectory. The Proxy.cfc extends the Application.cfc, also in the root directory, and the Application.cfc in the subdirectory (admin) extends the Proxy.cfc in the root directory.

root directory: contains both Application.cfc and Proxy.cfc (that extends the root Application.cfc).
subdirectory: Application.cfc (that extends Proxy.cfc).

Now we need to also add the following mapping in the root Application.cfc. This mapping logic should be near the top of the root Application.cfc, and it should not be within any of the Application.cfc event handlers (onApplicationStart, onApplicationRequest, etc). This mapping code does not need to be anywhere else other than the root Application.cfc:

view plain about
1<!--- Define application-specific mappings. These will be used to point to this application.cfc when we extend it in the admin/Administrator.cfc template using the Proxy.cfc that resides in the same folder as this Application.cfc. --->
2<cfset this.mappings = structNew() />
3<!--- Mapping for the ROOT Application.cfc --->
4<cfset this.mappings["rootCfc"] = getDirectoryFromPath(getCurrentTemplatePath()) />
5<!--- Mapping for the admin SUBDIRECTORY Application.cfc. Note the admin prefix is attached at the end of this line. This points to the admin folder. --->
6<cfset this.mappings["adminCfc"] = getDirectoryFromPath( getCurrentTemplatePath() & "/admin" ) />

I used rootCfc to identify the Application.cfc in the root directory, whereas adminCfc applies to the Application in the admin directory. These variables can be named anything. Note that the "/admin" string at the end of the adminCfc mapping points to the 'admin' folder, which is a subdirectory.

Now that we have the mappings in the root Application.cfc, we need to apply them to the extends statement in Application.cfc located in the subdirectory. In the /admin/Application.cfc template use:

/admin/Application.cfc

view plain about
1<cfcomponent displayname="xxx" sessionmanagement="xx" clientmanagement="xx" extends="rootCfc.Proxy">
2<!--- Logic --->

Of course, rootCfc tells the Application.cfc in the subdirectory to look for the Proxy.cfc template in the root directory. Like other 'extend' statements, you don't need to specify '.cfc' at the end of Proxy.

You don't need to use this 'extend' mapping in either the root Proxy.cfc or Application.cfc templates. They can already find each other as they are both in the same root directory.

/Proxy.cfc

view plain about
1<cfcomponent extends="Application">
2</cfcomponent>


Summary

For the sake of absolute clarity:
root Application.cfc
Contains the mapping logic. Has the mappings for both of the root and subdirectory.
This mapping logic should be near the top of the root Application.cfc, and it should not be within any of the Application.cfc event handlers (onApplicationStart, onApplicationRequest, etc).
Does not use an 'extend' statement

view plain about
1<cfset this.mappings = structNew() />
2<cfset this.mappings["rootCfc"] = getDirectoryFromPath(getCurrentTemplatePath()) />
3<cfset this.mappings["adminCfc"] = getDirectoryFromPath( getCurrentTemplatePath() & "/admin" ) />

root Proxy.cfm
A simple 'extends="Application" works.
No mapping logic.

view plain about
1<cfcomponent extends="Application">
2</cfcomponent>

subdirectory Application.cfc
The extends statement must be the mapping variable name of the folder (rootCfc), a dot (.), and finally the name of the Proxy.cfc template without the .cfc prefix (Proxy)
No mapping logic.

view plain about
1<cfcomponent displayname="Admin" sessionmanagement="yes" clientmanagement="yes" extends="rootCfc.Proxy">

My apologies for being so verbose. I annoyed myself while writing this- but not as annoyed when I was while trying to solve this problem!

Take care!

Related External Posts:

This entry was posted on January 29, 2021 at 10:31 PM and has received 263 views.

Happy New Year!

I hope that everyone has a wonderful New Year and I wanted to provide a status update on Galaxie Blog.

While I have not been blogging lately as I want to dedicate all of my time right now for development; I have been working like crazy to complete the next major version of the blog. The new blog has been completely overhauled. All of the database code has been stripped out and replaced with ColdFusion ORM. This allows the blog to use any modern database, SQL Server, Oracle, MySql, etc. Also, the entire administrative section of the site has been re-written from scratch and will support mobile devices. It's a mobile first responsive design and is a single page application built with HTML5. It is my goal to be able to go out into a National Park with nothing more than my camera and phone, take some lovely snapshots, and be able to upload the images, and create a blog post using nothing but my iPhone.

There are a slew of other major features, such as incorporating a WYSIWYG editor. I have been creating my own custom plug-ins for the editor to allow the users to upload and edit images, create sophisticated galleries, and link and upload videos, again- using nothing but your phone. There are also new HTML5 grids that have been incorporated to allow you to find and edit information quickly. All of the new user interfaces are themed, so if you choose a particular theme the theme will also be used in the new user interfaces, i.e. the new grids, editors, and image editing tools. It's also my goal to improve loading performance by using sophisticated caching.

I can't promise any release date at this time. I want to make sure that everything is done right. Since I had to completely overhaul the entire code-base, it is a good time to revisit some of the original approaches. I'll try to keep everyone updated during the course of this New Year. Once I am in final testing, I assure you that I will be blogging again.

Thank you for your interest!

Gregory

This entry was posted on January 22, 2021 at 1:51 PM and has received 156 views.

Galaxie Blog Status Update

It's been a while since I have posted or released a new version of Galaxie Blog. I have been busy at work, working with new clients, going on photography road trips and enjoying spending time with my family this summer.

Despite the lack of updates or releases in the last several months, I have been working on Galaxie Blog. I have incorporated the software for several clients now, and have been working on quite a few features, such as perfecting an independent blog page that takes on the characteristics of the blog's theme and serves as a landing page. I still am working on rewriting the software to use ColdFusion ORM, and completely overhauling the original BlogCfc Interface.

I hope all of you are safe,

This entry was posted on August 4, 2020 at 12:19 PM and has received 889 views.

Adding a dummy record in the first row of a recordset

There are numerous reasons why you should add a dummy record as the first row of a record. You may want to add a choice for the user to select none for example, or change the first row of a dropdown that is populated by a SQL query that has a unique label, such as select.... However, the best way to add a record coming from a database is in the SQL query itself.

Here, I want to add a new row at the top of the recordset that allows the user to choose none. I don't want to have to create a new SubCategory record into the database, and even if I could, the new None value would not be sorted correctly in the first row. Instead, we will create a dummy record as the first record using SQL.

In the inner query, the first select statement will create a new dummy record using SQL, and the second query is appending the data from the database to this record using a UNION ALL. We are also going to alias the column that we are displaying, in this case, the SubCategory, as a new column that we will sort by (SubCategorySort).

The dummy record at the top will have a 0 string as the SubCategorySort value. A zero value will make the dummy record with None appear at the top of the dropdown list. We will then use the SubCategory database column value as the SubCategorySort psuedo column in the subsequent SELECT statement in order to sort the rest of the data by the SubCategory, and will use an order by statement using our dummy SubCategorySort column outside of the inner query to sort the results like so:

view plain about
1SELECT *
2FROM (
3    SELECT
4        NULL as ResourceSubCategoryId,
5        'None' as SubCategory,
6        '0' as SubCategorySort
7    UNION ALL
8    SELECT
9        ResourceSubCategoryId,
10        SubCategory,
11        SubCategory as SubCategorySort
12    FROM
13        ResourceSubCategory
14
15) InnerQuery
16ORDER BY
17    SubCategorySort

This entry was posted on May 6, 2020 at 2:15 PM and has received 615 views.

Galaxie Blog Winter Update and Roadmap

Galaxie Blog Update

What is Galaxie Blog?

Galaxie Blog is the most modern and functional open-sourced Coldfusion Blog in the world. Galaxie Blog is a free open source ColdFusion blog platform, has an HTML5 interface, and is a beautifully designed responsive site that works flawlessly on desktop or mobile.

Galaxie Blog is completely open-source!

Galaxie Bog is open-source. All of the functionality out of the box that you see here is free. Unlike other blog software; I will commit to providing full functionality without charging any upcharge fee for more advanced features.

The only exception to this is that the blog owner may want to purchase their own Kendo license to include certain Kendo professional widgets- such as the Kendo grid. Galaxie Blog supports both the open-source version of Kendo Core, or Kendo Professional- which requires a license. The blog owner may choose to purchase their own professional Kendo UI license, directly from Telerik, to unlock certain Kendo UI functionality, such as incorporating the Kendo UI Grid.

So far, I have incorporated open-source libraries from third parties (such as Kendo Core), but I may eventually add a few more Kendo UI features that may require the professional license directly from Telerik. However, when I do decide to incorporate Kendo widgets requiring a paid license; I will always seek to provide similar free open-source functionality by developing free alternative interfaces.

Everything that you see on this blog, other than the grid that is shown below, is free and open-sourced. Grid, or no grid- this is a license thing that's totally up to you. I am not affiliated with Telerik- and will not be receiving any compensation.

Current Status

I am currently working on re-architecting Galaxie Blog to use ColdFusion ORM. Without getting into the weeds of the technical details, ColdFusion ORM allows Galaxie Blog to support any modern database. This is a massive endeavor! All of the database-oriented logic needs to be completely redone. I am also working on helping several clients migrating to Galaxie Blog. I likely will not have a new version of Galaxie Blog out until the early spring of 2020 (on a side note- I likely won't be blogging as much in the next few months).

Tentative 2020 General Roadmap (subject to change of course)

Version Date Description
1.75 Winter 2020 Re-engineer Galaxie Blog to use ColdFusion ORM. This will allow the blog owner to use Galaxie Blog with any modern database platform.
2.0 Spring 2020 Completely overhaul the administative interface and develop new HTML5 administrative interface that works with mobile devices
2.25 Summer 2020 Add functionality and rich editor widgets to the administative interface. It's my goal to be able to post a picture or a video along with a blog post using my mobile device. I'm currently investigating incorporating either TinyMce or CkEditor to allow blog owners and commenters to better present their posts.
2.50 Fall 2020 Develop Galaxie Blog into a Progressive Web Application.
3.0 Winter 2020 Incorporate ColdBox and Vue. ColdBox is the most popular ColdFusion MVC framework, and ColdBox has a much better ORM implementation. I am also really excited to use Vue (and ditch jQuery, which I am currently using). Vue should speed up the interative development cycles and make the code more maintainable.
TBD TBD Galaxie Blog supports two commenting systems, the native Galaxie Blog interface, and Disqus. However, the native Galaxie Blog interface does not have all of the features available in Disqus. It's my goal to make the core functionality of the native commenting interface comparable to the interfaces provided by Disqus. This requires having the blog handle Facebook and Twitter API logins.
TBD TBD Themes, themes, themes... Galaxie Blog already has dozens of professionally designed themes, but I will add a lot more. I'll also add the capability of attaching a theme to a blog post, a page, and potentially a widget. I also want to implement a theme pack- for example, to automatically display pictures of the current holiday or event- i.e. Halloween or Christmas. Although this is not what most users would think about when addressing blog functionality, it is really a fun feature and it improves user satisfaction.

Here is a fun little fact- did you know that Ben Nadel, one of the most pre-eminent ColdFusion bloggers around, coded his site to allow the user to always choose to display a certain photo when viewing his website? Ben's major theme is that he takes pictures with someone unique on most of his blog posts, and his readers can select to always view their own picture! Fun!
TBD TBD Improve user engagement. One of the biggest issues with blogging is that the users will read your posts, however, they rarely, if ever, comment or provide feedback. I will develop an interface to allow any user, even if they are not logged in, to recommend and or rate an article. Feedback is paramount to a successful blogger, and there is not really a good good mechanism to allow quick feedback right now other than to go through the captcha process and make a comment.
TBD TBD Enhance and develop new mobile interfaces. Currently, Galaxie Blogs Plyr control can cast video from the iPhone to an enabled airplay device for example, but I want to develop new interfaces improving native Andriod and iPhone functionality.
TBD TBD Better code syntax highlighting. Currently I use an older Java based library created by Jason Delmore to wrap up the code in a GUI, but there are other more modern open-source libraries such as Prism.

Note: this list is not complete, but represent some of the major milestones and goals that I want to incorporate into Galaxie Blog in the coming year.

If you would like to suggest any new features, or just make a general comment; please feel free to do so! I could always use any feedback or additional help!

I hope that everyone had a good holiday season- Happy Hanukkah, Merry Christmas, and all that jazz!

This entry was posted on January 15, 2020 at 6:35 PM and has received 833 views.

Using ColdFusion ORM to Populate the Database

Populating the new tables

We will be using simple 'SELECT *' database queries on the original BlogCfc tables and populate the new tables that CF-ORM created for us. Populating the database is where the rubber hits the road, if you made any errors in your ORM mappings, all of the flaws will be exposed. I'll try to show you some of the major issues that I faced, and how to resolve them.

Before we go any further on this topic, we must go over a few key concepts

  1. We can use explicit values to populate the database when no relationship exists.
  2. When are are dealing with a relationship, i.e. a property with a fieldtype (one-to-many, etc), a cfc, and a fkcolumn; we must use CF-ORM objects to populate the database.

In order to populate the new tables that were created with our persistent CFC mappings, we are going to use the EntityNew and EntityLoad objects along with these objects get and set methods.

  1. EntityNew instantiates a persistent CFC and allows us to insert records into the table columns using its set methods.
  2. EntityLoad allows us to load the persistent CFC in order to get the current values from the database, and then pass the CF-ORM object back to the set method of the object instantiated using EntityNew

In other words, we will use EntityNew to insert known or static values into the database, or use EntityLoad to get the values already in the database, and pass the loaded object back to the object that we created using EntityNew

We will cover each example in depth below.

1) Let's begin by inserting records into a table with no relationships

The code below is an example of populating the data from one table to another. The steps that we will use are:

  • Wrap the entire block with a transaction tag
  • Create a query that gets the current data found in the BlogCfc's original tblBlogRoles table
  • Loop through the tblBlogRoles query object using a cfoutput query tag and:
    • Create a new entity of the Role cfc object using EntityNew. The prefix before EntityNew can be anything you would like- I used RoleDbObj.
    • Use the set methods in the Role entity object to insert the records into all of the columns
    • Once the columns are set, save the Role entity with EntitySave
view plain about
1<!--- Get the Roles from BlogCfc --->
2<cfquery name="getTblBlogRoles" datasource="#dsn#">
3    SELECT
4    id
5 ,role
6 ,description
7     FROM tblblogroles
8</cfquery>
9
10<!--- Use a transaction --->
11<cftransaction>
12    <cfoutput query="getTblBlogRoles">
13            <!--- Load the entity. --->
14            <cfset RoleDbObj = entityNew("Role")>
15            <!--- Use the entity objects to set the data. --->
16            <cfset RoleDbObj.setBlogRef(blogRef)>
17            <cfset RoleDbObj.setRole(role)>
18            <cfset RoleDbObj.setDescription(description)>
19            <cfset RoleDbObj.setDate(now())>
20            <!--- Save it. Note: updates will automatically occur on persisted objects if the object notices any change. We don't have to use entity save after the Entity has been loaded and saved. --->
21            <cfset EntitySave(RoleDbObj)>
22    </cfoutput>
23</cftransaction>

2) Inserting records into a table that contains a relationship

We can load an object using EntityLoad several different ways:

A) Load a CF-ORM object using the primary key

BlogRefObj is the variable that we are storing the object in. We are loading the Blog table. The numeric value, which is 1, is the value of its primary key. You can also use dynamic values, such as [currentRow] when looping through a recordset.

view plain about
1<cfset BlogRefObj = entityLoadByPK("Blog", 1)>

B) Load a CF-ORM object using filters, similar to the WHERE clause in a query

Here, we are loading the Users table. UserName is the name of the column that we are querying, and "gregory" is the value that we are searching for. Notice the "true" argument at the tail end of this code. This argument allows us to load a single record, which is necessary when we pass back the object to the EntityNew's set method.

view plain about
1<cfset UserRefObj = entityLoad("Users", { UserName = "gregory" }, "true" )>

2A) Code Example using LoadByPk

  • Get all of the search statistics in the BlogCfc table
  • Wrap the code block with transaction tags
  • Loop through the getTblSearchStats query object using a cfoutput query tag and:
    • Load the new SearchQuery object using the loadByPk method where the primary key is equal to 1 (there is only one blog record)
    • Create a new SearchQueryObj entity (SearchQuery is the name of the persistent CFC)
    • Pass the BlogRefObj object to populate the BlogRef column using the set method.
    • Use the set methods to explicity insert values in the columns that don't contain references
    • Finally, save the SearchQueryObj entity with EntitySave

view plain about
1<!--- Get the Post Categories from BlogCfc --->
2<cfquery name="getTblSearchStats" datasource="#dsn#">
3    SELECT
4    searchterm
5    ,searched
6    ,blog
7    FROM tblblogsearchstats
8</cfquery>
9
10<!--- Use a transaction --->
11<cftransaction>
12    <cfoutput query="getTblSearchStats">
13        
14        <!--- Load the blog table and get the first record (there only should be one record at this time). This will pass back an object with the value of the blogId. This is needed as the setBlogRef is a foreign key and for some odd reason, ColdFusion or Hibernate must have an object passed as a reference instead of a hardcoded value. --->
15        <cfset BlogRefObj = entityLoadByPK("Blog", 1)>
16
17        <!--- Load the entity. --->
18        <cfset SearchQueryObj = entityNew("SearchQuery")>
19        <!--- Use the entity objects to set the data. --->
20        <cfset SearchQueryObj.setBlogRef(BlogRefObj)>
21        <cfset SearchQueryObj.setSearchQuery(searchterm)>
22        <cfset SearchQueryObj.setDate(searched)>
23
24        <!--- Save it. Note: updates will automatically occur on persisted objects if the object notices any change. We don't have to use entity save after the Entity has been loaded and saved. --->
25        <cfset EntitySave(SearchQueryObj)>
26
27    </cfoutput>
28</cftransaction>

2B) Code Example using EntityLoad filter methods

  • Get all of the roles from the tblBlogRoles table
  • Wrap the code block with transaction tags
  • Loop through the tblBlogRoles query object using a cfoutput query tag and:
    • Load one record from the users object where the user name is equal to the user name in the tblUserRoles query
    • Create a new UserRole entity (UserRole is the name of the persistent CFC)
    • Pass the UserRoleRef object to populate the UserRef column using the set method.
    • Use the set methods to explicity insert values in the columns that don't contain references
    • Finally, save the UserRole entity with EntitySave

view plain about
1<!--- Get the Users from BlogCfc --->
2<cfquery name="getTblUserRoles" datasource="#dsn#">
3    SELECT
4    username
5 ,roleidfk
6    ,role
7    FROM tbluserroles
8</cfquery>
9
10<!--- Use a transaction --->
11<cftransaction>
12    <cfoutput query="getTblUserRoles">
13            <!--- Get the user by the username in the Users Obj. --->
14            <cfset UserRefObj = entityLoad("Users", { UserName = username }, "true" )>
15            <!--- Load the entity. --->
16            <cfset UserRoleDbObj = entityNew("UserRole")>
17            <!--- Use the entity objects to set the data. --->
18            <cfset UserRoleDbObj.setUserRef(UserRefObj)>
19            <cfset UserRoleDbObj.setDate(now())>
20
21            <!--- Save it. Note: updates will automatically occur on persisted objects if the object notices any change. We don't have to use entity save after the Entity has been loaded and saved. --->
22            <cfset EntitySave(UserRoleDbObj)>
23    </cfoutput>
24</cftransaction>

Dealing with problems

Unless you're perfect, you will likely encounter problems once you try to populate your new tables. I will share a few solutions to common problems.

Inserting data that may have null values in columns that have relationships

If you have columns that may have null values that contain relationships, you need to use the missingrowignored="true" argument

For example, in my Comment table, I need to have either a known blog user or a commenter, attached to a comment record. A blog user is typically the administrator or super-user of the blog, and a commenter is a user that is a general user making a comment. The Blog user is able to have more functionality, and can perform actions on a comment; whereas the blog commenter has limited functionality and can just make a comment. My Comment table needs one of these references to be defined but does not require both- unless of course, the blog user is also the commenter. These two columns need to accept a null value.

To allow this, I am using the missingrowignored="true" argument.

view plain about
1<cfcomponent displayName="Comment" persistent="true" table="Comment" output="no" hint="ORM logic for the new Comment table">
2    
3    <cfproperty name="CommentId" fieldtype="id" generator="native" setter="false">
4    <!--- Many comments for one post --->
5    <cfproperty name="PostRef" ormtype="int" fieldtype="many-to-one" cfc="Post" fkcolumn="PostRef" cascade="all" lazy="false">
6    <!--- Many comments for one User --->
7    <cfproperty name="UserRef" ormtype="int" fieldtype="many-to-one" cfc="Users" fkcolumn="UserRef" cascade="all" lazy="false" missingrowignored="true">
8    <!--- Many comments for one commenter --->
9    <cfproperty name="CommenterRef" ormtype="int" fieldtype="many-to-one" cfc="Commenter" fkcolumn="CommenterRef" cascade="all" lazy="false" missingrowignored="true">
10    ...

The cryptic coldfusion orm java.lang.String error

This error message can manifest itself in many ways. The last part of the message String will be whatever datatype you passed to the set method. For example, it can be coldfusion orm java.lang.Int if you passed in an int, etc.

If you're getting this error- you likely forgot to pass in an object to the set method. Objects must be passed to columns that contain relationships! Use the EntityLoad method to load a CF-ORM object, and pass that object to the set method instead of setting an explicit value.

Issues with constraints

Cannot insert duplicate key in object xxx. The duplicate key value is (xxx).' error

Check your relationships and remember that any time that you encounter a one in your relationships (many-to-one for example), a unique constraint is placed on that key.

While CF-ORM will create relationships and constraints for you, CF-ORM will not remove existing constraints- even if CF-ORM created the constraint in the first place.

While creating tables and populating records, you'll probably have to change the existing relationships after encountering errors. When you change the relationships, make sure that you delete the existing relationships and constraints. I'll provide some helpful scripts that I used with SQL Server.

Script to delete an existing constraint (replace TableName with the table that your working on)

view plain about
1ALTER TABLE TableName DROP ConstraintName
Script to delete records and set the primary key back to a 1:
view plain about
1DELETE FROM TableName;
2DBCC CHECKIDENT ('[TableName]', RESEED, 0);

Script to determine existing relationships

view plain about
1select name 'ForeignKeyName',
2 OBJECT_NAME(referenced_object_id) 'RefrencedTable',
3 OBJECT_NAME(parent_object_id) 'ParentTable'
4from sys.foreign_keys
5where referenced_object_id = OBJECT_ID('TableName') or
6 parent_object_id = OBJECT_ID('TableName')

Remove all relationships from the database. This is helpful if you just want to delete everything and start over again.

view plain about
1SELECT 'ALTER TABLE ' + Table_Name +' DROP CONSTRAINT ' + Constraint_Name
2FROM Information_Schema.CONSTRAINT_TABLE_USAGE

The 'The ALTER TABLE statement conflicted with the FOREIGN KEY constraint' errors and ghost relationships

This particular error drove me crazy. I was receiving this constraint error for hours, and no matter what I did- I could not make it go away. I could not find the problematic relationship and deleted all of the constraints in the database, yet this error would not go away.

However, I did not delete the records that were in the database. What happened here was that CF-ORM was trying to create a new constraint based upon the recent changes that I applied to the persistent CFCs. Since there were records in the database that did not meet the new referential integrity, an error was raised. The database was enforcing referential integrity and could not create the constraint as it would result in orphaned records. CF-ORM could not create the new constraint and reported the error.

The solution to this problem is to delete the existing records from the table and to start over.

Other Resources

I highly recommend getting the ColdFusion ORM book written by John Whish. Although it was written for ColdFusion 9, the materials are still relevant and it is the most in-depth CF-ORM resource that I have found.

The cfml.slack.com page also has an active ORM channel with a lot of ORM experts. If you need a solution that we have not covered, try to pose the question there. Of course, you're always welcome to make a comment here if you're in need of help!

This entry was posted on December 28, 2019 at 7:15 PM and has received 1142 views.

Understanding ColdFusion ORM Relationships

Configuring ColdFusion ORM

The first thing we need to do in order to use CF-ORM is to place the following code in the Application.cfc template.

  • The first line of code below directs ColdFusion to reload CF-ORM every time the page is refreshed.
    • While initially setting up CF-ORM, you will want to include this argument in your code
    • Once everything is ready for production, you should remove this line of code as consumes more resources
  • The ormenabled setting enables CF-ORM.
  • The dbcreate = "update" argument is used to have CF-ORM create the database tables and relationships for you.
  • The cfclocation argument is optional and it used when you keep all of your persistent cfc's in a particular location. Setting the cfclocation argument should also marginally improve performance as without it ColdFusion will search the entire folder structure to find any persistent cfc's.

view plain about
1<cfset ORMReload()>
2    <cfset this.ormenabled = "true">
3    <cfset this.datasource = "GregorysBlog">
4    <!--- Allow ColdFusion to update and create the tables when they do not already exist. --->
5    <cfset this.ormSettings.dbcreate = "update">
6    <cfset this.ormSettings.cfclocation = expandPath("/common/cfc/db/model/")>

Creating the tables and the relationships using persistent CFC's

The code below is a persistent CFC that will be used to create the table and its relationships. Like other CFC's, this CFC has the initial component declaration with the addition of the persistent argument which is set to true, and the properties map the column names. We'll go over the relationships in-depth later in the article.

  • Examining the PostId
    • The PostId is our primary key, it is annotated with the fieldtype="id"
    • generator determines how to increment the primary key
    • See Map the properties for more information
  • The ormtype is the datatype. These are generic values since CF-ORM is database agnostic. If you want finer control, you can substitute the ormtype with sqltype.
  • length specifies the column length. The default length for string datatypes is 255 characters.
  • I will not cover the details of the other properties here, refer to Map the properties for more information.
view plain about
1<cfcomponent displayName="Post" persistent="true" table="Post" output="no" hint="ORM logic for the new Post table">
2<cfproperty name="PostId" fieldtype="id" generator="native" setter="false">
3    <!--- Many posts for one blog. --->
4    <cfproperty name="BlogRef" ormtype="int" fieldtype="many-to-one" cfc="Blog" fkcolumn="BlogRef" cascade="all">
5    <cfproperty name="UserRef" ormtype="int" fieldtype="many-to-one" cfc="Users" fkcolumn="UserRef" cascade="all">
6    <!--- The ThemeRef is optional. I am not going to make a relationship here as it will make a required constraint. --->
7    <cfproperty name="ThemeRef" ormtype="int">
8    <cfproperty name="PostUuid" ormtype="string" length="35" default="">
9    <cfproperty name="PostAlias" ormtype="string" length="100" default="">
10    <cfproperty name="Title" ormtype="string" length="125" default="">
11    <cfproperty name="Headline" ormtype="string" length="110" default="">
12    <cfproperty name="Body" ormtype="string" sqltype="varchar(max)" default="">
13    <cfproperty name="MoreBody" ormtype="string" sqltype="varchar(max)" default="">
14    <cfproperty name="AllowComment" ormtype="boolean" default="true">
15    <cfproperty name="NumViews" ormtype="int" default="">
16    <cfproperty name="Mailed" ormtype="boolean" default="false">
17    <cfproperty name="Released" ormtype="boolean" default="false">
18    <cfproperty name="Date" ormtype="timestamp">
19</cfcomponent>

The cfproperty name argument

The cfproperty name argument can either be the name of the physical column in the database, the name of a CFC, or a reference to a new object that will not be placed into the database. We'll cover this important aspect later in the post when we discuss the fkcolumn argument.

The field type argument maps the relationships

CF-ORM has the following relationships: one-to-one: one-to-many: many-to-one: and many-to-many.

The order of the relationship keywords

When you map a relationship, the keyword (one or many) to the left is applied to the cfc that you're working on- and the keyword to the right is applied to the table that you're mapping to.

For example, in the Post.cfc, the many-to-one relationship created below signifies that there are many posts (the CFC that is being worked on) for one Blog (the table that I am making a reference to).

view plain about
1<cfproperty name="BlogRef" ormtype="int" fieldtype="many-to-one" cfc="Blog" fkcolumn="BlogRef" cascade="all">

Understanding the one and the many

The one keyword signifies that this must be unique. When a one-to-many relationship is found, CF-ORM will create a unique key in the database for the table that is being mapped by the CFC. So, in the case of the UserRef column (which maps to a user), there can be many users for a one post. If the mapping for UserRef was one-to-one, a duplicate error will be raised when you try to insert the same user. Since the same author can make many posts, the many-to-one relationship must be used here. If you are receiving a duplicate error from the database when inserting new records, be sure to check your mapping a change any erroneous one-to-one mapping relationships.

one-to-one relationship

A one-to-one relationship is often applied to two tables when there is a set of optional data that is not required. For example, the PostRef, found in the code below, is a one-to-one relationship. I have a Post table that may have an optional image or video. The image or video is not required to be in the post table as there are posts that do not have any images or video. In order to consolidate the post table, I wanted to store images or video into a generic Media table, which is a different type of a 'thing'. Having the one to one relationship here helps me reduce the length of the column in the Post table, and allows me to organize the concept of two different 'things', i.e. a post and its associated media. Additionally, this relationship is quite useful for dropdowns; I can query the entire media table to make a dropdown list to allow the user to change the image or video.

Often, I am surprised that a lot of folks have a negative impression of the one to one relationship. This relationship is often misunderstood. I find the one to one relationship to be quite useful. Since this is not relevant to this article, I'll reserve further elaboration for another article.

The many-to-one relationship

The MimeTypeRef in the code below has a many-to-one relationship. This could be a little confusing, you might rationally conclude that one image or video (the CFC that we are working on) would have one mime-type, but remember that whenever the one keyword is found, it signifies that it must be unique record. If we did put a one-to-one relationship here, we would receive a duplicate error message whenever we tried to put in the same mime type for a new record. With the many-to-one mapping, we can have many videos and images for one mime type.

view plain about
1<cfcomponent displayName="Media" persistent="true" table="Media" output="no" hint="ORM logic for the new Media table, can be an image or a video.">
2    <cfproperty name="MediaId" fieldtype="id" generator="native" setter="false">
3    <!--- There can be many images and videos for a post --->
4    <cfproperty name="PostRef" ormtype="int" fieldtype="one-to-one" cfc="Post" fkcolumn="PostRef" cascade="all" missingrowignored="true">
5    <!--- Many images can have one mime type (if you have many-to-one you'll recive a 'Cannot insert duplicate key in object 'dbo.Media'. The duplicate key value is (11).' error ')--->
6    <cfproperty name="MimeTypeRef" ormtype="int" fieldtype="many-to-one" cfc="MimeType" fkcolumn="MimeTypeRef" cascade="all" missingrowignored="true">
7    <cfproperty name="FeaturedMedia" ormtype="boolean" default="false" hint="Is this an image or video that should be at the top of a blog post?">
8    <cfproperty name="MediaPath" ormtype="string" length="255" default="">
9    <cfproperty name="MediaUrl" ormtype="string" length="255" default="">
10    <cfproperty name="MediaTitle" ormtype="string" length="255" default="" hint="Also used for the alt tag.">
11    <cfproperty name="MediaWidth" ormtype="string" length="25" default="">
12    <cfproperty name="MediaHeight" ormtype="string" length="25" default="">
13    <cfproperty name="MediaSize" ormtype="string" length="25" default="">
14    <cfproperty name="MediaVideoDuration" ormtype="string" default="" length="25" hint="Used for video types">
15    <cfproperty name="MediaVideoCoverUrl" ormtype="string" default="" length="255" hint="The image URL to cover the video. Used for video types">
16    <cfproperty name="MediaVideoSubTitleUrl" ormtype="string" default="" length="255" hint="The URL to the subtitle file. Used for video types">
17    <cfproperty name="Date" ormtype="timestamp">
18</cfcomponent>

The one-to-many relationship

Simply put, the one-to-many relationship is the inverse of the many-to-one relationship. That is, there is one thing in the CFC that we are working on, to many things that we are mapping to. For example, in a blog, one Author can have many Posts. I don't often use this relationship as I tend to make the relationships from the other side (many-to-one).

The many-to-many relationship

A many-to-many relationship could be used to map a blog category to a blog post like so:

view plain about
1<cfcomponent displayName="Category" persistent="true" table="Category" output="no" hint="ORM logic for the new Category table">
2    <cfproperty name="CategoryId" fieldtype="id" generator="native" setter="false">
3    <!--- Many categories for one blog --->
4    <cfproperty name="PostRef" ormtype="int" fieldtype="many-to-many" cfc="Post" fkcolumn="PostRef" cascade="all">
5    <cfproperty name="CategoryUuid" ormtype="string" length="75" default="">
6    <cfproperty name="CategoryAlias" ormtype="string" length="75" default="">
7    <cfproperty name="Category" ormtype="string" length="125" default="">
8    <cfproperty name="Date" ormtype="timestamp">
9</cfcomponent>

However, I replaced this many-to-many relationship with several many-to-one relationships placed into a junction table.

A Junction table is also commonly defined as a:

  • cross-reference table
  • bridge table
  • join table
  • map table
  • intersection table
  • link table

While not technically correct, I personally refer to this as a lookup table as it closely matches the lookup table definition used in computer science (a table that contains a simple array).

Whatever you may call it, a many-to-many, or a set of many-to-one relationships used in a junction table are bi-directional.

Instead of using a many-to-many relationship, I used a many-to-one relationship to map a Post with a Category with a PostCategoryLookup junction table like so:

view plain about
1<cfcomponent displayName="PostCategoryLookup" persistent="true" table="PostCategoryLookup" output="no" hint="ORM logic for the new PostCategoryLookup table">
2    <cfproperty name="PostCategoryLookupId" fieldtype="id" generator="native" setter="false">
3    <!--- There can be many posts and categories --->
4    <cfproperty name="PostRef" ormtype="int" fieldtype="many-to-one" cfc="Post" fkcolumn="PostRef" singularname="Post" lazy="false" cascade="all">
5    <cfproperty name="CategoryRef" ormtype="int" fieldtype="many-to-one" cfc="Category" fkcolumn="CategoryRef" cascade="all">
6    <cfproperty name="Date" ormtype="timestamp">
7</cfcomponent>

Mapping with the cfc and fkcolumn arguments

The cfc and fkcolumn argument determines the table and column what you're mapping to.

The cfc argument is simple and needs no further explanation. It is the table that you want to create a foreign key too. The fkcolumn is not so simple, rather I find it to be an unnecessarily complex beast.

The fkcolumn argument

The fkcolumn argument takes on different characteristics depending on how its name was set.

If the cfproperty name is an ORM object reference

If we used the name as a object reference, such as Posts, we must use a name that is not already in use in the database, or the name of an existing CFC. A lot of documentation on the web uses the plural name of the table, such as the name that I used- i.e. Posts

However, John Whish, the author of the excellent book ColdFusion ORM, suggests using 'fk_TableName' to signify that the reference is a foreign key. If he applied his naming convention with my RelatedPost table, for example, he would use fk_RelatedPost. No matter what approach you use, what's important to recognize is that this 'Posts' or 'fk_RelatedPost' name is just a reference, and it won't actually exist in the database.

If the name is a reference, the fkcolumn argument should be set to the name of the primary key of the cfc that you're mapping to. Here the cfc value is Post and the fkcolumn is PostId. Even though the cfproperty name is Posts, the column that will be created into the RelatedPost table will be the value of the fkcolumn, i.e. BlogId. However, Posts will be the column when I dump out the CFC object.

Posts as an object reference in the persistent CFC:

view plain about
1<cfcomponent displayName="RelatedPost" persistent="true" table="RelatedPost" output="no" hint="ORM logic for the new RelatedPost table. This is used to indicate the related posts within the forum.">    
2    <cfproperty name="RelatedPostId" fieldtype="id" generator="native" setter="false">
3    <!--- There are many related posts for one post --->
4    <cfproperty name="Posts" ormtype="int" fieldtype="many-to-one" cfc="Post" fkcolumn="PostId" singularname="Post" cascade="all" lazy="false">
5    <!--- There is one related post that we are pointing to --->
6    <cfproperty name="Date" ormtype="timestamp">        
7</cfcomponent>

PostId is stored as column in the database:

Posts is the item in the CFC database object:

This works fine when working with a single foreign key reference to the Post.PostId column, but what if we wanted more than one reference to Post.PostId?

The RelatedPost table maps a relationship to a single post to all other posts that relate to it. At the bottom of may of my own posts, you will see a Related Resources label that has links to other posts. The RelatedPost database table was designed to handle this. So here, we need two references to the Post table's primary key- PostId

However, when we use more than one PostId in the fkcolumn, yet use two objects as the cfproperty name (Posts and RelatedPosts), we will get an error.

view plain about
1<cfcomponent displayName="RelatedPost" persistent="true" table="RelatedPost" output="no" hint="ORM logic for the new RelatedPost table. This is used to indicate the related posts within the forum.">
2    <cfproperty name="RelatedPostId" fieldtype="id" generator="native" setter="false">
3    <!--- There are many related posts for one post --->
4    <cfproperty name="Posts" ormtype="int" fieldtype="many-to-one" cfc="Post" fkcolumn="PostId" singularname="Post" cascade="all" lazy="false">
5    <!--- There is one related post that we are pointing to --->
6    <cfproperty name="RelatedPosts" ormtype="int" fieldtype="one-to-one" cfc="Post" fkcolumn="PostId" singularname="Post" cascade="all" lazy="false">
7    <cfproperty name="Date" ormtype="timestamp">
8</cfcomponent>

This is the error message raised when there are more than one references to the Post.PostId column in the database: Repeated column in mapping for entity: RelatedPost column: PostId (should be mapped with insert="false" update="false")

This error signifies that this column needs to be a read-only post. However, as with many other ORM related errors, this is incorrect. The problem here is that CF-ORM is trying to create two BlogId references into the RelatedPost table. There is several ways to fix this, but the best way that I found is to use the fkcolumn to point the foreign key back to itself.

Using the fkcolumn to point back to its self

Another way to use the cfproperty name and the fkcolumn is to create a new column into the database using the name attribute, and then use the same column name in fkcolumn to point back to itself. Let's look at the code:

view plain about
1<cfcomponent displayName="RelatedPost" persistent="true" table="RelatedPost" output="no" hint="ORM logic for the new RelatedPost table. This is used to indicate the related posts within the forum.">
2    <cfproperty name="RelatedPostId" fieldtype="id" generator="native" setter="false">
3    <!--- There are many related posts for one post --->
4    <cfproperty name="PostRef" ormtype="int" fieldtype="many-to-one" cfc="Post" fkcolumn="PostRef" cascade="all" lazy="false">
5    <!--- There is one related post that we are pointing to --->
6    <cfproperty name="RelatedPostRef" ormtype="int" fieldtype="one-to-one" cfc="Post" fkcolumn="RelatedPostRef" cascade="all" lazy="false">
7    <cfproperty name="Date" ormtype="timestamp">
8</cfcomponent>

Instead of creating an object reference using the name attribute, we are using PostRef and RelatedPostRef to create two new database columns. The cfc that we are pointing to remains the same, we want to use the primary key found in the Post table, and we are also using the same that we used in the fkcolumn to point back to itself.

This creates two new columns, the PostRef and the RelatedPostRef into the database, and creates the relationship to the PostId using these new columns. Viola! the error is gone, and now the database model is an exact replica of the ORM object model!

The PostRef relationship in the database

The RelatedPostRef relationship in the database

And the ORM Object that is now identical to the database model

I must admit that I am not a CF-ORM expert and stumbled upon this approach while discovering different ways to solve some issues. However, it is now my preferred approach. It is my personal preference to use TableNameRef for all of my foreign keys, and use TableNameId for my primary keys. I personally think that it is easier to read, and it allows me to quickly identify what I am working with. I have been using the same name database naming conventions for many many years. I also like the fact that both my object and database models are now uniform.

Final Relationship Notes

You will notice that anytime we create a new relationship with CF-ORM, the columns that hold the relationships will be placed at the end of the table. The order of the columns indicated with the persistent CFC will not be enforced. However, you can change the order of the columns after the tables are created, and CF-ORM won't modify the new order.

There is a lot of flexibility with CF-ORM. However, I personally think that the implementation is confusing and would prefer that CF-ORM be more opinionated. One of the reasons why I don't like PHP is that there are far too many ways in PHP to perform a task. This results in added complexity. There is a lot of room for improvement with CF-ORM. I wish that there was an argument in allowed in the cfproperty to be used as a foreign key, such as a foreignKey="true", or something like fkeycolumn="this" or "self".

This entry was posted on December 28, 2019 at 6:44 PM and has received 999 views.

Introducing ColdFusion ORM

ColdFusion ORM can be used to create new tables into an existing database but is not without challenges.

Introducing ColdFusion ORM

In this 3 part series; I will show you how to create new tables into an existing database and how to populate the records into the new tables using ColdFusion ORM. I will be using live examples and show you the steps that I used in Galaxie Blog when converting the original BlogCfc database into a new set of tables. Here we will introduce CF-ORM, cover alternatives, and discuss solutions that were used to overcome some common pitfalls when using CF-ORM.

When should ColdFusion ORM be used?

CF-ORM may be a viable solution when you want to have the widest support of databases for your application. I am incorporating CF-ORM into Galaxie Blog as I want the end-users to be able to use their own database of choice. Since version 9, CF-ORM is already included in ColdFusion, there is nothing new needed to be loaded, and CF-ORM should support any modern database. Another benefit of using CF-ORM, or any ORM product, is that the database logic is decoupled from the business logic of the application. I can't understate this benefit enough- this approach is vastly more efficient than having to rewrite the SQL queries in multiple areas of the business logic every time you add or remove a column from the database. I created my own CF-ORM package for SQL Server for this very reason.

ColdFusion ORM Supported Databases

RDBMS ORM Dialect
Apache Derby Derby
Informix Informix
IBM DB2 DB2
IBM DB2 AS400 DB2AS400
IBM DB2 OS390 DB2OS390
Postgre SQL PostgreSQL
Microsoft Access MicrosoftSQLServer
Microsoft SQL Server MicrosoftSQLServer
MySQL MySQL
MySQL InnoDB MySQLwithInnoDB
MySQL MyISAM MySQLwithMyISAM
Oracle 8i Oracle8i
Oracle 9i Oracle9i
Oracle 10g Oracle10g
Sybase Sybase
Sybase Anywhere SybaseAnywhere

ColdFusion ORM Supported Databases with a Custom Dialect

The following databases should be supported as long as you provide the custom dialect using the fully qualified class name.

RDBMS ORM Dialect
Oracle (any version) org.hibernate.dialect.OracleDialect
Oracle 11g org.hibernate.dialect.Oracle10gDialect
Microsoft SQL Server 2000 org.hibernate.dialect.SQLServerDialect
Microsoft SQL Server 2005 org.hibernate.dialect.SQLServer2005Dialect
Microsoft SQL Server 2008 org.hibernate.dialect.SQLServer2008Dialect
SAP DB org.hibernate.dialect.SAPDBDialect
Informix org.hibernate.dialect.InformixDialect
Hypersonic SQL org.hibernate.dialect.HSQLDialect
H2 Database org.hibernate.dialect.H2Dialect
Ingres org.hibernate.dialect.IngresDialect
Progress org.hibernate.dialect.ProgressDialect
Mckoi SQL org.hibernate.dialect.MckoiDialect
Interbase org.hibernate.dialect.InterbaseDialect
Pointbase org.hibernate.dialect.PointbaseDialect
FrontBase org.hibernate.dialect.FrontbaseDialect
Firebird org.hibernate.dialect.FirebirdDialect

However, ColdFusion ORM is not without its challenges

While having CF-ORM support all database platforms is terrific; using CF-ORM may lock you into using a particular ColdFusion version. CF-ORM functionality changes depending upon the version of ColdFusion. CF-ORM on ColdFusion 9 is quite a bit different than CF-ORM on ColdFusion 2016. So, while you may be supporting a wide variety of database platforms, you may be stuck on a particular ColdFusion version. There are also differences between CF-ORM between ColdFusion, and its open-source sister, Lucee.

Also, CF-ORM has a slew of other challenges. Error reporting is confusing. Since CF-ORM is built upon Hibernate, it does not have the error messages that we typically expect out of a ColdFusion product. Error messages are not always available and are often confusing. The documentation is sparse, and at times misleading. Take for example the cfproperty documentation on the Adobe site. Most of the properties are not documented at all. Two-thirds of the description columns are blank.

Additionally, if you dig around and find documentation for a certain feature, it may not work at all! For example, I wanted to eliminate the database constraint for some of the database columns using the constrained="false" argument. Adobe's own cfproperty documentation mentioned the constrained property, but gave no description. Finally, I was able to find some documentation on the constrained property on another site, however, no matter what I did, I could not get the argument to work. I also went to the ORM channel on cfslack to ask for help, and no one knew how to get it to work.

Finally, another issue is that just like ColdFusion UI, CF-ORM is tied to Adobe ColdFusion and you're limited in what changes you can make. You'll have to wait until a new ColdFusion version to come out before you can upgrade to a new version of Hibernate.

ColdFusion ORM alternatives

While I have not used them yet myself, I have heard good things about Quick and cbOrm. Quick is written in ColdFusion and it handles errors much better than CF-ORM. cbOrm is an extension of CF-ORM, and Ortus has added a lot of functionality and flexibility to the underlying Hibernate engine that CF-ORM uses. I won't cover either Quick or cbOrm here, but they are both worth recommending if you want to avoid CF-ORM, especially if you're already using the ColdBox framework.

Since my project requires that I support as many database platforms possible, and I don't want to include another library, such as ColdBox, I am using CF-ORM and will show you some of the solutions that I used to overcome common CF-ORM pitfalls.

In the next article, we'll jump in and look at the code....

This entry was posted on December 28, 2019 at 6:30 PM and has received 965 views.

Playing your own video content with Galaxie Blog


How to integrate your own video content to Galaxie Blog

Galaxie Blog supports the following video types: .mp3 , .mp4, .ogg, .ogv and .webm. If you have the video in another legacy format, you'll need to convert it to a modern format to play it in Galaxie Blog.

If you have a supported video format, you can either upload the video by clicking on the Add Enclosure, or by using the file uploader in the Galaxie Blog administrative interface. However, the Add Enclosure method will only work if the video is smaller than around 3MB.. You can use your own FTP tools to upload the video if that is what you prefer.

You can also host videos that are stored on a different server, but you'll need to specify the cross-origin true argument using a Galaxie Blog Post Directive.

Though completely optional, if you want the video's to be optimized for different client devices, just like responsive images, you can use up to three videos with different sizes. Galaxie Blog supports 576p, 720p, and High Definition 1080p video formats.

Once you have the video(s) on a server, you will need to use the proper URL xml post directives

The following Galaxie Blog Post XML Directives were used to play the video that you see on top of this blog post.

  • The videoType directive is necessary. Here I set it to ".mp4"
  • The videoPosterImageUrl directive completely optional. This is used to 'cover' the video with an image until it is played. I used an image of the video to cover the video and specified the URL.
  • Since my video format is 720p, I used the mediumVideoSourceUrl directive.
    • You can use one argument, two, or all three to have a responsive video. You will need at least one argument for the video to play
    • Use smallVideoSourceUrl for 576p
    • Use mediumVideoSourceUrl for 720p
    • Use largeVideoSourceUrl for 1080p
    • Or use all three arguments if you want the video to be responsive
      • This video is hosted on the same domain, so I used false for the cross-origin argument. If you are integrating a video that is hosted on another server, set the videoCrossOrigin to true.

This snippet of code will initialize our Plyr and it will play the video file within Galaxie Blog. The video will be lazy loaded, and will only load once the page loads and the video is downloaded to the client.

As with all Galaxie Blog video's, the video will automatically play when your looking at an individual post, and requires the user to click on the play button when your looking at the post from the main blog page. You can easily change this behavior by editing the code, or by making a suggestion here.

Note: the xml post directives will be deprecated in a later version

This entry was posted on December 16, 2019 at 1:32 PM and has received 492 views.




Footer Logo

Your input and contributions are welcomed!

If you have an idea, BlogCfc based code, or a theme that you have built using this site that you want to share, please contribute by making a post here or share it by contacting us! This community can only thrive if we continue to work together.

Images and Photography:

Gregory Alexander either owns the copyright, or has the rights to use, all images and photographs on the site. If an image is not part of the "Galaxie Blog" open sourced distribution package, and instead is part of a personal blog post or a comment, please contact us and the author of the post or comment to obtain permission if you would like to use a personal image or photograph found on this site.

Credits:

Portions of Galaxie Blog are powered on the server side by BlogCfc, an open source blog developed by Raymond Camden. Revitalizing BlogCfc was a part of my orginal inspiration that prompted me to design this site. Some of the major open source contributers to BlogCfc include:

  1. Peter Farrell: the author of 'Lyla Captcha' that is used on this blog.
  2. Pete Freitag: the author of the 'ColdFish' code formatter that is also used on this blog.

Version:

Galaxie Blog Version 1.50 November 22 2019