Merge remote-tracking branch 'origin/v10/dev' into v11/dev

This commit is contained in:
Bjarke Berg
2023-11-14 09:29:59 +01:00
13 changed files with 294 additions and 98 deletions

View File

@@ -9,15 +9,22 @@ namespace Umbraco.Cms.Core.PropertyEditors;
/// </summary> /// </summary>
public class DefaultPropertyIndexValueFactory : IPropertyIndexValueFactory public class DefaultPropertyIndexValueFactory : IPropertyIndexValueFactory
{ {
/// <inheritdoc /> public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published,
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published, IEnumerable<string> availableCultures) IEnumerable<string> availableCultures, IDictionary<Guid, IContentType> contentTypeDictionary)
{ {
yield return new KeyValuePair<string, IEnumerable<object?>>( yield return new KeyValuePair<string, IEnumerable<object?>>(
property.Alias, property.Alias,
property.GetValue(culture, segment, published).Yield()); property.GetValue(culture, segment, published).Yield());
} }
[Obsolete("Use the overload with the availableCultures parameter instead, scheduled for removal in v14")] /// <inheritdoc />
[Obsolete("Use the non-obsolete overload, scheduled for removal in v14")]
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture,
string? segment, bool published, IEnumerable<string> availableCultures)
=> GetIndexValues(property, culture, segment, published, availableCultures,
new Dictionary<Guid, IContentType>());
[Obsolete("Use the non-obsolete overload, scheduled for removal in v14")]
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published) public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published)
=> GetIndexValues(property, culture, segment, published, Enumerable.Empty<string>()); => GetIndexValues(property, culture, segment, published, Enumerable.Empty<string>(), new Dictionary<Guid, IContentType>());
} }

View File

@@ -22,9 +22,14 @@ public interface IPropertyIndexValueFactory
/// more than one value for a given field. /// more than one value for a given field.
/// </para> /// </para>
/// </remarks> /// </remarks>
IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture,
string? segment, bool published, IEnumerable<string> availableCultures,
IDictionary<Guid, IContentType> contentTypeDictionary) => GetIndexValues(property, culture, segment, published);
[Obsolete("Use non-obsolete overload, scheduled for removal in v14")]
IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published, IEnumerable<string> availableCultures) IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published, IEnumerable<string> availableCultures)
=> GetIndexValues(property, culture, segment, published); => GetIndexValues(property, culture, segment, published);
[Obsolete("Use the overload with the availableCultures parameter instead, scheduled for removal in v14")] [Obsolete("Use non-obsolete overload, scheduled for removal in v14")]
IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published); IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published);
} }

View File

@@ -3,6 +3,7 @@ using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions; using Umbraco.Extensions;
@@ -39,13 +40,13 @@ public abstract class JsonPropertyIndexValueFactoryBase<TSerialized> : IProperty
} }
/// <inheritdoc />
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues( public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(
IProperty property, IProperty property,
string? culture, string? culture,
string? segment, string? segment,
bool published, bool published,
IEnumerable<string> availableCultures) IEnumerable<string> availableCultures,
IDictionary<Guid, IContentType> contentTypeDictionary)
{ {
var result = new List<KeyValuePair<string, IEnumerable<object?>>>(); var result = new List<KeyValuePair<string, IEnumerable<object?>>>();
@@ -63,7 +64,7 @@ public abstract class JsonPropertyIndexValueFactoryBase<TSerialized> : IProperty
return result; return result;
} }
result.AddRange(Handle(deserializedPropertyValue, property, culture, segment, published, availableCultures)); result.AddRange(Handle(deserializedPropertyValue, property, culture, segment, published, availableCultures, contentTypeDictionary));
} }
catch (InvalidCastException) catch (InvalidCastException)
{ {
@@ -87,9 +88,31 @@ public abstract class JsonPropertyIndexValueFactoryBase<TSerialized> : IProperty
return summary; return summary;
} }
/// <inheritdoc />
[Obsolete("Use non-obsolete constructor. This will be removed in Umbraco 14.")]
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(
IProperty property,
string? culture,
string? segment,
bool published,
IEnumerable<string> availableCultures)
=> GetIndexValues(
property,
culture,
segment,
published,
Enumerable.Empty<string>(),
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>().GetAll().ToDictionary(x=>x.Key));
[Obsolete("Use method overload that has availableCultures, scheduled for removal in v14")] [Obsolete("Use method overload that has availableCultures, scheduled for removal in v14")]
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published) public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published)
=> GetIndexValues(property, culture, segment, published, Enumerable.Empty<string>()); => GetIndexValues(
property,
culture,
segment,
published,
Enumerable.Empty<string>(),
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>().GetAll().ToDictionary(x=>x.Key));
/// <summary> /// <summary>
/// Method to return a list of summary of the content. By default this returns an empty list /// Method to return a list of summary of the content. By default this returns an empty list
@@ -104,7 +127,7 @@ public abstract class JsonPropertyIndexValueFactoryBase<TSerialized> : IProperty
/// <summary> /// <summary>
/// Method that handle the deserialized object. /// Method that handle the deserialized object.
/// </summary> /// </summary>
[Obsolete("Use the overload with the availableCultures parameter instead, scheduled for removal in v14")] [Obsolete("Use the non-obsolete overload instead, scheduled for removal in v14")]
protected abstract IEnumerable<KeyValuePair<string, IEnumerable<object?>>> Handle( protected abstract IEnumerable<KeyValuePair<string, IEnumerable<object?>>> Handle(
TSerialized deserializedPropertyValue, TSerialized deserializedPropertyValue,
IProperty property, IProperty property,
@@ -112,6 +135,15 @@ public abstract class JsonPropertyIndexValueFactoryBase<TSerialized> : IProperty
string? segment, string? segment,
bool published); bool published);
[Obsolete("Use the non-obsolete overload instead, scheduled for removal in v14")]
protected virtual IEnumerable<KeyValuePair<string, IEnumerable<object?>>> Handle(
TSerialized deserializedPropertyValue,
IProperty property,
string? culture,
string? segment,
bool published,
IEnumerable<string> availableCultures) => Handle(deserializedPropertyValue, property, culture, segment, published);
/// <summary> /// <summary>
/// Method that handle the deserialized object. /// Method that handle the deserialized object.
/// </summary> /// </summary>
@@ -121,6 +153,7 @@ public abstract class JsonPropertyIndexValueFactoryBase<TSerialized> : IProperty
string? culture, string? culture,
string? segment, string? segment,
bool published, bool published,
IEnumerable<string> availableCultures) => IEnumerable<string> availableCultures,
Handle(deserializedPropertyValue, property, culture, segment, published); IDictionary<Guid, IContentType> contentTypeDictionary)
=> Handle(deserializedPropertyValue, property, culture, segment, published, availableCultures);
} }

