#18165: Injecting ContentPart, ContentItem and ContentField properties automatically in any Shape

Work Item: 18165

--HG--
branch : 1.x
This commit is contained in:
Sebastien Ros
2011-12-30 15:26:41 -08:00
parent 28a0b2fde6
commit 19f8286258
20 changed files with 141 additions and 85 deletions

View File

@@ -78,7 +78,7 @@ namespace Orchard.Tests.ContentManagement.Handlers.Coordinators {
}
protected override DriverResult Display(StubPart part, string displayType, dynamic shapeHelper) {
var stub = shapeHelper.Stub(ContentPart: part, Foo: string.Join(",", part.Foo));
var stub = shapeHelper.Stub(Foo: string.Join(",", part.Foo));
if (!string.IsNullOrWhiteSpace(displayType))
stub.Metadata.Type = string.Format("{0}.{1}", stub.Metadata.Type, displayType);
return ContentShape(stub).Location("TopMeta");

View File

@@ -34,12 +34,12 @@ namespace Orchard.Core.Common.Drivers {
ContentShape("Parts_Common_Body",
() => {
var bodyText = _htmlFilters.Aggregate(part.Text, (text, filter) => filter.ProcessContent(text, GetFlavor(part)));
return shapeHelper.Parts_Common_Body(ContentPart: part, Html: new HtmlString(bodyText));
return shapeHelper.Parts_Common_Body(Html: new HtmlString(bodyText));
}),
ContentShape("Parts_Common_Body_Summary",
() => {
var bodyText = _htmlFilters.Aggregate(part.Text, (text, filter) => filter.ProcessContent(text, GetFlavor(part)));
return shapeHelper.Parts_Common_Body_Summary(ContentPart: part, Html: new HtmlString(bodyText));
return shapeHelper.Parts_Common_Body_Summary(Html: new HtmlString(bodyText));
})
);
}

View File

@@ -38,11 +38,11 @@ namespace Orchard.Core.Common.Drivers {
protected override DriverResult Display(CommonPart part, string displayType, dynamic shapeHelper) {
return Combined(
ContentShape("Parts_Common_Metadata",
() => shapeHelper.Parts_Common_Metadata(ContentPart: part)),
() => shapeHelper.Parts_Common_Metadata()),
ContentShape("Parts_Common_Metadata_Summary",
() => shapeHelper.Parts_Common_Metadata_Summary(ContentPart: part)),
() => shapeHelper.Parts_Common_Metadata_Summary()),
ContentShape("Parts_Common_Metadata_SummaryAdmin",
() => shapeHelper.Parts_Common_Metadata_SummaryAdmin(ContentPart: part))
() => shapeHelper.Parts_Common_Metadata_SummaryAdmin())
);
}

View File

@@ -26,7 +26,7 @@ namespace Orchard.Core.Common.Drivers {
protected override DriverResult Display(ContentPart part, TextField field, string displayType, dynamic shapeHelper) {
return ContentShape("Fields_Common_Text", GetDifferentiator(field, part),
() => shapeHelper.Fields_Common_Text(ContentPart: part, ContentField: field, Name: field.Name, Value: field.Value));
() => shapeHelper.Fields_Common_Text(Name: field.Name, Value: field.Value));
}
protected override DriverResult Editor(ContentPart part, TextField field, dynamic shapeHelper) {

View File

@@ -8,11 +8,11 @@ namespace Orchard.Core.Contents.Drivers {
protected override DriverResult Display(ContentPart part, string displayType, dynamic shapeHelper) {
return Combined(
ContentShape("Parts_Contents_Publish",
() => shapeHelper.Parts_Contents_Publish(ContentPart: part)),
() => shapeHelper.Parts_Contents_Publish()),
ContentShape("Parts_Contents_Publish_Summary",
() => shapeHelper.Parts_Contents_Publish_Summary(ContentPart: part)),
() => shapeHelper.Parts_Contents_Publish_Summary()),
ContentShape("Parts_Contents_Publish_SummaryAdmin",
() => shapeHelper.Parts_Contents_Publish_SummaryAdmin(ContentPart: part))
() => shapeHelper.Parts_Contents_Publish_SummaryAdmin())
);
}

