From 84fd5dc2ee52a713f5fe168ab38c1bcab8fbb285 Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 4 Sep 2017 19:49:28 +0200 Subject: [PATCH] perfs - IContentService.IsPublishable --- src/Umbraco.Core/EnumerableExtensions.cs | 11 +++ src/Umbraco.Core/Services/ContentService.cs | 67 +++++++------------ .../Services/ContentServiceTests.cs | 15 +++++ 3 files changed, 50 insertions(+), 43 deletions(-) diff --git a/src/Umbraco.Core/EnumerableExtensions.cs b/src/Umbraco.Core/EnumerableExtensions.cs index e8565f3bc7..bb115b394d 100644 --- a/src/Umbraco.Core/EnumerableExtensions.cs +++ b/src/Umbraco.Core/EnumerableExtensions.cs @@ -295,5 +295,16 @@ namespace Umbraco.Core return list1Groups.Count == list2Groups.Count && list1Groups.All(g => g.Count() == list2Groups[g.Key].Count()); } + + public static IEnumerable SkipLast(this IEnumerable source) + { + using (var e = source.GetEnumerator()) + { + if (e.MoveNext() == false) yield break; + + for (var value = e.Current; e.MoveNext(); value = e.Current) + yield return value; + } + } } } diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 09e6068ce1..913a83c1cd 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -903,15 +903,30 @@ namespace Umbraco.Core.Services /// True if the Content can be published, otherwise False public bool IsPublishable(IContent content) { - //If the passed in content has yet to be saved we "fallback" to checking the Parent - //because if the Parent is publishable then the current content can be Saved and Published - if (content.HasIdentity == false) - { - var parent = GetById(content.ParentId); - return IsPublishable(parent, true); - } + // get ids from path + // skip the first one that has to be -1 - and we don't care + // skip the last one that has to be "this" - and it's ok to stop at the parent + var ids = content.Path.Split(',').Skip(1).SkipLast().Select(int.Parse).ToArray(); + if (ids.Length == 0) + return false; - return IsPublishable(content, false); + // if the first one is recycle bin, fail fast + if (ids[0] == Constants.System.RecycleBinContent) + return false; + + // fixme - move to repository? + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) + { + var sql = new Sql(@" + SELECT id + FROM umbracoNode + JOIN cmsDocument ON umbracoNode.id=cmsDocument.nodeId AND cmsDocument.published=@0 + WHERE umbracoNode.trashed=@1 AND umbracoNode.id IN (@2)", + true, false, ids); + Console.WriteLine(sql.SQL); + var x = uow.Database.Fetch(sql); + return ids.Length == x.Count; + } } /// @@ -1062,7 +1077,7 @@ namespace Umbraco.Core.Services descendant.WriterId = userId; descendant.ChangeTrashedState(true, descendant.ParentId); repository.AddOrUpdate(descendant); - + moveInfo.Add(new MoveEventInfo(descendant, descendant.Path, descendant.ParentId)); } @@ -2311,40 +2326,6 @@ namespace Umbraco.Core.Services } } - /// - /// Checks if the passed in can be published based on the anscestors publish state. - /// - /// - /// Check current is only used when falling back to checking the Parent of non-saved content, as - /// non-saved content doesn't have a valid path yet. - /// - /// to check if anscestors are published - /// Boolean indicating whether the passed in content should also be checked for published versions - /// True if the Content can be published, otherwise False - private bool IsPublishable(IContent content, bool checkCurrent) - { - var ids = content.Path.Split(',').Select(int.Parse).ToList(); - foreach (var id in ids) - { - //If Id equals that of the recycle bin we return false because nothing in the bin can be published - if (id == Constants.System.RecycleBinContent) - return false; - - //We don't check the System Root, so just continue - if (id == Constants.System.Root) continue; - - //If the current id equals that of the passed in content and if current shouldn't be checked we skip it. - if (checkCurrent == false && id == content.Id) continue; - - //Check if the content for the current id is published - escape the loop if we encounter content that isn't published - var hasPublishedVersion = HasPublishedVersion(id); - if (hasPublishedVersion == false) - return false; - } - - return true; - } - private PublishStatusType CheckAndLogIsPublishable(IContent content) { //Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 79bf91716e..6c1f388ee5 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -998,6 +998,21 @@ namespace Umbraco.Tests.Services Assert.That(content.Published, Is.True); } + [Test] + public void IsPublishable() + { + // Arrange + var contentService = ServiceContext.ContentService; + var parent = contentService.CreateContent("parent", -1, "umbTextpage"); + contentService.SaveAndPublishWithStatus(parent); + var content = contentService.CreateContent("child", parent, "umbTextpage"); + contentService.Save(content); + + Assert.IsTrue(contentService.IsPublishable(content)); + contentService.UnPublish(parent); + Assert.IsFalse(contentService.IsPublishable(content)); + } + [Test] public void Can_Publish_Content_WithEvents() {