U4-6674 - Kill ToContentSet, becomes ToIndexedArray

This commit is contained in:
Stephan
2016-06-09 20:13:20 +02:00
parent cfa91f000b
commit be2d81154b
18 changed files with 626 additions and 1826 deletions

View File

@@ -16,21 +16,6 @@ namespace Umbraco.Core.Models
/// </remarks>
public interface IPublishedContent
{
#region ContentSet
// Because of http://issues.umbraco.org/issue/U4-1797 and in order to implement
// Index() and methods that derive from it such as IsFirst(), IsLast(), etc... all
// content items must know about their containing content set.
/// <summary>
/// Gets the content set to which the content belongs.
/// </summary>
/// <remarks>The default set consists in the siblings of the content (including the content
/// itself) ordered by <c>sortOrder</c>.</remarks>
IEnumerable<IPublishedContent> ContentSet { get; }
#endregion
#region ContentType
/// <summary>
@@ -73,12 +58,6 @@ namespace Umbraco.Core.Models
/// have a published version, or not.</remarks>
bool IsDraft { get; }
/// <summary>
/// Gets the index of the published content within its current owning content set.
/// </summary>
/// <returns>The index of the published content within its current owning content set.</returns>
int GetIndex();
#endregion
#region Tree

View File

@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Umbraco.Core.Models.PublishedContent
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Provides methods to handle extended content.
@@ -20,27 +15,5 @@ namespace Umbraco.Core.Models.PublishedContent
/// Gets a value indicating whether properties were added to the extended content.
/// </summary>
bool HasAddedProperties { get; }
/// <summary>
/// Sets the content set of the extended content.
/// </summary>
/// <param name="contentSet"></param>
void SetContentSet(IEnumerable<IPublishedContent> contentSet);
/// <summary>
/// Resets the content set of the extended content.
/// </summary>
void ClearContentSet();
/// <summary>
/// Sets the index of the extended content.
/// </summary>
/// <param name="value">The index value.</param>
void SetIndex(int value);
/// <summary>
/// Resets the index of the extended content.
/// </summary>
void ClearIndex();
}
}

View File

@@ -0,0 +1,172 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Umbraco.Core.Models.PublishedContent
{
public class IndexedArrayItem<TContent>
{
public IndexedArrayItem(TContent content, int index)
{
Content = content;
Index = index;
}
public TContent Content { get; }
public int Index { get; }
public int TotalCount { get; internal set; }
public bool IsFirst()
{
return Index == 0;
}
public HtmlString IsFirst(string valueIfTrue)
{
return IsFirst(valueIfTrue, string.Empty);
}
public HtmlString IsFirst(string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsFirst() ? valueIfTrue : valueIfFalse);
}
public bool IsNotFirst()
{
return IsFirst() == false;
}
public HtmlString IsNotFirst(string valueIfTrue)
{
return IsNotFirst(valueIfTrue, string.Empty);
}
public HtmlString IsNotFirst(string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsNotFirst() ? valueIfTrue : valueIfFalse);
}
public bool IsIndex(int index)
{
return Index == index;
}
public HtmlString IsIndex(int index, string valueIfTrue)
{
return IsIndex(index, valueIfTrue, string.Empty);
}
public HtmlString IsIndex(int index, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsIndex(index) ? valueIfTrue : valueIfFalse);
}
public bool IsModZero(int modulus)
{
return Index % modulus == 0;
}
public HtmlString IsModZero(int modulus, string valueIfTrue)
{
return IsModZero(modulus, valueIfTrue, string.Empty);
}
public HtmlString IsModZero(int modulus, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsModZero(modulus) ? valueIfTrue : valueIfFalse);
}
public bool IsNotModZero(int modulus)
{
return IsModZero(modulus) == false;
}
public HtmlString IsNotModZero(int modulus, string valueIfTrue)
{
return IsNotModZero(modulus, valueIfTrue, string.Empty);
}
public HtmlString IsNotModZero(int modulus, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsNotModZero(modulus) ? valueIfTrue : valueIfFalse);
}
public bool IsNotIndex(int index)
{
return IsIndex(index) == false;
}
public HtmlString IsNotIndex(int index, string valueIfTrue)
{
return IsNotIndex(index, valueIfTrue, string.Empty);
}
public HtmlString IsNotIndex(int index, string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsNotIndex(index) ? valueIfTrue : valueIfFalse);
}
public bool IsLast()
{
return Index == TotalCount - 1;
}
public HtmlString IsLast(string valueIfTrue)
{
return IsLast(valueIfTrue, string.Empty);
}
public HtmlString IsLast(string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsLast() ? valueIfTrue : valueIfFalse);
}
public bool IsNotLast()
{
return IsLast() == false;
}
public HtmlString IsNotLast(string valueIfTrue)
{
return IsNotLast(valueIfTrue, string.Empty);
}
public HtmlString IsNotLast(string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsNotLast() ? valueIfTrue : valueIfFalse);
}
public bool IsEven()
{
return Index % 2 == 0;
}
public HtmlString IsEven(string valueIfTrue)
{
return IsEven(valueIfTrue, string.Empty);
}
public HtmlString IsEven(string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsEven() ? valueIfTrue : valueIfFalse);
}
public bool IsOdd()
{
return Index % 2 == 1;
}
public HtmlString IsOdd(string valueIfTrue)
{
return IsOdd(valueIfTrue, string.Empty);
}
public HtmlString IsOdd(string valueIfTrue, string valueIfFalse)
{
return new HtmlString(IsOdd() ? valueIfTrue : valueIfFalse);
}
}
}

