From d82e9848da0b672a2e38bddfdce781877a9f5df7 Mon Sep 17 00:00:00 2001 From: sitereactor Date: Wed, 24 Oct 2012 10:49:08 -0200 Subject: [PATCH] Implements IDataTypeService for U4-938 Refactoring base ContentType Repository and its implementations to allow for queries against PropertyType - still needs testing though. Adding mappers for PropertyGroup and PropertyType models, so they are usable for queries. --- src/Umbraco.Core/Models/DataTypeDefinition.cs | 2 +- .../Models/IDataTypeDefinition.cs | 65 ++++++++ src/Umbraco.Core/Models/PropertyType.cs | 4 +- .../Factories/DataTypeDefinitionFactory.cs | 8 +- .../Mappers/PropertyGroupMapper.cs | 49 ++++++ .../Persistence/Mappers/PropertyTypeMapper.cs | 59 ++++++++ .../Repositories/ContentTypeBaseRepository.cs | 20 +++ .../Repositories/ContentTypeRepository.cs | 9 ++ .../DataTypeDefinitionRepository.cs | 28 ++-- .../Interfaces/IContentTypeRepository.cs | 11 +- .../IDataTypeDefinitionRepository.cs | 2 +- .../Interfaces/IMediaTypeRepository.cs | 11 +- .../Interfaces/IRepositoryQueryable.cs | 2 +- .../Repositories/MediaTypeRepository.cs | 9 ++ src/Umbraco.Core/Umbraco.Core.csproj | 3 + .../Mappers/PropertyGroupMapperTest.cs | 62 ++++++++ .../Mappers/PropertyTypeMapperTest.cs | 88 +++++++++++ .../Persistence/RepositoryResolverTests.cs | 2 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 2 + src/Umbraco.Web/Services/DataTypeService.cs | 142 ++++++++++++++++++ src/Umbraco.Web/Services/IDataTypeService.cs | 65 ++++++++ .../Services/UmbracoContextExtensions.cs | 33 ---- src/Umbraco.Web/Umbraco.Web.csproj | 3 +- 23 files changed, 617 insertions(+), 62 deletions(-) create mode 100644 src/Umbraco.Core/Models/IDataTypeDefinition.cs create mode 100644 src/Umbraco.Core/Persistence/Mappers/PropertyGroupMapper.cs create mode 100644 src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs create mode 100644 src/Umbraco.Tests/Persistence/Mappers/PropertyGroupMapperTest.cs create mode 100644 src/Umbraco.Tests/Persistence/Mappers/PropertyTypeMapperTest.cs create mode 100644 src/Umbraco.Web/Services/DataTypeService.cs create mode 100644 src/Umbraco.Web/Services/IDataTypeService.cs delete mode 100644 src/Umbraco.Web/Services/UmbracoContextExtensions.cs diff --git a/src/Umbraco.Core/Models/DataTypeDefinition.cs b/src/Umbraco.Core/Models/DataTypeDefinition.cs index a4dff4432b..4f8069ae16 100644 --- a/src/Umbraco.Core/Models/DataTypeDefinition.cs +++ b/src/Umbraco.Core/Models/DataTypeDefinition.cs @@ -14,7 +14,7 @@ namespace Umbraco.Core.Models /// [Serializable] [DataContract(IsReference = true)] - public class DataTypeDefinition : Entity, IAggregateRoot + public class DataTypeDefinition : Entity, IDataTypeDefinition { private int _parentId; private string _name; diff --git a/src/Umbraco.Core/Models/IDataTypeDefinition.cs b/src/Umbraco.Core/Models/IDataTypeDefinition.cs new file mode 100644 index 0000000000..ce87fcb5e7 --- /dev/null +++ b/src/Umbraco.Core/Models/IDataTypeDefinition.cs @@ -0,0 +1,65 @@ +using System; +using System.Runtime.Serialization; +using Umbraco.Core.Models.EntityBase; + +namespace Umbraco.Core.Models +{ + public interface IDataTypeDefinition : IAggregateRoot + { + /// + /// Gets or sets the Id of the Parent entity + /// + /// Might not be necessary if handled as a relation? + [DataMember] + int ParentId { get; set; } + + /// + /// Gets or sets the name of the current entity + /// + [DataMember] + string Name { get; set; } + + /// + /// Gets or sets the sort order of the content entity + /// + [DataMember] + int SortOrder { get; set; } + + /// + /// Gets or sets the level of the content entity + /// + [DataMember] + int Level { get; set; } + + /// + /// Gets or sets the path + /// + [DataMember] + string Path //Setting this value should be handled by the class not the user + { get; set; } + + /// + /// Id of the user who created this entity + /// + [DataMember] + int UserId { get; set; } + + /// + /// Boolean indicating whether this entity is Trashed or not. + /// + [DataMember] + bool Trashed { get; } + + /// + /// Id of the DataType control + /// + [DataMember] + Guid ControlId { get; } + + /// + /// Gets or Sets the DatabaseType for which the DataType's value is saved as + /// + [DataMember] + DataTypeDatabaseType DatabaseType { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index 08a70a4d54..853044de9b 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -104,9 +104,9 @@ namespace Umbraco.Core.Models } /// - /// Gets of Sets the Id of the DataType, which the PropertyType is "wrapping" + /// Gets of Sets the Id of the DataType (Definition), which the PropertyType is "wrapping" /// - /// This is actually the Id of the DataTypeDefinition + /// This is actually the Id of the [DataMember] public int DataTypeId { diff --git a/src/Umbraco.Core/Persistence/Factories/DataTypeDefinitionFactory.cs b/src/Umbraco.Core/Persistence/Factories/DataTypeDefinitionFactory.cs index 058a867be3..d9d4636e4d 100644 --- a/src/Umbraco.Core/Persistence/Factories/DataTypeDefinitionFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/DataTypeDefinitionFactory.cs @@ -5,7 +5,7 @@ using Umbraco.Core.Models.Rdbms; namespace Umbraco.Core.Persistence.Factories { - internal class DataTypeDefinitionFactory : IEntityFactory + internal class DataTypeDefinitionFactory : IEntityFactory { private readonly Guid _nodeObjectTypeId; private int _primaryKey; @@ -17,7 +17,7 @@ namespace Umbraco.Core.Persistence.Factories #region Implementation of IEntityFactory - public DataTypeDefinition BuildEntity(DataTypeDto dto) + public IDataTypeDefinition BuildEntity(DataTypeDto dto) { var dataTypeDefinition = new DataTypeDefinition(dto.ControlId) { @@ -41,7 +41,7 @@ namespace Umbraco.Core.Persistence.Factories return dataTypeDefinition; } - public DataTypeDto BuildDto(DataTypeDefinition entity) + public DataTypeDto BuildDto(IDataTypeDefinition entity) { var dataTypeDto = new DataTypeDto { @@ -66,7 +66,7 @@ namespace Umbraco.Core.Persistence.Factories _primaryKey = primaryKey; } - private NodeDto BuildNodeDto(DataTypeDefinition entity) + private NodeDto BuildNodeDto(IDataTypeDefinition entity) { var nodeDto = new NodeDto { diff --git a/src/Umbraco.Core/Persistence/Mappers/PropertyGroupMapper.cs b/src/Umbraco.Core/Persistence/Mappers/PropertyGroupMapper.cs new file mode 100644 index 0000000000..5ddcbbbdc4 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Mappers/PropertyGroupMapper.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Concurrent; +using System.Linq.Expressions; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Rdbms; + +namespace Umbraco.Core.Persistence.Mappers +{ + /// + /// Represents a to DTO mapper used to translate the properties of the public api + /// implementation to that of the database's DTO as sql: [tableName].[columnName]. + /// + internal sealed class PropertyGroupMapper : BaseMapper + { + private static readonly ConcurrentDictionary PropertyInfoCache = new ConcurrentDictionary(); + + internal static PropertyGroupMapper Instance = new PropertyGroupMapper(); + + private PropertyGroupMapper() + { + BuildMap(); + } + + #region Overrides of BaseMapper + + internal override void BuildMap() + { + CacheMap(src => src.Id, dto => dto.Id); + CacheMap(src => src.ParentId, dto => dto.ParentGroupId); + CacheMap(src => src.SortOrder, dto => dto.SortOrder); + CacheMap(src => src.Name, dto => dto.Text); + } + + internal override string Map(string propertyName) + { + var dtoTypeProperty = PropertyInfoCache[propertyName]; + + return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo); + } + + internal override void CacheMap(Expression> sourceMember, Expression> destinationMember) + { + var property = base.ResolveMapping(sourceMember, destinationMember); + PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs new file mode 100644 index 0000000000..ca572f11ab --- /dev/null +++ b/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Concurrent; +using System.Linq.Expressions; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Rdbms; + +namespace Umbraco.Core.Persistence.Mappers +{ + /// + /// Represents a to DTO mapper used to translate the properties of the public api + /// implementation to that of the database's DTO as sql: [tableName].[columnName]. + /// + internal sealed class PropertyTypeMapper : BaseMapper + { + private static readonly ConcurrentDictionary PropertyInfoCache = new ConcurrentDictionary(); + + internal static PropertyTypeMapper Instance = new PropertyTypeMapper(); + + private PropertyTypeMapper() + { + BuildMap(); + } + + #region Overrides of BaseMapper + + internal override void BuildMap() + { + if(PropertyInfoCache.IsEmpty) + { + CacheMap(src => src.Id, dto => dto.Id); + CacheMap(src => src.Alias, dto => dto.Alias); + CacheMap(src => src.DataTypeId, dto => dto.DataTypeId); + CacheMap(src => src.Description, dto => dto.Description); + CacheMap(src => src.HelpText, dto => dto.HelpText); + CacheMap(src => src.Mandatory, dto => dto.Mandatory); + CacheMap(src => src.Name, dto => dto.Name); + CacheMap(src => src.SortOrder, dto => dto.SortOrder); + CacheMap(src => src.ValidationRegExp, dto => dto.ValidationRegExp); + CacheMap(src => src.DataTypeControlId, dto => dto.ControlId); + CacheMap(src => src.DataTypeDatabaseType, dto => dto.DbType); + } + } + + internal override string Map(string propertyName) + { + var dtoTypeProperty = PropertyInfoCache[propertyName]; + + return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo); + } + + internal override void CacheMap(Expression> sourceMember, Expression> destinationMember) + { + var property = base.ResolveMapping(sourceMember, destinationMember); + PropertyInfoCache.AddOrUpdate(property.SourcePropertyName, property, (x, y) => property); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs index 2ba1de3642..ac99d6b9a8 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs @@ -7,6 +7,7 @@ using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence.Caching; using Umbraco.Core.Persistence.Factories; +using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.Relators; using Umbraco.Core.Persistence.UnitOfWork; @@ -29,6 +30,25 @@ namespace Umbraco.Core.Persistence.Repositories { } + protected IEnumerable PerformGetByQuery(IQuery query) + { + var sqlClause = new Sql(); + sqlClause.Select("*"); + sqlClause.From("cmsPropertyTypeGroup"); + sqlClause.RightJoin("cmsPropertyType ON [cmsPropertyTypeGroup].[id] = [cmsPropertyType].[propertyTypeGroupId]"); + sqlClause.InnerJoin("cmsDataType ON [cmsPropertyType].[dataTypeId] = [cmsDataType].[nodeId]"); + + var translator = new SqlTranslator(sqlClause, query); + var sql = translator.Translate(); + + var dtos = Database.Fetch(new GroupPropertyTypeRelator().Map, sql); + + foreach (var dto in dtos.DistinctBy(x => x.ContentTypeNodeId)) + { + yield return dto.ContentTypeNodeId; + } + } + protected void PersistNewBaseContentType(ContentTypeDto dto, IContentTypeComposition entity) { //Logic for setting Path, Level and SortOrder diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs index e7afb1cd3a..6f1d228eef 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs @@ -88,6 +88,15 @@ namespace Umbraco.Core.Persistence.Repositories #endregion + public IEnumerable GetByQuery(IQuery query) + { + var ints = PerformGetByQuery(query); + foreach (var i in ints) + { + yield return Get(i); + } + } + #region Overrides of PetaPocoRepositoryBase protected override Sql GetBaseQuery(bool isCount) diff --git a/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs index baafb40e71..6694178e49 100644 --- a/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs @@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Repositories /// /// Represents a repository for doing CRUD operations for /// - internal class DataTypeDefinitionRepository : PetaPocoRepositoryBase, IDataTypeDefinitionRepository + internal class DataTypeDefinitionRepository : PetaPocoRepositoryBase, IDataTypeDefinitionRepository { public DataTypeDefinitionRepository(IUnitOfWork work) : base(work) { @@ -27,7 +27,7 @@ namespace Umbraco.Core.Persistence.Repositories #region Overrides of RepositoryBase - protected override DataTypeDefinition PerformGet(int id) + protected override IDataTypeDefinition PerformGet(int id) { var dataTypeSql = GetBaseQuery(false); dataTypeSql.Append(GetBaseWhereClause(id)); @@ -39,11 +39,11 @@ namespace Umbraco.Core.Persistence.Repositories var factory = new DataTypeDefinitionFactory(NodeObjectTypeId); var definition = factory.BuildEntity(dataTypeDto); - definition.ResetDirtyProperties(); + ((DataTypeDefinition)definition).ResetDirtyProperties(); return definition; } - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable PerformGetAll(params int[] ids) { if (ids.Any()) { @@ -62,10 +62,10 @@ namespace Umbraco.Core.Persistence.Repositories } } - protected override IEnumerable PerformGetByQuery(IQuery query) + protected override IEnumerable PerformGetByQuery(IQuery query) { var sqlClause = GetBaseQuery(false); - var translator = new SqlTranslator(sqlClause, query); + var translator = new SqlTranslator(sqlClause, query); var sql = translator.Translate(); var dataTypeDtos = Database.Fetch(sql); @@ -110,10 +110,10 @@ namespace Umbraco.Core.Persistence.Repositories #endregion #region Unit of Work Implementation - - protected override void PersistNewItem(DataTypeDefinition entity) + + protected override void PersistNewItem(IDataTypeDefinition entity) { - entity.AddingEntity(); + ((DataTypeDefinition)entity).AddingEntity(); var factory = new DataTypeDefinitionFactory(NodeObjectTypeId); var dto = factory.BuildDto(entity); @@ -144,13 +144,13 @@ namespace Umbraco.Core.Persistence.Repositories Database.Insert(dto); - entity.ResetDirtyProperties(); + ((DataTypeDefinition)entity).ResetDirtyProperties(); } - protected override void PersistUpdatedItem(DataTypeDefinition entity) + protected override void PersistUpdatedItem(IDataTypeDefinition entity) { //Updates Modified date and Version Guid - entity.UpdatingEntity(); + ((DataTypeDefinition)entity).UpdatingEntity(); var factory = new DataTypeDefinitionFactory(NodeObjectTypeId); //Look up DataTypeDefinition entry to get Primary for updating the DTO @@ -163,10 +163,10 @@ namespace Umbraco.Core.Persistence.Repositories Database.Update(nodeDto); Database.Update(dto); - entity.ResetDirtyProperties(); + ((DataTypeDefinition)entity).ResetDirtyProperties(); } - protected override void PersistDeletedItem(DataTypeDefinition entity) + protected override void PersistDeletedItem(IDataTypeDefinition entity) { //Remove Notifications Database.Delete("WHERE nodeId = @Id", new { Id = entity.Id }); diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentTypeRepository.cs index abbf8c95a0..a63e531d90 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentTypeRepository.cs @@ -1,9 +1,16 @@ -using Umbraco.Core.Models; +using System.Collections.Generic; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence.Querying; namespace Umbraco.Core.Persistence.Repositories { public interface IContentTypeRepository : IRepositoryQueryable { - + /// + /// Gets all entities of the specified query + /// + /// + /// An enumerable list of objects + IEnumerable GetByQuery(IQuery query); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IDataTypeDefinitionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IDataTypeDefinitionRepository.cs index 01e3faaa9a..7a39a2cdc1 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IDataTypeDefinitionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IDataTypeDefinitionRepository.cs @@ -2,7 +2,7 @@ namespace Umbraco.Core.Persistence.Repositories { - public interface IDataTypeDefinitionRepository : IRepositoryQueryable + public interface IDataTypeDefinitionRepository : IRepositoryQueryable { } diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaTypeRepository.cs index e92cb3fecf..54220e0b59 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMediaTypeRepository.cs @@ -1,9 +1,16 @@ -using Umbraco.Core.Models; +using System.Collections.Generic; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence.Querying; namespace Umbraco.Core.Persistence.Repositories { public interface IMediaTypeRepository : IRepositoryQueryable { - + /// + /// Gets all entities of the specified query + /// + /// + /// An enumerable list of objects + IEnumerable GetByQuery(IQuery query); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepositoryQueryable.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepositoryQueryable.cs index 9174c1caf0..9cea6ce7bc 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepositoryQueryable.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepositoryQueryable.cs @@ -13,7 +13,7 @@ namespace Umbraco.Core.Persistence.Repositories where TEntity : IAggregateRoot { /// - /// Gets all entities of the spefified type and query + /// Gets all entities of the specified type and query /// /// /// diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs index ed5a167b26..2271085696 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs @@ -88,6 +88,15 @@ namespace Umbraco.Core.Persistence.Repositories #endregion + public IEnumerable GetByQuery(IQuery query) + { + var ints = PerformGetByQuery(query); + foreach (var i in ints) + { + yield return Get(i); + } + } + #region Overrides of PetaPocoRepositoryBase protected override Sql GetBaseQuery(bool isCount) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 3b6b7fcb1e..7940527a46 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -87,6 +87,7 @@ + @@ -140,6 +141,8 @@ + + diff --git a/src/Umbraco.Tests/Persistence/Mappers/PropertyGroupMapperTest.cs b/src/Umbraco.Tests/Persistence/Mappers/PropertyGroupMapperTest.cs new file mode 100644 index 0000000000..1fad331023 --- /dev/null +++ b/src/Umbraco.Tests/Persistence/Mappers/PropertyGroupMapperTest.cs @@ -0,0 +1,62 @@ +using NUnit.Framework; +using Umbraco.Core.Persistence.Mappers; +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Tests.Persistence.Mappers +{ + [TestFixture] + public class PropertyGroupMapperTest + { + [Test] + public void Can_Map_Id_Property() + { + // Arrange + SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider; + + // Act + string column = PropertyGroupMapper.Instance.Map("Id"); + + // Assert + Assert.That(column, Is.EqualTo("[cmsPropertyTypeGroup].[id]")); + } + + [Test] + public void Can_Map_ParentId_Property() + { + // Arrange + SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider; + + // Act + string column = PropertyGroupMapper.Instance.Map("ParentId"); + + // Assert + Assert.That(column, Is.EqualTo("[cmsPropertyTypeGroup].[parentGroupId]")); + } + + [Test] + public void Can_Map_SortOrder_Property() + { + // Arrange + SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider; + + // Act + string column = PropertyGroupMapper.Instance.Map("SortOrder"); + + // Assert + Assert.That(column, Is.EqualTo("[cmsPropertyTypeGroup].[sortorder]")); + } + + [Test] + public void Can_Map_Name_Property() + { + // Arrange + SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider; + + // Act + string column = PropertyGroupMapper.Instance.Map("Name"); + + // Assert + Assert.That(column, Is.EqualTo("[cmsPropertyTypeGroup].[text]")); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Persistence/Mappers/PropertyTypeMapperTest.cs b/src/Umbraco.Tests/Persistence/Mappers/PropertyTypeMapperTest.cs new file mode 100644 index 0000000000..a45cf065e2 --- /dev/null +++ b/src/Umbraco.Tests/Persistence/Mappers/PropertyTypeMapperTest.cs @@ -0,0 +1,88 @@ +using NUnit.Framework; +using Umbraco.Core.Persistence.Mappers; +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Tests.Persistence.Mappers +{ + [TestFixture] + public class PropertyTypeMapperTest + { + [Test] + public void Can_Map_Id_Property() + { + // Arrange + SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider; + + // Act + string column = PropertyTypeMapper.Instance.Map("Id"); + + // Assert + Assert.That(column, Is.EqualTo("[cmsPropertyType].[id]")); + } + + [Test] + public void Can_Map_Alias_Property() + { + // Arrange + SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider; + + // Act + string column = PropertyTypeMapper.Instance.Map("Alias"); + + // Assert + Assert.That(column, Is.EqualTo("[cmsPropertyType].[Alias]")); + } + + [Test] + public void Can_Map_DataTypeId_Property() + { + // Arrange + SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider; + + // Act + string column = PropertyTypeMapper.Instance.Map("DataTypeId"); + + // Assert + Assert.That(column, Is.EqualTo("[cmsPropertyType].[dataTypeId]")); + } + + [Test] + public void Can_Map_SortOrder_Property() + { + // Arrange + SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider; + + // Act + string column = PropertyTypeMapper.Instance.Map("SortOrder"); + + // Assert + Assert.That(column, Is.EqualTo("[cmsPropertyType].[sortOrder]")); + } + + [Test] + public void Can_Map_DataTypeControlId_Property() + { + // Arrange + SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider; + + // Act + string column = PropertyTypeMapper.Instance.Map("DataTypeControlId"); + + // Assert + Assert.That(column, Is.EqualTo("[cmsDataType].[controlId]")); + } + + [Test] + public void Can_Map_DataTypeDatabaseType_Property() + { + // Arrange + SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider; + + // Act + string column = PropertyTypeMapper.Instance.Map("DataTypeDatabaseType"); + + // Assert + Assert.That(column, Is.EqualTo("[cmsDataType].[dbType]")); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Persistence/RepositoryResolverTests.cs b/src/Umbraco.Tests/Persistence/RepositoryResolverTests.cs index 88d3ac3d8b..6b291418f8 100644 --- a/src/Umbraco.Tests/Persistence/RepositoryResolverTests.cs +++ b/src/Umbraco.Tests/Persistence/RepositoryResolverTests.cs @@ -81,7 +81,7 @@ namespace Umbraco.Tests.Persistence var uow = new PetaPocoUnitOfWork(); // Act - var repository = RepositoryResolver.ResolveByType(uow); + var repository = RepositoryResolver.ResolveByType(uow); // Assert Assert.That(repository, Is.Not.Null); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 553f0679ca..048cd5a5ac 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -103,6 +103,8 @@ + + diff --git a/src/Umbraco.Web/Services/DataTypeService.cs b/src/Umbraco.Web/Services/DataTypeService.cs new file mode 100644 index 0000000000..8e71d16469 --- /dev/null +++ b/src/Umbraco.Web/Services/DataTypeService.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Querying; +using Umbraco.Core.Persistence.Repositories; +using Umbraco.Core.Persistence.UnitOfWork; +using umbraco.interfaces; + +namespace Umbraco.Web.Services +{ + /// + /// Represents the DataType Service, which is an easy access to operations involving and + /// + public class DataTypeService : IDataTypeService + { + private readonly IUnitOfWorkProvider _provider; + + public DataTypeService() : this(new PetaPocoUnitOfWorkProvider()) + { + } + + public DataTypeService(IUnitOfWorkProvider provider) + { + _provider = provider; + } + + /// + /// Gets a by its Id + /// + /// Id of the + /// + public IDataTypeDefinition GetDataTypeDefinitionById(int id) + { + var unitOfWork = _provider.GetUnitOfWork(); + var repository = RepositoryResolver.ResolveByType(unitOfWork); + return repository.Get(id); + } + + /// + /// Gets a by its control Id + /// + /// Id of the DataType control + /// + public IDataTypeDefinition GetDataTypeDefinitionById(Guid id) + { + var unitOfWork = _provider.GetUnitOfWork(); + var repository = RepositoryResolver.ResolveByType(unitOfWork); + + var query = Query.Builder.Where(x => x.ControlId == id); + var definitions = repository.GetByQuery(query); + + return definitions.FirstOrDefault(); + } + + /// + /// Gets all objects or those with the ids passed in + /// + /// Optional array of Ids + /// An enumerable list of objects + public IEnumerable GetAllDataTypeDefinitions(params int[] ids) + { + var unitOfWork = _provider.GetUnitOfWork(); + var repository = RepositoryResolver.ResolveByType(unitOfWork); + return repository.GetAll(ids); + } + + /// + /// Saves an + /// + /// to save + /// Id of the user issueing the save + public void Save(IDataTypeDefinition dataTypeDefinition, int userId) + { + var unitOfWork = _provider.GetUnitOfWork(); + var repository = RepositoryResolver.ResolveByType(unitOfWork); + repository.AddOrUpdate(dataTypeDefinition); + unitOfWork.Commit(); + } + + /// + /// Deletes an + /// + /// + /// Please note that deleting a will remove + /// all the data that references this . + /// + /// to delete + /// Id of the user issueing the deletion + public void Delete(IDataTypeDefinition dataTypeDefinition, int userId) + { + var unitOfWork = _provider.GetUnitOfWork(); + + //Find ContentTypes using this IDataTypeDefinition on a PropertyType + var contentTypeRepository = RepositoryResolver.ResolveByType(unitOfWork); + var query = Query.Builder.Where(x => x.DataTypeId == dataTypeDefinition.Id); + var contentTypes = contentTypeRepository.GetByQuery(query); + + //Loop through the list of results and remove the PropertyTypes that references the DataTypeDefinition that is being deleted + foreach (var contentType in contentTypes) + { + if(contentType == null) continue; + + foreach (var group in contentType.PropertyGroups) + { + var types = group.PropertyTypes.Where(x => x.DataTypeId == dataTypeDefinition.Id); + foreach (var propertyType in types) + { + group.PropertyTypes.Remove(propertyType); + } + } + + contentTypeRepository.AddOrUpdate(contentType); + } + + var repository = RepositoryResolver.ResolveByType(unitOfWork); + repository.Delete(dataTypeDefinition); + unitOfWork.Commit(); + } + + /// + /// Retrieves the IDataType specified by it's unique ID + /// + /// Id of the DataType, which corresponds to the Guid Id of the control + /// object + public IDataType GetDataTypeById(Guid id) + { + return DataTypesResolver.Current.GetById(id); + } + + /// + /// Retrieve a complete list of all registered IDataType's + /// + /// An enumerable list of objects + public IEnumerable GetAllDataTypes() + { + return DataTypesResolver.Current.DataTypes; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Services/IDataTypeService.cs b/src/Umbraco.Web/Services/IDataTypeService.cs new file mode 100644 index 0000000000..d16f62552c --- /dev/null +++ b/src/Umbraco.Web/Services/IDataTypeService.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core.Models; +using umbraco.interfaces; + +namespace Umbraco.Web.Services +{ + /// + /// Defines the DataType Service, which is an easy access to operations involving and + /// + public interface IDataTypeService : IService + { + /// + /// Gets a by its Id + /// + /// Id of the + /// + IDataTypeDefinition GetDataTypeDefinitionById(int id); + + /// + /// Gets a by its control Id + /// + /// Id of the DataType control + /// + IDataTypeDefinition GetDataTypeDefinitionById(Guid id); + + /// + /// Gets all objects or those with the ids passed in + /// + /// Optional array of Ids + /// An enumerable list of objects + IEnumerable GetAllDataTypeDefinitions(params int[] ids); + + /// + /// Saves an + /// + /// to save + /// Id of the user issueing the save + void Save(IDataTypeDefinition dataTypeDefinition, int userId); + + /// + /// Deletes an + /// + /// + /// Please note that deleting a will remove + /// all the data that references this . + /// + /// to delete + /// Id of the user issueing the deletion + void Delete(IDataTypeDefinition dataTypeDefinition, int userId); + + /// + /// Retrieves the IDataType specified by it's unique ID + /// + /// Id of the DataType, which corresponds to the Guid Id of the control + /// object + IDataType GetDataTypeById(Guid id); + + /// + /// Retrieve a complete list of all registered IDataType's + /// + /// An enumerable list of objects + IEnumerable GetAllDataTypes(); + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Services/UmbracoContextExtensions.cs b/src/Umbraco.Web/Services/UmbracoContextExtensions.cs deleted file mode 100644 index e69f98f762..0000000000 --- a/src/Umbraco.Web/Services/UmbracoContextExtensions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Concurrent; -using Umbraco.Core.Persistence.UnitOfWork; -using Umbraco.Web.Publishing; -using Umbraco.Web.Services; - -namespace Umbraco.Web -{ - /// - /// Service specific extensions for , which provides access to the various services - /// - public static class UmbracoContextExtensions - { - //TODO Add services to a dictionary, so we don't create a new instance each time a service is needed - private static readonly ConcurrentDictionary ServiceCache = new ConcurrentDictionary(); - - public static IContentService ContentService(this UmbracoContext umbracoContext) - { - return new ContentService(new PetaPocoUnitOfWorkProvider(), new PublishingStrategy()); - } - - public static IMediaService MediaService(this UmbracoContext umbracoContext) - { - return new MediaService(new PetaPocoUnitOfWorkProvider()); - } - - public static IContentTypeService ContentTypeService(this UmbracoContext umbracoContext) - { - var contentService = umbracoContext.ContentService(); - var mediaService = umbracoContext.MediaService(); - return new ContentTypeService(contentService, mediaService, new PetaPocoUnitOfWorkProvider()); - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 2306a102b2..c118c85ba4 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -315,12 +315,13 @@ + + - ASPXCodeBehind