Sample.Events module is an uncompleted module that demonstrates how to extend built-in Generic Content module in order to create more robust and complex functionality, yet not spend a lot of time on building already built functionality (like UI, tagging, security…). You can download the module from here.
Generic Content module is a cornerstone module of Sitefinity. On top of it we have already built News module as well as the Blogs module.
Sample.Events module is module that can be used for creating information about various events. The module allows one to enter the name of event, description of the event, tag and categorize the event. Since all this functionality is provided by Generic Content module, it makes sense to build this module by extending Generic Content module. In addition to provided functionality, for every event one or more News categories related to this event can be selected. Also, this module allows to select days on which event is taking place (by using multiple selection on RadCalendar control). While not spectacularly functional module it demonstrates some advanced topics in creating pluggable modules.
We'll start by creating a new module just as we would do it if we are to build a new module from scratch. Pay attention that in web.config we’ll be doing things a bit differently than it was the case with the Sample.Contacts module. If you examine the web.config you'll notice that we are following the same logic as with News or Blogs modules. We add a new Generic_Content provider for Events, set the meta fields (Name, NewsCategories, EventDates) and finally add the Events provider.
The ~/Sitefinity/Admin/ControlTemplates/Events folder has been created by copying all the files from ~/Sitefinity/Admin/ControlTemplates/Generic_Content folder and then making some minor changes (replacing words „Item“ with „Event“ and such...).
As you may already know Generic Content module and modules based on it are capable of storing information in meta fields. While that is a very quick and easy way to modify the module to fit your needs, it does have some drawbacks, which we will alleviate in this demonstration.
Let’s take the NewsCategory meta field for example. Every time user creates a new entry he can define one or more News categories related to this event. These will be saved in NewsCategory meta field as semi-colon delimited strings. So when we open a particular event, we can access the NewsCategory meta field, split the string and get all the NewsCategories related to this event. So far, so good… However, let’s assume that we want to list all the events that are related to particular News category. Obviously, we could scan all the Events and search for the correct string, but that approach would not scale very well.
To solve this problem we are going to create in our Sample.Events module lookup table called EventsNewsCategories. Every time when we save an event, we’ll enter in this table Event id (or ContentID) and the NewsCategoryId it is associated with. So when we want to find all the events that are related to a particular News category, we can execute a simple query against this table and simply load all the needed events, without parsing all the events’ NewsCategory meta field strings.
The question is when are we going to save values to this lookup table? Since it would take a lot of time to modify ControlPanel control (we have simply inherited Telerik.Cms.Engine.WebControls.Admin.ControlPanel class here), we can’t really influence the behavior of that Save button. However, we can extend the provider for Generic Content. So if you open the Sample.Events.Data.DefaultEventsProvider.cs file you’ll see it inherits Telerik.Cms.Engine.Data.Providers.DefaultProvider class. This means will have all the data manipulation methods Generic Content uses. Also, you’ll notice we are implementing IEventsProvider interface just to make sure our Events specific methods are implemented as well.
The idea here is to override SaveContent method and add some additional logic to it. SaveContent is a method of Telerik.Cms.Engine.Data.Providers.DefaultProvider and it saves content to a database (don’t get confused with “Content” part, our Events are nothing more than Content objects, we just call them Events in this module). So in the SaveContent module first we call base.SaveContent(content) and let the Generic Content provider do whatever it usually does to save content, but after that we take our meta fields and save these values to the look up tables. This is the key part of this demonstration.
The same concept is applied to EventDates meta field, only instead of News category ids it saves dates to a lookup table.
You’ll notice this module has only one public control: EventsCalendar. This control shows the calendar and on the days when an event is scheduled it shows the title of that event. So, what we are doing here is taking advantage of RadCalendar’s DayRender event. We provide an event handler for this event that checks if on that date any events have been scheduled. Since we have a lookup table called EventDates, we don’t need to go through all the events and parse the EventDates meta field, but we simply query a EventDates table for the particular date and return all the events (content) that has been scheduled on that day.
Please bear in mind that this is just a simple demonstration module. You could make it as complicated and feature rich as you want. The important thing is here to see how you can extend Generic Content module and use meta fields for storing complex data (e.g. multiple categories) and then create lookup tables which will make your modules scalable.
You can download the module from here.