View File

@@ -17,31 +17,9 @@ namespace Umbraco.Core.Models.PublishedContent
#endregion
#region Index
private int? _index;
public override int GetIndex()
{
// fast
if (_index.HasValue) return _index.Value;
// slow -- and don't cache, not in a set
if (_contentSet == null) return Content.GetIndex();
// slow -- but cache for next time
var index = _contentSet.FindIndex(x => x.Id == Id);
if (index < 0)
throw new IndexOutOfRangeException("Could not find content in the content set.");
_index = index;
return index;
}
#endregion
#region Extend
internal static IPublishedContentExtended Extend(IPublishedContent content, IEnumerable<IPublishedContent> contentSet)
internal static IPublishedContentExtended Extend(IPublishedContent content)
{
// first unwrap content down to the lowest possible level, ie either the deepest inner
// IPublishedContent or the first extended that has added properties. this is to avoid
@@ -95,7 +73,6 @@ namespace Umbraco.Core.Models.PublishedContent
var extended2 = extended as IPublishedContentExtended;
if (extended2 == null)
throw new Exception("Extended does not implement IPublishedContentExtended.");
extended2.SetContentSet(contentSet);
return extended2;
}
@@ -115,37 +92,6 @@ namespace Umbraco.Core.Models.PublishedContent
get { return _properties != null; }
}
void IPublishedContentExtended.SetContentSet(IEnumerable<IPublishedContent> contentSet)
{
_contentSet = contentSet;
}
void IPublishedContentExtended.ClearContentSet()
{
_contentSet = null;
}
void IPublishedContentExtended.SetIndex(int value)
{
_index = value;
}
void IPublishedContentExtended.ClearIndex()
{
_index = null;
}
#endregion
#region Content set
private IEnumerable<IPublishedContent> _contentSet;
public override IEnumerable<IPublishedContent> ContentSet
{
get { return _contentSet ?? Content.ContentSet; }
}
#endregion
#region Properties

View File

@@ -1,32 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Represents an ordered set of <see cref="IPublishedContent"/>.
/// </summary>
/// <typeparam name="T">The type of content.</typeparam>
public class PublishedContentOrderedSet<T> : PublishedContentSet<T>, IOrderedEnumerable<T>
where T : class, IPublishedContent
{
// ReSharper disable ParameterTypeCanBeEnumerable.Local
internal PublishedContentOrderedSet(IOrderedEnumerable<T> content)
// ReSharper restore ParameterTypeCanBeEnumerable.Local
: base(content)
{ }
// note: because we implement IOrderedEnumerable, we don't need to implement the ThenBy nor
// ThenByDescending methods here, only CreateOrderedEnumerable and that does it.
#region IOrderedEnumerable<T>
public IOrderedEnumerable<T> CreateOrderedEnumerable<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer, bool descending)
{
return new PublishedContentOrderedSet<T>(((IOrderedEnumerable<T>)Source).CreateOrderedEnumerable(keySelector, comparer, descending));
}
#endregion
}
}

View File

