Files
Umbraco-CMS/src/Umbraco.Core/PublishedCache/PublishedElementPropertyBase.cs
Mole 1258962429 V15: Remove Nucache (#17166)
* Remove nucache reference from Web.Common

* Get tests building-ish

* Move ReservedFieldNamesService to the right project

* Remove IPublishedSnapshotStatus

* Added functionality to the INavigationQueryService to get root keys

* Fixed issue with navigation

* Remove IPublishedSnapshot from UmbracoContext

* Begin removing usage of IPublishedSnapshot from PublishedContentExtensions

* Fix PublishedContentExtensions.cs

* Don't use snapshots in delivery media api

* Use IPublishedMediaCache in QueryMediaApiController

* Remove more usages of IPublishedSnapshotAccessor

* Comment out tests

* Remove more usages of PublishedSnapshotAccessor

* Remove PublishedSnapshot from property

* Fixed test build

* Fix errors

* Fix some tests

* Delete NuCache 🎉

* Implement DatabaseCacheRebuilder

* Remove usage of IPublishedSnapshotService

* Remove IPublishedSnapshotService

* Remove TestPublishedSnapshotAccessor and make tests build

* Don't test Snapshot cachelevel

It's no longer supported

* Fix BlockEditorConverter

Element != Element document type

* Remember to set cachemanager

* Fix RichTextParserTests

* Implement TryGetLevel on INavigationQueryService

* Fake level and obsolete it in PublishedContent

* Remove ChildrenForAllCultures

* Hack Path property on PublishedContent

* Remove usages of IPublishedSnapshot in tests

* More ConvertersTests

* Add hybrid cache to integration tests

We can actually do this now because we no longer save files on disk

* Rename IPublishedSnapshotRebuilder to ICacheRebuilder

* Comment out tests

* V15: Replacing the usages of Parent (navigation data) from IPublishedContent (#17125)

* Fix .Parent references in PublishedContentExtensions

* Add missing methods to FriendlyPublishedContentExtensions (ones that you were able to call on the content directly as they now require extra params)

* Fix references from the extension methods

* Fix dependencies in tests

* Replace IPublishedSnapshotAccessor with the content cache in tests

* Resolving more .Parent references

* Fix unit tests

* Obsolete and use extension methods

* Remove private method and use extension instead

* Moving code around

* Fix tests

* Fix more references

* Cleanup

* Fix more usages

* Resolve merge conflict

* Fix tests

* Cleanup

* Fix more tests

* Fixed unit tests

* Cleanup

* Replace last usages

---------

Co-authored-by: Bjarke Berg <mail@bergmania.dk>

* Remove usage of IPublishedSnapshotAccessor from IRequestItemProvider

* Post merge fixup

* Remo IPublishedSnapshot

* Add HasAny to IDocumentUrlService

* Fix TextBuilder

* Fix modelsbuilder tests

* Use explicit types

* Implement GetByContentType

* Support element types in PublishedContentTypeCache

* Run enlistments before publishing notifications

* Fix elements cache refreshing

* Implement GetByUdi

* Implement GetAtRoot

* Implement GetByRoute

* Reimplement GetRouteById

* Fix blocks unit tests

* Initialize domain cache on boot

* Only return routes with domains on non default lanauges

* V15: Replacing the usages of `Children` (navigation data) from `IPublishedContent` (#17159)

* Update params in PublishedContentExtensions to the general interfaces for the published cache and navigation service, so that we can use the extension methods on both documents and media

* Introduce GetParent() which uses the right services

* Fix obsolete message on .Parent

* Obsolete .Children

* Fix usages of Children for ApiMediaQueryService

* Fix usage in internal

* Fix usages in views

* Fix indentation

* Fix issue with delete language

* Update nuget pacakges

* Clear elements cache when content is deleted

instead of trying to update it

* Reset publishedModelFactory

* Fixed publishing

---------

Co-authored-by: Bjarke Berg <mail@bergmania.dk>
Co-authored-by: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com>
Co-authored-by: kjac <kja@umbraco.dk>
2024-10-01 15:03:02 +02:00

234 lines
9.0 KiB
C#

using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.PublishedCache;
internal class PublishedElementPropertyBase : PublishedPropertyBase
{
protected readonly IPublishedElement Element;
// define constant - determines whether to use cache when previewing
// to store eg routes, property converted values, anything - caching
// means faster execution, but uses memory - not sure if we want it
// so making it configurable.
private const bool FullCacheWhenPreviewing = true;
private readonly object _locko = new();
private readonly object? _sourceValue;
protected readonly bool IsMember;
protected readonly bool IsPreviewing;
private readonly ICacheManager? _cacheManager;
private CacheValues? _cacheValues;
private bool _interInitialized;
private object? _interValue;
private string? _valuesCacheKey;
public PublishedElementPropertyBase(
IPublishedPropertyType propertyType,
IPublishedElement element,
bool previewing,
PropertyCacheLevel referenceCacheLevel,
ICacheManager? cacheManager,
object? sourceValue = null)
: base(propertyType, referenceCacheLevel)
{
_sourceValue = sourceValue;
Element = element;
IsPreviewing = previewing;
_cacheManager = cacheManager;
IsMember = propertyType.ContentType?.ItemType == PublishedItemType.Member;
}
// used to cache the CacheValues of this property
// ReSharper disable InconsistentlySynchronizedField
internal string ValuesCacheKey => _valuesCacheKey ??= PropertyCacheValues(Element.Key, Alias, IsPreviewing);
public static string PropertyCacheValues(Guid contentUid, string typeAlias, bool previewing) =>
"PublishedSnapshot.Property.CacheValues[" + (previewing ? "D:" : "P:") + contentUid + ":" + typeAlias + "]";
// ReSharper restore InconsistentlySynchronizedField
public override bool HasValue(string? culture = null, string? segment = null)
{
var hasValue = PropertyType.IsValue(_sourceValue, PropertyValueLevel.Source);
if (hasValue.HasValue)
{
return hasValue.Value;
}
GetCacheLevels(out PropertyCacheLevel cacheLevel, out PropertyCacheLevel referenceCacheLevel);
lock (_locko)
{
var value = GetInterValue();
hasValue = PropertyType.IsValue(value, PropertyValueLevel.Inter);
if (hasValue.HasValue)
{
return hasValue.Value;
}
CacheValues cacheValues = GetCacheValues(cacheLevel);
if (!cacheValues.ObjectInitialized)
{
cacheValues.ObjectValue =
PropertyType.ConvertInterToObject(Element, referenceCacheLevel, value, IsPreviewing);
cacheValues.ObjectInitialized = true;
}
value = cacheValues.ObjectValue;
return PropertyType.IsValue(value, PropertyValueLevel.Object) ?? false;
}
}
public override object? GetSourceValue(string? culture = null, string? segment = null) => _sourceValue;
private void GetCacheLevels(out PropertyCacheLevel cacheLevel, out PropertyCacheLevel referenceCacheLevel)
=> GetCacheLevels(PropertyType.CacheLevel, out cacheLevel, out referenceCacheLevel);
private void GetDeliveryApiCacheLevels(out PropertyCacheLevel cacheLevel, out PropertyCacheLevel referenceCacheLevel)
=> GetCacheLevels(PropertyType.DeliveryApiCacheLevel, out cacheLevel, out referenceCacheLevel);
private void GetDeliveryApiCacheLevelsForExpansion(out PropertyCacheLevel cacheLevel, out PropertyCacheLevel referenceCacheLevel)
=> GetCacheLevels(PropertyType.DeliveryApiCacheLevelForExpansion, out cacheLevel, out referenceCacheLevel);
private void GetCacheLevels(PropertyCacheLevel propertyTypeCacheLevel, 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.
// 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 published snapshot, property specifies
// elements, ok to use element. OTOH, currently caching at elements,
// property specifies snapshot, need to use snapshot.
if (propertyTypeCacheLevel > ReferenceCacheLevel || propertyTypeCacheLevel == PropertyCacheLevel.None)
{
cacheLevel = propertyTypeCacheLevel;
referenceCacheLevel = cacheLevel;
}
else
{
cacheLevel = PropertyCacheLevel.Element;
referenceCacheLevel = ReferenceCacheLevel;
}
}
private CacheValues GetCacheValues(PropertyCacheLevel cacheLevel)
{
CacheValues cacheValues;
switch (cacheLevel)
{
case PropertyCacheLevel.None:
case PropertyCacheLevel.Snapshot:
// never cache anything
cacheValues = new CacheValues();
break;
case PropertyCacheLevel.Element:
// cache within the property object itself, ie within the content object
cacheValues = _cacheValues ??= new CacheValues();
break;
case PropertyCacheLevel.Elements:
cacheValues = (CacheValues?)_cacheManager?.ElementsCache.Get(ValuesCacheKey, () => new CacheValues()) ??
new CacheValues();
break;
default:
throw new InvalidOperationException("Invalid cache level.");
}
return cacheValues;
}
private object? GetInterValue()
{
if (_interInitialized)
{
return _interValue;
}
_interValue = PropertyType.ConvertSourceToInter(Element, _sourceValue, IsPreviewing);
_interInitialized = true;
return _interValue;
}
public override object? GetValue(string? culture = null, string? segment = null)
{
GetCacheLevels(out PropertyCacheLevel cacheLevel, out PropertyCacheLevel referenceCacheLevel);
lock (_locko)
{
CacheValues cacheValues = GetCacheValues(cacheLevel);
if (cacheValues.ObjectInitialized)
{
return cacheValues.ObjectValue;
}
cacheValues.ObjectValue =
PropertyType.ConvertInterToObject(Element, referenceCacheLevel, GetInterValue(), IsPreviewing);
cacheValues.ObjectInitialized = true;
return cacheValues.ObjectValue;
}
}
public override object? GetDeliveryApiValue(bool expanding, string? culture = null, string? segment = null)
{
PropertyCacheLevel cacheLevel, referenceCacheLevel;
if (expanding)
{
GetDeliveryApiCacheLevelsForExpansion(out cacheLevel, out referenceCacheLevel);
}
else
{
GetDeliveryApiCacheLevels(out cacheLevel, out referenceCacheLevel);
}
lock (_locko)
{
CacheValues cacheValues = GetCacheValues(cacheLevel);
object? GetDeliveryApiObject() => PropertyType.ConvertInterToDeliveryApiObject(Element, referenceCacheLevel, GetInterValue(), IsPreviewing, expanding);
return expanding
? GetDeliveryApiExpandedObject(cacheValues, GetDeliveryApiObject)
: GetDeliveryApiDefaultObject(cacheValues, GetDeliveryApiObject);
}
}
private object? GetDeliveryApiDefaultObject(CacheValues cacheValues, Func<object?> getValue)
{
if (cacheValues.DeliveryApiDefaultObjectInitialized == false)
{
cacheValues.DeliveryApiDefaultObjectValue = getValue();
cacheValues.DeliveryApiDefaultObjectInitialized = true;
}
return cacheValues.DeliveryApiDefaultObjectValue;
}
private object? GetDeliveryApiExpandedObject(CacheValues cacheValues, Func<object?> getValue)
{
if (cacheValues.DeliveryApiExpandedObjectInitialized == false)
{
cacheValues.DeliveryApiExpandedObjectValue = getValue();
cacheValues.DeliveryApiExpandedObjectInitialized = true;
}
return cacheValues.DeliveryApiExpandedObjectValue;
}
protected class CacheValues
{
public bool ObjectInitialized;
public object? ObjectValue;
public bool XPathInitialized;
public object? XPathValue;
public bool DeliveryApiDefaultObjectInitialized;
public object? DeliveryApiDefaultObjectValue;
public bool DeliveryApiExpandedObjectInitialized;
public object? DeliveryApiExpandedObjectValue;
}
}