Monday, July 23, 2012

Extracting data from the Sitecore Web Forms for Marketers Module

The Web Forms for Marketers module for Sitecore comes with an extensive reporting tool inside the Sitecore Desktop. Information about submissions and activity on forms can be viewed in the reports already provided by the module. Recently, I had to create a custom report on WFFM forms that would live outside of the Desktop, so I decided to put together the basics on accessing form items and entries.
You would need a reference to the Sitecore.Forms.Core.dll

private void Example()
{
     string formID = "{FCD67950-6473-4962-B090-B4821BDB2C80}";
     ItemUri uri = new ItemUri(Sitecore.Data.ID.Parse(formID), Sitecore.Context.Database);

     //1. Get Form
     FormItem form = new FormItem(Database.GetItem(uri));
     string name = form.FormName;

     //2. Data Filters
     List<GridFilter> filters = new List<GridFilter>();
     // 2.a Form filter
     filters.Add(new GridFilter(Sitecore.Form.Core.Configuration.Constants.DataKey, formID, GridFilter.FilterOperator.Contains));
     // 2.b Get archived items
     filters.Add(new GridFilter(Sitecore.Form.Core.Configuration.Constants.StorageName, Sitecore.Form.Core.Configuration.Constants.Archive, GridFilter.FilterOperator.Contains));
            
     //3. Get all entries
     IEnumerable<IForm> entries = Sitecore.Forms.Data.DataManager.GetForms().GetPage(new PageCriteria(0, 0x7ffffffe), null, filters);

     // 3.a Apply custom filtering on the entries
     entries = entries.Where(a => a.Timestamp.Date.CompareTo(startDate) >= 0 && a.Timestamp.Date.CompareTo(endDate) <= 0);
            
     //4. Create a form packet
     FormPacket packet = new FormPacket(entries);

     CustomProcessor export = new CustomProcessor();
     string result = export.Process(form, packet);
}

1. Get the form
Use the FormItem constructor, passing in the inner data item, which, like any other item, can be grabbed based on its ID from the Context.Database. The FormItem class will give you access to various form properties such as the form.Introduction, form.Footer, and form.FormName as well as all the form fields and save actions.


2. Data filters
There are two filters that are obligatory in order to use the Sitecore.Forms.Data.DataProvider. To grab entries for a specific form, you will need to apply a GridFilter on the DataKey ("dataKey") field where the criteria would be the ID of the form. And the second filter specifies whether you are getting entries out of the archive or not. 

3. Get the entries
Having defined the grid filters, you can now grab all entries using the DataManager.

4. Create a form packet
The FormPacket makes it easy to ship a packet of entries that you've already filtered out off to a processor. For example, this could be a processor for a specific file type.

Friday, July 6, 2012

Custom log files for the Sitecore CMS

I realize that in most cases, the purpose of doing this would be to avoid the hassle of digging through tons of Sitecore log messages to find your own. In my case, I really wanted to separate the custom messages so as to avoid polluting the Sitecore logs. There's actually a lot of information out there on how to write your custom log messages into a separate log file, so I'm not going to go into that. There is an extensive post by John West on Logging with Sitecore, which can get you started on successfully separating log entries into a new file and to the point where I found myself. My custom messages were successfully written to a separate file, but they also continued to get appended to the regular Sitecore logs.

I had to do some digging to configure the regular logs to ignore my custom messages, so I'm writing this in the hopes that I might save someone else the digging.

I ended up adding a filter to the LogFileAppender that would deny messages containing my custom string. The message would be denied on match.

<appender name="LogFileAppender" type="log4net.Appender.SitecoreLogFileAppender, Sitecore.Logging">
  <file value="$(dataFolder)/logs/log.{date}.txt"/>
  <filter type="log4net.Filter.StringMatchFilter">
     <stringToMatch value="YOUR_CUSTOM_STRING" />
     <acceptOnMatch value="false" />
  </filter>
  <appendToFile value="true"/>
  <layout type="log4net.Layout.PatternLayout">
     <conversionPattern value="%4t %d{ABSOLUTE} %-5p %m%n"/>
  </layout>
</appender>