Refactoring Content/Media and ContentTypes/MediaTypes so the two are as close as possible. By doing this Media and Content are practically the same witht the except of a few properties.
This implements U4-10
This commit is contained in:
@@ -1,11 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -14,21 +9,12 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class Content : Entity, IContent
|
||||
public class Content : ContentBase, IContent
|
||||
{
|
||||
private IContentType _contentType;
|
||||
private int _parentId;
|
||||
private string _name;
|
||||
private int _sortOrder;
|
||||
private int _level;
|
||||
private string _path;
|
||||
private string _template;
|
||||
private int _userId;
|
||||
private bool _trashed;
|
||||
private bool _published;
|
||||
private string _language;
|
||||
private int _contentTypeId;
|
||||
private PropertyCollection _properties;
|
||||
private DateTime? _releaseDate;
|
||||
private DateTime? _expireDate;
|
||||
|
||||
@@ -47,112 +33,16 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="parentId">Id of the Parent content</param>
|
||||
/// <param name="contentType">ContentType for the current Content object</param>
|
||||
/// <param name="properties">Collection of properties</param>
|
||||
public Content(int parentId, IContentType contentType, PropertyCollection properties)
|
||||
public Content(int parentId, IContentType contentType, PropertyCollection properties) : base(parentId, contentType, properties)
|
||||
{
|
||||
_parentId = parentId;
|
||||
_contentTypeId = int.Parse(contentType.Id.ToString(CultureInfo.InvariantCulture));
|
||||
_contentType = contentType;
|
||||
_properties = properties;
|
||||
_properties.EnsurePropertyTypes(PropertyTypes);
|
||||
Version = Guid.NewGuid();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<Content, string>(x => x.Name);
|
||||
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<Content, int>(x => x.ParentId);
|
||||
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<Content, int>(x => x.SortOrder);
|
||||
private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo<Content, int>(x => x.Level);
|
||||
private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo<Content, string>(x => x.Path);
|
||||
|
||||
private static readonly PropertyInfo TemplateSelector = ExpressionHelper.GetPropertyInfo<Content, string>(x => x.Template);
|
||||
private static readonly PropertyInfo UserIdSelector = ExpressionHelper.GetPropertyInfo<Content, int>(x => x.UserId);
|
||||
private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo<Content, bool>(x => x.Trashed);
|
||||
private static readonly PropertyInfo PublishedSelector = ExpressionHelper.GetPropertyInfo<Content, bool>(x => x.Published);
|
||||
private static readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo<Content, string>(x => x.Language);
|
||||
private static readonly PropertyInfo DefaultContentTypeIdSelector = ExpressionHelper.GetPropertyInfo<Content, int>(x => x.ContentTypeId);
|
||||
private static readonly PropertyInfo ReleaseDateSelector = ExpressionHelper.GetPropertyInfo<Content, DateTime?>(x => x.ReleaseDate);
|
||||
private static readonly PropertyInfo ExpireDateSelector = ExpressionHelper.GetPropertyInfo<Content, DateTime?>(x => x.ExpireDate);
|
||||
private readonly static PropertyInfo PropertyCollectionSelector = ExpressionHelper.GetPropertyInfo<Content, PropertyCollection>(x => x.Properties);
|
||||
void PropertiesChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(PropertyCollectionSelector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Id of the Parent entity
|
||||
/// </summary>
|
||||
/// <remarks>Might not be necessary if handled as a relation?</remarks>
|
||||
[DataMember]
|
||||
public int ParentId
|
||||
{
|
||||
get { return _parentId; }
|
||||
set
|
||||
{
|
||||
_parentId = value;
|
||||
OnPropertyChanged(ParentIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the current entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public string UrlName
|
||||
{
|
||||
//TODO Needs to implement proper url casing/syntax
|
||||
get { return Name.ToLower().Replace(" ", "-"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sort order of the content entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int SortOrder
|
||||
{
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the level of the content entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int Level
|
||||
{
|
||||
get { return _level; }
|
||||
set
|
||||
{
|
||||
_level = value;
|
||||
OnPropertyChanged(LevelSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Path //Setting this value should be handled by the class not the user
|
||||
{
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
_path = value;
|
||||
OnPropertyChanged(PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path to the template used by this Content
|
||||
@@ -176,20 +66,6 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Id of the user who created this Content
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int UserId
|
||||
{
|
||||
get { return _userId; }
|
||||
set
|
||||
{
|
||||
_userId = value;
|
||||
OnPropertyChanged(UserIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current status of the Content
|
||||
/// </summary>
|
||||
@@ -213,22 +89,6 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether this Content is Trashed or not.
|
||||
/// If Content is Trashed it will be located in the Recyclebin.
|
||||
/// </summary>
|
||||
/// <remarks>When content is trashed it should be unpublished</remarks>
|
||||
[DataMember]
|
||||
public bool Trashed //Setting this value should be handled by the class not the user
|
||||
{
|
||||
get { return _trashed; }
|
||||
internal set
|
||||
{
|
||||
_trashed = value;
|
||||
OnPropertyChanged(TrashedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether this Content is Published or not
|
||||
/// </summary>
|
||||
@@ -258,52 +118,6 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Guid Id of the curent Version
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public Guid Version { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Integer Id of the default ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int ContentTypeId
|
||||
{
|
||||
get { return _contentTypeId; }
|
||||
protected set
|
||||
{
|
||||
_contentTypeId = value;
|
||||
OnPropertyChanged(DefaultContentTypeIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collection of properties, which make up all the data available for this Content object
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public PropertyCollection Properties
|
||||
{
|
||||
get { return _properties; }
|
||||
set
|
||||
{
|
||||
_properties = value;
|
||||
_properties.CollectionChanged += PropertiesChanged;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of PropertyGroups available on this Content object
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyGroup> PropertyGroups { get { return _contentType.CompositionPropertyGroups; } }
|
||||
|
||||
/// <summary>
|
||||
/// List of PropertyTypes available on this Content object
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyType> PropertyTypes { get { return _contentType.CompositionPropertyTypes; } }
|
||||
|
||||
/// <summary>
|
||||
/// The date this Content should be released and thus be published
|
||||
/// </summary>
|
||||
@@ -359,8 +173,9 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
ContentTypeId = contentType.Id;
|
||||
_contentType = contentType;
|
||||
_properties.EnsurePropertyTypes(PropertyTypes);
|
||||
_properties.CollectionChanged += PropertiesChanged;
|
||||
ContentTypeBase = contentType;
|
||||
Properties.EnsurePropertyTypes(PropertyTypes);
|
||||
Properties.CollectionChanged += PropertiesChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -375,66 +190,15 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
ContentTypeId = contentType.Id;
|
||||
_contentType = contentType;
|
||||
_properties.EnsureCleanPropertyTypes(PropertyTypes);
|
||||
_properties.CollectionChanged += PropertiesChanged;
|
||||
ContentTypeBase = contentType;
|
||||
Properties.EnsureCleanPropertyTypes(PropertyTypes);
|
||||
Properties.CollectionChanged += PropertiesChanged;
|
||||
return;
|
||||
}
|
||||
|
||||
ChangeContentType(contentType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the content object has a property with the supplied alias
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns>True if Property with given alias exists, otherwise False</returns>
|
||||
public bool HasProperty(string propertyTypeAlias)
|
||||
{
|
||||
return Properties.Contains(propertyTypeAlias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns><see cref="Property"/> Value as an <see cref="object"/></returns>
|
||||
public object GetValue(string propertyTypeAlias)
|
||||
{
|
||||
return Properties[propertyTypeAlias].Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a Property
|
||||
/// </summary>
|
||||
/// <typeparam name="TPassType">Type of the value to return</typeparam>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns><see cref="Property"/> Value as a <see cref="TPassType"/></returns>
|
||||
public TPassType GetValue<TPassType>(string propertyTypeAlias)
|
||||
{
|
||||
return (TPassType)Properties[propertyTypeAlias].Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public void SetValue(string propertyTypeAlias, object value)
|
||||
{
|
||||
if (Properties.Contains(propertyTypeAlias))
|
||||
{
|
||||
Properties[propertyTypeAlias].Value = value;
|
||||
return;
|
||||
}
|
||||
|
||||
var propertyType = PropertyTypes.FirstOrDefault(x => x.Alias == propertyTypeAlias);
|
||||
if(propertyType == null)
|
||||
{
|
||||
throw new Exception(string.Format("No PropertyType exists with the supplied alias: {0}", propertyTypeAlias));
|
||||
}
|
||||
Properties.Add(propertyType.CreatePropertyFromValue(value));
|
||||
}
|
||||
|
||||
//TODO Possibly add a ToXml method, which will generate valid xml for the current Content object
|
||||
|
||||
/// <summary>
|
||||
|
||||
262
src/Umbraco.Core/Models/ContentBase.cs
Normal file
262
src/Umbraco.Core/Models/ContentBase.cs
Normal file
@@ -0,0 +1,262 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an abstract class for base Content properties and methods
|
||||
/// </summary>
|
||||
public abstract class ContentBase : Entity, IContentBase
|
||||
{
|
||||
protected IContentTypeComposition ContentTypeBase;
|
||||
private int _parentId;
|
||||
private string _name;
|
||||
private int _sortOrder;
|
||||
private int _level;
|
||||
private string _path;
|
||||
private int _userId;
|
||||
private bool _trashed;
|
||||
private int _contentTypeId;
|
||||
private PropertyCollection _properties;
|
||||
|
||||
protected ContentBase(int parentId, IContentTypeComposition contentType, PropertyCollection properties)
|
||||
{
|
||||
_parentId = parentId;
|
||||
_contentTypeId = int.Parse(contentType.Id.ToString(CultureInfo.InvariantCulture));
|
||||
ContentTypeBase = contentType;
|
||||
_properties = properties;
|
||||
_properties.EnsurePropertyTypes(PropertyTypes);
|
||||
Version = Guid.NewGuid();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<ContentBase, string>(x => x.Name);
|
||||
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<ContentBase, int>(x => x.ParentId);
|
||||
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<ContentBase, int>(x => x.SortOrder);
|
||||
private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo<ContentBase, int>(x => x.Level);
|
||||
private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo<ContentBase, string>(x => x.Path);
|
||||
private static readonly PropertyInfo UserIdSelector = ExpressionHelper.GetPropertyInfo<ContentBase, int>(x => x.UserId);
|
||||
private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo<ContentBase, bool>(x => x.Trashed);
|
||||
private static readonly PropertyInfo DefaultContentTypeIdSelector = ExpressionHelper.GetPropertyInfo<ContentBase, int>(x => x.ContentTypeId);
|
||||
private readonly static PropertyInfo PropertyCollectionSelector = ExpressionHelper.GetPropertyInfo<ContentBase, PropertyCollection>(x => x.Properties);
|
||||
|
||||
protected void PropertiesChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(PropertyCollectionSelector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Id of the Parent entity
|
||||
/// </summary>
|
||||
/// <remarks>Might not be necessary if handled as a relation?</remarks>
|
||||
[DataMember]
|
||||
public virtual int ParentId
|
||||
{
|
||||
get { return _parentId; }
|
||||
set
|
||||
{
|
||||
_parentId = value;
|
||||
OnPropertyChanged(ParentIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public virtual string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Url name of the entity
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public virtual string UrlName
|
||||
{
|
||||
//TODO Needs to implement proper url casing/syntax
|
||||
get { return Name.ToLower().Replace(" ", "-"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sort order of the content entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public virtual int SortOrder
|
||||
{
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the level of the content entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public virtual int Level
|
||||
{
|
||||
get { return _level; }
|
||||
set
|
||||
{
|
||||
_level = value;
|
||||
OnPropertyChanged(LevelSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public virtual string Path //Setting this value should be handled by the class not the user
|
||||
{
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
_path = value;
|
||||
OnPropertyChanged(PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Id of the user who created this Content
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public virtual int UserId
|
||||
{
|
||||
get { return _userId; }
|
||||
set
|
||||
{
|
||||
_userId = value;
|
||||
OnPropertyChanged(UserIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether this Content is Trashed or not.
|
||||
/// If Content is Trashed it will be located in the Recyclebin.
|
||||
/// </summary>
|
||||
/// <remarks>When content is trashed it should be unpublished</remarks>
|
||||
[DataMember]
|
||||
public virtual bool Trashed //Setting this value should be handled by the class not the user
|
||||
{
|
||||
get { return _trashed; }
|
||||
internal set
|
||||
{
|
||||
_trashed = value;
|
||||
OnPropertyChanged(TrashedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Guid Id of the curent Version
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public Guid Version { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Integer Id of the default ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public virtual int ContentTypeId
|
||||
{
|
||||
get { return _contentTypeId; }
|
||||
protected set
|
||||
{
|
||||
_contentTypeId = value;
|
||||
OnPropertyChanged(DefaultContentTypeIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collection of properties, which make up all the data available for this Content object
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public virtual PropertyCollection Properties
|
||||
{
|
||||
get { return _properties; }
|
||||
set
|
||||
{
|
||||
_properties = value;
|
||||
_properties.CollectionChanged += PropertiesChanged;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of PropertyGroups available on this Content object
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyGroup> PropertyGroups { get { return ContentTypeBase.CompositionPropertyGroups; } }
|
||||
|
||||
/// <summary>
|
||||
/// List of PropertyTypes available on this Content object
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyType> PropertyTypes { get { return ContentTypeBase.CompositionPropertyTypes; } }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the content object has a property with the supplied alias
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns>True if Property with given alias exists, otherwise False</returns>
|
||||
public virtual bool HasProperty(string propertyTypeAlias)
|
||||
{
|
||||
return Properties.Contains(propertyTypeAlias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns><see cref="Property"/> Value as an <see cref="object"/></returns>
|
||||
public virtual object GetValue(string propertyTypeAlias)
|
||||
{
|
||||
return Properties[propertyTypeAlias].Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a Property
|
||||
/// </summary>
|
||||
/// <typeparam name="TPassType">Type of the value to return</typeparam>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns><see cref="Property"/> Value as a <see cref="TPassType"/></returns>
|
||||
public virtual TPassType GetValue<TPassType>(string propertyTypeAlias)
|
||||
{
|
||||
return (TPassType)Properties[propertyTypeAlias].Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public virtual void SetValue(string propertyTypeAlias, object value)
|
||||
{
|
||||
if (Properties.Contains(propertyTypeAlias))
|
||||
{
|
||||
Properties[propertyTypeAlias].Value = value;
|
||||
return;
|
||||
}
|
||||
|
||||
var propertyType = PropertyTypes.FirstOrDefault(x => x.Alias == propertyTypeAlias);
|
||||
if (propertyType == null)
|
||||
{
|
||||
throw new Exception(String.Format("No PropertyType exists with the supplied alias: {0}", propertyTypeAlias));
|
||||
}
|
||||
Properties.Add(propertyType.CreatePropertyFromValue(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -13,182 +10,19 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class ContentType : Entity, IContentType
|
||||
public class ContentType : ContentTypeCompositionBase, IContentType
|
||||
{
|
||||
private int _parentId;
|
||||
private string _name;
|
||||
private int _level;
|
||||
private string _path;
|
||||
private string _alias;
|
||||
private string _description;
|
||||
private int _sortOrder;
|
||||
private string _icon;
|
||||
private string _thumbnail;
|
||||
private string _defaultTemplate;
|
||||
private int _userId;
|
||||
private bool _trashed;
|
||||
private PropertyGroupCollection _propertyGroups;
|
||||
private List<IContentTypeComposition> _contentTypeComposition;
|
||||
private IEnumerable<string> _allowedTemplates;
|
||||
private IEnumerable<ContentTypeSort> _allowedContentTypes;
|
||||
|
||||
public ContentType(int parentId)
|
||||
public ContentType(int parentId) : base(parentId)
|
||||
{
|
||||
_parentId = parentId;
|
||||
_allowedTemplates = new List<string>();
|
||||
_allowedContentTypes = new List<ContentTypeSort>();
|
||||
_propertyGroups = new PropertyGroupCollection();
|
||||
_contentTypeComposition = new List<IContentTypeComposition>();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<ContentType, string>(x => x.Name);
|
||||
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<ContentType, int>(x => x.ParentId);
|
||||
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<ContentType, int>(x => x.SortOrder);
|
||||
private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo<ContentType, int>(x => x.Level);
|
||||
private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo<ContentType, string>(x => x.Path);
|
||||
private static readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<ContentType, string>(x => x.Alias);
|
||||
private static readonly PropertyInfo DescriptionSelector = ExpressionHelper.GetPropertyInfo<ContentType, string>(x => x.Description);
|
||||
private static readonly PropertyInfo IconSelector = ExpressionHelper.GetPropertyInfo<ContentType, string>(x => x.Icon);
|
||||
private static readonly PropertyInfo ThumbnailSelector = ExpressionHelper.GetPropertyInfo<ContentType, string>(x => x.Thumbnail);
|
||||
private static readonly PropertyInfo DefaultTemplateSelector = ExpressionHelper.GetPropertyInfo<ContentType, string>(x => x.DefaultTemplate);
|
||||
private static readonly PropertyInfo UserIdSelector = ExpressionHelper.GetPropertyInfo<ContentType, int>(x => x.UserId);
|
||||
private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo<ContentType, bool>(x => x.Trashed);
|
||||
private static readonly PropertyInfo AllowedTemplatesSelector = ExpressionHelper.GetPropertyInfo<ContentType, IEnumerable<string>>(x => x.AllowedTemplates);
|
||||
private static readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo<ContentType, IEnumerable<ContentTypeSort>>(x => x.AllowedContentTypes);
|
||||
private static readonly PropertyInfo ContentTypeCompositionSelector = ExpressionHelper.GetPropertyInfo<ContentType, List<IContentTypeComposition>>(x => x.ContentTypeComposition);
|
||||
private readonly static PropertyInfo PropertyGroupCollectionSelector = ExpressionHelper.GetPropertyInfo<ContentType, PropertyGroupCollection>(x => x.PropertyGroups);
|
||||
void PropertyGroupsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(PropertyGroupCollectionSelector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Id of the Parent entity
|
||||
/// </summary>
|
||||
/// <remarks>Might not be necessary if handled as a relation?</remarks>
|
||||
[DataMember]
|
||||
public int ParentId
|
||||
{
|
||||
get { return _parentId; }
|
||||
set
|
||||
{
|
||||
_parentId = value;
|
||||
OnPropertyChanged(ParentIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the current entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the level of the content entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int Level //NOTE Is this relevant for a ContentType?
|
||||
{
|
||||
get { return _level; }
|
||||
set
|
||||
{
|
||||
_level = value;
|
||||
OnPropertyChanged(LevelSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets of sets the path
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Path //NOTE Is this relevant for a ContentType?
|
||||
{
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
_path = value;
|
||||
OnPropertyChanged(PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Alias of the ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Alias
|
||||
{
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
_alias = value;
|
||||
OnPropertyChanged(AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Description for the ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Description
|
||||
{
|
||||
get { return _description; }
|
||||
set
|
||||
{
|
||||
_description = value;
|
||||
OnPropertyChanged(DescriptionSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sort order of the content entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int SortOrder
|
||||
{
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of the icon (sprite class) used to identify the ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Icon
|
||||
{
|
||||
get { return _icon; }
|
||||
set
|
||||
{
|
||||
_icon = value;
|
||||
OnPropertyChanged(IconSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of the thumbnail used to identify the ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Thumbnail
|
||||
{
|
||||
get { return _thumbnail; }
|
||||
set
|
||||
{
|
||||
_thumbnail = value;
|
||||
OnPropertyChanged(ThumbnailSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Path to default Template
|
||||
/// </summary>
|
||||
@@ -203,35 +37,6 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Id of the user who created this Content
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int UserId
|
||||
{
|
||||
get { return _userId; }
|
||||
set
|
||||
{
|
||||
_userId = value;
|
||||
OnPropertyChanged(UserIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether this ContentType is Trashed or not.
|
||||
/// If ContentType is Trashed it will be located in the Recyclebin.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool Trashed //NOTE Is this relevant for a ContentType?
|
||||
{
|
||||
get { return _trashed; }
|
||||
set
|
||||
{
|
||||
_trashed = value;
|
||||
OnPropertyChanged(TrashedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of aliases for allowed Templates
|
||||
/// </summary>
|
||||
@@ -245,148 +50,6 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of integer Ids for allowed ContentTypes
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public IEnumerable<ContentTypeSort> AllowedContentTypes
|
||||
{
|
||||
get { return _allowedContentTypes; }
|
||||
set
|
||||
{
|
||||
_allowedContentTypes = value;
|
||||
OnPropertyChanged(AllowedContentTypesSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of PropertyGroups available on this ContentType
|
||||
/// </summary>
|
||||
/// <remarks>A PropertyGroup corresponds to a Tab in the UI</remarks>
|
||||
[DataMember]
|
||||
public PropertyGroupCollection PropertyGroups
|
||||
{
|
||||
get { return _propertyGroups; }
|
||||
set
|
||||
{
|
||||
_propertyGroups = value;
|
||||
_propertyGroups.CollectionChanged += PropertyGroupsChanged;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of PropertyTypes available on this ContentType.
|
||||
/// This list aggregates PropertyTypes across the PropertyGroups.
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyType> PropertyTypes
|
||||
{
|
||||
get { return PropertyGroups.SelectMany(x => x.PropertyTypes); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of ContentTypes that make up a composition of PropertyGroups and PropertyTypes for the current ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public List<IContentTypeComposition> ContentTypeComposition
|
||||
{
|
||||
get { return _contentTypeComposition; }
|
||||
set
|
||||
{
|
||||
_contentTypeComposition = value;
|
||||
OnPropertyChanged(ContentTypeCompositionSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of <see cref="PropertyGroup"/> objects from the composition
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyGroup> CompositionPropertyGroups
|
||||
{
|
||||
get
|
||||
{
|
||||
var groups = PropertyGroups.Union(ContentTypeComposition.SelectMany(x => x.CompositionPropertyGroups));
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of <see cref="PropertyType"/> objects from the composition
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyType> CompositionPropertyTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
var propertyTypes = PropertyTypes.Union(ContentTypeComposition.SelectMany(x => x.CompositionPropertyTypes));
|
||||
return propertyTypes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new ContentType to the list of composite ContentTypes
|
||||
/// </summary>
|
||||
/// <param name="contentType"><see cref="ContentType"/> to add</param>
|
||||
/// <returns>True if ContentType was added, otherwise returns False</returns>
|
||||
public bool AddContentType(IContentTypeComposition contentType)
|
||||
{
|
||||
if(contentType.ContentTypeComposition.Any(x => x.CompositionAliases().Any(ContentTypeCompositionExists)))
|
||||
return false;
|
||||
|
||||
if (!ContentTypeCompositionExists(contentType.Alias))
|
||||
{
|
||||
ContentTypeComposition.Add(contentType);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a ContentType with the supplied alias from the the list of composite ContentTypes
|
||||
/// </summary>
|
||||
/// <param name="alias">Alias of a <see cref="ContentType"/></param>
|
||||
/// <returns>True if ContentType was removed, otherwise returns False</returns>
|
||||
public bool RemoveContentType(string alias)
|
||||
{
|
||||
if (!ContentTypeCompositionExists(alias))
|
||||
{
|
||||
var contentTypeComposition = ContentTypeComposition.First(x => x.Alias == alias);
|
||||
return ContentTypeComposition.Remove(contentTypeComposition);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a ContentType with the supplied alias exists in the list of composite ContentTypes
|
||||
/// </summary>
|
||||
/// <param name="alias">Alias of a <see cref="ContentType"/></param>
|
||||
/// <returns>True if ContentType with alias exists, otherwise returns False</returns>
|
||||
public bool ContentTypeCompositionExists(string alias)
|
||||
{
|
||||
if (ContentTypeComposition.Any(x => x.Alias.Equals(alias)))
|
||||
return true;
|
||||
|
||||
if (ContentTypeComposition.Any(x => x.ContentTypeCompositionExists(alias)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of ContentType aliases from the current composition
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>Does not contain the alias of the Current ContentType</remarks>
|
||||
public IEnumerable<string> CompositionAliases()
|
||||
{
|
||||
return ContentTypeComposition.Select(x => x.Alias).Union(ContentTypeComposition.SelectMany(x => x.CompositionAliases()));
|
||||
}
|
||||
|
||||
//TODO Implement moving PropertyType between groups.
|
||||
/*public bool MovePropertyTypeToGroup(string propertyTypeAlias, string groupName)
|
||||
{}*/
|
||||
|
||||
/// <summary>
|
||||
/// Method to call when Entity is being saved
|
||||
/// </summary>
|
||||
|
||||
254
src/Umbraco.Core/Models/ContentTypeBase.cs
Normal file
254
src/Umbraco.Core/Models/ContentTypeBase.cs
Normal file
@@ -0,0 +1,254 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an abstract class for base ContentType properties and methods
|
||||
/// </summary>
|
||||
public abstract class ContentTypeBase : Entity, IContentTypeBase
|
||||
{
|
||||
private int _parentId;
|
||||
private string _name;
|
||||
private int _level;
|
||||
private string _path;
|
||||
private string _alias;
|
||||
private string _description;
|
||||
private int _sortOrder;
|
||||
private string _icon;
|
||||
private string _thumbnail;
|
||||
private int _userId;
|
||||
private bool _trashed;
|
||||
private PropertyGroupCollection _propertyGroups;
|
||||
private IEnumerable<ContentTypeSort> _allowedContentTypes;
|
||||
|
||||
protected ContentTypeBase(int parentId)
|
||||
{
|
||||
_parentId = parentId;
|
||||
_allowedContentTypes = new List<ContentTypeSort>();
|
||||
_propertyGroups = new PropertyGroupCollection();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, string>(x => x.Name);
|
||||
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, int>(x => x.ParentId);
|
||||
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, int>(x => x.SortOrder);
|
||||
private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, int>(x => x.Level);
|
||||
private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, string>(x => x.Path);
|
||||
private static readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, string>(x => x.Alias);
|
||||
private static readonly PropertyInfo DescriptionSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, string>(x => x.Description);
|
||||
private static readonly PropertyInfo IconSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, string>(x => x.Icon);
|
||||
private static readonly PropertyInfo ThumbnailSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, string>(x => x.Thumbnail);
|
||||
private static readonly PropertyInfo UserIdSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, int>(x => x.UserId);
|
||||
private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, bool>(x => x.Trashed);
|
||||
private static readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, IEnumerable<ContentTypeSort>>(x => x.AllowedContentTypes);
|
||||
private readonly static PropertyInfo PropertyGroupCollectionSelector = ExpressionHelper.GetPropertyInfo<ContentType, PropertyGroupCollection>(x => x.PropertyGroups);
|
||||
|
||||
protected void PropertyGroupsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(PropertyGroupCollectionSelector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Id of the Parent entity
|
||||
/// </summary>
|
||||
/// <remarks>Might not be necessary if handled as a relation?</remarks>
|
||||
[DataMember]
|
||||
public int ParentId
|
||||
{
|
||||
get { return _parentId; }
|
||||
set
|
||||
{
|
||||
_parentId = value;
|
||||
OnPropertyChanged(ParentIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the current entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the level of the content entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int Level //NOTE Is this relevant for a ContentType?
|
||||
{
|
||||
get { return _level; }
|
||||
set
|
||||
{
|
||||
_level = value;
|
||||
OnPropertyChanged(LevelSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets of sets the path
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Path //NOTE Is this relevant for a ContentType?
|
||||
{
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
_path = value;
|
||||
OnPropertyChanged(PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Alias of the ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Alias
|
||||
{
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
_alias = value;
|
||||
OnPropertyChanged(AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Description for the ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Description
|
||||
{
|
||||
get { return _description; }
|
||||
set
|
||||
{
|
||||
_description = value;
|
||||
OnPropertyChanged(DescriptionSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sort order of the content entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int SortOrder
|
||||
{
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of the icon (sprite class) used to identify the ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Icon
|
||||
{
|
||||
get { return _icon; }
|
||||
set
|
||||
{
|
||||
_icon = value;
|
||||
OnPropertyChanged(IconSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of the thumbnail used to identify the ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Thumbnail
|
||||
{
|
||||
get { return _thumbnail; }
|
||||
set
|
||||
{
|
||||
_thumbnail = value;
|
||||
OnPropertyChanged(ThumbnailSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Id of the user who created this Content
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int UserId
|
||||
{
|
||||
get { return _userId; }
|
||||
set
|
||||
{
|
||||
_userId = value;
|
||||
OnPropertyChanged(UserIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether this ContentType is Trashed or not.
|
||||
/// If ContentType is Trashed it will be located in the Recyclebin.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool Trashed //NOTE Is this relevant for a ContentType?
|
||||
{
|
||||
get { return _trashed; }
|
||||
set
|
||||
{
|
||||
_trashed = value;
|
||||
OnPropertyChanged(TrashedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of integer Ids for allowed ContentTypes
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public IEnumerable<ContentTypeSort> AllowedContentTypes
|
||||
{
|
||||
get { return _allowedContentTypes; }
|
||||
set
|
||||
{
|
||||
_allowedContentTypes = value;
|
||||
OnPropertyChanged(AllowedContentTypesSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of PropertyGroups available on this ContentType
|
||||
/// </summary>
|
||||
/// <remarks>A PropertyGroup corresponds to a Tab in the UI</remarks>
|
||||
[DataMember]
|
||||
public PropertyGroupCollection PropertyGroups
|
||||
{
|
||||
get { return _propertyGroups; }
|
||||
set
|
||||
{
|
||||
_propertyGroups = value;
|
||||
_propertyGroups.CollectionChanged += PropertyGroupsChanged;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of PropertyTypes available on this ContentType.
|
||||
/// This list aggregates PropertyTypes across the PropertyGroups.
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyType> PropertyTypes
|
||||
{
|
||||
get { return PropertyGroups.SelectMany(x => x.PropertyTypes); }
|
||||
}
|
||||
|
||||
//TODO Implement moving PropertyType between groups.
|
||||
/*public bool MovePropertyTypeToGroup(string propertyTypeAlias, string groupName)
|
||||
{}*/
|
||||
}
|
||||
}
|
||||
118
src/Umbraco.Core/Models/ContentTypeCompositionBase.cs
Normal file
118
src/Umbraco.Core/Models/ContentTypeCompositionBase.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public abstract class ContentTypeCompositionBase : ContentTypeBase, IContentTypeComposition
|
||||
{
|
||||
private List<IContentTypeComposition> _contentTypeComposition;
|
||||
|
||||
protected ContentTypeCompositionBase(int parentId) : base(parentId)
|
||||
{
|
||||
_contentTypeComposition = new List<IContentTypeComposition>();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo ContentTypeCompositionSelector = ExpressionHelper.GetPropertyInfo<ContentType, List<IContentTypeComposition>>(x => x.ContentTypeComposition);
|
||||
|
||||
/// <summary>
|
||||
/// List of ContentTypes that make up a composition of PropertyGroups and PropertyTypes for the current ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public List<IContentTypeComposition> ContentTypeComposition
|
||||
{
|
||||
get { return _contentTypeComposition; }
|
||||
set
|
||||
{
|
||||
_contentTypeComposition = value;
|
||||
OnPropertyChanged(ContentTypeCompositionSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of <see cref="PropertyGroup"/> objects from the composition
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyGroup> CompositionPropertyGroups
|
||||
{
|
||||
get
|
||||
{
|
||||
var groups = PropertyGroups.Union(ContentTypeComposition.SelectMany(x => x.CompositionPropertyGroups));
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of <see cref="PropertyType"/> objects from the composition
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyType> CompositionPropertyTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
var propertyTypes = PropertyTypes.Union(ContentTypeComposition.SelectMany(x => x.CompositionPropertyTypes));
|
||||
return propertyTypes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new ContentType to the list of composite ContentTypes
|
||||
/// </summary>
|
||||
/// <param name="contentType"><see cref="ContentType"/> to add</param>
|
||||
/// <returns>True if ContentType was added, otherwise returns False</returns>
|
||||
public bool AddContentType(IContentTypeComposition contentType)
|
||||
{
|
||||
if (contentType.ContentTypeComposition.Any(x => x.CompositionAliases().Any(ContentTypeCompositionExists)))
|
||||
return false;
|
||||
|
||||
if (!ContentTypeCompositionExists(contentType.Alias))
|
||||
{
|
||||
ContentTypeComposition.Add(contentType);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a ContentType with the supplied alias from the the list of composite ContentTypes
|
||||
/// </summary>
|
||||
/// <param name="alias">Alias of a <see cref="ContentType"/></param>
|
||||
/// <returns>True if ContentType was removed, otherwise returns False</returns>
|
||||
public bool RemoveContentType(string alias)
|
||||
{
|
||||
if (!ContentTypeCompositionExists(alias))
|
||||
{
|
||||
var contentTypeComposition = ContentTypeComposition.First(x => x.Alias == alias);
|
||||
return ContentTypeComposition.Remove(contentTypeComposition);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a ContentType with the supplied alias exists in the list of composite ContentTypes
|
||||
/// </summary>
|
||||
/// <param name="alias">Alias of a <see cref="ContentType"/></param>
|
||||
/// <returns>True if ContentType with alias exists, otherwise returns False</returns>
|
||||
public bool ContentTypeCompositionExists(string alias)
|
||||
{
|
||||
if (ContentTypeComposition.Any(x => x.Alias.Equals(alias)))
|
||||
return true;
|
||||
|
||||
if (ContentTypeComposition.Any(x => x.ContentTypeCompositionExists(alias)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of ContentType aliases from the current composition
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>Does not contain the alias of the Current ContentType</remarks>
|
||||
public IEnumerable<string> CompositionAliases()
|
||||
{
|
||||
return ContentTypeComposition.Select(x => x.Alias).Union(ContentTypeComposition.SelectMany(x => x.CompositionAliases()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,11 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
DateTime? ExpireDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ContentType used by this content object
|
||||
/// </summary>
|
||||
IContentType ContentType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Changes the <see cref="IContentType"/> for the current content object
|
||||
/// </summary>
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
{
|
||||
public interface IMedia : IContentBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the ContentType used by this Media object
|
||||
/// </summary>
|
||||
IMediaType ContentType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Changes the <see cref="IMediaType"/> for the current content object
|
||||
/// </summary>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/// <summary>
|
||||
/// Defines a ContentType, which Media is based on
|
||||
/// </summary>
|
||||
public interface IMediaType : IContentTypeBase
|
||||
public interface IMediaType : IContentTypeComposition
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -15,17 +8,8 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class Media : Entity, IMedia
|
||||
public class Media : ContentBase, IMedia
|
||||
{
|
||||
private int _parentId;
|
||||
private string _name;
|
||||
private int _sortOrder;
|
||||
private int _level;
|
||||
private string _path;
|
||||
private int _userId;
|
||||
private bool _trashed;
|
||||
private int _contentTypeId;
|
||||
private PropertyCollection _properties;
|
||||
private IMediaType _contentType;
|
||||
|
||||
/// <summary>
|
||||
@@ -44,193 +28,9 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="parentId"> </param>
|
||||
/// <param name="contentType">MediaType for the current Media object</param>
|
||||
/// <param name="properties">Collection of properties</param>
|
||||
public Media(int parentId, IMediaType contentType, PropertyCollection properties)
|
||||
public Media(int parentId, IMediaType contentType, PropertyCollection properties) : base(parentId, contentType, properties)
|
||||
{
|
||||
_parentId = parentId;
|
||||
_contentTypeId = int.Parse(contentType.Id.ToString(CultureInfo.InvariantCulture));
|
||||
_contentType = contentType;
|
||||
_properties = properties;
|
||||
_properties.EnsurePropertyTypes(PropertyTypes);
|
||||
Version = Guid.NewGuid();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<Media, string>(x => x.Name);
|
||||
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<Media, int>(x => x.ParentId);
|
||||
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<Media, int>(x => x.SortOrder);
|
||||
private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo<Media, int>(x => x.Level);
|
||||
private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo<Media, string>(x => x.Path);
|
||||
private static readonly PropertyInfo UserIdSelector = ExpressionHelper.GetPropertyInfo<Media, int>(x => x.UserId);
|
||||
private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo<Media, bool>(x => x.Trashed);
|
||||
private static readonly PropertyInfo DefaultContentTypeIdSelector = ExpressionHelper.GetPropertyInfo<Media, int>(x => x.ContentTypeId);
|
||||
private readonly static PropertyInfo PropertyCollectionSelector = ExpressionHelper.GetPropertyInfo<Media, PropertyCollection>(x => x.Properties);
|
||||
void PropertiesChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(PropertyCollectionSelector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the Id of the Parent for the Media
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int ParentId
|
||||
{
|
||||
get { return _parentId; }
|
||||
set
|
||||
{
|
||||
_parentId = value;
|
||||
OnPropertyChanged(ParentIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the Name of the Media
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Url name of the Media item
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public string UrlName
|
||||
{
|
||||
//TODO: Should return the relative path to the media - if it should be implemented at all
|
||||
get
|
||||
{
|
||||
string url = string.Concat(SystemDirectories.Media.Replace("~", ""), "/", _name);
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the Sort Order of the Media
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int SortOrder
|
||||
{
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the Level of the Media
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int Level
|
||||
{
|
||||
get { return _level; }
|
||||
set
|
||||
{
|
||||
_level = value;
|
||||
OnPropertyChanged(LevelSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the Path of the Media
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Path
|
||||
{
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
_path = value;
|
||||
OnPropertyChanged(PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Id of the user who created the Media
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int UserId
|
||||
{
|
||||
get { return _userId; }
|
||||
set
|
||||
{
|
||||
_userId = value;
|
||||
OnPropertyChanged(UserIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether this Media is Trashed or not.
|
||||
/// If Media is Trashed it will be located in the Recyclebin.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool Trashed
|
||||
{
|
||||
get { return _trashed; }
|
||||
internal set
|
||||
{
|
||||
_trashed = value;
|
||||
OnPropertyChanged(TrashedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Integer Id of the default MediaType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int ContentTypeId
|
||||
{
|
||||
get { return _contentTypeId; }
|
||||
protected set
|
||||
{
|
||||
_contentTypeId = value;
|
||||
OnPropertyChanged(DefaultContentTypeIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Guid Id of the curent Version
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public Guid Version { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of properties, which make up all the data available for this Media object
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public PropertyCollection Properties
|
||||
{
|
||||
get { return _properties; }
|
||||
set
|
||||
{
|
||||
_properties = value;
|
||||
_properties.CollectionChanged += PropertiesChanged;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of PropertyGroups available on this Media object
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyGroup> PropertyGroups
|
||||
{
|
||||
get { return _contentType.PropertyGroups; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of PropertyTypes available on this Media object
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyType> PropertyTypes
|
||||
{
|
||||
get { return _contentType.PropertyTypes; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -242,58 +42,6 @@ namespace Umbraco.Core.Models
|
||||
get { return _contentType; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the Media object has a property with the supplied alias
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns>True if Property with given alias exists, otherwise False</returns>
|
||||
public bool HasProperty(string propertyTypeAlias)
|
||||
{
|
||||
return Properties.Contains(propertyTypeAlias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns><see cref="Property"/> Value as an <see cref="object"/></returns>
|
||||
public object GetValue(string propertyTypeAlias)
|
||||
{
|
||||
return Properties[propertyTypeAlias].Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a Property
|
||||
/// </summary>
|
||||
/// <typeparam name="TPassType">Type of the value to return</typeparam>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns><see cref="Property"/> Value as a <see cref="TPassType"/></returns>
|
||||
public TPassType GetValue<TPassType>(string propertyTypeAlias)
|
||||
{
|
||||
return (TPassType)Properties[propertyTypeAlias].Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public void SetValue(string propertyTypeAlias, object value)
|
||||
{
|
||||
if (Properties.Contains(propertyTypeAlias))
|
||||
{
|
||||
Properties[propertyTypeAlias].Value = value;
|
||||
return;
|
||||
}
|
||||
|
||||
var propertyType = PropertyTypes.FirstOrDefault(x => x.Alias == propertyTypeAlias);
|
||||
if (propertyType == null)
|
||||
{
|
||||
throw new Exception(string.Format("No PropertyType exists with the supplied alias: {0}", propertyTypeAlias));
|
||||
}
|
||||
Properties.Add(propertyType.CreatePropertyFromValue(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the <see cref="IMediaType"/> for the current Media object
|
||||
/// </summary>
|
||||
@@ -303,8 +51,9 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
ContentTypeId = contentType.Id;
|
||||
_contentType = contentType;
|
||||
_properties.EnsurePropertyTypes(PropertyTypes);
|
||||
_properties.CollectionChanged += PropertiesChanged;
|
||||
ContentTypeBase = contentType;
|
||||
Properties.EnsurePropertyTypes(PropertyTypes);
|
||||
Properties.CollectionChanged += PropertiesChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -319,8 +68,9 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
ContentTypeId = contentType.Id;
|
||||
_contentType = contentType;
|
||||
_properties.EnsureCleanPropertyTypes(PropertyTypes);
|
||||
_properties.CollectionChanged += PropertiesChanged;
|
||||
ContentTypeBase = contentType;
|
||||
Properties.EnsureCleanPropertyTypes(PropertyTypes);
|
||||
Properties.CollectionChanged += PropertiesChanged;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -13,240 +8,10 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class MediaType : Entity, IMediaType
|
||||
public class MediaType : ContentTypeCompositionBase, IMediaType
|
||||
{
|
||||
private int _parentId;
|
||||
private string _name;
|
||||
private int _level;
|
||||
private string _path;
|
||||
private string _alias;
|
||||
private string _description;
|
||||
private int _sortOrder;
|
||||
private string _icon;
|
||||
private string _thumbnail;
|
||||
private int _userId;
|
||||
private bool _trashed;
|
||||
private PropertyGroupCollection _propertyGroups;
|
||||
private IEnumerable<ContentTypeSort> _allowedContentTypes;
|
||||
|
||||
public MediaType(int parentId)
|
||||
public MediaType(int parentId) : base(parentId)
|
||||
{
|
||||
_parentId = parentId;
|
||||
_allowedContentTypes = new List<ContentTypeSort>();
|
||||
_propertyGroups = new PropertyGroupCollection();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<MediaType, string>(x => x.Name);
|
||||
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<MediaType, int>(x => x.ParentId);
|
||||
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<MediaType, int>(x => x.SortOrder);
|
||||
private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo<MediaType, int>(x => x.Level);
|
||||
private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo<MediaType, string>(x => x.Path);
|
||||
private static readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<MediaType, string>(x => x.Alias);
|
||||
private static readonly PropertyInfo DescriptionSelector = ExpressionHelper.GetPropertyInfo<MediaType, string>(x => x.Description);
|
||||
private static readonly PropertyInfo IconSelector = ExpressionHelper.GetPropertyInfo<MediaType, string>(x => x.Icon);
|
||||
private static readonly PropertyInfo ThumbnailSelector = ExpressionHelper.GetPropertyInfo<MediaType, string>(x => x.Thumbnail);
|
||||
private static readonly PropertyInfo UserIdSelector = ExpressionHelper.GetPropertyInfo<MediaType, int>(x => x.UserId);
|
||||
private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo<MediaType, bool>(x => x.Trashed);
|
||||
private static readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo<MediaType, IEnumerable<ContentTypeSort>>(x => x.AllowedContentTypes);
|
||||
private readonly static PropertyInfo PropertyGroupCollectionSelector = ExpressionHelper.GetPropertyInfo<MediaType, PropertyGroupCollection>(x => x.PropertyGroups);
|
||||
void PropertyGroupsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(PropertyGroupCollectionSelector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Id of the Parent entity
|
||||
/// </summary>
|
||||
/// <remarks>Might not be necessary if handled as a relation?</remarks>
|
||||
[DataMember]
|
||||
public int ParentId
|
||||
{
|
||||
get { return _parentId; }
|
||||
set
|
||||
{
|
||||
_parentId = value;
|
||||
OnPropertyChanged(ParentIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the current entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the level of the content entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int Level //NOTE Is this relevant for a ContentType?
|
||||
{
|
||||
get { return _level; }
|
||||
set
|
||||
{
|
||||
_level = value;
|
||||
OnPropertyChanged(LevelSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets of sets the path
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Path //NOTE Is this relevant for a ContentType?
|
||||
{
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
_path = value;
|
||||
OnPropertyChanged(PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Alias of the ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Alias
|
||||
{
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
_alias = value;
|
||||
OnPropertyChanged(AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Description for the ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Description
|
||||
{
|
||||
get { return _description; }
|
||||
set
|
||||
{
|
||||
_description = value;
|
||||
OnPropertyChanged(DescriptionSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sort order of the content entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int SortOrder
|
||||
{
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of the icon (sprite class) used to identify the ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Icon
|
||||
{
|
||||
get { return _icon; }
|
||||
set
|
||||
{
|
||||
_icon = value;
|
||||
OnPropertyChanged(IconSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of the thumbnail used to identify the ContentType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Thumbnail
|
||||
{
|
||||
get { return _thumbnail; }
|
||||
set
|
||||
{
|
||||
_thumbnail = value;
|
||||
OnPropertyChanged(ThumbnailSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Id of the user who created this Content
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int UserId
|
||||
{
|
||||
get { return _userId; }
|
||||
set
|
||||
{
|
||||
_userId = value;
|
||||
OnPropertyChanged(UserIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether this ContentType is Trashed or not.
|
||||
/// If ContentType is Trashed it will be located in the Recyclebin.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool Trashed //NOTE Is this relevant for a ContentType?
|
||||
{
|
||||
get { return _trashed; }
|
||||
set
|
||||
{
|
||||
_trashed = value;
|
||||
OnPropertyChanged(TrashedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of integer Ids for allowed ContentTypes
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public IEnumerable<ContentTypeSort> AllowedContentTypes
|
||||
{
|
||||
get { return _allowedContentTypes; }
|
||||
set
|
||||
{
|
||||
_allowedContentTypes = value;
|
||||
OnPropertyChanged(AllowedContentTypesSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of PropertyGroups available on this ContentType
|
||||
/// </summary>
|
||||
/// <remarks>A PropertyGroup corresponds to a Tab in the UI</remarks>
|
||||
[DataMember]
|
||||
public PropertyGroupCollection PropertyGroups
|
||||
{
|
||||
get { return _propertyGroups; }
|
||||
set
|
||||
{
|
||||
_propertyGroups = value;
|
||||
_propertyGroups.CollectionChanged += PropertyGroupsChanged;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of PropertyTypes available on this ContentType.
|
||||
/// This list aggregates PropertyTypes across the PropertyGroups.
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public IEnumerable<PropertyType> PropertyTypes
|
||||
{
|
||||
get { return PropertyGroups.SelectMany(x => x.PropertyTypes); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence.Caching;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Relators;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// Represent an abstract Repository for ContentType based repositories
|
||||
/// </summary>
|
||||
/// <remarks>Exposes shared functionality</remarks>
|
||||
/// <typeparam name="TId"></typeparam>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
internal abstract class ContentTypeBaseRepository<TId, TEntity> : PetaPocoRepositoryBase<TId, TEntity>
|
||||
where TEntity : IContentTypeComposition
|
||||
{
|
||||
protected ContentTypeBaseRepository(IUnitOfWork work) : base(work)
|
||||
{
|
||||
}
|
||||
|
||||
protected ContentTypeBaseRepository(IUnitOfWork work, IRepositoryCacheProvider cache) : base(work, cache)
|
||||
{
|
||||
}
|
||||
|
||||
protected void PersistNewBaseContentType(ContentTypeDto dto, IContentTypeComposition entity)
|
||||
{
|
||||
//Logic for setting Path, Level and SortOrder
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = entity.ParentId });
|
||||
int level = parent.Level + 1;
|
||||
int sortOrder =
|
||||
Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoNode WHERE parentID = @ParentId AND nodeObjectType = @NodeObjectType",
|
||||
new { ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId });
|
||||
|
||||
//Create the (base) node data - umbracoNode
|
||||
var nodeDto = dto.NodeDto;
|
||||
nodeDto.Path = parent.Path;
|
||||
nodeDto.Level = short.Parse(level.ToString(CultureInfo.InvariantCulture));
|
||||
nodeDto.SortOrder = sortOrder;
|
||||
var o = Database.IsNew(nodeDto) ? Convert.ToInt32(Database.Insert(nodeDto)) : Database.Update(nodeDto);
|
||||
|
||||
//Update with new correct path
|
||||
nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId);
|
||||
Database.Update(nodeDto);
|
||||
|
||||
//Update entity with correct values
|
||||
entity.Id = nodeDto.NodeId; //Set Id on entity to ensure an Id is set
|
||||
entity.Path = nodeDto.Path;
|
||||
entity.SortOrder = sortOrder;
|
||||
entity.Level = level;
|
||||
|
||||
//Insert new ContentType entry
|
||||
Database.Insert(dto);
|
||||
|
||||
//Insert ContentType composition in new table
|
||||
foreach (var composition in entity.ContentTypeComposition)
|
||||
{
|
||||
if (composition.Id == entity.Id) continue;//Just to ensure that we aren't creating a reference to ourself.
|
||||
|
||||
Database.Insert(new ContentType2ContentTypeDto { ParentId = composition.Id, ChildId = entity.Id });
|
||||
}
|
||||
|
||||
//Insert collection of allowed content types
|
||||
foreach (var allowedContentType in entity.AllowedContentTypes)
|
||||
{
|
||||
Database.Insert(new ContentTypeAllowedContentTypeDto { Id = entity.Id, AllowedId = allowedContentType.Id, SortOrder = allowedContentType.SortOrder });
|
||||
}
|
||||
|
||||
var propertyFactory = new PropertyGroupFactory(nodeDto.NodeId);
|
||||
|
||||
//Insert Tabs
|
||||
foreach (var propertyGroup in entity.PropertyGroups)
|
||||
{
|
||||
var tabDto = propertyFactory.BuildGroupDto(propertyGroup);
|
||||
var primaryKey = Convert.ToInt32(Database.Insert(tabDto));
|
||||
propertyGroup.Id = primaryKey;//Set Id on PropertyGroup
|
||||
}
|
||||
|
||||
//Insert PropertyTypes
|
||||
foreach (var propertyGroup in entity.PropertyGroups)
|
||||
{
|
||||
foreach (var propertyType in propertyGroup.PropertyTypes)
|
||||
{
|
||||
var propertyTypeDto = propertyFactory.BuildPropertyTypeDto(propertyGroup.Id, propertyType);
|
||||
var primaryKey = Convert.ToInt32(Database.Insert(propertyTypeDto));
|
||||
propertyType.Id = primaryKey;//Set Id on PropertyType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void PersistUpdatedBaseContentType(ContentTypeDto dto, IContentTypeComposition entity)
|
||||
{
|
||||
var propertyFactory = new PropertyGroupFactory(entity.Id);
|
||||
|
||||
var nodeDto = dto.NodeDto;
|
||||
var o = Database.Update(nodeDto);
|
||||
|
||||
//Look up ContentType entry to get PrimaryKey for updating the DTO
|
||||
var dtoPk = Database.First<ContentTypeDto>("WHERE nodeId = @Id", new { Id = entity.Id });
|
||||
dto.PrimaryKey = dtoPk.PrimaryKey;
|
||||
Database.Update(dto);
|
||||
|
||||
//Delete the ContentType composition entries before adding the updated collection
|
||||
Database.Delete<ContentType2ContentTypeDto>("WHERE childContentTypeId = @Id", new { Id = entity.Id });
|
||||
//Update ContentType composition in new table
|
||||
foreach (var composition in entity.ContentTypeComposition)
|
||||
{
|
||||
Database.Insert(new ContentType2ContentTypeDto { ParentId = composition.Id, ChildId = entity.Id });
|
||||
}
|
||||
|
||||
//Delete the allowed content type entries before adding the updated collection
|
||||
Database.Delete<ContentTypeAllowedContentTypeDto>("WHERE Id = @Id", new { Id = entity.Id });
|
||||
//Insert collection of allowed content types
|
||||
foreach (var allowedContentType in entity.AllowedContentTypes)
|
||||
{
|
||||
Database.Insert(new ContentTypeAllowedContentTypeDto { Id = entity.Id, AllowedId = allowedContentType.Id, SortOrder = allowedContentType.SortOrder });
|
||||
}
|
||||
|
||||
//Check Dirty properties for Tabs/Groups and PropertyTypes - insert and delete accordingly
|
||||
if (((ICanBeDirty)entity).IsPropertyDirty("PropertyGroups") || entity.PropertyGroups.Any(x => x.IsDirty()))
|
||||
{
|
||||
//Delete PropertyTypes by excepting entries from db with entries from collections
|
||||
var dbPropertyTypes = Database.Fetch<PropertyTypeDto>("WHERE contentTypeId = @Id", new { Id = entity.Id }).Select(x => x.Alias);
|
||||
var entityPropertyTypes = entity.PropertyTypes.Select(x => x.Alias);
|
||||
var aliases = dbPropertyTypes.Except(entityPropertyTypes);
|
||||
foreach (var alias in aliases)
|
||||
{
|
||||
Database.Delete<PropertyTypeDto>("WHERE contentTypeId = @Id AND Alias = @Alias", new { Id = entity.Id, Alias = alias });
|
||||
}
|
||||
//Delete Tabs/Groups by excepting entries from db with entries from collections
|
||||
var dbPropertyGroups = Database.Fetch<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id", new { Id = entity.Id }).Select(x => x.Text);
|
||||
var entityPropertyGroups = entity.PropertyGroups.Select(x => x.Name);
|
||||
var tabs = dbPropertyGroups.Except(entityPropertyGroups);
|
||||
foreach (var tabName in tabs)
|
||||
{
|
||||
Database.Delete<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id AND text = @Name", new { Id = entity.Id, Name = tabName });
|
||||
}
|
||||
|
||||
//Run through all groups and types to insert or update entries
|
||||
foreach (var propertyGroup in entity.PropertyGroups)
|
||||
{
|
||||
var tabDto = propertyFactory.BuildGroupDto(propertyGroup);
|
||||
int groupPrimaryKey = propertyGroup.HasIdentity
|
||||
? Database.Update(tabDto)
|
||||
: Convert.ToInt32(Database.Insert(tabDto));
|
||||
if (!propertyGroup.HasIdentity)
|
||||
propertyGroup.Id = groupPrimaryKey;//Set Id on new PropertyGroup
|
||||
|
||||
//This should indicate that neither group nor property types has been touched, but this implies a deeper 'Dirty'-lookup
|
||||
//if(!propertyGroup.IsDirty()) continue;
|
||||
|
||||
foreach (var propertyType in propertyGroup.PropertyTypes)
|
||||
{
|
||||
var propertyTypeDto = propertyFactory.BuildPropertyTypeDto(propertyGroup.Id, propertyType);
|
||||
int typePrimaryKey = propertyType.HasIdentity
|
||||
? Database.Update(propertyTypeDto)
|
||||
: Convert.ToInt32(Database.Insert(propertyTypeDto));
|
||||
if (!propertyType.HasIdentity)
|
||||
propertyType.Id = typePrimaryKey;//Set Id on new PropertyType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected IEnumerable<ContentTypeSort> GetAllowedContentTypeIds(int id)
|
||||
{
|
||||
var allowedContentTypesSql = new Sql();
|
||||
allowedContentTypesSql.Select("*");
|
||||
allowedContentTypesSql.From("cmsContentTypeAllowedContentType");
|
||||
allowedContentTypesSql.Where("[cmsContentTypeAllowedContentType].[Id] = @Id", new { Id = id });
|
||||
|
||||
var allowedContentTypeDtos = Database.Fetch<ContentTypeAllowedContentTypeDto>(allowedContentTypesSql);
|
||||
return allowedContentTypeDtos.Select(x => new ContentTypeSort { Id = x.AllowedId, SortOrder = x.SortOrder }).ToList();
|
||||
}
|
||||
|
||||
protected PropertyGroupCollection GetPropertyGroupCollection(int id)
|
||||
{
|
||||
var propertySql = new Sql();
|
||||
propertySql.Select("*");
|
||||
propertySql.From("cmsTab");
|
||||
propertySql.RightJoin("cmsPropertyType ON [cmsTab].[id] = [cmsPropertyType].[tabId]");
|
||||
propertySql.InnerJoin("cmsDataType ON [cmsPropertyType].[dataTypeId] = [cmsDataType].[nodeId]");
|
||||
propertySql.Where("[cmsPropertyType].[contentTypeId] = @Id", new { Id = id });
|
||||
|
||||
var dtos = Database.Fetch<PropertyTypeGroupDto, PropertyTypeDto, DataTypeDto, PropertyTypeGroupDto>(new TabPropertyTypeRelator().Map, propertySql);
|
||||
|
||||
var propertyFactory = new PropertyGroupFactory(id);
|
||||
var propertyGroups = propertyFactory.BuildEntity(dtos);
|
||||
return new PropertyGroupCollection(propertyGroups);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
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;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
@@ -16,7 +13,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <summary>
|
||||
/// Represents a repository for doing CRUD operations for <see cref="IContentType"/>
|
||||
/// </summary>
|
||||
internal class ContentTypeRepository : PetaPocoRepositoryBase<int, IContentType>, IContentTypeRepository
|
||||
internal class ContentTypeRepository : ContentTypeBaseRepository<int, IContentType>, IContentTypeRepository
|
||||
{
|
||||
public ContentTypeRepository(IUnitOfWork work) : base(work)
|
||||
{
|
||||
@@ -147,72 +144,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var factory = new ContentTypeFactory(NodeObjectTypeId);
|
||||
var dto = factory.BuildDto(entity);
|
||||
|
||||
//Logic for setting Path, Level and SortOrder
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = entity.ParentId });
|
||||
int level = parent.Level + 1;
|
||||
int sortOrder =
|
||||
Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoNode WHERE parentID = @ParentId AND nodeObjectType = @NodeObjectType",
|
||||
new { ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId });
|
||||
|
||||
//Create the (base) node data - umbracoNode
|
||||
var nodeDto = dto.ContentTypeDto.NodeDto;
|
||||
nodeDto.Path = parent.Path;
|
||||
nodeDto.Level = short.Parse(level.ToString(CultureInfo.InvariantCulture));
|
||||
nodeDto.SortOrder = sortOrder;
|
||||
var o = Database.IsNew(nodeDto) ? Convert.ToInt32(Database.Insert(nodeDto)) : Database.Update(nodeDto);
|
||||
|
||||
//Update with new correct path
|
||||
nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId);
|
||||
Database.Update(nodeDto);
|
||||
|
||||
//Update entity with correct values
|
||||
entity.Id = nodeDto.NodeId; //Set Id on entity to ensure an Id is set
|
||||
entity.Path = nodeDto.Path;
|
||||
entity.SortOrder = sortOrder;
|
||||
entity.Level = level;
|
||||
|
||||
//Insert new ContentType entry
|
||||
var contentTypeDto = dto.ContentTypeDto;
|
||||
Database.Insert(contentTypeDto);
|
||||
PersistNewBaseContentType(dto.ContentTypeDto, entity);
|
||||
|
||||
//TODO Insert new DocumentType entries - NOTE only seems relevant as long as Templates resides in the DB?
|
||||
//TODO Insert allowed Templates
|
||||
|
||||
//Insert ContentType composition in new table
|
||||
foreach (var composition in entity.ContentTypeComposition)
|
||||
{
|
||||
if(composition.Id == entity.Id) continue;//Just to ensure that we aren't creating a reference to ourself.
|
||||
|
||||
Database.Insert(new ContentType2ContentTypeDto { ParentId = composition.Id, ChildId = entity.Id});
|
||||
}
|
||||
|
||||
//Insert collection of allowed content types
|
||||
foreach (var allowedContentType in entity.AllowedContentTypes)
|
||||
{
|
||||
Database.Insert(new ContentTypeAllowedContentTypeDto {Id = entity.Id, AllowedId = allowedContentType.Id, SortOrder = allowedContentType.SortOrder});
|
||||
}
|
||||
|
||||
var propertyFactory = new PropertyGroupFactory(nodeDto.NodeId);
|
||||
|
||||
//Insert Tabs
|
||||
foreach (var propertyGroup in entity.PropertyGroups)
|
||||
{
|
||||
var tabDto = propertyFactory.BuildGroupDto(propertyGroup);
|
||||
var primaryKey = Convert.ToInt32(Database.Insert(tabDto));
|
||||
propertyGroup.Id = primaryKey;//Set Id on PropertyGroup
|
||||
}
|
||||
|
||||
//Insert PropertyTypes
|
||||
foreach (var propertyGroup in entity.PropertyGroups)
|
||||
{
|
||||
foreach (var propertyType in propertyGroup.PropertyTypes)
|
||||
{
|
||||
var propertyTypeDto = propertyFactory.BuildPropertyTypeDto(propertyGroup.Id, propertyType);
|
||||
var primaryKey = Convert.ToInt32(Database.Insert(propertyTypeDto));
|
||||
propertyType.Id = primaryKey;//Set Id on PropertyType
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
((ContentType)entity).ResetDirtyProperties();
|
||||
}
|
||||
|
||||
@@ -221,114 +157,19 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//Updates Modified date
|
||||
((ContentType)entity).UpdatingEntity();
|
||||
|
||||
var propertyFactory = new PropertyGroupFactory(entity.Id);
|
||||
var factory = new ContentTypeFactory(NodeObjectTypeId);
|
||||
var dto = factory.BuildDto(entity);
|
||||
var nodeDto = dto.ContentTypeDto.NodeDto;
|
||||
var o = Database.Update(nodeDto);
|
||||
|
||||
//Look up ContentType entry to get PrimaryKey for updating the DTO
|
||||
var dtoPk = Database.First<ContentTypeDto>("WHERE nodeId = @Id", new { Id = entity.Id });
|
||||
var contentTypeDto = dto.ContentTypeDto;
|
||||
contentTypeDto.PrimaryKey = dtoPk.PrimaryKey;
|
||||
Database.Update(contentTypeDto);
|
||||
PersistUpdatedBaseContentType(dto.ContentTypeDto, entity);
|
||||
|
||||
//Look up DocumentType entries for updating - this could possibly be a "remove all, insert all"-approach
|
||||
|
||||
//TODO Update new DocumentType entries - NOTE only seems relevant as long as Templates resides in the DB?
|
||||
//TODO Update allowed Templates
|
||||
|
||||
//Delete the ContentType composition entries before adding the updated collection
|
||||
Database.Delete<ContentType2ContentTypeDto>("WHERE childContentTypeId = @Id", new { Id = entity.Id });
|
||||
//Update ContentType composition in new table
|
||||
foreach (var composition in entity.ContentTypeComposition)
|
||||
{
|
||||
Database.Insert(new ContentType2ContentTypeDto { ParentId = composition.Id, ChildId = entity.Id });
|
||||
}
|
||||
|
||||
//Delete the allowed content type entries before adding the updated collection
|
||||
Database.Delete<ContentTypeAllowedContentTypeDto>("WHERE Id = @Id", new {Id = entity.Id});
|
||||
//Insert collection of allowed content types
|
||||
foreach (var allowedContentType in entity.AllowedContentTypes)
|
||||
{
|
||||
Database.Insert(new ContentTypeAllowedContentTypeDto { Id = entity.Id, AllowedId = allowedContentType.Id, SortOrder = allowedContentType.SortOrder});
|
||||
}
|
||||
|
||||
//Check Dirty properties for Tabs/Groups and PropertyTypes - insert and delete accordingly
|
||||
if (((ICanBeDirty)entity).IsPropertyDirty("PropertyGroups") || entity.PropertyGroups.Any(x => x.IsDirty()))
|
||||
{
|
||||
//Delete PropertyTypes by excepting entries from db with entries from collections
|
||||
var dbPropertyTypes = Database.Fetch<PropertyTypeDto>("WHERE contentTypeId = @Id", new { Id = entity.Id }).Select(x => x.Alias);
|
||||
var entityPropertyTypes = entity.PropertyTypes.Select(x => x.Alias);
|
||||
var aliases = dbPropertyTypes.Except(entityPropertyTypes);
|
||||
foreach (var alias in aliases)
|
||||
{
|
||||
Database.Delete<PropertyTypeDto>("WHERE contentTypeId = @Id AND Alias = @Alias", new { Id = entity.Id, Alias = alias });
|
||||
}
|
||||
//Delete Tabs/Groups by excepting entries from db with entries from collections
|
||||
var dbPropertyGroups = Database.Fetch<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id", new { Id = entity.Id }).Select(x => x.Text);
|
||||
var entityPropertyGroups = entity.PropertyGroups.Select(x => x.Name);
|
||||
var tabs = dbPropertyGroups.Except(entityPropertyGroups);
|
||||
foreach (var tabName in tabs)
|
||||
{
|
||||
Database.Delete<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id AND text = @Name", new { Id = entity.Id, Name = tabName });
|
||||
}
|
||||
|
||||
//Run through all groups and types to insert or update entries
|
||||
foreach (var propertyGroup in entity.PropertyGroups)
|
||||
{
|
||||
var tabDto = propertyFactory.BuildGroupDto(propertyGroup);
|
||||
int groupPrimaryKey = propertyGroup.HasIdentity
|
||||
? Database.Update(tabDto)
|
||||
: Convert.ToInt32(Database.Insert(tabDto));
|
||||
if (!propertyGroup.HasIdentity)
|
||||
propertyGroup.Id = groupPrimaryKey;//Set Id on new PropertyGroup
|
||||
|
||||
//This should indicate that neither group nor property types has been touched, but this implies a deeper 'Dirty'-lookup
|
||||
//if(!propertyGroup.IsDirty()) continue;
|
||||
|
||||
foreach (var propertyType in propertyGroup.PropertyTypes)
|
||||
{
|
||||
var propertyTypeDto = propertyFactory.BuildPropertyTypeDto(propertyGroup.Id, propertyType);
|
||||
int typePrimaryKey = propertyType.HasIdentity
|
||||
? Database.Update(propertyTypeDto)
|
||||
: Convert.ToInt32(Database.Insert(propertyTypeDto));
|
||||
if (!propertyType.HasIdentity)
|
||||
propertyType.Id = typePrimaryKey;//Set Id on new PropertyType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
((ContentType)entity).ResetDirtyProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private IEnumerable<ContentTypeSort> GetAllowedContentTypeIds(int id)
|
||||
{
|
||||
var allowedContentTypesSql = new Sql();
|
||||
allowedContentTypesSql.Select("*");
|
||||
allowedContentTypesSql.From("cmsContentTypeAllowedContentType");
|
||||
allowedContentTypesSql.Where("[cmsContentTypeAllowedContentType].[Id] = @Id", new { Id = id });
|
||||
|
||||
var allowedContentTypeDtos = Database.Fetch<ContentTypeAllowedContentTypeDto>(allowedContentTypesSql);
|
||||
return allowedContentTypeDtos.Select(x => new ContentTypeSort { Id = x.AllowedId, SortOrder = x.SortOrder }).ToList();
|
||||
}
|
||||
|
||||
private PropertyGroupCollection GetPropertyGroupCollection(int id)
|
||||
{
|
||||
var propertySql = new Sql();
|
||||
propertySql.Select("*");
|
||||
propertySql.From("cmsTab");
|
||||
propertySql.RightJoin("cmsPropertyType ON [cmsTab].[id] = [cmsPropertyType].[tabId]");
|
||||
propertySql.InnerJoin("cmsDataType ON [cmsPropertyType].[dataTypeId] = [cmsDataType].[nodeId]");
|
||||
propertySql.Where("[cmsPropertyType].[contentTypeId] = @Id", new { Id = id });
|
||||
|
||||
var dtos = Database.Fetch<PropertyTypeGroupDto, PropertyTypeDto, DataTypeDto, PropertyTypeGroupDto>(new TabPropertyTypeRelator().Map, propertySql);
|
||||
|
||||
var propertyFactory = new PropertyGroupFactory(id);
|
||||
var propertyGroups = propertyFactory.BuildEntity(dtos);
|
||||
return new PropertyGroupCollection(propertyGroups);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
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;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
@@ -16,7 +13,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <summary>
|
||||
/// Represents a repository for doing CRUD operations for <see cref="IMediaType"/>
|
||||
/// </summary>
|
||||
internal class MediaTypeRepository : PetaPocoRepositoryBase<int, IMediaType>, IMediaTypeRepository
|
||||
internal class MediaTypeRepository : ContentTypeBaseRepository<int, IMediaType>, IMediaTypeRepository
|
||||
{
|
||||
public MediaTypeRepository(IUnitOfWork work) : base(work)
|
||||
{
|
||||
@@ -44,6 +41,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
contentType.AllowedContentTypes = GetAllowedContentTypeIds(id);
|
||||
contentType.PropertyGroups = GetPropertyGroupCollection(id);
|
||||
|
||||
var list = Database.Fetch<ContentType2ContentTypeDto>("WHERE childContentTypeId = @Id");
|
||||
foreach (var contentTypeDto in list)
|
||||
{
|
||||
bool result = contentType.AddContentType(Get(contentTypeDto.ParentId));
|
||||
//Do something if adding fails? (Should hopefully not be possible unless someone create a circular reference)
|
||||
}
|
||||
|
||||
((MediaType)contentType).ResetDirtyProperties();
|
||||
return contentType;
|
||||
}
|
||||
@@ -134,38 +138,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var factory = new MediaTypeFactory(NodeObjectTypeId);
|
||||
var dto = factory.BuildDto(entity);
|
||||
|
||||
//Logic for setting Path, Level and SortOrder
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = entity.ParentId });
|
||||
int level = parent.Level + 1;
|
||||
int sortOrder =
|
||||
Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoNode WHERE parentID = @ParentId AND nodeObjectType = @NodeObjectType",
|
||||
new { ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId });
|
||||
PersistNewBaseContentType(dto, entity);
|
||||
|
||||
//Create the (base) node data - umbracoNode
|
||||
var nodeDto = dto.NodeDto;
|
||||
nodeDto.Path = parent.Path;
|
||||
nodeDto.Level = short.Parse(level.ToString(CultureInfo.InvariantCulture));
|
||||
nodeDto.SortOrder = sortOrder;
|
||||
var o = Database.IsNew(nodeDto) ? Convert.ToInt32(Database.Insert(nodeDto)) : Database.Update(nodeDto);
|
||||
|
||||
//Update with new correct path
|
||||
nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId);
|
||||
Database.Update(nodeDto);
|
||||
|
||||
//Update entity with correct values
|
||||
entity.Id = nodeDto.NodeId; //Set Id on entity to ensure an Id is set
|
||||
entity.Path = nodeDto.Path;
|
||||
entity.SortOrder = sortOrder;
|
||||
entity.Level = level;
|
||||
|
||||
//Insert new ContentType entry
|
||||
Database.Insert(dto);
|
||||
|
||||
//Insert collection of allowed content types
|
||||
foreach (var allowedContentType in entity.AllowedContentTypes)
|
||||
{
|
||||
Database.Insert(new ContentTypeAllowedContentTypeDto { Id = entity.Id, AllowedId = allowedContentType.Id, SortOrder = allowedContentType.SortOrder});
|
||||
}
|
||||
((MediaType)entity).ResetDirtyProperties();
|
||||
}
|
||||
|
||||
protected override void PersistUpdatedItem(IMediaType entity)
|
||||
@@ -173,101 +148,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//Updates Modified date
|
||||
((MediaType)entity).UpdatingEntity();
|
||||
|
||||
var propertyFactory = new PropertyGroupFactory(entity.Id);
|
||||
var factory = new MediaTypeFactory(NodeObjectTypeId);
|
||||
var dto = factory.BuildDto(entity);
|
||||
var nodeDto = dto.NodeDto;
|
||||
var o = Database.Update(nodeDto);
|
||||
|
||||
//Look up ContentType entry to get PrimaryKey for updating the DTO
|
||||
var dtoPk = Database.First<ContentTypeDto>("WHERE nodeId = @Id", new { Id = entity.Id });
|
||||
dto.PrimaryKey = dtoPk.PrimaryKey;
|
||||
Database.Update(dto);
|
||||
|
||||
//Delete the allowed content type entries before adding the updated collection
|
||||
Database.Delete<ContentTypeAllowedContentTypeDto>("WHERE Id = @Id", new { Id = entity.Id });
|
||||
|
||||
//Insert collection of allowed content types
|
||||
foreach (var allowedContentType in entity.AllowedContentTypes)
|
||||
{
|
||||
Database.Insert(new ContentTypeAllowedContentTypeDto { Id = entity.Id, AllowedId = allowedContentType.Id, SortOrder = allowedContentType.SortOrder });
|
||||
}
|
||||
|
||||
//Check Dirty properties for Tabs/Groups and PropertyTypes - insert and delete accordingly
|
||||
if (((ICanBeDirty)entity).IsPropertyDirty("PropertyGroups") || entity.PropertyGroups.Any(x => x.IsDirty()))
|
||||
{
|
||||
//Delete PropertyTypes by excepting entries from db with entries from collections
|
||||
var dbPropertyTypes = Database.Fetch<PropertyTypeDto>("WHERE contentTypeId = @Id", new { Id = entity.Id }).Select(x => x.Alias);
|
||||
var entityPropertyTypes = entity.PropertyTypes.Select(x => x.Alias);
|
||||
var aliases = dbPropertyTypes.Except(entityPropertyTypes);
|
||||
foreach (var alias in aliases)
|
||||
{
|
||||
Database.Delete<PropertyTypeDto>("WHERE contentTypeId = @Id AND Alias = @Alias", new { Id = entity.Id, Alias = alias });
|
||||
}
|
||||
//Delete Tabs/Groups by excepting entries from db with entries from collections
|
||||
var dbPropertyGroups = Database.Fetch<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id", new { Id = entity.Id }).Select(x => x.Text);
|
||||
var entityPropertyGroups = entity.PropertyGroups.Select(x => x.Name);
|
||||
var tabs = dbPropertyGroups.Except(entityPropertyGroups);
|
||||
foreach (var tabName in tabs)
|
||||
{
|
||||
Database.Delete<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id AND text = @Name", new { Id = entity.Id, Name = tabName });
|
||||
}
|
||||
|
||||
//Run through all groups and types to insert or update entries
|
||||
foreach (var propertyGroup in entity.PropertyGroups)
|
||||
{
|
||||
var tabDto = propertyFactory.BuildGroupDto(propertyGroup);
|
||||
int groupPrimaryKey = propertyGroup.HasIdentity
|
||||
? Database.Update(tabDto)
|
||||
: Convert.ToInt32(Database.Insert(tabDto));
|
||||
if (!propertyGroup.HasIdentity)
|
||||
propertyGroup.Id = groupPrimaryKey;//Set Id on new PropertyGroup
|
||||
|
||||
//This should indicate that neither group nor property types has been touched, but this implies a deeper 'Dirty'-lookup
|
||||
//if(!propertyGroup.IsDirty()) continue;
|
||||
|
||||
foreach (var propertyType in propertyGroup.PropertyTypes)
|
||||
{
|
||||
var propertyTypeDto = propertyFactory.BuildPropertyTypeDto(propertyGroup.Id, propertyType);
|
||||
int typePrimaryKey = propertyType.HasIdentity
|
||||
? Database.Update(propertyTypeDto)
|
||||
: Convert.ToInt32(Database.Insert(propertyTypeDto));
|
||||
if (!propertyType.HasIdentity)
|
||||
propertyType.Id = typePrimaryKey;//Set Id on new PropertyType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PersistUpdatedBaseContentType(dto, entity);
|
||||
|
||||
((MediaType)entity).ResetDirtyProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private IEnumerable<ContentTypeSort> GetAllowedContentTypeIds(int id)
|
||||
{
|
||||
var allowedContentTypesSql = new Sql();
|
||||
allowedContentTypesSql.Select("*");
|
||||
allowedContentTypesSql.From("cmsContentTypeAllowedContentType");
|
||||
allowedContentTypesSql.Where("[cmsContentTypeAllowedContentType].[Id] = @Id", new { Id = id });
|
||||
|
||||
var allowedContentTypeDtos = Database.Fetch<ContentTypeAllowedContentTypeDto>(allowedContentTypesSql);
|
||||
return allowedContentTypeDtos.Select(x => new ContentTypeSort { Id = x.AllowedId, SortOrder = x.SortOrder}).ToList();
|
||||
}
|
||||
|
||||
private PropertyGroupCollection GetPropertyGroupCollection(int id)
|
||||
{
|
||||
var propertySql = new Sql();
|
||||
propertySql.Select("*");
|
||||
propertySql.From("cmsTab");
|
||||
propertySql.RightJoin("cmsPropertyType ON [cmsTab].[id] = [cmsPropertyType].[tabId]");
|
||||
propertySql.InnerJoin("cmsDataType ON [cmsPropertyType].[dataTypeId] = [cmsDataType].[nodeId]");
|
||||
propertySql.Where("[cmsPropertyType].[contentTypeId] = @Id", new { Id = id });
|
||||
|
||||
var tabDtos = Database.Fetch<PropertyTypeGroupDto, PropertyTypeDto, DataTypeDto, PropertyTypeGroupDto>(new TabPropertyTypeRelator().Map, propertySql);
|
||||
|
||||
var propertyFactory = new PropertyGroupFactory(id);
|
||||
var propertyGroups = propertyFactory.BuildEntity(tabDtos);
|
||||
return new PropertyGroupCollection(propertyGroups);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,8 +74,11 @@
|
||||
<Compile Include="DictionaryExtensions.cs" />
|
||||
<Compile Include="Dictionary\CultureDictionaryFactoryResolver.cs" />
|
||||
<Compile Include="Dictionary\ICultureDictionaryFactory.cs" />
|
||||
<Compile Include="Models\ContentBase.cs" />
|
||||
<Compile Include="Models\ContentExtensions.cs" />
|
||||
<Compile Include="Enum.cs" />
|
||||
<Compile Include="Models\ContentTypeBase.cs" />
|
||||
<Compile Include="Models\ContentTypeCompositionBase.cs" />
|
||||
<Compile Include="Models\ContentTypeSort.cs" />
|
||||
<Compile Include="Models\Css\CssCompactor.cs" />
|
||||
<Compile Include="Models\Css\CssParser.cs" />
|
||||
@@ -124,6 +127,7 @@
|
||||
<Compile Include="Persistence\Querying\SqlTranslator.cs" />
|
||||
<Compile Include="Persistence\Relators\DictionaryLanguageTextRelator.cs" />
|
||||
<Compile Include="Persistence\Repositories\ContentRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\ContentTypeBaseRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\ContentTypeRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\DataTypeDefinitionRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\DictionaryRepository.cs" />
|
||||
|
||||
Reference in New Issue
Block a user