View File

@@ -50,11 +50,11 @@ namespace Orchard.Core.Routable.Drivers {
protected override DriverResult Display(RoutePart part, string displayType, dynamic shapeHelper) {
return Combined(
ContentShape("Parts_RoutableTitle",
() => shapeHelper.Parts_RoutableTitle(ContentPart: part, Title: part.Title, Path: part.Path)),
() => shapeHelper.Parts_RoutableTitle(Title: part.Title, Path: part.Path)),
ContentShape("Parts_RoutableTitle_Summary",
() => shapeHelper.Parts_RoutableTitle_Summary(ContentPart: part, Title: part.Title, Path: part.Path)),
() => shapeHelper.Parts_RoutableTitle_Summary(Title: part.Title, Path: part.Path)),
ContentShape("Parts_RoutableTitle_SummaryAdmin",
() => shapeHelper.Parts_RoutableTitle_SummaryAdmin(ContentPart: part, Title: part.Title, Path: part.Path))
() => shapeHelper.Parts_RoutableTitle_SummaryAdmin(Title: part.Title, Path: part.Path))
);
}

View File

@@ -18,11 +18,11 @@ namespace Orchard.Core.Title.Drivers {
protected override DriverResult Display(TitlePart part, string displayType, dynamic shapeHelper) {
return Combined(
ContentShape("Parts_Title",
() => shapeHelper.Parts_Title(ContentPart: part, Title: part.Title)),
() => shapeHelper.Parts_Title(Title: part.Title)),
ContentShape("Parts_Title_Summary",
() => shapeHelper.Parts_Title_Summary(ContentPart: part, Title: part.Title)),
() => shapeHelper.Parts_Title_Summary(Title: part.Title)),
ContentShape("Parts_Title_SummaryAdmin",
() => shapeHelper.Parts_Title_SummaryAdmin(ContentPart: part, Title: part.Title))
() => shapeHelper.Parts_Title_SummaryAdmin(Title: part.Title))
);
}

View File

@@ -30,7 +30,7 @@ namespace Orchard.Blogs.Drivers {
if (blog == null)
return null;
return shapeHelper.Parts_Blogs_BlogArchives(ContentItem: part.ContentItem, Blog: blog, Archives: _blogPostService.GetArchives(blog));
return shapeHelper.Parts_Blogs_BlogArchives(Blog: blog, Archives: _blogPostService.GetArchives(blog));
});
}

View File

@@ -11,13 +11,13 @@ namespace Orchard.Blogs.Drivers {
protected override DriverResult Display(BlogPart part, string displayType, dynamic shapeHelper) {
return Combined(
ContentShape("Parts_Blogs_Blog_Manage",
() => shapeHelper.Parts_Blogs_Blog_Manage(ContentPart: part)),
() => shapeHelper.Parts_Blogs_Blog_Manage()),
ContentShape("Parts_Blogs_Blog_Description",
() => shapeHelper.Parts_Blogs_Blog_Description(ContentPart: part, Description: part.Description)),
() => shapeHelper.Parts_Blogs_Blog_Description(Description: part.Description)),
ContentShape("Parts_Blogs_Blog_SummaryAdmin",
() => shapeHelper.Parts_Blogs_Blog_SummaryAdmin(ContentPart: part, ContentItem: part.ContentItem)),
() => shapeHelper.Parts_Blogs_Blog_SummaryAdmin()),
ContentShape("Parts_Blogs_Blog_BlogPostCount",
() => shapeHelper.Parts_Blogs_Blog_BlogPostCount(ContentPart: part, PostCount: part.PostCount))
() => shapeHelper.Parts_Blogs_Blog_BlogPostCount(PostCount: part.PostCount))
);
}

View File

