3
votes

I have built a custom module in Orchard that creates a new part, type and a custom activity but I'm struggling with the last part of what I need to do which is to create a copy of all the content items associated with a specific parent item.

For instance, when someone creates a "Trade Show" (new type from my module), various subpages can be created off of it (directions, vendor maps, etc.) since the client runs a single show at a time. What I need to do is, when they create a new Trade Show, I want to get the most recent prior show (which I'm doing via _contentManager.HqlQuery().ForType("TradeShow").ForVersion(VersionOptions.Latest).ForVersion(VersionOptions.Published).List().Last() (positive that's not the most efficient way, but it works and the record count would be ~10 after five years), then find all of those child pages that correlate to that old show and copy them into new Content Items. They have to be a copy because on occasion they may have to refer back to parts with the old shows, or it could change, etc. All the usual reasons.

How do I go about finding all of the content items that reference that prior show in an Activity? Here is my full class for the Activity:

using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.Autoroute.Services;
using Orchard.ContentManagement;
using Orchard.Localization;
using Orchard.Projections.Models;
using Orchard.Projections.Services;
using Orchard.Workflows.Models;
using Orchard.Workflows.Services;
using Orchard.Workflows.Activities;

namespace Orchard.Web.Modules.TradeShows.Activities
{
public class TradeShowPublishedActivity : Task
{
    private readonly IContentManager _contentManager;
    private readonly IAutorouteService _autorouteService;
    private readonly IProjectionManager _projectionManager;

    public TradeShowPublishedActivity(IContentManager contentManager, IAutorouteService autorouteService, IProjectionManager projectionManager)
    {
        _contentManager = contentManager;
        _autorouteService = autorouteService;
        _projectionManager = projectionManager;

        T = NullLocalizer.Instance;
    }

    public Localizer T { get; set; }

    public override LocalizedString Category
    {
        get { return T("Flow"); }
    }

    public override LocalizedString Description
    {
        get { return T("Handles the automatic creation of content pages for the new show."); }
    } 

    public override string Name
    {
        get { return "TradeShowPublished"; }
    }

    public override string Form
    {
        get { return null; }
    }

    public override IEnumerable<LocalizedString> GetPossibleOutcomes(WorkflowContext workflowContext, ActivityContext activityContext)
    {
        yield return T("Done");
    }

    public override IEnumerable<LocalizedString> Execute(WorkflowContext workflowContext, ActivityContext activityContext)
    {
        var priorShow = _contentManager.HqlQuery().ForType("TradeShow").ForVersion(VersionOptions.Latest).ForVersion(VersionOptions.Published).List().Last();
        var tradeShowPart = priorShow.Parts.Where(p => p.PartDefinition.Name == "TradeShowContentPart").Single();

        //new show alias
        //workflowContext.Content.ContentItem.As<Orchard.Autoroute.Models.AutoroutePart>().DisplayAlias

        yield return T("Done");
    }
}

}

My Migrations.cs file sets up the part that is used for child pages to reference the parent show like this:

ContentDefinitionManager.AlterPartDefinition("AssociatedTradeShowPart", builder => builder.WithField("Trade Show", cfg => cfg.OfType("ContentPickerField")
                                                                                                                                  .WithDisplayName("Trade Show")
                                                                                                                                  .WithSetting("ContentPickerFieldSettings.Attachable", "true")
                                                                                                                                  .WithSetting("ContentPickerFieldSettings.Description", "Select the trade show this item is for.")
                                                                                                                                  .WithSetting("ContentPickerFieldSettings.Required", "true")
                                                                                                                                  .WithSetting("ContentPickerFieldSettings.DisplayedContentTypes", "TradeShow")
                                                                                                                                  .WithSetting("ContentPickerFieldSettings.Multiple", "false")
                                                                                                                                  .WithSetting("ContentPickerFieldSettings.ShowContentTab", "true")));

Then, my child pages (only one for now, but plenty more coming) are created like this:

ContentDefinitionManager.AlterTypeDefinition("ShowDirections", cfg => cfg.DisplayedAs("Show Directions")
                                                                                 .WithPart("AutoroutePart", builder => builder.WithSetting("AutorouteSettings.AllowCustomPattern", "true")
                                                                                                                               .WithSetting("AutorouteSettings.AutomaticAdjustmentOnEdit", "false")
                                                                                                                               .WithSetting("AutorouteSettings.PatternDefinitions", "[{Name:'Title', Pattern: '{Content.Slug}', Description: 'international-trade-show'}]")
                                                                                                                               .WithSetting("AutorouteSettings.DefaultPatternIndex", "0"))
                                                                                 .WithPart("CommonPart", builder => builder.WithSetting("DateEditorSettings.ShowDateEditor", "false"))
                                                                                 .WithPart("PublishLaterPart")
                                                                                 .WithPart("TitlePart")
                                                                                 .WithPart("AssociatedTradeShowPart") /* allows linking to parent show */
                                                                                 .WithPart("ContainablePart", builder => builder.WithSetting("ContainablePartSettings.ShowContainerPicker", "true"))
                                                                                 .WithPart("BodyPart"));
1

1 Answers

0
votes

So you have the Trade Show content item, the next step will be to find all parts with a ContentPickerField, then filter that list down to those where the field contains your show's ID.

        var items = _contentManager.Query().List().ToList() // Select all content items
            .Select(p => (p.Parts 
                // Select all parts on content items
            .Where(f => f.Fields.Where(d => 
                d.FieldDefinition.Name == typeof(ContentPickerField).Name && 
                // See if any of the fields are ContentPickerFields
                (d as ContentPickerField).Ids.ToList().Contains(priorShow.Id)).Any()))); 
                   // That field contains the Id of the show

This could get expensive depending on how many content items are in your database.