Detecting obsolete item groups

PageBuilder 4 allows you to build an entire catalog at once, but you can also build separate sections or chapters, or you can build item groups for specific products. When you build a full catalog, you can choose to reuse prebuilt content or to rebuild everything from scratch (using the option "Ignore Built Content" in the PageBuilder Studio UI).

A typical setup would be to first build item groups for all your products, and then configure a rule that automatically rebuilds item groups when product records are updated. Building your catalogs will be much faster when item groups are already available for all your products. And since each item group can be built separately, you benefit optimally from the automatic load balancing that is provided by the DocMaker Queuing Service (assuming you are using multiple InDesign Servers).

Product item groups often contain data from multiple linked records (e.g. a table with related products or stock-keeping units), so the rule conditions to automatically rebuild item groups when product data is updated can get rather complicated. Also, when a certain subset of products is updated very frequently, rebuilding the corresponding item groups results in redundant work and may put an excessive load on your server.

An alternative setup would be to detect item groups with obsolete product data while building the actual catalog. This approach is quite easy to implement, and allows you to consider live dependencies between product records. What we need here is a custom CatalogBuilder which uses a custom RecordContentAdder:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
using Adam.Core;
using Adam.PageBuilder.Core.Build;

namespace SmartReuseEngine
{
 public class SmartReuseCatalogBuilder : CatalogBuilder
 {
  public SmartReuseCatalogBuilder(Application application) : base(application)
  {
   RecordContentAdder = new SmartReuseContentAdder(application);
  }
 }
}

Our SmartReuseContentAdder overrides the HasBuiltContent method. The default implementation for this method simply checks whether an item group record exists for the current product record. Here we will check some additional conditions before we allow the existing item group to be used. If the current product record was modified after its item group was last modified, we do not allow to reuse the item group. We also force to rebuild the item group if a linked product record was modified at a later time. Here is the code:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using System;
using System.Linq;
using Adam.Core;
using Adam.Core.Fields;
using Adam.Core.Records;
using Adam.PageBuilder.Core.Extensions;
using Adam.PageBuilder.Core.ContentAdder;

namespace SmartReuseEngine
{
 public class SmartReuseContentAdder : RecordContentAdder
 {
  public SmartReuseContentAdder(Application application) : base(application)
  {
  }

  public override bool HasBuiltContent
  {
   get
   {
    if (!base.HasBuiltContent)
    {
     return false;
    }

    Guid? itemGroupRecordId = Record.GetBuiltItemGroupRecordId(BuiltItemGroupField, Languages);
    if (itemGroupRecordId.HasValue)
    {
     Record itemGroupRecord = new Record(App);
     itemGroupRecord.Load(itemGroupRecordId.Value);

     if (Record.ModifiedOnUtc.CompareTo(itemGroupRecord.ModifiedOnUtc) > 0)
     {
      // Product record was updated after building the item group.
      return false;
     }

     // Link fields to consider are specified in the Tag property.
     foreach (string linkFieldName in Tag.Split(','))
     {
      RecordLinkField linkField = (RecordLinkField)Record.Fields[linkFieldName].MyLanguage;

      RecordCollection links = new RecordCollection(App);
      links.Load(linkField.Children.Cast<RecordLinkItem>().Select(p => p.RecordId).ToList());

      foreach (Record link in links)
      {
       if (link.ModifiedOnUtc.CompareTo(itemGroupRecord.ModifiedOnUtc) > 0)
       {
        // Linked record was updated after building the item group.
        return false;
       }
      }
     }
    }

    return true;
   }
  }
 }
}

The link fields that should be considered can be specified as a comma-separated list through the Tag property in the PageBuilder Studio UI. Of course you could also use any other convention here. You can also further extend the implementation with more advanced record dependencies or more fine-grained conditions if desired.

The two classes above should be compiled into a class library which can be registered in ADAM or in the GAC. Next the custom engine should be added to the "PageBuilder build catalog engines" setting (as explained in previous blog posts and in the PageBuilder 4.0 Developer Guide). You can then use the custom engine when building catalogs from within PageBuilder Studio:

Comments

Leave a comment
You must be logged in to post comments.
Sign in now
 
 
Technical
Business
rss feed