From 40e4be78cb3e58e1794312cb57fa699e353c658b Mon Sep 17 00:00:00 2001 From: loudej Date: Thu, 10 Dec 2009 08:23:27 +0000 Subject: [PATCH] Adding a PartDriver concept to try and drive down complexity --HG-- extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4043668 --- .../Models/PartDriverHandlerTests.cs | 101 +++++++++++++ src/Orchard.Tests/Orchard.Tests.csproj | 4 + src/Orchard/Models/PartDriver.cs | 137 ++++++++++++++++++ .../Models/ViewModels/ItemDisplayModel.cs | 1 + src/Orchard/Orchard.csproj | 1 + 5 files changed, 244 insertions(+) create mode 100644 src/Orchard.Tests/Models/PartDriverHandlerTests.cs create mode 100644 src/Orchard/Models/PartDriver.cs diff --git a/src/Orchard.Tests/Models/PartDriverHandlerTests.cs b/src/Orchard.Tests/Models/PartDriverHandlerTests.cs new file mode 100644 index 000000000..b4415c279 --- /dev/null +++ b/src/Orchard.Tests/Models/PartDriverHandlerTests.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using Autofac; +using Autofac.Builder; +using Autofac.Modules; +using Moq; +using NUnit.Framework; +using Orchard.Models; +using Orchard.Models.Driver; +using Orchard.Models.ViewModels; + +namespace Orchard.Tests.Models { + [TestFixture] + public class PartDriverHandlerTests { + private IContainer _container; + + [SetUp] + public void Init() { + var builder = new ContainerBuilder(); + builder.RegisterModule(new ImplicitCollectionSupportModule()); + builder.Register().As(); + _container = builder.Build(); + } + + [Test] + public void DriverHandlerShouldNotThrowException() { + var contentHandler = _container.Resolve(); + contentHandler.BuildDisplayModel(null); + } + + [Test] + public void AllDriversShouldBeCalled() { + var driver1 = new Mock(); + var driver2 = new Mock(); + _container.Build(x => { + x.Register(driver1.Object); + x.Register(driver2.Object); + }); + var contentHandler = _container.Resolve(); + + var ctx = new BuildDisplayModelContext(new ItemDisplayModel(new ContentItem()), null, null); + + driver1.Verify(x => x.BuildDisplayModel(ctx), Times.Never()); + contentHandler.BuildDisplayModel(ctx); + driver1.Verify(x => x.BuildDisplayModel(ctx)); + } + + [Test] + public void TestDriverCanAddDisplay() { + var driver = new StubDriver(); + _container.Build(x => x.Register(driver).As()); + + var contentHandler = _container.Resolve(); + + var item = new ContentItem(); + item.Weld(new StubPart()); + + var ctx = new BuildDisplayModelContext(new ItemDisplayModel(item), null, null); + Assert.That(ctx.DisplayModel.Displays.Count(), Is.EqualTo(0)); + contentHandler.BuildDisplayModel(ctx); + Assert.That(ctx.DisplayModel.Displays.Count(), Is.EqualTo(1)); + Assert.That(ctx.DisplayModel.Displays.Single().Prefix, Is.EqualTo("Stub")); + + } + + private class StubDriver : PartDriver { + protected override string Prefix { + get { return "Stub"; } + } + + protected override DriverResult Display(StubPart part, string groupName, string displayType) { + var viewModel = new StubViewModel { Foo = string.Join(",", part.Foo) }; + return PartialView(viewModel); + } + + protected override DriverResult Editor(StubPart part, string groupName) { + var viewModel = new StubViewModel { Foo = string.Join(",", part.Foo) }; + return PartialView(viewModel); + } + + protected override DriverResult Editor(StubPart part, string groupName, IUpdateModel updater) { + var viewModel = new StubViewModel { Foo = string.Join(",", part.Foo) }; + updater.TryUpdateModel(viewModel, Prefix, null, null); + part.Foo = viewModel.Foo.Split(new[] {','}).Select(x => x.Trim()).ToArray(); + return PartialView(viewModel); + } + } + + private class StubPart : ContentPart { + public string[] Foo { get; set; } + } + private class StubViewModel { + [Required] + public string Foo { get; set; } + } + } + +} diff --git a/src/Orchard.Tests/Orchard.Tests.csproj b/src/Orchard.Tests/Orchard.Tests.csproj index 93fc5190e..691a3f8c1 100644 --- a/src/Orchard.Tests/Orchard.Tests.csproj +++ b/src/Orchard.Tests/Orchard.Tests.csproj @@ -66,6 +66,9 @@ ..\..\lib\nunit\nunit.framework.dll + + 3.5 + 3.5 @@ -117,6 +120,7 @@ + diff --git a/src/Orchard/Models/PartDriver.cs b/src/Orchard/Models/PartDriver.cs new file mode 100644 index 000000000..09ac824cf --- /dev/null +++ b/src/Orchard/Models/PartDriver.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; +using Orchard.Logging; +using Orchard.Models.Driver; +using Orchard.Models.ViewModels; + +namespace Orchard.Models { + public interface IPartDriver : IEvents { + DriverResult BuildDisplayModel(BuildDisplayModelContext context); + DriverResult BuildEditorModel(BuildEditorModelContext context); + DriverResult UpdateEditorModel(UpdateEditorModelContext context); + } + + + public abstract class PartDriver : IPartDriver where TPart : class, IContent { + DriverResult IPartDriver.BuildDisplayModel(BuildDisplayModelContext context) { + var part = context.ContentItem.As(); + return part == null ? null : BuildDisplayModel(part, context.GroupName, context.DisplayType); + } + + DriverResult IPartDriver.BuildEditorModel(BuildEditorModelContext context) { + var part = context.ContentItem.As(); + return part == null ? null : BuildEditorModel(part, context.GroupName); + } + + DriverResult IPartDriver.UpdateEditorModel(UpdateEditorModelContext context) { + var part = context.ContentItem.As(); + return part == null ? null : UpdateEditorModel(part, context.GroupName, context.Updater); + } + + protected virtual DriverResult BuildDisplayModel(TPart part, string groupName, string displayType) { + return null; + } + + protected virtual DriverResult BuildEditorModel(TPart part, string groupName) { + return null; + } + + protected virtual DriverResult UpdateEditorModel(TPart part, string groupName, IUpdateModel updater) { + return null; + } + + protected virtual string Prefix { get { return ""; } } + + public TemplateResult PartialView(object model) { + return new TemplateResult(model, null, Prefix); + } + public TemplateResult PartialView(object model, string template) { + return new TemplateResult(model, template, Prefix); + } + public TemplateResult PartialView(object model, string template, string prefix) { + return new TemplateResult(model, template, prefix); + } + } + + public class DriverResult { + public virtual void Apply(BuildDisplayModelContext context) { } + public virtual void Apply(BuildEditorModelContext context) { } + } + + public class TemplateResult : DriverResult { + public object Model { get; set; } + public string TemplateName { get; set; } + public string Prefix { get; set; } + + public TemplateResult(object model, string templateName, string prefix) { + Model = model; + TemplateName = templateName; + Prefix = prefix; + } + + public override void Apply(BuildDisplayModelContext context) { + context.AddDisplay(new TemplateViewModel(Model, Prefix) { TemplateName = TemplateName }); + } + + public override void Apply(BuildEditorModelContext context) { + context.AddEditor(new TemplateViewModel(Model, Prefix) { TemplateName = TemplateName }); + } + } + + [UsedImplicitly] + public class PartDriverHandler : IContentHandler { + private readonly IEnumerable _drivers; + + public PartDriverHandler(IEnumerable drivers) { + _drivers = drivers; + Logger = NullLogger.Instance; + } + + public ILogger Logger { get; set; } + + System.Collections.Generic.IEnumerable IContentHandler.GetContentTypes() { + return Enumerable.Empty(); + } + + void IContentHandler.Activating(ActivatingContentContext context) { } + + void IContentHandler.Activated(ActivatedContentContext context) { } + + void IContentHandler.Creating(CreateContentContext context) { } + + void IContentHandler.Created(CreateContentContext context) { } + + void IContentHandler.Loading(LoadContentContext context) { } + + void IContentHandler.Loaded(LoadContentContext context) { } + + void IContentHandler.GetItemMetadata(GetItemMetadataContext context) { } + + void IContentHandler.BuildDisplayModel(BuildDisplayModelContext context) { + _drivers.Invoke(driver => { + var result = driver.BuildDisplayModel(context); + if (result != null) + result.Apply(context); + }, Logger); + } + + void IContentHandler.BuildEditorModel(BuildEditorModelContext context) { + _drivers.Invoke(driver => { + var result = driver.BuildEditorModel(context); + if (result != null) + result.Apply(context); + }, Logger); + } + + void IContentHandler.UpdateEditorModel(UpdateEditorModelContext context) { + _drivers.Invoke(driver => { + var result = driver.UpdateEditorModel(context); + if (result != null) + result.Apply(context); + }, Logger); + } + + } +} diff --git a/src/Orchard/Models/ViewModels/ItemDisplayModel.cs b/src/Orchard/Models/ViewModels/ItemDisplayModel.cs index 53f8cd824..f0397d09d 100644 --- a/src/Orchard/Models/ViewModels/ItemDisplayModel.cs +++ b/src/Orchard/Models/ViewModels/ItemDisplayModel.cs @@ -19,6 +19,7 @@ namespace Orchard.Models.ViewModels { public ItemDisplayModel(ContentItem item) { Item = item; + Displays = Enumerable.Empty(); } public ContentItem Item { diff --git a/src/Orchard/Orchard.csproj b/src/Orchard/Orchard.csproj index b9c8e162b..adfacf6d7 100644 --- a/src/Orchard/Orchard.csproj +++ b/src/Orchard/Orchard.csproj @@ -178,6 +178,7 @@ +