From ea3d2f893f86ee385d8109bf79260f007ed1c6e9 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Mon, 1 Oct 2012 02:48:08 +0500 Subject: [PATCH] Added AsDynamic extension to IDocument. Makes DynamicDocument explicitly implement IDocument as well. Changes all ContentById methods, etc... back to returning just 'dynamic' Removes valueAlias from the .Field method of UmbracoHelper which didn't actually do anything removes altValueAlias from the .Field method of the UmbracoHelper which didn't actually do anything. --- src/Umbraco.Core/DocumentExtensions.cs | 8 + src/Umbraco.Core/Dynamics/DynamicDocument.cs | 171 +++++++++++++++--- .../DynamicDocument/DynamicDocumentTests.cs | 64 ++++++- .../Templates/TemplateUtilities.cs | 6 + src/Umbraco.Web/UmbracoHelper.cs | 76 +------- 5 files changed, 227 insertions(+), 98 deletions(-) diff --git a/src/Umbraco.Core/DocumentExtensions.cs b/src/Umbraco.Core/DocumentExtensions.cs index f0212ef1ed..4212dc49a1 100644 --- a/src/Umbraco.Core/DocumentExtensions.cs +++ b/src/Umbraco.Core/DocumentExtensions.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Data; using System.Linq; +using Umbraco.Core.Dynamics; using Umbraco.Core.Models; using umbraco.interfaces; @@ -9,6 +10,13 @@ namespace Umbraco.Core { public static class DocumentExtensions { + + public static dynamic AsDynamic(this IDocument doc) + { + var dd = new DynamicDocument(doc); + return dd.AsDynamic(); + } + /// /// Returns the property as the specified type, if the property is not found or does not convert /// then the default value of type T is returned. diff --git a/src/Umbraco.Core/Dynamics/DynamicDocument.cs b/src/Umbraco.Core/Dynamics/DynamicDocument.cs index 44e98fbc1e..39235b6150 100644 --- a/src/Umbraco.Core/Dynamics/DynamicDocument.cs +++ b/src/Umbraco.Core/Dynamics/DynamicDocument.cs @@ -17,7 +17,7 @@ namespace Umbraco.Core.Dynamics /// /// The dynamic model for views /// - public class DynamicDocument : DynamicObject + public class DynamicDocument : DynamicObject, IDocument { private readonly IDocument _document; private DynamicDocumentList _cachedChildren; @@ -25,6 +25,8 @@ namespace Umbraco.Core.Dynamics internal DynamicDocumentList OwnerList { get; set; } + #region Constructors + public DynamicDocument(IDocument node) { if (node == null) throw new ArgumentNullException("node"); @@ -41,14 +43,17 @@ namespace Umbraco.Core.Dynamics } private DynamicDocument() - { - } + { + } + + #endregion public dynamic AsDynamic() { return this; } + #region Traversal public DynamicDocument Up() { return DynamicDocumentWalker.Up(this); @@ -105,7 +110,8 @@ namespace Umbraco.Core.Dynamics public DynamicDocument Sibling(string nodeTypeAlias) { return DynamicDocumentWalker.Sibling(this, nodeTypeAlias); - } + } + #endregion public bool HasProperty(string name) { @@ -510,7 +516,6 @@ namespace Umbraco.Core.Dynamics }; } - /// /// Converts the currentValue to a correctly typed value based on known registered converters, then based on known standards. /// @@ -661,6 +666,7 @@ namespace Umbraco.Core.Dynamics // return null; //} + #region Ancestors, Descendants and Parent public DynamicDocument AncestorOrSelf() { //TODO: Why is this query like this?? @@ -843,7 +849,8 @@ namespace Umbraco.Core.Dynamics } return null; } - } + } + #endregion public int TemplateId { @@ -859,6 +866,7 @@ namespace Umbraco.Core.Dynamics { get { return _document.Name; } } + public bool Visible { get @@ -912,6 +920,7 @@ namespace Umbraco.Core.Dynamics { get { return _document.CreateDate; } } + public int Id { get { return _document.Id; } @@ -994,16 +1003,7 @@ namespace Umbraco.Core.Dynamics #endregion - public bool IsNull(string alias, bool recursive) - { - var prop = GetUserProperty(alias, recursive); - if (prop == null) return true; - return ((PropertyResult)prop).HasValue(); - } - public bool IsNull(string alias) - { - return IsNull(alias, false); - } + #region HasValue public bool HasValue(string alias) { return HasValue(alias, false); @@ -1029,7 +1029,9 @@ namespace Umbraco.Core.Dynamics public IHtmlString HasValue(string alias, bool recursive, string valueIfTrue) { return HasValue(alias, recursive) ? new HtmlString(valueIfTrue) : new HtmlString(string.Empty); - } + } + #endregion + public int Position() { return this.Index(); @@ -1060,6 +1062,18 @@ namespace Umbraco.Core.Dynamics throw new ArgumentNullException(string.Format("Node {0} has been orphaned and doesn't belong to a DynamicDocumentList", this.Id)); } } + + #region Is Helpers + public bool IsNull(string alias, bool recursive) + { + var prop = GetUserProperty(alias, recursive); + if (prop == null) return true; + return ((PropertyResult)prop).HasValue(); + } + public bool IsNull(string alias) + { + return IsNull(alias, false); + } public bool IsFirst() { return IsHelper(n => n.Index() == 0); @@ -1354,7 +1368,11 @@ namespace Umbraco.Core.Dynamics public HtmlString IsHelper(Func test, string valueIfTrue, string valueIfFalse) { return test(this) ? new HtmlString(valueIfTrue) : new HtmlString(valueIfFalse); - } + } + #endregion + + #region Where + public HtmlString Where(string predicate, string valueIfTrue) { return Where(predicate, valueIfTrue, string.Empty); @@ -1379,15 +1397,120 @@ namespace Umbraco.Core.Dynamics return true; } return false; + } + + #endregion + + //TODO: need a method to return a string value for a user property regardless of xml content or data type thus bypassing all of the PropertyEditorValueConverters + ///// + ///// Returns the value as as string regardless of xml content or data type + ///// + ///// + //public override string ToString() + //{ + // return base.ToString(); + //} + + #region Explicit IDocument implementation + IDocument IDocument.Parent + { + get { return _document.Parent; } } - /// - /// Returns the value as as string regardless of xml content or data type - /// - /// - public override string ToString() + int IDocument.Id { - return base.ToString(); + get { return _document.Id; } } + + int IDocument.TemplateId + { + get { return _document.TemplateId; } + } + + int IDocument.SortOrder + { + get { return _document.SortOrder; } + } + + string IDocument.Name + { + get { return _document.Name; } + } + + string IDocument.UrlName + { + get { return _document.UrlName; } + } + + string IDocument.DocumentTypeAlias + { + get { return _document.DocumentTypeAlias; } + } + + int IDocument.DocumentTypeId + { + get { return _document.DocumentTypeId; } + } + + string IDocument.WriterName + { + get { return _document.WriterName; } + } + + string IDocument.CreatorName + { + get { return _document.CreatorName; } + } + + int IDocument.WriterId + { + get { return _document.WriterId; } + } + + int IDocument.CreatorId + { + get { return _document.CreatorId; } + } + + string IDocument.Path + { + get { return _document.Path; } + } + + DateTime IDocument.CreateDate + { + get { return _document.CreateDate; } + } + + DateTime IDocument.UpdateDate + { + get { return _document.UpdateDate; } + } + + Guid IDocument.Version + { + get { return _document.Version; } + } + + int IDocument.Level + { + get { return _document.Level; } + } + + System.Collections.ObjectModel.Collection IDocument.Properties + { + get { return _document.Properties; } + } + + IEnumerable IDocument.Children + { + get { return _document.Children; } + } + + IDocumentProperty IDocument.GetProperty(string alias) + { + return _document.GetProperty(alias); + } + #endregion } } diff --git a/src/Umbraco.Tests/DynamicDocument/DynamicDocumentTests.cs b/src/Umbraco.Tests/DynamicDocument/DynamicDocumentTests.cs index b81372557e..447aa96d29 100644 --- a/src/Umbraco.Tests/DynamicDocument/DynamicDocumentTests.cs +++ b/src/Umbraco.Tests/DynamicDocument/DynamicDocumentTests.cs @@ -1,5 +1,7 @@ +using System.Linq; using NUnit.Framework; using Umbraco.Core.Dynamics; +using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Tests.Routing; using Umbraco.Web; @@ -34,9 +36,7 @@ namespace Umbraco.Tests.DynamicDocument PropertyEditorValueConvertersResolver.Reset(); } - - - protected override dynamic GetDynamicNode(int id) + internal Core.Dynamics.DynamicDocument GetNode(int id) { //var template = Template.MakeNew("test", new User(0)); //var ctx = GetUmbracoContext("/test", template.Id); @@ -46,7 +46,12 @@ namespace Umbraco.Tests.DynamicDocument Assert.IsNotNull(doc); var dynamicNode = new Core.Dynamics.DynamicDocument(doc); Assert.IsNotNull(dynamicNode); - return dynamicNode.AsDynamic(); + return dynamicNode; + } + + protected override dynamic GetDynamicNode(int id) + { + return GetNode(id).AsDynamic(); } [Test] @@ -60,5 +65,56 @@ namespace Umbraco.Tests.DynamicDocument Assert.AreEqual("Hello world!" + 123 + false, asDynamic.Children.DynamicDocumentListMultiParam("Hello world!", 123, false)); Assert.AreEqual("Hello world!" + 123 + false, asDynamic.Children.DynamicDocumentEnumerableMultiParam("Hello world!", 123, false)); } + + [Test] + public void Returns_IDocument_Object() + { + var helper = new TestHelper(GetNode(1173)); + var doc = helper.GetDoc(); + //HasProperty is only a prop on DynamicDocument, NOT IDocument + Assert.IsFalse(doc.GetType().GetProperties().Any(x => x.Name == "HasProperty")); + } + + [Test] + public void Returns_DynamicDocument_Object() + { + var helper = new TestHelper(GetNode(1173)); + var doc = helper.GetDocAsDynamic(); + //HasProperty is only a prop on DynamicDocument, NOT IDocument + Assert.IsTrue(doc.HasProperty("umbracoUrlAlias")); + } + + [Test] + public void Returns_DynamicDocument_Object_After_Casting() + { + var helper = new TestHelper(GetNode(1173)); + var doc = helper.GetDoc(); + var ddoc = (dynamic) doc; + //HasProperty is only a prop on DynamicDocument, NOT IDocument + Assert.IsTrue(ddoc.HasProperty("umbracoUrlAlias")); + } + + /// + /// Test class to mimic UmbracoHelper when returning docs + /// + public class TestHelper + { + private readonly Core.Dynamics.DynamicDocument _doc; + + public TestHelper(Core.Dynamics.DynamicDocument doc) + { + _doc = doc; + } + + public IDocument GetDoc() + { + return _doc; + } + + public dynamic GetDocAsDynamic() + { + return _doc.AsDynamic(); + } + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Templates/TemplateUtilities.cs b/src/Umbraco.Web/Templates/TemplateUtilities.cs index cac0b541c2..c9062e4b58 100644 --- a/src/Umbraco.Web/Templates/TemplateUtilities.cs +++ b/src/Umbraco.Web/Templates/TemplateUtilities.cs @@ -23,6 +23,12 @@ namespace Umbraco.Web.Templates /// public static string ParseInternalLinks(string text) { + //don't attempt to proceed without a context as we cannot lookup urls without one + if (UmbracoContext.Current == null) + { + return text; + } + var niceUrlsProvider = UmbracoContext.Current.NiceUrlProvider; // Parse internal links diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index d9af4928f7..de3fb61c5e 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -119,9 +119,7 @@ namespace Umbraco.Web /// Renders an field to the template /// /// - /// /// - /// /// /// /// @@ -132,8 +130,8 @@ namespace Umbraco.Web /// /// /// - public IHtmlString Field(string fieldAlias, string valueAlias = "", - string altFieldAlias = "", string altValueAlias = "", string altText = "", string insertBefore = "", string insertAfter = "", + public IHtmlString Field(string fieldAlias, + string altFieldAlias = "", string altText = "", string insertBefore = "", string insertAfter = "", bool recursive = false, bool convertLineBreaks = false, bool removeParagraphTags = false, RenderFieldCaseType casing = RenderFieldCaseType.Unchanged, RenderFieldEncodingType encoding = RenderFieldEncodingType.Unchanged, @@ -143,7 +141,7 @@ namespace Umbraco.Web { throw new InvalidOperationException("Cannot call this method when not rendering a front-end document"); } - return Field(_currentPage, fieldAlias, valueAlias, altFieldAlias, altValueAlias, + return Field(_currentPage, fieldAlias, altFieldAlias, altText, insertBefore, insertAfter, recursive, convertLineBreaks, removeParagraphTags, casing, encoding, formatString); } @@ -153,9 +151,7 @@ namespace Umbraco.Web /// /// /// - /// /// - /// /// /// /// @@ -166,8 +162,8 @@ namespace Umbraco.Web /// /// /// - public IHtmlString Field(IDocument currentPage, string fieldAlias, string valueAlias = "", - string altFieldAlias = "", string altValueAlias = "", string altText = "", string insertBefore = "", string insertAfter = "", + public IHtmlString Field(IDocument currentPage, string fieldAlias, + string altFieldAlias = "", string altText = "", string insertBefore = "", string insertAfter = "", bool recursive = false, bool convertLineBreaks = false, bool removeParagraphTags = false, RenderFieldCaseType casing = RenderFieldCaseType.Unchanged, RenderFieldEncodingType encoding = RenderFieldEncodingType.Unchanged, @@ -334,26 +330,7 @@ namespace Umbraco.Web #region Content - public IDocument GetContentById(int id) - { - return GetDocumentById(id, PublishedContentStoreResolver.Current.PublishedContentStore); - } - - public IDocument GetContentById(string id) - { - return GetDocumentById(id, PublishedContentStoreResolver.Current.PublishedContentStore); - } - - public IEnumerable GetContentByIds(params int[] ids) - { - return GetDocumentByIds(PublishedContentStoreResolver.Current.PublishedContentStore, ids); - } - - public IEnumerable GetContentByIds(params string[] ids) - { - return GetDocumentByIds(PublishedContentStoreResolver.Current.PublishedContentStore, ids); - } - + public dynamic ContentById(int id) { return DocumentById(id, PublishedContentStoreResolver.Current.PublishedContentStore); @@ -378,25 +355,6 @@ namespace Umbraco.Web #region Media - public IDocument GetMediaById(int id) - { - return GetDocumentById(id, PublishedMediaStoreResolver.Current.PublishedMediaStore); - } - - public IDocument GetMediaById(string id) - { - return GetDocumentById(id, PublishedMediaStoreResolver.Current.PublishedMediaStore); - } - - public IEnumerable GetMediaByIds(params int[] ids) - { - return GetDocumentByIds(PublishedMediaStoreResolver.Current.PublishedMediaStore, ids); - } - - public IEnumerable GetMediaByIds(params string[] ids) - { - return GetDocumentByIds(PublishedMediaStoreResolver.Current.PublishedMediaStore, ids); - } public dynamic MediaById(int id) { @@ -422,28 +380,6 @@ namespace Umbraco.Web #region Used by Content/Media - private IDocument GetDocumentById(int id, IPublishedStore store) - { - return store.GetDocumentById(UmbracoContext.Current, id); - } - - private IDocument GetDocumentById(string id, IPublishedStore store) - { - int docId; - return int.TryParse(id, out docId) - ? DocumentById(docId, store) - : null; - } - - private IEnumerable GetDocumentByIds(IPublishedStore store, params int[] ids) - { - return ids.Select(eachId => GetDocumentById(eachId, store)); - } - - private IEnumerable GetDocumentByIds(IPublishedStore store, params string[] ids) - { - return ids.Select(eachId => GetDocumentById(eachId, store)); - } private dynamic DocumentById(int id, IPublishedStore store) {