Refactoring

This commit is contained in:
Stephan
2018-07-24 13:32:29 +02:00
parent 053698baf6
commit a35f67ecef
14 changed files with 168 additions and 215 deletions

View File

@@ -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.
/// </summary>
public static class FallbackMethods
public static class ValueFallback
{
public const int None = 0;
public const int RecursiveTree = 1;
public const int FallbackLanguage = 2;
/// <summary>
/// No fallback at all.
/// </summary>
public const int None = -1;
/// <summary>
/// Default fallback.
/// </summary>
public const int Default = 0;
/// <summary>
/// Recurse up the tree.
/// </summary>
public const int Recurse = 1;
/// <summary>
/// Fallback to other languages.
/// </summary>
public const int Language = 2;
}
}
}

View File

@@ -1,15 +1,44 @@
using System.Collections.Generic;
namespace Umbraco.Core.Models.PublishedContent
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Provides a fallback strategy for getting <see cref="IPublishedElement"/> values.
/// </summary>
// 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
/// <summary>
/// Gets a fallback value for a property.
/// </summary>
@@ -25,7 +54,7 @@ namespace Umbraco.Core.Models.PublishedContent
/// <para>At property level, property.GetValue() does *not* implement fallback, and one has to
/// get property.Value() or property.Value{T}() to trigger fallback.</para>
/// </remarks>
object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue, ICollection<int> visitedLanguages);
object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue);
/// <summary>
/// Gets a fallback value for a property.
@@ -43,7 +72,7 @@ namespace Umbraco.Core.Models.PublishedContent
/// <para>At property level, property.GetValue() does *not* implement fallback, and one has to
/// get property.Value() or property.Value{T}() to trigger fallback.</para>
/// </remarks>
T GetValue<T>(IPublishedProperty property, string culture, string segment, T defaultValue, ICollection<int> visitedLanguages);
T GetValue<T>(IPublishedProperty property, string culture, string segment, T defaultValue);
/// <summary>
/// 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.</para>
/// <para>It can only fallback at element level (no recurse).</para>
/// </remarks>
object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue, ICollection<int> visitedLanguages);
object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue);
/// <summary>
/// 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.</para>
/// <para>It can only fallback at element level (no recurse).</para>
/// </remarks>
T GetValue<T>(IPublishedElement content, string alias, string culture, string segment, T defaultValue, ICollection<int> visitedLanguages);
T GetValue<T>(IPublishedElement content, string alias, string culture, string segment, T defaultValue);
/// <summary>
/// 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.</para>
/// fixme explain & document priority + merge w/recurse?
/// </remarks>
object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, IEnumerable<int> fallbackMethods, ICollection<int> visitedLanguages);
object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, int fallback);
/// <summary>
/// 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.</para>
/// fixme explain & document priority + merge w/recurse?
/// </remarks>
T GetValue<T>(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable<int> fallbackMethods, ICollection<int> visitedLanguages);
T GetValue<T>(IPublishedContent content, string alias, string culture, string segment, T defaultValue, int fallback);
}
}

View File

@@ -1,6 +1,4 @@
using System.Collections.Generic;
namespace Umbraco.Core.Models.PublishedContent
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Provides a noop implementation for <see cref="IPublishedValueFallback"/>.
@@ -11,21 +9,21 @@ namespace Umbraco.Core.Models.PublishedContent
public class NoopPublishedValueFallback : IPublishedValueFallback
{
/// <inheritdoc />
public object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue, ICollection<int> visitedLanguages) => defaultValue;
public object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue) => defaultValue;
/// <inheritdoc />
public T GetValue<T>(IPublishedProperty property, string culture, string segment, T defaultValue, ICollection<int> visitedLanguages) => defaultValue;
public T GetValue<T>(IPublishedProperty property, string culture, string segment, T defaultValue) => defaultValue;
/// <inheritdoc />
public object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue, ICollection<int> visitedLanguages) => defaultValue;
public object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue) => defaultValue;
/// <inheritdoc />
public T GetValue<T>(IPublishedElement content, string alias, string culture, string segment, T defaultValue, ICollection<int> visitedLanguages) => defaultValue;
public T GetValue<T>(IPublishedElement content, string alias, string culture, string segment, T defaultValue) => defaultValue;
/// <inheritdoc />
public object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, IEnumerable<int> fallbackMethods, ICollection<int> visitedLanguages) => defaultValue;
public object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, int fallback) => defaultValue;
/// <inheritdoc />
public T GetValue<T>(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable<int> fallbackMethods, ICollection<int> visitedLanguages) => defaultValue;
public T GetValue<T>(IPublishedContent content, string alias, string culture, string segment, T defaultValue, int fallback) => defaultValue;
}
}

