mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Refactoring shifts using reflection based accessors
This commit is contained in:
30
src/Orchard.Tests/ContentManagement/ContentHelpers.cs
Normal file
30
src/Orchard.Tests/ContentManagement/ContentHelpers.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.FieldStorage.InfosetStorage;
|
||||
using Orchard.ContentManagement.Records;
|
||||
|
||||
namespace Orchard.Tests.ContentManagement {
|
||||
public class ContentHelpers {
|
||||
public static ContentItem PreparePart<TPart, TRecord>(TPart part, string contentType, int id = -1)
|
||||
where TPart : ContentPart<TRecord>
|
||||
where TRecord : ContentPartRecord, new() {
|
||||
|
||||
part.Record = new TRecord();
|
||||
return PreparePart(part, contentType, id);
|
||||
}
|
||||
|
||||
public static ContentItem PreparePart<TPart>(TPart part, string contentType, int id = -1)
|
||||
where TPart : ContentPart {
|
||||
|
||||
var contentItem = part.ContentItem = new ContentItem {
|
||||
VersionRecord = new ContentItemVersionRecord {
|
||||
ContentItemRecord = new ContentItemRecord()
|
||||
},
|
||||
ContentType = contentType
|
||||
};
|
||||
contentItem.Record.Id = id;
|
||||
contentItem.Weld(part);
|
||||
contentItem.Weld(new InfosetPart());
|
||||
return contentItem;
|
||||
}
|
||||
}
|
||||
}
|
58
src/Orchard.Tests/ContentManagement/InfosetHelperTests.cs
Normal file
58
src/Orchard.Tests/ContentManagement/InfosetHelperTests.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using NUnit.Framework;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.FieldStorage.InfosetStorage;
|
||||
using Orchard.ContentManagement.Records;
|
||||
|
||||
namespace Orchard.Tests.ContentManagement {
|
||||
public class InfosetHelperTests {
|
||||
[Test]
|
||||
public void StoreByNameSavesIntoInfoset() {
|
||||
var part = new TestPart();
|
||||
ContentHelpers.PreparePart(part, "Test");
|
||||
part.Foo = 42;
|
||||
var infosetXml = part.As<InfosetPart>().Infoset.Element;
|
||||
var testPartElement = infosetXml.Element(typeof (TestPart).Name);
|
||||
Assert.That(testPartElement, Is.Not.Null);
|
||||
var fooAttribute = testPartElement.Attr<int>("Foo");
|
||||
|
||||
Assert.That(part.Foo, Is.EqualTo(42));
|
||||
Assert.That(fooAttribute, Is.EqualTo(42));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RetrieveSavesIntoInfoset() {
|
||||
var part = new TestPartWithRecord();
|
||||
ContentHelpers.PreparePart<TestPartWithRecord, TestPartWithRecordRecord>(part, "Test");
|
||||
part.Record.Foo = 42;
|
||||
var infosetXml = part.As<InfosetPart>().Infoset.Element;
|
||||
var testPartElement = infosetXml.Element(typeof (TestPartWithRecord).Name);
|
||||
Assert.That(testPartElement, Is.Null);
|
||||
|
||||
var foo = part.Foo;
|
||||
testPartElement = infosetXml.Element(typeof(TestPartWithRecord).Name);
|
||||
Assert.That(testPartElement, Is.Not.Null);
|
||||
var fooAttribute = testPartElement.Attr<int>("Foo");
|
||||
|
||||
Assert.That(foo, Is.EqualTo(42));
|
||||
Assert.That(fooAttribute, Is.EqualTo(42));
|
||||
}
|
||||
|
||||
public class TestPart : ContentPart {
|
||||
public int Foo {
|
||||
get { return this.Retrieve<int>("Foo"); }
|
||||
set { this.Store("Foo", value); }
|
||||
}
|
||||
}
|
||||
|
||||
public class TestPartWithRecordRecord : ContentPartRecord {
|
||||
public virtual int Foo { get; set; }
|
||||
}
|
||||
|
||||
public class TestPartWithRecord : ContentPart<TestPartWithRecordRecord> {
|
||||
public int Foo {
|
||||
get { return Retrieve(r => r.Foo); }
|
||||
set { Store(r => r.Foo, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
395
src/Orchard.Tests/ContentManagement/XmlHelperTests.cs
Normal file
395
src/Orchard.Tests/ContentManagement/XmlHelperTests.cs
Normal file
@@ -0,0 +1,395 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.ContentManagement;
|
||||
|
||||
namespace Orchard.Tests.ContentManagement {
|
||||
[TestFixture]
|
||||
public class XmlHelperTests {
|
||||
[Test]
|
||||
public void AddEl() {
|
||||
var el = new XElement("data");
|
||||
el
|
||||
.AddEl(new XElement("node1"), new XElement("node2"))
|
||||
.AddEl(new XElement("node3"));
|
||||
|
||||
Assert.That(el.Descendants().Count(), Is.EqualTo(3));
|
||||
Assert.That(el.Descendants().First().Name.ToString(), Is.EqualTo("node1"));
|
||||
Assert.That(el.Descendants().ElementAt(1).Name.ToString(), Is.EqualTo("node2"));
|
||||
Assert.That(el.Descendants().ElementAt(2).Name.ToString(), Is.EqualTo("node3"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Val() {
|
||||
var el = new XElement("data");
|
||||
el = el.Val(123);
|
||||
var val = el.Val<int>();
|
||||
|
||||
Assert.That(val, Is.EqualTo(123));
|
||||
Assert.That(el.ToString(SaveOptions.DisableFormatting),
|
||||
Is.EqualTo("<data>123</data>"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Infinities() {
|
||||
var el = new XElement("data")
|
||||
.Attr("doubleplus", double.PositiveInfinity)
|
||||
.Attr("doubleminus", double.NegativeInfinity)
|
||||
.Attr("floatplus", float.PositiveInfinity)
|
||||
.Attr("floatminus", float.NegativeInfinity);
|
||||
|
||||
Assert.That(el.Attr<string>("doubleplus"), Is.EqualTo("infinity"));
|
||||
Assert.That(el.Attr<string>("doubleminus"), Is.EqualTo("-infinity"));
|
||||
Assert.That(el.Attr<string>("floatplus"), Is.EqualTo("infinity"));
|
||||
Assert.That(el.Attr<string>("floatminus"), Is.EqualTo("-infinity"));
|
||||
|
||||
Assert.That(double.IsPositiveInfinity(el.Attr<double>("doubleplus")), Is.True);
|
||||
Assert.That(double.IsNegativeInfinity(el.Attr<double>("doubleminus")), Is.True);
|
||||
Assert.That(double.IsPositiveInfinity(el.Attr<float>("floatplus")), Is.True);
|
||||
Assert.That(double.IsNegativeInfinity(el.Attr<float>("floatminus")), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StringToAttribute() {
|
||||
var el = new XElement("data");
|
||||
el.Attr("foo", "bar");
|
||||
|
||||
Assert.That(el.Attribute("foo").Value, Is.EqualTo("bar"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IntToAttribute() {
|
||||
var el = new XElement("data");
|
||||
el.Attr("foo", 42);
|
||||
|
||||
Assert.That(el.Attribute("foo").Value, Is.EqualTo("42"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BoolToAttribute() {
|
||||
var el = new XElement("data");
|
||||
el.Attr("foo", true);
|
||||
el.Attr("bar", false);
|
||||
|
||||
Assert.That(el.Attribute("foo").Value, Is.EqualTo("true"));
|
||||
Assert.That(el.Attribute("bar").Value, Is.EqualTo("false"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DateTimeToAttribute() {
|
||||
var el = new XElement("data");
|
||||
el.Attr("foo", new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc));
|
||||
|
||||
Assert.That(el.Attribute("foo").Value, Is.EqualTo("1970-05-21T13:55:21.934Z"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoubleFloatDecimalToAttribute() {
|
||||
var el = new XElement("data");
|
||||
el.Attr("double", 12.456D);
|
||||
el.Attr("float", 12.457F);
|
||||
el.Attr("decimal", 12.458M);
|
||||
|
||||
Assert.That(el.Attribute("double").Value, Is.EqualTo("12.456"));
|
||||
Assert.That(el.Attribute("float").Value, Is.EqualTo("12.457"));
|
||||
Assert.That(el.Attribute("decimal").Value, Is.EqualTo("12.458"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadAttribute() {
|
||||
var el = XElement.Parse("<data foo=\"bar\"/>");
|
||||
|
||||
Assert.That(el.Attr("foo"), Is.EqualTo("bar"));
|
||||
Assert.That(el.Attr("bar"), Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StringToElement() {
|
||||
var el = new XElement("data");
|
||||
el.El("foo", "bar");
|
||||
|
||||
Assert.That(el.Element("foo").Value, Is.EqualTo("bar"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IntToElement() {
|
||||
var el = new XElement("data");
|
||||
el.El("foo", 42);
|
||||
|
||||
Assert.That(el.Element("foo").Value, Is.EqualTo("42"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BoolToElement() {
|
||||
var el = new XElement("data");
|
||||
el.El("foo", true);
|
||||
el.El("bar", false);
|
||||
|
||||
Assert.That(el.Element("foo").Value, Is.EqualTo("true"));
|
||||
Assert.That(el.Element("bar").Value, Is.EqualTo("false"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DateTimeToElement() {
|
||||
var el = new XElement("data");
|
||||
el.El("foo", new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc));
|
||||
|
||||
Assert.That(el.Element("foo").Value, Is.EqualTo("1970-05-21T13:55:21.934Z"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoubleFloatDecimalToElement() {
|
||||
var el = new XElement("data");
|
||||
el.El("double", 12.456D);
|
||||
el.El("float", 12.457F);
|
||||
el.El("decimal", 12.458M);
|
||||
|
||||
Assert.That(el.Element("double").Value, Is.EqualTo("12.456"));
|
||||
Assert.That(el.Element("float").Value, Is.EqualTo("12.457"));
|
||||
Assert.That(el.Element("decimal").Value, Is.EqualTo("12.458"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadElement() {
|
||||
var el = XElement.Parse("<data><foo>bar</foo></data>");
|
||||
|
||||
Assert.That(el.El("foo"), Is.EqualTo("bar"));
|
||||
Assert.That(el.El("bar"), Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeObject() {
|
||||
var target = new Target {
|
||||
AString = "foo",
|
||||
AnInt = 42,
|
||||
ABoolean = true,
|
||||
ADate = new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc),
|
||||
ADouble = 12.345D,
|
||||
AFloat = 23.456F,
|
||||
ADecimal = 34.567M,
|
||||
ANullableInt = 42,
|
||||
ANullableBoolean = true,
|
||||
ANullableDate = new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc),
|
||||
ANullableDouble = 12.345D,
|
||||
ANullableFloat = 23.456F,
|
||||
ANullableDecimal = 34.567M
|
||||
};
|
||||
var el = new XElement("data");
|
||||
el.With(target)
|
||||
.ToAttr(t => t.AString)
|
||||
.ToAttr(t => t.AnInt)
|
||||
.ToAttr(t => t.ABoolean)
|
||||
.ToAttr(t => t.ADate)
|
||||
.ToAttr(t => t.ADouble)
|
||||
.ToAttr(t => t.AFloat)
|
||||
.ToAttr(t => t.ADecimal)
|
||||
.ToAttr(t => t.ANullableInt)
|
||||
.ToAttr(t => t.ANullableBoolean)
|
||||
.ToAttr(t => t.ANullableDate)
|
||||
.ToAttr(t => t.ANullableDouble)
|
||||
.ToAttr(t => t.ANullableFloat)
|
||||
.ToAttr(t => t.ANullableDecimal);
|
||||
|
||||
|
||||
Assert.That(el.Attr("AString"), Is.EqualTo("foo"));
|
||||
Assert.That(el.Attr("AnInt"), Is.EqualTo("42"));
|
||||
Assert.That(el.Attr("ABoolean"), Is.EqualTo("true"));
|
||||
Assert.That(el.Attr("ADate"), Is.EqualTo("1970-05-21T13:55:21.934Z"));
|
||||
Assert.That(el.Attr("ADouble"), Is.EqualTo("12.345"));
|
||||
Assert.That(el.Attr("AFloat"), Is.EqualTo("23.456"));
|
||||
Assert.That(el.Attr("ADecimal"), Is.EqualTo("34.567"));
|
||||
Assert.That(el.Attr("ANullableInt"), Is.EqualTo("42"));
|
||||
Assert.That(el.Attr("ANullableBoolean"), Is.EqualTo("true"));
|
||||
Assert.That(el.Attr("ANullableDate"), Is.EqualTo("1970-05-21T13:55:21.934Z"));
|
||||
Assert.That(el.Attr("ANullableDouble"), Is.EqualTo("12.345"));
|
||||
Assert.That(el.Attr("ANullableFloat"), Is.EqualTo("23.456"));
|
||||
Assert.That(el.Attr("ANullableDecimal"), Is.EqualTo("34.567"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeSerializeObject() {
|
||||
var target = new Target();
|
||||
var el =
|
||||
XElement.Parse(
|
||||
"<data AString=\"foo\" AnInt=\"42\" ABoolean=\"true\" " +
|
||||
"ADate=\"1970-05-21T13:55:21.934Z\" ADouble=\"12.345\" " +
|
||||
"AFloat=\"23.456\" ADecimal=\"34.567\" " +
|
||||
"ANullableInt=\"42\" ANullableBoolean=\"true\" " +
|
||||
"ANullableDate=\"1970-05-21T13:55:21.934Z\" ANullableDouble=\"12.345\" " +
|
||||
"ANullableFloat=\"23.456\" ANullableDecimal=\"34.567\"/>");
|
||||
el.With(target)
|
||||
.FromAttr(t => t.AString)
|
||||
.FromAttr(t => t.AnInt)
|
||||
.FromAttr(t => t.ABoolean)
|
||||
.FromAttr(t => t.ADate)
|
||||
.FromAttr(t => t.ADouble)
|
||||
.FromAttr(t => t.AFloat)
|
||||
.FromAttr(t => t.ADecimal)
|
||||
.FromAttr(t => t.ANullableInt)
|
||||
.FromAttr(t => t.ANullableBoolean)
|
||||
.FromAttr(t => t.ANullableDate)
|
||||
.FromAttr(t => t.ANullableDouble)
|
||||
.FromAttr(t => t.ANullableFloat)
|
||||
.FromAttr(t => t.ANullableDecimal);
|
||||
|
||||
Assert.That(target.AString, Is.EqualTo("foo"));
|
||||
Assert.That(target.AnInt, Is.EqualTo(42));
|
||||
Assert.That(target.ABoolean, Is.True);
|
||||
Assert.That(target.ADate, Is.EqualTo(new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc)));
|
||||
Assert.That(target.ADouble, Is.EqualTo(12.345D));
|
||||
Assert.That(target.AFloat, Is.EqualTo(23.456F));
|
||||
Assert.That(target.ADecimal, Is.EqualTo(34.567M));
|
||||
Assert.That(target.ANullableInt, Is.EqualTo(42));
|
||||
Assert.That(target.ANullableBoolean, Is.True);
|
||||
Assert.That(target.ANullableDate, Is.EqualTo(new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc)));
|
||||
Assert.That(target.ANullableDouble, Is.EqualTo(12.345D));
|
||||
Assert.That(target.ANullableFloat, Is.EqualTo(23.456F));
|
||||
Assert.That(target.ANullableDecimal, Is.EqualTo(34.567M));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeSerializeFromMissingAttributeLeavesValueIntact() {
|
||||
var target = new Target {
|
||||
AString = "foo",
|
||||
AnInt = 42,
|
||||
ABoolean = true,
|
||||
ADate = new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc),
|
||||
ADouble = 12.345D,
|
||||
AFloat = 23.456F,
|
||||
ADecimal = 34.567M,
|
||||
ANullableInt = 42,
|
||||
ANullableBoolean = true,
|
||||
ANullableDate = new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc),
|
||||
ANullableDouble = 12.345D,
|
||||
ANullableFloat = 23.456F,
|
||||
ANullableDecimal = 34.567M
|
||||
};
|
||||
var el = new XElement("data");
|
||||
el.With(target)
|
||||
.FromAttr(t => t.AString)
|
||||
.FromAttr(t => t.AnInt)
|
||||
.FromAttr(t => t.ABoolean)
|
||||
.FromAttr(t => t.ADate)
|
||||
.FromAttr(t => t.ADouble)
|
||||
.FromAttr(t => t.AFloat)
|
||||
.FromAttr(t => t.ADecimal)
|
||||
.FromAttr(t => t.ANullableInt)
|
||||
.FromAttr(t => t.ANullableBoolean)
|
||||
.FromAttr(t => t.ANullableDate)
|
||||
.FromAttr(t => t.ANullableDouble)
|
||||
.FromAttr(t => t.ANullableFloat)
|
||||
.FromAttr(t => t.ANullableDecimal);
|
||||
|
||||
Assert.That(target.AString, Is.EqualTo("foo"));
|
||||
Assert.That(target.AnInt, Is.EqualTo(42));
|
||||
Assert.That(target.ABoolean, Is.True);
|
||||
Assert.That(target.ADate, Is.EqualTo(new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc)));
|
||||
Assert.That(target.ADouble, Is.EqualTo(12.345D));
|
||||
Assert.That(target.AFloat, Is.EqualTo(23.456F));
|
||||
Assert.That(target.ADecimal, Is.EqualTo(34.567M));
|
||||
Assert.That(target.ANullableInt, Is.EqualTo(42));
|
||||
Assert.That(target.ANullableBoolean, Is.True);
|
||||
Assert.That(target.ANullableDate, Is.EqualTo(new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc)));
|
||||
Assert.That(target.ANullableDouble, Is.EqualTo(12.345D));
|
||||
Assert.That(target.ANullableFloat, Is.EqualTo(23.456F));
|
||||
Assert.That(target.ANullableDecimal, Is.EqualTo(34.567M));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AttrWithContext() {
|
||||
var el = new XElement("data")
|
||||
.With(new {foo = 123})
|
||||
.ToAttr(o => o.foo);
|
||||
var val = el.Attr(o => o.foo);
|
||||
|
||||
Assert.That(val, Is.EqualTo(123));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ContextSwitch() {
|
||||
var el = new XElement("data");
|
||||
el.With(new {foo = "bar"})
|
||||
.ToAttr(o => o.foo)
|
||||
.With(new {bar = "baz"})
|
||||
.ToAttr(o => o.bar);
|
||||
|
||||
Assert.That(el.Attr<string>("foo"), Is.EqualTo("bar"));
|
||||
Assert.That(el.Attr<string>("bar"), Is.EqualTo("baz"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ImplicitConversion() {
|
||||
var el = new XElement("data")
|
||||
.With(new {foo = "bar"})
|
||||
.ToAttr(o => o.foo);
|
||||
Func<XElement, string> func = e => e.Attr<string>("foo");
|
||||
|
||||
Assert.That(func(el), Is.EqualTo("bar"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NullSerializes() {
|
||||
var target = new Target();
|
||||
var el = new XElement("data");
|
||||
el.With(target)
|
||||
.ToAttr(t => t.AString)
|
||||
.ToAttr(t => t.ANullableInt)
|
||||
.ToAttr(t => t.ANullableBoolean)
|
||||
.ToAttr(t => t.ANullableDate)
|
||||
.ToAttr(t => t.ANullableDouble)
|
||||
.ToAttr(t => t.ANullableFloat)
|
||||
.ToAttr(t => t.ANullableDecimal);
|
||||
|
||||
Assert.That(el.Attr("AString"), Is.EqualTo(""));
|
||||
Assert.That(el.Attr("ANullableInt"), Is.EqualTo("null"));
|
||||
Assert.That(el.Attr("ANullableBoolean"), Is.EqualTo("null"));
|
||||
Assert.That(el.Attr("ANullableDate"), Is.EqualTo("null"));
|
||||
Assert.That(el.Attr("ANullableDouble"), Is.EqualTo("null"));
|
||||
Assert.That(el.Attr("ANullableFloat"), Is.EqualTo("null"));
|
||||
Assert.That(el.Attr("ANullableDecimal"), Is.EqualTo("null"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeSerializeNull() {
|
||||
var target = new Target();
|
||||
var el =
|
||||
XElement.Parse(
|
||||
"<data AString=\"null\" ANullableInt=\"null\" ANullableBoolean=\"null\" " +
|
||||
"ANullableDate=\"null\" ANullableDouble=\"null\" " +
|
||||
"ANullableFloat=\"null\" ANullableDecimal=\"null\"/>");
|
||||
el.With(target)
|
||||
.FromAttr(t => t.AString)
|
||||
.FromAttr(t => t.ANullableInt)
|
||||
.FromAttr(t => t.ANullableBoolean)
|
||||
.FromAttr(t => t.ANullableDate)
|
||||
.FromAttr(t => t.ANullableDouble)
|
||||
.FromAttr(t => t.ANullableFloat)
|
||||
.FromAttr(t => t.ANullableDecimal);
|
||||
|
||||
Assert.That(target.AString, Is.EqualTo("null"));
|
||||
Assert.That(target.ANullableInt, Is.Null);
|
||||
Assert.That(target.ANullableBoolean, Is.Null);
|
||||
Assert.That(target.ANullableDate, Is.Null);
|
||||
Assert.That(target.ANullableDouble, Is.Null);
|
||||
Assert.That(target.ANullableFloat, Is.Null);
|
||||
Assert.That(target.ANullableDecimal, Is.Null);
|
||||
}
|
||||
|
||||
private class Target {
|
||||
public string AString { get; set; }
|
||||
public int AnInt { get; set; }
|
||||
public bool ABoolean { get; set; }
|
||||
public DateTime ADate { get; set; }
|
||||
public double ADouble { get; set; }
|
||||
public float AFloat { get; set; }
|
||||
public decimal ADecimal { get; set; }
|
||||
public int? ANullableInt { get; set; }
|
||||
public bool? ANullableBoolean { get; set; }
|
||||
public DateTime? ANullableDate { get; set; }
|
||||
public double? ANullableDouble { get; set; }
|
||||
public float? ANullableFloat { get; set; }
|
||||
public decimal? ANullableDecimal { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -161,6 +161,7 @@
|
||||
<Compile Include="Commands\CommandHandlerDescriptorBuilderTests.cs" />
|
||||
<Compile Include="Commands\CommandHandlerTests.cs" />
|
||||
<Compile Include="Commands\CommandManagerTests.cs" />
|
||||
<Compile Include="ContentManagement\ContentHelpers.cs" />
|
||||
<Compile Include="ContentManagement\ContentIdentityTests.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
@@ -180,6 +181,7 @@
|
||||
<Compile Include="ContentManagement\Handlers\GammaPartHandler.cs" />
|
||||
<Compile Include="ContentManagement\Handlers\ModelBuilderTests.cs" />
|
||||
<Compile Include="ContentManagement\ImportContentSessionTests.cs" />
|
||||
<Compile Include="ContentManagement\InfosetHelperTests.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\Builders\ContentTypeDefinitionBuilderTests.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\Services\ContentDefinitionReaderTests.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\Services\ContentDefinitionWriterTests.cs" />
|
||||
@@ -210,6 +212,7 @@
|
||||
<Compile Include="ContentManagement\Records\GammaRecord.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ContentManagement\XmlHelperTests.cs" />
|
||||
<Compile Include="DatabaseEnabledTestsBase.cs" />
|
||||
<Compile Include="DataMigration\SchemaBuilderTests.cs" />
|
||||
<Compile Include="DataMigration\DataMigrationTests.cs" />
|
||||
|
@@ -3,11 +3,8 @@ using Orchard.ContentManagement;
|
||||
namespace Orchard.Core.Common.Models {
|
||||
public class BodyPart : ContentPart<BodyPartRecord> {
|
||||
public string Text {
|
||||
get { return Get("Text"); }
|
||||
set {
|
||||
Set("Text", value);
|
||||
Record.Text = value;
|
||||
}
|
||||
get { return Retrieve(x => x.Text); }
|
||||
set { Store(x => x.Text, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Xml;
|
||||
using Orchard.Core.Common.Utilities;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Aspects;
|
||||
@@ -23,73 +22,56 @@ namespace Orchard.Core.Common.Models {
|
||||
get { return _container.Value; }
|
||||
set { _container.Value = value; }
|
||||
}
|
||||
|
||||
|
||||
public DateTime? CreatedUtc {
|
||||
get {
|
||||
var dateTime = Get("CreatedUtc");
|
||||
return String.IsNullOrEmpty(dateTime) ? (DateTime?)null : XmlConvert.ToDateTime(dateTime, XmlDateTimeSerializationMode.Utc);
|
||||
}
|
||||
set {
|
||||
string dateTime = value.HasValue ? XmlConvert.ToString(value.Value, XmlDateTimeSerializationMode.Utc) : "";
|
||||
Set("CreatedUtc", dateTime);
|
||||
Record.CreatedUtc = value;
|
||||
}
|
||||
get { return Retrieve(x => x.CreatedUtc); }
|
||||
set { Store(x => x.CreatedUtc, value); }
|
||||
}
|
||||
|
||||
public DateTime? PublishedUtc {
|
||||
get {
|
||||
var dateTime = Get("PublishedUtc");
|
||||
return String.IsNullOrEmpty(dateTime) ? (DateTime?)null : XmlConvert.ToDateTime(dateTime, XmlDateTimeSerializationMode.Utc);
|
||||
}
|
||||
set {
|
||||
string dateTime = value.HasValue ? XmlConvert.ToString(value.Value, XmlDateTimeSerializationMode.Utc) : "";
|
||||
Set("PublishedUtc", dateTime);
|
||||
Record.PublishedUtc = value;
|
||||
}
|
||||
get { return Retrieve(x => x.PublishedUtc); }
|
||||
set { Store(x => x.PublishedUtc, value); }
|
||||
}
|
||||
|
||||
public DateTime? ModifiedUtc {
|
||||
get { return Retrieve(x => x.ModifiedUtc); }
|
||||
set { Store(x => x.ModifiedUtc, value); }
|
||||
}
|
||||
|
||||
CommonPartVersionRecord PartVersionRecord {
|
||||
get {
|
||||
var dateTime = Get("ModifiedUtc");
|
||||
return String.IsNullOrEmpty(dateTime) ? (DateTime?)null : XmlConvert.ToDateTime(dateTime, XmlDateTimeSerializationMode.Utc);
|
||||
}
|
||||
set {
|
||||
string dateTime = value.HasValue ? XmlConvert.ToString(value.Value, XmlDateTimeSerializationMode.Utc) : "";
|
||||
Set("ModifiedUtc", dateTime);
|
||||
Record.ModifiedUtc = value;
|
||||
var versionPart = this.As<ContentPart<CommonPartVersionRecord>>();
|
||||
return versionPart == null ? null : versionPart.Record;
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime? VersionCreatedUtc {
|
||||
get {
|
||||
var dateTime = this.As<ContentPart<CommonPartVersionRecord>>().Get("CreatedUtc");
|
||||
return String.IsNullOrEmpty(dateTime) ? (DateTime?)null : XmlConvert.ToDateTime(dateTime, XmlDateTimeSerializationMode.Utc);
|
||||
return PartVersionRecord == null ? CreatedUtc : PartVersionRecord.CreatedUtc;
|
||||
}
|
||||
set {
|
||||
string dateTime = value.HasValue ? XmlConvert.ToString(value.Value, XmlDateTimeSerializationMode.Utc) : "";
|
||||
this.As<ContentPart<CommonPartVersionRecord>>().Set("CreatedUtc", dateTime);
|
||||
if (PartVersionRecord != null)
|
||||
PartVersionRecord.CreatedUtc = value;
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime? VersionPublishedUtc {
|
||||
get {
|
||||
var dateTime = this.As<ContentPart<CommonPartVersionRecord>>().Get("PublishedUtc");
|
||||
return String.IsNullOrEmpty(dateTime) ? (DateTime?)null : XmlConvert.ToDateTime(dateTime, XmlDateTimeSerializationMode.Utc);
|
||||
return PartVersionRecord == null ? PublishedUtc : PartVersionRecord.PublishedUtc;
|
||||
}
|
||||
set {
|
||||
string dateTime = value.HasValue ? XmlConvert.ToString(value.Value, XmlDateTimeSerializationMode.Utc) : "";
|
||||
this.As<ContentPart<CommonPartVersionRecord>>().Set("PublishedUtc", dateTime);
|
||||
if (PartVersionRecord != null)
|
||||
PartVersionRecord.PublishedUtc = value;
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime? VersionModifiedUtc {
|
||||
get {
|
||||
var dateTime = this.As<ContentPart<CommonPartVersionRecord>>().Get("ModifiedUtc");
|
||||
return String.IsNullOrEmpty(dateTime) ? (DateTime?)null : XmlConvert.ToDateTime(dateTime, XmlDateTimeSerializationMode.Utc);
|
||||
return PartVersionRecord == null ? ModifiedUtc : PartVersionRecord.ModifiedUtc;
|
||||
}
|
||||
set {
|
||||
string dateTime = value.HasValue ? XmlConvert.ToString(value.Value, XmlDateTimeSerializationMode.Utc) : "";
|
||||
this.As<ContentPart<CommonPartVersionRecord>>().Set("ModifiedUtc", dateTime);
|
||||
if (PartVersionRecord != null)
|
||||
PartVersionRecord.ModifiedUtc = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,11 +3,8 @@ using Orchard.ContentManagement;
|
||||
namespace Orchard.Core.Common.Models {
|
||||
public class IdentityPart : ContentPart<IdentityPartRecord> {
|
||||
public string Identifier {
|
||||
get { return Get("Identifier"); }
|
||||
set {
|
||||
Set("Identifier", value);
|
||||
Record.Identifier = value;
|
||||
}
|
||||
get { return Retrieve(x => x.Identifier); }
|
||||
set { Store(x => x.Identifier, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,48 +1,32 @@
|
||||
using System.Globalization;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Records;
|
||||
|
||||
namespace Orchard.Core.Navigation.Models {
|
||||
public class MenuWidgetPart : ContentPart<MenuWidgetPartRecord> {
|
||||
|
||||
public int StartLevel {
|
||||
get { return int.Parse(Get("StartLevel") ?? "0", CultureInfo.InvariantCulture); }
|
||||
set {
|
||||
Set("StartLevel", value.ToString(CultureInfo.InvariantCulture));
|
||||
Record.StartLevel = value;
|
||||
}
|
||||
get { return Retrieve(x => x.StartLevel); }
|
||||
set { Store(x => x.StartLevel, value); }
|
||||
}
|
||||
|
||||
public int Levels {
|
||||
get { return int.Parse(Get("Levels") ?? "0", CultureInfo.InvariantCulture); }
|
||||
set {
|
||||
Set("Levels", value.ToString(CultureInfo.InvariantCulture));
|
||||
Record.Levels = value;
|
||||
}
|
||||
get { return Retrieve(x => x.Levels); }
|
||||
set { Store(x => x.Levels, value); }
|
||||
}
|
||||
|
||||
public bool Breadcrumb {
|
||||
get { return bool.Parse(Get("Breadcrumb") ?? "false"); }
|
||||
set {
|
||||
Set("Breadcrumb", value.ToString());
|
||||
Record.Breadcrumb = value;
|
||||
}
|
||||
get { return Retrieve(x => x.Breadcrumb); }
|
||||
set { Store(x => x.Breadcrumb, value); }
|
||||
}
|
||||
|
||||
public bool AddHomePage {
|
||||
get { return bool.Parse(Get("AddHomePage") ?? "false"); }
|
||||
set {
|
||||
Set("AddHomePage", value.ToString());
|
||||
Record.AddHomePage = value;
|
||||
}
|
||||
get { return Retrieve(x => x.AddHomePage); }
|
||||
set { Store(x => x.AddHomePage, value); }
|
||||
}
|
||||
|
||||
public bool AddCurrentPage {
|
||||
get { return bool.Parse(Get("AddCurrentPage") ?? "false"); }
|
||||
set {
|
||||
Set("AddCurrentPage", value.ToString());
|
||||
Record.AddCurrentPage = value;
|
||||
}
|
||||
get { return Retrieve(x => x.AddCurrentPage); }
|
||||
set { Store(x => x.AddCurrentPage, value); }
|
||||
}
|
||||
|
||||
public ContentItemRecord Menu {
|
||||
|
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Settings;
|
||||
|
||||
namespace Orchard.Core.Settings.Models {
|
||||
@@ -8,55 +6,52 @@ namespace Orchard.Core.Settings.Models {
|
||||
|
||||
public const int DefaultPageSize = 10;
|
||||
public string PageTitleSeparator {
|
||||
get { return Get("PageTitleSeparator"); }
|
||||
set { Set("PageTitleSeparator", value); }
|
||||
get { return this.Retrieve(x => x.PageTitleSeparator); }
|
||||
set { this.Store(x => x.PageTitleSeparator, value); }
|
||||
}
|
||||
public string SiteName {
|
||||
get { return Get("SiteName"); }
|
||||
set { Set("SiteName", value); }
|
||||
get { return this.Retrieve(x => x.SiteName); }
|
||||
set { this.Store(x => x.SiteName, value); }
|
||||
}
|
||||
|
||||
public string SiteSalt {
|
||||
get { return Get("SiteSalt"); }
|
||||
set { Set("SiteSalt", value); }
|
||||
get { return this.Retrieve(x => x.SiteSalt); }
|
||||
set { this.Store(x => x.SiteSalt, value); }
|
||||
}
|
||||
|
||||
public string SuperUser {
|
||||
get { return Get("SuperUser"); }
|
||||
set { Set("SuperUser", value); }
|
||||
get { return this.Retrieve(x => x.SuperUser); }
|
||||
set { this.Store(x => x.SuperUser, value); }
|
||||
}
|
||||
|
||||
public string HomePage {
|
||||
get { return Get("HomePage"); }
|
||||
set { Set("HomePage", value); }
|
||||
get { return this.Retrieve(x => x.HomePage); }
|
||||
set { this.Store(x => x.HomePage, value); }
|
||||
}
|
||||
|
||||
public string SiteCulture {
|
||||
get { return Get("SiteCulture"); }
|
||||
set { Set("SiteCulture", value); }
|
||||
get { return this.Retrieve(x => x.SiteCulture); }
|
||||
set { this.Store(x => x.SiteCulture, value); }
|
||||
}
|
||||
|
||||
public ResourceDebugMode ResourceDebugMode {
|
||||
get {
|
||||
var value = Get("ResourceDebugMode");
|
||||
return String.IsNullOrEmpty(value) ? ResourceDebugMode.Disabled : (ResourceDebugMode)Enum.Parse(typeof(ResourceDebugMode), value);
|
||||
}
|
||||
set { Set("ResourceDebugMode", value.ToString()); }
|
||||
get { return this.Retrieve(x => x.ResourceDebugMode); }
|
||||
set { this.Store(x => x.ResourceDebugMode, value); }
|
||||
}
|
||||
|
||||
public int PageSize {
|
||||
get { return int.Parse(Get("PageSize") ?? "0", CultureInfo.InvariantCulture); }
|
||||
set { Set("PageSize", value.ToString(CultureInfo.InvariantCulture)); }
|
||||
get { return this.Retrieve(x => x.PageSize); }
|
||||
set { this.Store(x => x.PageSize, value); }
|
||||
}
|
||||
|
||||
public string SiteTimeZone {
|
||||
get { return Get("SiteTimeZone"); }
|
||||
set { Set("SiteTimeZone", value); }
|
||||
get { return this.Retrieve(x => x.SiteTimeZone); }
|
||||
set { this.Store(x => x.SiteTimeZone, value); }
|
||||
}
|
||||
|
||||
public string BaseUrl {
|
||||
get { return Get("BaseUrl"); }
|
||||
set { Set("BaseUrl", value); }
|
||||
get { return this.Retrieve(x => x.BaseUrl); }
|
||||
set { this.Store(x => x.BaseUrl, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,13 +6,8 @@ namespace Orchard.Core.Title.Models {
|
||||
public class TitlePart : ContentPart<TitlePartRecord>, ITitleAspect {
|
||||
[Required]
|
||||
public string Title {
|
||||
get {
|
||||
return Get("Title");
|
||||
}
|
||||
set {
|
||||
Set("Title", value);
|
||||
Record.Title = value;
|
||||
}
|
||||
get { return Retrieve(x => x.Title); }
|
||||
set { Store(x => x.Title, value); }
|
||||
}
|
||||
}
|
||||
}
|
@@ -83,13 +83,6 @@ namespace Orchard.AntiSpam {
|
||||
public class AkismetMigrations : DataMigrationImpl {
|
||||
|
||||
public int Create() {
|
||||
|
||||
SchemaBuilder.CreateTable("AkismetSettingsPartRecord",
|
||||
table => table.ContentPartVersionRecord()
|
||||
.Column<bool>("TrustAuthenticatedUsers")
|
||||
.Column<string>("ApiKey")
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@@ -3,13 +3,13 @@
|
||||
namespace Orchard.AntiSpam.Models {
|
||||
public class AkismetSettingsPart : ContentPart {
|
||||
public bool TrustAuthenticatedUsers {
|
||||
get { return bool.Parse(Get("TrustAuthenticatedUsers") ?? "false"); }
|
||||
set { Set("TrustAuthenticatedUsers", value.ToString()); }
|
||||
get { return this.Retrieve(x => x.TrustAuthenticatedUsers); }
|
||||
set { this.Store(x => x.TrustAuthenticatedUsers, value); }
|
||||
}
|
||||
|
||||
public string ApiKey {
|
||||
get { return Get("ApiKey"); }
|
||||
set { Set("ApiKey", value); }
|
||||
get { return this.Retrieve(x => x.ApiKey); }
|
||||
set { this.Store(x => x.ApiKey, value); }
|
||||
}
|
||||
}
|
||||
}
|
@@ -5,27 +5,16 @@ namespace Orchard.Autoroute.Models {
|
||||
public class AutoroutePart : ContentPart<AutoroutePartRecord>, IAliasAspect {
|
||||
|
||||
public string CustomPattern {
|
||||
get { return Get("CustomPattern"); }
|
||||
set {
|
||||
Set("CustomPattern", value);
|
||||
Record.CustomPattern = value;
|
||||
}
|
||||
get { return Retrieve(x => x.CustomPattern); }
|
||||
set { Store(x => x.CustomPattern, value); }
|
||||
}
|
||||
|
||||
public bool UseCustomPattern {
|
||||
get { return bool.Parse(Get("UseCustomPattern")); }
|
||||
set {
|
||||
Set("UseCustomPattern", value.ToString());
|
||||
Record.UseCustomPattern = value;
|
||||
}
|
||||
get { return Retrieve(x => x.UseCustomPattern); }
|
||||
set { Store(x => x.UseCustomPattern, value); }
|
||||
}
|
||||
|
||||
public string DisplayAlias {
|
||||
get { return Get("DisplayAlias"); }
|
||||
set {
|
||||
Set("DisplayAlias", value);
|
||||
Record.DisplayAlias = value;
|
||||
}
|
||||
get { return Retrieve(x => x.DisplayAlias); }
|
||||
set { Store(x => x.DisplayAlias, value); }
|
||||
}
|
||||
|
||||
public string Path {
|
||||
|
@@ -3,8 +3,8 @@
|
||||
namespace Orchard.Themes.Models {
|
||||
public class ThemeSiteSettingsPart : ContentPart {
|
||||
public string CurrentThemeName {
|
||||
get { return Get("CurrentThemeName"); }
|
||||
set { Set("CurrentThemeName", value); }
|
||||
get { return this.Retrieve(x => x.CurrentThemeName); }
|
||||
set { this.Store(x => x.CurrentThemeName, value); }
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,9 +2,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Web.Mvc;
|
||||
using Autofac;
|
||||
using Orchard.ContentManagement.FieldStorage.InfosetStorage;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.ContentManagement.Utilities;
|
||||
@@ -79,33 +79,49 @@ namespace Orchard.ContentManagement {
|
||||
|
||||
return true;
|
||||
}
|
||||
public virtual string Get(string fieldName) {
|
||||
return this.As<InfosetPart>().Get(GetType().Name, fieldName, null, false);
|
||||
|
||||
public T Retrieve<T>(string fieldName) {
|
||||
return InfosetHelper.Retrieve<T>(this, fieldName);
|
||||
}
|
||||
|
||||
public string GetVersioned(string fieldName) {
|
||||
return this.As<InfosetPart>().Get(GetType().Name, fieldName, null, true);
|
||||
public T RetrieveVersioned<T>(string fieldName) {
|
||||
return this.Retrieve<T>(fieldName, true);
|
||||
}
|
||||
public virtual void Set(string fieldName, string value) {
|
||||
this.As<InfosetPart>().Set(GetType().Name, fieldName, null, value, false);
|
||||
|
||||
public virtual void Store<T>(string fieldName, T value) {
|
||||
InfosetHelper.Store(this, fieldName, value);
|
||||
}
|
||||
public void SetVersionned(string fieldName, string value) {
|
||||
this.As<InfosetPart>().Set(GetType().Name, fieldName, null, value, true);
|
||||
|
||||
public virtual void StoreVersioned<T>(string fieldName, T value) {
|
||||
this.Store(fieldName, value, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class ContentPart<TRecord> : ContentPart {
|
||||
|
||||
static protected bool IsVersionableRecord { get; private set;}
|
||||
|
||||
static ContentPart() {
|
||||
IsVersionableRecord = typeof (TRecord).IsAssignableTo<ContentItemVersionRecord>();
|
||||
}
|
||||
|
||||
public override string Get(string fieldName) {
|
||||
return this.As<InfosetPart>().Get(GetType().Name, fieldName, null, IsVersionableRecord);
|
||||
protected TProperty Retrieve<TProperty>(Expression<Func<TRecord, TProperty>> targetExpression) {
|
||||
return InfosetHelper.Retrieve(this, targetExpression);
|
||||
}
|
||||
public override void Set(string fieldName, string value) {
|
||||
this.As<InfosetPart>().Set(GetType().Name, fieldName, null, value, IsVersionableRecord);
|
||||
|
||||
protected TProperty Retrieve<TProperty>(
|
||||
Expression<Func<TRecord, TProperty>> targetExpression,
|
||||
Func<TRecord, TProperty> defaultExpression) {
|
||||
|
||||
return InfosetHelper.Retrieve(this, targetExpression, defaultExpression);
|
||||
}
|
||||
protected ContentPart<TRecord> Store<TProperty>(
|
||||
Expression<Func<TRecord, TProperty>> targetExpression,
|
||||
TProperty value) {
|
||||
|
||||
InfosetHelper.Store(this, targetExpression, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public readonly LazyField<TRecord> _record = new LazyField<TRecord>();
|
||||
|
112
src/Orchard/ContentManagement/InfosetHelper.cs
Normal file
112
src/Orchard/ContentManagement/InfosetHelper.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.ContentManagement.FieldStorage.InfosetStorage;
|
||||
using Orchard.Utility;
|
||||
|
||||
namespace Orchard.ContentManagement {
|
||||
public static class InfosetHelper {
|
||||
|
||||
public static TProperty Retrieve<TPart, TProperty>(this TPart contentPart,
|
||||
Expression<Func<TPart, TProperty>> targetExpression,
|
||||
bool versioned = false) where TPart : ContentPart {
|
||||
|
||||
var propertyInfo = ReflectionHelper<TPart>.GetPropertyInfo(targetExpression);
|
||||
var name = propertyInfo.Name;
|
||||
|
||||
var infosetPart = contentPart.As<InfosetPart>();
|
||||
var el = infosetPart == null
|
||||
? null
|
||||
: (versioned ? infosetPart.VersionInfoset.Element : infosetPart.Infoset.Element)
|
||||
.Element(contentPart.GetType().Name);
|
||||
return el == null ? default(TProperty) : el.Attr<TProperty>(name);
|
||||
}
|
||||
|
||||
public static TProperty Retrieve<TProperty>(this ContentPart contentPart, string name,
|
||||
bool versioned = false) {
|
||||
var infosetPart = contentPart.As<InfosetPart>();
|
||||
var el = infosetPart == null
|
||||
? null
|
||||
: (versioned ? infosetPart.VersionInfoset.Element : infosetPart.Infoset.Element)
|
||||
.Element(contentPart.GetType().Name);
|
||||
return el == null ? default(TProperty) : el.Attr<TProperty>(name);
|
||||
}
|
||||
|
||||
public static void Store<TPart, TProperty>(this TPart contentPart,
|
||||
Expression<Func<TPart, TProperty>> targetExpression,
|
||||
TProperty value, bool versioned = false) where TPart : ContentPart {
|
||||
|
||||
var partName = contentPart.GetType().Name;
|
||||
|
||||
var infosetPart = contentPart.As<InfosetPart>();
|
||||
var infoset = (versioned ? infosetPart.VersionInfoset : infosetPart.Infoset);
|
||||
var partElement = infoset.Element.Element(partName);
|
||||
if (partElement == null) {
|
||||
partElement = new XElement(partName);
|
||||
infoset.Element.Add(partElement);
|
||||
}
|
||||
|
||||
var propertyInfo = ReflectionHelper<TPart>.GetPropertyInfo(targetExpression);
|
||||
var name = propertyInfo.Name;
|
||||
|
||||
partElement.Attr(name, value);
|
||||
}
|
||||
|
||||
public static void Store<TProperty>(this ContentPart contentPart, string name,
|
||||
TProperty value, bool versioned = false) {
|
||||
|
||||
var partName = contentPart.GetType().Name;
|
||||
|
||||
var infosetPart = contentPart.As<InfosetPart>();
|
||||
var infoset = (versioned ? infosetPart.VersionInfoset : infosetPart.Infoset);
|
||||
var partElement = infoset.Element.Element(partName);
|
||||
if (partElement == null) {
|
||||
partElement = new XElement(partName);
|
||||
infoset.Element.Add(partElement);
|
||||
}
|
||||
partElement.Attr(name, value);
|
||||
}
|
||||
|
||||
public static TProperty Retrieve<TPart, TRecord, TProperty>(this TPart contentPart,
|
||||
Expression<Func<TRecord, TProperty>> targetExpression)
|
||||
where TPart : ContentPart<TRecord> {
|
||||
|
||||
var getter = ReflectionHelper<TRecord>.GetGetter(targetExpression);
|
||||
return contentPart.Retrieve(targetExpression, getter);
|
||||
}
|
||||
|
||||
public static TProperty Retrieve<TPart, TRecord, TProperty>(this TPart contentPart,
|
||||
Expression<Func<TRecord, TProperty>> targetExpression,
|
||||
Delegate defaultExpression)
|
||||
where TPart : ContentPart<TRecord> {
|
||||
|
||||
var propertyInfo = ReflectionHelper<TRecord>.GetPropertyInfo(targetExpression);
|
||||
var name = propertyInfo.Name;
|
||||
|
||||
var infosetPart = contentPart.As<InfosetPart>();
|
||||
var el = infosetPart == null
|
||||
? null
|
||||
: infosetPart.Infoset.Element.Element(contentPart.GetType().Name);
|
||||
if (el == null || el.Attribute(name) == null) {
|
||||
// Property has never been stored. Get it from the default expression and store that.
|
||||
var defaultValue = defaultExpression == null
|
||||
? default(TProperty)
|
||||
: (TProperty)defaultExpression.DynamicInvoke(contentPart.Record);
|
||||
contentPart.Store(name, defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
return el.Attr<TProperty>(name);
|
||||
}
|
||||
|
||||
public static void Store<TPart, TRecord, TProperty>(this TPart contentPart,
|
||||
Expression<Func<TRecord, TProperty>> targetExpression,
|
||||
TProperty value)
|
||||
where TPart : ContentPart<TRecord> {
|
||||
|
||||
var propertyInfo = ReflectionHelper<TRecord>.GetPropertyInfo(targetExpression);
|
||||
var name = propertyInfo.Name;
|
||||
propertyInfo.SetValue(contentPart.Record, value, null);
|
||||
contentPart.Store(name, value);
|
||||
}
|
||||
}
|
||||
}
|
345
src/Orchard/ContentManagement/XmlHelper.cs
Normal file
345
src/Orchard/ContentManagement/XmlHelper.cs
Normal file
@@ -0,0 +1,345 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.Utility;
|
||||
|
||||
namespace Orchard.ContentManagement {
|
||||
public static class XmlHelper {
|
||||
/// <summary>
|
||||
/// Like Add, but chainable.
|
||||
/// </summary>
|
||||
/// <param name="el">The parent element.</param>
|
||||
/// <param name="children">The elements to add.</param>
|
||||
/// <returns>Itself</returns>
|
||||
public static XElement AddEl(this XElement el, params XElement[] children) {
|
||||
el.Add(children.Cast<object>());
|
||||
return el;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string value of an attribute, and null if the attribute doesn't exist.
|
||||
/// </summary>
|
||||
/// <param name="el">The element.</param>
|
||||
/// <param name="name">The name of the attribute.</param>
|
||||
/// <returns>The string value of the attribute if it exists, null otherwise.</returns>
|
||||
public static string Attr(this XElement el, string name) {
|
||||
var attr = el.Attribute(name);
|
||||
return attr == null ? null : attr.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a typed value from an attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value</typeparam>
|
||||
/// <param name="el">The element.</param>
|
||||
/// <param name="name">The name of the attribute.</param>
|
||||
/// <returns>The attribute value</returns>
|
||||
public static T Attr<T>(this XElement el, string name) {
|
||||
|
||||
var attr = el.Attribute(name);
|
||||
return attr == null ? default(T) : Parse<T>(attr.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets an attribute value. This is chainable.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value.</typeparam>
|
||||
/// <param name="el">The element.</param>
|
||||
/// <param name="name">The attribute name.</param>
|
||||
/// <param name="value">The value to set.</param>
|
||||
/// <returns>Itself</returns>
|
||||
public static XElement Attr<T>(this XElement el, string name, T value) {
|
||||
el.SetAttributeValue(name, ToString(value));
|
||||
return el;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the text contents of a child element.
|
||||
/// </summary>
|
||||
/// <param name="el">The parent element.</param>
|
||||
/// <param name="name">The name of the child element.</param>
|
||||
/// <returns>The text for the child element, and null if it doesn't exist.</returns>
|
||||
public static string El(this XElement el, string name) {
|
||||
var childElement = el.Element(name);
|
||||
return childElement == null ? null : childElement.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and sets the value of a child element. This is chainable.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value.</typeparam>
|
||||
/// <param name="el">The parent element.</param>
|
||||
/// <param name="name">The name of the child element.</param>
|
||||
/// <param name="value">The value to set.</param>
|
||||
/// <returns>Itself</returns>
|
||||
public static XElement El<T>(this XElement el, string name, T value) {
|
||||
el.SetElementValue(name, value);
|
||||
return el;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a property value from an attribute of the same name.
|
||||
/// </summary>
|
||||
/// <typeparam name="TTarget">The type of the target object.</typeparam>
|
||||
/// <typeparam name="TProperty">The type of the target property</typeparam>
|
||||
/// <param name="el">The element.</param>
|
||||
/// <param name="target">The target object.</param>
|
||||
/// <param name="targetExpression">The property expression.</param>
|
||||
/// <returns>Itself</returns>
|
||||
public static XElement FromAttr<TTarget, TProperty>(this XElement el, TTarget target,
|
||||
Expression<Func<TTarget, TProperty>> targetExpression) {
|
||||
|
||||
if (target == null) return el;
|
||||
var propertyInfo = ReflectionHelper<TTarget>.GetPropertyInfo(targetExpression);
|
||||
var name = propertyInfo.Name;
|
||||
var attr = el.Attribute(name);
|
||||
|
||||
if (attr == null) return el;
|
||||
propertyInfo.SetValue(target, el.Attr<TProperty>(name), null);
|
||||
return el;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets an attribute with the value of a property of the same name.
|
||||
/// </summary>
|
||||
/// <typeparam name="TTarget">The type of the object.</typeparam>
|
||||
/// <typeparam name="TProperty">The type of the property.</typeparam>
|
||||
/// <param name="el">The element.</param>
|
||||
/// <param name="target">The object.</param>
|
||||
/// <param name="targetExpression">The property expression.</param>
|
||||
/// <returns>Itself</returns>
|
||||
public static XElement ToAttr<TTarget, TProperty>(this XElement el, TTarget target,
|
||||
Expression<Func<TTarget, TProperty>> targetExpression) {
|
||||
|
||||
if (target == null) return el;
|
||||
var propertyInfo = ReflectionHelper<TTarget>.GetPropertyInfo(targetExpression);
|
||||
var name = propertyInfo.Name;
|
||||
var val = (TProperty)propertyInfo.GetValue(target, null);
|
||||
|
||||
el.Attr(name, ToString(val));
|
||||
return el;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the text value of an element as the specified type.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue">The type to parse the element as.</typeparam>
|
||||
/// <param name="el">The element.</param>
|
||||
/// <returns>The value of the element as type TValue.</returns>
|
||||
public static TValue Val<TValue>(this XElement el) {
|
||||
return Parse<TValue>(el.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of an element.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue">The type of the value to set.</typeparam>
|
||||
/// <param name="el">The element.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns>The element.</returns>
|
||||
public static XElement Val<TValue>(this XElement el, TValue value) {
|
||||
el.SetValue(ToString(value));
|
||||
return el;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the provided value as a string.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value.</typeparam>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns>The string representation of the value.</returns>
|
||||
public static string ToString<T>(T value) {
|
||||
var type = typeof(T);
|
||||
if (type == typeof(string)) {
|
||||
return Convert.ToString(value);
|
||||
}
|
||||
if ((!type.IsValueType || Nullable.GetUnderlyingType(type) != null) &&
|
||||
value == null &&
|
||||
type != typeof(string)) {
|
||||
|
||||
return "null";
|
||||
}
|
||||
|
||||
if (type == typeof(DateTime) || type == typeof(DateTime?)) {
|
||||
return XmlConvert.ToString(Convert.ToDateTime(value),
|
||||
XmlDateTimeSerializationMode.Utc);
|
||||
}
|
||||
|
||||
if (type == typeof(bool) ||
|
||||
type == typeof(bool?)) {
|
||||
return Convert.ToBoolean(value) ? "true" : "false";
|
||||
}
|
||||
|
||||
if (type == typeof(int) ||
|
||||
type == typeof(int?)) {
|
||||
|
||||
return Convert.ToInt64(value).ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (type == typeof(double) ||
|
||||
type == typeof(double?)) {
|
||||
|
||||
var doubleValue = (double)(object)value;
|
||||
if (double.IsPositiveInfinity(doubleValue)) {
|
||||
return "infinity";
|
||||
}
|
||||
if (double.IsNegativeInfinity(doubleValue)) {
|
||||
return "-infinity";
|
||||
}
|
||||
return doubleValue.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (type == typeof(float) ||
|
||||
type == typeof(float?)) {
|
||||
|
||||
var floatValue = (float)(object)value;
|
||||
if (float.IsPositiveInfinity(floatValue)) {
|
||||
return "infinity";
|
||||
}
|
||||
if (float.IsNegativeInfinity(floatValue)) {
|
||||
return "-infinity";
|
||||
}
|
||||
return floatValue.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (type == typeof(decimal) ||
|
||||
type == typeof(decimal?)) {
|
||||
|
||||
var decimalValue = Convert.ToDecimal(value);
|
||||
return decimalValue.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
throw new NotSupportedException(String.Format("Could not handle type {0}", type.Name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a string value as the provided type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The destination type</typeparam>
|
||||
/// <param name="value">The string representation of the value to parse.</param>
|
||||
/// <returns>The parsed value with type T.</returns>
|
||||
public static T Parse<T>(string value) {
|
||||
var type = typeof(T);
|
||||
|
||||
if (type == typeof(string)) {
|
||||
return (T)(object)value;
|
||||
}
|
||||
if (value == null ||
|
||||
"null".Equals(value, StringComparison.Ordinal) &&
|
||||
((!type.IsValueType || Nullable.GetUnderlyingType(type) != null))) {
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
if ("infinity".Equals(value, StringComparison.Ordinal)) {
|
||||
if (type == typeof(float) || type == typeof(float?)) return (T)(object)float.PositiveInfinity;
|
||||
if (type == typeof(double) || type == typeof(double?)) return (T)(object)double.PositiveInfinity;
|
||||
throw new NotSupportedException(String.Format("Infinity not supported for type {0}", type.Name));
|
||||
}
|
||||
if ("-infinity".Equals(value, StringComparison.Ordinal)) {
|
||||
if (type == typeof(float)) return (T)(object)float.NegativeInfinity;
|
||||
if (type == typeof(double)) return (T)(object)double.NegativeInfinity;
|
||||
throw new NotSupportedException(String.Format("Infinity not supported for type {0}", type.Name));
|
||||
}
|
||||
if (type == typeof(int) || type == typeof(int?)) {
|
||||
return (T)(object)int.Parse(value, CultureInfo.InvariantCulture);
|
||||
}
|
||||
if (type == typeof(bool) || type == typeof(bool?)) {
|
||||
return (T)(object)value.Equals("true", StringComparison.Ordinal);
|
||||
}
|
||||
if (type == typeof(DateTime) || type == typeof(DateTime?)) {
|
||||
return (T)(object)XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.Utc);
|
||||
}
|
||||
if (type == typeof(double) || type == typeof(double?)) {
|
||||
return (T)(object)double.Parse(value, CultureInfo.InvariantCulture);
|
||||
}
|
||||
if (type == typeof(float) || type == typeof(float?)) {
|
||||
return (T)(object)float.Parse(value, CultureInfo.InvariantCulture);
|
||||
}
|
||||
if (type == typeof(decimal) || type == typeof(decimal?)) {
|
||||
return (T)(object)decimal.Parse(value, CultureInfo.InvariantCulture);
|
||||
}
|
||||
throw new NotSupportedException(String.Format("Could not handle type {0}", type.Name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gives context to an XElement, enabling chained property operations.
|
||||
/// </summary>
|
||||
/// <typeparam name="TContext">The type of the context.</typeparam>
|
||||
/// <param name="el">The element.</param>
|
||||
/// <param name="context">The context.</param>
|
||||
/// <returns>The element with context.</returns>
|
||||
public static XElementWithContext<TContext> With<TContext>(this XElement el, TContext context) {
|
||||
return new XElementWithContext<TContext>(el, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A wrapper for XElement, with context, for strongly-typed manipulation
|
||||
/// of an XElement.
|
||||
/// </summary>
|
||||
/// <typeparam name="TContext">The type of the context.</typeparam>
|
||||
public class XElementWithContext<TContext> {
|
||||
public XElementWithContext(XElement element, TContext context) {
|
||||
Element = element;
|
||||
Context = context;
|
||||
}
|
||||
|
||||
public XElement Element { get; private set; }
|
||||
public TContext Context { get; private set; }
|
||||
|
||||
public static implicit operator XElement(XElementWithContext<TContext> elementWithContext) {
|
||||
return elementWithContext.Element;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the current context with a new one, enabling chained action on different objects.
|
||||
/// </summary>
|
||||
/// <typeparam name="TNewContext">The type of the new context.</typeparam>
|
||||
/// <param name="context">The new context.</param>
|
||||
/// <returns>A new XElementWithContext, that has the new context.</returns>
|
||||
public XElementWithContext<TNewContext> With<TNewContext>(TNewContext context) {
|
||||
return new XElementWithContext<TNewContext>(Element, context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of a context property as an attribute of the same name on the element.
|
||||
/// </summary>
|
||||
/// <typeparam name="TProperty">The type of the property.</typeparam>
|
||||
/// <param name="targetExpression">The property expression.</param>
|
||||
/// <returns>Itself</returns>
|
||||
public XElementWithContext<TContext> ToAttr<TProperty>(
|
||||
Expression<Func<TContext, TProperty>> targetExpression) {
|
||||
Element.ToAttr(Context, targetExpression);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an attribute on the element and sets the property of the same name on the context with its value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TProperty">The type of the property.</typeparam>
|
||||
/// <param name="targetExpression">The property expression.</param>
|
||||
/// <returns>Itself</returns>
|
||||
public XElementWithContext<TContext> FromAttr<TProperty>(
|
||||
Expression<Func<TContext, TProperty>> targetExpression) {
|
||||
Element.FromAttr(Context, targetExpression);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates an attribute from an expression.
|
||||
/// It's a nice strongly-typed way to read attributes.
|
||||
/// </summary>
|
||||
/// <typeparam name="TProperty">The type of the property.</typeparam>
|
||||
/// <param name="expression">The property expression.</param>
|
||||
/// <returns>The attribute, ready to be cast.</returns>
|
||||
public TProperty Attr<TProperty>(Expression<Func<TContext, TProperty>> expression) {
|
||||
var propertyInfo = ReflectionHelper<TContext>.GetPropertyInfo(expression);
|
||||
var name = propertyInfo.Name;
|
||||
return Element.Attr<TProperty>(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -159,6 +159,8 @@
|
||||
<Compile Include="ContentManagement\Aspects\ILocalizableAspect.cs" />
|
||||
<Compile Include="ContentManagement\ContentIdentity.cs" />
|
||||
<Compile Include="ContentManagement\DefaultHqlQuery.cs" />
|
||||
<Compile Include="ContentManagement\InfosetHelper.cs" />
|
||||
<Compile Include="ContentManagement\XmlHelper.cs" />
|
||||
<Compile Include="ContentManagement\Handlers\TemplateFilterForPart.cs" />
|
||||
<Compile Include="ContentManagement\Handlers\UpdateContentContext.cs" />
|
||||
<Compile Include="ContentManagement\IHqlExpression.cs" />
|
||||
@@ -577,6 +579,7 @@
|
||||
<Compile Include="Messaging\Services\IMessagingChannel.cs" />
|
||||
<Compile Include="IWorkContextAccessor.cs" />
|
||||
<Compile Include="Utility\Extensions\VirtualPathProviderExtensions.cs" />
|
||||
<Compile Include="Utility\ReflectionHelper.cs" />
|
||||
<Compile Include="Validation\PathValidation.cs" />
|
||||
<Compile Include="Wcf\OrchardDependencyInjectionServiceBehavior.cs" />
|
||||
<Compile Include="Wcf\OrchardInstanceContext.cs" />
|
||||
|
46
src/Orchard/Utility/ReflectionHelper.cs
Normal file
46
src/Orchard/Utility/ReflectionHelper.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Orchard.Utility {
|
||||
public class ReflectionHelper<T> {
|
||||
private static readonly ConcurrentDictionary<string, Delegate> _getterCache =
|
||||
new ConcurrentDictionary<string, Delegate>();
|
||||
|
||||
public delegate TProperty PropertyGetterDelegate<out TProperty>(T target);
|
||||
|
||||
/// <summary>
|
||||
/// Gets property info out of a Lambda.
|
||||
/// </summary>
|
||||
/// <typeparam name="TProperty">The return type of the Lambda.</typeparam>
|
||||
/// <param name="expression">The Lambda expression.</param>
|
||||
/// <returns>The property info.</returns>
|
||||
public static PropertyInfo GetPropertyInfo<TProperty>(Expression<Func<T, TProperty>> expression) {
|
||||
var memberExpression = expression.Body as MemberExpression;
|
||||
if (memberExpression == null) {
|
||||
throw new InvalidOperationException("Expression is not a member expression.");
|
||||
}
|
||||
var propertyInfo = memberExpression.Member as PropertyInfo;
|
||||
if (propertyInfo == null) {
|
||||
throw new InvalidOperationException("Expression is not for a property.");
|
||||
}
|
||||
return propertyInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a delegate from a property expression.
|
||||
/// </summary>
|
||||
/// <typeparam name="TProperty">The type of the property.</typeparam>
|
||||
/// <param name="targetExpression">The property expression.</param>
|
||||
/// <returns>The delegate.</returns>
|
||||
public static PropertyGetterDelegate<TProperty> GetGetter<TProperty>(
|
||||
Expression<Func<T, TProperty>> targetExpression) {
|
||||
|
||||
var propertyInfo = GetPropertyInfo(targetExpression);
|
||||
return (PropertyGetterDelegate<TProperty>)_getterCache
|
||||
.GetOrAdd(propertyInfo.Name,
|
||||
s => Delegate.CreateDelegate(typeof(PropertyGetterDelegate<TProperty>), propertyInfo.GetGetMethod()));
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user