using System; using System.Reflection; using System.Runtime.Serialization; namespace Umbraco.Core.Models { /// /// Represents a Content object /// [Serializable] [DataContract(IsReference = true)] public class Content : ContentBase, IContent { private IContentType _contentType; private string _template; private bool _published; private string _language; private DateTime? _releaseDate; private DateTime? _expireDate; /// /// Constructor for creating a Content object /// /// Id of the Parent content /// ContentType for the current Content object public Content(int parentId, IContentType contentType) : this(parentId, contentType, new PropertyCollection()) { } /// /// Constructor for creating a Content object /// /// Id of the Parent content /// ContentType for the current Content object /// Collection of properties public Content(int parentId, IContentType contentType, PropertyCollection properties) : base(parentId, contentType, properties) { _contentType = contentType; } private static readonly PropertyInfo TemplateSelector = ExpressionHelper.GetPropertyInfo(x => x.Template); private static readonly PropertyInfo PublishedSelector = ExpressionHelper.GetPropertyInfo(x => x.Published); private static readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo(x => x.Language); private static readonly PropertyInfo ReleaseDateSelector = ExpressionHelper.GetPropertyInfo(x => x.ReleaseDate); private static readonly PropertyInfo ExpireDateSelector = ExpressionHelper.GetPropertyInfo(x => x.ExpireDate); /// /// Path to the template used by this Content /// This is used to override the default one from the ContentType /// /// If no template is explicitly set on the Content object, the Default template from the ContentType will be returned [DataMember] public virtual string Template { get { if (string.IsNullOrEmpty(_template) || _template == null) return _contentType.DefaultTemplate; return _template; } set { _template = value; OnPropertyChanged(TemplateSelector); } } /// /// Gets the current status of the Content /// public ContentStatus Status { get { if(Trashed) return ContentStatus.Trashed; if(ExpireDate.HasValue && DateTime.UtcNow > ExpireDate.Value) return ContentStatus.Expired; if(ReleaseDate.HasValue && ReleaseDate.Value > DateTime.UtcNow) return ContentStatus.AwaitingRelease; if(Published) return ContentStatus.Published; return ContentStatus.Unpublished; } } /// /// Boolean indicating whether this Content is Published or not /// /// Setting Published to true/false should be private or internal [DataMember] public bool Published { get { return _published; } internal set { _published = value; OnPropertyChanged(PublishedSelector); } } /// /// Language of the data contained within this Content object /// [DataMember] internal string Language { get { return _language; } set { _language = value; OnPropertyChanged(LanguageSelector); } } /// /// The date this Content should be released and thus be published /// [DataMember] public DateTime? ReleaseDate { get { return _releaseDate; } set { if(value.HasValue && value.Value > DateTime.UtcNow && Published) ChangePublishedState(false); if (value.HasValue && value.Value < DateTime.UtcNow && !Published) ChangePublishedState(true); _releaseDate = value; OnPropertyChanged(ReleaseDateSelector); } } /// /// The date this Content should expire and thus be unpublished /// [DataMember] public DateTime? ExpireDate { get { return _expireDate; } set { if(value.HasValue && DateTime.UtcNow > value.Value && Published) ChangePublishedState(false); _expireDate = value; OnPropertyChanged(ExpireDateSelector); } } /// /// Gets the ContentType used by this content object /// [IgnoreDataMember] public IContentType ContentType { get { return _contentType; } } /// /// Changes the for the current content object /// /// New ContentType for this content /// Leaves PropertyTypes intact after change public void ChangeContentType(IContentType contentType) { ContentTypeId = contentType.Id; _contentType = contentType; ContentTypeBase = contentType; Properties.EnsurePropertyTypes(PropertyTypes); Properties.CollectionChanged += PropertiesChanged; } /// /// Changes the for the current content object and removes PropertyTypes, /// which are not part of the new ContentType. /// /// New ContentType for this content /// Boolean indicating whether to clear PropertyTypes upon change public void ChangeContentType(IContentType contentType, bool clearProperties) { if(clearProperties) { ContentTypeId = contentType.Id; _contentType = contentType; ContentTypeBase = contentType; Properties.EnsureCleanPropertyTypes(PropertyTypes); Properties.CollectionChanged += PropertiesChanged; return; } ChangeContentType(contentType); } //TODO Possibly add a ToXml method, which will generate valid xml for the current Content object /// /// Method to call when Entity is being saved /// /// Created date is set and a Unique key is assigned internal override void AddingEntity() { base.AddingEntity(); Key = Guid.NewGuid(); } /// /// Method to call when Entity is being updated /// /// Modified Date is set and a new Version guid is set internal override void UpdatingEntity() { base.UpdatingEntity(); Version = Guid.NewGuid(); } /// /// Changes the Published state of the content object /// /// Boolean indicating whether content is published (true) or unpublished (false) internal void ChangePublishedState(bool isPublished) { Published = isPublished; //NOTE Should this be checked against the Expire/Release dates? //TODO possibly create new (unpublished version)? } /// /// Changes the Trashed state of the content object /// /// Boolean indicating whether content is trashed (true) or not trashed (false) /// internal void ChangeTrashedState(bool isTrashed, int parentId = -1) { Trashed = isTrashed; //If Content is trashed the parent id should be set to that of the RecycleBin if(isTrashed) { ParentId = -20; } else//otherwise set the parent id to the optional parameter, -1 being the fallback { ParentId = parentId; } //If the content is trashed and is published it should be marked as unpublished if (isTrashed && Published) { ChangePublishedState(false); } } } }