From a0caab410ec441d173856411291c09ec536c19ec Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 19 Jul 2016 16:13:46 +0200 Subject: [PATCH] U4-8720 - add dynamic support, UmbracoHelper methods --- .../IDynamicPublishedContentQuery.cs | 10 +- .../ITypedPublishedContentQuery.cs | 2 +- src/Umbraco.Web/PublishedContentQuery.cs | 33 ++- src/Umbraco.Web/UmbracoHelper.cs | 220 +++++++++++++----- 4 files changed, 207 insertions(+), 58 deletions(-) diff --git a/src/Umbraco.Web/IDynamicPublishedContentQuery.cs b/src/Umbraco.Web/IDynamicPublishedContentQuery.cs index 051ba07ff6..7c95fd7e2e 100644 --- a/src/Umbraco.Web/IDynamicPublishedContentQuery.cs +++ b/src/Umbraco.Web/IDynamicPublishedContentQuery.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Xml.XPath; using Umbraco.Core.Xml; @@ -10,15 +11,22 @@ namespace Umbraco.Web public interface IDynamicPublishedContentQuery { dynamic Content(int id); + dynamic Content(Guid id); dynamic ContentSingleAtXPath(string xpath, params XPathVariable[] vars); dynamic ContentSingleAtXPath(XPathExpression xpath, params XPathVariable[] vars); dynamic Content(IEnumerable ids); + dynamic Content(IEnumerable ids); dynamic ContentAtXPath(string xpath, params XPathVariable[] vars); dynamic ContentAtXPath(XPathExpression xpath, params XPathVariable[] vars); dynamic ContentAtRoot(); - + + // note: we CANNOT implement Media by Guid in v7 without break-changing IPublishedCache, + // since we don't support XPath navigation of the media tree. + dynamic Media(int id); + //dynamic Media(Guid id); dynamic Media(IEnumerable ids); + //dynamic Media(IEnumerable ids); dynamic MediaAtRoot(); /// diff --git a/src/Umbraco.Web/ITypedPublishedContentQuery.cs b/src/Umbraco.Web/ITypedPublishedContentQuery.cs index 63bb2dabe3..7a2be964f7 100644 --- a/src/Umbraco.Web/ITypedPublishedContentQuery.cs +++ b/src/Umbraco.Web/ITypedPublishedContentQuery.cs @@ -20,7 +20,7 @@ namespace Umbraco.Web IEnumerable TypedContentAtXPath(XPathExpression xpath, params XPathVariable[] vars); IEnumerable TypedContentAtRoot(); - // note: we CANNOT implement TypedMedia in v7 without break-changing IPublishedCache, + // note: we CANNOT implement TypedMedia by Guid in v7 without break-changing IPublishedCache, // since we don't support XPath navigation of the media tree. IPublishedContent TypedMedia(int id); diff --git a/src/Umbraco.Web/PublishedContentQuery.cs b/src/Umbraco.Web/PublishedContentQuery.cs index 4966310c0f..f0f2461ad8 100644 --- a/src/Umbraco.Web/PublishedContentQuery.cs +++ b/src/Umbraco.Web/PublishedContentQuery.cs @@ -113,7 +113,14 @@ namespace Umbraco.Web ? DocumentById(id, _contentCache, DynamicNull.Null) : _dynamicContentQuery.Content(id); } - + + public dynamic Content(Guid id) + { + return _dynamicContentQuery == null + ? DocumentById(id, _contentCache, DynamicNull.Null) + : _dynamicContentQuery.Content(id); + } + public dynamic ContentSingleAtXPath(string xpath, params XPathVariable[] vars) { return _dynamicContentQuery == null @@ -135,6 +142,13 @@ namespace Umbraco.Web : _dynamicContentQuery.Content(ids); } + public dynamic Content(IEnumerable ids) + { + return _dynamicContentQuery == null + ? DocumentByIds(_contentCache, ids.ToArray()) + : _dynamicContentQuery.Content(ids); + } + public dynamic ContentAtXPath(string xpath, params XPathVariable[] vars) { return _dynamicContentQuery == null @@ -270,6 +284,14 @@ namespace Umbraco.Web : new DynamicPublishedContent(doc).AsDynamic(); } + private dynamic DocumentById(Guid id, ContextualPublishedCache cache, object ifNotFound) + { + var doc = TypedDocumentById(id, cache); + return doc == null + ? ifNotFound + : new DynamicPublishedContent(doc).AsDynamic(); + } + private dynamic DocumentByXPath(string xpath, XPathVariable[] vars, ContextualPublishedCache cache, object ifNotFound) { var doc = cache.GetSingleByXPath(xpath, vars); @@ -295,6 +317,15 @@ namespace Umbraco.Web return new DynamicPublishedContentList(nodes); } + private dynamic DocumentByIds(ContextualPublishedCache cache, IEnumerable ids) + { + var dNull = DynamicNull.Null; + var nodes = ids.Select(eachId => DocumentById(eachId, cache, dNull)) + .Where(x => TypeHelper.IsTypeAssignableFrom(x) == false) + .Cast(); + return new DynamicPublishedContentList(nodes); + } + private dynamic DocumentsByXPath(string xpath, XPathVariable[] vars, ContextualPublishedCache cache) { return new DynamicPublishedContentList( diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index 165b81daba..587c821daa 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -15,6 +15,7 @@ using Umbraco.Web.Routing; using Umbraco.Web.Security; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Web.Mvc; using System.Web.Routing; using Umbraco.Core.Cache; @@ -561,21 +562,35 @@ namespace Umbraco.Web #region Content public IPublishedContent TypedContent(object id) - { - int intId; - return ConvertIdObjectToInt(id, out intId) ? ContentQuery.TypedContent(intId) : null; + { + return TypedContentForObject(id); } - public IPublishedContent TypedContent(int id) + private IPublishedContent TypedContentForObject(object id) + { + int intId; + if (ConvertIdObjectToInt(id, out intId)) + return ContentQuery.TypedContent(intId); + Guid guidId; + if (ConvertIdObjectToGuid(id, out guidId)) + return ContentQuery.TypedContent(guidId); + return null; + } + + public IPublishedContent TypedContent(int id) { return ContentQuery.TypedContent(id); } + public IPublishedContent TypedContent(Guid id) + { + return ContentQuery.TypedContent(id); + } + public IPublishedContent TypedContent(string id) { - int intId; - return ConvertIdObjectToInt(id, out intId) ? ContentQuery.TypedContent(intId) : null; - } + return TypedContentForObject(id); + } public IPublishedContent TypedContentSingleAtXPath(string xpath, params XPathVariable[] vars) { @@ -584,9 +599,21 @@ namespace Umbraco.Web public IEnumerable TypedContent(params object[] ids) { - return ContentQuery.TypedContent(ConvertIdsObjectToInts(ids)); + return TypedContentForObjects(ids); } + private IEnumerable TypedContentForObjects(IEnumerable ids) + { + var idsA = ids.ToArray(); + IEnumerable intIds; + if (ConvertIdsObjectToInts(idsA, out intIds)) + return ContentQuery.TypedContent(intIds); + IEnumerable guidIds; + if (ConvertIdsObjectToGuids(idsA, out guidIds)) + return ContentQuery.TypedContent(guidIds); + return Enumerable.Empty(); + } + /// /// Gets the contents corresponding to the identifiers. /// @@ -598,6 +625,11 @@ namespace Umbraco.Web return ContentQuery.TypedContent(ids); } + public IEnumerable TypedContent(params Guid[] ids) + { + return ContentQuery.TypedContent(ids); + } + /// /// Gets the contents corresponding to the identifiers. /// @@ -605,8 +637,8 @@ namespace Umbraco.Web /// The existing contents corresponding to the identifiers. /// If an identifier does not match an existing content, it will be missing in the returned value. public IEnumerable TypedContent(params string[] ids) - { - return ContentQuery.TypedContent(ConvertIdsObjectToInts(ids)); + { + return TypedContentForObjects(ids); } /// @@ -616,8 +648,8 @@ namespace Umbraco.Web /// The existing contents corresponding to the identifiers. /// If an identifier does not match an existing content, it will be missing in the returned value. public IEnumerable TypedContent(IEnumerable ids) - { - return ContentQuery.TypedContent(ConvertIdsObjectToInts(ids)); + { + return TypedContentForObjects(ids); } /// @@ -628,7 +660,7 @@ namespace Umbraco.Web /// If an identifier does not match an existing content, it will be missing in the returned value. public IEnumerable TypedContent(IEnumerable ids) { - return ContentQuery.TypedContent(ConvertIdsObjectToInts(ids)); + return TypedContentForObjects(ids); } /// @@ -659,20 +691,29 @@ namespace Umbraco.Web public dynamic Content(object id) { - int intId; - return ConvertIdObjectToInt(id, out intId) ? ContentQuery.Content(intId) : DynamicNull.Null; + return ContentForObject(id); } - public dynamic Content(int id) + private dynamic ContentForObject(object id) + { + int intId; + if (ConvertIdObjectToInt(id, out intId)) + return ContentQuery.Content(intId); + Guid guidId; + if (ConvertIdObjectToGuid(id, out guidId)) + return ContentQuery.Content(guidId); + return DynamicNull.Null; + } + + public dynamic Content(int id) { return ContentQuery.Content(id); } public dynamic Content(string id) { - int intId; - return ConvertIdObjectToInt(id, out intId) ? ContentQuery.Content(intId) : DynamicNull.Null; - } + return ContentForObject(id); + } public dynamic ContentSingleAtXPath(string xpath, params XPathVariable[] vars) { @@ -691,9 +732,21 @@ namespace Umbraco.Web /// The existing contents corresponding to the identifiers. /// If an identifier does not match an existing content, it will be missing in the returned value. public dynamic Content(params object[] ids) - { - return ContentQuery.Content(ConvertIdsObjectToInts(ids)); - } + { + return ContentForObjects(ids); + } + + private dynamic ContentForObjects(IEnumerable ids) + { + var idsA = ids.ToArray(); + IEnumerable intIds; + if (ConvertIdsObjectToInts(idsA, out intIds)) + return ContentQuery.Content(intIds); + IEnumerable guidIds; + if (ConvertIdsObjectToGuids(idsA, out guidIds)) + return ContentQuery.Content(guidIds); + return Enumerable.Empty(); + } /// /// Gets the contents corresponding to the identifiers. @@ -714,8 +767,8 @@ namespace Umbraco.Web /// If an identifier does not match an existing content, it will be missing in the returned value. public dynamic Content(params string[] ids) { - return ContentQuery.Content(ConvertIdsObjectToInts(ids)); - } + return ContentForObjects(ids); + } /// /// Gets the contents corresponding to the identifiers. @@ -725,8 +778,8 @@ namespace Umbraco.Web /// If an identifier does not match an existing content, it will be missing in the returned value. public dynamic Content(IEnumerable ids) { - return ContentQuery.Content(ConvertIdsObjectToInts(ids)); - } + return ContentForObjects(ids); + } /// /// Gets the contents corresponding to the identifiers. @@ -747,8 +800,8 @@ namespace Umbraco.Web /// If an identifier does not match an existing content, it will be missing in the returned value. public dynamic Content(IEnumerable ids) { - return ContentQuery.Content(ConvertIdsObjectToInts(ids)); - } + return ContentForObjects(ids); + } public dynamic ContentAtXPath(string xpath, params XPathVariable[] vars) { @@ -765,35 +818,68 @@ namespace Umbraco.Web return ContentQuery.ContentAtRoot(); } - private bool ConvertIdObjectToInt(object id, out int intId) + private static bool ConvertIdObjectToInt(object id, out int intId) { var s = id as string; if (s != null) { return int.TryParse(s, out intId); - } - + } if (id is int) { intId = (int) id; return true; } - - throw new InvalidOperationException("The value of parameter 'id' must be either a string or an integer"); + intId = default(int); + return false; } - private IEnumerable ConvertIdsObjectToInts(IEnumerable ids) + private static bool ConvertIdObjectToGuid(object id, out Guid guidId) + { + var s = id as string; + if (s != null) + { + return Guid.TryParse(s, out guidId); + } + if (id is Guid) + { + guidId = (Guid) id; + return true; + } + guidId = default(Guid); + return false; + } + + private static bool ConvertIdsObjectToInts(IEnumerable ids, out IEnumerable intIds) { var list = new List(); + intIds = null; foreach (var id in ids) { int intId; if (ConvertIdObjectToInt(id, out intId)) - { list.Add(intId); - } + else + return false; // if one of them is not an int, fail } - return list; + intIds = list; + return true; + } + + private static bool ConvertIdsObjectToGuids(IEnumerable ids, out IEnumerable guidIds) + { + var list = new List(); + guidIds = null; + foreach (var id in ids) + { + Guid guidId; + if (ConvertIdObjectToGuid(id, out guidId)) + list.Add(guidId); + else + return false; // if one of them is not a guid, fail + } + guidIds = list; + return true; } #endregion @@ -834,9 +920,21 @@ namespace Umbraco.Web /// The existing medias corresponding to the identifiers. /// If an identifier does not match an existing media, it will be missing in the returned value. public IEnumerable TypedMedia(params object[] ids) - { - return ContentQuery.TypedMedia(ConvertIdsObjectToInts(ids)); - } + { + return TypedMediaForObjects(ids); + } + + private IEnumerable TypedMediaForObjects(IEnumerable ids) + { + var idsA = ids.ToArray(); + IEnumerable intIds; + if (ConvertIdsObjectToInts(idsA, out intIds)) + return ContentQuery.TypedMedia(intIds); + //IEnumerable guidIds; + //if (ConvertIdsObjectToGuids(idsA, out guidIds)) + // return ContentQuery.TypedMedia(guidIds); + return Enumerable.Empty(); + } /// /// Gets the medias corresponding to the identifiers. @@ -857,8 +955,8 @@ namespace Umbraco.Web /// If an identifier does not match an existing media, it will be missing in the returned value. public IEnumerable TypedMedia(params string[] ids) { - return ContentQuery.TypedMedia(ConvertIdsObjectToInts(ids)); - } + return TypedMediaForObjects(ids); + } /// /// Gets the medias corresponding to the identifiers. @@ -868,8 +966,8 @@ namespace Umbraco.Web /// If an identifier does not match an existing media, it will be missing in the returned value. public IEnumerable TypedMedia(IEnumerable ids) { - return ContentQuery.TypedMedia(ConvertIdsObjectToInts(ids)); - } + return TypedMediaForObjects(ids); + } /// /// Gets the medias corresponding to the identifiers. @@ -890,8 +988,8 @@ namespace Umbraco.Web /// If an identifier does not match an existing media, it will be missing in the returned value. public IEnumerable TypedMedia(IEnumerable ids) { - return ContentQuery.TypedMedia(ConvertIdsObjectToInts(ids)); - } + return TypedMediaForObjects(ids); + } public IEnumerable TypedMediaAtRoot() { @@ -922,9 +1020,21 @@ namespace Umbraco.Web /// The existing medias corresponding to the identifiers. /// If an identifier does not match an existing media, it will be missing in the returned value. public dynamic Media(params object[] ids) - { - return ContentQuery.Media(ConvertIdsObjectToInts(ids)); - } + { + return MediaForObjects(ids); + } + + private dynamic MediaForObjects(IEnumerable ids) + { + var idsA = ids.ToArray(); + IEnumerable intIds; + if (ConvertIdsObjectToInts(idsA, out intIds)) + return ContentQuery.Media(intIds); + //IEnumerable guidIds; + //if (ConvertIdsObjectToGuids(idsA, out guidIds)) + // return ContentQuery.Media(guidIds); + return Enumerable.Empty(); + } /// /// Gets the medias corresponding to the identifiers. @@ -944,8 +1054,8 @@ namespace Umbraco.Web /// The existing medias corresponding to the identifiers. /// If an identifier does not match an existing media, it will be missing in the returned value. public dynamic Media(params string[] ids) - { - return ContentQuery.Media(ConvertIdsObjectToInts(ids)); + { + return MediaForObjects(ids); } /// @@ -956,8 +1066,8 @@ namespace Umbraco.Web /// If an identifier does not match an existing media, it will be missing in the returned value. public dynamic Media(IEnumerable ids) { - return ContentQuery.Media(ConvertIdsObjectToInts(ids)); - } + return MediaForObjects(ids); + } /// /// Gets the medias corresponding to the identifiers. @@ -978,8 +1088,8 @@ namespace Umbraco.Web /// If an identifier does not match an existing media, it will be missing in the returned value. public dynamic Media(IEnumerable ids) { - return ContentQuery.Media(ConvertIdsObjectToInts(ids)); - } + return MediaForObjects(ids); + } public dynamic MediaAtRoot() {