Fixes: U4-4798 When new property types are added, the internal Examine index isn't notified and will ignore them

This commit is contained in:
Shannon
2014-05-01 12:43:40 +10:00
parent 1e9d1007b6
commit c4603ee5cd
3 changed files with 70 additions and 32 deletions

View File

@@ -61,6 +61,7 @@ namespace Umbraco.Web.Search
CacheRefresherBase<PageCacheRefresher>.CacheUpdated += PublishedPageCacheRefresherCacheUpdated;
CacheRefresherBase<MediaCacheRefresher>.CacheUpdated += MediaCacheRefresherCacheUpdated;
CacheRefresherBase<MemberCacheRefresher>.CacheUpdated += MemberCacheRefresherCacheUpdated;
CacheRefresherBase<ContentTypeCacheRefresher>.CacheUpdated += ContentTypeCacheRefresherCacheUpdated;
var contentIndexer = ExamineManager.Instance.IndexProviderCollection["InternalIndexer"] as UmbracoContentIndexer;
if (contentIndexer != null)
@@ -74,6 +75,25 @@ namespace Umbraco.Web.Search
}
}
/// <summary>
/// This is used to refresh content indexers IndexData based on the DataService whenever a content type is changed since
/// properties may have been added/removed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks>
/// See: http://issues.umbraco.org/issue/U4-4798
/// </remarks>
[SecuritySafeCritical]
static void ContentTypeCacheRefresherCacheUpdated(ContentTypeCacheRefresher sender, CacheRefresherEventArgs e)
{
var indexersToUpdated = ExamineManager.Instance.IndexProviderCollection.OfType<UmbracoContentIndexer>();
foreach (var provider in indexersToUpdated)
{
provider.RefreshIndexerDataFromDataService();
}
}
[SecuritySafeCritical]
static void MemberCacheRefresherCacheUpdated(MemberCacheRefresher sender, CacheRefresherEventArgs e)
{

View File

@@ -14,58 +14,63 @@ namespace UmbracoExamine.Config
/// </summary>
public static class IndexSetExtensions
{
private static readonly object Locker = new object();
internal static IIndexCriteria ToIndexCriteria(this IndexSet set, IDataService svc,
IEnumerable<StaticField> indexFieldPolicies)
{
var attributeFields = set.IndexAttributeFields.Cast<IIndexField>().ToArray();
var userFields = set.IndexUserFields.Cast<IIndexField>().ToArray();
var includeNodeTypes = set.IncludeNodeTypes.ToList().Select(x => x.Name).ToArray();
var excludeNodeTypes = set.ExcludeNodeTypes.ToList().Select(x => x.Name).ToArray();
var parentId = set.IndexParentId;
//if there are no user fields defined, we'll populate them from the data source (include them all)
if (set.IndexUserFields.Count == 0)
{
lock (Locker)
//we need to add all user fields to the collection if it is empty (this is the default if none are specified)
var userProps = svc.ContentService.GetAllUserPropertyNames();
var fields = new List<IIndexField>();
foreach (var u in userProps)
{
//we need to add all user fields to the collection if it is empty (this is the default if none are specified)
var userFields = svc.ContentService.GetAllUserPropertyNames();
foreach (var u in userFields)
var field = new IndexField() { Name = u };
var policy = indexFieldPolicies.FirstOrDefault(x => x.Name == u);
if (policy != null)
{
var field = new IndexField() {Name = u};
var policy = indexFieldPolicies.FirstOrDefault(x => x.Name == u);
if (policy != null)
{
field.Type = policy.Type;
field.EnableSorting = policy.EnableSorting;
}
set.IndexUserFields.Add(field);
field.Type = policy.Type;
field.EnableSorting = policy.EnableSorting;
}
fields.Add(field);
}
userFields = fields.ToArray();
}
//if there are no attribute fields defined, we'll populate them from the data source (include them all)
if (set.IndexAttributeFields.Count == 0)
{
lock (Locker)
//we need to add all system fields to the collection if it is empty (this is the default if none are specified)
var sysProps = svc.ContentService.GetAllSystemPropertyNames();
var fields = new List<IIndexField>();
foreach (var s in sysProps)
{
//we need to add all system fields to the collection if it is empty (this is the default if none are specified)
var sysFields = svc.ContentService.GetAllSystemPropertyNames();
foreach (var s in sysFields)
var field = new IndexField() { Name = s };
var policy = indexFieldPolicies.FirstOrDefault(x => x.Name == s);
if (policy != null)
{
var field = new IndexField() { Name = s };
var policy = indexFieldPolicies.FirstOrDefault(x => x.Name == s);
if (policy != null)
{
field.Type = policy.Type;
field.EnableSorting = policy.EnableSorting;
}
set.IndexAttributeFields.Add(field);
field.Type = policy.Type;
field.EnableSorting = policy.EnableSorting;
}
fields.Add(field);
}
attributeFields = fields.ToArray();
}
return new IndexCriteria(
set.IndexAttributeFields.Cast<IIndexField>().ToArray(),
set.IndexUserFields.Cast<IIndexField>().ToArray(),
set.IncludeNodeTypes.ToList().Select(x => x.Name).ToArray(),
set.ExcludeNodeTypes.ToList().Select(x => x.Name).ToArray(),
set.IndexParentId);
attributeFields,
userFields,
includeNodeTypes,
excludeNodeTypes,
parentId);
}
/// <summary>

View File

@@ -298,6 +298,19 @@ namespace UmbracoExamine
base.RebuildIndex();
}
/// <summary>
/// Used to refresh the current IndexerData from the data in the DataService. This can be used
/// if there are more properties added/removed from the database
/// </summary>
public void RefreshIndexerDataFromDataService()
{
//TODO: This would be much better done if the IndexerData property had read/write locks applied
// to it! Unless we update the base class there's really no way to prevent the IndexerData from being
// changed during an operation that is reading from it.
var newIndexerData = GetIndexerData(IndexSets.Instance.Sets[IndexSetName]);
IndexerData = newIndexerData;
}
/// <summary>
/// Override this method to strip all html from all user fields before raising the event, then after the event
/// ensure our special Path field is added to the collection