From c6a420579e3af9c28e298d0962f98307f2bc5709 Mon Sep 17 00:00:00 2001 From: Zeegaan Date: Wed, 11 Dec 2024 14:56:44 +0100 Subject: [PATCH] Fix ancestors --- .../Extensions/PublishedContentExtensions.cs | 699 ++++++++++++++++-- .../FriendlyPublishedContentExtensions.cs | 10 +- 2 files changed, 657 insertions(+), 52 deletions(-) diff --git a/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs b/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs index c558557740..848bf62208 100644 --- a/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs +++ b/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs @@ -521,15 +521,70 @@ public static class PublishedContentExtensions /// Gets the ancestors of the content. /// /// The content. + /// /// The content cache. /// The query service for the in-memory navigation structure. + /// /// The ancestors of the content, in down-top order. /// Does not consider the content itself. public static IEnumerable Ancestors( this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, - INavigationQueryService navigationQueryService) => - content.AncestorsOrSelf(publishedCache, navigationQueryService, false, null); + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService) => + content.AncestorsOrSelf( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + false, + null); + + /// + /// Gets the ancestors of the content. + /// + /// The content. + /// The content cache. + /// The query service for the in-memory navigation structure. + /// The ancestors of the content, in down-top order. + /// Does not consider the content itself. + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] + public static IEnumerable Ancestors( + this IPublishedContent content, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService) => Ancestors( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService()); + + /// + /// Gets the ancestors of the content, at a level lesser or equal to a specified level. + /// + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The level. + /// The ancestors of the content, at a level lesser or equal to the specified level, in down-top order. + /// Does not consider the content itself. Only content that are "high enough" in the tree are returned. + public static IEnumerable Ancestors( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + int maxLevel) => + content.AncestorsOrSelf( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + false, + n => n.Level <= maxLevel); /// /// Gets the ancestors of the content, at a level lesser or equal to a specified level. @@ -540,12 +595,50 @@ public static class PublishedContentExtensions /// The level. /// The ancestors of the content, at a level lesser or equal to the specified level, in down-top order. /// Does not consider the content itself. Only content that are "high enough" in the tree are returned. + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable Ancestors( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, int maxLevel) => - content.AncestorsOrSelf(publishedCache, navigationQueryService, false, n => n.Level <= maxLevel); + Ancestors( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + maxLevel); + + + /// + /// Gets the ancestors of the content, of a specified content type. + /// + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The content type. + /// The ancestors of the content, of the specified content type, in down-top order. + /// Does not consider the content itself. Returns all ancestors, of the specified content type. + public static IEnumerable Ancestors( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string contentTypeAlias) + { + ArgumentNullException.ThrowIfNull(content); + + return content.EnumerateAncestorsOrSelfInternal( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + false, + contentTypeAlias); + } /// /// Gets the ancestors of the content, of a specified content type. @@ -556,16 +649,39 @@ public static class PublishedContentExtensions /// The content type. /// The ancestors of the content, of the specified content type, in down-top order. /// Does not consider the content itself. Returns all ancestors, of the specified content type. + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable Ancestors( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, - string contentTypeAlias) - { - ArgumentNullException.ThrowIfNull(content); + string contentTypeAlias) => + Ancestors( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias); - return content.EnumerateAncestorsOrSelfInternal(publishedCache, navigationQueryService, false, contentTypeAlias); - } + /// + /// Gets the ancestors of the content, of a specified content type. + /// + /// The content type. + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The ancestors of the content, of the specified content type, in down-top order. + /// Does not consider the content itself. Returns all ancestors, of the specified content type. + public static IEnumerable Ancestors( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService) + where T : class, IPublishedContent => + content.Ancestors(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService).OfType(); /// /// Gets the ancestors of the content, of a specified content type. @@ -576,12 +692,47 @@ public static class PublishedContentExtensions /// The query service for the in-memory navigation structure. /// The ancestors of the content, of the specified content type, in down-top order. /// Does not consider the content itself. Returns all ancestors, of the specified content type. + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable Ancestors( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService) where T : class, IPublishedContent => - content.Ancestors(publishedCache, navigationQueryService).OfType(); + Ancestors( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService()); + + /// + /// Gets the ancestors of the content, at a level lesser or equal to a specified level, and of a specified content + /// type. + /// + /// The content type. + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The level. + /// + /// The ancestors of the content, at a level lesser or equal to the specified level, and of the specified + /// content type, in down-top order. + /// + /// + /// Does not consider the content itself. Only content that are "high enough" in the trees, and of the + /// specified content type, are returned. + /// + public static IEnumerable Ancestors( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + int maxLevel) + where T : class, IPublishedContent => + content.Ancestors(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, maxLevel).OfType(); /// /// Gets the ancestors of the content, at a level lesser or equal to a specified level, and of a specified content @@ -600,13 +751,43 @@ public static class PublishedContentExtensions /// Does not consider the content itself. Only content that are "high enough" in the trees, and of the /// specified content type, are returned. /// + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable Ancestors( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, int maxLevel) where T : class, IPublishedContent => - content.Ancestors(publishedCache, navigationQueryService, maxLevel).OfType(); + Ancestors( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + maxLevel); + + /// + /// Gets the content and its ancestors. + /// + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The content and its ancestors, in down-top order. + public static IEnumerable AncestorsOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService) => + content.AncestorsOrSelf( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + true, + null); /// /// Gets the content and its ancestors. @@ -615,11 +796,49 @@ public static class PublishedContentExtensions /// The content cache. /// The query service for the in-memory navigation structure. /// The content and its ancestors, in down-top order. + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable AncestorsOrSelf( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService) => - content.AncestorsOrSelf(publishedCache, navigationQueryService, true, null); + AncestorsOrSelf( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService()); + + /// + /// Gets the content and its ancestors, at a level lesser or equal to a specified level. + /// + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The level. + /// + /// The content and its ancestors, at a level lesser or equal to the specified level, + /// in down-top order. + /// + /// + /// Only content that are "high enough" in the tree are returned. So it may or may not begin + /// with the content itself, depending on its level. + /// + public static IEnumerable AncestorsOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + int maxLevel) => + content.AncestorsOrSelf( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + true, + n => n.Level <= maxLevel); /// /// Gets the content and its ancestors, at a level lesser or equal to a specified level. @@ -636,12 +855,49 @@ public static class PublishedContentExtensions /// Only content that are "high enough" in the tree are returned. So it may or may not begin /// with the content itself, depending on its level. /// + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable AncestorsOrSelf( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, int maxLevel) => - content.AncestorsOrSelf(publishedCache, navigationQueryService, true, n => n.Level <= maxLevel); + AncestorsOrSelf( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + maxLevel); + + /// + /// Gets the content and its ancestors, of a specified content type. + /// + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The content type. + /// The content and its ancestors, of the specified content type, in down-top order. + /// May or may not begin with the content itself, depending on its content type. + public static IEnumerable AncestorsOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string contentTypeAlias) + { + ArgumentNullException.ThrowIfNull(content); + + return content.EnumerateAncestorsOrSelfInternal( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + true, + contentTypeAlias); + } /// /// Gets the content and its ancestors, of a specified content type. @@ -652,16 +908,39 @@ public static class PublishedContentExtensions /// The content type. /// The content and its ancestors, of the specified content type, in down-top order. /// May or may not begin with the content itself, depending on its content type. + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable AncestorsOrSelf( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, - string contentTypeAlias) - { - ArgumentNullException.ThrowIfNull(content); + string contentTypeAlias) => + AncestorsOrSelf( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias); - return content.EnumerateAncestorsOrSelfInternal(publishedCache, navigationQueryService, true, contentTypeAlias); - } + /// + /// Gets the content and its ancestors, of a specified content type. + /// + /// The content type. + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The content and its ancestors, of the specified content type, in down-top order. + /// May or may not begin with the content itself, depending on its content type. + public static IEnumerable AncestorsOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService) + where T : class, IPublishedContent => + content.AncestorsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService).OfType(); /// /// Gets the content and its ancestors, of a specified content type. @@ -672,12 +951,43 @@ public static class PublishedContentExtensions /// The query service for the in-memory navigation structure. /// The content and its ancestors, of the specified content type, in down-top order. /// May or may not begin with the content itself, depending on its content type. + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable AncestorsOrSelf( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService) + where T : class, IPublishedContent => AncestorsOrSelf( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService()); + + /// + /// Gets the content and its ancestor, at a lever lesser or equal to a specified level, and of a specified content + /// type. + /// + /// The content type. + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The level. + /// + /// The content and its ancestors, at a level lesser or equal to the specified level, and of the specified + /// content type, in down-top order. + /// + /// May or may not begin with the content itself, depending on its level and content type. + public static IEnumerable AncestorsOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + int maxLevel) where T : class, IPublishedContent => - content.AncestorsOrSelf(publishedCache, navigationQueryService).OfType(); + content.AncestorsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, maxLevel).OfType(); /// /// Gets the content and its ancestor, at a lever lesser or equal to a specified level, and of a specified content @@ -693,13 +1003,19 @@ public static class PublishedContentExtensions /// content type, in down-top order. /// /// May or may not begin with the content itself, depending on its level and content type. + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable AncestorsOrSelf( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, int maxLevel) - where T : class, IPublishedContent => - content.AncestorsOrSelf(publishedCache, navigationQueryService, maxLevel).OfType(); + where T : class, IPublishedContent => AncestorsOrSelf( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + maxLevel); /// /// Gets the ancestor of the content, ie its parent. @@ -719,17 +1035,80 @@ public static class PublishedContentExtensions /// Gets the nearest ancestor of the content, at a lever lesser or equal to a specified level. /// /// The content. + /// /// The content cache. /// The query service for the in-memory navigation structure. + /// The query service for the in-memory navigation structure. /// The level. /// The nearest (in down-top order) ancestor of the content, at a level lesser or equal to the specified level. /// Does not consider the content itself. May return null. + public static IPublishedContent? Ancestor( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + int maxLevel) => + content.EnumerateAncestors( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + false).FirstOrDefault(x => x.Level <= maxLevel); + + /// + /// Gets the nearest ancestor of the content, at a lever lesser or equal to a specified level. + /// + /// The content. + /// The content cache. + /// The query service for the in-memory navigation structure. + /// The level. + /// The nearest (in down-top order) ancestor of the content, at a level lesser or equal to the specified level. + /// Does not consider the content itself. May return null. + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static IPublishedContent? Ancestor( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, int maxLevel) => - content.EnumerateAncestors(publishedCache, navigationQueryService, false).FirstOrDefault(x => x.Level <= maxLevel); + Ancestor( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + maxLevel); + + /// + /// Gets the nearest ancestor of the content, of a specified content type. + /// + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The content type alias. + /// The nearest (in down-top order) ancestor of the content, of the specified content type. + /// Does not consider the content itself. May return null. + public static IPublishedContent? Ancestor( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string contentTypeAlias) + { + ArgumentNullException.ThrowIfNull(content); + + return content + .EnumerateAncestorsOrSelfInternal( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + false, + contentTypeAlias).FirstOrDefault(); + } /// /// Gets the nearest ancestor of the content, of a specified content type. @@ -740,18 +1119,39 @@ public static class PublishedContentExtensions /// The content type alias. /// The nearest (in down-top order) ancestor of the content, of the specified content type. /// Does not consider the content itself. May return null. + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static IPublishedContent? Ancestor( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, - string contentTypeAlias) - { - ArgumentNullException.ThrowIfNull(content); + string contentTypeAlias) => + Ancestor( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias); - return content - .EnumerateAncestorsOrSelfInternal(publishedCache, navigationQueryService, false, contentTypeAlias) - .FirstOrDefault(); - } + /// + /// Gets the nearest ancestor of the content, of a specified content type. + /// + /// The content type. + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The nearest (in down-top order) ancestor of the content, of the specified content type. + /// Does not consider the content itself. May return null. + public static T? Ancestor( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService) + where T : class, IPublishedContent => + content.Ancestors(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService).FirstOrDefault(); /// /// Gets the nearest ancestor of the content, of a specified content type. @@ -762,12 +1162,48 @@ public static class PublishedContentExtensions /// The query service for the in-memory navigation structure. /// The nearest (in down-top order) ancestor of the content, of the specified content type. /// Does not consider the content itself. May return null. + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static T? Ancestor( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService) where T : class, IPublishedContent => - content.Ancestors(publishedCache, navigationQueryService).FirstOrDefault(); + Ancestor( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService()); + + /// + /// Gets the nearest ancestor of the content, at the specified level and of the specified content type. + /// + /// The content type. + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The level. + /// The ancestor of the content, at the specified level and of the specified content type. + /// + /// Does not consider the content itself. If the ancestor at the specified level is + /// not of the specified type, returns null. + /// + public static T? Ancestor( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + int maxLevel) + where T : class, IPublishedContent => + content.Ancestors( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + maxLevel).FirstOrDefault(); /// /// Gets the nearest ancestor of the content, at the specified level and of the specified content type. @@ -782,13 +1218,20 @@ public static class PublishedContentExtensions /// Does not consider the content itself. If the ancestor at the specified level is /// not of the specified type, returns null. /// + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static T? Ancestor( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, int maxLevel) where T : class, IPublishedContent => - content.Ancestors(publishedCache, navigationQueryService, maxLevel).FirstOrDefault(); + Ancestor( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + maxLevel); /// /// Gets the content or its nearest ancestor. @@ -802,17 +1245,82 @@ public static class PublishedContentExtensions /// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level. /// /// The content. + /// /// The content cache. /// The query service for the in-memory navigation structure. + /// The query service for the in-memory navigation structure. /// The level. /// The content or its nearest (in down-top order) ancestor, at a level lesser or equal to the specified level. /// May or may not return the content itself depending on its level. May return null. + public static IPublishedContent AncestorOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + int maxLevel) => + content.EnumerateAncestors( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + true) + .FirstOrDefault(x => x.Level <= maxLevel) ?? content; + + /// + /// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level. + /// + /// The content. + /// The content cache. + /// The query service for the in-memory navigation structure. + /// The level. + /// The content or its nearest (in down-top order) ancestor, at a level lesser or equal to the specified level. + /// May or may not return the content itself depending on its level. May return null. + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static IPublishedContent AncestorOrSelf( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, int maxLevel) => - content.EnumerateAncestors(publishedCache, navigationQueryService, true).FirstOrDefault(x => x.Level <= maxLevel) ?? content; + AncestorOrSelf( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + maxLevel); + + /// + /// Gets the content or its nearest ancestor, of a specified content type. + /// + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The content type. + /// The content or its nearest (in down-top order) ancestor, of the specified content type. + /// May or may not return the content itself depending on its content type. May return null. + public static IPublishedContent AncestorOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string contentTypeAlias) + { + ArgumentNullException.ThrowIfNull(content); + + return content + .EnumerateAncestorsOrSelfInternal( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + true, + contentTypeAlias) + .FirstOrDefault() ?? content; + } /// /// Gets the content or its nearest ancestor, of a specified content type. @@ -823,18 +1331,38 @@ public static class PublishedContentExtensions /// The content type. /// The content or its nearest (in down-top order) ancestor, of the specified content type. /// May or may not return the content itself depending on its content type. May return null. + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static IPublishedContent AncestorOrSelf( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, - string contentTypeAlias) - { - ArgumentNullException.ThrowIfNull(content); + string contentTypeAlias) => AncestorOrSelf( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias); - return content - .EnumerateAncestorsOrSelfInternal(publishedCache, navigationQueryService, true, contentTypeAlias) - .FirstOrDefault() ?? content; - } + /// + /// Gets the content or its nearest ancestor, of a specified content type. + /// + /// The content type. + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The content or its nearest (in down-top order) ancestor, of the specified content type. + /// May or may not return the content itself depending on its content type. May return null. + public static T? AncestorOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService) + where T : class, IPublishedContent => + content.AncestorsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService).FirstOrDefault(); /// /// Gets the content or its nearest ancestor, of a specified content type. @@ -845,12 +1373,46 @@ public static class PublishedContentExtensions /// The query service for the in-memory navigation structure. /// The content or its nearest (in down-top order) ancestor, of the specified content type. /// May or may not return the content itself depending on its content type. May return null. + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static T? AncestorOrSelf( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService) where T : class, IPublishedContent => - content.AncestorsOrSelf(publishedCache, navigationQueryService).FirstOrDefault(); + AncestorOrSelf( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService()); + + /// + /// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level, and of a specified + /// content type. + /// + /// The content type. + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// The level. + /// + public static T? AncestorOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + int maxLevel) + where T : class, IPublishedContent => + content.AncestorsOrSelf( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + maxLevel) + .FirstOrDefault(); /// /// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level, and of a specified @@ -862,42 +1424,76 @@ public static class PublishedContentExtensions /// The query service for the in-memory navigation structure. /// The level. /// + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static T? AncestorOrSelf( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, int maxLevel) where T : class, IPublishedContent => - content.AncestorsOrSelf(publishedCache, navigationQueryService, maxLevel).FirstOrDefault(); + AncestorOrSelf( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + maxLevel); + public static IEnumerable AncestorsOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + bool orSelf, + Func? func) + { + IEnumerable ancestorsOrSelf = content.EnumerateAncestors( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + orSelf); + return func == null ? ancestorsOrSelf : ancestorsOrSelf.Where(func); + } + + [Obsolete("Use the overload with IVariationContextAccessor and IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable AncestorsOrSelf( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, bool orSelf, - Func? func) - { - IEnumerable ancestorsOrSelf = content.EnumerateAncestors(publishedCache, navigationQueryService, orSelf); - return func == null ? ancestorsOrSelf : ancestorsOrSelf.Where(func); - } + Func? func) => + AncestorsOrSelf( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + orSelf, + func); /// /// Enumerates ancestors of the content, bottom-up. /// /// The content. + /// The content. /// The content cache. /// The query service for the in-memory navigation structure. + /// /// Indicates whether the content should be included. /// Enumerates bottom-up ie walking up the tree (parent, grand-parent, etc). internal static IEnumerable EnumerateAncestors( this IPublishedContent? content, + IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, bool orSelf) { ArgumentNullException.ThrowIfNull(content); - return content.EnumerateAncestorsOrSelfInternal(publishedCache, navigationQueryService, orSelf); + return content.EnumerateAncestorsOrSelfInternal(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, orSelf); } #endregion @@ -3667,10 +4263,13 @@ public static class PublishedContentExtensions private static IEnumerable EnumerateAncestorsOrSelfInternal( this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, bool orSelf, - string? contentTypeAlias = null) + string? contentTypeAlias = null, + string? culture = null) { if (orSelf) { @@ -3689,8 +4288,14 @@ public static class PublishedContentExtensions yield break; } + culture ??= variationContextAccessor.VariationContext?.Culture ?? string.Empty; foreach (Guid ancestorKey in ancestorsKeys) { + if (publishStatusQueryService.IsDocumentPublished(ancestorKey, culture) is false) + { + yield break; + } + IPublishedContent? ancestor = publishedCache.GetById(ancestorKey); if (ancestor is not null) { diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs index 3b801bc8d7..94294f1330 100644 --- a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs @@ -289,7 +289,7 @@ public static class FriendlyPublishedContentExtensions /// The ancestors of the content, in down-top order. /// Does not consider the content itself. public static IEnumerable Ancestors(this IPublishedContent content) - => content.Ancestors(GetPublishedCache(content), GetNavigationQueryService(content)); + => content.Ancestors(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService); /// /// Gets the content and its ancestors. @@ -297,7 +297,7 @@ public static class FriendlyPublishedContentExtensions /// The content. /// The content and its ancestors, in down-top order. public static IEnumerable AncestorsOrSelf(this IPublishedContent content) - => content.AncestorsOrSelf(GetPublishedCache(content), GetNavigationQueryService(content)); + => content.AncestorsOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService); /// /// Gets the content and its ancestors, of a specified content type. @@ -308,7 +308,7 @@ public static class FriendlyPublishedContentExtensions /// May or may not begin with the content itself, depending on its content type. public static IEnumerable AncestorsOrSelf(this IPublishedContent content) where T : class, IPublishedContent - => content.AncestorsOrSelf(GetPublishedCache(content), GetNavigationQueryService(content)); + => content.AncestorsOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService); /// /// Gets the ancestor of the content, i.e. its parent. @@ -327,7 +327,7 @@ public static class FriendlyPublishedContentExtensions /// Does not consider the content itself. May return null. public static T? Ancestor(this IPublishedContent content) where T : class, IPublishedContent - => content.Ancestor(GetPublishedCache(content), GetNavigationQueryService(content)); + => content.Ancestor(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService); /// /// Gets the content or its nearest ancestor, of a specified content type. @@ -338,7 +338,7 @@ public static class FriendlyPublishedContentExtensions /// May or may not return the content itself depending on its content type. May return null. public static T? AncestorOrSelf(this IPublishedContent content) where T : class, IPublishedContent - => content.AncestorOrSelf(GetPublishedCache(content), GetNavigationQueryService(content)); + => content.AncestorOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService); /// /// Returns all DescendantsOrSelf of all content referenced