View File

@@ -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);
}
}

View File

@@ -34,7 +34,7 @@ namespace Umbraco.Tests.PublishedContent
Container.RegisterSingleton<IPublishedModelFactory>(f => new PublishedModelFactory(f.GetInstance<TypeLoader>().GetTypes<PublishedContentModel>()));
Container.RegisterSingleton<IPublishedContentTypeFactory, PublishedContentTypeFactory>();
Container.RegisterSingleton<IPublishedValueFallback, PublishedValueLanguageFallback>();
Container.RegisterSingleton<IPublishedValueFallback, PublishedValueFallback>();
var logger = Mock.Of<ILogger>();
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);
}

View File

@@ -28,7 +28,7 @@ namespace Umbraco.Tests.TestHelpers
{
base.Compose();
Container.RegisterSingleton<IPublishedValueFallback, PublishedValueLanguageFallback>();
Container.RegisterSingleton<IPublishedValueFallback, PublishedValueFallback>();
Container.RegisterSingleton<ProfilingLogger>();
}

View File

@@ -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
/// </summary>
public class PublishedValueFallback : IPublishedValueFallback
{
// kinda reproducing what was available in v7
private readonly ILocalizationService _localizationService;
/// <summary>
/// Initializes a new instance of the <see cref="PublishedValueFallback"/> class.
/// </summary>
/// <param name="localizationService"></param>
public PublishedValueFallback(ILocalizationService localizationService)
{
_localizationService = localizationService;
}
/// <inheritdoc />
public object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue, ICollection<int> visitedLanguages)
public object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue)
{
// no fallback here
return defaultValue;
}
/// <inheritdoc />
public T GetValue<T>(IPublishedProperty property, string culture, string segment, T defaultValue, ICollection<int> visitedLanguages)
public T GetValue<T>(IPublishedProperty property, string culture, string segment, T defaultValue)
{
// no fallback here
return defaultValue;
}
/// <inheritdoc />
public object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue, ICollection<int> visitedLanguages)
public object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue)
{
// no fallback here
return defaultValue;
}
/// <inheritdoc />
public T GetValue<T>(IPublishedElement content, string alias, string culture, string segment, T defaultValue, ICollection<int> visitedLanguages)
public T GetValue<T>(IPublishedElement content, string alias, string culture, string segment, T defaultValue)
{
// no fallback here
return defaultValue;
}
/// <inheritdoc />
public object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, IEnumerable<int> fallbackMethods, ICollection<int> visitedLanguages)
public object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, int fallback)
{
// is that ok?
return GetValue<object>(content, alias, culture, segment, defaultValue, fallbackMethods, visitedLanguages);
return GetValue<object>(content, alias, culture, segment, defaultValue, fallback);
}
/// <inheritdoc />
public T GetValue<T>(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable<int> fallbackMethods, ICollection<int> visitedLanguages)
public virtual T GetValue<T>(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<T>(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable<int> fallbackMethods, ICollection<int> 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<T>(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<T>(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<T>(IPublishedContent content, string alias, string culture, string segment, T defaultValue, out T value)
{
value = defaultValue;
if (culture.IsNullOrWhiteSpace()) return false;
var visited = new HashSet<int>();
// 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<T>(alias, culture2, segment);
return true;
}
language = language2;
}
}
}
}

