#17312: Refactoring ContainerPart to use a driver

Work Item: 17312

--HG--
branch : 1.x
This commit is contained in:
piedone
2011-11-15 11:46:33 -08:00
parent 5d94aefdc0
commit 679e4fed3d
14 changed files with 228 additions and 81 deletions

View File

@@ -59,34 +59,8 @@ namespace Orchard.Core.Containers.Controllers {
}
var container = _contentManager.Get(hits.Single().Id);
IContentQuery<ContentItem> query = _contentManager
.Query(VersionOptions.Published)
.Join<CommonPartRecord>().Where(cr => cr.Container.Id == container.Id);
var descendingOrder = container.As<ContainerPart>().Record.OrderByDirection == (int) OrderByDirection.Descending;
query = query.OrderBy(container.As<ContainerPart>().Record.OrderByProperty, descendingOrder);
_feedManager.Register(container.As<RoutePart>().Title, "rss", new RouteValueDictionary { { "containerid", container.Id } });
Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
pager.PageSize = pagerParameters.PageSize != null && container.As<ContainerPart>().Record.Paginated
? pager.PageSize
: container.As<ContainerPart>().Record.PageSize;
var pagerShape = Shape.Pager(pager).TotalItemCount(query.Count());
var startIndex = container.As<ContainerPart>().Record.Paginated ? pager.GetStartIndex() : 0;
var pageOfItems = query.Slice(startIndex, pager.PageSize).ToList();
var list = Shape.List();
list.AddRange(pageOfItems.Select(item => _contentManager.BuildDisplay(item, "Summary")));
list.Classes.Add("content-items");
list.Classes.Add("list-items");
container.As<ContainerPart>().PagerParameters = pagerParameters;
var model = _contentManager.BuildDisplay(container, "Detail");
model.Content.Add(list, "7");
if (container.As<ContainerPart>().Record.Paginated) {
model.Content.Add(pagerShape, "7.5");
}
return new ShapeResult(this, model);
}

View File

@@ -2,7 +2,6 @@
using System.Linq;
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Models;
using Orchard.Core.Containers.Models;
@@ -44,6 +43,7 @@ namespace Orchard.Core.Containers.Drivers {
commonPart.Record.Container = containerItem == null ? null : containerItem.Record;
}
}
part.Weight = model.Weight;
}
// note: string.isnullorempty not being recognized by linq-to-nhibernate hence the inline or
@@ -59,6 +59,7 @@ namespace Orchard.Core.Containers.Drivers {
.ToList();
model.AvailableContainers = new SelectList(listItems, "Value", "Text", model.ContainerId);
model.Weight = part.Weight;
return shapeHelper.EditorTemplate(TemplateName: "Containable", Model: model, Prefix: "Containable");
});

View File