@@ -23,24 +23,26 @@ namespace Orchard.Blogs.Drivers {
}
protected override DriverResult Display(RecentBlogPostsPart part, string displayType, dynamic shapeHelper) {
BlogPart blog = GetBlogFromSlug(part.ForBlog);
return ContentShape("Parts_Blogs_RecentBlogPosts", () => {
BlogPart blog = GetBlogFromSlug(part.ForBlog);
if (blog == null) {
return null;
}
if (blog == null) {
return null;
}
var blogPosts =_contentManager.Query(VersionOptions.Published, "BlogPost")
.Join<CommonPartRecord>().Where(cr => cr.Container == blog.Record.ContentItemRecord)
.OrderByDescending(cr => cr.CreatedUtc)
.Slice(0, part.Count)
.Select(ci => ci.As<BlogPostPart>());
var blogPosts = _contentManager.Query(VersionOptions.Published, "BlogPost")
.Join<CommonPartRecord>().Where(cr => cr.Container == blog.Record.ContentItemRecord)
.OrderByDescending(cr => cr.CreatedUtc)
.Slice(0, part.Count)
.Select(ci => ci.As<BlogPostPart>());
var list = shapeHelper.List();
list.AddRange(blogPosts.Select(bp => _contentManager.BuildDisplay(bp, "Summary")));
var list = shapeHelper.List();
list.AddRange(blogPosts.Select(bp => _contentManager.BuildDisplay(bp, "Summary")));
var blogPostList = shapeHelper.Parts_Blogs_BlogPost_List(ContentPart: part, ContentItems: list);
var blogPostList = shapeHelper.Parts_Blogs_BlogPost_List(ContentItems: list);
return ContentShape(shapeHelper.Parts_Blogs_RecentBlogPosts(ContentItem: part.ContentItem, ContentItems: blogPostList, Blog: blog));
return shapeHelper.Parts_Blogs_RecentBlogPosts(ContentItems: blogPostList, Blog: blog);
});
}
protected override DriverResult Editor(RecentBlogPostsPart part, dynamic shapeHelper) {

View File

@@ -21,9 +21,9 @@ namespace Orchard.Comments.Drivers {
return Combined(
ContentShape("Parts_Comments_Count",
() => shapeHelper.Parts_Comments_Count(ContentPart: part, CommentCount: commentsForCommentedContent.Count(), PendingCount: pendingCount)),
() => shapeHelper.Parts_Comments_Count(CommentCount: commentsForCommentedContent.Count(), PendingCount: pendingCount)),
ContentShape("Parts_Comments_Count_SummaryAdmin",
() => shapeHelper.Parts_Comments_Count_SummaryAdmin(ContentPart: part, CommentCount: commentsForCommentedContent.Count(), PendingCount: pendingCount))
() => shapeHelper.Parts_Comments_Count_SummaryAdmin(CommentCount: commentsForCommentedContent.Count(), PendingCount: pendingCount))
);
}
}

View File

@@ -23,11 +23,11 @@ namespace Orchard.Comments.Drivers {
return Combined(
ContentShape("Parts_Comments",
() => shapeHelper.Parts_Comments(ContentPart: part)),
() => shapeHelper.Parts_Comments()),
ContentShape("Parts_Comments_Count",
() => shapeHelper.Parts_Comments_Count(ContentPart: part, CommentCount: commentsForCommentedContent.Count(), PendingCount: pendingCount)),
() => shapeHelper.Parts_Comments_Count(CommentCount: commentsForCommentedContent.Count(), PendingCount: pendingCount)),
ContentShape("Parts_Comments_Count_SummaryAdmin",
() => shapeHelper.Parts_Comments_Count_SummaryAdmin(ContentPart: part, CommentCount: commentsForCommentedContent.Count(), PendingCount: pendingCount))
() => shapeHelper.Parts_Comments_Count_SummaryAdmin(CommentCount: commentsForCommentedContent.Count(), PendingCount: pendingCount))
);
}

View File

