mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-12-02 19:44:02 +08:00
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:
@@ -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>>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
21
src/Orchard/ContentManagement/ContentItemBehavior.cs
Normal file
21
src/Orchard/ContentManagement/ContentItemBehavior.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
20
src/Orchard/ContentManagement/ContentPartBehavior.cs
Normal file
20
src/Orchard/ContentManagement/ContentPartBehavior.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
7
src/Orchard/ContentManagement/IContentBehavior.cs
Normal file
7
src/Orchard/ContentManagement/IContentBehavior.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using ClaySharp;
|
||||
|
||||
namespace Orchard.ContentManagement {
|
||||
public interface IContentBehavior {
|
||||
IClayBehavior Behavior { get; }
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
Reference in New Issue
Block a user