@@ -7,29 +7,79 @@ using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Common.Models;
using Orchard.Core.Containers.Models;
using Orchard.Core.Containers.Settings;
using Orchard.Core.Containers.ViewModels;
using Orchard.Data;
using Orchard.Localization;
using Orchard.UI.Notify;
using Orchard.DisplayManagement;
using Orchard.Core.Containers.Extensions;
using Orchard.Core.Routable.Models;
using System.Web.Routing;
using Orchard.Settings;
using Orchard.Core.Feeds;
using Orchard.UI.Navigation;
namespace Orchard.Core.Containers.Drivers {
public class ContainerPartDriver : ContentPartDriver<ContainerPart> {
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly IOrchardServices _orchardServices;
private readonly IContentManager _contentManager;
private readonly dynamic _shapeFactory;
private readonly ISiteService _siteService;
private readonly IFeedManager _feedManager;
public ContainerPartDriver(IContentDefinitionManager contentDefinitionManager, IOrchardServices orchardServices) {
public ContainerPartDriver(
IContentDefinitionManager contentDefinitionManager,
IOrchardServices orchardServices,
IShapeFactory shapeFactory,
ISiteService siteService,
IFeedManager feedManager) {
_contentDefinitionManager = contentDefinitionManager;
Services = orchardServices;
_orchardServices = orchardServices;
_contentManager = orchardServices.ContentManager;
_shapeFactory = shapeFactory;
_siteService = siteService;
_feedManager = feedManager;
T = NullLocalizer.Instance;
}
public IOrchardServices Services { get; private set; }
public Localizer T { get; set; }
protected override DriverResult Display(ContainerPart part, string displayType, dynamic shapeHelper) {
if (!part.ItemsShown)
return null;
return Combined(
ContentShape("Parts_Container_Contained",
() => shapeHelper.Parts_Container_Contained(ContentPart: part)),
() => {
var container = part.ContentItem;
IContentQuery<ContentItem> query = _contentManager
.Query(VersionOptions.Published)
.Join<CommonPartRecord>().Where(cr => cr.Container.Id == container.Id);
var descendingOrder = part.OrderByDirection == (int)OrderByDirection.Descending;
query = query.OrderBy(part.OrderByProperty, descendingOrder);
_feedManager.Register(container.As<RoutePart>().Title, "rss", new RouteValueDictionary { { "containerid", container.Id } });
var pager = new Pager(_siteService.GetSiteSettings(), part.PagerParameters);
pager.PageSize = part.PagerParameters.PageSize != null && part.Paginated
? pager.PageSize
: part.PageSize;
// var pagerShape = _shapeFactory.Pager(pager).TotalItemCount(query.Count());
var startIndex = part.Paginated ? pager.GetStartIndex() : 0;
var pageOfItems = query.Slice(startIndex, pager.PageSize).ToList();
var list = _shapeFactory.List();
list.AddRange(pageOfItems.Select(item => _contentManager.BuildDisplay(item, "Summary")));
list.Classes.Add("content-items");
list.Classes.Add("list-items");
return list;
}),
ContentShape("Parts_Container_Contained_Summary",
() => shapeHelper.Parts_Container_Contained_Summary(ContentPart: part)),
ContentShape("Parts_Container_Contained_SummaryAdmin",
@@ -39,9 +89,8 @@ namespace Orchard.Core.Containers.Drivers {
protected override DriverResult Editor(ContainerPart part, dynamic shapeHelper) {
// if there are no containable items then show a nice little warning
if (!_contentDefinitionManager.ListTypeDefinitions()
.Where(typeDefinition => typeDefinition.Parts.Any(partDefinition => partDefinition.PartDefinition.Name == "ContainablePart")).Any()) {
Services.Notifier.Warning(T("There are no content types in the system with a Containable part attached. Consider adding a Containable part to some content type, existing or new, in order to relate items to this (Container enabled) item."));
if (!_contentDefinitionManager.ListTypeDefinitions().Any(typeDefinition => typeDefinition.Parts.Any(partDefinition => partDefinition.PartDefinition.Name == "ContainablePart"))) {
_orchardServices.Notifier.Warning(T("There are no content types in the system with a Containable part attached. Consider adding a Containable part to some content type, existing or new, in order to relate items to this (Container enabled) item."));
}
return Editor(part, (IUpdateModel)null, shapeHelper);
@@ -62,12 +111,12 @@ namespace Orchard.Core.Containers.Drivers {
}))
.ToList();
model.AvailableContainables = new SelectList(listItems, "Value", "Text", model.Part.Record.ItemContentType);
model.AvailableContainables = new SelectList(listItems, "Value", "Text", model.Part.ItemContentType);
if (updater != null) {
updater.TryUpdateModel(model, "Container", null, null);
}
return shapeHelper.EditorTemplate(TemplateName: "Container", Model: model, Prefix: "Container");
});
}
@@ -80,6 +129,11 @@ namespace Orchard.Core.Containers.Drivers {
}
}
var itemsShown = context.Attribute(part.PartDefinition.Name, "ItemsShown");
if (itemsShown != null) {
part.Record.ItemsShown = Convert.ToBoolean(itemsShown);
}
var paginated = context.Attribute(part.PartDefinition.Name, "Paginated");
if (paginated != null) {
part.Record.Paginated = Convert.ToBoolean(paginated);
@@ -103,26 +157,11 @@ namespace Orchard.Core.Containers.Drivers {
protected override void Exporting(ContainerPart part, ExportContentContext context) {
context.Element(part.PartDefinition.Name).SetAttributeValue("ItemContentType", part.Record.ItemContentType);
context.Element(part.PartDefinition.Name).SetAttributeValue("ItemsShown", part.Record.ItemsShown);
context.Element(part.PartDefinition.Name).SetAttributeValue("Paginated", part.Record.Paginated);
context.Element(part.PartDefinition.Name).SetAttributeValue("PageSize", part.Record.PageSize);
context.Element(part.PartDefinition.Name).SetAttributeValue("OrderByProperty", part.Record.OrderByProperty);
context.Element(part.PartDefinition.Name).SetAttributeValue("OrderByDirection", part.Record.OrderByDirection);
}
}
public class ContainerPartHandler : ContentHandler {
public ContainerPartHandler(IRepository<ContainerPartRecord> repository) {
Filters.Add(StorageFilter.For(repository));
OnInitializing<ContainerPart>((context, part) => {
part.Record.PageSize = part.Settings.GetModel<ContainerTypePartSettings>().PageSizeDefault
?? part.PartDefinition.Settings.GetModel<ContainerPartSettings>().PageSizeDefault;
part.Record.Paginated = part.Settings.GetModel<ContainerTypePartSettings>().PaginatedDefault
?? part.PartDefinition.Settings.GetModel<ContainerPartSettings>().PaginatedDefault;
// hard-coded defaults for ordering
part.Record.OrderByProperty = part.Is<CommonPart>() ? "CommonPart.CreatedUtc" : string.Empty;
part.Record.OrderByDirection = (int)OrderByDirection.Descending;
});
}
}
}

View File

@@ -6,12 +6,16 @@ using Orchard.Core.Containers.Models;
using Orchard.Core.Routable.Models;
using Orchard.Core.Title.Models;
namespace Orchard.Core.Containers.Extensions
{
namespace Orchard.Core.Containers.Extensions {
public static class ContentQueryExtensions {
public static IContentQuery<T> OrderBy<T>(this IContentQuery<T> query, string partAndProperty, bool descendingOrder) where T : IContent {
//todo: (heskew) order by custom part properties
switch (partAndProperty) {
case "ContainablePart.Weight":
query = descendingOrder
? query.OrderByDescending<ContainablePartRecord, int>(record => record.Weight)
: query.OrderBy<ContainablePartRecord, int>(record => record.Weight);
break;
case "TitlePart.Title":
query = descendingOrder
? query.OrderByDescending<TitlePartRecord, string>(record => record.Title)

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.ContentManagement.Handlers;
using Orchard.Data;
using Orchard.Core.Containers.Models;
namespace Orchard.Core.Containers.Handlers {
public class ContainablePartHandler : ContentHandler {
public ContainablePartHandler(IRepository<ContainablePartRecord> repository) {
Filters.Add(StorageFilter.For(repository));
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Containers.Models;
using Orchard.Core.Containers.Settings;
using Orchard.Core.Common.Models;
using Orchard.Data;
using Orchard.Core.Containers.Extensions;
using Orchard.ContentManagement;
namespace Orchard.Core.Containers.Handlers {
public class ContainerPartHandler : ContentHandler {
public ContainerPartHandler(IRepository<ContainerPartRecord> repository) {
Filters.Add(StorageFilter.For(repository));
OnInitializing<ContainerPart>((context, part) => {
part.Record.ItemsShown = true;
part.Record.PageSize = part.Settings.GetModel<ContainerTypePartSettings>().PageSizeDefault
?? part.PartDefinition.Settings.GetModel<ContainerPartSettings>().PageSizeDefault;
part.Record.Paginated = part.Settings.GetModel<ContainerTypePartSettings>().PaginatedDefault
?? part.PartDefinition.Settings.GetModel<ContainerPartSettings>().PaginatedDefault;
// hard-coded defaults for ordering
part.Record.OrderByProperty = part.Is<CommonPart>() ? "CommonPart.CreatedUtc" : string.Empty;
part.Record.OrderByDirection = (int)OrderByDirection.Descending;
});
}
}
}

View File

@@ -11,7 +11,9 @@ namespace Orchard.Core.Containers {
.Column<bool>("Paginated")
.Column<int>("PageSize")
.Column<string>("OrderByProperty")
.Column<int>("OrderByDirection"));
.Column<int>("OrderByDirection")
.Column<string>("ItemContentType")
.Column<bool>("ItemsShown", column => column.WithDefault(true)));
SchemaBuilder.CreateTable("ContainerWidgetPartRecord",
table => table
@@ -32,6 +34,11 @@ namespace Orchard.Core.Containers {
.Column<string>("CustomTwo")
.Column<string>("CustomThree"));
SchemaBuilder.CreateTable("ContainablePartRecord",
table => table
.ContentPartRecord()
.Column<int>("Weight"));
ContentDefinitionManager.AlterTypeDefinition("ContainerWidget",
cfg => cfg
.WithPart("CommonPart")
@@ -43,12 +50,24 @@ namespace Orchard.Core.Containers {
ContentDefinitionManager.AlterPartDefinition("ContainablePart", builder => builder.Attachable());
ContentDefinitionManager.AlterPartDefinition("CustomPropertiesPart", builder => builder.Attachable());
return 1;
return 3;
}
public int UpdateFrom1() {
SchemaBuilder.AlterTable("ContainerPartRecord", table => table.AddColumn<string>("ItemContentType"));
return 2;
}
public int UpdateFrom2() {
SchemaBuilder.AlterTable("ContainerPartRecord",
table => table.AddColumn<bool>("ItemsShown", column => column.WithDefault(true)));
SchemaBuilder.CreateTable("ContainablePartRecord",
table => table
.ContentPartRecord()
.Column<int>("Weight"));
return 3;
}
}
}

View File

@@ -1,6 +1,15 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.Records;
namespace Orchard.Core.Containers.Models {
public class ContainablePart : ContentPart {
public class ContainablePart : ContentPart<ContainablePartRecord> {
public int Weight {
get { return Record.Weight; }
set { Record.Weight = value; }
}
}
public class ContainablePartRecord : ContentPartRecord {
public virtual int Weight { get; set; }
}
}

View File

@@ -1,12 +1,49 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.Records;
using Orchard.UI.Navigation;
namespace Orchard.Core.Containers.Models {
public class ContainerPart : ContentPart<ContainerPartRecord> {
public string ItemContentType {
get { return Record.ItemContentType; }
set { Record.ItemContentType = value; }
}
public bool ItemsShown {
get { return Record.ItemsShown; }
set { Record.ItemsShown = value; }
}
public bool Paginated {
get { return Record.Paginated; }
set { Record.Paginated = value; }
}
public int PageSize {
get { return Record.PageSize; }
set { Record.PageSize = value; }
}
public string OrderByProperty {
get { return Record.OrderByProperty; }
set { Record.OrderByProperty = value; }
}
public int OrderByDirection {
get { return Record.OrderByDirection; }
set { Record.OrderByDirection = value; }
}
public PagerParameters PagerParameters { get; set; }
public ContainerPart() {
PagerParameters = new PagerParameters();
}
}
public class ContainerPartRecord : ContentPartRecord {
public virtual string ItemContentType { get; set; }
public virtual bool ItemsShown { get; set; }
public virtual bool Paginated { get; set; }
public virtual int PageSize { get; set; }
public virtual string OrderByProperty { get; set; }

View File

@@ -4,6 +4,9 @@
Parts_Container_Contained
Parts_Container_Contained_Summary
-->
<Match DisplayType="Detail">
<Place Parts_Container_Contained="Content:7.5"/>
</Match>
<Place Parts_Containable_Edit="Content:before.3"/>
<Place Parts_Container_Edit="Content:5"/>
<Place Parts_CustomProperties_Edit="Content:5"/>

View File

@@ -4,5 +4,6 @@ namespace Orchard.Core.Containers.ViewModels {
public class ContainableViewModel {
public int ContainerId { get; set; }
public SelectList AvailableContainers { get; set; }
public int Weight { get; set; }
}
}

View File

@@ -1,5 +1,11 @@
@model Orchard.Core.Containers.ViewModels.ContainableViewModel
<fieldset>
@Html.LabelFor(m => m.ContainerId, T("Add to"))
@Html.DropDownListFor(m => m.ContainerId, Model.AvailableContainers)
<span>
@Html.LabelFor(m => m.ContainerId, T("Add to"))
@Html.DropDownListFor(m => m.ContainerId, Model.AvailableContainers)
</span>
<span>
@Html.LabelFor(m => m.Weight, T("Weight"))
@Html.TextBoxFor(m => m.Weight, new { @class = "text text-small" })
</span>
</fieldset>

View File

@@ -1,34 +1,41 @@
@model Orchard.Core.Containers.ViewModels.ContainerViewModel
@using Orchard.Core.Containers.Models;
<fieldset class="with-checkbox">
<span class="checkbox-and-label">
@Html.CheckBoxFor(m => m.Part.ItemsShown)
<label for="@Html.FieldIdFor(m => m.Part.ItemsShown)" class="forcheckbox">@T("Show contained items list")</label>
</span>
</fieldset>
<fieldset>
@Html.LabelFor(m => m.Part.Record.ItemContentType, T("Contains"))
@Html.DropDownListFor(m => m.Part.Record.ItemContentType, Model.AvailableContainables)
@Html.LabelFor(m => m.Part.ItemContentType, T("Contains"))
@Html.DropDownListFor(m => m.Part.ItemContentType, Model.AvailableContainables)
<span class="hint">@T("Only types with the Containable part can be contained in a list.")</span>
</fieldset>
<fieldset>
@Html.LabelFor(m => m.Part.Record.OrderByProperty, T("Order by"))
<select id="@Html.FieldIdFor(m => m.Part.Record.OrderByProperty)" name="@Html.FieldNameFor(m => m.Part.Record.OrderByProperty)">
@Html.SelectOption(Model.Part.Record.OrderByProperty, "CommonPart.CreatedUtc", T("Date Created").Text)
@Html.SelectOption(Model.Part.Record.OrderByProperty, "CommonPart.PublishedUtc", T("Date Published").Text)
@Html.SelectOption(Model.Part.Record.OrderByProperty, "TitlePart.Title", T("Title").Text)
@Html.SelectOption(Model.Part.Record.OrderByProperty, "RoutePart.Title", T("Routable Title").Text)
@Html.SelectOption(Model.Part.Record.OrderByProperty, "RoutePart.Slug", T("Slug").Text)
@Html.SelectOption(Model.Part.Record.OrderByProperty, "CustomPropertiesPart.CustomOne", T("Custom 1").Text)
@Html.SelectOption(Model.Part.Record.OrderByProperty, "CustomPropertiesPart.CustomTwo", T("Custom 2").Text)
@Html.SelectOption(Model.Part.Record.OrderByProperty, "CustomPropertiesPart.CustomThree", T("Custom 3").Text)
@Html.LabelFor(m => m.Part.OrderByProperty, T("Order by"))
<select id="@Html.FieldIdFor(m => m.Part.OrderByProperty)" name="@Html.FieldNameFor(m => m.Part.OrderByProperty)">
@Html.SelectOption(Model.Part.OrderByProperty, "ContainablePart.Weight", T("Weight").Text)
@Html.SelectOption(Model.Part.OrderByProperty, "CommonPart.CreatedUtc", T("Date Created").Text)
@Html.SelectOption(Model.Part.OrderByProperty, "CommonPart.PublishedUtc", T("Date Published").Text)
@Html.SelectOption(Model.Part.OrderByProperty, "TitlePart.Title", T("Title").Text)
@Html.SelectOption(Model.Part.OrderByProperty, "RoutePart.Title", T("Routable Title").Text)
@Html.SelectOption(Model.Part.OrderByProperty, "RoutePart.Slug", T("Slug").Text)
@Html.SelectOption(Model.Part.OrderByProperty, "CustomPropertiesPart.CustomOne", T("Custom 1").Text)
@Html.SelectOption(Model.Part.OrderByProperty, "CustomPropertiesPart.CustomTwo", T("Custom 2").Text)
@Html.SelectOption(Model.Part.OrderByProperty, "CustomPropertiesPart.CustomThree", T("Custom 3").Text)
</select>
<select id="@Html.FieldIdFor(m => m.Part.Record.OrderByDirection)" name="@Html.FieldNameFor(m => m.Part.Record.OrderByDirection)">
@Html.SelectOption(Model.Part.Record.OrderByDirection, (int)OrderByDirection.Ascending, T("Ascending").Text)
@Html.SelectOption(Model.Part.Record.OrderByDirection, (int)OrderByDirection.Descending, T("Descending").Text)
<select id="@Html.FieldIdFor(m => m.Part.OrderByDirection)" name="@Html.FieldNameFor(m => m.Part.OrderByDirection)">
@Html.SelectOption(Model.Part.OrderByDirection, (int)OrderByDirection.Ascending, T("Ascending").Text)
@Html.SelectOption(Model.Part.OrderByDirection, (int)OrderByDirection.Descending, T("Descending").Text)
</select>
</fieldset>
<fieldset class="with-checkbox">
<span>
@Html.LabelFor(m => m.Part.Record.PageSize, T("Page size"))
@Html.TextBoxFor(m => m.Part.Record.PageSize, new { @class = "text text-small" })
@Html.LabelFor(m => m.Part.PageSize, T("Page size"))
@Html.TextBoxFor(m => m.Part.PageSize, new { @class = "text text-small" })
</span>
<span class="checkbox-and-label">
@Html.CheckBoxFor(m => m.Part.Record.Paginated)
<label for="@Html.FieldIdFor(m => m.Part.Record.Paginated)" class="forcheckbox">@T("Show paging controls")</label>
@Html.CheckBoxFor(m => m.Part.Paginated)
<label for="@Html.FieldIdFor(m => m.Part.Paginated)" class="forcheckbox">@T("Show paging controls")</label>
</span>
</fieldset>

View File

@@ -89,6 +89,8 @@
<Compile Include="Containers\Drivers\ContainerWidgetPartDriver.cs" />
<Compile Include="Containers\Drivers\CustomPropertiesDriver.cs" />
<Compile Include="Containers\Extensions\ContentQueryExtensions.cs" />
<Compile Include="Containers\Handlers\ContainablePartHandler.cs" />
<Compile Include="Containers\Handlers\ContainerPartHandler.cs" />
<Compile Include="Containers\Migrations.cs" />
<Compile Include="Containers\Models\ContainablePart.cs" />
<Compile Include="Containers\Models\ContainerPart.cs" />