diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 18b768658e..86a176ee19 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -449,7 +449,7 @@ namespace Umbraco.Core.Services { try { - RePublishAllDo(); + RebuildXmlStructures(); return true; } catch (Exception ex) @@ -470,7 +470,7 @@ namespace Umbraco.Core.Services { try { - RePublishAllDo(contentTypeIds); + RebuildXmlStructures(contentTypeIds); } catch (Exception ex) { @@ -1152,11 +1152,18 @@ namespace Umbraco.Core.Services #region Private Methods + //TODO: WE should make a base class for ContentService and MediaService to share! + // currently we have this logic duplicated (nearly the same) for media types and soon to be member types + /// - /// Rebuilds all xml content in the cmsContentXml table for all published documents + /// Rebuilds all xml content in the cmsContentXml table for all documents /// + /// + /// Only rebuild the xml structures for the content type ids passed in, if none then rebuilds the structures + /// for all content + /// /// True if publishing succeeded, otherwise False - private void RePublishAllDo(params int[] contentTypeIds) + private void RebuildXmlStructures(params int[] contentTypeIds) { using (new WriteLock(Locker)) { @@ -1165,7 +1172,7 @@ namespace Umbraco.Core.Services var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateContentRepository(uow)) { - if (!contentTypeIds.Any()) + if (contentTypeIds.Any() == false) { //Remove all Document records from the cmsContentXml table (DO NOT REMOVE Media/Members!) uow.Database.Execute(@"DELETE FROM cmsContentXml WHERE nodeId IN @@ -1207,7 +1214,7 @@ namespace Umbraco.Core.Services uow.Database.Insert(poco); } } - Audit.Add(AuditTypes.Publish, "RePublish All completed, the xml has been regenerated in the database", 0, -1); + Audit.Add(AuditTypes.Publish, "RebuildXmlStructures completed, the xml has been regenerated in the database", 0, -1); } } diff --git a/src/Umbraco.Core/Services/ContentTypeService.cs b/src/Umbraco.Core/Services/ContentTypeService.cs index 1c764d88cf..9d0a8265b6 100644 --- a/src/Umbraco.Core/Services/ContentTypeService.cs +++ b/src/Umbraco.Core/Services/ContentTypeService.cs @@ -144,7 +144,7 @@ namespace Umbraco.Core.Services /// if they are required to be updated. /// /// A tuple of a content type and a boolean indicating if it is new (HasIdentity was false before committing) - private void UpdateContentXmlStructure(params IContentType[] contentTypes) + private void UpdateContentXmlStructure(params IContentTypeBase[] contentTypes) { var toUpdate = new List(); @@ -190,17 +190,33 @@ namespace Umbraco.Core.Services } } - var typedContentService = _contentService as ContentService; - if (typedContentService != null && toUpdate.Any()) + if (toUpdate.Any()) { - typedContentService.RePublishAll(toUpdate.Select(x => x.Id).ToArray()); + var firstType = toUpdate.First(); + //if it is a content type then call the rebuilding methods or content + if (firstType is IContentType) + { + var typedContentService = _contentService as ContentService; + if (typedContentService != null) + { + typedContentService.RePublishAll(toUpdate.Select(x => x.Id).ToArray()); + } + else + { + //this should never occur, the content service should always be typed but we'll check anyways. + _contentService.RePublishAll(); + } + } + else if (firstType is IMediaType) + { + //if it is a media type then call the rebuilding methods for media + var typedContentService = _mediaService as MediaService; + if (typedContentService != null) + { + typedContentService.RebuildXmlStructures(toUpdate.Select(x => x.Id).ToArray()); + } + } } - else if (toUpdate.Any()) - { - //this should never occur, the content service should always be typed but we'll check anyways. - _contentService.RePublishAll(); - } - } @@ -258,7 +274,7 @@ namespace Umbraco.Core.Services uow.Commit(); } - UpdateContentXmlStructure(asArray); + UpdateContentXmlStructure(asArray.Cast().ToArray()); } SavedContentType.RaiseEvent(new SaveEventArgs(asArray, false), this); Audit.Add(AuditTypes.Save, string.Format("Save ContentTypes performed by user"), userId, -1); @@ -412,17 +428,22 @@ namespace Umbraco.Core.Services { if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs(mediaType), this)) return; - - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow)) - { - mediaType.CreatorId = userId; - repository.AddOrUpdate(mediaType); - uow.Commit(); - SavedMediaType.RaiseEvent(new SaveEventArgs(mediaType, false), this); - } + using (new WriteLock(Locker)) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow)) + { + mediaType.CreatorId = userId; + repository.AddOrUpdate(mediaType); + uow.Commit(); + + } + UpdateContentXmlStructure(mediaType); + } + + SavedMediaType.RaiseEvent(new SaveEventArgs(mediaType, false), this); Audit.Add(AuditTypes.Save, string.Format("Save MediaType performed by user"), userId, mediaType.Id); } @@ -438,22 +459,26 @@ namespace Umbraco.Core.Services if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs(asArray), this)) return; - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow)) - { + using (new WriteLock(Locker)) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow)) + { - foreach (var mediaType in asArray) - { - mediaType.CreatorId = userId; - repository.AddOrUpdate(mediaType); - } + foreach (var mediaType in asArray) + { + mediaType.CreatorId = userId; + repository.AddOrUpdate(mediaType); + } - //save it all in one go - uow.Commit(); + //save it all in one go + uow.Commit(); + } - SavedMediaType.RaiseEvent(new SaveEventArgs(asArray, false), this); - } + UpdateContentXmlStructure(asArray.Cast().ToArray()); + } + SavedMediaType.RaiseEvent(new SaveEventArgs(asArray, false), this); Audit.Add(AuditTypes.Save, string.Format("Save MediaTypes performed by user"), userId, -1); } diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs index 77a24cdc03..4fed0f6e0c 100644 --- a/src/Umbraco.Core/Services/MediaService.cs +++ b/src/Umbraco.Core/Services/MediaService.cs @@ -698,6 +698,72 @@ namespace Umbraco.Core.Services Audit.Add(AuditTypes.Save, "Save Media items performed by user", userId, -1); } + /// + /// Rebuilds all xml content in the cmsContentXml table for all media + /// + /// + /// Only rebuild the xml structures for the content type ids passed in, if none then rebuilds the structures + /// for all media + /// + /// True if publishing succeeded, otherwise False + internal void RebuildXmlStructures(params int[] contentTypeIds) + { + using (new WriteLock(Locker)) + { + var list = new List(); + + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + if (contentTypeIds.Any() == false) + { + //Remove all media records from the cmsContentXml table (DO NOT REMOVE Content/Members!) + uow.Database.Execute(@"DELETE FROM cmsContentXml WHERE nodeId IN + (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml + INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id + WHERE nodeObjectType = @nodeObjectType)", + new {nodeObjectType = Constants.ObjectTypes.Media}); + + // Consider creating a Path query instead of recursive method: + // var query = Query.Builder.Where(x => x.Path.StartsWith("-1")); + var rootMedia = GetRootMedia(); + foreach (var media in rootMedia) + { + list.Add(media); + list.AddRange(GetDescendants(media)); + } + } + else + { + foreach (var id in contentTypeIds) + { + //first we'll clear out the data from the cmsContentXml table for this type + uow.Database.Execute(@"delete from cmsContentXml where nodeId in + (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml + INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id + INNER JOIN cmsContent ON cmsContent.nodeId = umbracoNode.id + WHERE nodeObjectType = @nodeObjectType AND cmsContent.contentType = @contentTypeId)", + new {contentTypeId = id, nodeObjectType = Constants.ObjectTypes.Media}); + + //now get all media objects of this type and add to the list + list.AddRange(GetMediaOfMediaType(id)); + } + } + + foreach (var c in list) + { + //generate the xml + var xml = c.ToXml(); + //create the dto to insert + var poco = new ContentXmlDto { NodeId = c.Id, Xml = xml.ToString(SaveOptions.None) }; + //insert it into the database + uow.Database.Insert(poco); + } + } + Audit.Add(AuditTypes.Publish, "RebuildXmlStructures completed, the xml has been regenerated in the database", 0, -1); + } + } + /// /// Updates the Path and Level on a collection of objects /// based on the Parent's Path and Level.