2012-10-10 08:42:54 -02:00
using System ;
using System.Collections.Generic ;
using System.Collections.Specialized ;
2013-02-09 04:05:01 +06:00
using System.Diagnostics ;
2012-10-10 08:42:54 -02:00
using System.Globalization ;
using System.Linq ;
using System.Reflection ;
using System.Runtime.Serialization ;
2013-01-14 11:02:12 -01:00
using System.Web ;
2012-10-10 08:42:54 -02:00
using Umbraco.Core.Models.EntityBase ;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents an abstract class for base Content properties and methods
/// </summary>
2013-02-09 04:05:01 +06:00
[DebuggerDisplay("Id: {Id}, Name: {Name}, ContentType: {ContentTypeBase.Alias}")]
2012-10-10 08:42:54 -02:00
public abstract class ContentBase : Entity , IContentBase
{
protected IContentTypeComposition ContentTypeBase ;
2012-11-13 14:30:05 -01:00
private Lazy < int > _parentId ;
2013-01-15 10:12:23 -01:00
private string _name ; //NOTE Once localization is introduced this will be the localized Name of the Content/Media.
2012-10-10 08:42:54 -02:00
private int _sortOrder ;
private int _level ;
private string _path ;
2012-11-11 06:53:02 -01:00
private int _creatorId ;
2012-10-10 08:42:54 -02:00
private bool _trashed ;
private int _contentTypeId ;
private PropertyCollection _properties ;
2013-07-24 12:54:10 +10:00
private readonly List < Property > _lastInvalidProperties = new List < Property > ( ) ;
2012-10-10 08:42:54 -02:00
2013-01-15 10:12:23 -01:00
/// <summary>
/// Protected constructor for ContentBase (Base for Content and Media)
/// </summary>
/// <param name="name">Localized Name of the entity</param>
/// <param name="parentId"></param>
/// <param name="contentType"></param>
/// <param name="properties"></param>
protected ContentBase ( string name , int parentId , IContentTypeComposition contentType , PropertyCollection properties )
2012-10-10 08:42:54 -02:00
{
2012-12-16 06:28:43 +05:00
Mandate . ParameterCondition ( parentId ! = 0 , "parentId" ) ;
2012-11-02 11:54:42 -01:00
Mandate . ParameterNotNull ( contentType , "contentType" ) ;
Mandate . ParameterNotNull ( properties , "properties" ) ;
2013-01-15 10:21:24 -01:00
ContentTypeBase = contentType ;
Version = Guid . NewGuid ( ) ;
2012-11-13 14:30:05 -01:00
_parentId = new Lazy < int > ( ( ) = > parentId ) ;
2013-01-15 10:12:23 -01:00
_name = name ;
2012-10-10 08:42:54 -02:00
_contentTypeId = int . Parse ( contentType . Id . ToString ( CultureInfo . InvariantCulture ) ) ;
_properties = properties ;
_properties . EnsurePropertyTypes ( PropertyTypes ) ;
}
2013-01-15 10:12:23 -01:00
/// <summary>
/// Protected constructor for ContentBase (Base for Content and Media)
/// </summary>
/// <param name="name">Localized Name of the entity</param>
/// <param name="parent"></param>
/// <param name="contentType"></param>
/// <param name="properties"></param>
protected ContentBase ( string name , IContentBase parent , IContentTypeComposition contentType , PropertyCollection properties )
2012-12-16 04:02:29 +05:00
{
Mandate . ParameterNotNull ( parent , "parent" ) ;
Mandate . ParameterNotNull ( contentType , "contentType" ) ;
Mandate . ParameterNotNull ( properties , "properties" ) ;
2013-01-15 10:21:24 -01:00
ContentTypeBase = contentType ;
Version = Guid . NewGuid ( ) ;
2012-12-16 04:02:29 +05:00
_parentId = new Lazy < int > ( ( ) = > parent . Id ) ;
2013-01-15 10:12:23 -01:00
_name = name ;
2012-12-16 04:02:29 +05:00
_contentTypeId = int . Parse ( contentType . Id . ToString ( CultureInfo . InvariantCulture ) ) ;
_properties = properties ;
_properties . EnsurePropertyTypes ( PropertyTypes ) ;
}
private static readonly PropertyInfo NameSelector = ExpressionHelper . GetPropertyInfo < ContentBase , string > ( x = > x . Name ) ;
2012-10-10 08:42:54 -02:00
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 ) ;
2012-11-11 06:53:02 -01:00
private static readonly PropertyInfo CreatorIdSelector = ExpressionHelper . GetPropertyInfo < ContentBase , int > ( x = > x . CreatorId ) ;
2012-10-10 08:42:54 -02:00
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>
[DataMember]
public virtual int ParentId
{
2012-12-16 04:02:29 +05:00
get
{
var val = _parentId . Value ;
if ( val = = 0 )
{
2013-01-03 08:30:38 -01:00
throw new InvalidOperationException ( "The ParentId cannot have a value of 0. Perhaps the parent object used to instantiate this object has not been persisted to the data store." ) ;
2012-12-16 04:02:29 +05:00
}
return val ;
}
2012-10-10 08:42:54 -02:00
set
{
2012-11-13 14:30:05 -01:00
_parentId = new Lazy < int > ( ( ) = > value ) ;
2012-10-10 08:42:54 -02:00
OnPropertyChanged ( ParentIdSelector ) ;
}
}
/// <summary>
/// Gets or sets the name of the entity
/// </summary>
[DataMember]
public virtual string Name
{
get { return _name ; }
set
{
2013-03-21 00:05:56 +06:00
SetPropertyValueAndDetectChanges ( o = >
{
_name = value ;
return _name ;
} , _name , NameSelector ) ;
2012-10-10 08:42:54 -02:00
}
}
/// <summary>
/// Gets or sets the sort order of the content entity
/// </summary>
[DataMember]
public virtual int SortOrder
{
get { return _sortOrder ; }
set
{
2013-03-21 00:05:56 +06:00
SetPropertyValueAndDetectChanges ( o = >
{
_sortOrder = value ;
return _sortOrder ;
} , _sortOrder , SortOrderSelector ) ;
2012-10-10 08:42:54 -02:00
}
}
/// <summary>
/// Gets or sets the level of the content entity
/// </summary>
[DataMember]
public virtual int Level
{
get { return _level ; }
set
{
2013-03-21 00:05:56 +06:00
SetPropertyValueAndDetectChanges ( o = >
{
_level = value ;
return _level ;
} , _level , LevelSelector ) ;
2012-10-10 08:42:54 -02:00
}
}
/// <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
{
2013-03-21 00:05:56 +06:00
SetPropertyValueAndDetectChanges ( o = >
{
_path = value ;
return _path ;
} , _path , PathSelector ) ;
2012-10-10 08:42:54 -02:00
}
}
/// <summary>
2012-11-09 14:45:28 -01:00
/// Profile of the user who created this Content
2012-10-10 08:42:54 -02:00
/// </summary>
[DataMember]
2012-11-11 06:53:02 -01:00
public virtual int CreatorId
2012-10-10 08:42:54 -02:00
{
2012-11-11 06:53:02 -01:00
get { return _creatorId ; }
2012-10-10 08:42:54 -02:00
set
{
2013-03-21 00:05:56 +06:00
SetPropertyValueAndDetectChanges ( o = >
{
_creatorId = value ;
return _creatorId ;
} , _creatorId , CreatorIdSelector ) ;
2012-10-10 08:42:54 -02:00
}
}
/// <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
{
2013-03-21 00:05:56 +06:00
SetPropertyValueAndDetectChanges ( o = >
{
_trashed = value ;
return _trashed ;
} , _trashed , TrashedSelector ) ;
2012-10-10 08:42:54 -02:00
}
}
/// <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
{
2013-03-21 00:05:56 +06:00
SetPropertyValueAndDetectChanges ( o = >
{
_contentTypeId = value ;
return _contentTypeId ;
} , _contentTypeId , DefaultContentTypeIdSelector ) ;
2012-10-10 08:42:54 -02:00
}
}
/// <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 )
{
2013-08-12 16:20:32 +02:00
if ( Properties [ propertyTypeAlias ] . Value is TPassType )
return ( TPassType ) Properties [ propertyTypeAlias ] . Value ;
return ( TPassType ) Convert . ChangeType ( Properties [ propertyTypeAlias ] . Value , typeof ( TPassType ) ) ;
2012-10-10 08:42:54 -02:00
}
/// <summary>
2013-01-14 11:02:12 -01:00
/// Sets the <see cref="System.Object"/> value of a Property
2012-10-10 08:42:54 -02:00
/// </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 )
2013-01-14 11:02:12 -01:00
{
2013-01-15 11:56:25 -01:00
if ( value = = null )
{
SetValueOnProperty ( propertyTypeAlias , value ) ;
return ;
}
2013-01-14 11:02:12 -01:00
// .NET magic to call one of the 'SetPropertyValue' handlers with matching signature
( ( dynamic ) this ) . SetPropertyValue ( propertyTypeAlias , ( dynamic ) value ) ;
}
/// <summary>
/// Sets the <see cref="System.String"/> 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 SetPropertyValue ( string propertyTypeAlias , string value )
{
SetValueOnProperty ( propertyTypeAlias , value ) ;
}
/// <summary>
/// Sets the <see cref="System.Int32"/> 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 SetPropertyValue ( string propertyTypeAlias , int value )
{
SetValueOnProperty ( propertyTypeAlias , value ) ;
}
2013-01-18 09:03:58 -01:00
/// <summary>
/// Sets the <see cref="System.Int64"/> 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 SetPropertyValue ( string propertyTypeAlias , long value )
{
string val = value . ToString ( ) ;
SetValueOnProperty ( propertyTypeAlias , val ) ;
}
2013-01-14 11:02:12 -01:00
/// <summary>
/// Sets the <see cref="System.Boolean"/> 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 SetPropertyValue ( string propertyTypeAlias , bool value )
{
int val = Convert . ToInt32 ( value ) ;
SetValueOnProperty ( propertyTypeAlias , val ) ;
}
/// <summary>
/// Sets the <see cref="System.DateTime"/> 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 SetPropertyValue ( string propertyTypeAlias , DateTime value )
{
SetValueOnProperty ( propertyTypeAlias , value ) ;
}
/// <summary>
/// Sets the <see cref="System.Web.HttpPostedFile"/> 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 SetPropertyValue ( string propertyTypeAlias , HttpPostedFile value )
{
ContentExtensions . SetValue ( this , propertyTypeAlias , value ) ;
}
/// <summary>
/// Sets the <see cref="System.Web.HttpPostedFileBase"/> 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 SetPropertyValue ( string propertyTypeAlias , HttpPostedFileBase value )
{
ContentExtensions . SetValue ( this , propertyTypeAlias , value ) ;
}
/// <summary>
/// Sets the <see cref="System.Web.HttpPostedFileWrapper"/> 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 SetPropertyValue ( string propertyTypeAlias , HttpPostedFileWrapper value )
{
ContentExtensions . SetValue ( this , propertyTypeAlias , value ) ;
}
/// <summary>
/// Private method to set the value of a property
/// </summary>
/// <param name="propertyTypeAlias"></param>
/// <param name="value"></param>
private void SetValueOnProperty ( string propertyTypeAlias , object value )
2012-10-10 08:42:54 -02:00
{
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 ) ) ;
}
2012-10-10 13:18:14 -02:00
/// <summary>
/// Boolean indicating whether the content and its properties are valid
/// </summary>
/// <returns>True if content is valid otherwise false</returns>
public virtual bool IsValid ( )
{
2013-07-24 12:54:10 +10:00
_lastInvalidProperties . Clear ( ) ;
_lastInvalidProperties . AddRange ( Properties . Where ( property = > property . IsValid ( ) = = false ) ) ;
return _lastInvalidProperties . Any ( ) = = false ;
}
/// <summary>
/// Returns a collection of the result of the last validation process, this collection contains all invalid properties.
/// </summary>
internal IEnumerable < Property > LastInvalidProperties
{
get { return _lastInvalidProperties ; }
2012-10-10 13:18:14 -02:00
}
2013-01-11 10:38:32 -01:00
2013-01-29 10:26:18 -01:00
public abstract void ChangeTrashedState ( bool isTrashed , int parentId = - 20 ) ;
2013-08-07 11:39:25 +10:00
/// <summary>
/// We will override this method to ensure that when we reset the dirty properties that we
/// also reset the dirty changes made to the content's Properties (user defined)
/// </summary>
/// <param name="rememberPreviouslyChangedProperties"></param>
internal override void ResetDirtyProperties ( bool rememberPreviouslyChangedProperties )
{
base . ResetDirtyProperties ( rememberPreviouslyChangedProperties ) ;
foreach ( var prop in Properties )
{
prop . ResetDirtyProperties ( rememberPreviouslyChangedProperties ) ;
}
}
2012-10-10 08:42:54 -02:00
}
}