using System; using System.Collections.Generic; using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Web.Models.PublishedContent { /// /// Provides a default implementation for . /// public class PublishedValueFallback : IPublishedValueFallback { // kinda reproducing what was available in v7 /// public object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue, ICollection visitedLanguages) { // no fallback here return defaultValue; } /// public T GetValue(IPublishedProperty property, string culture, string segment, T defaultValue, ICollection visitedLanguages) { // no fallback here return defaultValue; } /// public object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue, ICollection visitedLanguages) { // no fallback here return defaultValue; } /// public T GetValue(IPublishedElement content, string alias, string culture, string segment, T defaultValue, ICollection visitedLanguages) { // no fallback here return defaultValue; } /// public object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages) { // is that ok? return GetValue(content, alias, culture, segment, defaultValue, fallbackMethods, visitedLanguages); } /// public T GetValue(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable fallbackMethods, ICollection visitedLanguages) { if (fallbackMethods == null) { 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); 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? // // 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 { content = content.Parent; property = content?.GetProperty(alias); 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)) { 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) { value = noValueProperty.Value(culture, segment, defaultValue: defaultValue); return true; } value = defaultValue; return false; } } }