This August I rolled out a new feature for Conductor: Asset References. In short, Conductor now provides a means of tracking which Pages, News, and/or Events make use of a given Asset. This feature is certainly helpful in both trouble-shooting your site and to help you understand where the content is being used.
I’m going to step through the system development that went into this feature.
Conductor is backed by a Relational Database responsible for storing the content of the site. As part of the database, we have a table for Pages, Events, and News. Each of those tables can have one or more of the following fields: content, excerpt, “parts” and “meta-fields”; A reference to an Asset can be found in any of the preceding attributes an HTML link, but not all of the tables have the same attributes (see below).
As a result there is a bit of a challenge; I don’t want to write three separate functions that looked for references to Assets (i.e. one for Events, one for News, etc.). So lets do a little bit of abstraction, blur your eyes if you will, and say that the heterogeneous Pages, Events and News are all “ThingsWithContent”; This is sometimes referred to as Duck-Typing.
Calculating an asset reference is not the primary role of a “ThingWithContent”; Managing content is. So I’m going to create another table called AssetReference who’s sole purpose is to record the relation between ThingsWithContent and Assets by using a many-to-many relationship.
An AssetReference is created by taking a “ThingWithContent” and then checking each of it’s attributes that could have references to an Asset. This process is run each time a “ThingWithContent” is created or updated.
Since a Page, News, and Event’s primary role is not checking for AssetReferences, I wanted to loosely couple the AssetReferences calculation; The goal of loose coupling is to insulate the coupled objects from any changes in the other. By implementing the Observer Pattern, I’m able to loosely couple a ThingWithContent to an AssetReference. I created a ReferenceObserver which is notified when a ThingWithContent is created or updated. The ReferenceObserver then builds the AssetReferences by inspecting the observed ThingWithContent and only processing the attributes (i.e. content, excerpt, parts, meta-fields) that the ThingWithContent has implemented. In short the ReferenceObserver can take any type of ThingWithContent and successfully check for AssetReferences.
Each of the implemented fields that might have an AssetReference are then checked by using a Regular Expression to find all of the links to an Asset. Regular expressions are a powerful tool for finding and even replacing text. If you haven’t seen them before, they are extremely daunting. And if you’ve seen them before, they are merely daunting. The regular expression I use is as follows:
I’m going to break this down so you can understand what’s going on. To simplify, I’m going to remove most of the back-slashes (\). They are a technical necessity but in this instance a learning obstacle, so I’ll remove them.
Then I’m going to remove the leading and trailing forward-slash (/) as those are used to indicate a regular expression.
This is a bit more legible but still needs explanation. See the “/assets/(a-conductor-site.nd.edu/)?”, what that chunk says is to find text that includes “/assets/” and optionally includes “a-conductor-site.nd.edu/”; The parenthesis indicates a Group of text and the question mark means the Group is optional. The next chunk (\d+)/ means a Group of one or more numbers; The \d stands for any digit and the plus-sign (+) means one or more of the preceding character.
For example: “/assets/22/” would match the patterns, but “/assets/2a/” would not.
Once I have the asset URLs, it is a matter of connecting the Asset to the ThingWithContent.
By keeping the responsibility of determining AssetReferences away from the ThingWithContent, I’m able to keep the core responsibility of a ThingWithContent intact (i.e. provide content). By use of object inspection, I’m able to handle a heterogeneous set of ThingWithContent. And by use of Regular Expressions, I’m able to find and register links to multiple assets.