One of the first issues developers encounter when building a plugin for the Mura CMS is in finding a place to store data. It is possible to create a script for adding tables to the Mura site's datasource, or even generating the tables for a completely separate datasource, but often that is a level of complexity that just isn't needed or desired. There are other options, such as flat files or XML documents, but they have their own issues and aren't always scalable or search-friendly.
Last week a little light went off in my head about something I hadn't used a great amount ... Mura's Extended Attributes ... and I asked Matt Levine of Blue River if it was possible to create an Extended Attribute set without linking it to a particular content type. A much bigger light went off in Matt's head, and he whipped up some brand new and very cool code and forwarded it back to me. The functionality would still be what I'd call 'experimental'; in fact as you read this it has only just been added to the Mura core. That said, it works well and is a powerful, flexible addition to Mura.
The work is actually based on an earlier modification I had discussed with Matt, that of being able to search and sort extended attributes by data type. Matt recently accommodated this by adding typed columns to the extended data table. Now in Mura when you assign a validation type to an extended attribute such as 'number' or 'date', the values entered will be added to typed columns as well as the generic attribute column. The columns are indexed, so this makes well-performing custom queries of the data sets possible.
The next step was creating the ability to create "Custom" data sets, which Matt did by adding a new Class Extension type of "Custom" and building an associated object to manage it. To begin, you first create your custom Extended Attribute set manually or, more likely, via code. To learn how to do this via code, I'd suggest downloading the first plugin I ever built for Mura, the Google Site Maps Generator. The /plugin/plugin.cfc file creates an Extended Attribute set on the fly, and should include enough information to get you going (if not, please request a post on this and I'll see what I can put together). The one key ingredient in doing this is that the BaseTable attribute is set to "Custom", as is the DataTable attribute. Creating the set manually first will tell you how the data should appear in the tclassextend/tclassextendattributes tables.
For this example, assume that a "Custom" Extended Attribute set exists called "MyPluginData", and that it has 3 attributes ("Name", no validation type;"DateUpdated", date validation type;"Gender", numeric validation type). It looks like this:
To interact with the Extended Attribute data I've built two example functions:
I can now add data to my Extended Attribute set using:
... and then retrieve it using the 'getMyData' function:
There a couple of important points in this process:
- The 'setID()' function on your custom Extended Attribute set is of course crucial to identifying your content. This can be any unique 35-character string (i.e. uuid), such as a contentID, userID, or a custom id of your own creation
- Thanks to method injection, using myDataObject.setGender() will set the value. You can also use myDataObject.setValue('gender',1)
- Only attributes that actually exist in the Extended Attributes set will be saved
Running the 'get' function will return the following data:
There is a huge amount of benefit in using Extended Attributes as your data repository. First, it removes the need to create database tables, avoiding all the inherent cross-engine issues and complicated scripting (never mind future updates). Second, with the indexes on the custom columns it is possible to efficiently retrieve data using custom queries, should you need to. Some of these queries can get a bit complicated, to be sure, but this is still in the 'experimental' stage and will be made easier via some soon-to-be-released feed/iterator classes.
Finally, it is easy to tie your custom data to other Mura content types, such as Users or content pages. A big advantage is that you can now link multiple data sets with a single content type. An example of this might be a dating site that had user data sets called "Global", "Male", "Female" and "Premium". Everybody would be linked to "Global", "Male" and "Female" would be associated to users of a particular gender, and "Premium" would only be linked to users who were paid members. You'll have to manage these relationships yourself for now, but this too will probably become more streamlined in Mura's future.
Also, I should note your plugins don't have to use custom sets; they can just as easily interact with Page/User/etc. attribute sets. This would allow users to interact with the data in the standard Mura way, as well as allowing your plugin to create, update and access them as described above.
Using Extended Attributes as your data repository is not just a fast, simple way of storing your data, but also an integrated approach that can be leveraged by other parts of the Mura CMS. It won't replace the need for a dedicated datasource in every case, but certainly adds a powerful alternative.
Finally, Matt has also created very cool feed/iterator tools, but they have not be made part of the core update as of yet. When they have, I'll add a post on how to use them against your custom Extend sets. Until then, have fun exploring!