View File

@@ -8,6 +8,12 @@ namespace Umbraco.Cms.Core.PropertyEditors;
public class NoopPropertyIndexValueFactory : IPropertyIndexValueFactory public class NoopPropertyIndexValueFactory : IPropertyIndexValueFactory
{ {
/// <inheritdoc /> /// <inheritdoc />
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published,
IEnumerable<string> availableCultures, IDictionary<Guid, IContentType> contentTypeDictionary)
=> Array.Empty<KeyValuePair<string, IEnumerable<object?>>>();
[Obsolete("Use the overload with the availableCultures parameter instead, scheduled for removal in v14")]
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published, IEnumerable<string> availableCultures) => Array.Empty<KeyValuePair<string, IEnumerable<object?>>>(); public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published, IEnumerable<string> availableCultures) => Array.Empty<KeyValuePair<string, IEnumerable<object?>>>();
[Obsolete("Use the overload with the availableCultures parameter instead, scheduled for removal in v14")] [Obsolete("Use the overload with the availableCultures parameter instead, scheduled for removal in v14")]

View File

@@ -1,6 +1,9 @@
using Examine; using Examine;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions; using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Examine; namespace Umbraco.Cms.Infrastructure.Examine;
@@ -24,9 +27,26 @@ public abstract class BaseValueSetBuilder<TContent> : IValueSetBuilder<TContent>
[Obsolete("Use the overload that specifies availableCultures, scheduled for removal in v14")] [Obsolete("Use the overload that specifies availableCultures, scheduled for removal in v14")]
protected void AddPropertyValue(IProperty property, string? culture, string? segment, IDictionary<string, IEnumerable<object?>>? values) protected void AddPropertyValue(IProperty property, string? culture, string? segment, IDictionary<string, IEnumerable<object?>>? values)
=> AddPropertyValue(property, culture, segment, values, Enumerable.Empty<string>()); => AddPropertyValue(
property,
culture,
segment,
values,
Enumerable.Empty<string>(),
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>().GetAll().ToDictionary(x=>x.Key));
protected void AddPropertyValue(IProperty property, string? culture, string? segment, IDictionary<string, IEnumerable<object?>>? values, IEnumerable<string> availableCultures) [Obsolete("Use the overload that specifies availableCultures, scheduled for removal in v14")]
protected void AddPropertyValue(IProperty property, string? culture, string? segment,
IDictionary<string, IEnumerable<object?>>? values, IEnumerable<string> availableCultures)
=> AddPropertyValue(
property,
culture,
segment,
values,
Enumerable.Empty<string>(),
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>().GetAll().ToDictionary(x=>x.Key));
protected void AddPropertyValue(IProperty property, string? culture, string? segment, IDictionary<string, IEnumerable<object?>>? values, IEnumerable<string> availableCultures, IDictionary<Guid, IContentType> contentTypeDictionary)
{ {
IDataEditor? editor = _propertyEditors[property.PropertyType.PropertyEditorAlias]; IDataEditor? editor = _propertyEditors[property.PropertyType.PropertyEditorAlias];
if (editor == null) if (editor == null)
@@ -35,7 +55,7 @@ public abstract class BaseValueSetBuilder<TContent> : IValueSetBuilder<TContent>
} }
IEnumerable<KeyValuePair<string, IEnumerable<object?>>> indexVals = IEnumerable<KeyValuePair<string, IEnumerable<object?>>> indexVals =
editor.PropertyIndexValueFactory.GetIndexValues(property, culture, segment, PublishedValuesOnly, availableCultures); editor.PropertyIndexValueFactory.GetIndexValues(property, culture, segment, PublishedValuesOnly, availableCultures, contentTypeDictionary);
foreach (KeyValuePair<string, IEnumerable<object?>> keyVal in indexVals) foreach (KeyValuePair<string, IEnumerable<object?>> keyVal in indexVals)
{ {
if (keyVal.Key.IsNullOrWhiteSpace()) if (keyVal.Key.IsNullOrWhiteSpace())

View File

@@ -21,13 +21,34 @@ public class ContentValueSetBuilder : BaseValueSetBuilder<IContent>, IContentVal
private static readonly object[] NoValue = new[] { "n" }; private static readonly object[] NoValue = new[] { "n" };
private static readonly object[] YesValue = new[] { "y" }; private static readonly object[] YesValue = new[] { "y" };
private readonly IScopeProvider _scopeProvider; private readonly ICoreScopeProvider _scopeProvider;
private readonly IShortStringHelper _shortStringHelper; private readonly IShortStringHelper _shortStringHelper;
private readonly UrlSegmentProviderCollection _urlSegmentProviders; private readonly UrlSegmentProviderCollection _urlSegmentProviders;
private readonly IUserService _userService; private readonly IUserService _userService;
private readonly ILocalizationService _localizationService; private readonly ILocalizationService _localizationService;
private readonly IContentTypeService _contentTypeService;
public ContentValueSetBuilder(
PropertyEditorCollection propertyEditors,
UrlSegmentProviderCollection urlSegmentProviders,
IUserService userService,
IShortStringHelper shortStringHelper,
ICoreScopeProvider scopeProvider,
bool publishedValuesOnly,
ILocalizationService localizationService,
IContentTypeService contentTypeService)
: base(propertyEditors, publishedValuesOnly)
{
_urlSegmentProviders = urlSegmentProviders;
_userService = userService;
_shortStringHelper = shortStringHelper;
_scopeProvider = scopeProvider;
_localizationService = localizationService;
_contentTypeService = contentTypeService;
}
[Obsolete("Use non-obsolete ctor, scheduled for removal in v14")]
public ContentValueSetBuilder( public ContentValueSetBuilder(
PropertyEditorCollection propertyEditors, PropertyEditorCollection propertyEditors,
UrlSegmentProviderCollection urlSegmentProviders, UrlSegmentProviderCollection urlSegmentProviders,
@@ -36,16 +57,20 @@ public class ContentValueSetBuilder : BaseValueSetBuilder<IContent>, IContentVal
IScopeProvider scopeProvider, IScopeProvider scopeProvider,
bool publishedValuesOnly, bool publishedValuesOnly,
ILocalizationService localizationService) ILocalizationService localizationService)
: base(propertyEditors, publishedValuesOnly) : this(
propertyEditors,
urlSegmentProviders,
userService,
shortStringHelper,
scopeProvider,
publishedValuesOnly,
localizationService,
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>())
{ {
_urlSegmentProviders = urlSegmentProviders;
_userService = userService;
_shortStringHelper = shortStringHelper;
_scopeProvider = scopeProvider;
_localizationService = localizationService;
} }
[Obsolete("Use the constructor that takes an ILocalizationService, scheduled for removal in v14")] [Obsolete("Use non-obsolete ctor, scheduled for removal in v14")]
public ContentValueSetBuilder( public ContentValueSetBuilder(
PropertyEditorCollection propertyEditors, PropertyEditorCollection propertyEditors,
UrlSegmentProviderCollection urlSegmentProviders, UrlSegmentProviderCollection urlSegmentProviders,
@@ -60,7 +85,8 @@ public class ContentValueSetBuilder : BaseValueSetBuilder<IContent>, IContentVal
shortStringHelper, shortStringHelper,
scopeProvider, scopeProvider,
publishedValuesOnly, publishedValuesOnly,
StaticServiceProvider.Instance.GetRequiredService<ILocalizationService>()) StaticServiceProvider.Instance.GetRequiredService<ILocalizationService>(),
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>())
{ {
} }
@@ -72,7 +98,7 @@ public class ContentValueSetBuilder : BaseValueSetBuilder<IContent>, IContentVal
// We can lookup all of the creator/writer names at once which can save some // We can lookup all of the creator/writer names at once which can save some
// processing below instead of one by one. // processing below instead of one by one.
using (IScope scope = _scopeProvider.CreateScope()) using (ICoreScope scope = _scopeProvider.CreateCoreScope())
{ {
creatorIds = _userService.GetProfilesById(content.Select(x => x.CreatorId).ToArray()) creatorIds = _userService.GetProfilesById(content.Select(x => x.CreatorId).ToArray())
.ToDictionary(x => x.Id, x => x); .ToDictionary(x => x.Id, x => x);
@@ -86,6 +112,8 @@ public class ContentValueSetBuilder : BaseValueSetBuilder<IContent>, IContentVal
private IEnumerable<ValueSet> GetValueSetsEnumerable(IContent[] content, Dictionary<int, IProfile> creatorIds, Dictionary<int, IProfile> writerIds) private IEnumerable<ValueSet> GetValueSetsEnumerable(IContent[] content, Dictionary<int, IProfile> creatorIds, Dictionary<int, IProfile> writerIds)
{ {
IDictionary<Guid, IContentType> contentTypeDictionary = _contentTypeService.GetAll().ToDictionary(x => x.Key);
// TODO: There is a lot of boxing going on here and ultimately all values will be boxed by Lucene anyways // TODO: There is a lot of boxing going on here and ultimately all values will be boxed by Lucene anyways
// but I wonder if there's a way to reduce the boxing that we have to do or if it will matter in the end since // but I wonder if there's a way to reduce the boxing that we have to do or if it will matter in the end since
// Lucene will do it no matter what? One idea was to create a `FieldValue` struct which would contain `object`, `object[]`, `ValueType` and `ValueType[]` // Lucene will do it no matter what? One idea was to create a `FieldValue` struct which would contain `object`, `object[]`, `ValueType` and `ValueType[]`
@@ -162,13 +190,13 @@ public class ContentValueSetBuilder : BaseValueSetBuilder<IContent>, IContentVal
{ {
if (!property.PropertyType.VariesByCulture()) if (!property.PropertyType.VariesByCulture())
{ {
AddPropertyValue(property, null, null, values, availableCultures); AddPropertyValue(property, null, null, values, availableCultures, contentTypeDictionary);
} }
else else
{ {
foreach (var culture in c.AvailableCultures) foreach (var culture in c.AvailableCultures)
{ {
AddPropertyValue(property, culture.ToLowerInvariant(), null, values, availableCultures); AddPropertyValue(property, culture.ToLowerInvariant(), null, values, availableCultures, contentTypeDictionary);
} }
} }
} }

View File

@@ -1,10 +1,12 @@
using Examine; using Examine;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions; using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Examine; namespace Umbraco.Cms.Infrastructure.Examine;
@@ -14,6 +16,7 @@ public class MediaValueSetBuilder : BaseValueSetBuilder<IMedia>
private readonly ContentSettings _contentSettings; private readonly ContentSettings _contentSettings;
private readonly MediaUrlGeneratorCollection _mediaUrlGenerators; private readonly MediaUrlGeneratorCollection _mediaUrlGenerators;
private readonly IShortStringHelper _shortStringHelper; private readonly IShortStringHelper _shortStringHelper;
private readonly IContentTypeService _contentTypeService;
private readonly UrlSegmentProviderCollection _urlSegmentProviders; private readonly UrlSegmentProviderCollection _urlSegmentProviders;
private readonly IUserService _userService; private readonly IUserService _userService;
@@ -23,19 +26,41 @@ public class MediaValueSetBuilder : BaseValueSetBuilder<IMedia>
MediaUrlGeneratorCollection mediaUrlGenerators, MediaUrlGeneratorCollection mediaUrlGenerators,
IUserService userService, IUserService userService,
IShortStringHelper shortStringHelper, IShortStringHelper shortStringHelper,
IOptions<ContentSettings> contentSettings) IOptions<ContentSettings> contentSettings,
IContentTypeService contentTypeService)
: base(propertyEditors, false) : base(propertyEditors, false)
{ {
_urlSegmentProviders = urlSegmentProviders; _urlSegmentProviders = urlSegmentProviders;
_mediaUrlGenerators = mediaUrlGenerators; _mediaUrlGenerators = mediaUrlGenerators;
_userService = userService; _userService = userService;
_shortStringHelper = shortStringHelper; _shortStringHelper = shortStringHelper;
_contentTypeService = contentTypeService;
_contentSettings = contentSettings.Value; _contentSettings = contentSettings.Value;
} }
[Obsolete("Use non-obsolete ctor, scheduled for removal in v14")]
public MediaValueSetBuilder(
PropertyEditorCollection propertyEditors,
UrlSegmentProviderCollection urlSegmentProviders,
MediaUrlGeneratorCollection mediaUrlGenerators,
IUserService userService,
IShortStringHelper shortStringHelper,
IOptions<ContentSettings> contentSettings)
: this(propertyEditors,
urlSegmentProviders,
mediaUrlGenerators,
userService,
shortStringHelper,
contentSettings,
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>())
{
}
/// <inheritdoc /> /// <inheritdoc />
public override IEnumerable<ValueSet> GetValueSets(params IMedia[] media) public override IEnumerable<ValueSet> GetValueSets(params IMedia[] media)
{ {
IDictionary<Guid, IContentType> contentTypeDictionary = _contentTypeService.GetAll().ToDictionary(x => x.Key);
foreach (IMedia m in media) foreach (IMedia m in media)
{ {
var urlValue = m.GetUrlSegment(_shortStringHelper, _urlSegmentProviders); var urlValue = m.GetUrlSegment(_shortStringHelper, _urlSegmentProviders);
@@ -65,7 +90,7 @@ public class MediaValueSetBuilder : BaseValueSetBuilder<IMedia>
foreach (IProperty property in m.Properties) foreach (IProperty property in m.Properties)
{ {
AddPropertyValue(property, null, null, values, m.AvailableCultures); AddPropertyValue(property, null, null, values, m.AvailableCultures, contentTypeDictionary);
} }
var vs = new ValueSet(m.Id.ToInvariantString(), IndexTypes.Media, m.ContentType.Alias, values); var vs = new ValueSet(m.Id.ToInvariantString(), IndexTypes.Media, m.ContentType.Alias, values);

View File

@@ -1,20 +1,34 @@
using Examine; using Examine;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions; using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Examine; namespace Umbraco.Cms.Infrastructure.Examine;
public class MemberValueSetBuilder : BaseValueSetBuilder<IMember> public class MemberValueSetBuilder : BaseValueSetBuilder<IMember>
{ {
public MemberValueSetBuilder(PropertyEditorCollection propertyEditors) private readonly IContentTypeService _contentTypeService;
public MemberValueSetBuilder(PropertyEditorCollection propertyEditors, IContentTypeService contentTypeService)
: base(propertyEditors, false) : base(propertyEditors, false)
{
_contentTypeService = contentTypeService;
}
[Obsolete("Use non-obsolete ctor, scheduled for removal in v14")]
public MemberValueSetBuilder(PropertyEditorCollection propertyEditors)
: this(propertyEditors, StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>())
{ {
} }
/// <inheritdoc /> /// <inheritdoc />
public override IEnumerable<ValueSet> GetValueSets(params IMember[] members) public override IEnumerable<ValueSet> GetValueSets(params IMember[] members)
{ {
IDictionary<Guid, IContentType> contentTypeDictionary = _contentTypeService.GetAll().ToDictionary(x => x.Key);
foreach (IMember m in members) foreach (IMember m in members)
{ {
var values = new Dictionary<string, IEnumerable<object?>> var values = new Dictionary<string, IEnumerable<object?>>
@@ -37,7 +51,7 @@ public class MemberValueSetBuilder : BaseValueSetBuilder<IMember>
foreach (IProperty property in m.Properties) foreach (IProperty property in m.Properties)
{ {
AddPropertyValue(property, null, null, values, m.AvailableCultures); AddPropertyValue(property, null, null, values, m.AvailableCultures, contentTypeDictionary);
} }
var vs = new ValueSet(m.Id.ToInvariantString(), IndexTypes.Member, m.ContentType.Alias, values); var vs = new ValueSet(m.Id.ToInvariantString(), IndexTypes.Member, m.ContentType.Alias, values);

View File

@@ -38,10 +38,13 @@ internal sealed class BlockValuePropertyIndexValueFactory :
_contentTypeService = contentTypeService; _contentTypeService = contentTypeService;
} }
[Obsolete("Use non-obsolete overload, scheduled for removal in v14")]
protected override IContentType? GetContentTypeOfNestedItem(BlockItemData input) => protected override IContentType? GetContentTypeOfNestedItem(BlockItemData input) =>
_contentTypeService.Get(input.ContentTypeKey); _contentTypeService.Get(input.ContentTypeKey);
protected override IContentType? GetContentTypeOfNestedItem(BlockItemData input, IDictionary<Guid, IContentType> contentTypeDictionary)
=> contentTypeDictionary.TryGetValue(input.ContentTypeKey, out var result) ? result : null;
protected override IDictionary<string, object?> GetRawProperty(BlockItemData blockItemData) => protected override IDictionary<string, object?> GetRawProperty(BlockItemData blockItemData) =>
blockItemData.RawPropertyValues; blockItemData.RawPropertyValues;

View File

@@ -2,19 +2,20 @@
// See LICENSE for more details. // See LICENSE for more details.
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json; using Newtonsoft.Json;
using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing; using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.Models.Editors; using Umbraco.Cms.Core.Models.Editors;
using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Core.Strings;
using Umbraco.Extensions; using Umbraco.Cms.Web.Common.DependencyInjection;
namespace Umbraco.Cms.Core.PropertyEditors; namespace Umbraco.Cms.Core.PropertyEditors;
@@ -26,11 +27,57 @@ public class MultiUrlPickerValueEditor : DataValueEditor, IDataValueReference
NullValueHandling = NullValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore,
}; };
private readonly IEntityService _entityService;
private readonly ILogger<MultiUrlPickerValueEditor> _logger; private readonly ILogger<MultiUrlPickerValueEditor> _logger;
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
private readonly IPublishedUrlProvider _publishedUrlProvider; private readonly IPublishedUrlProvider _publishedUrlProvider;
private readonly IContentService _contentService;
private readonly IMediaService _mediaService;
public MultiUrlPickerValueEditor(
ILogger<MultiUrlPickerValueEditor> logger,
ILocalizedTextService localizedTextService,
IShortStringHelper shortStringHelper,
DataEditorAttribute attribute,
IPublishedUrlProvider publishedUrlProvider,
IJsonSerializer jsonSerializer,
IIOHelper ioHelper,
IContentService contentService,
IMediaService mediaService)
: base(localizedTextService, shortStringHelper, jsonSerializer, ioHelper, attribute)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_publishedUrlProvider = publishedUrlProvider;
_contentService = contentService;
_mediaService = mediaService;
}
[Obsolete("Use non-obsolete constructor. Scheduled for removal in Umbraco 14.")]
public MultiUrlPickerValueEditor(
IEntityService entityService,
IPublishedSnapshotAccessor publishedSnapshotAccessor,
ILogger<MultiUrlPickerValueEditor> logger,
ILocalizedTextService localizedTextService,
IShortStringHelper shortStringHelper,
DataEditorAttribute attribute,
IPublishedUrlProvider publishedUrlProvider,
IJsonSerializer jsonSerializer,
IIOHelper ioHelper,
IContentService contentService,
IMediaService mediaService)
:this(
logger,
localizedTextService,
shortStringHelper,
attribute,
publishedUrlProvider,
jsonSerializer,
ioHelper,
contentService,
mediaService)
{
}
[Obsolete("Use non-obsolete constructor. Scheduled for removal in Umbraco 14.")]
public MultiUrlPickerValueEditor( public MultiUrlPickerValueEditor(
IEntityService entityService, IEntityService entityService,
IPublishedSnapshotAccessor publishedSnapshotAccessor, IPublishedSnapshotAccessor publishedSnapshotAccessor,
@@ -41,13 +88,18 @@ public class MultiUrlPickerValueEditor : DataValueEditor, IDataValueReference
IPublishedUrlProvider publishedUrlProvider, IPublishedUrlProvider publishedUrlProvider,
IJsonSerializer jsonSerializer, IJsonSerializer jsonSerializer,
IIOHelper ioHelper) IIOHelper ioHelper)
: base(localizedTextService, shortStringHelper, jsonSerializer, ioHelper, attribute) : this(
logger,
localizedTextService,
shortStringHelper,
attribute,
publishedUrlProvider,
jsonSerializer,
ioHelper,
StaticServiceProvider.Instance.GetRequiredService<IContentService>(),
StaticServiceProvider.Instance.GetRequiredService<IMediaService>())
{ {
_entityService = entityService ?? throw new ArgumentNullException(nameof(entityService));
_publishedSnapshotAccessor = publishedSnapshotAccessor ??
throw new ArgumentNullException(nameof(publishedSnapshotAccessor));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_publishedUrlProvider = publishedUrlProvider;
} }
public IEnumerable<UmbracoEntityReference> GetReferences(object? value) public IEnumerable<UmbracoEntityReference> GetReferences(object? value)
@@ -86,26 +138,6 @@ public class MultiUrlPickerValueEditor : DataValueEditor, IDataValueReference
{ {
List<LinkDto>? links = JsonConvert.DeserializeObject<List<LinkDto>>(value); List<LinkDto>? links = JsonConvert.DeserializeObject<List<LinkDto>>(value);
List<LinkDto>? documentLinks = links?.FindAll(link =>
link.Udi != null && link.Udi.EntityType == Constants.UdiEntityType.Document);
List<LinkDto>? mediaLinks = links?.FindAll(link =>
link.Udi != null && link.Udi.EntityType == Constants.UdiEntityType.Media);
var entities = new List<IEntitySlim>();
if (documentLinks?.Count > 0)
{
entities.AddRange(
_entityService.GetAll(
UmbracoObjectTypes.Document,
documentLinks.Select(link => link.Udi!.Guid).ToArray()));
}
if (mediaLinks?.Count > 0)
{
entities.AddRange(
_entityService.GetAll(UmbracoObjectTypes.Media, mediaLinks.Select(link => link.Udi!.Guid).ToArray()));
}
var result = new List<LinkDisplay>(); var result = new List<LinkDisplay>();
if (links is null) if (links is null)
{ {
@@ -114,7 +146,7 @@ public class MultiUrlPickerValueEditor : DataValueEditor, IDataValueReference
foreach (LinkDto dto in links) foreach (LinkDto dto in links)
{ {
GuidUdi? udi = null; GuidUdi? udi = dto.Udi;
var icon = "icon-link"; var icon = "icon-link";
var published = true; var published = true;
var trashed = false; var trashed = false;
@@ -122,35 +154,30 @@ public class MultiUrlPickerValueEditor : DataValueEditor, IDataValueReference
if (dto.Udi != null) if (dto.Udi != null)
{ {
IUmbracoEntity? entity = entities.Find(e => e.Key == dto.Udi.Guid); if (dto.Udi.EntityType == Constants.UdiEntityType.Document)
if (entity == null)
{ {
continue; url = _publishedUrlProvider.GetUrl(dto.Udi.Guid, UrlMode.Relative, culture);
} IContent? c = _contentService.GetById(dto.Udi.Guid);
IPublishedSnapshot publishedSnapshot = _publishedSnapshotAccessor.GetRequiredPublishedSnapshot(); if (c is not null)
if (entity is IDocumentEntitySlim documentEntity) {
{ published = culture == null
icon = documentEntity.ContentTypeIcon; ? c.Published
published = culture == null : c.PublishedCultures.Contains(culture);
? documentEntity.Published icon = c.ContentType.Icon;
: documentEntity.PublishedCultures.Contains(culture); trashed = c.Trashed;
udi = new GuidUdi(Constants.UdiEntityType.Document, documentEntity.Key); }
url = publishedSnapshot.Content?.GetById(entity.Key)?.Url(_publishedUrlProvider) ?? "#";
trashed = documentEntity.Trashed;
} }
else if (entity is IContentEntitySlim contentEntity) else if (dto.Udi.EntityType == Constants.UdiEntityType.Media)
{ {
icon = contentEntity.ContentTypeIcon; url = _publishedUrlProvider.GetMediaUrl(dto.Udi.Guid, UrlMode.Relative, culture);
published = !contentEntity.Trashed; IMedia? m = _mediaService.GetById(dto.Udi.Guid);
udi = new GuidUdi(Constants.UdiEntityType.Media, contentEntity.Key); if (m is not null)
url = publishedSnapshot.Media?.GetById(entity.Key)?.Url(_publishedUrlProvider) ?? "#"; {
trashed = contentEntity.Trashed; published = m.Trashed is false;
} icon = m.ContentType.Icon;
else trashed = m.Trashed;
{ }
// Not supported
continue;
} }
} }

View File

@@ -39,6 +39,11 @@ internal sealed class NestedContentPropertyIndexValueFactory
_contentTypeService = contentTypeService; _contentTypeService = contentTypeService;
} }
protected override IContentType? GetContentTypeOfNestedItem(
NestedContentPropertyEditor.NestedContentValues.NestedContentRowValue input, IDictionary<Guid, IContentType> contentTypeDictionary)
=> contentTypeDictionary.Values.FirstOrDefault(x=>x.Alias.Equals(input.ContentTypeAlias));
[Obsolete("Use non-obsolete overload, scheduled for removal in v14")]
protected override IContentType? GetContentTypeOfNestedItem( protected override IContentType? GetContentTypeOfNestedItem(
NestedContentPropertyEditor.NestedContentValues.NestedContentRowValue input) NestedContentPropertyEditor.NestedContentValues.NestedContentRowValue input)
=> _contentTypeService.Get(input.ContentTypeAlias); => _contentTypeService.Get(input.ContentTypeAlias);

View File

@@ -4,6 +4,7 @@ using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Examine; using Umbraco.Cms.Infrastructure.Examine;
using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions; using Umbraco.Extensions;
@@ -42,20 +43,39 @@ internal abstract class NestedPropertyIndexValueFactoryBase<TSerialized, TItem>
bool published) => bool published) =>
Handle(deserializedPropertyValue, property, culture, segment, published, Enumerable.Empty<string>()); Handle(deserializedPropertyValue, property, culture, segment, published, Enumerable.Empty<string>());
[Obsolete("Use the overload that specifies availableCultures, scheduled for removal in v14")]
protected override IEnumerable<KeyValuePair<string, IEnumerable<object?>>> Handle( protected override IEnumerable<KeyValuePair<string, IEnumerable<object?>>> Handle(
TSerialized deserializedPropertyValue, TSerialized deserializedPropertyValue,
IProperty property, IProperty property,
string? culture, string? culture,
string? segment, string? segment,
bool published, bool published,
IEnumerable<string> availableCultures) IEnumerable<string> availableCultures) =>
Handle(
deserializedPropertyValue,
property,
culture,
segment,
published,
Enumerable.Empty<string>(),
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>().GetAll().ToDictionary(x=>x.Key));
protected override IEnumerable<KeyValuePair<string, IEnumerable<object?>>> Handle(
TSerialized deserializedPropertyValue,
IProperty property,
string? culture,
string? segment,
bool published,
IEnumerable<string> availableCultures,
IDictionary<Guid, IContentType> contentTypeDictionary)
{ {
var result = new List<KeyValuePair<string, IEnumerable<object?>>>(); var result = new List<KeyValuePair<string, IEnumerable<object?>>>();
var index = 0; var index = 0;
foreach (TItem nestedContentRowValue in GetDataItems(deserializedPropertyValue)) foreach (TItem nestedContentRowValue in GetDataItems(deserializedPropertyValue))
{ {
IContentType? contentType = GetContentTypeOfNestedItem(nestedContentRowValue); IContentType? contentType = GetContentTypeOfNestedItem(nestedContentRowValue, contentTypeDictionary);
if (contentType is null) if (contentType is null)
{ {
@@ -125,6 +145,9 @@ internal abstract class NestedPropertyIndexValueFactoryBase<TSerialized, TItem>
/// <summary> /// <summary>
/// Gets the content type using the nested item. /// Gets the content type using the nested item.
/// </summary> /// </summary>
protected abstract IContentType? GetContentTypeOfNestedItem(TItem nestedItem, IDictionary<Guid, IContentType> contentTypeDictionary);
[Obsolete("Use non-obsolete overload. Scheduled for removal in Umbraco 14.")]
protected abstract IContentType? GetContentTypeOfNestedItem(TItem nestedItem); protected abstract IContentType? GetContentTypeOfNestedItem(TItem nestedItem);
/// <summary> /// <summary>

View File

@@ -224,7 +224,7 @@ AND cmsContentNu.nodeId IS NULL
IContentCacheDataSerializer serializer = IContentCacheDataSerializer serializer =
_contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Document); _contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Document);
IEnumerable<ContentSourceDto> dtos = GetContentNodeDtos(sql); IEnumerable<ContentSourceDto> dtos = GetContentNodeDtos(sql, Constants.ObjectTypes.Document);
foreach (ContentSourceDto row in dtos) foreach (ContentSourceDto row in dtos)
{ {
@@ -242,7 +242,7 @@ AND cmsContentNu.nodeId IS NULL
IContentCacheDataSerializer serializer = IContentCacheDataSerializer serializer =
_contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Document); _contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Document);
IEnumerable<ContentSourceDto> dtos = GetContentNodeDtos(sql); IEnumerable<ContentSourceDto> dtos = GetContentNodeDtos(sql, Constants.ObjectTypes.Document);
foreach (ContentSourceDto row in dtos) foreach (ContentSourceDto row in dtos)
{ {
@@ -265,7 +265,7 @@ AND cmsContentNu.nodeId IS NULL
IContentCacheDataSerializer serializer = IContentCacheDataSerializer serializer =
_contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Document); _contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Document);
IEnumerable<ContentSourceDto> dtos = GetContentNodeDtos(sql); IEnumerable<ContentSourceDto> dtos = GetContentNodeDtos(sql, Constants.ObjectTypes.Document);
foreach (ContentSourceDto row in dtos) foreach (ContentSourceDto row in dtos)
{ {
@@ -301,7 +301,7 @@ AND cmsContentNu.nodeId IS NULL
IContentCacheDataSerializer serializer = IContentCacheDataSerializer serializer =
_contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Media); _contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Media);
IEnumerable<ContentSourceDto> dtos = GetContentNodeDtos(sql); IEnumerable<ContentSourceDto> dtos = GetContentNodeDtos(sql, Constants.ObjectTypes.Media);
foreach (ContentSourceDto row in dtos) foreach (ContentSourceDto row in dtos)
{ {
@@ -319,7 +319,7 @@ AND cmsContentNu.nodeId IS NULL
IContentCacheDataSerializer serializer = IContentCacheDataSerializer serializer =
_contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Media); _contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Media);
IEnumerable<ContentSourceDto> dtos = GetContentNodeDtos(sql); IEnumerable<ContentSourceDto> dtos = GetContentNodeDtos(sql, Constants.ObjectTypes.Media);
foreach (ContentSourceDto row in dtos) foreach (ContentSourceDto row in dtos)
{ {
@@ -342,7 +342,7 @@ AND cmsContentNu.nodeId IS NULL
IContentCacheDataSerializer serializer = IContentCacheDataSerializer serializer =
_contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Media); _contentCacheDataSerializerFactory.Create(ContentCacheDataSerializerEntityType.Media);
IEnumerable<ContentSourceDto> dtos = GetContentNodeDtos(sql); IEnumerable<ContentSourceDto> dtos = GetContentNodeDtos(sql, Constants.ObjectTypes.Media);
foreach (ContentSourceDto row in dtos) foreach (ContentSourceDto row in dtos)
{ {
@@ -990,7 +990,7 @@ WHERE cmsContentNu.nodeId IN (
return s; return s;
} }
private IEnumerable<ContentSourceDto> GetContentNodeDtos(Sql<ISqlContext> sql) private IEnumerable<ContentSourceDto> GetContentNodeDtos(Sql<ISqlContext> sql, Guid nodeObjectType)
{ {
// We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout. // We need to page here. We don't want to iterate over every single row in one connection cuz this can cause an SQL Timeout.
// We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that. // We also want to read with a db reader and not load everything into memory, QueryPaged lets us do that.
@@ -1000,7 +1000,7 @@ WHERE cmsContentNu.nodeId IN (
{ {
// Use a more efficient COUNT query // Use a more efficient COUNT query
Sql<ISqlContext>? sqlCountQuery = SqlContentSourcesCount() Sql<ISqlContext>? sqlCountQuery = SqlContentSourcesCount()
.Append(SqlObjectTypeNotTrashed(SqlContext, Constants.ObjectTypes.Document)); .Append(SqlObjectTypeNotTrashed(SqlContext, nodeObjectType));
Sql<ISqlContext>? sqlCount = Sql<ISqlContext>? sqlCount =
SqlContext.Sql("SELECT COUNT(*) FROM (").Append(sqlCountQuery).Append(") npoco_tbl"); SqlContext.Sql("SELECT COUNT(*) FROM (").Append(sqlCountQuery).Append(") npoco_tbl");