Adding support for dynamic content expressions

ContentItem as dynamic will respond to get property which matches a ContentPart's metadata definition name
ContentPart as dynamic will respond to get property which matches a ContentField's metadata instance name

--HG--
branch : dev
extra : transplant_source : Qu0%9E%09%9B%97rbq%EE%9B%1Ax3%C8p%ED%91%3E
This commit is contained in:
Louis DeJardin
2011-02-10 12:32:28 -08:00
parent ffb376ff40
commit e0f10275b2
8 changed files with 164 additions and 2 deletions

View File

@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData.Models;
namespace Orchard.Tests.ContentManagement {
[TestFixture]
public class DynamicContentItemTests {
[Test]
public void ContentItemProjectsPartNamesAsProperties() {
var contentItem = new ContentItem();
var testingPart = new ContentPart { TypePartDefinition = new ContentTypePartDefinition(new ContentPartDefinition("TestingPart"), new SettingsDictionary()) };
contentItem.Weld(testingPart);
dynamic contentItemDynamic = contentItem;
dynamic testingPartDynamic = contentItemDynamic.TestingPart;
Assert.That((object)testingPartDynamic, Is.SameAs(testingPart));
}
[Test]
public void ContentPartsAlsoProjectPartNamesAsProperties() {
var contentItem = new ContentItem();
var testingPart = new ContentPart { TypePartDefinition = new ContentTypePartDefinition(new ContentPartDefinition("TestingPart"), new SettingsDictionary()) };
var anotherPart = new ContentPart { TypePartDefinition = new ContentTypePartDefinition(new ContentPartDefinition("AnotherPart"), new SettingsDictionary()) };
contentItem.Weld(testingPart);
contentItem.Weld(anotherPart);
dynamic contentItemDynamic = contentItem;
dynamic testingPartDynamic = contentItemDynamic.TestingPart;
dynamic anotherPartDynamic = contentItemDynamic.AnotherPart;
dynamic testingPartDynamic2 = testingPartDynamic.TestingPart;
dynamic anotherPartDynamic2 = testingPartDynamic.AnotherPart;
Assert.That((object)testingPartDynamic, Is.SameAs(testingPart));
Assert.That((object)anotherPartDynamic, Is.SameAs(anotherPart));
Assert.That((object)testingPartDynamic2, Is.SameAs(testingPart));
Assert.That((object)anotherPartDynamic2, Is.SameAs(anotherPart));
}
[Test]
public void ContentItemPropertyOnPartRootsYou() {
var contentItem = new ContentItem();
var testingPart = new ContentPart { TypePartDefinition = new ContentTypePartDefinition(new ContentPartDefinition("TestingPart"), new SettingsDictionary()) };
var anotherPart = new ContentPart { TypePartDefinition = new ContentTypePartDefinition(new ContentPartDefinition("AnotherPart"), new SettingsDictionary()) };
contentItem.Weld(testingPart);
contentItem.Weld(anotherPart);
dynamic contentItemDynamic = contentItem;
dynamic testingPartDynamic = contentItemDynamic.TestingPart;
dynamic anotherPartDynamic = contentItemDynamic.AnotherPart;
dynamic contentItemDynamic1 = testingPartDynamic.ContentItem;
dynamic contentItemDynamic2 = anotherPartDynamic.ContentItem;
Assert.That((object)contentItemDynamic1, Is.SameAs(contentItem));
Assert.That((object)contentItemDynamic2, Is.SameAs(contentItem));
}
[Test]
public void ActualPropertiesTakePriority() {
var contentItem = new ContentItem();
var testingPart = new ContentPart { TypePartDefinition = new ContentTypePartDefinition(new ContentPartDefinition("Parts"), new SettingsDictionary()) };
contentItem.Weld(testingPart);
dynamic contentItemDynamic = contentItem;
dynamic testingPartDynamic = contentItemDynamic.Parts;
Assert.That((object)testingPartDynamic, Is.AssignableTo<IEnumerable<ContentPart>>());
}
}
}

View File

@@ -173,6 +173,7 @@
</Compile>
<Compile Include="ContentManagement\Drivers\FieldStorage\FieldStorageProviderSelectorTests.cs" />
<Compile Include="ContentManagement\Drivers\FieldStorage\InfosetFieldStorageProviderTests.cs" />
<Compile Include="ContentManagement\DynamicContentItemTests.cs" />
<Compile Include="ContentManagement\Handlers\ContentHandlerTests.cs" />
<Compile Include="ContentManagement\Handlers\DeltaPartHandler.cs" />
<Compile Include="ContentManagement\Handlers\EpsilonPartHandler.cs" />

