As part of our efforts to share the latest technologies and capabilities in the world of digital marketing and web development, we’ll be posting a series of articles on Sitecore, one of the most impressive experience platforms available today. Though this post will primarily be relevant to developers, we hope the content remains interesting to all of our readers and provides some insight into the more technical aspects of the digital development world.
Not too long ago I released the Express Subitem Sitecore Marketplace module. This module allows content editors to edit multiple child Sitecore items at the same time within the context of the parent item. This field is commonly used to manage lists of related items that exist only within the context of the parent.
The example I gave was one where a Person record contained education history. For this article, let’s assume the education sub-item has a Drop Link to choose a school from a defined list.
In this particular example, we want the School field to be required seeing as it does not make sense to have an education record without a school. We can easily set the School to be a required field through validation rules, meaning a content administrator must pick a school or they will not be able to save the record.
It’s important to note that there is a problem when making relationship fields required. Making a relationship field required does not guarantee the related item exists on the live site. A content administrator can chose a School that is not publishable or published. If the person with the education record is published (publish item and subitems), the school may be missing in the web database. This has the effect of a required field missing a value.
In the case where the school is missing, we don’t want to display the education record on the live site. This would typically be accomplished by adding custom logic to hide the education record if the school was missing. This is error prone as this can be missed and not discovered until the situation arises on the live site.
It would be beneficial to handle this situation without the developer having to think about each situation when this could occur.
Many Sitecore implementations use the popular Glass.Mapper ORM to render content. Continuing the example, we can use Glass.Mapper to render the Person, including Education records. These examples use Glass.Mapper 4.0.
Logic would typically be added around the iteration of the Model.Education to ignore records that do not have a School. Instead of adding custom logic on render, we can tap into the flexibility of Glass.Mapper to return only valid records. Glass.Mapper provides a pipeline framework where the out of the box behavior can be modified by plugging in custom pipeline steps.
First, we need to tell Glass.Mapper what the required fields are. We can do this through a custom property attribute. This attribute can be applied to all required properties on the Glass objects.
Next, we need to figure out where to put our custom pipeline logic. The ObjectConstructionFactory handles building the objects returned in the ORM. We can have the ObjectConstructionFactory return null when a required field is missing. To plug into the ObjectConstructionFactory pipeline, we modify the CreateResolver method in the GlassMapperScCustom.cs class. We want our pipeline step to run before the resulting object is constructed. We also want it to happen after the cache is checked so it only runs when necessary. The task will be inserted just after the CacheCheckTask. The implementation of our task will be done in the ValidateItemTask class.
Now, we will create the ValidateItemTask. All tasks that participate in the ObjectConstructionFactory implement the IObjectConstructionTask interface. The Execute method must be implemented. Within this method, the args.Result can be set to null if the object is not valid. Args.AbortPipeline should also be called in this case so further tasks are not called to resolve the object. To prevent issues with data loaders and previewing, the validation logic will only run when outside the context of the master database, i.e. the web database.
This IsValid method needs to be implemented, validating the context item based on the SitecoreRequiredAttribute. It will check the values of all of the fields marked with this attribute. If the field is empty, false will be returned. We will first create a helper methods to return the list of required fields for a given context. The GetRequiredFields helper method uses reflection to obtain the attributes on the configured properties. The results are cached in a static variable.
Next, the IsValid method can be implemented. It will first get the required fields using the helper methods from above. Then, for each field, it will check the validity. If a field is not valid, it returns false. In most cases, if the value of the field is null or empty, we can return false. There are a few cases where the field may be populated, but it is still empty. Relationship fields may have an ID present, but the item associated with the ID has not been published, and therefore is not there. For these fields we need to perform some extra checks. In this particular case, we just need to check for the presence of the item in the database. I did not fill in all of the logic for the different field types. This can be an exercise for another time.
Give it a try… All required relationship fields that are missing the related item in the web database will cause the request for the item/object to return null.
Glass.Mapper is very flexible. With this flexibility, we were able to add business logic to the pipeline. This business logic eliminates the need of adding additional checks when required fields are missing.
Found this post interesting? Check out my other posts on Sitecore and Sitecore-related topics:
How-To: Resetting the Sitecore Admin Password
Sitecore: Express Subitem Module
Sitecore: Using NuGet to Add Items to TDS Projects
Templating Rich Text Content in Sitecore Using Razor (on the Sitecore Technical Blog at sitecore.net)