From c4603ee5cdfdbed46856765d2c23a90bb6c18fcb Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 1 May 2014 12:43:40 +1000 Subject: [PATCH] Fixes: U4-4798 When new property types are added, the internal Examine index isn't notified and will ignore them --- src/Umbraco.Web/Search/ExamineEvents.cs | 20 ++++++ .../Config/IndexSetExtensions.cs | 69 ++++++++++--------- src/UmbracoExamine/UmbracoContentIndexer.cs | 13 ++++ 3 files changed, 70 insertions(+), 32 deletions(-) diff --git a/src/Umbraco.Web/Search/ExamineEvents.cs b/src/Umbraco.Web/Search/ExamineEvents.cs index a015761481..a3660b887a 100644 --- a/src/Umbraco.Web/Search/ExamineEvents.cs +++ b/src/Umbraco.Web/Search/ExamineEvents.cs @@ -61,6 +61,7 @@ namespace Umbraco.Web.Search CacheRefresherBase.CacheUpdated += PublishedPageCacheRefresherCacheUpdated; CacheRefresherBase.CacheUpdated += MediaCacheRefresherCacheUpdated; CacheRefresherBase.CacheUpdated += MemberCacheRefresherCacheUpdated; + CacheRefresherBase.CacheUpdated += ContentTypeCacheRefresherCacheUpdated; var contentIndexer = ExamineManager.Instance.IndexProviderCollection["InternalIndexer"] as UmbracoContentIndexer; if (contentIndexer != null) @@ -74,6 +75,25 @@ namespace Umbraco.Web.Search } } + /// + /// 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 + /// + /// + /// + /// + /// See: http://issues.umbraco.org/issue/U4-4798 + /// + [SecuritySafeCritical] + static void ContentTypeCacheRefresherCacheUpdated(ContentTypeCacheRefresher sender, CacheRefresherEventArgs e) + { + var indexersToUpdated = ExamineManager.Instance.IndexProviderCollection.OfType(); + foreach (var provider in indexersToUpdated) + { + provider.RefreshIndexerDataFromDataService(); + } + } + [SecuritySafeCritical] static void MemberCacheRefresherCacheUpdated(MemberCacheRefresher sender, CacheRefresherEventArgs e) { diff --git a/src/UmbracoExamine/Config/IndexSetExtensions.cs b/src/UmbracoExamine/Config/IndexSetExtensions.cs index 76a4d46575..ac432b16ec 100644 --- a/src/UmbracoExamine/Config/IndexSetExtensions.cs +++ b/src/UmbracoExamine/Config/IndexSetExtensions.cs @@ -14,58 +14,63 @@ namespace UmbracoExamine.Config /// public static class IndexSetExtensions { - - private static readonly object Locker = new object(); - internal static IIndexCriteria ToIndexCriteria(this IndexSet set, IDataService svc, IEnumerable indexFieldPolicies) { + + var attributeFields = set.IndexAttributeFields.Cast().ToArray(); + var userFields = set.IndexUserFields.Cast().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(); + 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(); + 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().ToArray(), - set.IndexUserFields.Cast().ToArray(), - set.IncludeNodeTypes.ToList().Select(x => x.Name).ToArray(), - set.ExcludeNodeTypes.ToList().Select(x => x.Name).ToArray(), - set.IndexParentId); + attributeFields, + userFields, + includeNodeTypes, + excludeNodeTypes, + parentId); } /// diff --git a/src/UmbracoExamine/UmbracoContentIndexer.cs b/src/UmbracoExamine/UmbracoContentIndexer.cs index 9da53a77f2..3f442f5daa 100644 --- a/src/UmbracoExamine/UmbracoContentIndexer.cs +++ b/src/UmbracoExamine/UmbracoContentIndexer.cs @@ -298,6 +298,19 @@ namespace UmbracoExamine base.RebuildIndex(); } + /// + /// 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 + /// + 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; + } + /// /// 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