View File

@@ -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
{
/// <summary>
/// Provides a default implementation for <see cref="IPublishedValueFallback"/> that allows
/// for use of fall-back languages
/// </summary>
/// <remarks>
/// Inherits from <see cref="PublishedValueFallback" /> that implments what was available in v7.
/// </remarks>
public class PublishedValueLanguageFallback : PublishedValueFallback
{
private readonly ILocalizationService _localizationService;
public PublishedValueLanguageFallback(ServiceContext services)
{
_localizationService = services.LocalizationService;
}
protected override bool TryGetValueWithFallbackMethod<T>(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable<int> fallbackMethods, ICollection<int> 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<T>(IPublishedContent content, string alias, string culture, string segment, T defaultValue, IEnumerable<int> fallbackMethods, ICollection<int> 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<int> visitedLanguages, int fallbackLanguageId)
{
return visitedLanguages.Contains(fallbackLanguageId);
}
private ILanguage GetLanguageById(int id)
{
return _localizationService.GetLanguageById(id);
}
private static bool ValueIsNotNullEmptyOrDefault<T>(T value, T defaultValue)
{
return value != null &&
string.IsNullOrEmpty(value.ToString()) == false &&
value.Equals(defaultValue) == false;
}
}
}

View File

@@ -153,18 +153,16 @@ namespace Umbraco.Web
/// <param name="culture">The variation language.</param>
/// <param name="segment">The variation segment.</param>
/// <param name="defaultValue">The default value.</param>
/// <param name="fallbackMethods">Options for fall-back if content not found.</param>
/// <param name="visitedLanguages">A list of cultures already visited in looking for a value via a fall-back method.</param>
/// <param name="fallback">Optional fallback strategy.</param>
/// <returns>The value of the content's property identified by the alias, if it exists, otherwise a default value.</returns>
public static object Value(this IPublishedContent content, string alias, string culture = null, string segment = null, object defaultValue = default,
int[] fallbackMethods = null, ICollection<int> 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<int>());
return PublishedValueFallback.GetValue(content, alias, culture, segment, defaultValue, fallback);
}
#endregion
@@ -180,24 +178,20 @@ namespace Umbraco.Web
/// <param name="culture">The variation language.</param>
/// <param name="segment">The variation segment.</param>
/// <param name="defaultValue">The default value.</param>
/// <param name="fallbackMethods">Options for fall-back if content not found.</param>
/// <param name="visitedLanguages">A list of cultures already visited in looking for a value via a fall-back method.</param>
/// <param name="fallback">Optional fallback strategy.</param>
/// <returns>The value of the content's property identified by the alias, converted to the specified type.</returns>
/// <remarks>
public static T Value<T>(this IPublishedContent content, string alias, string culture = null, string segment = null, T defaultValue = default,
int[] fallbackMethods = null, ICollection<int> visitedLanguages = null)
public static T Value<T>(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<T>(culture, segment);
return PublishedValueFallback.GetValue(content, alias, culture, segment, defaultValue, fallbackMethods, visitedLanguages ?? new List<int>());
return PublishedValueFallback.GetValue(content, alias, culture, segment, defaultValue, fallback);
}
// fixme - .Value() refactoring - in progress
public static IHtmlString Value<T>(this IPublishedContent content, string aliases, Func<T, string> format, string alt = "",
int[] fallbackMethods = null, ICollection<int> visitedLanguages = null)
public static IHtmlString Value<T>(this IPublishedContent content, string aliases, Func<T, string> format, string alt = "", int fallback = 0)
{
var aliasesA = aliases.Split(',');
if (aliasesA.Length == 0)

View File

@@ -100,7 +100,6 @@ namespace Umbraco.Web
/// <param name="culture">The variation language.</param>
/// <param name="segment">The variation segment.</param>
/// <param name="defaultValue">The default value.</param>
/// <param name="visitedLanguages">A list of cultures already visited in looking for a value via a fall-back method.</param>
/// <returns>The value of the content's property identified by the alias, if it exists, otherwise a default value.</returns>
/// <remarks>
/// <para>The value comes from <c>IPublishedProperty</c> field <c>Value</c> ie it is suitable for use when rendering content.</para>
@@ -108,14 +107,19 @@ namespace Umbraco.Web
/// <para>If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter.</para>
/// <para>The alias is case-insensitive.</para>
/// </remarks>
public static object Value(this IPublishedElement content, string alias, string culture = null, string segment = null, object defaultValue = default, ICollection<int> 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<int>());
// fixme defaultValue is a problem here
// assuming the value may return as an IEnumerable<int> 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
/// <param name="culture">The variation language.</param>
/// <param name="segment">The variation segment.</param>
/// <param name="defaultValue">The default value.</param>
/// <param name="visitedLanguages">A list of cultures already visited in looking for a value via a fall-back method.</param>
/// <returns>The value of the content's property identified by the alias, converted to the specified type.</returns>
/// <remarks>
/// <para>The value comes from <c>IPublishedProperty</c> field <c>Value</c> ie it is suitable for use when rendering content.</para>
@@ -139,14 +142,14 @@ namespace Umbraco.Web
/// <para>If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter.</para>
/// <para>The alias is case-insensitive.</para>
/// </remarks>
public static T Value<T>(this IPublishedElement content, string alias, string culture = null, string segment = null, T defaultValue = default, ICollection<int> visitedLanguages = null)
public static T Value<T>(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<T>(culture, segment);
return PublishedValueFallback.GetValue<T>(content, alias, culture, segment, defaultValue, visitedLanguages ?? new List<int>());
return PublishedValueFallback.GetValue<T>(content, alias, culture, segment, defaultValue);
}
#endregion

View File

@@ -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<int> 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<int>());
return PublishedValueFallback.GetValue(property, culture, segment, defaultValue);
}
#endregion

