Files
Umbraco-CMS/src/Umbraco.Web/PublishedCache/NuCache/Property.cs

163 lines
7.3 KiB
C#
Raw Normal View History

2016-05-27 14:26:28 +02:00
using System;
using System.Xml.Serialization;
using Umbraco.Core.Cache;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PublishedCache.NuCache
{
[Serializable]
[XmlType(Namespace = "http://umbraco.org/webservices/")]
2017-07-12 14:09:31 +02:00
internal class Property : PublishedPropertyBase
2016-05-27 14:26:28 +02:00
{
2017-10-31 12:48:24 +01:00
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
private readonly object _sourceValue;
2016-05-27 14:26:28 +02:00
private readonly Guid _contentUid;
private readonly bool _isPreviewing;
private readonly bool _isMember;
private readonly IPublishedContent _content;
2016-05-27 14:26:28 +02:00
private readonly object _locko = new object();
2016-05-27 14:26:28 +02:00
private bool _interInitialized;
private object _interValue;
private CacheValues _cacheValues;
private string _valuesCacheKey;
2016-05-27 14:26:28 +02:00
private string _recurseCacheKey;
// initializes a published content property with no value
2017-10-31 12:48:24 +01:00
public Property(PublishedPropertyType propertyType, PublishedContent content, IPublishedSnapshotAccessor publishedSnapshotAccessor, PropertyCacheLevel referenceCacheLevel = PropertyCacheLevel.Element)
: this(propertyType, content, null, publishedSnapshotAccessor, referenceCacheLevel)
2016-05-27 14:26:28 +02:00
{ }
// initializes a published content property with a value
2017-10-31 12:48:24 +01:00
public Property(PublishedPropertyType propertyType, PublishedContent content, object sourceValue, IPublishedSnapshotAccessor publishedSnapshotAccessor, PropertyCacheLevel referenceCacheLevel = PropertyCacheLevel.Element)
: base(propertyType, referenceCacheLevel)
2016-05-27 14:26:28 +02:00
{
_sourceValue = sourceValue;
2016-05-27 14:26:28 +02:00
_contentUid = content.Key;
_content = content;
_isPreviewing = content.IsPreviewing;
2016-05-27 14:26:28 +02:00
_isMember = content.ContentType.ItemType == PublishedItemType.Member;
2017-10-31 12:48:24 +01:00
_publishedSnapshotAccessor = publishedSnapshotAccessor;
2016-05-27 14:26:28 +02:00
}
// clone for previewing as draft a published content that is published and has no draft
public Property(Property origin, IPublishedContent content)
: base(origin.PropertyType, origin.ReferenceCacheLevel)
2016-05-27 14:26:28 +02:00
{
_sourceValue = origin._sourceValue;
2016-05-27 14:26:28 +02:00
_contentUid = origin._contentUid;
_content = content;
2016-05-27 14:26:28 +02:00
_isPreviewing = true;
_isMember = origin._isMember;
2017-10-31 12:48:24 +01:00
_publishedSnapshotAccessor = origin._publishedSnapshotAccessor;
2016-05-27 14:26:28 +02:00
}
2017-12-06 11:51:35 +01:00
public override bool HasValue(int? languageId = null, string segment = null) => _sourceValue != null
2017-07-27 11:09:53 +02:00
&& (!(_sourceValue is string) || string.IsNullOrWhiteSpace((string) _sourceValue) == false);
2016-05-27 14:26:28 +02:00
private class CacheValues
2016-05-27 14:26:28 +02:00
{
public bool ObjectInitialized;
public object ObjectValue;
2016-05-27 14:26:28 +02:00
public bool XPathInitialized;
public object XPathValue;
2016-05-27 14:26:28 +02:00
}
// used to cache the recursive *property* for this property
internal string RecurseCacheKey => _recurseCacheKey
2016-05-30 19:54:36 +02:00
?? (_recurseCacheKey = CacheKeys.PropertyRecurse(_contentUid, PropertyTypeAlias, _isPreviewing));
2016-05-27 14:26:28 +02:00
// used to cache the CacheValues of this property
internal string ValuesCacheKey => _valuesCacheKey
?? (_valuesCacheKey = CacheKeys.PropertyCacheValues(_contentUid, PropertyTypeAlias, _isPreviewing));
2016-05-27 14:26:28 +02:00
private CacheValues GetCacheValues(PropertyCacheLevel cacheLevel)
2016-05-27 14:26:28 +02:00
{
CacheValues cacheValues;
2017-10-31 12:48:24 +01:00
PublishedShapshot publishedSnapshot;
2016-05-27 14:26:28 +02:00
ICacheProvider cache;
switch (cacheLevel)
{
case PropertyCacheLevel.None:
// never cache anything
cacheValues = new CacheValues();
2016-05-27 14:26:28 +02:00
break;
2017-10-31 12:48:24 +01:00
case PropertyCacheLevel.Element:
2016-05-27 14:26:28 +02:00
// cache within the property object itself, ie within the content object
cacheValues = _cacheValues ?? (_cacheValues = new CacheValues());
2016-05-27 14:26:28 +02:00
break;
2017-10-31 12:48:24 +01:00
case PropertyCacheLevel.Elements:
// cache within the elements cache, unless previewing, then use the snapshot or
// elements cache (if we don't want to pollute the elements cache with short-lived
2016-05-27 14:26:28 +02:00
// data) depending on settings
2017-10-31 12:48:24 +01:00
// for members, always cache in the snapshot cache - never pollute elements cache
publishedSnapshot = (PublishedShapshot) _publishedSnapshotAccessor.PublishedSnapshot;
cache = publishedSnapshot == null
? null
2017-10-31 12:48:24 +01:00
: ((_isPreviewing == false || PublishedSnapshotService.FullCacheWhenPreviewing) && (_isMember == false)
? publishedSnapshot.ElementsCache
: publishedSnapshot.SnapshotCache);
cacheValues = GetCacheValues(cache);
2016-05-27 14:26:28 +02:00
break;
2017-10-31 12:48:24 +01:00
case PropertyCacheLevel.Snapshot:
// cache within the snapshot cache
publishedSnapshot = (PublishedShapshot) _publishedSnapshotAccessor.PublishedSnapshot;
cache = publishedSnapshot?.SnapshotCache;
cacheValues = GetCacheValues(cache);
2016-05-27 14:26:28 +02:00
break;
default:
throw new InvalidOperationException("Invalid cache level.");
}
return cacheValues;
2016-05-27 14:26:28 +02:00
}
private CacheValues GetCacheValues(ICacheProvider cache)
2016-05-27 14:26:28 +02:00
{
if (cache == null) // no cache, don't cache
return new CacheValues();
return (CacheValues) cache.GetCacheItem(ValuesCacheKey, () => new CacheValues());
2016-05-27 14:26:28 +02:00
}
private object GetInterValue()
2016-05-27 14:26:28 +02:00
{
if (_interInitialized) return _interValue;
_interValue = PropertyType.ConvertSourceToInter(_content, _sourceValue, _isPreviewing);
_interInitialized = true;
return _interValue;
2016-05-27 14:26:28 +02:00
}
2017-12-06 11:51:35 +01:00
public override object GetSourceValue(int? languageId = null, string segment = null) => _sourceValue;
2016-05-27 14:26:28 +02:00
2017-12-06 11:51:35 +01:00
public override object GetValue(int? languageId = null, string segment = null)
2016-05-27 14:26:28 +02:00
{
2017-12-06 11:51:35 +01:00
lock (_locko)
2016-05-27 14:26:28 +02:00
{
2017-12-06 11:51:35 +01:00
var cacheValues = GetCacheValues(PropertyType.CacheLevel);
if (cacheValues.ObjectInitialized) return cacheValues.ObjectValue;
// initial reference cache level always is .Content
cacheValues.ObjectValue = PropertyType.ConvertInterToObject(_content, PropertyCacheLevel.Element, GetInterValue(), _isPreviewing);
cacheValues.ObjectInitialized = true;
return cacheValues.ObjectValue;
2016-05-27 14:26:28 +02:00
}
}
2017-12-06 11:51:35 +01:00
public override object GetXPathValue(int? languageId = null, string segment = null)
2016-05-27 14:26:28 +02:00
{
2017-12-06 11:51:35 +01:00
lock (_locko)
2016-05-27 14:26:28 +02:00
{
2017-12-06 11:51:35 +01:00
var cacheValues = GetCacheValues(PropertyType.CacheLevel);
if (cacheValues.XPathInitialized) return cacheValues.XPathValue;
// initial reference cache level always is .Content
cacheValues.XPathValue = PropertyType.ConvertInterToXPath(_content, PropertyCacheLevel.Element, GetInterValue(), _isPreviewing);
cacheValues.XPathInitialized = true;
return cacheValues.XPathValue;
2016-05-27 14:26:28 +02:00
}
}
}
}