From 1be74589f2d3869f504f13a07ad6ce36f9664752 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sat, 21 Jul 2018 15:58:49 +0200 Subject: [PATCH] Combined fallback parameters into an array that defines methods and priority to be used. --- src/Umbraco.Core/Constants-Content.cs | 22 +++ .../IPublishedValueFallback.cs | 10 +- .../NoopPublishedValueFallback.cs | 4 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../PublishedContentLanuageVariantTests.cs | 102 ++++++++++- .../PublishedContent/PublishedContentTests.cs | 4 +- .../SolidPublishedSnapshot.cs | 22 ++- .../PublishedValueFallback.cs | 78 ++++++--- .../PublishedValueLanguageFallback.cs | 163 ++---------------- src/Umbraco.Web/PublishedContentExtensions.cs | 39 ++--- src/Umbraco.Web/umbraco.presentation/item.cs | 4 +- 11 files changed, 226 insertions(+), 223 deletions(-) create mode 100644 src/Umbraco.Core/Constants-Content.cs diff --git a/src/Umbraco.Core/Constants-Content.cs b/src/Umbraco.Core/Constants-Content.cs new file mode 100644 index 0000000000..4b8c383e6f --- /dev/null +++ b/src/Umbraco.Core/Constants-Content.cs @@ -0,0 +1,22 @@ +namespace Umbraco.Core +{ + public static partial class Constants + { + /// + /// Defines content retrieval related constants + /// + public static class Content + { + /// + /// Defines core supported content fall-back options when retrieving content property values. + /// Defined as constants rather than enum to allow solution or package defined fall-back methods. + /// + public static class FallbackMethods + { + public const int None = 0; + public const int RecursiveTree = 1; + public const int FallbackLanguage = 2; + } + } + } +} diff --git a/src/Umbraco.Core/Models/PublishedContent/IPublishedValueFallback.cs b/src/Umbraco.Core/Models/PublishedContent/IPublishedValueFallback.cs index d9d9c0c298..7a7b67a2d1 100644 --- a/src/Umbraco.Core/Models/PublishedContent/IPublishedValueFallback.cs +++ b/src/Umbraco.Core/Models/PublishedContent/IPublishedValueFallback.cs @@ -2,12 +2,6 @@ namespace Umbraco.Core.Models.PublishedContent { - public enum PublishedValueFallbackPriority - { - RecursiveTree, - FallbackLanguage - } - /// /// Provides a fallback strategy for getting values. /// @@ -36,8 +30,8 @@ namespace Umbraco.Core.Models.PublishedContent T GetValue(IPublishedElement content, string alias, string culture, string segment, T defaultValue, ICollection visitedLanguages); - object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, bool recurse, PublishedValueFallbackPriority fallbackPriority, ICollection visitedLanguages); + object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages); - T GetValue(IPublishedContent content, string alias, string culture, string segment, T defaultValue, bool recurse, PublishedValueFallbackPriority fallbackPriority, ICollection visitedLanguages); + T GetValue(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages); } } diff --git a/src/Umbraco.Core/Models/PublishedContent/NoopPublishedValueFallback.cs b/src/Umbraco.Core/Models/PublishedContent/NoopPublishedValueFallback.cs index a7de0709e6..a8d55176a3 100644 --- a/src/Umbraco.Core/Models/PublishedContent/NoopPublishedValueFallback.cs +++ b/src/Umbraco.Core/Models/PublishedContent/NoopPublishedValueFallback.cs @@ -23,9 +23,9 @@ namespace Umbraco.Core.Models.PublishedContent public T GetValue(IPublishedElement content, string alias, string culture, string segment, T defaultValue, ICollection visitedLanguages) => defaultValue; /// - public object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, bool recurse, PublishedValueFallbackPriority fallbackPriority, ICollection visitedLanguages) => defaultValue; + public object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages) => defaultValue; /// - public T GetValue(IPublishedContent content, string alias, string culture, string segment, T defaultValue, bool recurse, PublishedValueFallbackPriority fallbackPriority, ICollection visitedLanguages) => defaultValue; + public T GetValue(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages) => defaultValue; } } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 67028568eb..0a24cc5286 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -286,6 +286,7 @@ + diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentLanuageVariantTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentLanuageVariantTests.cs index 17ce032005..7ee2e11209 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentLanuageVariantTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentLanuageVariantTests.cs @@ -45,7 +45,8 @@ namespace Umbraco.Tests.PublishedContent new Language("de") { Id = 5, CultureName = "German" }, new Language("da") { Id = 6, CultureName = "Danish", FallbackLanguageId = 8 }, new Language("sv") { Id = 7, CultureName = "Swedish", FallbackLanguageId = 6 }, - new Language("no") { Id = 8, CultureName = "Norweigan", FallbackLanguageId = 7 } + new Language("no") { Id = 8, CultureName = "Norweigan", FallbackLanguageId = 7 }, + new Language("nl") { Id = 9, CultureName = "Dutch", FallbackLanguageId = 1 } }; var localizationService = Mock.Get(serviceContext.LocalizationService); @@ -68,12 +69,28 @@ namespace Umbraco.Tests.PublishedContent { Alias = "welcomeText", }; - prop1.SetSourceValue("en-US", "Welcome"); - prop1.SetValue("en-US", "Welcome"); + prop1.SetSourceValue("en-US", "Welcome", true); + prop1.SetValue("en-US", "Welcome", true); prop1.SetSourceValue("de", "Willkommen"); prop1.SetValue("de", "Willkommen"); + prop1.SetSourceValue("nl", "Welkom"); + prop1.SetValue("nl", "Welkom"); - cache.Add(new SolidPublishedContent(contentType1) + var prop2 = new SolidPublishedPropertyWithLanguageVariants + { + Alias = "welcomeText2", + }; + prop2.SetSourceValue("en-US", "Welcome", true); + prop2.SetValue("en-US", "Welcome", true); + + var prop3 = new SolidPublishedPropertyWithLanguageVariants + { + Alias = "welcomeText", + }; + prop3.SetSourceValue("en-US", "Welcome", true); + prop3.SetValue("en-US", "Welcome", true); + + var item1 = new SolidPublishedContent(contentType1) { Id = 1, SortOrder = 0, @@ -83,12 +100,35 @@ namespace Umbraco.Tests.PublishedContent Level = 1, Url = "/content-1", ParentId = -1, + ChildIds = new[] { 2 }, + Properties = new Collection + { + prop1, prop2 + } + }; + + var item2 = new SolidPublishedContent(contentType1) + { + Id = 2, + SortOrder = 0, + Name = "Content 2", + UrlSegment = "content-2", + Path = "/1/2", + Level = 2, + Url = "/content-1/content-2", + ParentId = 1, ChildIds = new int[] { }, Properties = new Collection { - prop1 + prop3 } - }); + }; + + item1.Children = new List { item2 }; + item2.Parent = item1; + + cache.Add(item1); + cache.Add(item2); } [Test] @@ -116,10 +156,18 @@ namespace Umbraco.Tests.PublishedContent } [Test] - public void Can_Get_Content_For_Unpopulated_Requested_Language_With_Fallback() + public void Do_Not_Get_Content_For_Unpopulated_Requested_Language_With_Fallback_Unless_Requested() { var content = UmbracoContext.Current.ContentCache.GetAtRoot().First(); var value = content.Value("welcomeText", "es"); + Assert.IsNull(value); + } + + [Test] + public void Can_Get_Content_For_Unpopulated_Requested_Language_With_Fallback() + { + var content = UmbracoContext.Current.ContentCache.GetAtRoot().First(); + var value = content.Value("welcomeText", "es", fallbackMethods: new[] { Core.Constants.Content.FallbackMethods.FallbackLanguage }); Assert.AreEqual("Welcome", value); } @@ -127,7 +175,7 @@ namespace Umbraco.Tests.PublishedContent public void Can_Get_Content_For_Unpopulated_Requested_Language_With_Fallback_Over_Two_Levels() { var content = UmbracoContext.Current.ContentCache.GetAtRoot().First(); - var value = content.Value("welcomeText", "it"); + var value = content.Value("welcomeText", "it", fallbackMethods: new[] { Core.Constants.Content.FallbackMethods.FallbackLanguage }); Assert.AreEqual("Welcome", value); } @@ -135,8 +183,44 @@ namespace Umbraco.Tests.PublishedContent public void Do_Not_GetContent_For_Unpopulated_Requested_Language_With_Fallback_Over_That_Loops() { var content = UmbracoContext.Current.ContentCache.GetAtRoot().First(); - var value = content.Value("welcomeText", "no"); + var value = content.Value("welcomeText", "no", fallbackMethods: new[] { Core.Constants.Content.FallbackMethods.FallbackLanguage }); Assert.IsNull(value); } + + [Test] + public void Do_Not_Get_Content_Recursively_Unless_Requested() + { + var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First(); + var value = content.Value("welcomeText2"); + Assert.IsNull(value); + } + + [Test] + public void Can_Get_Content_Recursively() + { + var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First(); + var value = content.Value("welcomeText2", fallbackMethods: new[] { Core.Constants.Content.FallbackMethods.RecursiveTree }); + Assert.AreEqual("Welcome", value); + } + + [Test] + public void Can_Get_Content_With_Recursive_Priority() + { + var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First(); + var value = content.Value("welcomeText", "nl", fallbackMethods: new[] { Core.Constants.Content.FallbackMethods.RecursiveTree, Core.Constants.Content.FallbackMethods.FallbackLanguage }); + + // No Dutch value is directly assigned. Check has fallen back to Dutch value from parent. + Assert.AreEqual("Welkom", value); + } + + [Test] + public void Can_Get_Content_With_Fallback_Language_Priority() + { + var content = UmbracoContext.Current.ContentCache.GetAtRoot().First().Children.First(); + var value = content.Value("welcomeText", "nl", fallbackMethods: new[] { Core.Constants.Content.FallbackMethods.FallbackLanguage, Core.Constants.Content.FallbackMethods.RecursiveTree }); + + // No Dutch value is directly assigned. Check has fallen back to English value from language variant. + Assert.AreEqual("Welcome", value); + } } } diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index a09cf6d4ad..330711a6ba 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -326,8 +326,8 @@ namespace Umbraco.Tests.PublishedContent public void Get_Property_Value_Recursive() { var doc = GetNode(1174); - var rVal = doc.Value("testRecursive", recurse: true); - var nullVal = doc.Value("DoNotFindThis", recurse: true); + var rVal = doc.Value("testRecursive", fallbackMethods: new[] { Constants.Content.FallbackMethods.RecursiveTree } ); + var nullVal = doc.Value("DoNotFindThis", fallbackMethods: new[] { Constants.Content.FallbackMethods.RecursiveTree }); Assert.AreEqual("This is the recursive val", rVal); Assert.AreEqual(null, nullVal); } diff --git a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs index 33e315ebec..cbf7f3189d 100644 --- a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs +++ b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs @@ -248,7 +248,7 @@ namespace Umbraco.Tests.PublishedContent #endregion } - class SolidPublishedProperty : IPublishedProperty + internal class SolidPublishedProperty : IPublishedProperty { public PublishedPropertyType PropertyType { get; set; } public string Alias { get; set; } @@ -309,19 +309,33 @@ namespace Umbraco.Tests.PublishedContent return _solidSourceValues.ContainsKey(culture); } - public void SetSourceValue(string culture, object value) + public void SetSourceValue(string culture, object value, bool defaultValue = false) { _solidSourceValues.Add(culture, value); + if (defaultValue) + { + SolidSourceValue = value; + SolidHasValue = true; + } } - public void SetValue(string culture, object value) + public void SetValue(string culture, object value, bool defaultValue = false) { _solidValues.Add(culture, value); + if (defaultValue) + { + SolidValue = value; + SolidHasValue = true; + } } - public void SetXPathValue(string culture, object value) + public void SetXPathValue(string culture, object value, bool defaultValue = false) { _solidXPathValues.Add(culture, value); + if (defaultValue) + { + SolidXPathValue = value; + } } } diff --git a/src/Umbraco.Web/Models/PublishedContent/PublishedValueFallback.cs b/src/Umbraco.Web/Models/PublishedContent/PublishedValueFallback.cs index 86823767fd..85b10be480 100644 --- a/src/Umbraco.Web/Models/PublishedContent/PublishedValueFallback.cs +++ b/src/Umbraco.Web/Models/PublishedContent/PublishedValueFallback.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Web.Models.PublishedContent @@ -8,54 +9,79 @@ namespace Umbraco.Web.Models.PublishedContent /// public class PublishedValueFallback : IPublishedValueFallback { - // this is our default implementation // kinda reproducing what was available in v7 /// - public virtual object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue, ICollection visitedLanguages) + public object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue, ICollection visitedLanguages) { // no fallback here return defaultValue; } /// - public virtual T GetValue(IPublishedProperty property, string culture, string segment, T defaultValue, ICollection visitedLanguages) + public T GetValue(IPublishedProperty property, string culture, string segment, T defaultValue, ICollection visitedLanguages) { // no fallback here return defaultValue; } /// - public virtual object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue, ICollection visitedLanguages) + public object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue, ICollection visitedLanguages) { // no fallback here return defaultValue; } /// - public virtual T GetValue(IPublishedElement content, string alias, string culture, string segment, T defaultValue, ICollection visitedLanguages) + public T GetValue(IPublishedElement content, string alias, string culture, string segment, T defaultValue, ICollection visitedLanguages) { // no fallback here return defaultValue; } /// - public virtual object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, bool recurse, PublishedValueFallbackPriority fallbackPriority, ICollection visitedLanguages) + public object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages) { - // no fallback here - if (!recurse) return defaultValue; - // is that ok? - return GetValue(content, alias, culture, segment, defaultValue, true, fallbackPriority, visitedLanguages); + return GetValue(content, alias, culture, segment, defaultValue, fallbackMethods, visitedLanguages); } /// - public virtual T GetValue(IPublishedContent content, string alias, string culture, string segment, T defaultValue, bool recurse, PublishedValueFallbackPriority fallbackPriority, ICollection visitedLanguages) + public T GetValue(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages) { - // no fallback here - if (!recurse) return defaultValue; + if (fallbackMethods == null) + { + return defaultValue; + } - // otherwise, implement recursion as it was implemented in PublishedContentBase + foreach (var fallbackMethod in fallbackMethods) + { + if (TryGetValueWithFallbackMethod(content, alias, culture, segment, defaultValue, fallbackMethods, visitedLanguages, fallbackMethod, out T value)) + { + return value; + } + } + + return defaultValue; + } + + protected virtual bool TryGetValueWithFallbackMethod(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages, int fallbackMethod, out T value) + { + value = defaultValue; + switch (fallbackMethod) + { + case Core.Constants.Content.FallbackMethods.None: + return false; + case Core.Constants.Content.FallbackMethods.RecursiveTree: + return TryGetValueWithRecursiveTree(content, alias, culture, segment, defaultValue, out value); + default: + throw new NotSupportedException($"Fallback method with indentifying number {fallbackMethod} is not supported within {GetType().Name}."); + } + } + + protected static bool TryGetValueWithRecursiveTree(IPublishedContent content, string alias, string culture, string segment, T defaultValue, out T value) + { + // Implement recursion as it was implemented in PublishedContentBase // fixme caching? // @@ -73,21 +99,31 @@ namespace Umbraco.Web.Models.PublishedContent { content = content.Parent; property = content?.GetProperty(alias); - if (property != null) noValueProperty = property; - } while (content != null && (property == null || property.HasValue(culture, segment) == false)); + if (property != null) + { + noValueProperty = property; + } + } + while (content != null && (property == null || property.HasValue(culture, segment) == false)); // if we found a content with the property having a value, return that property value if (property != null && property.HasValue(culture, segment)) - return property.Value(culture, segment); + { + value = property.Value(culture, segment); + return true; + } // if we found a property, even though with no value, return that property value // because the converter may want to handle the missing value. ie if defaultValue is default, // either specified or by default, the converter may want to substitute something else. if (noValueProperty != null) - return noValueProperty.Value(culture, segment, defaultValue: defaultValue); + { + value = noValueProperty.Value(culture, segment, defaultValue: defaultValue); + return true; + } - // else return default - return defaultValue; + value = defaultValue; + return false; } } } diff --git a/src/Umbraco.Web/Models/PublishedContent/PublishedValueLanguageFallback.cs b/src/Umbraco.Web/Models/PublishedContent/PublishedValueLanguageFallback.cs index d19ef80732..e94a8559a0 100644 --- a/src/Umbraco.Web/Models/PublishedContent/PublishedValueLanguageFallback.cs +++ b/src/Umbraco.Web/Models/PublishedContent/PublishedValueLanguageFallback.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; @@ -21,158 +23,23 @@ namespace Umbraco.Web.Models.PublishedContent _localizationService = services.LocalizationService; } - /// - public override object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue, ICollection visitedLanguages) - { - object value; - if (TryGetValueFromFallbackLanguage(property, culture, segment, defaultValue, visitedLanguages, out value)) - { - return value; - } - - return base.GetValue(property, culture, segment, defaultValue, visitedLanguages); - } - - /// - public override T GetValue(IPublishedProperty property, string culture, string segment, T defaultValue, ICollection visitedLanguages) - { - T value; - if (TryGetValueFromFallbackLanguage(property, culture, segment, defaultValue, visitedLanguages, out value)) - { - return value; - } - - return base.GetValue(property, culture, segment, defaultValue, visitedLanguages); - } - - /// - public override object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue, ICollection visitedLanguages) - { - object value; - if (TryGetValueFromFallbackLanguage(content, alias, culture, segment, defaultValue, visitedLanguages, out value)) - { - return value; - } - - return base.GetValue(content, alias, culture, segment, defaultValue, visitedLanguages); - } - - /// - public override T GetValue(IPublishedElement content, string alias, string culture, string segment, T defaultValue, ICollection visitedLanguages) - { - T value; - if (TryGetValueFromFallbackLanguage(content, alias, culture, segment, defaultValue, visitedLanguages, out value)) - { - return value; - } - - return base.GetValue(content, alias, culture, segment, defaultValue, visitedLanguages); - } - - /// - public override object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, bool recurse, PublishedValueFallbackPriority fallbackPriority, ICollection visitedLanguages) - { - return GetValue(content, alias, culture, segment, defaultValue, recurse, fallbackPriority, visitedLanguages); - } - - /// - public override T GetValue(IPublishedContent content, string alias, string culture, string segment, T defaultValue, bool recurse, PublishedValueFallbackPriority fallbackPriority, ICollection visitedLanguages) - { - if (fallbackPriority == PublishedValueFallbackPriority.RecursiveTree) - { - var result = base.GetValue(content, alias, culture, segment, defaultValue, recurse, PublishedValueFallbackPriority.RecursiveTree, visitedLanguages); - if (ValueIsNotNullEmptyOrDefault(result, defaultValue)) - { - // We've prioritised recursive tree search and found a value, so can return it. - return result; - } - - if (TryGetValueFromFallbackLanguage(content, alias, culture, segment, defaultValue, recurse, fallbackPriority, visitedLanguages, out result)) - { - return result; - } - - return defaultValue; - } - - if (fallbackPriority == PublishedValueFallbackPriority.FallbackLanguage) - { - T result; - if (TryGetValueFromFallbackLanguage(content, alias, culture, segment, defaultValue, recurse, fallbackPriority, visitedLanguages, out result)) - { - return result; - } - } - - // No language fall back content found, so use base implementation - return base.GetValue(content, alias, culture, segment, defaultValue, recurse, fallbackPriority, visitedLanguages); - } - - private bool TryGetValueFromFallbackLanguage(IPublishedProperty property, string culture, string segment, T defaultValue, ICollection visitedLanguages, out T value) + protected override bool TryGetValueWithFallbackMethod(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages, int fallbackMethod, out T value) { value = defaultValue; - - if (string.IsNullOrEmpty(culture)) + switch (fallbackMethod) { - return false; + case Core.Constants.Content.FallbackMethods.None: + return false; + case Core.Constants.Content.FallbackMethods.RecursiveTree: + return TryGetValueWithRecursiveTree(content, alias, culture, segment, defaultValue, out value); + case Core.Constants.Content.FallbackMethods.FallbackLanguage: + return TryGetValueWithFallbackLanguage(content, alias, culture, segment, defaultValue, fallbackMethods, visitedLanguages, out value); + default: + throw new NotSupportedException($"Fallback method with indentifying number {fallbackMethod} is not supported within {GetType().Name}."); } - - var language = _localizationService.GetLanguageByIsoCode(culture); - if (language.FallbackLanguageId.HasValue == false) - { - return false; - } - - if (AlreadyVisitedLanguage(visitedLanguages, language.FallbackLanguageId.Value)) - { - return false; - } - - visitedLanguages.Add(language.FallbackLanguageId.Value); - - var fallbackLanguage = GetLanguageById(language.FallbackLanguageId.Value); - value = property.Value(fallbackLanguage.IsoCode, segment, defaultValue, visitedLanguages); - if (ValueIsNotNullEmptyOrDefault(value, defaultValue)) - { - return true; - } - - return false; } - private bool TryGetValueFromFallbackLanguage(IPublishedElement content, string alias, string culture, string segment, T defaultValue, ICollection visitedLanguages, out T value) - { - value = defaultValue; - - if (string.IsNullOrEmpty(culture)) - { - return false; - } - - var language = _localizationService.GetLanguageByIsoCode(culture); - if (language.FallbackLanguageId.HasValue == false) - { - return false; - } - - if (AlreadyVisitedLanguage(visitedLanguages, language.FallbackLanguageId.Value)) - { - return false; - } - - visitedLanguages.Add(language.FallbackLanguageId.Value); - - var fallbackLanguage = GetLanguageById(language.FallbackLanguageId.Value); - value = content.Value(alias, fallbackLanguage.IsoCode, segment, defaultValue, visitedLanguages); - if (ValueIsNotNullEmptyOrDefault(value, defaultValue)) - { - return true; - } - - return false; - } - - private bool TryGetValueFromFallbackLanguage(IPublishedContent content, string alias, string culture, string segment, T defaultValue, bool recurse, PublishedValueFallbackPriority fallbackPriority, ICollection visitedLanguages, out T value) + private bool TryGetValueWithFallbackLanguage(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages, out T value) { value = defaultValue; if (string.IsNullOrEmpty(culture)) @@ -194,7 +61,7 @@ namespace Umbraco.Web.Models.PublishedContent visitedLanguages.Add(language.FallbackLanguageId.Value); var fallbackLanguage = GetLanguageById(language.FallbackLanguageId.Value); - value = content.Value(alias, fallbackLanguage.IsoCode, segment, defaultValue, recurse, fallbackPriority, visitedLanguages); + value = content.Value(alias, fallbackLanguage.IsoCode, segment, defaultValue, fallbackMethods.ToArray(), visitedLanguages); if (ValueIsNotNullEmptyOrDefault(value, defaultValue)) { return true; diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 4ab2d1dc79..c4c745a087 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -151,43 +151,35 @@ namespace Umbraco.Web #endregion #region Value - + /// - /// Recursively the value of a content's property identified by its alias, if it exists, otherwise a default value. + /// Gets the value of a content's property identified by its alias, if it exists, otherwise a default value. /// /// The content. /// The property alias. /// The variation language. /// The variation segment. /// The default value. - /// A value indicating whether to recurse. - /// Flag indicating priority order of fallback paths in cases when content does not exist and a fall back method is used. + /// Options for fall-back if content not found. /// A list of cultures already visited in looking for a value via a fall-back method. /// The value of the content's property identified by the alias, if it exists, otherwise a default value. - /// - /// Recursively means: walking up the tree from , get the first value that can be found. - /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content. - /// If no property with the specified alias exists, or if the property has no value, returns . - /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter. - /// The alias is case-insensitive. - /// - public static object Value(this IPublishedContent content, string alias, string culture = null, string segment = null, object defaultValue = default, - bool recurse = false, PublishedValueFallbackPriority fallbackPriority = PublishedValueFallbackPriority.RecursiveTree, ICollection visitedLanguages = null) + public static object Value(this IPublishedContent content, string alias, string culture = null, string segment = null, object defaultValue = default, + int[] fallbackMethods = null, ICollection visitedLanguages = null) { var property = content.GetProperty(alias); if (property != null && property.HasValue(culture, segment)) return property.GetValue(culture, segment); - return PublishedValueFallback.GetValue(content, alias, culture, segment, defaultValue, recurse, fallbackPriority, visitedLanguages ?? new List()); + return PublishedValueFallback.GetValue(content, alias, culture, segment, defaultValue, fallbackMethods, visitedLanguages ?? new List()); } #endregion #region Value - + /// - /// Recursively gets the value of a content's property identified by its alias, converted to a specified type. + /// Gets the value of a content's property identified by its alias, converted to a specified type. /// /// The target property type. /// The content. @@ -195,31 +187,24 @@ namespace Umbraco.Web /// The variation language. /// The variation segment. /// The default value. - /// A value indicating whether to recurse. - /// Flag indicating priority order of fallback paths in cases when content does not exist and a fall back method is used. + /// Options for fall-back if content not found. /// A list of cultures already visited in looking for a value via a fall-back method. /// The value of the content's property identified by the alias, converted to the specified type. /// - /// Recursively means: walking up the tree from , get the first value that can be found. - /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content. - /// If no property with the specified alias exists, or if the property has no value, or if it could not be converted, returns default(T). - /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter. - /// The alias is case-insensitive. - /// public static T Value(this IPublishedContent content, string alias, string culture = null, string segment = null, T defaultValue = default, - bool recurse = false, PublishedValueFallbackPriority fallbackPriority = PublishedValueFallbackPriority.RecursiveTree, ICollection visitedLanguages = null) + int[] fallbackMethods = null, ICollection visitedLanguages = null) { var property = content.GetProperty(alias); if (property != null && property.HasValue(culture, segment)) return property.Value(culture, segment); - return PublishedValueFallback.GetValue(content, alias, culture, segment, defaultValue, recurse, fallbackPriority, visitedLanguages ?? new List()); + return PublishedValueFallback.GetValue(content, alias, culture, segment, defaultValue, fallbackMethods, visitedLanguages ?? new List()); } // fixme - .Value() refactoring - in progress public static IHtmlString Value(this IPublishedContent content, string aliases, Func format, string alt = "", - bool recurse = false, PublishedValueFallbackPriority fallbackPriority = PublishedValueFallbackPriority.RecursiveTree, ICollection visitedLanguages = null) + int[] fallbackMethods = null, ICollection visitedLanguages = null) { var aliasesA = aliases.Split(','); if (aliasesA.Length == 0) diff --git a/src/Umbraco.Web/umbraco.presentation/item.cs b/src/Umbraco.Web/umbraco.presentation/item.cs index 3937b5675c..18437f5235 100644 --- a/src/Umbraco.Web/umbraco.presentation/item.cs +++ b/src/Umbraco.Web/umbraco.presentation/item.cs @@ -76,7 +76,7 @@ namespace umbraco //check for published content and get its value using that if (publishedContent != null && (publishedContent.HasProperty(_fieldName) || recursive)) { - var pval = publishedContent.Value(_fieldName, recurse: recursive); + var pval = publishedContent.Value(_fieldName, fallbackMethods: new[] { Constants.Content.FallbackMethods.RecursiveTree }); var rval = pval == null ? string.Empty : pval.ToString(); _fieldContent = rval.IsNullOrWhiteSpace() ? _fieldContent : rval; } @@ -96,7 +96,7 @@ namespace umbraco { if (publishedContent != null && (publishedContent.HasProperty(altFieldName) || recursive)) { - var pval = publishedContent.Value(altFieldName, recurse: recursive); + var pval = publishedContent.Value(altFieldName, fallbackMethods: new[] { Constants.Content.FallbackMethods.RecursiveTree }); var rval = pval == null ? string.Empty : pval.ToString(); _fieldContent = rval.IsNullOrWhiteSpace() ? _fieldContent : rval; }