View File

@@ -199,7 +199,7 @@ namespace Umbraco.Web.Runtime
composition.Container.Register(_ => GlobalHost.ConnectionManager.GetHubContext<PreviewHub>(), new PerContainerLifetime());
// register properties fallback
composition.Container.RegisterSingleton<IPublishedValueFallback, PublishedValueLanguageFallback>();
composition.Container.RegisterSingleton<IPublishedValueFallback, PublishedValueFallback>();
}
internal void Initialize(

View File

@@ -263,7 +263,6 @@
<Compile Include="Models\Mapping\UserGroupDefaultPermissionsResolver.cs" />
<Compile Include="Models\Mapping\ContentItemDisplayVariationResolver.cs" />
<Compile Include="Models\PublishedContent\HttpContextVariationContextAccessor.cs" />
<Compile Include="Models\PublishedContent\PublishedValueLanguageFallback.cs" />
<Compile Include="Models\PublishedContent\PublishedValueFallback.cs" />
<Compile Include="Models\RelatedLink.cs" />
<Compile Include="Models\RelatedLinkBase.cs" />
@@ -838,7 +837,7 @@
<Compile Include="Models\LoginStatusModel.cs" />
<Compile Include="PropertyEditors\ValueConverters\MarkdownEditorValueConverter.cs" />
<Compile Include="PropertyEditors\ValueConverters\TextStringValueConverter.cs" />
<Compile Include="PublishedContentPropertyExtension.cs" />
<Compile Include="PublishedPropertyExtension.cs" />
<Compile Include="Models\UmbracoProperty.cs" />
<Compile Include="Mvc\MergeParentContextViewDataAttribute.cs" />
<Compile Include="Mvc\ViewDataDictionaryExtensions.cs" />

View File

@@ -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;
}