mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-11-28 17:32:44 +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 NHibernate;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Orchard.Data;
|
using Orchard.Data;
|
||||||
using Orchard.Tests.Models;
|
using Orchard.Tests.Records;
|
||||||
|
|
||||||
namespace Orchard.Tests.Data {
|
namespace Orchard.Tests.Data {
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using NHibernate;
|
|||||||
using NHibernate.Criterion;
|
using NHibernate.Criterion;
|
||||||
using NHibernate.Tool.hbm2ddl;
|
using NHibernate.Tool.hbm2ddl;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Orchard.Tests.Models;
|
using Orchard.Tests.Records;
|
||||||
|
|
||||||
namespace Orchard.Tests {
|
namespace Orchard.Tests {
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
using NHibernate;
|
using NHibernate;
|
||||||
using NHibernate.Linq;
|
using NHibernate.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Orchard.Tests.Models;
|
using Orchard.Tests.Records;
|
||||||
|
|
||||||
namespace Orchard.Tests {
|
namespace Orchard.Tests {
|
||||||
[TestFixture]
|
[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\DefaultOrchardRuntimeTests.cs" />
|
||||||
<Compile Include="Environment\OrchardStarterTests.cs" />
|
<Compile Include="Environment\OrchardStarterTests.cs" />
|
||||||
<Compile Include="Logging\LoggingModuleTests.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\ModelBinders\KeyedListModelBinderTests.cs" />
|
||||||
<Compile Include="Mvc\OrchardControllerFactoryTests.cs" />
|
<Compile Include="Mvc\OrchardControllerFactoryTests.cs" />
|
||||||
<Compile Include="Mvc\OrchardControllerIdentificationStrategyTests.cs" />
|
<Compile Include="Mvc\OrchardControllerIdentificationStrategyTests.cs" />
|
||||||
@@ -117,8 +126,8 @@
|
|||||||
<Compile Include="FakeTests.cs" />
|
<Compile Include="FakeTests.cs" />
|
||||||
<Compile Include="FluentDbTests.cs" />
|
<Compile Include="FluentDbTests.cs" />
|
||||||
<Compile Include="LinqToNHibernateTests.cs" />
|
<Compile Include="LinqToNHibernateTests.cs" />
|
||||||
<Compile Include="Models\Bar.cs" />
|
<Compile Include="Records\Bar.cs" />
|
||||||
<Compile Include="Models\Foo.cs" />
|
<Compile Include="Records\Foo.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Stubs\StubHttpContext.cs" />
|
<Compile Include="Stubs\StubHttpContext.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Orchard.Tests.Models {
|
namespace Orchard.Tests.Records {
|
||||||
public class Bar {
|
public class Bar {
|
||||||
public virtual int Id { get; set; }
|
public virtual int Id { get; set; }
|
||||||
public virtual decimal Height { get; set; }
|
public virtual decimal Height { get; set; }
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Orchard.Tests.Models {
|
namespace Orchard.Tests.Records {
|
||||||
public class Foo {
|
public class Foo {
|
||||||
public virtual int Id { get; set; }
|
public virtual int Id { get; set; }
|
||||||
public virtual string Name { 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\LoggingModule.cs" />
|
||||||
<Compile Include="Logging\NullLogger.cs" />
|
<Compile Include="Logging\NullLogger.cs" />
|
||||||
<Compile Include="Logging\NullLoggerFactory.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\Html\HtmlHelperExtensions.cs" />
|
||||||
<Compile Include="Mvc\Filters\FilterProvider.cs" />
|
<Compile Include="Mvc\Filters\FilterProvider.cs" />
|
||||||
<Compile Include="Mvc\Filters\FilterResolvingActionInvoker.cs" />
|
<Compile Include="Mvc\Filters\FilterResolvingActionInvoker.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user