@@ -1,15 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Containers.Models;
namespace Orchard.Lists.Drivers {
public class ContainerPartDriver : ContentPartDriver<ContainerPart>{
protected override DriverResult Display(ContainerPart part, string displayType, dynamic shapeHelper) {
return ContentShape("Parts_Container_Contained_SummaryAdmin",
() => shapeHelper.Parts_Container_Contained_SummaryAdmin(ContentPart: part)
() => shapeHelper.Parts_Container_Contained_SummaryAdmin()
);
}
}

View File

@@ -27,11 +27,11 @@ namespace Orchard.Localization.Drivers {
: part.Id;
return Combined(
ContentShape("Parts_Localization_ContentTranslations",
() => shapeHelper.Parts_Localization_ContentTranslations(ContentPart: part, MasterId: masterId, Localizations: GetDisplayLocalizations(part, VersionOptions.Published))),
() => shapeHelper.Parts_Localization_ContentTranslations(MasterId: masterId, Localizations: GetDisplayLocalizations(part, VersionOptions.Published))),
ContentShape("Parts_Localization_ContentTranslations_Summary",
() => shapeHelper.Parts_Localization_ContentTranslations_Summary(ContentPart: part, MasterId: masterId, Localizations: GetDisplayLocalizations(part, VersionOptions.Published))),
() => shapeHelper.Parts_Localization_ContentTranslations_Summary(MasterId: masterId, Localizations: GetDisplayLocalizations(part, VersionOptions.Published))),
ContentShape("Parts_Localization_ContentTranslations_SummaryAdmin",
() => shapeHelper.Parts_Localization_ContentTranslations_SummaryAdmin(ContentPart: part, MasterId: masterId, Localizations: GetDisplayLocalizations(part, VersionOptions.Latest)))
() => shapeHelper.Parts_Localization_ContentTranslations_SummaryAdmin(MasterId: masterId, Localizations: GetDisplayLocalizations(part, VersionOptions.Latest)))
);
}

View File

@@ -42,11 +42,11 @@ namespace Orchard.PublishLater.Drivers {
protected override DriverResult Display(PublishLaterPart part, string displayType, dynamic shapeHelper) {
return Combined(
ContentShape("Parts_PublishLater_Metadata",
() => shapeHelper.Parts_PublishLater_Metadata(ContentPart: part, ScheduledPublishUtc: part.ScheduledPublishUtc.Value)),
() => shapeHelper.Parts_PublishLater_Metadata(ScheduledPublishUtc: part.ScheduledPublishUtc.Value)),
ContentShape("Parts_PublishLater_Metadata_Summary",
() => shapeHelper.Parts_PublishLater_Metadata_Summary(ContentPart: part, ScheduledPublishUtc: part.ScheduledPublishUtc.Value)),
() => shapeHelper.Parts_PublishLater_Metadata_Summary(ScheduledPublishUtc: part.ScheduledPublishUtc.Value)),
ContentShape("Parts_PublishLater_Metadata_SummaryAdmin",
() => shapeHelper.Parts_PublishLater_Metadata_SummaryAdmin(ContentPart: part, ScheduledPublishUtc: part.ScheduledPublishUtc.Value))
() => shapeHelper.Parts_PublishLater_Metadata_SummaryAdmin(ScheduledPublishUtc: part.ScheduledPublishUtc.Value))
);
}

View File