View File

@@ -1,16 +1,21 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using ClaySharp;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.Records;
namespace Orchard.ContentManagement {
public class ContentItem : IContent {
public class ContentItem : IContent, IContentBehavior, IDynamicMetaObjectProvider {
public ContentItem() {
_behavior = new ClayBehaviorCollection(new[] { new ContentItemBehavior(this) });
_parts = new List<ContentPart>();
}
private readonly IList<ContentPart> _parts;
ContentItem IContent.ContentItem { get { return this; } }
public int Id { get { return Record == null ? 0 : Record.Id; } }
@@ -39,5 +44,15 @@ namespace Orchard.ContentManagement {
part.ContentItem = this;
_parts.Add(part);
}
private readonly IClayBehavior _behavior;
IClayBehavior IContentBehavior.Behavior {
get { return _behavior; }
}
DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
return new ClayMetaObject(this, parameter, ex => Expression.Property(Expression.Convert(ex, typeof(IContentBehavior)), "Behavior"));
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
using ClaySharp;
namespace Orchard.ContentManagement {
public class ContentItemBehavior : ClayBehavior {
private readonly IContent _content;
public ContentItemBehavior(IContent content) {
_content = content;
}
public override object GetMemberMissing(Func<object> proceed, object self, string name) {
var contentItem = _content.ContentItem;
foreach (var part in contentItem.Parts) {
if (part.PartDefinition.Name == name)
return part;
}
return base.GetMemberMissing(proceed, self, name);
}
}
}

View File

@@ -1,19 +1,24 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Web.Mvc;
using ClaySharp;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.Utilities;
using Orchard.UI;
namespace Orchard.ContentManagement {
public class ContentPart : IContent {
public class ContentPart : IContent, IContentBehavior, IDynamicMetaObjectProvider {
private readonly IList<ContentField> _fields;
public ContentPart() {
_behavior = new ClayBehaviorCollection(new[] { new ContentPartBehavior(this) });
_fields = new List<ContentField>();
}
public virtual ContentItem ContentItem { get; set; }
//interesting thought, should/could parts also have zones (would then have zones on the page, content item and parts...)?
@@ -24,6 +29,14 @@ namespace Orchard.ContentManagement {
}
}
private readonly IClayBehavior _behavior;
IClayBehavior IContentBehavior.Behavior {
get { return _behavior; }
}
DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
return new ClayMetaObject(this, parameter, ex => Expression.Property(Expression.Convert(ex, typeof(IContentBehavior)), "Behavior"));
}
/// <summary>
/// The ContentItem's identifier.
/// </summary>
@@ -51,6 +64,8 @@ namespace Orchard.ContentManagement {
public void Weld(ContentField field) {
_fields.Add(field);
}
}
public class ContentPart<TRecord> : ContentPart {

View File

@@ -0,0 +1,20 @@
using System;
namespace Orchard.ContentManagement {
public class ContentPartBehavior : ContentItemBehavior {
private readonly ContentPart _contentPart;
public ContentPartBehavior(ContentPart contentPart)
: base(contentPart) {
_contentPart = contentPart;
}
public override object GetMemberMissing(Func<object> proceed, object self, string name) {
foreach (var field in _contentPart.Fields) {
if (field.PartFieldDefinition.Name == name)
return field;
}
return base.GetMemberMissing(proceed, self, name);
}
}
}

View File

@@ -0,0 +1,7 @@
using ClaySharp;
namespace Orchard.ContentManagement {
public interface IContentBehavior {
IClayBehavior Behavior { get; }
}
}

View File

@@ -150,9 +150,12 @@
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<Compile Include="ContentManagement\ContentItemBehavior.cs" />
<Compile Include="ContentManagement\ContentPartBehavior.cs" />
<Compile Include="ContentManagement\DefaultContentDisplay.cs" />
<Compile Include="ContentManagement\Drivers\ContentShapeResult.cs" />
<Compile Include="ContentManagement\Handlers\BuildShapeContext.cs" />
<Compile Include="ContentManagement\IContentBehavior.cs" />
<Compile Include="ContentManagement\Utilities\ComputedField.cs" />
<Compile Include="DisplayManagement\Descriptors\ResourceBindingStrategy\StylesheetBindingStrategy.cs" />
<Compile Include="DisplayManagement\Descriptors\ShapeDescriptor.cs" />