Added missing property index value factories (#13819)
* Added missing PropertyIndexValueFactories, for Block Grid, Block List, Nested Content, Tags and added No-op for image picker, image cropper etc, where the content dont make any sense anyway. Made it replace for block grid/list, nested content and tags * Fixed tests * Ensure raw-fields are the prefix * Code clean up * build fix * Minor cleanup * Fixed issue with published values / external index --------- Co-authored-by: nikolajlauridsen <nikolajlauridsen@protonmail.ch>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
public interface IBlockValuePropertyIndexValueFactory : IPropertyIndexValueFactory
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
public interface INestedContentPropertyIndexValueFactory : IPropertyIndexValueFactory
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
public interface ITagPropertyIndexValueFactory : IPropertyIndexValueFactory
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
/// <summary>
|
||||
/// Abstract base for property index value factories where the value is json.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSerialized">The type to deserialize the json to.</typeparam>
|
||||
public abstract class JsonPropertyIndexValueFactoryBase<TSerialized> : IPropertyIndexValueFactory
|
||||
{
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the JsonPropertyIndexValueFactoryBase.
|
||||
/// </summary>
|
||||
protected JsonPropertyIndexValueFactoryBase(IJsonSerializer jsonSerializer)
|
||||
{
|
||||
_jsonSerializer = jsonSerializer;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(
|
||||
IProperty property,
|
||||
string? culture,
|
||||
string? segment,
|
||||
bool published)
|
||||
{
|
||||
var result = new List<KeyValuePair<string, IEnumerable<object?>>>();
|
||||
|
||||
var propertyValue = property.GetValue(culture, segment, published);
|
||||
|
||||
// If there is a value, it's a string and it's detected as json.
|
||||
if (propertyValue is string rawValue && rawValue.DetectIsJson())
|
||||
{
|
||||
try
|
||||
{
|
||||
TSerialized? deserializedPropertyValue = _jsonSerializer.Deserialize<TSerialized>(rawValue);
|
||||
|
||||
if (deserializedPropertyValue is null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result.AddRange(Handle(deserializedPropertyValue, property, culture, segment, published));
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
// Swallow...on purpose, there's a chance that this isn't the json format we are looking for
|
||||
// and we don't want that to affect the website.
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
// Swallow on purpose to prevent this error:
|
||||
// Can not add Newtonsoft.Json.Linq.JValue to Newtonsoft.Json.Linq.JObject.
|
||||
}
|
||||
}
|
||||
|
||||
result.AddRange(HandleResume(result, property, culture, segment, published));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to return a list of resume of the content. By default this returns an empty list
|
||||
/// </summary>
|
||||
protected virtual IEnumerable<KeyValuePair<string, IEnumerable<object?>>> HandleResume(
|
||||
List<KeyValuePair<string, IEnumerable<object?>>> result,
|
||||
IProperty property,
|
||||
string? culture,
|
||||
string? segment,
|
||||
bool published) => Array.Empty<KeyValuePair<string, IEnumerable<object?>>>();
|
||||
|
||||
/// <summary>
|
||||
/// Method that handle the deserialized object.
|
||||
/// </summary>
|
||||
protected abstract IEnumerable<KeyValuePair<string, IEnumerable<object?>>> Handle(
|
||||
TSerialized deserializedPropertyValue,
|
||||
IProperty property,
|
||||
string? culture,
|
||||
string? segment,
|
||||
bool published);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
/// <summary>
|
||||
/// Property Index Valye Factory that do not index anything.
|
||||
/// </summary>
|
||||
public class NoopPropertyIndexValueFactory : IPropertyIndexValueFactory
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetIndexValues(IProperty property, string? culture, string? segment, bool published) => Array.Empty<KeyValuePair<string, IEnumerable<object?>>>();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
public class TagPropertyIndexValueFactory : JsonPropertyIndexValueFactoryBase<string[]>, ITagPropertyIndexValueFactory
|
||||
{
|
||||
public TagPropertyIndexValueFactory(IJsonSerializer jsonSerializer) : base(jsonSerializer)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<KeyValuePair<string, IEnumerable<object?>>> Handle(
|
||||
string[] deserializedPropertyValue,
|
||||
IProperty property,
|
||||
string? culture,
|
||||
string? segment,
|
||||
bool published)
|
||||
{
|
||||
yield return new KeyValuePair<string, IEnumerable<object?>>(property.Alias, deserializedPropertyValue);
|
||||
}
|
||||
}
|
||||
@@ -222,6 +222,19 @@ public static partial class UmbracoBuilderExtensions
|
||||
builder.Services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();
|
||||
|
||||
builder.Services.AddTransient<IFireAndForgetRunner, FireAndForgetRunner>();
|
||||
|
||||
|
||||
builder.AddPropertyIndexValueFactories();
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IUmbracoBuilder AddPropertyIndexValueFactories(this IUmbracoBuilder builder)
|
||||
{
|
||||
builder.Services.AddSingleton<IBlockValuePropertyIndexValueFactory, BlockValuePropertyIndexValueFactory>();
|
||||
builder.Services.AddSingleton<INestedContentPropertyIndexValueFactory, NestedContentPropertyIndexValueFactory>();
|
||||
builder.Services.AddSingleton<ITagPropertyIndexValueFactory, TagPropertyIndexValueFactory>();
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Web.Common.DependencyInjection;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
// Scheduled for removal in v12
|
||||
@@ -11,11 +14,26 @@ public abstract class BlockEditorPropertyEditor : BlockListPropertyEditorBase
|
||||
public const string ContentTypeKeyPropertyKey = "contentTypeKey";
|
||||
public const string UdiPropertyKey = "udi";
|
||||
|
||||
[Obsolete("Use non-obsoleted ctor. This will be removed in Umbraco 13.")]
|
||||
protected BlockEditorPropertyEditor(
|
||||
IDataValueEditorFactory dataValueEditorFactory,
|
||||
PropertyEditorCollection propertyEditors)
|
||||
: base(dataValueEditorFactory) =>
|
||||
: this(
|
||||
dataValueEditorFactory,
|
||||
propertyEditors,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IBlockValuePropertyIndexValueFactory>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected BlockEditorPropertyEditor(
|
||||
IDataValueEditorFactory dataValueEditorFactory,
|
||||
PropertyEditorCollection propertyEditors,
|
||||
IBlockValuePropertyIndexValueFactory blockValuePropertyIndexValueFactory)
|
||||
: base(dataValueEditorFactory, blockValuePropertyIndexValueFactory)
|
||||
{
|
||||
PropertyEditors = propertyEditors;
|
||||
}
|
||||
|
||||
private PropertyEditorCollection PropertyEditors { get; }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Web.Common.DependencyInjection;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
@@ -19,11 +21,25 @@ public class BlockGridPropertyEditor : BlockGridPropertyEditorBase
|
||||
{
|
||||
private readonly IIOHelper _ioHelper;
|
||||
|
||||
[Obsolete("Use non-obsoleted ctor. This will be removed in Umbraco 13.")]
|
||||
public BlockGridPropertyEditor(
|
||||
IDataValueEditorFactory dataValueEditorFactory,
|
||||
IIOHelper ioHelper)
|
||||
: base(dataValueEditorFactory) =>
|
||||
: this(dataValueEditorFactory, ioHelper, StaticServiceProvider.Instance.GetRequiredService<IBlockValuePropertyIndexValueFactory>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public BlockGridPropertyEditor(
|
||||
IDataValueEditorFactory dataValueEditorFactory,
|
||||
IIOHelper ioHelper,
|
||||
IBlockValuePropertyIndexValueFactory blockValuePropertyIndexValueFactory)
|
||||
: base(dataValueEditorFactory, blockValuePropertyIndexValueFactory)
|
||||
{
|
||||
_ioHelper = ioHelper;
|
||||
}
|
||||
|
||||
|
||||
#region Pre Value Editor
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
@@ -9,6 +10,7 @@ using Umbraco.Cms.Core.Models.Blocks;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Web.Common.DependencyInjection;
|
||||
using Umbraco.Extensions;
|
||||
using BlockGridAreaConfiguration = Umbraco.Cms.Core.PropertyEditors.BlockGridConfiguration.BlockGridAreaConfiguration;
|
||||
|
||||
@@ -19,9 +21,24 @@ namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
/// </summary>
|
||||
public abstract class BlockGridPropertyEditorBase : DataEditor
|
||||
{
|
||||
private readonly IBlockValuePropertyIndexValueFactory _blockValuePropertyIndexValueFactory;
|
||||
|
||||
[Obsolete("Use non-obsoleted ctor. This will be removed in Umbraco 13.")]
|
||||
protected BlockGridPropertyEditorBase(IDataValueEditorFactory dataValueEditorFactory)
|
||||
: base(dataValueEditorFactory) =>
|
||||
: this(dataValueEditorFactory, StaticServiceProvider.Instance.GetRequiredService<IBlockValuePropertyIndexValueFactory>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected BlockGridPropertyEditorBase(IDataValueEditorFactory dataValueEditorFactory, IBlockValuePropertyIndexValueFactory blockValuePropertyIndexValueFactory)
|
||||
: base(dataValueEditorFactory)
|
||||
{
|
||||
_blockValuePropertyIndexValueFactory = blockValuePropertyIndexValueFactory;
|
||||
SupportsReadOnly = true;
|
||||
}
|
||||
|
||||
public override IPropertyIndexValueFactory PropertyIndexValueFactory => _blockValuePropertyIndexValueFactory;
|
||||
|
||||
|
||||
#region Value Editor
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ public class BlockListPropertyEditor : BlockEditorPropertyEditor
|
||||
private readonly IIOHelper _ioHelper;
|
||||
|
||||
// Scheduled for removal in v12
|
||||
[Obsolete("Please use constructor that takes an IEditorConfigurationParser instead")]
|
||||
[Obsolete("Use non-obsoleted ctor. This will be removed in Umbraco 13.")]
|
||||
public BlockListPropertyEditor(
|
||||
IDataValueEditorFactory dataValueEditorFactory,
|
||||
PropertyEditorCollection propertyEditors,
|
||||
@@ -34,12 +34,29 @@ public class BlockListPropertyEditor : BlockEditorPropertyEditor
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use non-obsoleted ctor. This will be removed in Umbraco 13.")]
|
||||
public BlockListPropertyEditor(
|
||||
IDataValueEditorFactory dataValueEditorFactory,
|
||||
PropertyEditorCollection propertyEditors,
|
||||
IIOHelper ioHelper,
|
||||
IEditorConfigurationParser editorConfigurationParser)
|
||||
: base(dataValueEditorFactory, propertyEditors)
|
||||
: this(
|
||||
dataValueEditorFactory,
|
||||
propertyEditors,
|
||||
ioHelper,
|
||||
editorConfigurationParser,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IBlockValuePropertyIndexValueFactory>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public BlockListPropertyEditor(
|
||||
IDataValueEditorFactory dataValueEditorFactory,
|
||||
PropertyEditorCollection propertyEditors,
|
||||
IIOHelper ioHelper,
|
||||
IEditorConfigurationParser editorConfigurationParser,
|
||||
IBlockValuePropertyIndexValueFactory blockValuePropertyIndexValueFactory)
|
||||
: base(dataValueEditorFactory, propertyEditors, blockValuePropertyIndexValueFactory)
|
||||
{
|
||||
_ioHelper = ioHelper;
|
||||
_editorConfigurationParser = editorConfigurationParser;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
@@ -6,6 +7,7 @@ using Umbraco.Cms.Core.Models.Blocks;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Web.Common.DependencyInjection;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
@@ -14,9 +16,25 @@ namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
/// </summary>
|
||||
public abstract class BlockListPropertyEditorBase : DataEditor
|
||||
{
|
||||
|
||||
private readonly IBlockValuePropertyIndexValueFactory _blockValuePropertyIndexValueFactory;
|
||||
|
||||
[Obsolete("Use non-obsoleted ctor. This will be removed in Umbraco 13.")]
|
||||
protected BlockListPropertyEditorBase(IDataValueEditorFactory dataValueEditorFactory)
|
||||
: base(dataValueEditorFactory) =>
|
||||
: this(dataValueEditorFactory, StaticServiceProvider.Instance.GetRequiredService<IBlockValuePropertyIndexValueFactory>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected BlockListPropertyEditorBase(IDataValueEditorFactory dataValueEditorFactory, IBlockValuePropertyIndexValueFactory blockValuePropertyIndexValueFactory)
|
||||
: base(dataValueEditorFactory)
|
||||
{
|
||||
_blockValuePropertyIndexValueFactory = blockValuePropertyIndexValueFactory;
|
||||
SupportsReadOnly = true;
|
||||
}
|
||||
|
||||
public override IPropertyIndexValueFactory PropertyIndexValueFactory => _blockValuePropertyIndexValueFactory;
|
||||
|
||||
|
||||
#region Value Editor
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Blocks;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
internal sealed class BlockValuePropertyIndexValueFactory :
|
||||
NestedPropertyIndexValueFactoryBase<BlockValue, BlockItemData>,
|
||||
IBlockValuePropertyIndexValueFactory
|
||||
{
|
||||
private readonly IContentTypeService _contentTypeService;
|
||||
|
||||
|
||||
public BlockValuePropertyIndexValueFactory(
|
||||
PropertyEditorCollection propertyEditorCollection,
|
||||
IContentTypeService contentTypeService,
|
||||
IJsonSerializer jsonSerializer)
|
||||
: base(propertyEditorCollection, jsonSerializer)
|
||||
{
|
||||
_contentTypeService = contentTypeService;
|
||||
}
|
||||
|
||||
|
||||
protected override IContentType? GetContentTypeOfNestedItem(BlockItemData input) =>
|
||||
_contentTypeService.Get(input.ContentTypeKey);
|
||||
|
||||
protected override IDictionary<string, object?> GetRawProperty(BlockItemData blockItemData) =>
|
||||
blockItemData.RawPropertyValues;
|
||||
|
||||
protected override IEnumerable<BlockItemData> GetDataItems(BlockValue input) => input.ContentData;
|
||||
}
|
||||
@@ -45,6 +45,9 @@ public class ColorPickerPropertyEditor : DataEditor
|
||||
SupportsReadOnly = true;
|
||||
}
|
||||
|
||||
public override IPropertyIndexValueFactory PropertyIndexValueFactory { get; } = new NoopPropertyIndexValueFactory();
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IConfigurationEditor CreateConfigurationEditor() =>
|
||||
new ColorPickerConfigurationEditor(_ioHelper, _jsonSerializer, _editorConfigurationParser);
|
||||
|
||||
@@ -97,6 +97,8 @@ public class ImageCropperPropertyEditor : DataEditor, IMediaUrlGenerator,
|
||||
SupportsReadOnly = true;
|
||||
}
|
||||
|
||||
public override IPropertyIndexValueFactory PropertyIndexValueFactory { get; } = new NoopPropertyIndexValueFactory();
|
||||
|
||||
public bool TryGetMediaPath(string? propertyEditorAlias, object? value, out string? mediaPath)
|
||||
{
|
||||
if (propertyEditorAlias == Alias &&
|
||||
|
||||
@@ -59,6 +59,8 @@ public class MediaPicker3PropertyEditor : DataEditor
|
||||
SupportsReadOnly = true;
|
||||
}
|
||||
|
||||
public override IPropertyIndexValueFactory PropertyIndexValueFactory { get; } = new NoopPropertyIndexValueFactory();
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IConfigurationEditor CreateConfigurationEditor() =>
|
||||
new MediaPicker3ConfigurationEditor(_ioHelper, _editorConfigurationParser);
|
||||
@@ -67,6 +69,8 @@ public class MediaPicker3PropertyEditor : DataEditor
|
||||
protected override IDataValueEditor CreateValueEditor() =>
|
||||
DataValueEditorFactory.Create<MediaPicker3PropertyValueEditor>(Attribute!);
|
||||
|
||||
|
||||
|
||||
internal class MediaPicker3PropertyValueEditor : DataValueEditor, IDataValueReference
|
||||
{
|
||||
private readonly IDataTypeService _dataTypeService;
|
||||
|
||||
@@ -32,9 +32,9 @@ public class NestedContentPropertyEditor : DataEditor
|
||||
public const string ContentTypeAliasPropertyKey = "ncContentTypeAlias";
|
||||
private readonly IEditorConfigurationParser _editorConfigurationParser;
|
||||
private readonly IIOHelper _ioHelper;
|
||||
private readonly INestedContentPropertyIndexValueFactory _nestedContentPropertyIndexValueFactory;
|
||||
|
||||
// Scheduled for removal in v12
|
||||
[Obsolete("Please use constructor that takes an IEditorConfigurationParser instead")]
|
||||
[Obsolete("Use non-obsoleted ctor. This will be removed in Umbraco 12.")]
|
||||
public NestedContentPropertyEditor(
|
||||
IDataValueEditorFactory dataValueEditorFactory,
|
||||
IIOHelper ioHelper)
|
||||
@@ -42,17 +42,35 @@ public class NestedContentPropertyEditor : DataEditor
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use non-obsoleted ctor. This will be removed in Umbraco 13.")]
|
||||
public NestedContentPropertyEditor(
|
||||
IDataValueEditorFactory dataValueEditorFactory,
|
||||
IIOHelper ioHelper,
|
||||
IEditorConfigurationParser editorConfigurationParser)
|
||||
: this(
|
||||
dataValueEditorFactory,
|
||||
ioHelper,
|
||||
editorConfigurationParser,
|
||||
StaticServiceProvider.Instance.GetRequiredService<INestedContentPropertyIndexValueFactory>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public NestedContentPropertyEditor(
|
||||
IDataValueEditorFactory dataValueEditorFactory,
|
||||
IIOHelper ioHelper,
|
||||
IEditorConfigurationParser editorConfigurationParser,
|
||||
INestedContentPropertyIndexValueFactory nestedContentPropertyIndexValueFactory)
|
||||
: base(dataValueEditorFactory)
|
||||
{
|
||||
_ioHelper = ioHelper;
|
||||
_editorConfigurationParser = editorConfigurationParser;
|
||||
_nestedContentPropertyIndexValueFactory = nestedContentPropertyIndexValueFactory;
|
||||
SupportsReadOnly = true;
|
||||
}
|
||||
|
||||
public override IPropertyIndexValueFactory PropertyIndexValueFactory => _nestedContentPropertyIndexValueFactory;
|
||||
|
||||
#region Pre Value Editor
|
||||
|
||||
protected override IConfigurationEditor CreateConfigurationEditor() =>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
internal sealed class NestedContentPropertyIndexValueFactory
|
||||
: NestedPropertyIndexValueFactoryBase<
|
||||
NestedContentPropertyEditor.NestedContentValues.NestedContentRowValue[],
|
||||
NestedContentPropertyEditor.NestedContentValues.NestedContentRowValue>,
|
||||
INestedContentPropertyIndexValueFactory
|
||||
{
|
||||
private readonly IContentTypeService _contentTypeService;
|
||||
|
||||
|
||||
public NestedContentPropertyIndexValueFactory(
|
||||
PropertyEditorCollection propertyEditorCollection,
|
||||
IContentTypeService contentTypeService,
|
||||
IJsonSerializer jsonSerializer) : base(propertyEditorCollection, jsonSerializer)
|
||||
{
|
||||
_contentTypeService = contentTypeService;
|
||||
}
|
||||
|
||||
protected override IContentType? GetContentTypeOfNestedItem(
|
||||
NestedContentPropertyEditor.NestedContentValues.NestedContentRowValue input)
|
||||
=> _contentTypeService.Get(input.ContentTypeAlias);
|
||||
|
||||
protected override IDictionary<string, object?> GetRawProperty(
|
||||
NestedContentPropertyEditor.NestedContentValues.NestedContentRowValue nestedContentRowValue) =>
|
||||
nestedContentRowValue.RawPropertyValues;
|
||||
|
||||
protected override IEnumerable<NestedContentPropertyEditor.NestedContentValues.NestedContentRowValue> GetDataItems(
|
||||
NestedContentPropertyEditor.NestedContentValues.NestedContentRowValue[] input) => input;
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
using System.Text;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Infrastructure.Examine;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
internal abstract class NestedPropertyIndexValueFactoryBase<TSerialized, TItem> : JsonPropertyIndexValueFactoryBase<TSerialized>
|
||||
{
|
||||
private readonly PropertyEditorCollection _propertyEditorCollection;
|
||||
|
||||
protected NestedPropertyIndexValueFactoryBase(
|
||||
PropertyEditorCollection propertyEditorCollection,
|
||||
IJsonSerializer jsonSerializer)
|
||||
: base(jsonSerializer)
|
||||
{
|
||||
_propertyEditorCollection = propertyEditorCollection;
|
||||
}
|
||||
|
||||
protected override IEnumerable<KeyValuePair<string, IEnumerable<object?>>> Handle(
|
||||
TSerialized deserializedPropertyValue,
|
||||
IProperty property,
|
||||
string? culture,
|
||||
string? segment,
|
||||
bool published)
|
||||
{
|
||||
var result = new List<KeyValuePair<string, IEnumerable<object?>>>();
|
||||
|
||||
foreach (TItem nestedContentRowValue in GetDataItems(deserializedPropertyValue))
|
||||
{
|
||||
IContentType? contentType = GetContentTypeOfNestedItem(nestedContentRowValue);
|
||||
|
||||
if (contentType is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var propertyTypeDictionary =
|
||||
contentType
|
||||
.PropertyGroups
|
||||
.SelectMany(x => x.PropertyTypes!)
|
||||
.ToDictionary(x => x.Alias);
|
||||
|
||||
result.AddRange(GetNestedResults(
|
||||
property.Alias,
|
||||
culture,
|
||||
segment,
|
||||
published,
|
||||
propertyTypeDictionary,
|
||||
nestedContentRowValue));
|
||||
}
|
||||
|
||||
return RenameKeysToEnsureRawSegmentsIsAPrefix(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rename keys that count the RAW-constant, to ensure the RAW-constant is a prefix.
|
||||
/// </summary>
|
||||
private IEnumerable<KeyValuePair<string, IEnumerable<object?>>> RenameKeysToEnsureRawSegmentsIsAPrefix(
|
||||
List<KeyValuePair<string, IEnumerable<object?>>> indexContent)
|
||||
{
|
||||
foreach (KeyValuePair<string, IEnumerable<object?>> indexedKeyValuePair in indexContent)
|
||||
{
|
||||
// Tests if key includes the RawFieldPrefix and it is not in the start
|
||||
if (indexedKeyValuePair.Key.Substring(1).Contains(UmbracoExamineFieldNames.RawFieldPrefix))
|
||||
{
|
||||
var newKey = UmbracoExamineFieldNames.RawFieldPrefix +
|
||||
indexedKeyValuePair.Key.Replace(UmbracoExamineFieldNames.RawFieldPrefix, string.Empty);
|
||||
yield return new KeyValuePair<string, IEnumerable<object?>>(newKey, indexedKeyValuePair.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return indexedKeyValuePair;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content type using the nested item.
|
||||
/// </summary>
|
||||
protected abstract IContentType? GetContentTypeOfNestedItem(TItem nestedItem);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the raw data from a nested item.
|
||||
/// </summary>
|
||||
protected abstract IDictionary<string, object?> GetRawProperty(TItem nestedItem);
|
||||
|
||||
/// <summary>
|
||||
/// Get the data times of a parent item. E.g. block list have contentData.
|
||||
/// </summary>
|
||||
protected abstract IEnumerable<TItem> GetDataItems(TSerialized input);
|
||||
|
||||
/// <summary>
|
||||
/// Index a key with the name of the property, using the relevant content of all the children.
|
||||
/// </summary>
|
||||
protected override IEnumerable<KeyValuePair<string, IEnumerable<object?>>> HandleResume(
|
||||
List<KeyValuePair<string, IEnumerable<object?>>> indexedContent,
|
||||
IProperty property,
|
||||
string? culture,
|
||||
string? segment,
|
||||
bool published)
|
||||
{
|
||||
yield return new KeyValuePair<string, IEnumerable<object?>>(
|
||||
property.Alias,
|
||||
GetResumeFromAllContent(indexedContent).Yield());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a resume as string of all the content in this nested type.
|
||||
/// </summary>
|
||||
/// <param name="indexedContent">All the indexed content for this property.</param>
|
||||
/// <returns>the string with all relevant content from </returns>
|
||||
private static string GetResumeFromAllContent(List<KeyValuePair<string, IEnumerable<object?>>> indexedContent)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
foreach ((var indexKey, IEnumerable<object?>? indexedValue) in indexedContent)
|
||||
{
|
||||
// Ignore Raw fields
|
||||
if (indexKey.Contains(UmbracoExamineFieldNames.RawFieldPrefix))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var value in indexedValue)
|
||||
{
|
||||
if (value is not null)
|
||||
{
|
||||
stringBuilder.AppendLine(value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content to index for the nested type. E.g. Block list, Nested Content, etc..
|
||||
/// </summary>
|
||||
private IEnumerable<KeyValuePair<string, IEnumerable<object?>>> GetNestedResults(
|
||||
string keyPrefix,
|
||||
string? culture,
|
||||
string? segment,
|
||||
bool published,
|
||||
IDictionary<string, IPropertyType> propertyTypeDictionary,
|
||||
TItem nestedContentRowValue)
|
||||
{
|
||||
var blockIndex = 0;
|
||||
|
||||
foreach ((var propertyAlias, var propertyValue) in GetRawProperty(nestedContentRowValue))
|
||||
{
|
||||
if (propertyTypeDictionary.TryGetValue(propertyAlias, out IPropertyType? propertyType))
|
||||
{
|
||||
IProperty subProperty = new Property(propertyType);
|
||||
subProperty.SetValue(propertyValue, culture, segment);
|
||||
|
||||
if (published)
|
||||
{
|
||||
subProperty.PublishValues(culture, segment ?? "*");
|
||||
}
|
||||
|
||||
IDataEditor? editor = _propertyEditorCollection[propertyType.PropertyEditorAlias];
|
||||
if (editor is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IEnumerable<KeyValuePair<string, IEnumerable<object?>>> indexValues =
|
||||
editor.PropertyIndexValueFactory.GetIndexValues(subProperty, culture, segment, published);
|
||||
|
||||
foreach ((var nestedAlias, IEnumerable<object?> nestedValue) in indexValues)
|
||||
{
|
||||
yield return new KeyValuePair<string, IEnumerable<object?>>(
|
||||
$"{keyPrefix}.items[{blockIndex}].{nestedAlias}", nestedValue!);
|
||||
}
|
||||
}
|
||||
|
||||
blockIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,12 +29,13 @@ namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
public class TagsPropertyEditor : DataEditor
|
||||
{
|
||||
private readonly IEditorConfigurationParser _editorConfigurationParser;
|
||||
private readonly ITagPropertyIndexValueFactory _tagPropertyIndexValueFactory;
|
||||
private readonly IIOHelper _ioHelper;
|
||||
private readonly ILocalizedTextService _localizedTextService;
|
||||
private readonly ManifestValueValidatorCollection _validators;
|
||||
|
||||
// Scheduled for removal in v12
|
||||
[Obsolete("Please use constructor that takes an IEditorConfigurationParser instead")]
|
||||
[Obsolete("Use non-obsoleted ctor. This will be removed in Umbraco 13.")]
|
||||
public TagsPropertyEditor(
|
||||
IDataValueEditorFactory dataValueEditorFactory,
|
||||
ManifestValueValidatorCollection validators,
|
||||
@@ -45,24 +46,48 @@ public class TagsPropertyEditor : DataEditor
|
||||
validators,
|
||||
ioHelper,
|
||||
localizedTextService,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IEditorConfigurationParser>())
|
||||
StaticServiceProvider.Instance.GetRequiredService<IEditorConfigurationParser>(),
|
||||
StaticServiceProvider.Instance.GetRequiredService<ITagPropertyIndexValueFactory>())
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use non-obsoleted ctor. This will be removed in Umbraco 13.")]
|
||||
public TagsPropertyEditor(
|
||||
IDataValueEditorFactory dataValueEditorFactory,
|
||||
ManifestValueValidatorCollection validators,
|
||||
IIOHelper ioHelper,
|
||||
ILocalizedTextService localizedTextService,
|
||||
IEditorConfigurationParser editorConfigurationParser)
|
||||
: this(
|
||||
dataValueEditorFactory,
|
||||
validators,
|
||||
ioHelper,
|
||||
localizedTextService,
|
||||
editorConfigurationParser,
|
||||
StaticServiceProvider.Instance.GetRequiredService<ITagPropertyIndexValueFactory>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public TagsPropertyEditor(
|
||||
IDataValueEditorFactory dataValueEditorFactory,
|
||||
ManifestValueValidatorCollection validators,
|
||||
IIOHelper ioHelper,
|
||||
ILocalizedTextService localizedTextService,
|
||||
IEditorConfigurationParser editorConfigurationParser)
|
||||
IEditorConfigurationParser editorConfigurationParser,
|
||||
ITagPropertyIndexValueFactory tagPropertyIndexValueFactory)
|
||||
: base(dataValueEditorFactory)
|
||||
{
|
||||
_validators = validators;
|
||||
_ioHelper = ioHelper;
|
||||
_localizedTextService = localizedTextService;
|
||||
_editorConfigurationParser = editorConfigurationParser;
|
||||
_tagPropertyIndexValueFactory = tagPropertyIndexValueFactory;
|
||||
}
|
||||
|
||||
public override IPropertyIndexValueFactory PropertyIndexValueFactory => _tagPropertyIndexValueFactory;
|
||||
|
||||
|
||||
protected override IDataValueEditor CreateValueEditor() =>
|
||||
DataValueEditorFactory.Create<TagPropertyValueEditor>(Attribute!);
|
||||
|
||||
|
||||
@@ -95,7 +95,8 @@ public class DataValueEditorReuseTests
|
||||
_dataValueEditorFactoryMock.Object,
|
||||
new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>)),
|
||||
Mock.Of<IIOHelper>(),
|
||||
Mock.Of<IEditorConfigurationParser>());
|
||||
Mock.Of<IEditorConfigurationParser>(),
|
||||
Mock.Of<IBlockValuePropertyIndexValueFactory>());
|
||||
|
||||
// block list is *not* set to reuse its data value editor
|
||||
var dataValueEditor1 = blockListPropertyEditor.GetValueEditor();
|
||||
@@ -115,7 +116,8 @@ public class DataValueEditorReuseTests
|
||||
_dataValueEditorFactoryMock.Object,
|
||||
new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>)),
|
||||
Mock.Of<IIOHelper>(),
|
||||
Mock.Of<IEditorConfigurationParser>());
|
||||
Mock.Of<IEditorConfigurationParser>(),
|
||||
Mock.Of<IBlockValuePropertyIndexValueFactory>());
|
||||
|
||||
// no matter what, a property editor should never reuse its data value editor when created *with* configuration
|
||||
var dataValueEditor1 = blockListPropertyEditor.GetValueEditor("config");
|
||||
|
||||
@@ -34,7 +34,11 @@ public class NestedContentTests
|
||||
var localizationService = Mock.Of<ILocalizationService>();
|
||||
|
||||
PropertyEditorCollection editors = null;
|
||||
var editor = new NestedContentPropertyEditor(Mock.Of<IDataValueEditorFactory>(), Mock.Of<IIOHelper>(), Mock.Of<IEditorConfigurationParser>());
|
||||
var editor = new NestedContentPropertyEditor(
|
||||
Mock.Of<IDataValueEditorFactory>(),
|
||||
Mock.Of<IIOHelper>(),
|
||||
Mock.Of<IEditorConfigurationParser>(),
|
||||
Mock.Of<INestedContentPropertyIndexValueFactory>());
|
||||
editors = new PropertyEditorCollection(new DataEditorCollection(() => new DataEditor[] { editor }));
|
||||
|
||||
var serializer = new ConfigurationEditorJsonSerializer();
|
||||
|
||||
Reference in New Issue
Block a user