diff --git a/src/Umbraco.Core/DeliveryApi/ApiContentRouteBuilder.cs b/src/Umbraco.Core/DeliveryApi/ApiContentRouteBuilder.cs index 306cf7f3ee..221a1a1af5 100644 --- a/src/Umbraco.Core/DeliveryApi/ApiContentRouteBuilder.cs +++ b/src/Umbraco.Core/DeliveryApi/ApiContentRouteBuilder.cs @@ -1,5 +1,7 @@ -using Microsoft.Extensions.Options; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models.DeliveryApi; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PublishedCache; @@ -16,6 +18,7 @@ public sealed class ApiContentRouteBuilder : IApiContentRouteBuilder private readonly IRequestPreviewService _requestPreviewService; private readonly IPublishedContentCache _contentCache; private readonly IDocumentNavigationQueryService _navigationQueryService; + private readonly IPublishStatusQueryService _publishStatusQueryService; private RequestHandlerSettings _requestSettings; public ApiContentRouteBuilder( @@ -25,18 +28,41 @@ public sealed class ApiContentRouteBuilder : IApiContentRouteBuilder IRequestPreviewService requestPreviewService, IOptionsMonitor requestSettings, IPublishedContentCache contentCache, - IDocumentNavigationQueryService navigationQueryService) + IDocumentNavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService) { _apiContentPathProvider = apiContentPathProvider; _variationContextAccessor = variationContextAccessor; _requestPreviewService = requestPreviewService; _contentCache = contentCache; _navigationQueryService = navigationQueryService; + _publishStatusQueryService = publishStatusQueryService; _globalSettings = globalSettings.Value; _requestSettings = requestSettings.CurrentValue; requestSettings.OnChange(settings => _requestSettings = settings); } + [Obsolete("Use constructor that takes an IPublishStatusQueryService instead, scheduled for removal in v17")] + public ApiContentRouteBuilder( + IApiContentPathProvider apiContentPathProvider, + IOptions globalSettings, + IVariationContextAccessor variationContextAccessor, + IRequestPreviewService requestPreviewService, + IOptionsMonitor requestSettings, + IPublishedContentCache contentCache, + IDocumentNavigationQueryService navigationQueryService) + : this( + apiContentPathProvider, + globalSettings, + variationContextAccessor, + requestPreviewService, + requestSettings, + contentCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService()) + { + } + public IApiContentRoute? Build(IPublishedContent content, string? culture = null) { if (content.ItemType != PublishedItemType.Content) @@ -105,7 +131,7 @@ public sealed class ApiContentRouteBuilder : IApiContentRouteBuilder { if (isPreview is false) { - return content.Root(_contentCache, _navigationQueryService); + return content.Root(_variationContextAccessor, _contentCache, _navigationQueryService, _publishStatusQueryService); } _navigationQueryService.TryGetRootKeys(out IEnumerable rootKeys); @@ -114,6 +140,6 @@ public sealed class ApiContentRouteBuilder : IApiContentRouteBuilder // in very edge case scenarios during preview, content.Root() does not map to the root. // we'll code our way around it for the time being. return rootContent.FirstOrDefault(root => root.IsAncestorOrSelf(content)) - ?? content.Root(_contentCache, _navigationQueryService); + ?? content.Root(_variationContextAccessor, _contentCache, _navigationQueryService, _publishStatusQueryService); } } diff --git a/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs b/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs index d36158fdcf..adfdbb6076 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 @@ -987,6 +1583,7 @@ public static class PublishedContentExtensions /// /// Variation context accessor. /// + /// /// /// /// The specific culture to filter for. If null is used the current culture is used. (Default is @@ -1002,9 +1599,69 @@ public static class PublishedContentExtensions IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, string docTypeAlias, string? culture = null) => parentNodes.SelectMany(x => - x.DescendantsOrSelfOfType(variationContextAccessor, publishedCache, navigationQueryService, docTypeAlias, culture)); + x.DescendantsOrSelfOfType(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, docTypeAlias, culture)); + + /// + /// Returns all DescendantsOrSelf of all content referenced + /// + /// + /// Variation context accessor. + /// + /// + /// + /// The specific culture to filter for. If null is used the current culture is used. (Default is + /// null) + /// + /// + /// + /// + /// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot + /// + [Obsolete("Use the overload with IPublishStatusQueryService instead, scheduled for removal in v17")] + public static IEnumerable DescendantsOrSelfOfType( + this IEnumerable parentNodes, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + string docTypeAlias, + string? culture = null) => + DescendantsOrSelfOfType( + parentNodes, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + docTypeAlias, + culture); + + /// + /// Returns all DescendantsOrSelf of all content referenced + /// + /// + /// Variation context accessor. + /// + /// + /// + /// The specific culture to filter for. If null is used the current culture is used. (Default is + /// null) + /// + /// + /// + /// + /// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot + /// + public static IEnumerable DescendantsOrSelf( + this IEnumerable parentNodes, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) + where T : class, IPublishedContent => + parentNodes.SelectMany(x => x.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, culture)); /// /// Returns all DescendantsOrSelf of all content referenced @@ -1021,6 +1678,7 @@ public static class PublishedContentExtensions /// /// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot /// + [Obsolete("Use the overload with IPublishStatusQueryService instead, scheduled for removal in v17")] public static IEnumerable DescendantsOrSelf( this IEnumerable parentNodes, IVariationContextAccessor variationContextAccessor, @@ -1028,7 +1686,13 @@ public static class PublishedContentExtensions INavigationQueryService navigationQueryService, string? culture = null) where T : class, IPublishedContent => - parentNodes.SelectMany(x => x.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, culture)); + DescendantsOrSelf( + parentNodes, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + culture); // as per XPath 1.0 specs �2.2, // - the descendant axis contains the descendants of the context node; a descendant is a child or a child of a child and so on; thus @@ -1053,9 +1717,43 @@ public static class PublishedContentExtensions IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, string? culture = null) => - content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, false, null, culture); + content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, false, null, culture); + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] + public static IEnumerable Descendants( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + string? culture = null) => + Descendants( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + culture); + + public static IEnumerable Descendants( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + int level, + string? culture = null) => + content.DescendantsOrSelf( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + false, + p => p.Level >= level, + culture); + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] public static IEnumerable Descendants( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1063,8 +1761,33 @@ public static class PublishedContentExtensions INavigationQueryService navigationQueryService, int level, string? culture = null) => - content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, false, p => p.Level >= level, culture); + Descendants( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + level, + culture); + public static IEnumerable DescendantsOfType( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string contentTypeAlias, + string? culture = null) => + content.EnumerateDescendantsOrSelfInternal( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + culture, + false, + contentTypeAlias); + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] public static IEnumerable DescendantsOfType( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1072,14 +1795,26 @@ public static class PublishedContentExtensions INavigationQueryService navigationQueryService, string contentTypeAlias, string? culture = null) => - content.EnumerateDescendantsOrSelfInternal( + DescendantsOfType( + content, variationContextAccessor, publishedCache, navigationQueryService, - culture, - false, - contentTypeAlias); + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias, + culture); + public static IEnumerable Descendants( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) + where T : class, IPublishedContent => + content.Descendants(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, culture).OfType(); + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] public static IEnumerable Descendants( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1094,19 +1829,65 @@ public static class PublishedContentExtensions IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, int level, string? culture = null) where T : class, IPublishedContent => - content.Descendants(variationContextAccessor, publishedCache, navigationQueryService, level, culture).OfType(); + content.Descendants(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, level, culture).OfType(); + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] + public static IEnumerable Descendants( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + int level, + string? culture = null) + where T : class, IPublishedContent => + Descendants( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + level, + culture); public static IEnumerable DescendantsOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, string? culture = null) => - content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, true, null, culture); + content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, true, null, culture); + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] + public static IEnumerable DescendantsOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + string? culture = null) => + DescendantsOrSelf( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + culture); + + public static IEnumerable DescendantsOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + int level, + string? culture = null) => + content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, true, p => p.Level >= level, culture); + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] public static IEnumerable DescendantsOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1114,8 +1895,33 @@ public static class PublishedContentExtensions INavigationQueryService navigationQueryService, int level, string? culture = null) => - content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, true, p => p.Level >= level, culture); + DescendantsOrSelf( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + level, + culture); + public static IEnumerable DescendantsOrSelfOfType( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string contentTypeAlias, + string? culture = null) => + content.EnumerateDescendantsOrSelfInternal( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + culture, + true, + contentTypeAlias); + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] public static IEnumerable DescendantsOrSelfOfType( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1123,14 +1929,26 @@ public static class PublishedContentExtensions INavigationQueryService navigationQueryService, string contentTypeAlias, string? culture = null) => - content.EnumerateDescendantsOrSelfInternal( + DescendantsOrSelfOfType( + content, variationContextAccessor, publishedCache, navigationQueryService, - culture, - true, - contentTypeAlias); + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias, + culture); + public static IEnumerable DescendantsOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) + where T : class, IPublishedContent => + content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, culture).OfType(); + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] public static IEnumerable DescendantsOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1138,8 +1956,25 @@ public static class PublishedContentExtensions INavigationQueryService navigationQueryService, string? culture = null) where T : class, IPublishedContent => - content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, culture).OfType(); + content.DescendantsOrSelf( + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + culture); + public static IEnumerable DescendantsOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + int level, + string? culture = null) + where T : class, IPublishedContent => + content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, level, culture).OfType(); + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] public static IEnumerable DescendantsOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1148,41 +1983,118 @@ public static class PublishedContentExtensions int level, string? culture = null) where T : class, IPublishedContent => - content.DescendantsOrSelf(variationContextAccessor, publishedCache, navigationQueryService, level, culture).OfType(); + DescendantsOrSelf( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + level, + culture); + public static IPublishedContent? Descendant( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) => + content.Children( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + culture)?.FirstOrDefault(); + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] public static IPublishedContent? Descendant( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, string? culture = null) => - content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture)?.FirstOrDefault(); + Descendant( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + culture); public static IPublishedContent? Descendant( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, int level, string? culture = null) => content - .EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, false, culture).FirstOrDefault(x => x.Level == level); + .EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, false, culture).FirstOrDefault(x => x.Level == level); + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] + public static IPublishedContent? Descendant( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + int level, + string? culture = null) => + content + .EnumerateDescendants( + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + false, + culture) + .FirstOrDefault(x => x.Level == level); public static IPublishedContent? DescendantOfType( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, string contentTypeAlias, string? culture = null) => content .EnumerateDescendantsOrSelfInternal( variationContextAccessor, publishedCache, navigationQueryService, + publishStatusQueryService, culture, false, contentTypeAlias) .FirstOrDefault(); + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] + public static IPublishedContent? DescendantOfType( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + string contentTypeAlias, + string? culture = null) => + DescendantOfType( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias, + culture); + + public static T? Descendant( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) + where T : class, IPublishedContent => + content.EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, false, culture).FirstOrDefault(x => x is T) as T; + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] public static T? Descendant( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1190,8 +2102,26 @@ public static class PublishedContentExtensions INavigationQueryService navigationQueryService, string? culture = null) where T : class, IPublishedContent => - content.EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, false, culture).FirstOrDefault(x => x is T) as T; + Descendant( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + culture); + public static T? Descendant( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + int level, + string? culture = null) + where T : class, IPublishedContent => + content.Descendant(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, level, culture) as T; + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] public static T? Descendant( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1200,35 +2130,121 @@ public static class PublishedContentExtensions int level, string? culture = null) where T : class, IPublishedContent => - content.Descendant(variationContextAccessor, publishedCache, navigationQueryService, level, culture) as T; + Descendant( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + level, + culture); - public static IPublishedContent DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null) => content; + public static IPublishedContent DescendantOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) => + content.EnumerateDescendants( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + true, + culture) + .FirstOrDefault() ?? + content; + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] + public static IPublishedContent DescendantOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + string? culture = null) => + DescendantOrSelf( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + culture); public static IPublishedContent? DescendantOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, int level, string? culture = null) => content - .EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, true, culture).FirstOrDefault(x => x.Level == level); + .EnumerateDescendants( + variationContextAccessor, + publishedCache, + navigationQueryService, + publishStatusQueryService, + true, + culture) + .FirstOrDefault(x => x.Level == level); + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] + public static IPublishedContent? DescendantOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + int level, + string? culture = null) => + DescendantOrSelf( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + level, + culture); public static IPublishedContent? DescendantOrSelfOfType( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, string contentTypeAlias, string? culture = null) => content .EnumerateDescendantsOrSelfInternal( variationContextAccessor, publishedCache, navigationQueryService, + publishStatusQueryService, culture, true, contentTypeAlias) .FirstOrDefault(); + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] + public static IPublishedContent? DescendantOrSelfOfType( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + string contentTypeAlias, + string? culture = null) => + DescendantOrSelfOfType( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias, + culture); + + public static T? DescendantOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) + where T : class, IPublishedContent => + content.EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, true, culture).FirstOrDefault(x => x is T) as T; + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] public static T? DescendantOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1236,8 +2252,26 @@ public static class PublishedContentExtensions INavigationQueryService navigationQueryService, string? culture = null) where T : class, IPublishedContent => - content.EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, true, culture).FirstOrDefault(x => x is T) as T; + DescendantOrSelf( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + culture); + public static T? DescendantOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + int level, + string? culture = null) + where T : class, IPublishedContent => + content.DescendantOrSelf(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, level, culture) as T; + + [Obsolete("Use the overload with IPublishStatusQuery instead, scheduled for removal in v17")] public static T? DescendantOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1246,17 +2280,25 @@ public static class PublishedContentExtensions int level, string? culture = null) where T : class, IPublishedContent => - content.DescendantOrSelf(variationContextAccessor, publishedCache, navigationQueryService, level, culture) as T; + DescendantOrSelf( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + level, + culture); internal static IEnumerable DescendantsOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, bool orSelf, Func? func, string? culture = null) => - content.EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, orSelf, culture) + content.EnumerateDescendants(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, orSelf, culture) .Where(x => func == null || func(x)); internal static IEnumerable EnumerateDescendants( @@ -1264,6 +2306,7 @@ public static class PublishedContentExtensions IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, bool orSelf, string? culture = null) { @@ -1273,6 +2316,7 @@ public static class PublishedContentExtensions variationContextAccessor, publishedCache, navigationQueryService, + publishStatusQueryService, culture, orSelf)) { @@ -1285,6 +2329,7 @@ public static class PublishedContentExtensions IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, string? culture = null) { yield return content; @@ -1293,6 +2338,7 @@ public static class PublishedContentExtensions variationContextAccessor, publishedCache, navigationQueryService, + publishStatusQueryService, culture, false)) { @@ -1304,6 +2350,48 @@ public static class PublishedContentExtensions #region Axes: children + /// + /// Gets the children of the content item. + /// + /// The content item. + /// + /// + /// + /// + /// The specific culture to get the URL children for. Default is null which will use the current culture in + /// + /// + /// + /// + /// Gets children that are available for the specified culture. + /// Children are sorted by their sortOrder. + /// + /// For culture, + /// if null is used the current culture is used. + /// If an empty string is used only invariant children are returned. + /// If "*" is used all children are returned. + /// + /// + /// If a variant culture is specified or there is a current culture in the then the + /// Children returned + /// will include both the variant children matching the culture AND the invariant children because the invariant + /// children flow with the current culture. + /// However, if an empty string is specified only invariant children are returned. + /// + /// + public static IEnumerable Children( + this IPublishedContent content, + IVariationContextAccessor? variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) + { + IEnumerable children = GetChildren(navigationQueryService, publishedCache, content.Key, publishStatusQueryService, variationContextAccessor, null, culture); + + return children.FilterByCulture(culture, variationContextAccessor); + } + /// /// Gets the children of the content item. /// @@ -1332,6 +2420,7 @@ public static class PublishedContentExtensions /// However, if an empty string is specified only invariant children are returned. /// /// + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable Children( this IPublishedContent content, IVariationContextAccessor? variationContextAccessor, @@ -1339,11 +2428,37 @@ public static class PublishedContentExtensions INavigationQueryService navigationQueryService, string? culture = null) { - IEnumerable children = GetChildren(navigationQueryService, publishedCache, content.Key); - - return children.FilterByCulture(culture, variationContextAccessor); + IPublishStatusQueryService publishStatusQueryService = StaticServiceProvider.Instance.GetRequiredService(); + return Children(content, variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, culture); } + /// + /// Gets the children of the content, filtered by a predicate. + /// + /// The content. + /// The accessor for VariationContext + /// + /// + /// The predicate. + /// + /// The specific culture to filter for. If null is used the current culture is used. (Default is + /// null) + /// + /// + /// The children of the content, filtered by the predicate. + /// + /// Children are sorted by their sortOrder. + /// + public static IEnumerable Children( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + Func predicate, + string? culture = null) => + content.Children(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, culture).Where(predicate); + /// /// Gets the children of the content, filtered by a predicate. /// @@ -1360,6 +2475,7 @@ public static class PublishedContentExtensions /// /// Children are sorted by their sortOrder. /// + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable Children( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1382,6 +2498,7 @@ public static class PublishedContentExtensions /// /// The content type alias. /// The children of the content, of any of the specified types. + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable ChildrenOfType( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1389,14 +2506,68 @@ public static class PublishedContentExtensions INavigationQueryService navigationQueryService, string? contentTypeAlias, string? culture = null) + { + IPublishStatusQueryService publishStatusQueryService = StaticServiceProvider.Instance.GetRequiredService(); + return ChildrenOfType(content, variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, contentTypeAlias, culture); + } + + /// + /// Gets the children of the content, of any of the specified types. + /// + /// The content. + /// + /// + /// + /// The accessor for the VariationContext + /// + /// The specific culture to filter for. If null is used the current culture is used. (Default is + /// null) + /// + /// The content type alias. + /// The children of the content, of any of the specified types. + public static IEnumerable ChildrenOfType( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string? contentTypeAlias, + string? culture = null) { IEnumerable children = contentTypeAlias is not null - ? GetChildren(navigationQueryService, publishedCache, content.Key, contentTypeAlias) + ? GetChildren(navigationQueryService, publishedCache, content.Key, publishStatusQueryService, variationContextAccessor, contentTypeAlias, culture) : []; return children.FilterByCulture(culture, variationContextAccessor); } + /// + /// Gets the children of the content, of a given content type. + /// + /// The content type. + /// The content. + /// The accessor for the VariationContext + /// + /// + /// + /// The specific culture to filter for. If null is used the current culture is used. (Default is + /// null) + /// + /// + /// The children of content, of the given content type. + /// + /// Children are sorted by their sortOrder. + /// + public static IEnumerable Children( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) + where T : class, IPublishedContent => + content.Children(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, culture).OfType(); + /// /// Gets the children of the content, of a given content type. /// @@ -1413,6 +2584,7 @@ public static class PublishedContentExtensions /// /// Children are sorted by their sortOrder. /// + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable Children( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1427,8 +2599,18 @@ public static class PublishedContentExtensions IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, string? culture = null) => - content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture)?.FirstOrDefault(); + content.Children(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, culture)?.FirstOrDefault(); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IPublishedContent? FirstChild( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + string? culture = null) => + FirstChild(content, variationContextAccessor, publishedCache, navigationQueryService, StaticServiceProvider.Instance.GetRequiredService(), culture); /// /// Gets the first child of the content, of a given content type. @@ -1438,29 +2620,97 @@ public static class PublishedContentExtensions IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, string contentTypeAlias, string? culture = null) => content - .ChildrenOfType(variationContextAccessor, publishedCache, navigationQueryService, contentTypeAlias, culture) + .ChildrenOfType(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, contentTypeAlias, culture) .FirstOrDefault(); + /// + /// Gets the first child of the content, of a given content type. + /// + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IPublishedContent? FirstChildOfType( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + string contentTypeAlias, + string? culture = null) => + FirstChildOfType( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias, + culture); + + public static IPublishedContent? FirstChild( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + Func predicate, + string? culture = null) + => content.Children(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, predicate, culture)?.FirstOrDefault(); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IPublishedContent? FirstChild( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, Func predicate, - string? culture = null) - => content.Children(variationContextAccessor, publishedCache, navigationQueryService, predicate, culture)?.FirstOrDefault(); + string? culture = null) => + FirstChild( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + predicate, + culture); public static IPublishedContent? FirstChild( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, Guid uniqueId, string? culture = null) => content - .Children(variationContextAccessor, publishedCache, navigationQueryService, x => x.Key == uniqueId, culture)?.FirstOrDefault(); + .Children(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, x => x.Key == uniqueId, culture)?.FirstOrDefault(); + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IPublishedContent? FirstChild( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + Guid uniqueId, + string? culture = null) => + FirstChild( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + uniqueId, + culture); + + public static T? FirstChild( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) + where T : class, IPublishedContent => + content.Children(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, culture)?.FirstOrDefault(); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static T? FirstChild( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1468,8 +2718,20 @@ public static class PublishedContentExtensions INavigationQueryService navigationQueryService, string? culture = null) where T : class, IPublishedContent => - content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture)?.FirstOrDefault(); + FirstChild(content, variationContextAccessor, publishedCache, navigationQueryService, StaticServiceProvider.Instance.GetRequiredService(), culture); + public static T? FirstChild( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + Func predicate, + string? culture = null) + where T : class, IPublishedContent => + content.Children(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, culture)?.FirstOrDefault(predicate); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static T? FirstChild( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1478,12 +2740,45 @@ public static class PublishedContentExtensions Func predicate, string? culture = null) where T : class, IPublishedContent => - content.Children(variationContextAccessor, publishedCache, navigationQueryService, culture)?.FirstOrDefault(predicate); + FirstChild( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + predicate, + culture); #endregion #region Axes: siblings + /// + /// Gets the siblings of the content. + /// + /// The content. + /// The navigation service + /// Variation context accessor. + /// + /// + /// The specific culture to filter for. If null is used the current culture is used. (Default is + /// null) + /// + /// The content cache instance. + /// The siblings of the content. + /// + /// Note that in V7 this method also return the content node self. + /// + public static IEnumerable Siblings( + this IPublishedContent content, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) => + SiblingsAndSelf(content, publishedCache, navigationQueryService, variationContextAccessor, publishStatusQueryService, culture) + ?.Where(x => x.Id != content.Id) ?? Enumerable.Empty(); + /// /// Gets the siblings of the content. /// @@ -1499,14 +2794,48 @@ public static class PublishedContentExtensions /// /// Note that in V7 this method also return the content node self. /// + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable Siblings( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, IVariationContextAccessor variationContextAccessor, string? culture = null) => - SiblingsAndSelf(content, publishedCache, navigationQueryService, variationContextAccessor, culture) - ?.Where(x => x.Id != content.Id) ?? Enumerable.Empty(); + Siblings( + content, + publishedCache, + navigationQueryService, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + culture); + + /// + /// Gets the siblings of the content, of a given content type. + /// + /// The content. + /// Variation context accessor. + /// + /// The specific culture to filter for. If null is used the current culture is used. (Default is + /// null) + /// + /// + /// + /// + /// The content type alias. + /// The siblings of the content, of the given content type. + /// + /// Note that in V7 this method also return the content node self. + /// + public static IEnumerable SiblingsOfType( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string contentTypeAlias, + string? culture = null) => + SiblingsAndSelfOfType(content, variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, contentTypeAlias, culture) + .Where(x => x.Id != content.Id); /// /// Gets the siblings of the content, of a given content type. @@ -1524,6 +2853,7 @@ public static class PublishedContentExtensions /// /// Note that in V7 this method also return the content node self. /// + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable SiblingsOfType( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -1531,8 +2861,14 @@ public static class PublishedContentExtensions INavigationQueryService navigationQueryService, string contentTypeAlias, string? culture = null) => - SiblingsAndSelfOfType(content, variationContextAccessor, publishedCache, navigationQueryService, contentTypeAlias, culture) - .Where(x => x.Id != content.Id); + SiblingsOfType( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias, + culture); /// /// Gets the siblings of the content, of a given content type. @@ -1542,6 +2878,7 @@ public static class PublishedContentExtensions /// Variation context accessor. /// /// + /// /// /// The specific culture to filter for. If null is used the current culture is used. (Default is /// null) @@ -1555,11 +2892,87 @@ public static class PublishedContentExtensions IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, string? culture = null) where T : class, IPublishedContent => - SiblingsAndSelf(content, variationContextAccessor, publishedCache, navigationQueryService, culture) + SiblingsAndSelf(content, variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, culture) ?.Where(x => x.Id != content.Id) ?? Enumerable.Empty(); + /// + /// Gets the siblings of the content, of a given content type. + /// + /// The content type. + /// The content. + /// Variation context accessor. + /// + /// + /// + /// The specific culture to filter for. If null is used the current culture is used. (Default is + /// null) + /// + /// The siblings of the content, of the given content type. + /// + /// Note that in V7 this method also return the content node self. + /// + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IEnumerable Siblings( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + string? culture = null) + where T : class, IPublishedContent => + Siblings( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + culture); + + /// + /// Gets the siblings of the content including the node itself to indicate the position. + /// + /// The content. + /// Cache instance. + /// The navigation service. + /// Variation context accessor. + /// + /// + /// The specific culture to filter for. If null is used the current culture is used. (Default is + /// null) + /// + /// The siblings of the content including the node itself. + public static IEnumerable? SiblingsAndSelf( + this IPublishedContent content, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) + { + var success = navigationQueryService.TryGetParentKey(content.Key, out Guid? parentKey); + + if (success is false || parentKey is null) + { + if (navigationQueryService.TryGetRootKeys(out IEnumerable childrenKeys) is false) + { + return null; + } + + culture ??= variationContextAccessor.VariationContext?.Culture ?? string.Empty; + return childrenKeys + .Where(x => publishStatusQueryService.IsDocumentPublished(x , culture)) + .Select(publishedCache.GetById) + .WhereNotNull() + .WhereIsInvariantOrHasCulture(variationContextAccessor, culture); + } + + return navigationQueryService.TryGetChildrenKeys(parentKey.Value, out IEnumerable siblingKeys) is false + ? null + : siblingKeys.Select(publishedCache.GetById).WhereNotNull(); + } + /// /// Gets the siblings of the content including the node itself to indicate the position. /// @@ -1572,31 +2985,66 @@ public static class PublishedContentExtensions /// null) /// /// The siblings of the content including the node itself. + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable? SiblingsAndSelf( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, IVariationContextAccessor variationContextAccessor, + string? culture = null) => + SiblingsAndSelf( + content, + publishedCache, + navigationQueryService, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + culture); + + /// + /// Gets the siblings of the content including the node itself to indicate the position, of a given content type. + /// + /// The content. + /// Variation context accessor. + /// + /// The specific culture to filter for. If null is used the current culture is used. (Default is + /// null) + /// + /// + /// + /// The content type alias. + /// + /// The siblings of the content including the node itself, of the given content type. + public static IEnumerable SiblingsAndSelfOfType( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, + string contentTypeAlias, string? culture = null) { - var success = navigationQueryService.TryGetParentKey(content.Key, out Guid? parentKey); + var parentExists = navigationQueryService.TryGetParentKey(content.Key, out Guid? parentKey); - if (success is false || parentKey is null) + IPublishedContent? parent = parentKey is null + ? null + : publishedCache.GetById(parentKey.Value); + + if (parentExists && parent is not null) { - if (navigationQueryService.TryGetRootKeys(out IEnumerable childrenKeys) is false) - { - return null; - } - - return childrenKeys - .Select(publishedCache.GetById) - .WhereNotNull() - .WhereIsInvariantOrHasCulture(variationContextAccessor, culture); + return parent.ChildrenOfType(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, contentTypeAlias, culture); } - return navigationQueryService.TryGetChildrenKeys(parentKey.Value, out IEnumerable siblingKeys) is false - ? null - : siblingKeys.Select(publishedCache.GetById).WhereNotNull(); + if (navigationQueryService.TryGetRootKeysOfType(contentTypeAlias, out IEnumerable rootKeysOfType) is false) + { + return []; + } + + culture ??= variationContextAccessor.VariationContext?.Culture ?? string.Empty; + return rootKeysOfType + .Where(x => publishStatusQueryService.IsDocumentPublished(x, culture)) + .Select(publishedCache.GetById) + .WhereNotNull() + .WhereIsInvariantOrHasCulture(variationContextAccessor, culture); } /// @@ -1612,35 +3060,22 @@ public static class PublishedContentExtensions /// The content type alias. /// /// The siblings of the content including the node itself, of the given content type. + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable SiblingsAndSelfOfType( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, string contentTypeAlias, - string? culture = null) - { - var parentExists = navigationQueryService.TryGetParentKey(content.Key, out Guid? parentKey); - - IPublishedContent? parent = parentKey is null - ? null - : publishedCache.GetById(parentKey.Value); - - if (parentExists && parent is not null) - { - return parent.ChildrenOfType(variationContextAccessor, publishedCache, navigationQueryService, contentTypeAlias, culture); - } - - if (navigationQueryService.TryGetRootKeysOfType(contentTypeAlias, out IEnumerable rootKeysOfType) is false) - { - return []; - } - - return rootKeysOfType - .Select(publishedCache.GetById) - .WhereNotNull() - .WhereIsInvariantOrHasCulture(variationContextAccessor, culture); - } + string? culture = null) => + SiblingsAndSelfOfType( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias, + culture); /// /// Gets the siblings of the content including the node itself to indicate the position, of a given content type. @@ -1649,6 +3084,7 @@ public static class PublishedContentExtensions /// The content. /// Variation context accessor. /// + /// /// /// The specific culture to filter for. If null is used the current culture is used. (Default is /// null) @@ -1660,6 +3096,7 @@ public static class PublishedContentExtensions IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, string? culture = null) where T : class, IPublishedContent { @@ -1674,20 +3111,73 @@ public static class PublishedContentExtensions return []; } + culture ??= variationContextAccessor.VariationContext?.Culture ?? string.Empty; return rootKeys + .Where(x => publishStatusQueryService.IsDocumentPublished(x, culture)) .Select(publishedCache.GetById) .WhereNotNull() .WhereIsInvariantOrHasCulture(variationContextAccessor, culture) .OfType(); } - return parent.Children(variationContextAccessor, publishedCache, navigationQueryService, culture); + return parent.Children(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, culture); } + /// + /// Gets the siblings of the content including the node itself to indicate the position, of a given content type. + /// + /// The content type. + /// The content. + /// Variation context accessor. + /// + /// + /// The specific culture to filter for. If null is used the current culture is used. (Default is + /// null) + /// + /// + /// The siblings of the content including the node itself, of the given content type. + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IEnumerable SiblingsAndSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + string? culture = null) + where T : class, IPublishedContent => SiblingsAndSelf( + content, + variationContextAccessor, + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService(), + culture); + #endregion #region Axes: custom + /// + /// Gets the root content (ancestor or self at level 1) for the specified . + /// + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// + /// The root content (ancestor or self at level 1) for the specified . + /// + /// + /// This is the same as calling + /// with maxLevel + /// set to 1. + /// + public static IPublishedContent Root( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService) => content.AncestorOrSelf(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, 1); + /// /// Gets the root content (ancestor or self at level 1) for the specified . /// @@ -1702,10 +3192,44 @@ public static class PublishedContentExtensions /// with maxLevel /// set to 1. /// + [Obsolete("Use the overload with IVariationContextAccessor & IPublishStatusQueryService, scheduled for removal in v17")] public static IPublishedContent Root( this IPublishedContent content, IPublishedCache publishedCache, - INavigationQueryService navigationQueryService) => content.AncestorOrSelf(publishedCache, navigationQueryService, 1); + INavigationQueryService navigationQueryService) => Root( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService()); + + /// + /// Gets the root content (ancestor or self at level 1) for the specified if it's of the + /// specified content type . + /// + /// The content type. + /// The content. + /// + /// The content cache. + /// The query service for the in-memory navigation structure. + /// + /// + /// The root content (ancestor or self at level 1) for the specified of content type + /// . + /// + /// + /// This is the same as calling + /// with + /// maxLevel set to 1. + /// + public static T? Root( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishedCache publishedCache, + INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService) + where T : class, IPublishedContent => + content.AncestorOrSelf(variationContextAccessor, publishedCache, navigationQueryService, publishStatusQueryService, 1); /// /// Gets the root content (ancestor or self at level 1) for the specified if it's of the @@ -1724,12 +3248,18 @@ public static class PublishedContentExtensions /// with /// maxLevel set to 1. /// + [Obsolete("Use the overload with IVariationContextAccessor & PublishStatusQueryService, scheduled for removal in v17")] public static T? Root( this IPublishedContent content, IPublishedCache publishedCache, INavigationQueryService navigationQueryService) where T : class, IPublishedContent => - content.AncestorOrSelf(publishedCache, navigationQueryService, 1); + Root( + content, + StaticServiceProvider.Instance.GetRequiredService(), + publishedCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService()); #endregion @@ -2037,36 +3567,78 @@ public static class PublishedContentExtensions public static IEnumerable Children( this IPublishedContent content, IVariationContextAccessor? variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, string? culture = null) - => Children(content, variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture); + => Children(content, variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), publishStatusQueryService, culture); + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IEnumerable Children( + this IPublishedContent content, + IVariationContextAccessor? variationContextAccessor, + string? culture = null) + => Children(content, variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), StaticServiceProvider.Instance.GetRequiredService(), culture); + + public static IEnumerable Children( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + Func predicate, + string? culture = null) => + content.Children(variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), publishStatusQueryService, culture).Where(predicate); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable Children( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Func predicate, string? culture = null) => - content.Children(variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture).Where(predicate); + Children( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + predicate, + culture); + public static IEnumerable ChildrenOfType( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + string? contentTypeAlias, + string? culture = null) + { + IEnumerable children = contentTypeAlias is not null + ? GetChildren(GetNavigationQueryService(content), GetPublishedCache(content), content.Key, publishStatusQueryService, variationContextAccessor, contentTypeAlias, culture) + : []; + + return children.FilterByCulture(culture, variationContextAccessor); + } + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable ChildrenOfType( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? contentTypeAlias, string? culture = null) { - IEnumerable children = contentTypeAlias is not null - ? GetChildren(GetNavigationQueryService(content), GetPublishedCache(content), content.Key, contentTypeAlias) - : []; - - return children.FilterByCulture(culture, variationContextAccessor); + IPublishStatusQueryService publishStatusQueryService = StaticServiceProvider.Instance.GetRequiredService(); + return ChildrenOfType(content, variationContextAccessor, publishStatusQueryService, contentTypeAlias, culture); } public static IEnumerable Children( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, string? culture = null) where T : class, IPublishedContent => - content.Children(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), culture).OfType(); + content.Children(variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), publishStatusQueryService, culture).OfType(); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IEnumerable Children( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + string? culture = null) + where T : class, IPublishedContent => + Children(content, variationContextAccessor, StaticServiceProvider.Instance.GetRequiredService(), culture); public static DataTable ChildrenAsTable( this IPublishedContent content, @@ -2083,233 +3655,591 @@ public static class PublishedContentExtensions public static IEnumerable DescendantsOrSelfOfType( this IEnumerable parentNodes, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, string docTypeAlias, - string? culture = null) => parentNodes.SelectMany(x => - x.DescendantsOrSelfOfType(variationContextAccessor, GetPublishedCache(parentNodes.First()), - GetNavigationQueryService(parentNodes.First()), docTypeAlias, culture)); + string? culture = null) => + parentNodes.SelectMany(x => x.DescendantsOrSelfOfType( + variationContextAccessor, + GetPublishedCache(parentNodes.First()), + GetNavigationQueryService(parentNodes.First()), + publishStatusQueryService, + docTypeAlias, + culture)); + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IEnumerable DescendantsOrSelfOfType( + this IEnumerable parentNodes, + IVariationContextAccessor variationContextAccessor, + string docTypeAlias, + string? culture = null) => + DescendantsOrSelfOfType( + parentNodes, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + docTypeAlias, + culture); + public static IEnumerable DescendantsOrSelf( + this IEnumerable parentNodes, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) + where T : class, IPublishedContent => + parentNodes.SelectMany( + x => x.DescendantsOrSelf( + variationContextAccessor, + GetPublishedCache(parentNodes.First()), + GetNavigationQueryService(parentNodes.First()), + publishStatusQueryService, + culture)); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable DescendantsOrSelf( this IEnumerable parentNodes, IVariationContextAccessor variationContextAccessor, string? culture = null) where T : class, IPublishedContent => - parentNodes.SelectMany(x => x.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(parentNodes.First()), - GetNavigationQueryService(parentNodes.First()), culture)); + DescendantsOrSelf(parentNodes, variationContextAccessor, StaticServiceProvider.Instance.GetRequiredService(), culture); + public static IEnumerable Descendants( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) => + content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), publishStatusQueryService, false, null, culture); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IEnumerable Descendants( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + string? culture = null) => + Descendants(content, variationContextAccessor, StaticServiceProvider.Instance.GetRequiredService(), culture); public static IEnumerable Descendants( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + int level, string? culture = null) => - content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), false, null, culture); - + content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), publishStatusQueryService, false, p => p.Level >= level, culture); + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable Descendants( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null) => - content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), false, p => p.Level >= level, culture); + Descendants( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + level, + culture); public static IEnumerable DescendantsOfType( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, string contentTypeAlias, string? culture = null) => content.EnumerateDescendantsOrSelfInternal( variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), + publishStatusQueryService, culture, false, contentTypeAlias); + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IEnumerable DescendantsOfType( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + string contentTypeAlias, + string? culture = null) => + DescendantsOfType( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias, + culture); + + public static IEnumerable Descendants( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) + where T : class, IPublishedContent => + content.Descendants(variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), publishStatusQueryService, culture).OfType(); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable Descendants( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null) where T : class, IPublishedContent => - content.Descendants(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), culture).OfType(); + Descendants(content, variationContextAccessor, StaticServiceProvider.Instance.GetRequiredService(), culture); + public static IEnumerable Descendants( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + int level, + string? culture = null) + where T : class, IPublishedContent => + content.Descendants(variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), publishStatusQueryService, level, culture).OfType(); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable Descendants( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null) where T : class, IPublishedContent => - content.Descendants(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), level, culture).OfType(); + Descendants( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + level, + culture); public static IEnumerable DescendantsOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, string? culture = null) => - content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), true, null, culture); + content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), publishStatusQueryService, true, null, culture); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IEnumerable DescendantsOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + string? culture = null) => + DescendantsOrSelf( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + culture); + public static IEnumerable DescendantsOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + int level, + string? culture = null) => + content.DescendantsOrSelf( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + true, + p => p.Level >= level, + culture); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable DescendantsOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null) => - content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), true, p => p.Level >= level, culture); - + DescendantsOrSelf( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + level, + culture); public static IEnumerable DescendantsOrSelfOfType( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, string contentTypeAlias, string? culture = null) => content.EnumerateDescendantsOrSelfInternal( variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), + publishStatusQueryService, culture, true, contentTypeAlias); + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IEnumerable DescendantsOrSelfOfType( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + string contentTypeAlias, + string? culture = null) => + DescendantsOrSelfOfType( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias, + culture); + + public static IEnumerable DescendantsOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) + where T : class, IPublishedContent => + content.DescendantsOrSelf( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + culture).OfType(); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable DescendantsOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null) where T : class, IPublishedContent => - content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), culture).OfType(); + DescendantsOrSelf( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + culture); + public static IEnumerable DescendantsOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + int level, + string? culture = null) + where T : class, IPublishedContent => + content.DescendantsOrSelf( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + level, + culture).OfType(); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IEnumerable DescendantsOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null) where T : class, IPublishedContent => - content.DescendantsOrSelf(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), level, culture).OfType(); + DescendantsOrSelf( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + level, + culture); + public static IPublishedContent? Descendant( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) => + content.Children(variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), publishStatusQueryService, culture)?.FirstOrDefault(); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IPublishedContent? Descendant( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null) => - content.Children(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), culture)?.FirstOrDefault(); + Descendant( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + culture); public static IPublishedContent? Descendant( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, int level, string? culture = null) => content - .EnumerateDescendants(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), false, culture).FirstOrDefault(x => x.Level == level); + .EnumerateDescendants( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + false, + culture).FirstOrDefault(x => x.Level == level); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IPublishedContent? Descendant( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + int level, + string? culture = null) => + Descendant( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + level, + culture); public static IPublishedContent? DescendantOfType( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, string contentTypeAlias, string? culture = null) => content .EnumerateDescendantsOrSelfInternal( variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), + publishStatusQueryService, culture, false, contentTypeAlias) .FirstOrDefault(); + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IPublishedContent? DescendantOfType( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + string contentTypeAlias, + string? culture = null) => + DescendantOfType( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias, + culture); + + public static T? Descendant( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) + where T : class, IPublishedContent => + content.EnumerateDescendants( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + false, + culture) + .FirstOrDefault(x => x is T) as T; + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static T? Descendant( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null) where T : class, IPublishedContent => - content.EnumerateDescendants(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), false, culture).FirstOrDefault(x => x is T) as T; + Descendant( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + culture); + public static T? Descendant( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + int level, + string? culture = null) + where T : class, IPublishedContent => + content.Descendant( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + level, + culture) as T; + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static T? Descendant( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null) where T : class, IPublishedContent => - content.Descendant(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), level, culture) as T; + Descendant( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + level, + culture); public static IPublishedContent? DescendantOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, int level, string? culture = null) => content - .EnumerateDescendants(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), true, culture).FirstOrDefault(x => x.Level == level); + .EnumerateDescendants( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + true, + culture).FirstOrDefault(x => x.Level == level); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IPublishedContent? DescendantOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + int level, + string? culture = null) => DescendantOrSelf(content, variationContextAccessor, StaticServiceProvider.Instance.GetRequiredService(), level, culture); public static IPublishedContent? DescendantOrSelfOfType( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, string contentTypeAlias, string? culture = null) => content .EnumerateDescendantsOrSelfInternal( variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), + publishStatusQueryService, culture, true, contentTypeAlias) .FirstOrDefault(); + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IPublishedContent? DescendantOrSelfOfType( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + string contentTypeAlias, + string? culture = null) => + DescendantOrSelfOfType( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias, + culture); + + public static T? DescendantOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + string? culture = null) + where T : class, IPublishedContent => + content.EnumerateDescendants( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + true, + culture).FirstOrDefault(x => x is T) as T; + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static T? DescendantOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null) where T : class, IPublishedContent => - content.EnumerateDescendants(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), true, culture).FirstOrDefault(x => x is T) as T; + DescendantOrSelf( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + culture); + public static T? DescendantOrSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + int level, + string? culture = null) + where T : class, IPublishedContent => + content.DescendantOrSelf(variationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), publishStatusQueryService, level, culture) as T; + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static T? DescendantOrSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string? culture = null) where T : class, IPublishedContent => - content.DescendantOrSelf(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), level, culture) as T; + DescendantOrSelf( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + level, + culture); public static IPublishedContent? FirstChild( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, string? culture = null) => - content.Children(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), culture)?.FirstOrDefault(); + content.Children( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + culture)?.FirstOrDefault(); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IPublishedContent? FirstChild( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + string? culture = null) => + FirstChild(content, variationContextAccessor, StaticServiceProvider.Instance.GetRequiredService(), culture); public static IPublishedContent? FirstChildOfType( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, string contentTypeAlias, string? culture = null) => - content.ChildrenOfType(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), contentTypeAlias, culture)?.FirstOrDefault(); + content.ChildrenOfType( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + contentTypeAlias, + culture)?.FirstOrDefault(); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IPublishedContent? FirstChildOfType( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + string contentTypeAlias, + string? culture = null) => + FirstChildOfType( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeAlias, + culture); + public static IPublishedContent? FirstChild( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + Func predicate, + string? culture = null) => + content.Children( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + predicate, + culture)?.FirstOrDefault(); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] public static IPublishedContent? FirstChild( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, @@ -2322,20 +4252,70 @@ public static class PublishedContentExtensions public static IPublishedContent? FirstChild( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, Guid uniqueId, string? culture = null) => content - .Children(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), x => x.Key == uniqueId, culture)?.FirstOrDefault(); + .Children( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + x => x.Key == uniqueId, + culture)?.FirstOrDefault(); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IPublishedContent? FirstChild( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + Guid uniqueId, + string? culture = null) => + FirstChild( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + uniqueId, + culture); public static T? FirstChild( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, string? culture = null) where T : class, IPublishedContent => - content.Children(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), culture)?.FirstOrDefault(); + content.Children( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + culture)?.FirstOrDefault(); + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static T? FirstChild( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + string? culture = null) + where T : class, IPublishedContent => + FirstChild( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + culture); + + + public static T? FirstChild( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, + Func predicate, + string? culture = null) + where T : class, IPublishedContent => + content.Children( + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + culture)?.FirstOrDefault(predicate); public static T? FirstChild( this IPublishedContent content, @@ -2343,8 +4323,12 @@ public static class PublishedContentExtensions Func predicate, string? culture = null) where T : class, IPublishedContent => - content.Children(variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), culture)?.FirstOrDefault(predicate); + FirstChild( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + predicate, + culture); [Obsolete( "Please use IPublishedCache and IDocumentNavigationQueryService or IMediaNavigationQueryService directly. This will be removed in a future version of Umbraco")] @@ -2393,9 +4377,27 @@ public static class PublishedContentExtensions public static IEnumerable SiblingsAndSelf( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, + IPublishStatusQueryService publishStatusQueryService, string? culture = null) - where T : class, IPublishedContent => SiblingsAndSelf(content, variationContextAccessor, GetPublishedCache(content), - GetNavigationQueryService(content), culture); + where T : class, IPublishedContent => + SiblingsAndSelf( + content, + variationContextAccessor, + GetPublishedCache(content), + GetNavigationQueryService(content), + publishStatusQueryService, + culture); + + [Obsolete("Use the overload with IPublishStatusQueryService, scheduled for removal in v17")] + public static IEnumerable SiblingsAndSelf( + this IPublishedContent content, + IVariationContextAccessor variationContextAccessor, + string? culture = null) + where T : class, IPublishedContent => SiblingsAndSelf( + content, + variationContextAccessor, + StaticServiceProvider.Instance.GetRequiredService(), + culture); private static INavigationQueryService GetNavigationQueryService(IPublishedContent content) @@ -2429,7 +4431,10 @@ public static class PublishedContentExtensions INavigationQueryService navigationQueryService, IPublishedCache publishedCache, Guid parentKey, - string? contentTypeAlias = null) + IPublishStatusQueryService publishStatusQueryService, + IVariationContextAccessor? variationContextAccessor, + string? contentTypeAlias = null, + string? culture = null) { var nodeExists = contentTypeAlias is null ? navigationQueryService.TryGetChildrenKeys(parentKey, out IEnumerable childrenKeys) @@ -2439,8 +4444,14 @@ public static class PublishedContentExtensions { return []; } + // We need to filter what keys are published, as calling the GetById + // with a non-existing published node, will get cache misses and call the DB + // making it a very slow operation. + + culture ??= variationContextAccessor?.VariationContext?.Culture ?? string.Empty; return childrenKeys + .Where(x => publishStatusQueryService.IsDocumentPublished(x, culture)) .Select(publishedCache.GetById) .WhereNotNull(); } @@ -2463,6 +4474,7 @@ public static class PublishedContentExtensions IVariationContextAccessor variationContextAccessor, IPublishedCache publishedCache, INavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService, string? culture, bool orSelf, string? contentTypeAlias = null) @@ -2484,7 +4496,9 @@ public static class PublishedContentExtensions yield break; } + culture ??= variationContextAccessor?.VariationContext?.Culture ?? string.Empty; IEnumerable descendants = descendantsKeys + .Where(x => publishStatusQueryService.IsDocumentPublished(x, culture)) .Select(publishedCache.GetById) .WhereNotNull() .FilterByCulture(culture, variationContextAccessor); @@ -2497,10 +4511,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) { @@ -2519,8 +4536,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.Core/Routing/ContentFinderByUrlAlias.cs b/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs index f592fb0a0f..39cd4c8854 100644 --- a/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs +++ b/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs @@ -1,4 +1,6 @@ +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Services.Navigation; @@ -24,6 +26,7 @@ public class ContentFinderByUrlAlias : IContentFinder private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IPublishedContentCache _contentCache; private readonly IDocumentNavigationQueryService _documentNavigationQueryService; + private readonly IPublishStatusQueryService _publishStatusQueryService; private readonly IVariationContextAccessor _variationContextAccessor; /// @@ -35,16 +38,37 @@ public class ContentFinderByUrlAlias : IContentFinder IVariationContextAccessor variationContextAccessor, IUmbracoContextAccessor umbracoContextAccessor, IPublishedContentCache contentCache, - IDocumentNavigationQueryService documentNavigationQueryService) + IDocumentNavigationQueryService documentNavigationQueryService, + IPublishStatusQueryService publishStatusQueryService) { _publishedValueFallback = publishedValueFallback; _variationContextAccessor = variationContextAccessor; _umbracoContextAccessor = umbracoContextAccessor; _contentCache = contentCache; _documentNavigationQueryService = documentNavigationQueryService; + _publishStatusQueryService = publishStatusQueryService; _logger = logger; } + [Obsolete("Please use constructor that takes an IPublishStatusQueryService instead. Scheduled removal in v17")] + public ContentFinderByUrlAlias( + ILogger logger, + IPublishedValueFallback publishedValueFallback, + IVariationContextAccessor variationContextAccessor, + IUmbracoContextAccessor umbracoContextAccessor, + IPublishedContentCache contentCache, + IDocumentNavigationQueryService documentNavigationQueryService) + : this( + logger, + publishedValueFallback, + variationContextAccessor, + umbracoContextAccessor, + contentCache, + documentNavigationQueryService, + StaticServiceProvider.Instance.GetRequiredService()) + { + } + /// /// Tries to find and assign an Umbraco document to a PublishedRequest. /// @@ -145,14 +169,14 @@ public class ContentFinderByUrlAlias : IContentFinder if (rootNodeId > 0) { IPublishedContent? rootNode = cache?.GetById(rootNodeId); - return rootNode?.Descendants(_variationContextAccessor, _contentCache, _documentNavigationQueryService).FirstOrDefault(x => IsMatch(x, test1, test2)); + return rootNode?.Descendants(_variationContextAccessor, _contentCache, _documentNavigationQueryService, _publishStatusQueryService).FirstOrDefault(x => IsMatch(x, test1, test2)); } if (cache is not null) { foreach (IPublishedContent rootContent in cache.GetAtRoot()) { - IPublishedContent? c = rootContent.DescendantsOrSelf(_variationContextAccessor, _contentCache, _documentNavigationQueryService) + IPublishedContent? c = rootContent.DescendantsOrSelf(_variationContextAccessor, _contentCache, _documentNavigationQueryService, _publishStatusQueryService) .FirstOrDefault(x => IsMatch(x, test1, test2)); if (c != null) { diff --git a/src/Umbraco.Core/Routing/UrlProvider.cs b/src/Umbraco.Core/Routing/UrlProvider.cs index f40c240a73..f034fbf8b9 100644 --- a/src/Umbraco.Core/Routing/UrlProvider.cs +++ b/src/Umbraco.Core/Routing/UrlProvider.cs @@ -27,6 +27,28 @@ namespace Umbraco.Cms.Core.Routing /// The current variation accessor. /// The content cache. /// The query service for the in-memory navigation structure. + /// The publish status query service, to query if a given content is published in a given culture. + public UrlProvider( + IUmbracoContextAccessor umbracoContextAccessor, + IOptions routingSettings, + UrlProviderCollection urlProviders, + MediaUrlProviderCollection mediaUrlProviders, + IVariationContextAccessor variationContextAccessor, + IPublishedContentCache contentCache, + IDocumentNavigationQueryService navigationQueryService, + IPublishStatusQueryService publishStatusQueryService) + { + _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); + _urlProviders = urlProviders; + _mediaUrlProviders = mediaUrlProviders; + _variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor)); + _contentCache = contentCache; + _navigationQueryService = navigationQueryService; + _publishStatusQueryService = publishStatusQueryService; + Mode = routingSettings.Value.UrlProviderMode; + } + + [Obsolete("Use the constructor that takes all parameters. Scheduled for removal in V17.")] public UrlProvider( IUmbracoContextAccessor umbracoContextAccessor, IOptions routingSettings, @@ -35,14 +57,16 @@ namespace Umbraco.Cms.Core.Routing IVariationContextAccessor variationContextAccessor, IPublishedContentCache contentCache, IDocumentNavigationQueryService navigationQueryService) + : this( + umbracoContextAccessor, + routingSettings, + urlProviders, + mediaUrlProviders, + variationContextAccessor, + contentCache, + navigationQueryService, + StaticServiceProvider.Instance.GetRequiredService()) { - _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); - _urlProviders = urlProviders; - _mediaUrlProviders = mediaUrlProviders; - _variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor)); - _contentCache = contentCache; - _navigationQueryService = navigationQueryService; - Mode = routingSettings.Value.UrlProviderMode; } [Obsolete("Use the constructor that takes all parameters. Scheduled for removal in V17.")] @@ -59,7 +83,8 @@ namespace Umbraco.Cms.Core.Routing mediaUrlProviders, variationContextAccessor, StaticServiceProvider.Instance.GetRequiredService(), - StaticServiceProvider.Instance.GetRequiredService()) + StaticServiceProvider.Instance.GetRequiredService(), + StaticServiceProvider.Instance.GetRequiredService()) { } @@ -69,6 +94,7 @@ namespace Umbraco.Cms.Core.Routing private readonly IVariationContextAccessor _variationContextAccessor; private readonly IPublishedContentCache _contentCache; private readonly IDocumentNavigationQueryService _navigationQueryService; + private readonly IPublishStatusQueryService _publishStatusQueryService; /// /// Gets or sets the provider URL mode. @@ -147,7 +173,7 @@ namespace Umbraco.Cms.Core.Routing // be nice with tests, assume things can be null, ultimately fall back to invariant // (but only for variant content of course) // We need to check all ancestors because urls are variant even for invariant content, if an ancestor is variant. - if (culture == null && content.AncestorsOrSelf(_contentCache, _navigationQueryService).Any(x => x.ContentType.VariesByCulture())) + if (culture == null && content.AncestorsOrSelf(_variationContextAccessor, _contentCache, _navigationQueryService, _publishStatusQueryService).Any(x => x.ContentType.VariesByCulture())) { culture = _variationContextAccessor?.VariationContext?.Culture ?? string.Empty; } diff --git a/src/Umbraco.Core/Services/PublishStatus/PublishStatusService.cs b/src/Umbraco.Core/Services/PublishStatus/PublishStatusService.cs index 17694873c5..c6d1f7481f 100644 --- a/src/Umbraco.Core/Services/PublishStatus/PublishStatusService.cs +++ b/src/Umbraco.Core/Services/PublishStatus/PublishStatusService.cs @@ -1,5 +1,7 @@ using System.Collections.Concurrent; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Persistence.Repositories; using Umbraco.Cms.Core.Scoping; @@ -10,15 +12,31 @@ public class PublishStatusService : IPublishStatusManagementService, IPublishSta private readonly ILogger _logger; private readonly IPublishStatusRepository _publishStatusRepository; private readonly ICoreScopeProvider _coreScopeProvider; + private readonly ILanguageService _languageService; private readonly IDictionary> _publishedCultures = new Dictionary>(); + + private string? DefaultCulture { get; set; } + + [Obsolete("Use non-obsolete constructor. This will be removed in Umbraco 17.")] public PublishStatusService( ILogger logger, IPublishStatusRepository publishStatusRepository, ICoreScopeProvider coreScopeProvider) + : this(logger, publishStatusRepository, coreScopeProvider, StaticServiceProvider.Instance.GetRequiredService()) + { + + } + + public PublishStatusService( + ILogger logger, + IPublishStatusRepository publishStatusRepository, + ICoreScopeProvider coreScopeProvider, + ILanguageService languageService) { _logger = logger; _publishStatusRepository = publishStatusRepository; _coreScopeProvider = coreScopeProvider; + _languageService = languageService; } public async Task InitializeAsync(CancellationToken cancellationToken) @@ -39,11 +57,16 @@ public class PublishStatusService : IPublishStatusManagementService, IPublishSta } } - + DefaultCulture = await _languageService.GetDefaultIsoCodeAsync(); } public bool IsDocumentPublished(Guid documentKey, string culture) { + if (string.IsNullOrEmpty(culture) && DefaultCulture is not null) + { + culture = DefaultCulture; + } + if (_publishedCultures.TryGetValue(documentKey, out ISet? publishedCultures)) { return publishedCultures.Contains(culture, StringComparer.InvariantCultureIgnoreCase); diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs index 97bf4c8839..c4c839f695 100644 --- a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs @@ -67,6 +67,9 @@ public static class FriendlyPublishedContentExtensions private static IMemberTypeService MemberTypeService { get; } = StaticServiceProvider.Instance.GetRequiredService(); + private static IPublishStatusQueryService PublishStatusQueryService { get; } = + StaticServiceProvider.Instance.GetRequiredService(); + private static INavigationQueryService GetNavigationQueryService(IPublishedContent content) { switch (content.ContentType.ItemType) @@ -240,7 +243,7 @@ public static class FriendlyPublishedContentExtensions /// set to 1. /// public static IPublishedContent Root(this IPublishedContent content) - => content.Root(GetPublishedCache(content), GetNavigationQueryService(content)); + => content.Root(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService); /// /// Gets the root content (ancestor or self at level 1) for the specified if it's of the @@ -259,7 +262,7 @@ public static class FriendlyPublishedContentExtensions /// public static T? Root(this IPublishedContent content) where T : class, IPublishedContent - => content.Root(GetPublishedCache(content), GetNavigationQueryService(content)); + => content.Root(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService); /// /// Gets the parent of the content item. @@ -286,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. @@ -294,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. @@ -305,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. @@ -324,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. @@ -335,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 @@ -352,7 +355,7 @@ public static class FriendlyPublishedContentExtensions /// public static IEnumerable DescendantsOrSelfOfType( this IEnumerable parentNodes, string docTypeAlias, string? culture = null) - => parentNodes.DescendantsOrSelfOfType(VariationContextAccessor, GetPublishedCache(parentNodes.First()), GetNavigationQueryService(parentNodes.First()), docTypeAlias, culture); + => parentNodes.DescendantsOrSelfOfType(VariationContextAccessor, GetPublishedCache(parentNodes.First()), GetNavigationQueryService(parentNodes.First()), PublishStatusQueryService, docTypeAlias, culture); /// /// Returns all DescendantsOrSelf of all content referenced @@ -370,77 +373,77 @@ public static class FriendlyPublishedContentExtensions this IEnumerable parentNodes, string? culture = null) where T : class, IPublishedContent - => parentNodes.DescendantsOrSelf(VariationContextAccessor, GetPublishedCache(parentNodes.First()), GetNavigationQueryService(parentNodes.First()), culture); + => parentNodes.DescendantsOrSelf(VariationContextAccessor, GetPublishedCache(parentNodes.First()), GetNavigationQueryService(parentNodes.First()), PublishStatusQueryService, culture); public static IEnumerable Descendants(this IPublishedContent content, string? culture = null) - => content.Descendants(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture); + => content.Descendants(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, culture); public static IEnumerable Descendants(this IPublishedContent content, int level, string? culture = null) - => content.Descendants(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture); + => content.Descendants(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, level, culture); public static IEnumerable DescendantsOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) - => content.DescendantsOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture); + => content.DescendantsOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, contentTypeAlias, culture); public static IEnumerable Descendants(this IPublishedContent content, string? culture = null) where T : class, IPublishedContent - => content.Descendants(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture); + => content.Descendants(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, culture); public static IEnumerable Descendants(this IPublishedContent content, int level, string? culture = null) where T : class, IPublishedContent - => content.Descendants(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture); + => content.Descendants(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, level, culture); public static IEnumerable DescendantsOrSelf( this IPublishedContent content, string? culture = null) - => content.DescendantsOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture); + => content.DescendantsOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, culture); public static IEnumerable DescendantsOrSelf(this IPublishedContent content, int level, string? culture = null) - => content.DescendantsOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture); + => content.DescendantsOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, level, culture); public static IEnumerable DescendantsOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) - => content.DescendantsOrSelfOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture); + => content.DescendantsOrSelfOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, contentTypeAlias, culture); public static IEnumerable DescendantsOrSelf(this IPublishedContent content, string? culture = null) where T : class, IPublishedContent - => content.DescendantsOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture); + => content.DescendantsOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, culture); public static IEnumerable DescendantsOrSelf(this IPublishedContent content, int level, string? culture = null) where T : class, IPublishedContent - => content.DescendantsOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture); + => content.DescendantsOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, level, culture); public static IPublishedContent? Descendant(this IPublishedContent content, string? culture = null) - => content.Descendant(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture); + => content.Descendant(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, culture); public static IPublishedContent? Descendant(this IPublishedContent content, int level, string? culture = null) - => content.Descendant(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture); + => content.Descendant(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, level, culture); public static IPublishedContent? DescendantOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) - => content.DescendantOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture); + => content.DescendantOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, contentTypeAlias, culture); public static T? Descendant(this IPublishedContent content, string? culture = null) where T : class, IPublishedContent - => content.Descendant(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture); + => content.Descendant(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, culture); public static T? Descendant(this IPublishedContent content, int level, string? culture = null) where T : class, IPublishedContent - => content.Descendant(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture); + => content.Descendant(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, level, culture); public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string? culture = null) - => content.DescendantOrSelf(VariationContextAccessor, culture); + => content.DescendantOrSelf(VariationContextAccessor, PublishStatusQueryService, culture); public static IPublishedContent? DescendantOrSelf(this IPublishedContent content, int level, string? culture = null) - => content.DescendantOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture); + => content.DescendantOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, level, culture); public static IPublishedContent? DescendantOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) - => content.DescendantOrSelfOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture); + => content.DescendantOrSelfOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, contentTypeAlias, culture); public static T? DescendantOrSelf(this IPublishedContent content, string? culture = null) where T : class, IPublishedContent - => content.DescendantOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture); + => content.DescendantOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, culture); public static T? DescendantOrSelf(this IPublishedContent content, int level, string? culture = null) where T : class, IPublishedContent - => content.DescendantOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), level, culture); + => content.DescendantOrSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, level, culture); /// /// Gets the children of the content item. @@ -468,7 +471,7 @@ public static class FriendlyPublishedContentExtensions /// /// public static IEnumerable Children(this IPublishedContent content, string? culture = null) - => content.Children(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture); + => content.Children(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, culture); /// /// Gets the children of the content, filtered by a predicate. @@ -487,7 +490,7 @@ public static class FriendlyPublishedContentExtensions this IPublishedContent content, Func predicate, string? culture = null) - => content.Children(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), predicate, culture); + => content.Children(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, predicate, culture); /// /// Gets the children of the content, of any of the specified types. @@ -500,7 +503,7 @@ public static class FriendlyPublishedContentExtensions /// The content type alias. /// The children of the content, of any of the specified types. public static IEnumerable? ChildrenOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) - => content.ChildrenOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture); + => content.ChildrenOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, contentTypeAlias, culture); /// /// Gets the children of the content, of a given content type. @@ -517,30 +520,30 @@ public static class FriendlyPublishedContentExtensions /// public static IEnumerable? Children(this IPublishedContent content, string? culture = null) where T : class, IPublishedContent - => content.Children(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture); + => content.Children(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, culture); public static IPublishedContent? FirstChild(this IPublishedContent content, string? culture = null) - => content.FirstChild(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture); + => content.FirstChild(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, culture); /// /// Gets the first child of the content, of a given content type. /// public static IPublishedContent? FirstChildOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) - => content.FirstChildOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture); + => content.FirstChildOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, contentTypeAlias, culture); public static IPublishedContent? FirstChild(this IPublishedContent content, Func predicate, string? culture = null) - => content.FirstChild(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), predicate, culture); + => content.FirstChild(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, predicate, culture); public static IPublishedContent? FirstChild(this IPublishedContent content, Guid uniqueId, string? culture = null) - => content.FirstChild(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), uniqueId, culture); + => content.FirstChild(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, uniqueId, culture); public static T? FirstChild(this IPublishedContent content, string? culture = null) where T : class, IPublishedContent - => content.FirstChild(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture); + => content.FirstChild(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, culture); public static T? FirstChild(this IPublishedContent content, Func predicate, string? culture = null) where T : class, IPublishedContent - => content.FirstChild(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), predicate, culture); + => content.FirstChild(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, predicate, culture); /// /// Gets the siblings of the content. @@ -555,7 +558,7 @@ public static class FriendlyPublishedContentExtensions /// Note that in V7 this method also return the content node self. /// public static IEnumerable? Siblings(this IPublishedContent content, string? culture = null) - => content.Siblings(GetPublishedCache(content), GetNavigationQueryService(content), VariationContextAccessor, culture); + => content.Siblings(GetPublishedCache(content), GetNavigationQueryService(content), VariationContextAccessor, PublishStatusQueryService, culture); /// /// Gets the siblings of the content, of a given content type. @@ -571,7 +574,7 @@ public static class FriendlyPublishedContentExtensions /// Note that in V7 this method also return the content node self. /// public static IEnumerable? SiblingsOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) - => content.SiblingsOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture); + => content.SiblingsOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, contentTypeAlias, culture); /// /// Gets the siblings of the content, of a given content type. @@ -588,7 +591,7 @@ public static class FriendlyPublishedContentExtensions /// public static IEnumerable? Siblings(this IPublishedContent content, string? culture = null) where T : class, IPublishedContent - => content.Siblings(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture); + => content.Siblings(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, culture); /// /// Gets the siblings of the content including the node itself to indicate the position. @@ -602,7 +605,7 @@ public static class FriendlyPublishedContentExtensions public static IEnumerable? SiblingsAndSelf( this IPublishedContent content, string? culture = null) - => content.SiblingsAndSelf(GetPublishedCache(content), GetNavigationQueryService(content), VariationContextAccessor, culture); + => content.SiblingsAndSelf(GetPublishedCache(content), GetNavigationQueryService(content), VariationContextAccessor, PublishStatusQueryService, culture); /// /// Gets the siblings of the content including the node itself to indicate the position, of a given content type. @@ -618,7 +621,7 @@ public static class FriendlyPublishedContentExtensions this IPublishedContent content, string contentTypeAlias, string? culture = null) - => content.SiblingsAndSelfOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), contentTypeAlias, culture); + => content.SiblingsAndSelfOfType(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, contentTypeAlias, culture); /// /// Gets the siblings of the content including the node itself to indicate the position, of a given content type. @@ -632,7 +635,7 @@ public static class FriendlyPublishedContentExtensions /// The siblings of the content including the node itself, of the given content type. public static IEnumerable? SiblingsAndSelf(this IPublishedContent content, string? culture = null) where T : class, IPublishedContent - => content.SiblingsAndSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), culture); + => content.SiblingsAndSelf(VariationContextAccessor, GetPublishedCache(content), GetNavigationQueryService(content), PublishStatusQueryService, culture); /// /// Gets the url of the content item. diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Core/Services/PublishStatusServiceTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Core/Services/PublishStatusServiceTest.cs index 861b8bac6c..3580d0314b 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Core/Services/PublishStatusServiceTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Core/Services/PublishStatusServiceTest.cs @@ -98,7 +98,9 @@ public class PublishStatusServiceTest : UmbracoIntegrationTestWithContent var sut = new PublishStatusService( GetRequiredService>(), GetRequiredService(), - GetRequiredService()); + GetRequiredService(), + GetRequiredService() + ); Assert.IsFalse(sut.IsDocumentPublished(Textpage.Key, DefaultCulture)); @@ -118,7 +120,8 @@ public class PublishStatusServiceTest : UmbracoIntegrationTestWithContent var sut = new PublishStatusService( GetRequiredService>(), GetRequiredService(), - GetRequiredService()); + GetRequiredService(), + GetRequiredService()); Assert.IsFalse(sut.IsDocumentPublished(Textpage.Key, DefaultCulture)); diff --git a/tests/Umbraco.Tests.UnitTests/AutoFixture/Customizations/UmbracoCustomizations.cs b/tests/Umbraco.Tests.UnitTests/AutoFixture/Customizations/UmbracoCustomizations.cs index ea794faeb7..eb29633166 100644 --- a/tests/Umbraco.Tests.UnitTests/AutoFixture/Customizations/UmbracoCustomizations.cs +++ b/tests/Umbraco.Tests.UnitTests/AutoFixture/Customizations/UmbracoCustomizations.cs @@ -11,6 +11,7 @@ using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Install; @@ -34,7 +35,8 @@ internal class UmbracoCustomizations : ICustomization .Customize(new ConstructorCustomization(typeof(DatabaseSchemaCreatorFactory), new GreedyConstructorQuery())) .Customize(new ConstructorCustomization(typeof(InstallHelper), new GreedyConstructorQuery())) .Customize(new ConstructorCustomization(typeof(DatabaseBuilder), new GreedyConstructorQuery())) - .Customize(new ConstructorCustomization(typeof(ContentVersionService), new GreedyConstructorQuery())); + .Customize(new ConstructorCustomization(typeof(ContentVersionService), new GreedyConstructorQuery())) + .Customize(new ConstructorCustomization(typeof(ContentFinderByUrlAlias), new GreedyConstructorQuery())); // When requesting an IUserStore ensure we actually uses a IUserLockoutStore fixture.Customize>(cc => diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/ContentRouteBuilderTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/ContentRouteBuilderTests.cs index 06950c4ba9..c0001bf067 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/ContentRouteBuilderTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/ContentRouteBuilderTests.cs @@ -429,9 +429,10 @@ public class ContentRouteBuilderTests : DeliveryApiTests { var variantContextAccessor = Mock.Of(); + string Url(IPublishedContent content, string? culture) { - var ancestorsOrSelf = content.AncestorsOrSelf(contentCache, navigationQueryService).ToArray(); + var ancestorsOrSelf = content.AncestorsOrSelf(variantContextAccessor, contentCache, navigationQueryService, PublishStatusQueryService).ToArray(); return ancestorsOrSelf.All(c => c.IsPublished(culture)) ? string.Join("/", ancestorsOrSelf.Reverse().Skip(hideTopLevelNodeFromPath ? 1 : 0).Select(c => c.UrlSegment(variantContextAccessor, culture))).EnsureStartsWith("/") : "#"; diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/DeliveryApiTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/DeliveryApiTests.cs index 5b349671d6..2764dd21d3 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/DeliveryApiTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/DeliveryApiTests.cs @@ -20,6 +20,8 @@ public class DeliveryApiTests protected IPublishedPropertyType DefaultPropertyType { get; private set; } + protected IPublishStatusQueryService PublishStatusQueryService { get; private set; } + [SetUp] public virtual void Setup() { @@ -57,6 +59,13 @@ public class DeliveryApiTests defaultPropertyValueConverter.Setup(p => p.GetPropertyCacheLevel(It.IsAny())).Returns(PropertyCacheLevel.None); DefaultPropertyType = SetupPublishedPropertyType(defaultPropertyValueConverter.Object, "default", "Default.Editor"); + + var publishStatusQueryService = new Mock(); + publishStatusQueryService + .Setup(x => x.IsDocumentPublished(It.IsAny(), It.IsAny())) + .Returns(true); + + PublishStatusQueryService = publishStatusQueryService.Object; } protected IPublishedPropertyType SetupPublishedPropertyType(IPropertyValueConverter valueConverter, string propertyTypeAlias, string editorAlias, object? dataTypeConfiguration = null) @@ -117,7 +126,8 @@ public class DeliveryApiTests IRequestPreviewService? requestPreviewService = null, IOptionsMonitor? requestHandlerSettingsMonitor = null, IPublishedContentCache? contentCache = null, - IDocumentNavigationQueryService? navigationQueryService = null) + IDocumentNavigationQueryService? navigationQueryService = null, + IPublishStatusQueryService? publishStatusQueryService = null) { if (requestHandlerSettingsMonitor == null) { @@ -133,6 +143,7 @@ public class DeliveryApiTests requestPreviewService ?? Mock.Of(), requestHandlerSettingsMonitor, contentCache ?? Mock.Of(), - navigationQueryService ?? Mock.Of()); + navigationQueryService ?? Mock.Of(), + publishStatusQueryService ?? PublishStatusQueryService); } } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByUrlAliasTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByUrlAliasTests.cs index 1977c918a5..d7f86ff11e 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByUrlAliasTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/ContentFinderByUrlAliasTests.cs @@ -7,6 +7,7 @@ using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Services.Navigation; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Tests.UnitTests.AutoFixture; @@ -30,6 +31,7 @@ public class ContentFinderByUrlAliasTests [Frozen] IUmbracoContextAccessor umbracoContextAccessor, [Frozen] IUmbracoContext umbracoContext, [Frozen] IVariationContextAccessor variationContextAccessor, + [Frozen] IPublishStatusQueryService publishStatusQueryService, IFileService fileService, ContentFinderByUrlAlias sut, IPublishedContent[] rootContents, @@ -48,6 +50,7 @@ public class ContentFinderByUrlAliasTests Mock.Get(urlProperty).Setup(x => x.GetValue(null, null)).Returns(relativeUrl); Mock.Get(variationContextAccessor).Setup(x => x.VariationContext).Returns(variationContext); + Mock.Get(publishStatusQueryService).Setup(x => x.IsDocumentPublished(It.IsAny(), It.IsAny())).Returns(true); var publishedRequestBuilder = new PublishedRequestBuilder(new Uri(absoluteUrl, UriKind.Absolute), fileService); // Act diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlImageSourceParserTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlImageSourceParserTests.cs index b98d1b1731..1a4a73f800 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlImageSourceParserTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlImageSourceParserTests.cs @@ -99,7 +99,8 @@ public class HtmlImageSourceParserTests new MediaUrlProviderCollection(() => new[] { mediaUrlProvider.Object }), Mock.Of(), Mock.Of(), - Mock.Of()); + Mock.Of(), + Mock.Of()); using (var reference = umbracoContextFactory.EnsureUmbracoContext()) { diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlLocalLinkParserTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlLocalLinkParserTests.cs index 5a35a096ee..ad2fb0b231 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlLocalLinkParserTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlLocalLinkParserTests.cs @@ -235,6 +235,11 @@ public class HtmlLocalLinkParserTests mediaCache.Setup(x => x.GetById(It.IsAny())).Returns(media.Object); mediaCache.Setup(x => x.GetById(It.IsAny())).Returns(media.Object); + var publishStatusQueryService = new Mock(); + publishStatusQueryService + .Setup(x => x.IsDocumentPublished(It.IsAny(), It.IsAny())) + .Returns(true); + var publishedUrlProvider = new UrlProvider( umbracoContextAccessor, Options.Create(webRoutingSettings), @@ -242,7 +247,8 @@ public class HtmlLocalLinkParserTests new MediaUrlProviderCollection(() => new[] { mediaUrlProvider.Object }), Mock.Of(), contentCache.Object, - navigationQueryService.Object); + navigationQueryService.Object, + publishStatusQueryService.Object); var linkParser = new HtmlLocalLinkParser(publishedUrlProvider);