@@ -1,234 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Represents a set of <see cref="IPublishedContent"/>.
/// </summary>
/// <typeparam name="T">The type of content.</typeparam>
/// <remarks>
/// <para>A <c>ContentSet{T}</c> is created from an <c>IEnumerable{T}</c> using the <c>ToContentSet</c>
/// extension method.</para>
/// <para>The content set source is enumerated only once. Same as what you get
/// when you call ToList on an IEnumerable. Only, ToList enumerates its source when
/// created, whereas a content set enumerates its source only when the content set itself
/// is enumerated.</para>
/// </remarks>
public class PublishedContentSet<T> : IEnumerable<T>
where T : class, IPublishedContent
{
// used by <c>ToContentSet</c> extension method to initialize a new set from an IEnumerable.
internal PublishedContentSet(IEnumerable<T> source)
{
if (source == null)
throw new ArgumentNullException("source");
Source = source;
}
#region Source
protected readonly IEnumerable<T> Source;
#endregion
#region Enumerated
// cache the enumeration so we don't enumerate more than once. Same as what you get
// when you call ToList on an IEnumerable. Only, ToList enumerates its source when
// created, whereas a content set enumerates its source only when the content set itself
// is enumerated.
// cache the wrapped items so if we reset the enumeration, we do not re-wrap everything (only new items).
private T[] _enumerated;
private readonly Dictionary<T, IPublishedContentExtended> _xContent = new Dictionary<T, IPublishedContentExtended>();
// wrap an item, ie create the actual clone for this set
private T MapContentAsT(T t)
{
return MapContent(t) as T;
}
internal IPublishedContentExtended MapContent(T t)
{
IPublishedContentExtended extend;
if (_xContent.TryGetValue(t, out extend)) return extend;
extend = PublishedContentExtended.Extend(t, this);
var asT = extend as T;
if (asT == null)
throw new InvalidOperationException(string.Format("Failed extend a published content of type {0}."
+ "Got {1} when expecting {2}.", t.GetType().FullName, extend.GetType().FullName, typeof(T).FullName));
_xContent[t] = extend;
return extend;
}
private T[] Enumerated
{
get
{
// enumerate the source and cache the result
// tell clones about their index within the set (for perfs purposes)
var index = 0;
return _enumerated ?? (_enumerated = Source.Select(t =>
{
var extend = MapContent(t);
extend.SetIndex(index++);
return extend as T;
}).ToArray());
}
}
// indicates that the source has changed
// so the set can clear its inner caches
// should only be used by DynamicPublishedContentList
internal void SourceChanged()
{
// reset the cached enumeration so it's enumerated again
if (_enumerated == null) return;
_enumerated = null;
foreach (var item in _xContent.Values)
item.ClearIndex();
var removed = _xContent.Keys.Except(Source);
foreach (var content in removed)
{
_xContent[content].ClearContentSet();
_xContent.Remove(content);
}
}
/// <summary>
/// Gets the number of items in the set.
/// </summary>
/// <returns>The number of items in the set.</returns>
/// <remarks>Will cause the set to be enumerated if it hasn't been already.</remarks>
public virtual int Count
{
get { return Enumerated.Length; }
}
#endregion
#region IEnumerable<T>
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)Enumerated).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
#region Wrap methods returning T
public T ElementAt(int index)
{
return MapContentAsT(Source.ElementAt(index));
}
public T ElementAtOrDefault(int index)
{
var element = Source.ElementAtOrDefault(index);
return element == null ? null : MapContentAsT(element);
}
public T First()
{
return MapContentAsT(Source.First());
}
public T First(Func<T, bool> predicate)
{
return MapContentAsT(Source.First(predicate));
}
public T FirstOrDefault()
{
var first = Source.FirstOrDefault();
return first == null ? null : MapContentAsT(first);
}
public T FirstOrDefault(Func<T, bool> predicate)
{
var first = Source.FirstOrDefault(predicate);
return first == null ? null : MapContentAsT(first);
}
public T Last()
{
return MapContentAsT(Source.Last());
}
public T Last(Func<T, bool> predicate)
{
return MapContentAsT(Source.Last(predicate));
}
public T LastOrDefault()
{
var last = Source.LastOrDefault();
return last == null ? null : MapContentAsT(last);
}
public T LastOrDefault(Func<T, bool> predicate)
{
var last = Source.LastOrDefault(predicate);
return last == null ? null : MapContentAsT(last);
}
public T Single()
{
return MapContentAsT(Source.Single());
}
public T Single(Func<T, bool> predicate)
{
return MapContentAsT(Source.Single(predicate));
}
public T SingleOrDefault()
{
var single = Source.SingleOrDefault();
return single == null ? null : MapContentAsT(single);
}
public T SingleOrDefault(Func<T, bool> predicate)
{
var single = Source.SingleOrDefault(predicate);
return single == null ? null : MapContentAsT(single);
}
#endregion
#region Wrap methods returning IOrderedEnumerable<T>
public PublishedContentOrderedSet<T> OrderBy<TKey>(Func<T, TKey> keySelector)
{
return new PublishedContentOrderedSet<T>(Source.OrderBy(keySelector));
}
public PublishedContentOrderedSet<T> OrderBy<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
{
return new PublishedContentOrderedSet<T>(Source.OrderBy(keySelector, comparer));
}
public PublishedContentOrderedSet<T> OrderByDescending<TKey>(Func<T, TKey> keySelector)
{
return new PublishedContentOrderedSet<T>(Source.OrderByDescending(keySelector));
}
public PublishedContentOrderedSet<T> OrderByDescending<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
{
return new PublishedContentOrderedSet<T>(Source.OrderByDescending(keySelector, comparer));
}
#endregion
}
}

View File

@@ -48,12 +48,6 @@ namespace Umbraco.Core.Models.PublishedContent
return Content;
}
#region ContentSet
public virtual IEnumerable<IPublishedContent> ContentSet => Content.ContentSet;
#endregion
#region ContentType
public virtual PublishedContentType ContentType => Content.ContentType;
@@ -102,11 +96,6 @@ namespace Umbraco.Core.Models.PublishedContent
public virtual bool IsDraft => Content.IsDraft;
public virtual int GetIndex()
{
return Content.GetIndex();
}
#endregion
#region Tree