diff --git a/src/Umbraco.Core/PropertyEditors/DataEditor.cs b/src/Umbraco.Core/PropertyEditors/DataEditor.cs
index 2d0b34a849..f3a9c7f4c6 100644
--- a/src/Umbraco.Core/PropertyEditors/DataEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/DataEditor.cs
@@ -153,6 +153,11 @@ namespace Umbraco.Core.PropertyEditors
set => _defaultConfiguration = value;
}
+ ///
+ /// Returns the value indexer for this editor
+ ///
+ public virtual IValueIndexer ValueIndexer => new DefaultValueIndexer();
+
///
/// Creates a value editor instance.
///
diff --git a/src/Umbraco.Core/PropertyEditors/DefaultValueIndexer.cs b/src/Umbraco.Core/PropertyEditors/DefaultValueIndexer.cs
new file mode 100644
index 0000000000..d46f15771c
--- /dev/null
+++ b/src/Umbraco.Core/PropertyEditors/DefaultValueIndexer.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+using Umbraco.Core.Models;
+
+namespace Umbraco.Core.PropertyEditors
+{
+ ///
+ /// Returns a single field to index containing the property value
+ ///
+ public class DefaultValueIndexer : IValueIndexer
+ {
+ public IEnumerable> GetIndexValues(Property property, string culture)
+ {
+ yield return new KeyValuePair(property.Alias, new[] { property.GetValue(culture) });
+ }
+ }
+}
diff --git a/src/Umbraco.Core/PropertyEditors/IDataEditor.cs b/src/Umbraco.Core/PropertyEditors/IDataEditor.cs
index 8137101826..f967f6f269 100644
--- a/src/Umbraco.Core/PropertyEditors/IDataEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/IDataEditor.cs
@@ -3,6 +3,7 @@ using Umbraco.Core.Composing;
namespace Umbraco.Core.PropertyEditors
{
+
///
/// Represents a data editor.
///
@@ -65,5 +66,7 @@ namespace Umbraco.Core.PropertyEditors
/// Is expected to throw if the editor does not support being configured, e.g. for most parameter editors.
///
IConfigurationEditor GetConfigurationEditor();
+
+ IValueIndexer ValueIndexer { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Core/PropertyEditors/IValueIndexer.cs b/src/Umbraco.Core/PropertyEditors/IValueIndexer.cs
new file mode 100644
index 0000000000..fdf3a9234f
--- /dev/null
+++ b/src/Umbraco.Core/PropertyEditors/IValueIndexer.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+using Umbraco.Core.Models;
+
+namespace Umbraco.Core.PropertyEditors
+{
+ ///
+ /// Returns indexable data for the property
+ ///
+ public interface IValueIndexer
+ {
+ //fixme: What about segments and whether we want the published value?
+ IEnumerable> GetIndexValues(Property property, string culture);
+ }
+}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 23b90aaf3c..c54f14423b 100755
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -439,6 +439,7 @@
+
@@ -447,6 +448,7 @@
+
diff --git a/src/Umbraco.Examine/Umbraco.Examine.csproj b/src/Umbraco.Examine/Umbraco.Examine.csproj
index 8065cc799c..50561f7d8f 100644
--- a/src/Umbraco.Examine/Umbraco.Examine.csproj
+++ b/src/Umbraco.Examine/Umbraco.Examine.csproj
@@ -74,6 +74,7 @@
Properties\SolutionInfo.cs
+
diff --git a/src/Umbraco.Examine/UmbracoContentIndexer.cs b/src/Umbraco.Examine/UmbracoContentIndexer.cs
index 541ecd1b2b..ae0c93a6ae 100644
--- a/src/Umbraco.Examine/UmbracoContentIndexer.cs
+++ b/src/Umbraco.Examine/UmbracoContentIndexer.cs
@@ -22,6 +22,7 @@ using Umbraco.Examine.Config;
using IContentService = Umbraco.Core.Services.IContentService;
using IMediaService = Umbraco.Core.Services.IMediaService;
using Examine.LuceneEngine;
+using Umbraco.Core.PropertyEditors;
namespace Umbraco.Examine
{
@@ -30,12 +31,11 @@ namespace Umbraco.Examine
///
public class UmbracoContentIndexer : UmbracoExamineIndexer
{
+ protected UmbracoValueSetBuilder ValueSetBuilder { get; }
protected IContentService ContentService { get; }
protected IMediaService MediaService { get; }
- protected IUserService UserService { get; }
protected ILocalizationService LanguageService { get; }
- private readonly IEnumerable _urlSegmentProviders;
private int? _parentId;
#region Constructors
@@ -48,10 +48,9 @@ namespace Umbraco.Examine
{
ContentService = Current.Services.ContentService;
MediaService = Current.Services.MediaService;
- UserService = Current.Services.UserService;
LanguageService = Current.Services.LocalizationService;
- _urlSegmentProviders = Current.UrlSegmentProviders;
+ ValueSetBuilder = new UmbracoValueSetBuilder(Current.PropertyEditors, Current.UrlSegmentProviders, Current.Services.UserService);
InitializeQueries(Current.SqlContext);
}
@@ -66,9 +65,7 @@ namespace Umbraco.Examine
///
///
///
- ///
///
- ///
///
///
///
@@ -78,12 +75,11 @@ namespace Umbraco.Examine
Directory luceneDirectory,
Analyzer defaultAnalyzer,
ProfilingLogger profilingLogger,
+ UmbracoValueSetBuilder valueSetBuilder,
IContentService contentService,
IMediaService mediaService,
- IUserService userService,
ILocalizationService languageService,
ISqlContext sqlContext,
- IEnumerable urlSegmentProviders,
IValueSetValidator validator,
UmbracoContentIndexerOptions options,
IReadOnlyDictionary> indexValueTypes = null)
@@ -95,12 +91,10 @@ namespace Umbraco.Examine
SupportProtectedContent = options.SupportProtectedContent;
SupportUnpublishedContent = options.SupportUnpublishedContent;
ParentId = options.ParentId;
-
+ ValueSetBuilder = valueSetBuilder ?? throw new ArgumentNullException(nameof(valueSetBuilder));
ContentService = contentService ?? throw new ArgumentNullException(nameof(contentService));
MediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService));
- UserService = userService ?? throw new ArgumentNullException(nameof(userService));
LanguageService = languageService ?? throw new ArgumentNullException(nameof(languageService));
- _urlSegmentProviders = urlSegmentProviders ?? throw new ArgumentNullException(nameof(urlSegmentProviders));
InitializeQueries(sqlContext);
}
@@ -292,7 +286,7 @@ namespace Umbraco.Examine
content = descendants.ToArray();
}
- IndexItems(GetValueSets(_urlSegmentProviders, UserService, content));
+ IndexItems(ValueSetBuilder.GetValueSets(content));
pageIndex++;
} while (content.Length == pageSize);
@@ -327,7 +321,7 @@ namespace Umbraco.Examine
media = descendants.ToArray();
}
- IndexItems(GetValueSets(_urlSegmentProviders, UserService, media));
+ IndexItems(ValueSetBuilder.GetValueSets(media));
pageIndex++;
} while (media.Length == pageSize);
@@ -336,146 +330,7 @@ namespace Umbraco.Examine
}
}
- ///
- /// Creates a collection of for a collection
- ///
- ///
- ///
- ///
- /// Yield returns
- public static IEnumerable GetValueSets(IEnumerable urlSegmentProviders, IUserService userService, params IContent[] content)
- {
- //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
- // Lucene will do it no matter what? One idea was to create a `FieldValue` struct which would contain `object`, `object[]`, `ValueType` and `ValueType[]`
- // references and then each array is an array of `FieldValue[]` and values are assigned accordingly. Not sure if it will make a difference or not.
-
- foreach (var c in content)
- {
- var isVariant = c.ContentType.VariesByCulture();
-
- var urlValue = c.GetUrlSegment(urlSegmentProviders); //Always add invariant urlName
- var values = new Dictionary
- {
- {"icon", new [] {c.ContentType.Icon}},
- {PublishedFieldName, new object[] {c.Published ? 1 : 0}}, //Always add invariant published value
- {"id", new object[] {c.Id}},
- {"key", new object[] {c.Key}},
- {"parentID", new object[] {c.Level > 1 ? c.ParentId : -1}},
- {"level", new object[] {c.Level}},
- {"creatorID", new object[] {c.CreatorId}},
- {"sortOrder", new object[] {c.SortOrder}},
- {"createDate", new object[] {c.CreateDate}}, //Always add invariant createDate
- {"updateDate", new object[] {c.UpdateDate}}, //Always add invariant updateDate
- {"nodeName", new object[] {c.Name}}, //Always add invariant nodeName
- {"urlName", new object[] {urlValue}}, //Always add invariant urlName
- {"path", new object[] {c.Path}},
- {"nodeType", new object[] {c.ContentType.Id}},
- {"creatorName", new object[] {c.GetCreatorProfile(userService)?.Name ?? "??"}},
- {"writerName", new object[] {c.GetWriterProfile(userService)?.Name ?? "??"}},
- {"writerID", new object[] {c.WriterId}},
- {"template", new object[] {c.Template?.Id ?? 0}},
- {$"{SpecialFieldPrefix}VariesByCulture", new object[] {0}},
- };
-
- if (isVariant)
- {
- values[$"{SpecialFieldPrefix}VariesByCulture"] = new object[] { 1 };
-
- foreach(var culture in c.AvailableCultures)
- {
- var variantUrl = c.GetUrlSegment(urlSegmentProviders, culture);
- var lowerCulture = culture.ToLowerInvariant();
- values[$"urlName_{lowerCulture}"] = new object[] { variantUrl };
- values[$"nodeName_{lowerCulture}"] = new object[] { c.GetCultureName(culture) };
- values[$"{PublishedFieldName}_{lowerCulture}"] = new object[] { c.IsCulturePublished(culture) ? 1 : 0 };
- values[$"updateDate_{lowerCulture}"] = new object[] { c.GetUpdateDate(culture) };
- }
- }
-
- foreach (var property in c.Properties)
- {
- if (!property.PropertyType.VariesByCulture())
- {
- AddPropertyValue(null, c, property, values);
- }
- else
- {
- foreach (var culture in c.AvailableCultures)
- AddPropertyValue(culture.ToLowerInvariant(), c, property, values);
- }
- }
-
- var vs = new ValueSet(c.Id.ToInvariantString(), IndexTypes.Content, c.ContentType.Alias, values);
-
- yield return vs;
- }
- }
-
- private static void AddPropertyValue(string culture, IContent c, Property property, IDictionary values)
- {
- var val = property.GetValue(culture);
- var cultureSuffix = culture == null ? string.Empty : "_" + culture;
- switch (val)
- {
- //only add the value if its not null or empty (we'll check for string explicitly here too)
- case null:
- return;
- case string strVal:
- if (strVal.IsNullOrWhiteSpace()) return;
- values.Add($"{property.Alias}{cultureSuffix}", new[] { val });
- break;
- default:
- values.Add($"{property.Alias}{cultureSuffix}", new[] { val });
- break;
- }
- }
-
- public static IEnumerable GetValueSets(IEnumerable urlSegmentProviders, IUserService userService, params IMedia[] media)
- {
- foreach (var m in media)
- {
- var urlValue = m.GetUrlSegment(urlSegmentProviders);
- var values = new Dictionary
- {
- {"icon", new object[] {m.ContentType.Icon}},
- {"id", new object[] {m.Id}},
- {"key", new object[] {m.Key}},
- {"parentID", new object[] {m.Level > 1 ? m.ParentId : -1}},
- {"level", new object[] {m.Level}},
- {"creatorID", new object[] {m.CreatorId}},
- {"sortOrder", new object[] {m.SortOrder}},
- {"createDate", new object[] {m.CreateDate}},
- {"updateDate", new object[] {m.UpdateDate}},
- {"nodeName", new object[] {m.Name}},
- {"urlName", new object[] {urlValue}},
- {"path", new object[] {m.Path}},
- {"nodeType", new object[] {m.ContentType.Id}},
- {"creatorName", new object[] {m.GetCreatorProfile(userService).Name}}
- };
-
- foreach (var property in m.Properties)
- {
- //only add the value if its not null or empty (we'll check for string explicitly here too)
- var val = property.GetValue();
- switch (val)
- {
- case null:
- continue;
- case string strVal when strVal.IsNullOrWhiteSpace() == false:
- values.Add(property.Alias, new[] { val });
- break;
- default:
- values.Add(property.Alias, new[] { val });
- break;
- }
- }
-
- var vs = new ValueSet(m.Id.ToInvariantString(), IndexTypes.Media, m.ContentType.Alias, values);
-
- yield return vs;
- }
- }
+
#endregion
diff --git a/src/Umbraco.Examine/UmbracoContentValueSetValidator.cs b/src/Umbraco.Examine/UmbracoContentValueSetValidator.cs
index fb5c26d3c1..1881511ee3 100644
--- a/src/Umbraco.Examine/UmbracoContentValueSetValidator.cs
+++ b/src/Umbraco.Examine/UmbracoContentValueSetValidator.cs
@@ -7,6 +7,7 @@ using Umbraco.Core.Services;
namespace Umbraco.Examine
{
+
///
/// Used to validate a ValueSet for content - based on permissions, parent id, etc....
///
diff --git a/src/Umbraco.Examine/UmbracoExamineIndexer.cs b/src/Umbraco.Examine/UmbracoExamineIndexer.cs
index 1fb3b0c3a3..3ede45c60a 100644
--- a/src/Umbraco.Examine/UmbracoExamineIndexer.cs
+++ b/src/Umbraco.Examine/UmbracoExamineIndexer.cs
@@ -419,30 +419,6 @@ namespace Umbraco.Examine
e.IndexItem.ValueSet.Set(IndexPathFieldName, path);
}
- //strip html of all users fields if we detect it has HTML in it.
- //if that is the case, we'll create a duplicate 'raw' copy of it so that we can return
- //the value of the field 'as-is'.
- foreach (var value in e.IndexItem.ValueSet.Values.ToList()) //ToList here to make a diff collection else we'll get collection modified errors
- {
- if (value.Value == null) continue;
-
- if (value.Value.Count > 0)
- {
- if (value.Value.First() is string str)
- {
- if (XmlHelper.CouldItBeXml(str))
- {
- //First save the raw value to a raw field, we will change the policy of this field by detecting the prefix later
- e.IndexItem.ValueSet.Values[string.Concat(RawFieldPrefix, value.Key)] = new List