diff --git a/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs b/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs index f7ad53d7d6..b97c1c8161 100644 --- a/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs +++ b/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs @@ -25,7 +25,7 @@ public static class PublishedContentExtensions /// The specific culture to get the name for. If null is used the current culture is used (Default is /// null). /// - public static string? Name(this IPublishedContent content, IVariationContextAccessor? variationContextAccessor, string? culture = null) + public static string Name(this IPublishedContent content, IVariationContextAccessor? variationContextAccessor, string? culture = null) { if (content == null) { @@ -37,7 +37,7 @@ public static class PublishedContentExtensions { return content.Cultures.TryGetValue(string.Empty, out PublishedCultureInfo? invariantInfos) ? invariantInfos.Name - : null; + : string.Empty; } // handle context culture for variant @@ -49,7 +49,7 @@ public static class PublishedContentExtensions // get return culture != string.Empty && content.Cultures.TryGetValue(culture, out PublishedCultureInfo? infos) ? infos.Name - : null; + : string.Empty; } #endregion @@ -683,8 +683,8 @@ public static class PublishedContentExtensions /// 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, int maxLevel) => - content.EnumerateAncestors(true).FirstOrDefault(x => x.Level <= maxLevel); + public static IPublishedContent AncestorOrSelf(this IPublishedContent content, int maxLevel) => + content.EnumerateAncestors(true).FirstOrDefault(x => x.Level <= maxLevel) ?? content; /// /// Gets the content or its nearest ancestor, of a specified content type. @@ -693,8 +693,8 @@ 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. - public static IPublishedContent? AncestorOrSelf(this IPublishedContent content, string contentTypeAlias) => content - .EnumerateAncestors(true).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias)); + public static IPublishedContent AncestorOrSelf(this IPublishedContent content, string contentTypeAlias) => content + .EnumerateAncestors(true).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias)) ?? content; /// /// Gets the content or its nearest ancestor, of a specified content type. @@ -1012,7 +1012,7 @@ public static class PublishedContentExtensions /// However, if an empty string is specified only invariant children are returned. /// /// - public static IEnumerable? Children(this IPublishedContent content, IVariationContextAccessor? variationContextAccessor, string? culture = null) + public static IEnumerable Children(this IPublishedContent content, IVariationContextAccessor? variationContextAccessor, string? culture = null) { // handle context culture for variant if (culture == null) @@ -1021,9 +1021,9 @@ public static class PublishedContentExtensions } IEnumerable? children = content.ChildrenForAllCultures; - return culture == "*" - ? children - : children?.Where(x => x.IsInvariantOrHasCulture(culture)); + return (culture == "*" + ? children : children?.Where(x => x.IsInvariantOrHasCulture(culture))) + ?? Enumerable.Empty(); } /// @@ -1040,12 +1040,12 @@ public static class PublishedContentExtensions /// /// Children are sorted by their sortOrder. /// - public static IEnumerable? Children( + public static IEnumerable Children( this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Func predicate, string? culture = null) => - content.Children(variationContextAccessor, culture)?.Where(predicate); + content.Children(variationContextAccessor, culture).Where(predicate); /// /// Gets the children of the content, of any of the specified types. @@ -1058,7 +1058,7 @@ public static class PublishedContentExtensions /// /// The content type alias. /// The children of the content, of any of the specified types. - public static IEnumerable? ChildrenOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? contentTypeAlias, string? culture = null) => + public static IEnumerable ChildrenOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? contentTypeAlias, string? culture = null) => content.Children(variationContextAccessor, x => x.ContentType.Alias.InvariantEquals(contentTypeAlias), culture); /// @@ -1075,9 +1075,9 @@ public static class PublishedContentExtensions /// /// Children are sorted by their sortOrder. /// - public static IEnumerable? Children(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null) + public static IEnumerable Children(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null) where T : class, IPublishedContent => - content.Children(variationContextAccessor, culture)?.OfType(); + content.Children(variationContextAccessor, culture).OfType(); public static IPublishedContent? FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string? culture = null) => content.Children(variationContextAccessor, culture)?.FirstOrDefault(); @@ -1119,12 +1119,13 @@ public static class PublishedContentExtensions /// /// Note that in V7 this method also return the content node self. /// - public static IEnumerable? Siblings( + public static IEnumerable Siblings( this IPublishedContent content, IPublishedSnapshot? publishedSnapshot, IVariationContextAccessor variationContextAccessor, string? culture = null) => - SiblingsAndSelf(content, publishedSnapshot, variationContextAccessor, culture)?.Where(x => x.Id != content.Id); + SiblingsAndSelf(content, publishedSnapshot, variationContextAccessor, culture) + ?.Where(x => x.Id != content.Id) ?? Enumerable.Empty(); /// /// Gets the siblings of the content, of a given content type. @@ -1141,14 +1142,14 @@ public static class PublishedContentExtensions /// /// Note that in V7 this method also return the content node self. /// - public static IEnumerable? SiblingsOfType( + public static IEnumerable SiblingsOfType( this IPublishedContent content, IPublishedSnapshot? publishedSnapshot, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null) => SiblingsAndSelfOfType(content, publishedSnapshot, variationContextAccessor, contentTypeAlias, culture) - ?.Where(x => x.Id != content.Id); + ?.Where(x => x.Id != content.Id) ?? Enumerable.Empty(); /// /// Gets the siblings of the content, of a given content type. @@ -1165,10 +1166,10 @@ public static class PublishedContentExtensions /// /// Note that in V7 this method also return the content node self. /// - public static IEnumerable? Siblings(this IPublishedContent content, IPublishedSnapshot? publishedSnapshot, IVariationContextAccessor variationContextAccessor, string? culture = null) + public static IEnumerable Siblings(this IPublishedContent content, IPublishedSnapshot? publishedSnapshot, IVariationContextAccessor variationContextAccessor, string? culture = null) where T : class, IPublishedContent => SiblingsAndSelf(content, publishedSnapshot, variationContextAccessor, culture) - ?.Where(x => x.Id != content.Id); + ?.Where(x => x.Id != content.Id) ?? Enumerable.Empty(); /// /// Gets the siblings of the content including the node itself to indicate the position. @@ -1203,16 +1204,17 @@ public static class PublishedContentExtensions /// /// The content type alias. /// The siblings of the content including the node itself, of the given content type. - public static IEnumerable? SiblingsAndSelfOfType( + public static IEnumerable SiblingsAndSelfOfType( this IPublishedContent content, IPublishedSnapshot? publishedSnapshot, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null) => - content.Parent != null + (content.Parent != null ? content.Parent.ChildrenOfType(variationContextAccessor, contentTypeAlias, culture) : publishedSnapshot?.Content?.GetAtRoot(culture).OfTypes(contentTypeAlias) - .WhereIsInvariantOrHasCulture(variationContextAccessor, culture); + .WhereIsInvariantOrHasCulture(variationContextAccessor, culture)) + ?? Enumerable.Empty(); /// /// Gets the siblings of the content including the node itself to indicate the position, of a given content type. @@ -1226,16 +1228,17 @@ public static class PublishedContentExtensions /// null) /// /// The siblings of the content including the node itself, of the given content type. - public static IEnumerable? SiblingsAndSelf( + public static IEnumerable SiblingsAndSelf( this IPublishedContent content, IPublishedSnapshot? publishedSnapshot, IVariationContextAccessor variationContextAccessor, string? culture = null) where T : class, IPublishedContent => - content.Parent != null + (content.Parent != null ? content.Parent.Children(variationContextAccessor, culture) : publishedSnapshot?.Content?.GetAtRoot(culture).OfType() - .WhereIsInvariantOrHasCulture(variationContextAccessor, culture); + .WhereIsInvariantOrHasCulture(variationContextAccessor, culture)) + ?? Enumerable.Empty(); #endregion @@ -1253,7 +1256,7 @@ public static class PublishedContentExtensions /// with maxLevel /// set to 1. /// - public static IPublishedContent? Root(this IPublishedContent content) => content.AncestorOrSelf(1); + public static IPublishedContent Root(this IPublishedContent content) => content.AncestorOrSelf(1); /// /// Gets the root content (ancestor or self at level 1) for the specified if it's of the @@ -1278,16 +1281,16 @@ public static class PublishedContentExtensions #region Writer and creator - public static string? GetCreatorName(this IPublishedContent content, IUserService userService) + public static string GetCreatorName(this IPublishedContent content, IUserService userService) { IProfile? user = userService.GetProfileById(content.CreatorId); - return user?.Name; + return user?.Name ?? string.Empty; } - public static string? GetWriterName(this IPublishedContent content, IUserService userService) + public static string GetWriterName(this IPublishedContent content, IUserService userService) { IProfile? user = userService.GetProfileById(content.WriterId); - return user?.Name; + return user?.Name ?? string.Empty; } #endregion diff --git a/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs b/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs index 01b57f38f8..6ecac18711 100644 --- a/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs +++ b/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs @@ -23,7 +23,7 @@ public interface IPublishedContent : IPublishedElement /// /// Gets the name of the content item for the current culture. /// - string? Name { get; } + string Name { get; } /// /// Gets the URL segment of the content item for the current culture. @@ -141,10 +141,10 @@ public interface IPublishedContent : IPublishedElement /// /// Gets the children of the content item that are available for the current culture. /// - IEnumerable? Children { get; } + IEnumerable Children { get; } /// /// Gets all the children of the content item, regardless of whether they are available for the current culture. /// - IEnumerable? ChildrenForAllCultures { get; } + IEnumerable ChildrenForAllCultures { get; } } diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentBase.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentBase.cs index 077b420735..c9394e1e27 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentBase.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentBase.cs @@ -24,7 +24,7 @@ namespace Umbraco.Cms.Core.Models.PublishedContent public abstract int Id { get; } /// - public virtual string? Name => this.Name(_variationContextAccessor); + public virtual string Name => this.Name(_variationContextAccessor); /// public virtual string? UrlSegment => this.UrlSegment(_variationContextAccessor); @@ -69,7 +69,7 @@ namespace Umbraco.Cms.Core.Models.PublishedContent public abstract IPublishedContent? Parent { get; } /// - public virtual IEnumerable? Children => this.Children(_variationContextAccessor); + public virtual IEnumerable Children => this.Children(_variationContextAccessor); /// public abstract IEnumerable ChildrenForAllCultures { get; } diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs index b5e9a94e13..ddeff558dd 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs @@ -54,7 +54,7 @@ public abstract class PublishedContentWrapped : IPublishedContent public IPublishedContent Unwrap() => _content; /// - public virtual string? Name => _content.Name; + public virtual string Name => _content.Name; /// public virtual string? UrlSegment => _content.UrlSegment; @@ -99,10 +99,10 @@ public abstract class PublishedContentWrapped : IPublishedContent public virtual bool IsPublished(string? culture = null) => _content.IsPublished(culture); /// - public virtual IEnumerable? Children => _content.Children; + public virtual IEnumerable Children => _content.Children; /// - public virtual IEnumerable? ChildrenForAllCultures => _content.ChildrenForAllCultures; + public virtual IEnumerable ChildrenForAllCultures => _content.ChildrenForAllCultures; /// public virtual IEnumerable Properties => _content.Properties; diff --git a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContent.cs b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContent.cs index 0659e835a3..f4e381d3a1 100644 --- a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContent.cs +++ b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedContent.cs @@ -20,13 +20,14 @@ public sealed class InternalPublishedContent : IPublishedContent Path = string.Empty; ContentType = contentType; Properties = Enumerable.Empty(); + Name = string.Empty; } public Guid Version { get; set; } public int ParentId { get; set; } - public IEnumerable? ChildIds { get; set; } + public IEnumerable ChildIds { get; set; } = Enumerable.Empty(); public int Id { get; set; } @@ -45,7 +46,7 @@ public sealed class InternalPublishedContent : IPublishedContent public int SortOrder { get; set; } - public string? Name { get; set; } + public string Name { get; set; } public IReadOnlyDictionary Cultures => _cultures ??= GetCultures(); @@ -71,9 +72,9 @@ public sealed class InternalPublishedContent : IPublishedContent public bool IsPublished(string? culture = null) => true; - public IEnumerable? Children { get; set; } + public IEnumerable Children { get; set; } = Enumerable.Empty(); - public IEnumerable? ChildrenForAllCultures => Children; + public IEnumerable ChildrenForAllCultures => Children; public IPublishedContentType ContentType { get; set; } diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs index 4e22615ddf..4b7d02bf7a 100644 --- a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs @@ -330,7 +330,7 @@ public static class FriendlyPublishedContentExtensions /// However, if an empty string is specified only invariant children are returned. /// /// - public static IEnumerable? Children(this IPublishedContent content, string? culture = null) + public static IEnumerable Children(this IPublishedContent content, string? culture = null) => content.Children(VariationContextAccessor, culture); /// diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedSnapshotServiceCollectionTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedSnapshotServiceCollectionTests.cs index a0e48069a3..ac22b112cd 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedSnapshotServiceCollectionTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedSnapshotServiceCollectionTests.cs @@ -719,25 +719,25 @@ public class PublishedSnapshotServiceCollectionTests : PublishedSnapshotServiceT AssertDocuments(documents); documents = snapshot.Content.GetById(1).Children(VariationContextAccessor, "*").ToArray(); - AssertDocuments(documents, "N4-fr-FR", null, "N6-fr-FR"); + AssertDocuments(documents, "N4-fr-FR", string.Empty, "N6-fr-FR"); AssertDocuments("en-US", documents, "N4-en-US", "N5-en-US", "N6-en-US"); documents = snapshot.Content.GetById(1).Children(VariationContextAccessor, "en-US").ToArray(); - AssertDocuments(documents, "N4-fr-FR", null, "N6-fr-FR"); + AssertDocuments(documents, "N4-fr-FR", string.Empty, "N6-fr-FR"); AssertDocuments("en-US", documents, "N4-en-US", "N5-en-US", "N6-en-US"); documents = snapshot.Content.GetById(1).ChildrenForAllCultures.ToArray(); - AssertDocuments(documents, "N4-fr-FR", null, "N6-fr-FR"); + AssertDocuments(documents, "N4-fr-FR", string.Empty, "N6-fr-FR"); AssertDocuments("en-US", documents, "N4-en-US", "N5-en-US", "N6-en-US"); documents = snapshot.Content.GetAtRoot("*").ToArray(); - AssertDocuments(documents, "N1-fr-FR", null, "N3-fr-FR"); + AssertDocuments(documents, "N1-fr-FR", string.Empty, "N3-fr-FR"); documents = snapshot.Content.GetById(1).DescendantsOrSelf(VariationContextAccessor).ToArray(); AssertDocuments(documents, "N1-fr-FR", "N4-fr-FR", "N12-fr-FR", "N6-fr-FR"); documents = snapshot.Content.GetById(1).DescendantsOrSelf(VariationContextAccessor, "*").ToArray(); - AssertDocuments(documents, "N1-fr-FR", "N4-fr-FR", null /*11*/, "N12-fr-FR", null /*5*/, "N6-fr-FR"); + AssertDocuments(documents, "N1-fr-FR", "N4-fr-FR", string.Empty /*11*/, "N12-fr-FR", string.Empty /*5*/, "N6-fr-FR"); } [Test] diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedSnapshotServiceContentTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedSnapshotServiceContentTests.cs index 4a017911bc..5c1312ae8f 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedSnapshotServiceContentTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/PublishedCache/PublishedSnapshotServiceContentTests.cs @@ -120,7 +120,7 @@ public class PublishedSnapshotServiceContentTests : PublishedSnapshotServiceTest Assert.AreEqual("val-fr1", publishedContent.Value(Mock.Of(), "prop", "fr-FR")); Assert.AreEqual("val-uk1", publishedContent.Value(Mock.Of(), "prop", "en-UK")); - Assert.IsNull(publishedContent.Name(VariationContextAccessor)); // no invariant name for varying content + Assert.AreEqual(publishedContent.Name(VariationContextAccessor), string.Empty); // no invariant name for varying content Assert.AreEqual("name-fr1", publishedContent.Name(VariationContextAccessor, "fr-FR")); Assert.AreEqual("name-uk1", publishedContent.Name(VariationContextAccessor, "en-UK")); @@ -129,7 +129,7 @@ public class PublishedSnapshotServiceContentTests : PublishedSnapshotServiceTest Assert.AreEqual("val-fr2", draftContent.Value(Mock.Of(), "prop", "fr-FR")); Assert.AreEqual("val-uk2", draftContent.Value(Mock.Of(), "prop", "en-UK")); - Assert.IsNull(draftContent.Name(VariationContextAccessor)); // no invariant name for varying content + Assert.AreEqual(draftContent.Name(VariationContextAccessor), string.Empty); // no invariant name for varying content Assert.AreEqual("name-fr2", draftContent.Name(VariationContextAccessor, "fr-FR")); Assert.AreEqual("name-uk2", draftContent.Name(VariationContextAccessor, "en-UK"));