diff --git a/src/Umbraco.Core/CodeAnnotations/FriendlyNameAttribute.cs b/src/Umbraco.Core/CodeAnnotations/FriendlyNameAttribute.cs new file mode 100644 index 0000000000..54d47cca17 --- /dev/null +++ b/src/Umbraco.Core/CodeAnnotations/FriendlyNameAttribute.cs @@ -0,0 +1,34 @@ +using System; + +namespace Umbraco.Core.CodeAnnotations +{ + /// + /// Attribute to add a Friendly Name string with an UmbracoObjectType enum value + /// + internal class FriendlyNameAttribute : Attribute + { + /// + /// friendly name value + /// + private readonly string _friendlyName; + + /// + /// Initializes a new instance of the FriendlyNameAttribute class + /// Sets the friendly name value + /// + /// attribute value + public FriendlyNameAttribute(string friendlyName) + { + this._friendlyName = friendlyName; + } + + /// + /// Gets the friendly name + /// + /// string of friendly name + public override string ToString() + { + return this._friendlyName; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/CodeAnnotations/UmbracoObjectTypeAttribute.cs b/src/Umbraco.Core/CodeAnnotations/UmbracoObjectTypeAttribute.cs new file mode 100644 index 0000000000..e6f887a2c8 --- /dev/null +++ b/src/Umbraco.Core/CodeAnnotations/UmbracoObjectTypeAttribute.cs @@ -0,0 +1,25 @@ +using System; + +namespace Umbraco.Core.CodeAnnotations +{ + /// + /// Attribute to associate a GUID string and Type with an UmbracoObjectType Enum value + /// + internal class UmbracoObjectTypeAttribute : Attribute + { + public UmbracoObjectTypeAttribute(string objectId) + { + ObjectId = new Guid(objectId); + } + + public UmbracoObjectTypeAttribute(string objectId, Type modelType) + { + ObjectId = new Guid(objectId); + ModelType = modelType; + } + + public Guid ObjectId { get; private set; } + + public Type ModelType { get; private set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/UmbracoEntity.cs b/src/Umbraco.Core/Models/UmbracoEntity.cs new file mode 100644 index 0000000000..6e29dda984 --- /dev/null +++ b/src/Umbraco.Core/Models/UmbracoEntity.cs @@ -0,0 +1,40 @@ +using System; +using Umbraco.Core.Models.EntityBase; + +namespace Umbraco.Core.Models +{ + /// + /// Implementation of the for internal use. + /// + internal class UmbracoEntity : Entity, IUmbracoEntity + { + public UmbracoEntity() + { + } + + public UmbracoEntity(bool trashed) + { + Trashed = trashed; + } + + public int CreatorId { get; set; } + + public int Level { get; set; } + + public string Name { get; set; } + + public int ParentId { get; set; } + + public string Path { get; set; } + + public int SortOrder { get; set; } + + public bool Trashed { get; private set; } + + public bool HasChildren { get; set; } + + public bool IsPublished { get; set; } + + public Guid NodeObjectTypeId { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/UmbracoObjectTypes.cs b/src/Umbraco.Core/Models/UmbracoObjectTypes.cs new file mode 100644 index 0000000000..e4121a22a1 --- /dev/null +++ b/src/Umbraco.Core/Models/UmbracoObjectTypes.cs @@ -0,0 +1,113 @@ +using Umbraco.Core.CodeAnnotations; + +namespace Umbraco.Core.Models +{ + /// + /// Enum used to represent the Umbraco Object Types and thier associated GUIDs + /// + public enum UmbracoObjectTypes + { + /// + /// Default value + /// + Unknown, + + /// + /// Content Item Type + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.ContentItemType)] + [FriendlyName("Content Item Type")] + ContentItemType, + + /// + /// Root + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.SystemRoot)] + [FriendlyName("Root")] + ROOT, + + /// + /// Document + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.Document, typeof(IContent))] + [FriendlyName("Document")] + Document, + + /// + /// Media + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.Media, typeof(IMedia))] + [FriendlyName("Media")] + Media, + + /// + /// Member Type + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.MemberType)] + [FriendlyName("Member Type")] + MemberType, + + /// + /// Template + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.Template, typeof(ITemplate))] + [FriendlyName("Template")] + Template, + + /// + /// Member Group + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.MemberGroup)] + [FriendlyName("Member Group")] + MemberGroup, + + /// + /// Content Item + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.ContentItem)] + [FriendlyName("Content Item")] + ContentItem, + + /// + /// "Media Type + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.MediaType, typeof(IMediaType))] + [FriendlyName("Media Type")] + MediaType, + + /// + /// Document Type + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.DocumentType, typeof(IContentType))] + [FriendlyName("Document Type")] + DocumentType, + + /// + /// Recycle Bin + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.RecycleBin)] + [FriendlyName("Recycle Bin")] + RecycleBin, + + /// + /// Stylesheet + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.Stylesheet)] + [FriendlyName("Stylesheet")] + Stylesheet, + + /// + /// Member + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.Member)] + [FriendlyName("Member")] + Member, + + /// + /// Data Type + /// + [UmbracoObjectTypeAttribute(Constants.ObjectTypes.DataType, typeof(IDataTypeDefinition))] + [FriendlyName("Data Type")] + DataType + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs b/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs new file mode 100644 index 0000000000..af4476f394 --- /dev/null +++ b/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs @@ -0,0 +1,79 @@ +using System; +using Umbraco.Core.CodeAnnotations; + +namespace Umbraco.Core.Models +{ + /// + /// Extension methods for the UmbracoObjectTypes enum + /// + public static class UmbracoObjectTypesExtensions + { + /// + /// Get an UmbracoObjectTypes value from it's name + /// + /// Enum value name + /// an UmbracoObjectTypes Enum value + public static UmbracoObjectTypes GetUmbracoObjectType(string name) + { + return (UmbracoObjectTypes)Enum.Parse(typeof(UmbracoObjectTypes), name, false); + } + + /// + /// Get an instance of an UmbracoObjectTypes enum value from it's GUID + /// + /// Enum value GUID + /// an UmbracoObjectTypes Enum value + public static UmbracoObjectTypes GetUmbracoObjectType(Guid guid) + { + var umbracoObjectType = UmbracoObjectTypes.Unknown; + + foreach (var name in Enum.GetNames(typeof(UmbracoObjectTypes))) + { + if (GetUmbracoObjectType(name).GetGuid() == guid) + { + umbracoObjectType = GetUmbracoObjectType(name); + } + } + + return umbracoObjectType; + } + + /// + /// Extension method for the UmbracoObjectTypes enum to return the enum GUID + /// + /// UmbracoObjectTypes Enum value + /// a GUID value of the UmbracoObjectTypes + public static Guid GetGuid(this UmbracoObjectTypes umbracoObjectType) + { + var attribute = umbracoObjectType.GetType().FirstAttribute(); + if (attribute == null) + return Guid.Empty; + + return attribute.ObjectId; + } + + /// + /// Extension method for the UmbracoObjectTypes enum to return the enum name + /// + /// UmbracoObjectTypes value + /// The enum name of the UmbracoObjectTypes value + public static string GetName(this UmbracoObjectTypes umbracoObjectType) + { + return Enum.GetName(typeof(UmbracoObjectTypes), umbracoObjectType); + } + + /// + /// Extension method for the UmbracoObejctTypes enum to return the enum friendly name + /// + /// UmbracoObjectTypes value + /// a string of the FriendlyName + public static string GetFriendlyName(this UmbracoObjectTypes umbracoObjectType) + { + var attribute = umbracoObjectType.GetType().FirstAttribute(); + if (attribute == null) + return string.Empty; + + return attribute.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs new file mode 100644 index 0000000000..41ce480a44 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs @@ -0,0 +1,48 @@ +using System.Globalization; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Rdbms; + +namespace Umbraco.Core.Persistence.Factories +{ + internal class UmbracoEntityFactory : IEntityFactory + { + public UmbracoEntity BuildEntity(NodeDto dto) + { + var entity = new UmbracoEntity(dto.Trashed) + { + CreateDate = dto.CreateDate, + CreatorId = dto.UserId.Value, + Id = dto.NodeId, + Key = dto.UniqueId.Value, + Level = dto.Level, + Name = dto.Text, + NodeObjectTypeId = dto.NodeObjectType.Value, + ParentId = dto.ParentId, + Path = dto.Path, + SortOrder = dto.SortOrder, + HasChildren = false, + IsPublished = false + }; + return entity; + } + + public NodeDto BuildDto(UmbracoEntity entity) + { + var node = new NodeDto + { + CreateDate = entity.CreateDate, + Level = short.Parse(entity.Level.ToString(CultureInfo.InvariantCulture)), + NodeId = entity.Id, + NodeObjectType = entity.NodeObjectTypeId, + ParentId = entity.ParentId, + Path = entity.Path, + SortOrder = entity.SortOrder, + Text = entity.Name, + Trashed = entity.Trashed, + UniqueId = entity.Key, + UserId = entity.CreatorId + }; + return node; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs new file mode 100644 index 0000000000..62d2978004 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.Models.EntityBase; +using Umbraco.Core.Models.Rdbms; +using Umbraco.Core.Persistence.Factories; +using Umbraco.Core.Persistence.Querying; +using Umbraco.Core.Persistence.UnitOfWork; + +namespace Umbraco.Core.Persistence.Repositories +{ + /// + /// Represents the EntityRepository used to query objects. + /// + /// + /// This is limited to objects that are based in the umbracoNode-table. + /// + internal class EntityRepository : DisposableObject, IEntityRepository + { + private readonly IDatabaseUnitOfWork _work; + + public EntityRepository(IDatabaseUnitOfWork work) + { + _work = work; + } + + /// + /// Returns the Unit of Work added to the repository + /// + protected internal IDatabaseUnitOfWork UnitOfWork + { + get { return _work; } + } + + /// + /// Internal for testing purposes + /// + internal Guid UnitKey + { + get { return (Guid)_work.Key; } + } + + #region Query Methods + + public virtual IUmbracoEntity Get(int id) + { + var sql = GetBaseWhere(id); + var nodeDto = _work.Database.FirstOrDefault(sql); + if (nodeDto == null) + return null; + + var factory = new UmbracoEntityFactory(); + var entity = factory.BuildEntity(nodeDto); + + //TODO Update HasChildren and IsPublished + + return entity; + } + + public virtual IUmbracoEntity Get(int id, Guid objectTypeId) + { + var sql = GetBaseWhere(objectTypeId, id); + var nodeDto = _work.Database.FirstOrDefault(sql); + if (nodeDto == null) + return null; + + var factory = new UmbracoEntityFactory(); + var entity = factory.BuildEntity(nodeDto); + + //TODO Update HasChildren and IsPublished + + return entity; + } + + public virtual IEnumerable GetAll(Guid objectTypeId, params int[] ids) + { + if (ids.Any()) + { + foreach (var id in ids) + { + yield return Get(id, objectTypeId); + } + } + else + { + var sql = GetBaseWhere(objectTypeId); + var dtos = _work.Database.Fetch(sql); + + var factory = new UmbracoEntityFactory(); + + foreach (var dto in dtos) + { + var entity = factory.BuildEntity(dto); + //TODO Update HasChildren and IsPublished properties + yield return entity; + } + } + } + + public virtual IEnumerable GetByQuery(IQuery query) + { + var sqlClause = GetBaseQuery(); + var translator = new SqlTranslator(sqlClause, query); + var sql = translator.Translate(); + + var dtos = _work.Database.Fetch(sql); + + var factory = new UmbracoEntityFactory(); + var list = dtos.Select(factory.BuildEntity).Cast().ToList(); + + //TODO Update HasChildren and IsPublished properties + + return list; + } + + public virtual IEnumerable GetByQuery(IQuery query, Guid objectTypeId) + { + var sqlClause = GetBaseWhere(objectTypeId); + var translator = new SqlTranslator(sqlClause, query); + var sql = translator.Translate(); + + var dtos = _work.Database.Fetch(sql); + + var factory = new UmbracoEntityFactory(); + var list = dtos.Select(factory.BuildEntity).Cast().ToList(); + + //TODO Update HasChildren and IsPublished properties + + return list; + } + + #endregion + + #region Sql Statements + + protected virtual Sql GetBaseQuery() + { + var sql = new Sql() + .From(); + return sql; + } + + protected virtual Sql GetBaseWhere(Guid id) + { + var sql = GetBaseQuery() + .Where(x => x.NodeObjectType == id); + return sql; + } + + protected virtual Sql GetBaseWhere(int id) + { + var sql = GetBaseQuery() + .Where(x => x.NodeId == id); + return sql; + } + + protected virtual Sql GetBaseWhere(Guid objectId, int id) + { + var sql = GetBaseWhere(objectId) + .Where(x => x.NodeId == id); + return sql; + } + + #endregion + + /// + /// Dispose disposable properties + /// + /// + /// Ensure the unit of work is disposed + /// + protected override void DisposeResources() + { + UnitOfWork.DisposeIfDisposable(); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IEntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IEntityRepository.cs new file mode 100644 index 0000000000..6df0293be0 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IEntityRepository.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core.Models.EntityBase; +using Umbraco.Core.Persistence.Querying; + +namespace Umbraco.Core.Persistence.Repositories +{ + public interface IEntityRepository : IRepository + { + IUmbracoEntity Get(int id); + IUmbracoEntity Get(int id, Guid objectTypeId); + IEnumerable GetAll(Guid objectTypeId, params int[] ids); + IEnumerable GetByQuery(IQuery query); + IEnumerable GetByQuery(IQuery query, Guid objectTypeId); + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs index aac31b9568..78007f35da 100644 --- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs +++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs @@ -32,6 +32,11 @@ namespace Umbraco.Core.Persistence CreateUserTypeRepository(uow)); } + internal virtual IEntityRepository CreateEntityRepository(IDatabaseUnitOfWork uow) + { + return new EntityRepository(uow); + } + public virtual IContentRepository CreateContentRepository(IDatabaseUnitOfWork uow) { return new ContentRepository( diff --git a/src/Umbraco.Core/Services/EntityService.cs b/src/Umbraco.Core/Services/EntityService.cs new file mode 100644 index 0000000000..42f7bcb189 --- /dev/null +++ b/src/Umbraco.Core/Services/EntityService.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core.Models; +using Umbraco.Core.Models.EntityBase; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.UnitOfWork; + +namespace Umbraco.Core.Services +{ + internal class EntityService : IService + { + private readonly IDatabaseUnitOfWorkProvider _uowProvider; + private readonly RepositoryFactory _repositoryFactory; + + public EntityService() + : this(new RepositoryFactory()) + { } + + public EntityService(RepositoryFactory repositoryFactory) + : this(new PetaPocoUnitOfWorkProvider(), repositoryFactory) + { } + + public EntityService(IDatabaseUnitOfWorkProvider provider) + : this(provider, new RepositoryFactory()) + { } + + public EntityService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory) + { + _uowProvider = provider; + _repositoryFactory = repositoryFactory; + } + + /// + /// Gets an UmbracoEntity by its Id, and optionally loads the complete object graph. + /// + /// + /// By default this will load the base type with a minimum set of properties. + /// + /// Id of the object to retrieve + /// Optional bool to load the complete object graph when set to False. + /// An + public virtual IUmbracoEntity Get(int id, bool loadBaseType = true) + { + throw new NotImplementedException(); + } + + /// + /// Gets an UmbracoEntity by its Id and specified Type. Optionally loads the complete object graph. + /// + /// + /// By default this will load the base type with a minimum set of properties. + /// + /// Type of the model to retrieve. Must be based on an + /// Id of the object to retrieve + /// Optional bool to load the complete object graph when set to False. + /// An + public virtual IUmbracoEntity Get(int id, bool loadBaseType = true) where T : IUmbracoEntity + { + throw new NotImplementedException(); + } + + public virtual IUmbracoEntity GetParent(int id) + { + throw new NotImplementedException(); + } + + public virtual IEnumerable GetChildren(int id) + { + throw new NotImplementedException(); + } + + public virtual IEnumerable GetDescendents(int id) + { + throw new NotImplementedException(); + } + + public virtual IEnumerable GetAll() where T : IUmbracoEntity + { + throw new NotImplementedException(); + } + + public virtual IEnumerable GetAll(UmbracoObjectTypes objectType) + { + throw new NotImplementedException(); + } + + public virtual IEnumerable GetAll(Guid objectTypeId) + { + throw new NotImplementedException(); + } + + public virtual UmbracoObjectTypes GetObjectType(int id) + { + throw new NotImplementedException(); + } + + public virtual UmbracoObjectTypes GetObjectType(IUmbracoEntity entity) + { + throw new NotImplementedException(); + } + + public virtual Type GetModelType(int id) + { + throw new NotImplementedException(); + } + + public virtual Type GetModelType(UmbracoObjectTypes objectType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 1b4eab601a..c8ad3e9626 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -109,6 +109,8 @@ + + @@ -206,6 +208,9 @@ + + + @@ -213,6 +218,7 @@ + @@ -436,7 +442,9 @@ + + @@ -670,6 +678,7 @@ +