Adding a PartDriver concept to try and drive down complexity

--HG--
extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4043668
This commit is contained in:
loudej
2009-12-10 08:23:27 +00:00
parent 73d291a565
commit 40e4be78cb
5 changed files with 244 additions and 0 deletions

View File

@@ -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<PartDriverHandler>().As<IContentHandler>();
_container = builder.Build();
}
[Test]
public void DriverHandlerShouldNotThrowException() {
var contentHandler = _container.Resolve<IContentHandler>();
contentHandler.BuildDisplayModel(null);
}
[Test]
public void AllDriversShouldBeCalled() {
var driver1 = new Mock<IPartDriver>();
var driver2 = new Mock<IPartDriver>();
_container.Build(x => {
x.Register(driver1.Object);
x.Register(driver2.Object);
});
var contentHandler = _container.Resolve<IContentHandler>();
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<IPartDriver>());
var contentHandler = _container.Resolve<IContentHandler>();
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<StubPart> {
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; }
}
}
}

View File

@@ -66,6 +66,9 @@
<HintPath>..\..\lib\nunit\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Configuration" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
@@ -117,6 +120,7 @@
<Compile Include="Models\DefaultModelManagerTests.cs" />
<Compile Include="Models\Drivers\ModelBuilderTests.cs" />
<Compile Include="Models\Drivers\ModelDriverTests.cs" />
<Compile Include="Models\PartDriverHandlerTests.cs" />
<Compile Include="Models\Stubs\Alpha.cs" />
<Compile Include="Models\Stubs\AlphaHandler.cs" />
<Compile Include="Models\Stubs\Beta.cs" />

View File

@@ -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<TPart> : IPartDriver where TPart : class, IContent {
DriverResult IPartDriver.BuildDisplayModel(BuildDisplayModelContext context) {
var part = context.ContentItem.As<TPart>();
return part == null ? null : BuildDisplayModel(part, context.GroupName, context.DisplayType);
}
DriverResult IPartDriver.BuildEditorModel(BuildEditorModelContext context) {
var part = context.ContentItem.As<TPart>();
return part == null ? null : BuildEditorModel(part, context.GroupName);
}
DriverResult IPartDriver.UpdateEditorModel(UpdateEditorModelContext context) {
var part = context.ContentItem.As<TPart>();
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<IPartDriver> _drivers;
public PartDriverHandler(IEnumerable<IPartDriver> drivers) {
_drivers = drivers;
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
System.Collections.Generic.IEnumerable<ContentType> IContentHandler.GetContentTypes() {
return Enumerable.Empty<ContentType>();
}
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);
}
}
}

View File

@@ -19,6 +19,7 @@ namespace Orchard.Models.ViewModels {
public ItemDisplayModel(ContentItem item) {
Item = item;
Displays = Enumerable.Empty<TemplateViewModel>();
}
public ContentItem Item {

View File

@@ -178,6 +178,7 @@
<Compile Include="Models\ContentPart.cs" />
<Compile Include="Models\IContent.cs" />
<Compile Include="Models\IContentQuery.cs" />
<Compile Include="Models\PartDriver.cs" />
<Compile Include="Models\Records\ContentItemRecordAlteration.cs" />
<Compile Include="Models\Records\ContentPartRecord.cs" />
<Compile Include="Models\Records\ContentPartRecordAlteration.cs" />