mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-18 09:44:20 +08:00
Starting an implementation of a composite model management system
--HG-- extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4038935
This commit is contained in:
@@ -5,7 +5,7 @@ using System.Linq;
|
||||
using NHibernate;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Data;
|
||||
using Orchard.Tests.Models;
|
||||
using Orchard.Tests.Records;
|
||||
|
||||
namespace Orchard.Tests.Data {
|
||||
[TestFixture]
|
||||
|
@@ -9,7 +9,7 @@ using NHibernate;
|
||||
using NHibernate.Criterion;
|
||||
using NHibernate.Tool.hbm2ddl;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Tests.Models;
|
||||
using Orchard.Tests.Records;
|
||||
|
||||
namespace Orchard.Tests {
|
||||
[TestFixture]
|
||||
|
@@ -2,7 +2,7 @@
|
||||
using NHibernate;
|
||||
using NHibernate.Linq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Tests.Models;
|
||||
using Orchard.Tests.Records;
|
||||
|
||||
namespace Orchard.Tests {
|
||||
[TestFixture]
|
||||
|
64
src/Orchard.Tests/Models/DefaultModelBuilderTests.cs
Normal file
64
src/Orchard.Tests/Models/DefaultModelBuilderTests.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using Autofac;
|
||||
using Autofac.Builder;
|
||||
using Autofac.Modules;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Models;
|
||||
using Orchard.Models.Driver;
|
||||
using Orchard.Tests.Models.Stubs;
|
||||
|
||||
namespace Orchard.Tests.Models {
|
||||
[TestFixture]
|
||||
public class DefaultModelBuilderTests {
|
||||
private IContainer _container;
|
||||
private IModelManager _manager;
|
||||
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterModule(new ImplicitCollectionSupportModule());
|
||||
builder.Register<DefaultModelManager>().As<IModelManager>();
|
||||
builder.Register<AlphaDriver>().As<IModelDriver>();
|
||||
builder.Register<BetaDriver>().As<IModelDriver>();
|
||||
builder.Register<FlavoredDriver>().As<IModelDriver>();
|
||||
builder.Register<StyledDriver>().As<IModelDriver>();
|
||||
|
||||
_container = builder.Build();
|
||||
_manager = _container.Resolve<IModelManager>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AlphaDriverShouldWeldItsPart() {
|
||||
var foo = _manager.New("alpha");
|
||||
|
||||
Assert.That(foo.Is<Alpha>(), Is.True);
|
||||
Assert.That(foo.As<Alpha>(), Is.Not.Null);
|
||||
Assert.That(foo.Is<Beta>(), Is.False);
|
||||
Assert.That(foo.As<Beta>(), Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StronglyTypedNewShouldTypeCast() {
|
||||
var foo = _manager.New<Alpha>("alpha");
|
||||
Assert.That(foo, Is.Not.Null);
|
||||
Assert.That(foo.GetType(), Is.EqualTo(typeof(Alpha)));
|
||||
}
|
||||
|
||||
[Test, ExpectedException(typeof(InvalidCastException))]
|
||||
public void StronglyTypedNewShouldThrowCastExceptionIfNull() {
|
||||
var foo = _manager.New<Beta>("alpha");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AlphaIsFlavoredAndStyledAndBetaIsFlavoredOnly() {
|
||||
var alpha = _manager.New<Alpha>("alpha");
|
||||
var beta = _manager.New<Beta>("beta");
|
||||
|
||||
Assert.That(alpha.Is<Flavored>(), Is.True);
|
||||
Assert.That(alpha.Is<Styled>(), Is.True);
|
||||
Assert.That(beta.Is<Flavored>(), Is.True);
|
||||
Assert.That(beta.Is<Styled>(), Is.False);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
6
src/Orchard.Tests/Models/Stubs/Alpha.cs
Normal file
6
src/Orchard.Tests/Models/Stubs/Alpha.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
using Orchard.Models;
|
||||
|
||||
namespace Orchard.Tests.Models.Stubs {
|
||||
public class Alpha : ModelPart {
|
||||
}
|
||||
}
|
11
src/Orchard.Tests/Models/Stubs/AlphaDriver.cs
Normal file
11
src/Orchard.Tests/Models/Stubs/AlphaDriver.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Orchard.Models.Driver;
|
||||
|
||||
namespace Orchard.Tests.Models.Stubs {
|
||||
public class AlphaDriver : ModelDriverBase {
|
||||
protected override void New(NewModelContext context) {
|
||||
if (context.ModelType == "alpha") {
|
||||
WeldModelPart<Alpha>(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
6
src/Orchard.Tests/Models/Stubs/Beta.cs
Normal file
6
src/Orchard.Tests/Models/Stubs/Beta.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
using Orchard.Models;
|
||||
|
||||
namespace Orchard.Tests.Models.Stubs {
|
||||
public class Beta : ModelPart {
|
||||
}
|
||||
}
|
15
src/Orchard.Tests/Models/Stubs/BetaDriver.cs
Normal file
15
src/Orchard.Tests/Models/Stubs/BetaDriver.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Orchard.Models.Driver;
|
||||
|
||||
namespace Orchard.Tests.Models.Stubs {
|
||||
public class BetaDriver : ModelDriverBase {
|
||||
protected override void New(NewModelContext context) {
|
||||
if (context.ModelType == "beta") {
|
||||
WeldModelPart<Beta>(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
src/Orchard.Tests/Models/Stubs/Flavored.cs
Normal file
10
src/Orchard.Tests/Models/Stubs/Flavored.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Orchard.Models;
|
||||
|
||||
namespace Orchard.Tests.Models.Stubs {
|
||||
class Flavored : ModelPart {
|
||||
}
|
||||
}
|
11
src/Orchard.Tests/Models/Stubs/FlavoredDriver.cs
Normal file
11
src/Orchard.Tests/Models/Stubs/FlavoredDriver.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Orchard.Models.Driver;
|
||||
|
||||
namespace Orchard.Tests.Models.Stubs {
|
||||
public class FlavoredDriver : ModelDriverBase {
|
||||
protected override void New(NewModelContext context) {
|
||||
if (context.ModelType == "beta" || context.ModelType == "alpha") {
|
||||
WeldModelPart<Flavored>(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
src/Orchard.Tests/Models/Stubs/Styled.cs
Normal file
10
src/Orchard.Tests/Models/Stubs/Styled.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Orchard.Models;
|
||||
|
||||
namespace Orchard.Tests.Models.Stubs {
|
||||
public class Styled : ModelPart {
|
||||
}
|
||||
}
|
11
src/Orchard.Tests/Models/Stubs/StyledDriver.cs
Normal file
11
src/Orchard.Tests/Models/Stubs/StyledDriver.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Orchard.Models.Driver;
|
||||
|
||||
namespace Orchard.Tests.Models.Stubs {
|
||||
public class StyledDriver : ModelDriverBase {
|
||||
protected override void New(NewModelContext context) {
|
||||
if (context.ModelType == "alpha") {
|
||||
WeldModelPart<Styled>(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -104,6 +104,15 @@
|
||||
<Compile Include="Environment\DefaultOrchardRuntimeTests.cs" />
|
||||
<Compile Include="Environment\OrchardStarterTests.cs" />
|
||||
<Compile Include="Logging\LoggingModuleTests.cs" />
|
||||
<Compile Include="Models\DefaultModelBuilderTests.cs" />
|
||||
<Compile Include="Models\Stubs\Alpha.cs" />
|
||||
<Compile Include="Models\Stubs\AlphaDriver.cs" />
|
||||
<Compile Include="Models\Stubs\Beta.cs" />
|
||||
<Compile Include="Models\Stubs\BetaDriver.cs" />
|
||||
<Compile Include="Models\Stubs\Flavored.cs" />
|
||||
<Compile Include="Models\Stubs\FlavoredDriver.cs" />
|
||||
<Compile Include="Models\Stubs\Styled.cs" />
|
||||
<Compile Include="Models\Stubs\StyledDriver.cs" />
|
||||
<Compile Include="Mvc\ModelBinders\KeyedListModelBinderTests.cs" />
|
||||
<Compile Include="Mvc\OrchardControllerFactoryTests.cs" />
|
||||
<Compile Include="Mvc\OrchardControllerIdentificationStrategyTests.cs" />
|
||||
@@ -117,8 +126,8 @@
|
||||
<Compile Include="FakeTests.cs" />
|
||||
<Compile Include="FluentDbTests.cs" />
|
||||
<Compile Include="LinqToNHibernateTests.cs" />
|
||||
<Compile Include="Models\Bar.cs" />
|
||||
<Compile Include="Models\Foo.cs" />
|
||||
<Compile Include="Records\Bar.cs" />
|
||||
<Compile Include="Records\Foo.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Stubs\StubHttpContext.cs" />
|
||||
</ItemGroup>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
namespace Orchard.Tests.Models {
|
||||
namespace Orchard.Tests.Records {
|
||||
public class Bar {
|
||||
public virtual int Id { get; set; }
|
||||
public virtual decimal Height { get; set; }
|
@@ -1,4 +1,4 @@
|
||||
namespace Orchard.Tests.Models {
|
||||
namespace Orchard.Tests.Records {
|
||||
public class Foo {
|
||||
public virtual int Id { get; set; }
|
||||
public virtual string Name { get; set; }
|
29
src/Orchard/Models/DefaultModelManager.cs
Normal file
29
src/Orchard/Models/DefaultModelManager.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.Models.Driver;
|
||||
|
||||
namespace Orchard.Models {
|
||||
public class DefaultModelManager : IModelManager {
|
||||
private readonly IEnumerable<IModelDriver> _drivers;
|
||||
|
||||
public DefaultModelManager(IEnumerable<IModelDriver> drivers) {
|
||||
_drivers = drivers;
|
||||
}
|
||||
|
||||
public virtual IModel New(string modelType) {
|
||||
|
||||
// create a new kernel for the model instance
|
||||
var context = new NewModelContext {
|
||||
ModelType = modelType,
|
||||
Instance = new ModelRoot(modelType)
|
||||
};
|
||||
|
||||
// invoke drivers to weld aspects onto kernel
|
||||
foreach(var driver in _drivers) {
|
||||
driver.New(context);
|
||||
}
|
||||
|
||||
// composite result is returned
|
||||
return context.Instance;
|
||||
}
|
||||
}
|
||||
}
|
27
src/Orchard/Models/Driver/IModelDriver.cs
Normal file
27
src/Orchard/Models/Driver/IModelDriver.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.Models.Driver {
|
||||
public interface IModelDriver : IDependency {
|
||||
void New(NewModelContext context);
|
||||
}
|
||||
|
||||
public abstract class ModelDriverBase : IModelDriver {
|
||||
protected ModelDriverBase() {
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger{ get; set;}
|
||||
|
||||
void IModelDriver.New(NewModelContext context) {New(context);}
|
||||
|
||||
protected virtual void New(NewModelContext context) {
|
||||
}
|
||||
|
||||
protected void WeldModelPart<TPart>(NewModelContext context) where TPart : class,IModel,new() {
|
||||
var newPart = new TPart();
|
||||
newPart.Weld(context.Instance);
|
||||
context.Instance = newPart;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
6
src/Orchard/Models/Driver/NewModelContext.cs
Normal file
6
src/Orchard/Models/Driver/NewModelContext.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Orchard.Models.Driver {
|
||||
public class NewModelContext {
|
||||
public string ModelType { get; set; }
|
||||
public IModel Instance { get; set; }
|
||||
}
|
||||
}
|
11
src/Orchard/Models/IModel.cs
Normal file
11
src/Orchard/Models/IModel.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Orchard.Models {
|
||||
public interface IModel {
|
||||
int Id { get; }
|
||||
string ModelType { get; }
|
||||
|
||||
bool Is<T>() where T : class, IModel;
|
||||
T As<T>() where T : class, IModel;
|
||||
|
||||
void Weld(IModel model);
|
||||
}
|
||||
}
|
5
src/Orchard/Models/IModelManager.cs
Normal file
5
src/Orchard/Models/IModelManager.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace Orchard.Models {
|
||||
public interface IModelManager {
|
||||
IModel New(string modelType);
|
||||
}
|
||||
}
|
13
src/Orchard/Models/ModelExtensions.cs
Normal file
13
src/Orchard/Models/ModelExtensions.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace Orchard.Models {
|
||||
public static class ModelExtensions {
|
||||
public static T New<T>(this IModelManager manager, string modelType) where T : class, IModel {
|
||||
var t = manager.New(modelType).As<T>();
|
||||
if (t == null)
|
||||
throw new InvalidCastException();
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
33
src/Orchard/Models/ModelPart.cs
Normal file
33
src/Orchard/Models/ModelPart.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
|
||||
namespace Orchard.Models {
|
||||
public class ModelPart : IModel {
|
||||
protected IModel Next { get; set; }
|
||||
protected ModelRoot Root { get; set; }
|
||||
|
||||
void IModel.Weld(IModel model) {
|
||||
Next = model;
|
||||
Root = model.As<ModelRoot>();
|
||||
Root.Welded = this;
|
||||
}
|
||||
|
||||
public int Id { get { return Root.Id; } }
|
||||
public string ModelType { get { return Root.ModelType; } }
|
||||
|
||||
bool IModel.Is<T>() {
|
||||
return this is T ? true : Next.Is<T>();
|
||||
}
|
||||
|
||||
T IModel.As<T>() {
|
||||
return this is T ? this as T : Next.As<T>();
|
||||
}
|
||||
|
||||
public bool Is<T>() where T : class, IModel {
|
||||
return Root.WeldedIs<T>();
|
||||
}
|
||||
|
||||
public T As<T>() where T : class, IModel {
|
||||
return Root.WeldedAs<T>();
|
||||
}
|
||||
}
|
||||
}
|
35
src/Orchard/Models/ModelRoot.cs
Normal file
35
src/Orchard/Models/ModelRoot.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
|
||||
namespace Orchard.Models {
|
||||
public class ModelRoot : IModel {
|
||||
public ModelRoot(string modelType) {
|
||||
Welded = this;
|
||||
ModelType = modelType;
|
||||
}
|
||||
|
||||
public IModel Welded { get; set; }
|
||||
|
||||
public int Id { get; set; }
|
||||
public string ModelType { get; set; }
|
||||
|
||||
bool IModel.Is<T>() {
|
||||
return this is T;
|
||||
}
|
||||
|
||||
T IModel.As<T>() {
|
||||
return this as T;
|
||||
}
|
||||
|
||||
public bool WeldedIs<T>() where T : class, IModel {
|
||||
return Welded.Is<T>();
|
||||
}
|
||||
|
||||
public T WeldedAs<T>() where T : class, IModel {
|
||||
return Welded.As<T>();
|
||||
}
|
||||
|
||||
void IModel.Weld(IModel model) {
|
||||
// this method is not called on root
|
||||
}
|
||||
}
|
||||
}
|
@@ -122,6 +122,14 @@
|
||||
<Compile Include="Logging\LoggingModule.cs" />
|
||||
<Compile Include="Logging\NullLogger.cs" />
|
||||
<Compile Include="Logging\NullLoggerFactory.cs" />
|
||||
<Compile Include="Models\DefaultModelManager.cs" />
|
||||
<Compile Include="Models\Driver\NewModelContext.cs" />
|
||||
<Compile Include="Models\IModelManager.cs" />
|
||||
<Compile Include="Models\Driver\IModelDriver.cs" />
|
||||
<Compile Include="Models\IModel.cs" />
|
||||
<Compile Include="Models\ModelExtensions.cs" />
|
||||
<Compile Include="Models\ModelPart.cs" />
|
||||
<Compile Include="Models\ModelRoot.cs" />
|
||||
<Compile Include="Mvc\Html\HtmlHelperExtensions.cs" />
|
||||
<Compile Include="Mvc\Filters\FilterProvider.cs" />
|
||||
<Compile Include="Mvc\Filters\FilterResolvingActionInvoker.cs" />
|
||||
|
Reference in New Issue
Block a user