【问题标题】:How to dynamically add a content part in a Orchard content handler?如何在 Orchard 内容处理程序中动态添加内容部分?
【发布时间】:2015-08-04 12:08:33
【问题描述】:

我有一个调用

的 Orchard 内容处理程序
Filters.Add(new Orchard.ContentManagement.Handlers.ActivatingFilter<MyPart>("User"));

在其构造函数中将MyPart 焊接到用户内容项。

如何根据内容项 ID 焊接 MyPart

这里的问题是在调用构造函数时内容项尚未创建。我尝试通过覆盖 Activating() 来连接到生命周期,但这也不起作用,因为内容项还没有创建。

【问题讨论】:

    标签: orchardcms content-type


    【解决方案1】:

    好吧,这个任务真的很难。这是我的解决方案。

    1) 创建一个将内容部分焊接到内容项的扩展方法(遗憾的是,我们不能使用 ContentItemBuild.Weld(),因为没有机会传递内容项)

    // adopted from ContentItemBuilder.Weld<>()
    public static TPart Weld<TPart>(this Orchard.ContentManagement.ContentItem aContentItem)
      where TPart: Orchard.ContentManagement.ContentPart, new()
    {
      var partName = typeof(TPart).Name;
    
      // obtain the type definition for the part
      var typePartDefinition = aContentItem.TypeDefinition.Parts.FirstOrDefault(p => p.PartDefinition.Name == partName);
      if (typePartDefinition == null) {
          // If the content item's type definition does not define the part; use an empty type definition.
          typePartDefinition = new Orchard.ContentManagement.MetaData.Models.ContentTypePartDefinition(
              new Orchard.ContentManagement.MetaData.Models.ContentPartDefinition(partName),
              new Orchard.ContentManagement.MetaData.Models.SettingsDictionary());
      }
    
      // build and weld the part
      var part = new TPart { TypePartDefinition = typePartDefinition };
      aContentItem.Weld(part); 
    
      return part;
    }
    

    2) 定义一个 StorageFilter 用于将内容部分动态焊接到内容项

    public class BaseWeldBeforeStorageFilter<TPart, TRecord> : Orchard.ContentManagement.Handlers.IContentStorageFilter 
      where TPart: Orchard.ContentManagement.ContentPart, new()
      where TRecord: Orchard.ContentManagement.Records.ContentPartRecord
    {
      // public
        public BaseWeldBeforeStorageFilter(Orchard.Data.IRepository<TRecord> aPartRecords)
        {
          mPartRecords = aPartRecords;
        }
    
        ...
    
        public void Loading(Orchard.ContentManagement.Handlers.LoadContentContext aContext)
        {
          // dynamically weld TPart to content item when condition is met (is a user, does record exist)
          if (aContext.ContentItem.Is<Orchard.Users.Models.UserPart>())
          {
            if (!aContext.ContentItem.Is<TPart>())
            {
              if (mPartRecords.Count(r => r.Id == aContext.ContentItem.Id) > 0)
                aContext.ContentItem.Weld<TPart>();
            }
          }
        }
    
        ...
    
      // private
        Orchard.Data.IRepository<TRecord> mPartRecords;
    }
    

    3) 为动态内容部分定义内容处理程序

    public abstract class BasePartHandler<TPart, TRecord> : Orchard.ContentManagement.Handlers.ContentHandler
      where TPart: Orchard.ContentManagement.ContentPart<TRecord>, new()
      where TRecord: Orchard.ContentManagement.Records.ContentPartRecord, new()
    {
      // public
        // the constructor of a content handler is called when a content item (e.g. user) is created
        public BasePartHandler(Orchard.Data.IRepository<TRecord> aPartRecords)
        {
          ...
    
          // add storage filter for dynamically welding TPart to content item
          Filters.Add(new BaseWeldBeforeStorageFilter<TPart, TRecord>(aPartRecords)); 
    
          // enable storing TPart to associated table
          Filters.Add(Orchard.ContentManagement.Handlers.StorageFilter.For<TRecord>(aPartRecords));
    
          ...
    
          // listen to user creation, update, removal...
          OnCreated<Orchard.Users.Models.UserPart>(UserCreated);
          ...
        }
    
        ...
    
      // private
        private void UserCreated(Orchard.ContentManagement.Handlers.CreateContentContext aContext, Orchard.Users.Models.UserPart aUserPart)
        {
          if (...) // condition for checking whether user 
            CreatePartRecordWhenNeededAndWeldPart(aContext.ContentItem, ...);
        }
    
        private void CreatePartRecordWhenNeededAndWeldPart(Orchard.ContentManagement.ContentItem aContentItem)
        {
          TPart lPart = aContentItem.Weld<TPart>();
    
          // assign record, adopted from StorageFilter.cs
          // todo: find a way to do it the "Orchard way" as this feels like hack
          lPart._record.Loader(r => 
            new TRecord {
              Id = aContentItem.Id, 
              ContentItemRecord = new Orchard.ContentManagement.Records.ContentItemRecord {Id = aContentItem.Id}
            });
    
          // there are situations where part record already exists in DB but part is not welded at this point, thus check for existing record to avoid
          //  - creating record multiple times 
          //  - NHibernate exception
          if (!mPartRecords.Table.Contains(lPart.Record))
            mPartRecords.Create(lPart.Record);
        }
    
        private Orchard.Data.IRepository<TRecord> mPartRecords;
    }
    

    目前,动态内容部分处理工作正常,但我仍然不确定如何在 Orchard 中正确创建内容部分记录(请参阅步骤 3 源代码中的待办事项提示)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-18
      • 2010-12-18
      • 2017-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多