Sitecore SXA:创建一个基于规则的代码片段渲染

时间阅读: 大约7 - 10分钟
用于: Sitecore开发人员,高级开发人员 & 领导
主要结论: 如何创建自定义渲染来动态显示使用Sitecore规则引擎的片段内容.

在最近的一个商务项目中,需要在产品详细信息页面上显示特定于产品的内容. 这可能是一个品牌提供的图像,额外的细节,或某种类型的广告或特殊. 因为产品数据是动态显示的,所以我需要想出一个动态的方法来处理这个问题.

我首先讲了个性化. 虽然这可能可行,但最佳实践是只使用它来显示基于客户行为的内容. 当将访问者规则和内容规则混合在一起时,规则也会很快变得混乱. 然而,规则引擎是一个强大的工具,所以我决定利用它与一个新的自定义渲染来满足需求.

创建基于规则的代码段

我决定使用片段作为起点. 我以代码片段呈现为基础,让内容作者可以灵活地添加内容. 它允许他们添加任何东西,从简单的图像渲染到详细的产品信息使用多个渲染.

我从制作Snippet呈现的克隆开始,并只在数据源项上添加了一个额外的规则字段. 其想法是使用规则引擎根据所显示产品的一组条件来选择一个片段数据项. 前提相当直接, 我只需要根据规则引擎的结果更改数据源项.

GetXmlBasedLayoutDefinition管道

当一个代码片段被渲染时,它的xml布局定义被注入到页面条目布局定义中. 为此,将解析数据源项,并读取和注入其布局定义. 这发生在 Sitecore.XA.功能.复合材料.管道.GetXmlBasedLayoutDefinition.InjectCompositeComponents. 这里我重写了 ResolveCompositeDatasource 方法来基于规则字段(而不是呈现的数据源字段)解析数据.

var datasourceItem = Context.数据库.GetItem (datasourceId);
如果(datasourceItem.TemplateID = =模板.规则BasedSnippetSnippet.ID)
{
    var 规则sBasedDatasource = 规则sBasedSnippetRepository.Get规则BasedSnippetDataSource (datasourceItem contextItem);
    返回规则sBasedDatasource ?? datasourceItem;
}
其他的
{
    返回datasourceItem;
}

改变很简单, 如果数据源项是基于规则的片段,则从规则引擎获取该项,否则返回原始数据源项. 我将在下一节介绍规则引擎代码.

还需要考虑对管道的另一个更改. 生成的布局定义xml根据当前上下文项id存储在字典缓存中. 这需要调整,因为我需要为相同的页面返回不同的结果. 所以我重写了 Create复合材料XmlCacheKey 方法返回一个不同的缓存键,该键的url仅为基于规则的代码段添加.

var pagePath = args.PageContext.请求Context.HttpContext.请求.路径;
如果(currentItem.Name = = " * " && renderingIds.Any(r => r == Renderings.规则BasedSnippet.ID))
{
    返回$”SXA:{常数.复合材料XmlPropertiesKey}: {siteItem.ID}:{上下文.数据库.名称}:{上下文.设备.ID}:{上下文.语言.名称}:{currentItem.ID}: {pagePath}”;
}
其他的
{
    返回$”SXA:{常数.复合材料XmlPropertiesKey}: {siteItem.ID}:{上下文.数据库.名称}:{上下文.设备.ID}:{上下文.语言.名称}:{currentItem.ID}";
}

解析数据源项

最后,我需要使用规则引擎来解析数据源项. 让我们从下面的代码片段开始:

var commerceContextItem = siteContext.CurrentCatalogItem ?? contextItem;
var 规则s = RuleFactory.Parse规则(contextItem.数据库,XElement.解析(规则sBasedSnippetSnippetItem[模板.规则BasedSnippetSnippet.字段.Snippet规则]));
var 规则Context = new 规则Context ()
{
    项= commerceContextItem
};

如果(规则.规则.任何())
{
    Foreach(规则中的var规则.规则)
    {
        如果(规则.条件 != null)
        {
            var stack = new RuleStack();
            规则.条件.评估(规则Context堆栈);

            如果(规则Context.IsAborted)
            {
                继续;
            }
            如果(栈.数 != 0) && ((bool)堆栈.Pop ()))
            {
                规则.执行(规则Context);
                Var动作=规则.行动.FirstOrDefault ();
                var snippetId = action is SelectSnippet ? ((SelectSnippet)action)?.SnippetId:字符串.空的;
                返回 !字符串.IsNullOrEmpty (snippetId) ? contextItem.数据库.GetItem (ID.解析(snippetId)):空;
            }
        }
        其他的
        {
            规则.执行(规则Context);
        }
    }
}

返回null;

首先,我使用RuleFactory解析器解析规则字段xml. 然后, 因为我需要对产品项执行规则引擎,所以我从商务网站上下文中检索了当前的目录项. 然后将其用作规则引擎的上下文项. 最后,我使用返回最终结果的规则引擎对每个规则进行循环和评估.

SelectSnippet 是一个自定义 RuleAction 它从已解析的规则中返回选定的代码段id. 的 SelectSnippetRuleContext 是否使用自定义宏设置代码段. 在这篇文章中,我不会详细介绍如何创建宏. 然而,你可以找到大量的资源来在线创建自定义宏.

public class SelectSnippet : RuleAction where T : RuleContext
{
    public 字符串 SnippetId { get; set; }

    应用(T 规则Context)
    {
        select snippeulecontext dataSourceRuleContext = 规则Context as selectsnippeulecontext;
        ID的结果;
        if (dataSourceRuleContext == null || !ID.TryParse (SnippetId,结果)
        {
            返回;
        }
        dataSourceRuleContext.SnippetId =结果;
    }
}

结束

到目前为止,这个解决方案对我们的客户来说工作得很好. 目前尚不清楚,随着规则条件数量的增加,该解决方案是否会带来任何性能问题. 到目前为止,它还没有给我们带来任何问题. 一个积极的方面是它与个性化相结合. 因此,它允许根据客户行为选择不同的规则集.

我希望这些信息对您有用. 如果你有任何问题,请随时留下评论.