Files
Umbraco-CMS/src/Umbraco.Web/PublishedCache/PublishedFragmentPropertyBase.cs

166 lines
6.2 KiB
C#
Raw Normal View History

using System;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PublishedCache
{
internal abstract class PublishedFragmentPropertyBase : PublishedPropertyBase
{
private readonly object _locko = new object();
private readonly object _sourceValue;
protected readonly Guid FragmentKey;
protected readonly bool IsPreviewing;
protected readonly bool IsMember;
private bool _interInitialized;
private object _interValue;
private CacheValues _cacheValues;
// initializes a published item property
protected PublishedFragmentPropertyBase(PublishedPropertyType propertyType, Guid fragmentKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null)
: base(propertyType, referenceCacheLevel)
{
_sourceValue = sourceValue;
FragmentKey = fragmentKey;
IsPreviewing = previewing;
IsMember = propertyType.ContentType.ItemType == PublishedItemType.Member;
}
public override bool HasValue => _sourceValue != null
&& ((_sourceValue is string) == false || string.IsNullOrWhiteSpace((string)_sourceValue) == false);
protected class CacheValues
{
public bool ObjectInitialized;
public object ObjectValue;
public bool XPathInitialized;
public object XPathValue;
}
private static void ValidateCacheLevel(PropertyCacheLevel cacheLevel)
{
switch (cacheLevel)
{
case PropertyCacheLevel.Content:
case PropertyCacheLevel.Snapshot:
case PropertyCacheLevel.Facade:
case PropertyCacheLevel.None:
break;
default:
throw new Exception("Invalid cache level.");
}
}
private void GetCacheLevels(out PropertyCacheLevel cacheLevel, out PropertyCacheLevel referenceCacheLevel)
{
// based upon the current reference cache level (ReferenceCacheLevel) and this property
// cache level (PropertyType.CacheLevel), determines both the actual cache level for the
// property, and the new reference cache level.
// sanity checks
ValidateCacheLevel(ReferenceCacheLevel);
ValidateCacheLevel(PropertyType.CacheLevel);
// if the property cache level is 'shorter-termed' that the reference
// then use it and it becomes the new reference, else use Content and
// don't change the reference.
//
// examples:
// currently (reference) caching at facade, property specifies
// snapshot, ok to use content. OTOH, currently caching at snapshot,
// property specifies facade, need to use facade.
//
if (PropertyType.CacheLevel > ReferenceCacheLevel)
{
cacheLevel = PropertyType.CacheLevel;
referenceCacheLevel = cacheLevel;
}
else
{
cacheLevel = PropertyCacheLevel.Content;
referenceCacheLevel = ReferenceCacheLevel;
}
}
protected abstract CacheValues GetSnapshotCacheValues();
protected abstract CacheValues GetFacadeCacheValues();
private CacheValues GetCacheValues(PropertyCacheLevel cacheLevel)
{
CacheValues cacheValues;
switch (cacheLevel)
{
case PropertyCacheLevel.None:
// never cache anything
cacheValues = new CacheValues();
break;
case PropertyCacheLevel.Content:
// cache within the property object itself, ie within the content object
cacheValues = _cacheValues ?? (_cacheValues = new CacheValues());
break;
case PropertyCacheLevel.Snapshot:
// cache within the snapshot cache, depending...
cacheValues = GetSnapshotCacheValues();
break;
case PropertyCacheLevel.Facade:
// cache within the facade cache
cacheValues = GetFacadeCacheValues();
break;
default:
throw new InvalidOperationException("Invalid cache level.");
}
return cacheValues;
}
private object GetInterValue()
{
if (_interInitialized) return _interValue;
_interValue = PropertyType.ConvertSourceToInter(_sourceValue, IsPreviewing);
_interInitialized = true;
return _interValue;
}
public override object SourceValue => _sourceValue;
public override object Value
{
get
{
lock (_locko)
{
PropertyCacheLevel cacheLevel, referenceCacheLevel;
GetCacheLevels(out cacheLevel, out referenceCacheLevel);
var cacheValues = GetCacheValues(cacheLevel);
if (cacheValues.ObjectInitialized) return cacheValues.ObjectValue;
cacheValues.ObjectValue = PropertyType.ConvertInterToObject(referenceCacheLevel, GetInterValue(), IsPreviewing);
cacheValues.ObjectInitialized = true;
return cacheValues.ObjectValue;
}
}
}
public override object XPathValue
{
get
{
lock (_locko)
{
PropertyCacheLevel cacheLevel, referenceCacheLevel;
GetCacheLevels(out cacheLevel, out referenceCacheLevel);
var cacheValues = GetCacheValues(cacheLevel);
if (cacheValues.XPathInitialized) return cacheValues.XPathValue;
cacheValues.XPathValue = PropertyType.ConvertInterToXPath(referenceCacheLevel, GetInterValue(), IsPreviewing);
cacheValues.XPathInitialized = true;
return cacheValues.XPathValue;
}
}
}
}
2017-07-20 11:21:28 +02:00
}