From 6ee078108dab69ba0ea1f6f2af74ac5c13baf3ec Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sun, 3 Aug 2014 23:09:56 +0200 Subject: [PATCH] Added NodeCount property to ITag/Tag and an optional flag to tag retrieval methods on TagsService, in order to retrieve the count for the tag as well as it's text --- src/Umbraco.Core/Models/ITag.cs | 2 + src/Umbraco.Core/Models/Rdbms/TagDto.cs | 3 + src/Umbraco.Core/Models/Tag.cs | 10 +- .../Persistence/Factories/TagFactory.cs | 5 +- .../Interfaces/ITagsRepository.cs | 5 +- .../Repositories/TagsRepository.cs | 98 +++++++++++++------ src/Umbraco.Core/Services/ITagService.cs | 26 ++--- src/Umbraco.Core/Services/TagService.cs | 33 ++++--- 8 files changed, 120 insertions(+), 62 deletions(-) diff --git a/src/Umbraco.Core/Models/ITag.cs b/src/Umbraco.Core/Models/ITag.cs index 8c1c1aa5e0..fe5eaf4a9a 100644 --- a/src/Umbraco.Core/Models/ITag.cs +++ b/src/Umbraco.Core/Models/ITag.cs @@ -11,6 +11,8 @@ namespace Umbraco.Core.Models [DataMember] string Group { get; set; } + int NodeCount { get; } + //TODO: enable this at some stage //int ParentId { get; set; } } diff --git a/src/Umbraco.Core/Models/Rdbms/TagDto.cs b/src/Umbraco.Core/Models/Rdbms/TagDto.cs index 19ff41db90..d2bdc0b036 100644 --- a/src/Umbraco.Core/Models/Rdbms/TagDto.cs +++ b/src/Umbraco.Core/Models/Rdbms/TagDto.cs @@ -27,5 +27,8 @@ namespace Umbraco.Core.Models.Rdbms [NullSetting(NullSetting = NullSettings.Null)] [Length(100)] public string Group { get; set; }//NOTE Is set to [varchar] (100) in Sql Server script + + [Column("NodeCount")] + public int NodeCount { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Tag.cs b/src/Umbraco.Core/Models/Tag.cs index 1bd5bff76d..bfe4c10f42 100644 --- a/src/Umbraco.Core/Models/Tag.cs +++ b/src/Umbraco.Core/Models/Tag.cs @@ -16,9 +16,15 @@ namespace Umbraco.Core.Models public Tag(int id, string text, string @group) { + Id = id; Text = text; Group = @group; - Id = id; + } + + public Tag(int id, string text, string @group, int nodeCount) + : this(id, text, @group) + { + NodeCount = nodeCount; } private static readonly PropertyInfo TextSelector = ExpressionHelper.GetPropertyInfo(x => x.Text); @@ -52,6 +58,8 @@ namespace Umbraco.Core.Models } } + public int NodeCount { get; internal set; } + //TODO: enable this at some stage //public int ParentId { get; set; } } diff --git a/src/Umbraco.Core/Persistence/Factories/TagFactory.cs b/src/Umbraco.Core/Persistence/Factories/TagFactory.cs index c154a60198..7cebe5f65e 100644 --- a/src/Umbraco.Core/Persistence/Factories/TagFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/TagFactory.cs @@ -7,7 +7,7 @@ namespace Umbraco.Core.Persistence.Factories { public ITag BuildEntity(TagDto dto) { - var model = new Tag(dto.Id, dto.Tag, dto.Group); + var model = new Tag(dto.Id, dto.Tag, dto.Group, dto.NodeCount); //on initial construction we don't want to have dirty properties tracked // http://issues.umbraco.org/issue/U4-1946 model.ResetDirtyProperties(false); @@ -20,7 +20,8 @@ namespace Umbraco.Core.Persistence.Factories { Id = entity.Id, Group = entity.Group, - Tag = entity.Text + Tag = entity.Text, + NodeCount = entity.NodeCount, }; } } diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/ITagsRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/ITagsRepository.cs index 479f9c85d8..17dfb4f96a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/ITagsRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/ITagsRepository.cs @@ -12,10 +12,11 @@ namespace Umbraco.Core.Persistence.Repositories /// /// Returns all tags for an entity type (content/media/member) /// - /// + /// Entity type /// Optional group + /// Optional flag to return the number of content items tagged with the tag /// - IEnumerable GetTagsForEntityType(TaggableObjectTypes objectType, string group = null); + IEnumerable GetTagsForEntityType(TaggableObjectTypes objectType, string group = null, bool withCount = false); /// /// Returns all tags that exist on the content item - Content/Media/Member diff --git a/src/Umbraco.Core/Persistence/Repositories/TagsRepository.cs b/src/Umbraco.Core/Persistence/Repositories/TagsRepository.cs index f98545ebe5..65ffa492ba 100644 --- a/src/Umbraco.Core/Persistence/Repositories/TagsRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/TagsRepository.cs @@ -226,67 +226,105 @@ namespace Umbraco.Core.Persistence.Repositories return list; } - public IEnumerable GetTagsForEntityType(TaggableObjectTypes objectType, string group = null) + public IEnumerable GetTagsForEntityType(TaggableObjectTypes objectType, string group = null, bool withCount = false) { var nodeObjectType = GetNodeObjectType(objectType); - var sql = new Sql() - .Select("DISTINCT cmsTags.*") - .From() - .InnerJoin() - .On(left => left.TagId, right => right.Id) + var sql = GetTagsQuerySelect(withCount); + + sql = ApplyRelationshipJoinToTagsQuery(sql); + + sql = sql .InnerJoin() .On(left => left.NodeId, right => right.NodeId) .InnerJoin() .On(left => left.NodeId, right => right.NodeId) .Where(dto => dto.NodeObjectType == nodeObjectType); - if (group.IsNullOrWhiteSpace() == false) - { - sql = sql.Where(dto => dto.Group == group); - } + sql = ApplyGroupFilterToTagsQuery(sql, group); - var factory = new TagFactory(); + sql = ApplyGroupByToTagsQuery(sql, withCount); - return Database.Fetch(sql).Select(factory.BuildEntity); + return ExecuteTagsQuery(sql); } public IEnumerable GetTagsForEntity(int contentId, string group = null) { - var sql = new Sql() - .Select("DISTINCT cmsTags.*") - .From() - .InnerJoin() - .On(left => left.TagId, right => right.Id) + var sql = GetTagsQuerySelect(); + + sql = ApplyRelationshipJoinToTagsQuery(sql); + + sql = sql .Where(dto => dto.NodeId == contentId); - if (group.IsNullOrWhiteSpace() == false) - { - sql = sql.Where(dto => dto.Group == group); - } + sql = ApplyGroupFilterToTagsQuery(sql, group); - var factory = new TagFactory(); - - return Database.Fetch(sql).Select(factory.BuildEntity); + return ExecuteTagsQuery(sql); } public IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string group = null) { - var sql = new Sql() - .Select("DISTINCT cmsTags.*") - .From() - .InnerJoin() - .On(left => left.TagId, right => right.Id) + var sql = GetTagsQuerySelect(); + + sql = ApplyRelationshipJoinToTagsQuery(sql); + + sql = sql .InnerJoin() .On(left => left.Id, right => right.PropertyTypeId) .Where(dto => dto.NodeId == contentId) .Where(dto => dto.Alias == propertyTypeAlias); - if (group.IsNullOrWhiteSpace() == false) + sql = ApplyGroupFilterToTagsQuery(sql, group); + + return ExecuteTagsQuery(sql); + } + + private Sql GetTagsQuerySelect(bool withCount = false) + { + var sql = new Sql(); + + if (withCount) + { + sql = sql.Select("cmsTags.Id, cmsTags.Tag, cmsTags.[Group], Count(*) NodeCount"); + } + else + { + sql = sql.Select("DISTINCT cmsTags.*"); + } + + return sql; + } + + private Sql ApplyRelationshipJoinToTagsQuery(Sql sql) + { + return sql + .From() + .InnerJoin() + .On(left => left.TagId, right => right.Id); + } + + private Sql ApplyGroupFilterToTagsQuery(Sql sql, string group) + { + if (!group.IsNullOrWhiteSpace()) { sql = sql.Where(dto => dto.Group == group); } + return sql; + } + + private Sql ApplyGroupByToTagsQuery(Sql sql, bool withCount) + { + if (withCount) + { + sql = sql.GroupBy(new string[] { "cmsTags.Id", "cmsTags.Tag", "cmsTags.[Group]" }); + } + + return sql; + } + + private IEnumerable ExecuteTagsQuery(Sql sql) + { var factory = new TagFactory(); return Database.Fetch(sql).Select(factory.BuildEntity); diff --git a/src/Umbraco.Core/Services/ITagService.cs b/src/Umbraco.Core/Services/ITagService.cs index 87b47c1cbc..c0ef7a2189 100644 --- a/src/Umbraco.Core/Services/ITagService.cs +++ b/src/Umbraco.Core/Services/ITagService.cs @@ -32,40 +32,42 @@ namespace Umbraco.Core.Services /// /// Get all tags for content items (with optional group) /// - /// + /// Optional group + /// Optional flag to return the number of content items tagged with the tag /// - IEnumerable GetAllContentTags(string group = null); + IEnumerable GetAllContentTags(string group = null, bool withCount = false); /// /// Get all tags for media items (with optional group) /// - /// + /// Optional group + /// Optional flag to return the number of content items tagged with the tag /// - IEnumerable GetAllMediaTags(string group = null); + IEnumerable GetAllMediaTags(string group = null, bool withCount = false); /// /// Get all tags for member items (with optional group) /// - /// + /// Optional group + /// Optional flag to return the number of content items tagged with the tag /// - IEnumerable GetAllMemberTags(string group = null); + IEnumerable GetAllMemberTags(string group = null, bool withCount = false); /// /// Returns all tags attached to a property by entity id /// - /// - /// - /// + /// The content item id to get tags for + /// Property type alias + /// Optional tag group /// IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string tagGroup = null); /// /// Returns all tags attached to an entity (content, media or member) by entity id /// - /// - /// + /// The content item id to get tags for + /// Optional tag group /// IEnumerable GetTagsForEntity(int contentId, string tagGroup = null); - } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/TagService.cs b/src/Umbraco.Core/Services/TagService.cs index 01c2826cea..76adf37995 100644 --- a/src/Umbraco.Core/Services/TagService.cs +++ b/src/Umbraco.Core/Services/TagService.cs @@ -10,7 +10,7 @@ using Umbraco.Core.Persistence.UnitOfWork; namespace Umbraco.Core.Services { /// - /// Tag service to query for tags in the tags db table. The tags returned are only relavent for published content & saved media or members + /// Tag service to query for tags in the tags db table. The tags returned are only relevant for published content & saved media or members /// /// /// If there is unpublished content with tags, those tags will not be contained @@ -110,48 +110,51 @@ namespace Umbraco.Core.Services /// /// Get all tags for content items (with optional group) /// - /// + /// Optional group + /// Optional flag to return the number of content items tagged with the tag /// - public IEnumerable GetAllContentTags(string group = null) + public IEnumerable GetAllContentTags(string group = null, bool withCount = false) { using (var repository = _repositoryFactory.CreateTagsRepository(_uowProvider.GetUnitOfWork())) { - return repository.GetTagsForEntityType(TaggableObjectTypes.Content, group); + return repository.GetTagsForEntityType(TaggableObjectTypes.Content, group, withCount); } } /// /// Get all tags for media items (with optional group) /// - /// + /// Optional group + /// Optional flag to return the number of content items tagged with the tag /// - public IEnumerable GetAllMediaTags(string group = null) + public IEnumerable GetAllMediaTags(string group = null, bool withCount = false) { using (var repository = _repositoryFactory.CreateTagsRepository(_uowProvider.GetUnitOfWork())) { - return repository.GetTagsForEntityType(TaggableObjectTypes.Media, group); + return repository.GetTagsForEntityType(TaggableObjectTypes.Media, group, withCount); } } /// /// Get all tags for member items (with optional group) /// - /// + /// Optional group + /// Optional flag to return the number of content items tagged with the tag /// - public IEnumerable GetAllMemberTags(string group = null) + public IEnumerable GetAllMemberTags(string group = null, bool withCount = false) { using (var repository = _repositoryFactory.CreateTagsRepository(_uowProvider.GetUnitOfWork())) { - return repository.GetTagsForEntityType(TaggableObjectTypes.Member, group); + return repository.GetTagsForEntityType(TaggableObjectTypes.Member, group, withCount); } } /// /// Returns all tags attached to a property by entity id /// - /// - /// - /// + /// The content item id to get tags for + /// Property type alias + /// Optional tag group /// public IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string tagGroup = null) { @@ -164,8 +167,8 @@ namespace Umbraco.Core.Services /// /// Returns all tags attached to an entity (content, media or member) by entity id /// - /// - /// + /// The content item id to get tags for + /// Optional tag group /// public IEnumerable GetTagsForEntity(int contentId, string tagGroup = null) {