Removed unnecessary loop in looking up value from a fall-back language.

Put in a check to abort fall-back if there's a loop in language fall-backs.
This commit is contained in:
AndyButland
2018-07-21 09:41:07 +02:00
parent ecc75bc4c9
commit 695f21eadb
8 changed files with 127 additions and 98 deletions

View File

@@ -1,4 +1,5 @@
using Umbraco.Core.Models;
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
@@ -21,72 +22,72 @@ namespace Umbraco.Web.Models.PublishedContent
}
/// <inheritdoc />
public override object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue)
public override object GetValue(IPublishedProperty property, string culture, string segment, object defaultValue, ICollection<int> visitedLanguages)
{
object value;
if (TryGetValueFromFallbackLanguage(property, culture, segment, defaultValue, out value))
if (TryGetValueFromFallbackLanguage(property, culture, segment, defaultValue, visitedLanguages, out value))
{
return value;
}
return base.GetValue(property, culture, segment, defaultValue);
return base.GetValue(property, culture, segment, defaultValue, visitedLanguages);
}
/// <inheritdoc />
public override T GetValue<T>(IPublishedProperty property, string culture, string segment, T defaultValue)
public override T GetValue<T>(IPublishedProperty property, string culture, string segment, T defaultValue, ICollection<int> visitedLanguages)
{
T value;
if (TryGetValueFromFallbackLanguage(property, culture, segment, defaultValue, out value))
if (TryGetValueFromFallbackLanguage(property, culture, segment, defaultValue, visitedLanguages, out value))
{
return value;
}
return base.GetValue(property, culture, segment, defaultValue);
return base.GetValue(property, culture, segment, defaultValue, visitedLanguages);
}
/// <inheritdoc />
public override object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue)
public override object GetValue(IPublishedElement content, string alias, string culture, string segment, object defaultValue, ICollection<int> visitedLanguages)
{
object value;
if (TryGetValueFromFallbackLanguage(content, alias, culture, segment, defaultValue, out value))
if (TryGetValueFromFallbackLanguage(content, alias, culture, segment, defaultValue, visitedLanguages, out value))
{
return value;
}
return base.GetValue(content, alias, culture, segment, defaultValue);
return base.GetValue(content, alias, culture, segment, defaultValue, visitedLanguages);
}
/// <inheritdoc />
public override T GetValue<T>(IPublishedElement content, string alias, string culture, string segment, T defaultValue)
public override T GetValue<T>(IPublishedElement content, string alias, string culture, string segment, T defaultValue, ICollection<int> visitedLanguages)
{
T value;
if (TryGetValueFromFallbackLanguage(content, alias, culture, segment, defaultValue, out value))
if (TryGetValueFromFallbackLanguage(content, alias, culture, segment, defaultValue, visitedLanguages, out value))
{
return value;
}
return base.GetValue(content, alias, culture, segment, defaultValue);
return base.GetValue(content, alias, culture, segment, defaultValue, visitedLanguages);
}
/// <inheritdoc />
public override object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, bool recurse, PublishedValueFallbackPriority fallbackPriority)
public override object GetValue(IPublishedContent content, string alias, string culture, string segment, object defaultValue, bool recurse, PublishedValueFallbackPriority fallbackPriority, ICollection<int> visitedLanguages)
{
return GetValue<object>(content, alias, culture, segment, defaultValue, recurse, fallbackPriority);
return GetValue<object>(content, alias, culture, segment, defaultValue, recurse, fallbackPriority, visitedLanguages);
}
/// <inheritdoc />
public override T GetValue<T>(IPublishedContent content, string alias, string culture, string segment, T defaultValue, bool recurse, PublishedValueFallbackPriority fallbackPriority)
public override T GetValue<T>(IPublishedContent content, string alias, string culture, string segment, T defaultValue, bool recurse, PublishedValueFallbackPriority fallbackPriority, ICollection<int> visitedLanguages)
{
if (fallbackPriority == PublishedValueFallbackPriority.RecursiveTree)
{
var result = base.GetValue<T>(content, alias, culture, segment, defaultValue, recurse, PublishedValueFallbackPriority.RecursiveTree);
var result = base.GetValue<T>(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, out result))
if (TryGetValueFromFallbackLanguage(content, alias, culture, segment, defaultValue, recurse, fallbackPriority, visitedLanguages, out result))
{
return result;
}
@@ -97,112 +98,116 @@ namespace Umbraco.Web.Models.PublishedContent
if (fallbackPriority == PublishedValueFallbackPriority.FallbackLanguage)
{
T result;
if (TryGetValueFromFallbackLanguage(content, alias, culture, segment, defaultValue, recurse, out 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<T>(content, alias, culture, segment, defaultValue, recurse, fallbackPriority);
return base.GetValue<T>(content, alias, culture, segment, defaultValue, recurse, fallbackPriority, visitedLanguages);
}
private bool TryGetValueFromFallbackLanguage<T>(IPublishedProperty property, string culture, string segment, T defaultValue, out T value)
private bool TryGetValueFromFallbackLanguage<T>(IPublishedProperty property, string culture, string segment, T defaultValue, ICollection<int> visitedLanguages, out T value)
{
value = defaultValue;
if (string.IsNullOrEmpty(culture))
{
value = defaultValue;
return false;
}
var language = _localizationService.GetLanguageByIsoCode(culture);
if (language.FallbackLanguageId.HasValue == false)
{
value = defaultValue;
return false;
}
var fallbackLanguageId = language.FallbackLanguageId;
while (fallbackLanguageId.HasValue)
if (AlreadyVisitedLanguage(visitedLanguages, language.FallbackLanguageId.Value))
{
var fallbackLanguage = GetLanguageById(fallbackLanguageId.Value);
value = property.Value(fallbackLanguage.IsoCode, segment, defaultValue);
if (ValueIsNotNullEmptyOrDefault(value, defaultValue))
{
return true;
}
fallbackLanguageId = fallbackLanguage.FallbackLanguageId;
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;
}
value = defaultValue;
return false;
}
private bool TryGetValueFromFallbackLanguage<T>(IPublishedElement content, string alias, string culture, string segment, T defaultValue, out T value)
private bool TryGetValueFromFallbackLanguage<T>(IPublishedElement content, string alias, string culture, string segment, T defaultValue, ICollection<int> visitedLanguages, out T value)
{
value = defaultValue;
if (string.IsNullOrEmpty(culture))
{
value = defaultValue;
return false;
}
var language = _localizationService.GetLanguageByIsoCode(culture);
if (language.FallbackLanguageId.HasValue == false)
{
value = defaultValue;
return false;
}
var fallbackLanguageId = language.FallbackLanguageId;
while (fallbackLanguageId.HasValue)
if (AlreadyVisitedLanguage(visitedLanguages, language.FallbackLanguageId.Value))
{
var fallbackLanguage = GetLanguageById(fallbackLanguageId.Value);
value = content.Value(alias, fallbackLanguage.IsoCode, segment, defaultValue);
if (ValueIsNotNullEmptyOrDefault(value, defaultValue))
{
return true;
}
fallbackLanguageId = fallbackLanguage.FallbackLanguageId;
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;
}
value = defaultValue;
return false;
}
private bool TryGetValueFromFallbackLanguage<T>(IPublishedContent content, string alias, string culture, string segment, T defaultValue, bool recurse, out T value)
private bool TryGetValueFromFallbackLanguage<T>(IPublishedContent content, string alias, string culture, string segment, T defaultValue, bool recurse, PublishedValueFallbackPriority fallbackPriority, ICollection<int> visitedLanguages, out T value)
{
value = defaultValue;
if (string.IsNullOrEmpty(culture))
{
value = defaultValue;
return false;
}
var language = _localizationService.GetLanguageByIsoCode(culture);
if (language.FallbackLanguageId.HasValue == false)
{
value = defaultValue;
return false;
}
var fallbackLanguageId = language.FallbackLanguageId;
while (fallbackLanguageId.HasValue)
if (AlreadyVisitedLanguage(visitedLanguages, language.FallbackLanguageId.Value))
{
var fallbackLanguage = GetLanguageById(fallbackLanguageId.Value);
value = content.Value(alias, fallbackLanguage.IsoCode, segment, defaultValue, recurse);
if (ValueIsNotNullEmptyOrDefault(value, defaultValue))
{
return true;
}
fallbackLanguageId = fallbackLanguage.FallbackLanguageId;
return false;
}
visitedLanguages.Add(language.FallbackLanguageId.Value);
var fallbackLanguage = GetLanguageById(language.FallbackLanguageId.Value);
value = content.Value(alias, fallbackLanguage.IsoCode, segment, defaultValue, recurse, fallbackPriority, visitedLanguages);
if (ValueIsNotNullEmptyOrDefault(value, defaultValue))
{
return true;
}
value = defaultValue;
return false;
}
private static bool AlreadyVisitedLanguage(ICollection<int> visitedLanguages, int fallbackLanguageId)
{
return visitedLanguages.Contains(fallbackLanguageId);
}
private ILanguage GetLanguageById(int id)
{
return _localizationService.GetLanguageById(id);