From a35f67ecef25af5befcbe52c62df6471ac66d460 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 24 Jul 2018 13:32:29 +0200 Subject: [PATCH] Refactoring --- src/Umbraco.Core/Constants-Content.cs | 24 +++- .../IPublishedValueFallback.cs | 53 ++++++-- .../NoopPublishedValueFallback.cs | 16 ++- .../PublishedContentLanguageVariantTests.cs | 28 +---- .../PublishedContent/PublishedContentTests.cs | 6 +- src/Umbraco.Tests/TestHelpers/BaseWebTest.cs | 2 +- .../PublishedValueFallback.cs | 116 +++++++++++------- .../PublishedValueLanguageFallback.cs | 90 -------------- src/Umbraco.Web/PublishedContentExtensions.cs | 20 ++- src/Umbraco.Web/PublishedElementExtensions.cs | 15 ++- ...nsion.cs => PublishedPropertyExtension.cs} | 4 +- .../Runtime/WebRuntimeComponent.cs | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 3 +- src/Umbraco.Web/umbraco.presentation/item.cs | 4 +- 14 files changed, 168 insertions(+), 215 deletions(-) delete mode 100644 src/Umbraco.Web/Models/PublishedContent/PublishedValueLanguageFallback.cs rename src/Umbraco.Web/{PublishedContentPropertyExtension.cs => PublishedPropertyExtension.cs} (96%) diff --git a/src/Umbraco.Core/Constants-Content.cs b/src/Umbraco.Core/Constants-Content.cs index 4b8c383e6f..b9d0691454 100644 --- a/src/Umbraco.Core/Constants-Content.cs +++ b/src/Umbraco.Core/Constants-Content.cs @@ -11,11 +11,27 @@ /// 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 static class ValueFallback { - public const int None = 0; - public const int RecursiveTree = 1; - public const int FallbackLanguage = 2; + /// + /// No fallback at all. + /// + public const int None = -1; + + /// + /// Default fallback. + /// + public const int Default = 0; + + /// + /// Recurse up the tree. + /// + public const int Recurse = 1; + + /// + /// Fallback to other languages. + /// + public const int Language = 2; } } } diff --git a/src/Umbraco.Core/Models/PublishedContent/IPublishedValueFallback.cs b/src/Umbraco.Core/Models/PublishedContent/IPublishedValueFallback.cs index 59442e20bb..96a6c144fa 100644 --- a/src/Umbraco.Core/Models/PublishedContent/IPublishedValueFallback.cs +++ b/src/Umbraco.Core/Models/PublishedContent/IPublishedValueFallback.cs @@ -1,15 +1,44 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Models.PublishedContent +namespace Umbraco.Core.Models.PublishedContent { /// /// Provides a fallback strategy for getting values. /// - // fixme - IPublishedValueFallback is still WorkInProgress - // todo - properly document methods, etc - // todo - understand caching vs fallback (recurse etc) public interface IPublishedValueFallback { + // fixme discussions & challenges + // + // - what's with visitedLanguage? should be internal to fallback implementation + // so that should be the case now, with latest changes + // + // - should be as simple as + // model.Value("price", fallback: ValueFallback.Language); + // model.Value("name", fallback: ValueFallback.Recurse); + // + // so chaining things through an array of ints is not... convenient + // it feels like ppl could have ValueFallback.LanguageAndRecurse or something? + // + // - the fallback: parameter value must be open, so about anything can be passed to the IPublishedValueFallback + // we have it now, it's an integer + constants, cool + // + // - we need to be able to configure (via code for now) a default fallback policy? + // not! the default value of the fallback: parameter is 'default', not 'none', and if people + // want to implement a different default behavior, they have to override the fallback provider + // + // - currently, no policies on IPublishedProperty nor IPublishedElement, but some may apply (language) + // todo: implement + // + // - general defaultValue discussion: + // when HasValue is false, the converter may return something, eg an empty enumerable, even though + // defaultValue is null, so should we respect defaultValue only when it is not 'default'? + // todo: when defaultValue==default, and HasValue is false, still return GetValue to ensure this + // + // - (and...) + // ModelsBuilder model.Value(x => x.Price, ...) extensions need to be adjusted too + // + // - cache & perfs + // soon as ppl implement custom fallbacks, caching is a problem, so better just not cache + // OTOH we need to implement the readonly thing for languages + /// /// Gets a fallback value for a property. /// @@ -25,7 +54,7 @@ namespace Umbraco.Core.Models.PublishedContent /// At property level, property.GetValue() does *not* implement fallback, and one has to /// get property.Value() or property.Value{T}() to trigger fallback. /// - object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue, ICollection visitedLanguages); + object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue); /// /// Gets a fallback value for a property. @@ -43,7 +72,7 @@ namespace Umbraco.Core.Models.PublishedContent /// At property level, property.GetValue() does *not* implement fallback, and one has to /// get property.Value() or property.Value{T}() to trigger fallback. /// - T GetValue(IPublishedProperty property, string culture, string segment, T defaultValue, ICollection visitedLanguages); + T GetValue(IPublishedProperty property, string culture, string segment, T defaultValue); /// /// Gets a fallback value for a published element property. @@ -59,7 +88,7 @@ namespace Umbraco.Core.Models.PublishedContent /// segment, either returned no property at all, or a property with HasValue(culture, segment) being false. /// It can only fallback at element level (no recurse). /// - object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue, ICollection visitedLanguages); + object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue); /// /// Gets a fallback value for a published element property. @@ -76,7 +105,7 @@ namespace Umbraco.Core.Models.PublishedContent /// segment, either returned no property at all, or a property with HasValue(culture, segment) being false. /// It can only fallback at element level (no recurse). /// - T GetValue(IPublishedElement content, string alias, string culture, string segment, T defaultValue, ICollection visitedLanguages); + T GetValue(IPublishedElement content, string alias, string culture, string segment, T defaultValue); /// /// Gets a fallback value for a published content property. @@ -92,7 +121,7 @@ namespace Umbraco.Core.Models.PublishedContent /// segment, either returned no property at all, or a property with HasValue(culture, segment) being false. /// fixme explain & document priority + merge w/recurse? /// - object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages); + object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, int fallback); /// /// Gets a fallback value for a published content property. @@ -109,6 +138,6 @@ namespace Umbraco.Core.Models.PublishedContent /// segment, either returned no property at all, or a property with HasValue(culture, segment) being false. /// fixme explain & document priority + merge w/recurse? /// - T GetValue(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages); + T GetValue(IPublishedContent content, string alias, string culture, string segment, T defaultValue, int fallback); } } diff --git a/src/Umbraco.Core/Models/PublishedContent/NoopPublishedValueFallback.cs b/src/Umbraco.Core/Models/PublishedContent/NoopPublishedValueFallback.cs index a8d55176a3..9d74c4d8a2 100644 --- a/src/Umbraco.Core/Models/PublishedContent/NoopPublishedValueFallback.cs +++ b/src/Umbraco.Core/Models/PublishedContent/NoopPublishedValueFallback.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Models.PublishedContent +namespace Umbraco.Core.Models.PublishedContent { /// /// Provides a noop implementation for . @@ -11,21 +9,21 @@ namespace Umbraco.Core.Models.PublishedContent public class NoopPublishedValueFallback : IPublishedValueFallback { /// - public object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue, ICollection visitedLanguages) => defaultValue; + public object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue) => defaultValue; /// - public T GetValue(IPublishedProperty property, string culture, string segment, T defaultValue, ICollection visitedLanguages) => defaultValue; + public T GetValue(IPublishedProperty property, string culture, string segment, T defaultValue) => defaultValue; /// - public object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue, ICollection visitedLanguages) => defaultValue; + public object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue) => defaultValue; /// - public T GetValue(IPublishedElement content, string alias, string culture, string segment, T defaultValue, ICollection visitedLanguages) => defaultValue; + public T GetValue(IPublishedElement content, string alias, string culture, string segment, T defaultValue) => defaultValue; /// - public object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages) => defaultValue; + public object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, int fallback) => defaultValue; /// - public T GetValue(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages) => defaultValue; + public T GetValue(IPublishedContent content, string alias, string culture, string segment, T defaultValue, int fallback) => defaultValue; } } diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs index 7108824602..0b0f4dea51 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs @@ -167,7 +167,7 @@ namespace Umbraco.Tests.PublishedContent 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 }); + var value = content.Value("welcomeText", "es", fallback: Core.Constants.Content.ValueFallback.Language); Assert.AreEqual("Welcome", value); } @@ -175,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", fallbackMethods: new[] { Core.Constants.Content.FallbackMethods.FallbackLanguage }); + var value = content.Value("welcomeText", "it", fallback: Core.Constants.Content.ValueFallback.Language); Assert.AreEqual("Welcome", value); } @@ -183,7 +183,7 @@ 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", fallbackMethods: new[] { Core.Constants.Content.FallbackMethods.FallbackLanguage }); + var value = content.Value("welcomeText", "no", fallback: Core.Constants.Content.ValueFallback.Language); Assert.IsNull(value); } @@ -199,27 +199,7 @@ namespace Umbraco.Tests.PublishedContent 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. + var value = content.Value("welcomeText2", fallback: Core.Constants.Content.ValueFallback.Recurse); Assert.AreEqual("Welcome", value); } } diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 950bbf2283..93f4f3f242 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -34,7 +34,7 @@ namespace Umbraco.Tests.PublishedContent Container.RegisterSingleton(f => new PublishedModelFactory(f.GetInstance().GetTypes())); Container.RegisterSingleton(); - Container.RegisterSingleton(); + Container.RegisterSingleton(); var logger = Mock.Of(); var dataTypeService = new TestObjects.TestDataTypeService( @@ -336,8 +336,8 @@ namespace Umbraco.Tests.PublishedContent public void Get_Property_Value_Recursive() { var doc = GetNode(1174); - var rVal = doc.Value("testRecursive", fallbackMethods: new[] { Constants.Content.FallbackMethods.RecursiveTree } ); - var nullVal = doc.Value("DoNotFindThis", fallbackMethods: new[] { Constants.Content.FallbackMethods.RecursiveTree }); + var rVal = doc.Value("testRecursive", fallback: Constants.Content.ValueFallback.Recurse); + var nullVal = doc.Value("DoNotFindThis", fallback: Constants.Content.ValueFallback.Recurse); Assert.AreEqual("This is the recursive val", rVal); Assert.AreEqual(null, nullVal); } diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index 2f7fe8700b..5eea6bcf72 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -28,7 +28,7 @@ namespace Umbraco.Tests.TestHelpers { base.Compose(); - Container.RegisterSingleton(); + Container.RegisterSingleton(); Container.RegisterSingleton(); } diff --git a/src/Umbraco.Web/Models/PublishedContent/PublishedValueFallback.cs b/src/Umbraco.Web/Models/PublishedContent/PublishedValueFallback.cs index 85b10be480..4136be40d8 100644 --- a/src/Umbraco.Web/Models/PublishedContent/PublishedValueFallback.cs +++ b/src/Umbraco.Web/Models/PublishedContent/PublishedValueFallback.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Services; +using ValueFallback = Umbraco.Core.Constants.Content.ValueFallback; namespace Umbraco.Web.Models.PublishedContent { @@ -9,90 +12,72 @@ namespace Umbraco.Web.Models.PublishedContent /// public class PublishedValueFallback : IPublishedValueFallback { - // kinda reproducing what was available in v7 + private readonly ILocalizationService _localizationService; + + /// + /// Initializes a new instance of the class. + /// + /// + public PublishedValueFallback(ILocalizationService localizationService) + { + _localizationService = localizationService; + } /// - public object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue, ICollection visitedLanguages) + public object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue) { // no fallback here return defaultValue; } /// - public T GetValue(IPublishedProperty property, string culture, string segment, T defaultValue, ICollection visitedLanguages) + public T GetValue(IPublishedProperty property, string culture, string segment, T defaultValue) { // no fallback here return defaultValue; } /// - public 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) { // no fallback here return defaultValue; } /// - public 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) { // no fallback here return defaultValue; } /// - public object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages) + public object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, int fallback) { // is that ok? - return GetValue(content, alias, culture, segment, defaultValue, fallbackMethods, visitedLanguages); + return GetValue(content, alias, culture, segment, defaultValue, fallback); } /// - public T GetValue(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages) + public virtual T GetValue(IPublishedContent content, string alias, string culture, string segment, T defaultValue, int fallback) { - if (fallbackMethods == null) + switch (fallback) { - return defaultValue; - } - - 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); + case ValueFallback.None: + case ValueFallback.Default: + return defaultValue; + case ValueFallback.Recurse: + return TryGetValueWithRecursiveFallback(content, alias, culture, segment, defaultValue, out var value1) ? value1 : defaultValue; + case ValueFallback.Language: + return TryGetValueWithLanguageFallback(content, alias, culture, segment, defaultValue, out var value2) ? value2 : defaultValue; default: - throw new NotSupportedException($"Fallback method with indentifying number {fallbackMethod} is not supported within {GetType().Name}."); + throw new NotSupportedException($"Fallback {GetType().Name} does not support policy code '{fallback}'."); } } - protected static bool TryGetValueWithRecursiveTree(IPublishedContent content, string alias, string culture, string segment, T defaultValue, out T value) + // tries to get a value, recursing the tree + protected static bool TryGetValueWithRecursiveFallback(IPublishedContent content, string alias, string culture, string segment, T defaultValue, out T value) { - // Implement recursion as it was implemented in PublishedContentBase - - // fixme caching? - // - // all caches were using PublishedContentBase.GetProperty(alias, recurse) to get the property, - // then, - // NuCache.PublishedContent was storing the property in GetAppropriateCache() with key "NuCache.Property.Recurse[" + DraftOrPub(previewing) + contentUid + ":" + typeAlias + "]"; - // XmlPublishedContent was storing the property in _cacheProvider with key $"XmlPublishedCache.PublishedContentCache:RecursiveProperty-{Id}-{alias.ToLowerInvariant()}"; - // DictionaryPublishedContent was storing the property in _cacheProvider with key $"XmlPublishedCache.PublishedMediaCache:RecursiveProperty-{Id}-{alias.ToLowerInvariant()}"; - // - // at the moment, caching has been entirely removed, until we better understand caching + fallback - IPublishedProperty property = null; // if we are here, content's property has no value IPublishedProperty noValueProperty = null; do @@ -125,5 +110,44 @@ namespace Umbraco.Web.Models.PublishedContent value = defaultValue; return false; } + + // tries to get a value, falling back onto other languages + private bool TryGetValueWithLanguageFallback(IPublishedContent content, string alias, string culture, string segment, T defaultValue, out T value) + { + value = defaultValue; + + if (culture.IsNullOrWhiteSpace()) return false; + + var visited = new HashSet(); + + // fixme + // _localizationService.GetXxx() is expensive, it deep clones objects + // we want _localizationService.GetReadOnlyXxx() returning IReadOnlyLanguage which cannot be saved back = no need to clone + + var language = _localizationService.GetLanguageByIsoCode(culture); + if (language == null) return false; + + while (true) + { + if (language.FallbackLanguageId == null) return false; + + var language2Id = language.FallbackLanguageId.Value; + if (visited.Contains(language2Id)) return false; + visited.Add(language2Id); + + var language2 = _localizationService.GetLanguageById(language2Id); + if (language2 == null) return false; + var culture2 = language2.IsoCode; + + if (content.HasValue(alias, culture2, segment)) + { + value = content.Value(alias, culture2, segment); + return true; + } + + language = language2; + } + } + } } diff --git a/src/Umbraco.Web/Models/PublishedContent/PublishedValueLanguageFallback.cs b/src/Umbraco.Web/Models/PublishedContent/PublishedValueLanguageFallback.cs deleted file mode 100644 index e94a8559a0..0000000000 --- a/src/Umbraco.Web/Models/PublishedContent/PublishedValueLanguageFallback.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Umbraco.Core.Models; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Services; - -namespace Umbraco.Web.Models.PublishedContent -{ - /// - /// Provides a default implementation for that allows - /// for use of fall-back languages - /// - /// - /// Inherits from that implments what was available in v7. - /// - public class PublishedValueLanguageFallback : PublishedValueFallback - { - private readonly ILocalizationService _localizationService; - - public PublishedValueLanguageFallback(ServiceContext services) - { - _localizationService = services.LocalizationService; - } - - 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; - 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); - 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}."); - } - } - - 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)) - { - 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, fallbackMethods.ToArray(), visitedLanguages); - if (ValueIsNotNullEmptyOrDefault(value, defaultValue)) - { - return true; - } - - return false; - } - - private static bool AlreadyVisitedLanguage(ICollection visitedLanguages, int fallbackLanguageId) - { - return visitedLanguages.Contains(fallbackLanguageId); - } - - private ILanguage GetLanguageById(int id) - { - return _localizationService.GetLanguageById(id); - } - - private static bool ValueIsNotNullEmptyOrDefault(T value, T defaultValue) - { - return value != null && - string.IsNullOrEmpty(value.ToString()) == false && - value.Equals(defaultValue) == false; - } - } -} diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 0bea71358a..64738aa923 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -153,18 +153,16 @@ namespace Umbraco.Web /// The variation language. /// The variation segment. /// The default value. - /// Options for fall-back if content not found. - /// A list of cultures already visited in looking for a value via a fall-back method. + /// Optional fallback strategy. /// The value of the content's property identified by the alias, if it exists, otherwise a default value. - public static object Value(this IPublishedContent content, string alias, string culture = null, string segment = null, object defaultValue = default, - int[] fallbackMethods = null, ICollection visitedLanguages = null) + public static object Value(this IPublishedContent content, string alias, string culture = null, string segment = null, object defaultValue = default, int fallback = 0) { 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, fallbackMethods, visitedLanguages ?? new List()); + return PublishedValueFallback.GetValue(content, alias, culture, segment, defaultValue, fallback); } #endregion @@ -180,24 +178,20 @@ namespace Umbraco.Web /// The variation language. /// The variation segment. /// The default value. - /// Options for fall-back if content not found. - /// A list of cultures already visited in looking for a value via a fall-back method. + /// Optional fallback strategy. /// The value of the content's property identified by the alias, converted to the specified type. - /// - public static T Value(this IPublishedContent content, string alias, string culture = null, string segment = null, T defaultValue = default, - int[] fallbackMethods = null, ICollection visitedLanguages = null) + public static T Value(this IPublishedContent content, string alias, string culture = null, string segment = null, T defaultValue = default, int fallback = 0) { 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, fallbackMethods, visitedLanguages ?? new List()); + return PublishedValueFallback.GetValue(content, alias, culture, segment, defaultValue, fallback); } // fixme - .Value() refactoring - in progress - public static IHtmlString Value(this IPublishedContent content, string aliases, Func format, string alt = "", - int[] fallbackMethods = null, ICollection visitedLanguages = null) + public static IHtmlString Value(this IPublishedContent content, string aliases, Func format, string alt = "", int fallback = 0) { var aliasesA = aliases.Split(','); if (aliasesA.Length == 0) diff --git a/src/Umbraco.Web/PublishedElementExtensions.cs b/src/Umbraco.Web/PublishedElementExtensions.cs index b0d2826df4..51f0b6c0dc 100644 --- a/src/Umbraco.Web/PublishedElementExtensions.cs +++ b/src/Umbraco.Web/PublishedElementExtensions.cs @@ -100,7 +100,6 @@ namespace Umbraco.Web /// The variation language. /// The variation segment. /// The default value. - /// 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. /// /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content. @@ -108,14 +107,19 @@ namespace Umbraco.Web /// 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 IPublishedElement content, string alias, string culture = null, string segment = null, object defaultValue = default, ICollection visitedLanguages = null) + public static object Value(this IPublishedElement content, string alias, string culture = null, string segment = null, object defaultValue = default) { 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, visitedLanguages ?? new List()); + // fixme defaultValue is a problem here + // assuming the value may return as an IEnumerable and no defaultValue is provided, then defaultValue is null + // and if HasValue is false, what we get is 'null' - but the converter may instead have been able to return an + // empty enumerable, which would be way nicer - so we need a way to tell that 'no defaultValue has been provided'? + + return PublishedValueFallback.GetValue(content, alias, culture, segment, defaultValue); } #endregion @@ -131,7 +135,6 @@ namespace Umbraco.Web /// The variation language. /// The variation segment. /// The default value. - /// 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. /// /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content. @@ -139,14 +142,14 @@ namespace Umbraco.Web /// 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 IPublishedElement content, string alias, string culture = null, string segment = null, T defaultValue = default, ICollection visitedLanguages = null) + public static T Value(this IPublishedElement content, string alias, string culture = null, string segment = null, T defaultValue = default) { 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, visitedLanguages ?? new List()); + return PublishedValueFallback.GetValue(content, alias, culture, segment, defaultValue); } #endregion diff --git a/src/Umbraco.Web/PublishedContentPropertyExtension.cs b/src/Umbraco.Web/PublishedPropertyExtension.cs similarity index 96% rename from src/Umbraco.Web/PublishedContentPropertyExtension.cs rename to src/Umbraco.Web/PublishedPropertyExtension.cs index fdfd772ce7..bce13d30b4 100644 --- a/src/Umbraco.Web/PublishedContentPropertyExtension.cs +++ b/src/Umbraco.Web/PublishedPropertyExtension.cs @@ -16,12 +16,12 @@ namespace Umbraco.Web #region Value - public static object Value(this IPublishedProperty property, string culture = null, string segment = null, object defaultValue = default, ICollection visitedLanguages = null) + public static object Value(this IPublishedProperty property, string culture = null, string segment = null, object defaultValue = default) { if (property.HasValue(culture, segment)) return property.GetValue(culture, segment); - return PublishedValueFallback.GetValue(property, culture, segment, defaultValue, visitedLanguages ?? new List()); + return PublishedValueFallback.GetValue(property, culture, segment, defaultValue); } #endregion diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs index 78ddb935a0..03ba763527 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComponent.cs @@ -199,7 +199,7 @@ namespace Umbraco.Web.Runtime composition.Container.Register(_ => GlobalHost.ConnectionManager.GetHubContext(), new PerContainerLifetime()); // register properties fallback - composition.Container.RegisterSingleton(); + composition.Container.RegisterSingleton(); } internal void Initialize( diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index af2170123a..1d56ed5c7c 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -263,7 +263,6 @@ - @@ -838,7 +837,7 @@ - + diff --git a/src/Umbraco.Web/umbraco.presentation/item.cs b/src/Umbraco.Web/umbraco.presentation/item.cs index 14835b278f..d89733044d 100644 --- a/src/Umbraco.Web/umbraco.presentation/item.cs +++ b/src/Umbraco.Web/umbraco.presentation/item.cs @@ -78,7 +78,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, fallbackMethods: new[] { Constants.Content.FallbackMethods.RecursiveTree }); + var pval = publishedContent.Value(_fieldName, fallback: Constants.Content.ValueFallback.Recurse); var rval = pval == null ? string.Empty : pval.ToString(); _fieldContent = rval.IsNullOrWhiteSpace() ? _fieldContent : rval; } @@ -98,7 +98,7 @@ namespace umbraco { if (publishedContent != null && (publishedContent.HasProperty(altFieldName) || recursive)) { - var pval = publishedContent.Value(altFieldName, fallbackMethods: new[] { Constants.Content.FallbackMethods.RecursiveTree }); + var pval = publishedContent.Value(altFieldName, fallback: Constants.Content.ValueFallback.Recurse); var rval = pval == null ? string.Empty : pval.ToString(); _fieldContent = rval.IsNullOrWhiteSpace() ? _fieldContent : rval; }