@@ -33,7 +33,7 @@ namespace Orchard.Tags.Drivers {
protected override DriverResult Display(TagsPart part, string displayType, dynamic shapeHelper) {
return ContentShape("Parts_Tags_ShowTags",
() => shapeHelper.Parts_Tags_ShowTags(ContentPart: part, Tags: part.CurrentTags));
() => shapeHelper.Parts_Tags_ShowTags(Tags: part.CurrentTags));
}
protected override DriverResult Editor(TagsPart part, dynamic shapeHelper) {

View File

@@ -16,15 +16,27 @@ namespace Orchard.ContentManagement.Drivers {
}
DriverResult IContentFieldDriver.BuildDisplayShape(BuildDisplayContext context) {
return Process(context.ContentItem, (part, field) => Display(part, field, context.DisplayType, context.New));
return Process(context.ContentItem, (part, field) => {
context.ContentPart = part;
context.ContentField = field;
return Display(part, field, context.DisplayType, context.New);
});
}
DriverResult IContentFieldDriver.BuildEditorShape(BuildEditorContext context) {
return Process(context.ContentItem, (part, field) => Editor(part, field, context.New));
return Process(context.ContentItem, (part, field) => {
context.ContentPart = part;
context.ContentField = field;
return Editor(part, field, context.New);
});
}
DriverResult IContentFieldDriver.UpdateEditorShape(UpdateEditorContext context) {
return Process(context.ContentItem, (part, field) => Editor(part, field, context.Updater, context.New));
return Process(context.ContentItem, (part, field) => {
context.ContentPart = part;
context.ContentField = field;
return Editor(part, field, context.Updater, context.New);
});
}
void IContentFieldDriver.Importing(ImportContentContext context) {
@@ -75,7 +87,7 @@ namespace Orchard.ContentManagement.Drivers {
return contentFieldInfo;
}
protected virtual void GetContentItemMetadata(ContentPart part, TField field, ContentItemMetadata metadata) { return; }
protected virtual void GetContentItemMetadata(ContentPart part, TField field, ContentItemMetadata metadata) { }
protected virtual DriverResult Display(ContentPart part, TField field, string displayType, dynamic shapeHelper) { return null; }
protected virtual DriverResult Editor(ContentPart part, TField field, dynamic shapeHelper) { return null; }
@@ -105,19 +117,34 @@ namespace Orchard.ContentManagement.Drivers {
}
private ContentShapeResult ContentShapeImplementation(string shapeType, string differentiator, Func<BuildShapeContext, object> shapeBuilder) {
return new ContentShapeResult(shapeType, Prefix, ctx => AddAlternates(shapeBuilder(ctx), differentiator)).Differentiator(differentiator);
return new ContentShapeResult(shapeType, Prefix, ctx => AddAlternates(shapeBuilder(ctx), ctx, differentiator)).Differentiator(differentiator);
}
private static object AddAlternates(dynamic shape, string differentiator) {
private static object AddAlternates(dynamic shape, BuildShapeContext ctx, string differentiator) {
// automatically add shape alternates for shapes added by fields
// for fields on dynamic parts the part name is the same as the content type name
ShapeMetadata metadata = shape.Metadata;
ContentPart part = shape.ContentPart;
// if no ContentField property has been set, assign it
if (shape.ContentPart == null) {
shape.ContentPart = ctx.ContentField;
}
// if no ContentPart property has been set, assign it
if (shape.ContentPart == null) {
shape.ContentPart = ctx.ContentPart;
}
// if no ContentItem property has been set, assign it
if (shape.ContentItem == null) {
shape.ContentItem = ctx.ContentItem;
}
var shapeType = metadata.Type;
var fieldName = differentiator ?? String.Empty;
var partName = part != null ? part.PartDefinition.Name : String.Empty;
var contentType = part != null ? part.ContentItem.ContentType : String.Empty;
var partName = shape.ContentPart.PartDefinition.Name;
var contentType = shape.ContentItem.ContentType;
var dynamicType = string.Equals(partName, contentType, StringComparison.Ordinal);
// [ShapeType__FieldName] e.g. Fields/Common.Text-Teaser

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData;
using Orchard.DisplayManagement;
@@ -17,17 +18,38 @@ namespace Orchard.ContentManagement.Drivers {
DriverResult IContentPartDriver.BuildDisplay(BuildDisplayContext context) {
var part = context.ContentItem.As<TContent>();
return part == null ? null : Display(part, context.DisplayType, context.New);
if(part == null) {
return null;
}
context.ContentPart = part;
return Display(part, context.DisplayType, context.New);
}
DriverResult IContentPartDriver.BuildEditor(BuildEditorContext context) {
var part = context.ContentItem.As<TContent>();
return part == null ? null : Editor(part, context.New);
if (part == null) {
return null;
}
context.ContentPart = part;
return Editor(part, context.New);
}
DriverResult IContentPartDriver.UpdateEditor(UpdateEditorContext context) {
var part = context.ContentItem.As<TContent>();
return part == null ? null : Editor(part, context.Updater, context.New);
if (part == null) {
return null;
}
context.ContentPart = part;
return Editor(part, context.Updater, context.New);
}
void IContentPartDriver.Importing(ImportContentContext context) {
@@ -54,16 +76,16 @@ namespace Orchard.ContentManagement.Drivers {
Exported(part, context);
}
protected virtual void GetContentItemMetadata(TContent context, ContentItemMetadata metadata) { return; }
protected virtual void GetContentItemMetadata(TContent context, ContentItemMetadata metadata) {}
protected virtual DriverResult Display(TContent part, string displayType, dynamic shapeHelper) { return null; }
protected virtual DriverResult Editor(TContent part, dynamic shapeHelper) { return null; }
protected virtual DriverResult Editor(TContent part, IUpdateModel updater, dynamic shapeHelper) { return null; }
protected virtual void Importing(TContent part, ImportContentContext context) { return; }
protected virtual void Imported(TContent part, ImportContentContext context) { return; }
protected virtual void Exporting(TContent part, ExportContentContext context) { return; }
protected virtual void Exported(TContent part, ExportContentContext context) { return; }
protected virtual void Importing(TContent part, ImportContentContext context) {}
protected virtual void Imported(TContent part, ImportContentContext context) {}
protected virtual void Exporting(TContent part, ExportContentContext context) {}
protected virtual void Exported(TContent part, ExportContentContext context) {}
[Obsolete("Provided while transitioning to factory variations")]
public ContentShapeResult ContentShape(IShape shape) {
@@ -79,26 +101,30 @@ namespace Orchard.ContentManagement.Drivers {
}
private ContentShapeResult ContentShapeImplementation(string shapeType, Func<BuildShapeContext, object> shapeBuilder) {
return new ContentShapeResult(shapeType, Prefix, ctx => AddAlternates(shapeBuilder(ctx)));
return new ContentShapeResult(shapeType, Prefix, ctx => AddAlternates(shapeBuilder(ctx), ctx));
}
private static object AddAlternates(dynamic shape) {
private static dynamic AddAlternates(dynamic shape, BuildShapeContext ctx) {
ShapeMetadata metadata = shape.Metadata;
ContentPart part = shape.ContentPart;
var id = part != null ? part.ContentItem.Id.ToString() : String.Empty;
// if no ContentPart property has been set, assign it
if (shape.ContentPart == null) {
shape.ContentPart = ctx.ContentPart;
}
// if no ContentItem property has been set, assign it
if (shape.ContentItem == null) {
shape.ContentItem = ctx.ContentItem;
}
var shapeType = metadata.Type;
var contentType = part != null ? part.ContentItem.ContentType : String.Empty;
// [ShapeType]__[Id] e.g. Parts/Common.Metadata-42
if ( !string.IsNullOrEmpty(id) ) {
metadata.Alternates.Add(shapeType + "__" + id);
}
metadata.Alternates.Add(shapeType + "__" + ctx.ContentItem.Id.ToString(CultureInfo.InvariantCulture));
// [ShapeType]__[ContentType] e.g. Parts/Common.Metadata-BlogPost
if ( !string.IsNullOrEmpty(contentType) ) {
metadata.Alternates.Add(shapeType + "__" + contentType);
}
metadata.Alternates.Add(shapeType + "__" + ctx.ContentItem.ContentType);
return shape;
}

View File

@@ -1,12 +1,14 @@
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData;
using Orchard.Logging;
namespace Orchard.ContentManagement.Drivers.Coordinators {
[UsedImplicitly]
/// <summary>
/// This component coordinates how parts are taking part in the rendering when some content needs to be rendered.
/// It will dispatch BuildDisplay/BuildEditor to all <see cref="IContentPartDriver"/> implementations.
/// </summary>
public class ContentPartDriverCoordinator : ContentHandlerBase {
private readonly IEnumerable<IContentPartDriver> _drivers;
private readonly IContentDefinitionManager _contentDefinitionManager;

View File

@@ -1,12 +1,12 @@
using System;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy;
namespace Orchard.ContentManagement.Handlers {
public class BuildShapeContext {
protected BuildShapeContext(IShape shape, IContent content, string groupId, IShapeFactory shapeFactory) {
Shape = shape;
Content = content;
ContentItem = content.ContentItem;
New = shapeFactory;
GroupId = groupId;
@@ -14,7 +14,10 @@ namespace Orchard.ContentManagement.Handlers {
}
public dynamic Shape { get; private set; }
public IContent Content { get; private set; }
public ContentItem ContentItem { get; private set; }
public ContentPart ContentPart { get; set; }
public ContentField ContentField { get; set; }
public dynamic New { get; private set; }
public string GroupId { get; private set; }