2012-12-09 03:22:11 +05:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
2013-05-07 18:56:24 -10:00
|
|
|
|
using System.Diagnostics;
|
2012-12-09 03:22:11 +05:00
|
|
|
|
using Umbraco.Core;
|
|
|
|
|
|
using Umbraco.Core.Models;
|
2013-09-05 17:47:13 +02:00
|
|
|
|
using Umbraco.Core.Models.PublishedContent;
|
2012-12-09 03:22:11 +05:00
|
|
|
|
|
|
|
|
|
|
namespace Umbraco.Web.Models
|
|
|
|
|
|
{
|
2013-03-02 01:02:38 +06:00
|
|
|
|
/// <summary>
|
2013-09-05 17:47:13 +02:00
|
|
|
|
/// Provide an abstract base class for <c>IPublishedContent</c> implementations.
|
2012-12-09 03:22:11 +05:00
|
|
|
|
/// </summary>
|
2013-09-05 17:47:13 +02:00
|
|
|
|
/// <remarks>This base class does which (a) consitently resolves and caches the Url, (b) provides an implementation
|
|
|
|
|
|
/// for this[alias], and (c) provides basic content set management.</remarks>
|
2013-05-07 18:56:24 -10:00
|
|
|
|
[DebuggerDisplay("Content Id: {Id}, Name: {Name}")]
|
2013-09-05 17:47:13 +02:00
|
|
|
|
public abstract class PublishedContentBase : IPublishedContent
|
|
|
|
|
|
{
|
|
|
|
|
|
#region Content
|
2012-12-10 03:40:50 +05:00
|
|
|
|
|
2013-09-05 17:47:13 +02:00
|
|
|
|
private string _url;
|
2013-03-02 01:02:38 +06:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2013-09-05 17:47:13 +02:00
|
|
|
|
/// Gets the url of the content.
|
2012-12-09 03:22:11 +05:00
|
|
|
|
/// </summary>
|
2012-12-09 03:27:19 +05:00
|
|
|
|
/// <remarks>
|
2013-09-05 17:47:13 +02:00
|
|
|
|
/// If this content is Content, the url that is returned is the one computed by the NiceUrlProvider, otherwise if
|
|
|
|
|
|
/// this content is Media, the url returned is the value found in the 'umbracoFile' property.
|
2012-12-09 03:27:19 +05:00
|
|
|
|
/// </remarks>
|
2012-12-09 03:22:11 +05:00
|
|
|
|
public virtual string Url
|
|
|
|
|
|
{
|
2016-01-14 09:40:40 +01:00
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
// should be thread-safe although it won't prevent url from being resolved more than once
|
|
|
|
|
|
if (_url != null)
|
|
|
|
|
|
return _url;
|
2012-12-10 03:40:50 +05:00
|
|
|
|
|
2016-01-14 09:40:40 +01:00
|
|
|
|
switch (ItemType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case PublishedItemType.Content:
|
|
|
|
|
|
if (UmbracoContext.Current == null)
|
|
|
|
|
|
throw new InvalidOperationException(
|
|
|
|
|
|
"Cannot resolve a Url for a content item when UmbracoContext.Current is null.");
|
|
|
|
|
|
if (UmbracoContext.Current.UrlProvider == null)
|
|
|
|
|
|
throw new InvalidOperationException(
|
|
|
|
|
|
"Cannot resolve a Url for a content item when UmbracoContext.Current.UrlProvider is null.");
|
|
|
|
|
|
_url = UmbracoContext.Current.UrlProvider.GetUrl(Id);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case PublishedItemType.Media:
|
|
|
|
|
|
var prop = GetProperty(Constants.Conventions.Media.File);
|
|
|
|
|
|
if (prop == null || prop.Value == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_url = string.Empty;
|
|
|
|
|
|
return _url;
|
|
|
|
|
|
}
|
2014-03-20 14:58:18 +11:00
|
|
|
|
|
2016-01-14 09:40:40 +01:00
|
|
|
|
var propType = ContentType.GetPropertyType(Constants.Conventions.Media.File);
|
2014-03-20 14:58:18 +11:00
|
|
|
|
|
2016-01-14 09:40:40 +01:00
|
|
|
|
//This is a hack - since we now have 2 properties that support a URL: upload and cropper, we need to detect this since we always
|
|
|
|
|
|
// want to return the normal URL and the cropper stores data as json
|
|
|
|
|
|
switch (propType.PropertyEditorAlias)
|
|
|
|
|
|
{
|
|
|
|
|
|
case Constants.PropertyEditors.UploadFieldAlias:
|
|
|
|
|
|
_url = prop.Value.ToString();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case Constants.PropertyEditors.ImageCropperAlias:
|
|
|
|
|
|
//get the url from the json format
|
|
|
|
|
|
var val = prop.Value.ToString();
|
|
|
|
|
|
var crops = val.SerializeToCropDataSet();
|
|
|
|
|
|
_url = crops != null ? crops.Src : string.Empty;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
throw new NotSupportedException();
|
|
|
|
|
|
}
|
2013-09-05 17:47:13 +02:00
|
|
|
|
|
2016-01-14 09:40:40 +01:00
|
|
|
|
return _url;
|
|
|
|
|
|
}
|
2012-12-09 03:22:11 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public abstract PublishedItemType ItemType { get; }
|
|
|
|
|
|
public abstract int Id { get; }
|
|
|
|
|
|
public abstract int TemplateId { get; }
|
|
|
|
|
|
public abstract int SortOrder { get; }
|
|
|
|
|
|
public abstract string Name { get; }
|
|
|
|
|
|
public abstract string UrlName { get; }
|
|
|
|
|
|
public abstract string DocumentTypeAlias { get; }
|
|
|
|
|
|
public abstract int DocumentTypeId { get; }
|
|
|
|
|
|
public abstract string WriterName { get; }
|
|
|
|
|
|
public abstract string CreatorName { get; }
|
|
|
|
|
|
public abstract int WriterId { get; }
|
|
|
|
|
|
public abstract int CreatorId { get; }
|
|
|
|
|
|
public abstract string Path { get; }
|
|
|
|
|
|
public abstract DateTime CreateDate { get; }
|
|
|
|
|
|
public abstract DateTime UpdateDate { get; }
|
|
|
|
|
|
public abstract Guid Version { get; }
|
2012-12-09 03:27:19 +05:00
|
|
|
|
public abstract int Level { get; }
|
2012-12-09 03:22:11 +05:00
|
|
|
|
|
2013-09-05 17:47:13 +02:00
|
|
|
|
public abstract bool IsDraft { get; }
|
|
|
|
|
|
|
|
|
|
|
|
public int GetIndex()
|
|
|
|
|
|
{
|
|
|
|
|
|
var index = this.Siblings().FindIndex(x => x.Id == Id);
|
|
|
|
|
|
if (index < 0)
|
|
|
|
|
|
throw new IndexOutOfRangeException("Could not find content in the content set.");
|
|
|
|
|
|
return index;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Tree
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the parent of the content.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public abstract IPublishedContent Parent { get; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the children of the content.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>Children are sorted by their sortOrder.</remarks>
|
|
|
|
|
|
public abstract IEnumerable<IPublishedContent> Children { get; }
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region ContentSet
|
|
|
|
|
|
|
|
|
|
|
|
public virtual IEnumerable<IPublishedContent> ContentSet
|
|
|
|
|
|
{
|
|
|
|
|
|
// the default content set of a content is its siblings
|
|
|
|
|
|
get { return this.Siblings(); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region ContentType
|
|
|
|
|
|
|
|
|
|
|
|
public abstract PublishedContentType ContentType { get; }
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Properties
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the properties of the content.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public abstract ICollection<IPublishedProperty> Properties { get; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets the value of a property identified by its alias.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="alias">The property alias.</param>
|
|
|
|
|
|
/// <returns>The value of the property identified by the alias.</returns>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// <para>If <c>GetProperty(alias)</c> is <c>null</c> then returns <c>null</c> else return <c>GetProperty(alias).Value</c>.</para>
|
|
|
|
|
|
/// <para>So if the property has no value, returns the default value for that property type.</para>
|
|
|
|
|
|
/// <para>This one is defined here really because we cannot define index extension methods, but all it should do is:
|
|
|
|
|
|
/// <code>var p = GetProperty(alias); return p == null ? null : p.Value;</code> and nothing else.</para>
|
|
|
|
|
|
/// <para>The recursive syntax (eg "_title") is _not_ supported here.</para>
|
|
|
|
|
|
/// <para>The alias is case-insensitive.</para>
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public virtual object this[string alias]
|
2012-12-09 03:22:11 +05:00
|
|
|
|
{
|
2012-12-10 03:40:50 +05:00
|
|
|
|
get
|
|
|
|
|
|
{
|
2013-09-05 17:47:13 +02:00
|
|
|
|
// no cache here: GetProperty should be fast, and .Value cache should be managed by the property.
|
|
|
|
|
|
var property = GetProperty(alias);
|
2013-09-25 13:16:37 +02:00
|
|
|
|
return property == null ? null : property.Value;
|
2012-12-10 03:40:50 +05:00
|
|
|
|
}
|
2012-12-09 03:22:11 +05:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-09-05 17:47:13 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets a property identified by its alias.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="alias">The property alias.</param>
|
|
|
|
|
|
/// <returns>The property identified by the alias.</returns>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// <para>If no property with the specified alias exists, returns <c>null</c>.</para>
|
|
|
|
|
|
/// <para>The returned property may have no value (ie <c>HasValue</c> is <c>false</c>).</para>
|
|
|
|
|
|
/// <para>The alias is case-insensitive.</para>
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public abstract IPublishedProperty GetProperty(string alias);
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets a property identified by its alias.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="alias">The property alias.</param>
|
|
|
|
|
|
/// <param name="recurse">A value indicating whether to navigate the tree upwards until a property with a value is found.</param>
|
|
|
|
|
|
/// <returns>The property identified by the alias.</returns>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// <para>Navigate the tree upwards and look for a property with that alias and with a value (ie <c>HasValue</c> is <c>true</c>).
|
|
|
|
|
|
/// If found, return the property. If no property with that alias is found, having a value or not, return <c>null</c>. Otherwise
|
|
|
|
|
|
/// return the first property that was found with the alias but had no value (ie <c>HasValue</c> is <c>false</c>).</para>
|
|
|
|
|
|
/// <para>The alias is case-insensitive.</para>
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
public virtual IPublishedProperty GetProperty(string alias, bool recurse)
|
|
|
|
|
|
{
|
|
|
|
|
|
var property = GetProperty(alias);
|
|
|
|
|
|
if (recurse == false) return property;
|
|
|
|
|
|
|
|
|
|
|
|
IPublishedContent content = this;
|
|
|
|
|
|
var firstNonNullProperty = property;
|
|
|
|
|
|
while (content != null && (property == null || property.HasValue == false))
|
|
|
|
|
|
{
|
|
|
|
|
|
content = content.Parent;
|
|
|
|
|
|
property = content == null ? null : content.GetProperty(alias);
|
|
|
|
|
|
if (firstNonNullProperty == null && property != null) firstNonNullProperty = property;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// if we find a content with the property with a value, return that property
|
|
|
|
|
|
// if we find no content with the property, return null
|
|
|
|
|
|
// if we find a content with the property without a value, return that property
|
|
|
|
|
|
// have to save that first property while we look further up, hence firstNonNullProperty
|
|
|
|
|
|
|
|
|
|
|
|
return property != null && property.HasValue ? property : firstNonNullProperty;
|
|
|
|
|
|
}
|
2013-03-02 01:02:38 +06:00
|
|
|
|
|
2013-09-05 17:47:13 +02:00
|
|
|
|
#endregion
|
2013-03-02 01:02:38 +06:00
|
|
|
|
}
|
2012-12-09 03:22:11 +05:00
|
|
|
|
}
|