2016-05-27 14:26:28 +02:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using Umbraco.Core;
|
|
|
|
|
|
using Umbraco.Core.Cache;
|
2019-08-16 16:18:58 +10:00
|
|
|
|
using Umbraco.Core.Exceptions;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
using Umbraco.Core.Models.PublishedContent;
|
2017-05-30 18:13:11 +02:00
|
|
|
|
using Umbraco.Web.Composing;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
using Umbraco.Web.Models;
|
|
|
|
|
|
using Umbraco.Web.PublishedCache.NuCache.DataSource;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Umbraco.Web.PublishedCache.NuCache
|
|
|
|
|
|
{
|
2016-06-09 19:38:51 +02:00
|
|
|
|
internal class PublishedContent : PublishedContentBase
|
2016-05-27 14:26:28 +02:00
|
|
|
|
{
|
2017-10-31 12:48:24 +01:00
|
|
|
|
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
private readonly ContentNode _contentNode;
|
2018-04-28 16:34:43 +02:00
|
|
|
|
private readonly string _urlSegment;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
|
|
|
|
|
#region Constructors
|
|
|
|
|
|
|
2019-01-23 14:16:42 +01:00
|
|
|
|
public PublishedContent(
|
|
|
|
|
|
ContentNode contentNode,
|
|
|
|
|
|
ContentData contentData,
|
|
|
|
|
|
IPublishedSnapshotAccessor publishedSnapshotAccessor,
|
2019-04-24 14:25:41 +02:00
|
|
|
|
IVariationContextAccessor variationContextAccessor)
|
2016-05-27 14:26:28 +02:00
|
|
|
|
{
|
2019-02-15 19:32:13 +01:00
|
|
|
|
_contentNode = contentNode ?? throw new ArgumentNullException(nameof(contentNode));
|
|
|
|
|
|
ContentData = contentData ?? throw new ArgumentNullException(nameof(contentData));
|
|
|
|
|
|
_publishedSnapshotAccessor = publishedSnapshotAccessor ?? throw new ArgumentNullException(nameof(publishedSnapshotAccessor));
|
|
|
|
|
|
VariationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2019-03-05 11:15:30 +01:00
|
|
|
|
_urlSegment = ContentData.UrlSegment;
|
2019-01-28 16:22:40 +01:00
|
|
|
|
IsPreviewing = ContentData.Published == false;
|
2016-06-10 16:37:28 +02:00
|
|
|
|
|
2017-12-07 13:22:32 +01:00
|
|
|
|
var properties = new List<IPublishedProperty>();
|
|
|
|
|
|
foreach (var propertyType in _contentNode.ContentType.PropertyTypes)
|
|
|
|
|
|
{
|
2018-04-25 15:55:27 +02:00
|
|
|
|
// add one property per property type - this is required, for the indexing to work
|
|
|
|
|
|
// if contentData supplies pdatas, use them, else use null
|
|
|
|
|
|
contentData.Properties.TryGetValue(propertyType.Alias, out var pdatas); // else will be null
|
|
|
|
|
|
properties.Add(new Property(propertyType, this, pdatas, _publishedSnapshotAccessor));
|
2017-12-07 13:22:32 +01:00
|
|
|
|
}
|
|
|
|
|
|
PropertiesArray = properties.ToArray();
|
2016-05-27 14:26:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-30 19:54:36 +02:00
|
|
|
|
private string GetProfileNameById(int id)
|
2016-05-27 14:26:28 +02:00
|
|
|
|
{
|
2017-10-31 12:48:24 +01:00
|
|
|
|
var cache = GetCurrentSnapshotCache();
|
2016-05-27 14:26:28 +02:00
|
|
|
|
return cache == null
|
|
|
|
|
|
? GetProfileNameByIdNoCache(id)
|
2019-01-17 11:01:23 +01:00
|
|
|
|
: (string)cache.Get(CacheKeys.ProfileName(id), () => GetProfileNameByIdNoCache(id));
|
2016-05-27 14:26:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static string GetProfileNameByIdNoCache(int id)
|
|
|
|
|
|
{
|
|
|
|
|
|
#if DEBUG
|
2016-09-01 19:06:08 +02:00
|
|
|
|
var userService = Current.Services?.UserService;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
if (userService == null) return "[null]"; // for tests
|
|
|
|
|
|
#else
|
|
|
|
|
|
// we don't want each published content to hold a reference to the service
|
2016-09-01 19:06:08 +02:00
|
|
|
|
// so where should they get the service from really? from the locator...
|
|
|
|
|
|
var userService = Current.Services.UserService;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
var user = userService.GetProfileById(id);
|
2016-05-30 19:54:36 +02:00
|
|
|
|
return user?.Name;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-04-22 17:51:07 +02:00
|
|
|
|
// used when cloning in ContentNode
|
|
|
|
|
|
public PublishedContent(ContentNode contentNode, PublishedContent origin)
|
2016-05-27 14:26:28 +02:00
|
|
|
|
{
|
|
|
|
|
|
_contentNode = contentNode;
|
2017-10-31 12:48:24 +01:00
|
|
|
|
_publishedSnapshotAccessor = origin._publishedSnapshotAccessor;
|
2018-04-30 21:29:49 +02:00
|
|
|
|
VariationContextAccessor = origin.VariationContextAccessor;
|
2019-01-28 16:22:40 +01:00
|
|
|
|
ContentData = origin.ContentData;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
_urlSegment = origin._urlSegment;
|
2016-05-30 19:54:36 +02:00
|
|
|
|
IsPreviewing = origin.IsPreviewing;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
|
|
|
|
|
// here is the main benefit: we do not re-create properties so if anything
|
|
|
|
|
|
// is cached locally, we share the cache - which is fine - if anything depends
|
|
|
|
|
|
// on the tree structure, it should not be cached locally to begin with
|
2016-05-30 19:54:36 +02:00
|
|
|
|
PropertiesArray = origin.PropertiesArray;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// clone for previewing as draft a published content that is published and has no draft
|
2019-04-24 14:25:41 +02:00
|
|
|
|
private PublishedContent(PublishedContent origin)
|
2016-05-27 14:26:28 +02:00
|
|
|
|
{
|
2017-10-31 12:48:24 +01:00
|
|
|
|
_publishedSnapshotAccessor = origin._publishedSnapshotAccessor;
|
2018-04-30 21:29:49 +02:00
|
|
|
|
VariationContextAccessor = origin.VariationContextAccessor;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
_contentNode = origin._contentNode;
|
2019-01-28 16:22:40 +01:00
|
|
|
|
ContentData = origin.ContentData;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
_urlSegment = origin._urlSegment;
|
2016-05-30 19:54:36 +02:00
|
|
|
|
IsPreviewing = true;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
|
|
|
|
|
// clone properties so _isPreviewing is true
|
2018-04-24 01:31:01 +10:00
|
|
|
|
PropertiesArray = origin.PropertiesArray.Select(x => (IPublishedProperty)new Property((Property)x, this)).ToArray();
|
2016-05-27 14:26:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Get Content/Media for Parent/Children
|
|
|
|
|
|
|
|
|
|
|
|
// this is for tests purposes
|
2017-10-31 12:48:24 +01:00
|
|
|
|
// args are: current published snapshot (may be null), previewing, content id - returns: content
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2018-04-27 11:38:50 +10:00
|
|
|
|
internal static Func<IPublishedSnapshot, bool, int, IPublishedContent> GetContentByIdFunc { get; set; }
|
2017-10-31 12:50:30 +01:00
|
|
|
|
= (publishedShapshot, previewing, id) => publishedShapshot.Content.GetById(previewing, id);
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2018-04-27 11:38:50 +10:00
|
|
|
|
internal static Func<IPublishedSnapshot, bool, int, IPublishedContent> GetMediaByIdFunc { get; set; }
|
2017-10-31 12:50:30 +01:00
|
|
|
|
= (publishedShapshot, previewing, id) => publishedShapshot.Media.GetById(previewing, id);
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2019-06-06 16:54:00 +02:00
|
|
|
|
private Func<IPublishedSnapshot, bool, int, IPublishedContent> GetGetterById()
|
2016-05-27 14:26:28 +02:00
|
|
|
|
{
|
2019-04-22 19:49:49 +02:00
|
|
|
|
switch (ContentType.ItemType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case PublishedItemType.Content:
|
|
|
|
|
|
return GetContentByIdFunc;
|
|
|
|
|
|
case PublishedItemType.Media:
|
|
|
|
|
|
return GetMediaByIdFunc;
|
|
|
|
|
|
default:
|
2019-08-16 16:18:58 +10:00
|
|
|
|
throw new PanicException("invalid item type");
|
2019-04-22 19:49:49 +02:00
|
|
|
|
}
|
2016-05-27 14:26:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
#region Content Type
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
/// <inheritdoc />
|
2019-04-15 13:04:14 +02:00
|
|
|
|
public override IPublishedContentType ContentType => _contentNode.ContentType;
|
2018-04-28 16:34:43 +02:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region PublishedElement
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2016-05-30 19:54:36 +02:00
|
|
|
|
public override Guid Key => _contentNode.Uid;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region PublishedContent
|
|
|
|
|
|
|
2019-01-28 16:22:40 +01:00
|
|
|
|
internal ContentData ContentData { get; }
|
|
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public override int Id => _contentNode.Id;
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public override int SortOrder => _contentNode.SortOrder;
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2016-05-30 19:54:36 +02:00
|
|
|
|
public override int Level => _contentNode.Level;
|
2018-04-28 16:34:43 +02:00
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2016-05-30 19:54:36 +02:00
|
|
|
|
public override string Path => _contentNode.Path;
|
2018-04-28 16:34:43 +02:00
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2019-01-28 16:22:40 +01:00
|
|
|
|
public override int? TemplateId => ContentData.TemplateId;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public override int CreatorId => _contentNode.CreatorId;
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public override string CreatorName => GetProfileNameById(_contentNode.CreatorId);
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
/// <inheritdoc />
|
2016-05-30 19:54:36 +02:00
|
|
|
|
public override DateTime CreateDate => _contentNode.CreateDate;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
/// <inheritdoc />
|
2019-01-28 16:22:40 +01:00
|
|
|
|
public override int WriterId => ContentData.WriterId;
|
2018-04-28 16:34:43 +02:00
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2019-01-28 16:22:40 +01:00
|
|
|
|
public override string WriterName => GetProfileNameById(ContentData.WriterId);
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
/// <inheritdoc />
|
2019-01-28 16:22:40 +01:00
|
|
|
|
public override DateTime UpdateDate => ContentData.VersionDate;
|
2018-04-28 16:34:43 +02:00
|
|
|
|
|
2019-04-17 10:03:49 +02:00
|
|
|
|
// ReSharper disable once CollectionNeverUpdated.Local
|
2019-06-06 16:54:00 +02:00
|
|
|
|
private static readonly IReadOnlyDictionary<string, PublishedCultureInfo> EmptyCultures = new Dictionary<string, PublishedCultureInfo>();
|
|
|
|
|
|
private IReadOnlyDictionary<string, PublishedCultureInfo> _cultures;
|
2019-04-17 10:03:49 +02:00
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
/// <inheritdoc />
|
2019-06-06 16:54:00 +02:00
|
|
|
|
public override IReadOnlyDictionary<string, PublishedCultureInfo> Cultures
|
2018-04-28 16:34:43 +02:00
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
2019-06-06 16:54:00 +02:00
|
|
|
|
if (_cultures != null) return _cultures;
|
|
|
|
|
|
|
2019-06-07 11:15:58 +02:00
|
|
|
|
if (!ContentType.VariesByCulture())
|
|
|
|
|
|
return _cultures = new Dictionary<string, PublishedCultureInfo>
|
|
|
|
|
|
{
|
|
|
|
|
|
{ "", new PublishedCultureInfo("", ContentData.Name, _urlSegment, CreateDate) }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2019-06-06 16:54:00 +02:00
|
|
|
|
if (ContentData.CultureInfos == null)
|
2019-08-16 16:18:58 +10:00
|
|
|
|
throw new PanicException("_contentDate.CultureInfos is null.");
|
2019-03-05 11:15:30 +01:00
|
|
|
|
|
2019-06-06 16:54:00 +02:00
|
|
|
|
return _cultures = ContentData.CultureInfos
|
|
|
|
|
|
.ToDictionary(x => x.Key, x => new PublishedCultureInfo(x.Key, x.Value.Name, x.Value.UrlSegment, x.Value.Date), StringComparer.OrdinalIgnoreCase);
|
2018-04-28 16:34:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-06-06 16:54:00 +02:00
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
|
public override PublishedItemType ItemType => _contentNode.ContentType.ItemType;
|
|
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
/// <inheritdoc />
|
2018-12-13 15:08:12 +01:00
|
|
|
|
public override bool IsDraft(string culture = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// if this is the 'published' published content, nothing can be draft
|
2019-01-28 16:22:40 +01:00
|
|
|
|
if (ContentData.Published)
|
2018-12-13 15:08:12 +01:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
// not the 'published' published content, and does not vary = must be draft
|
|
|
|
|
|
if (!ContentType.VariesByCulture())
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
// handle context culture
|
|
|
|
|
|
if (culture == null)
|
|
|
|
|
|
culture = VariationContextAccessor?.VariationContext?.Culture ?? "";
|
|
|
|
|
|
|
|
|
|
|
|
// not the 'published' published content, and varies
|
|
|
|
|
|
// = depends on the culture
|
2019-01-28 16:22:40 +01:00
|
|
|
|
return ContentData.CultureInfos.TryGetValue(culture, out var cvar) && cvar.IsDraft;
|
2018-12-13 15:08:12 +01:00
|
|
|
|
}
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2019-01-24 15:22:20 +01:00
|
|
|
|
/// <inheritdoc />
|
2019-01-23 07:54:45 +01:00
|
|
|
|
public override bool IsPublished(string culture = null)
|
|
|
|
|
|
{
|
2019-01-28 14:04:31 +01:00
|
|
|
|
// whether we are the 'draft' or 'published' content, need to determine whether
|
|
|
|
|
|
// there is a 'published' version for the specified culture (or at all, for
|
|
|
|
|
|
// invariant content items)
|
2019-01-24 15:22:20 +01:00
|
|
|
|
|
2019-01-28 14:04:31 +01:00
|
|
|
|
// if there is no 'published' published content, no culture can be published
|
2019-09-13 09:55:53 +02:00
|
|
|
|
if (!_contentNode.HasPublished)
|
2019-01-28 14:04:31 +01:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
// if there is a 'published' published content, and does not vary = published
|
2019-01-23 07:54:45 +01:00
|
|
|
|
if (!ContentType.VariesByCulture())
|
2019-01-28 14:04:31 +01:00
|
|
|
|
return true;
|
2019-01-23 07:54:45 +01:00
|
|
|
|
|
|
|
|
|
|
// handle context culture
|
|
|
|
|
|
if (culture == null)
|
|
|
|
|
|
culture = VariationContextAccessor?.VariationContext?.Culture ?? "";
|
|
|
|
|
|
|
2019-01-28 14:04:31 +01:00
|
|
|
|
// there is a 'published' published content, and varies
|
|
|
|
|
|
// = depends on the culture
|
2019-09-13 09:55:53 +02:00
|
|
|
|
return _contentNode.HasPublishedCulture(culture);
|
2018-12-13 15:08:12 +01:00
|
|
|
|
}
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Tree
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
2019-06-06 16:54:00 +02:00
|
|
|
|
public override IPublishedContent Parent
|
2016-05-27 14:26:28 +02:00
|
|
|
|
{
|
2019-06-06 16:54:00 +02:00
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
var getById = GetGetterById();
|
|
|
|
|
|
var publishedSnapshot = _publishedSnapshotAccessor.PublishedSnapshot;
|
|
|
|
|
|
return getById(publishedSnapshot, IsPreviewing, ParentId);
|
|
|
|
|
|
}
|
2016-05-27 14:26:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
/// <inheritdoc />
|
2019-06-06 16:54:00 +02:00
|
|
|
|
public override IEnumerable<IPublishedContent> ChildrenForAllCultures
|
2016-05-27 14:26:28 +02:00
|
|
|
|
{
|
2019-06-06 16:54:00 +02:00
|
|
|
|
get
|
2019-04-22 17:51:07 +02:00
|
|
|
|
{
|
2019-06-06 16:54:00 +02:00
|
|
|
|
var getById = GetGetterById();
|
|
|
|
|
|
var publishedSnapshot = _publishedSnapshotAccessor.PublishedSnapshot;
|
|
|
|
|
|
var id = _contentNode.FirstChildContentId;
|
|
|
|
|
|
|
|
|
|
|
|
while (id > 0)
|
|
|
|
|
|
{
|
2019-06-18 09:46:29 +02:00
|
|
|
|
// is IsPreviewing is false, then this can return null
|
2019-06-06 16:54:00 +02:00
|
|
|
|
var content = getById(publishedSnapshot, IsPreviewing, id);
|
2019-04-22 17:51:07 +02:00
|
|
|
|
|
2019-06-18 11:57:36 +10:00
|
|
|
|
if (content != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return content;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2019-06-18 09:46:29 +02:00
|
|
|
|
// but if IsPreviewing is true, we should have a child
|
2019-06-18 11:57:36 +10:00
|
|
|
|
if (IsPreviewing)
|
2019-08-16 16:18:58 +10:00
|
|
|
|
throw new PanicException($"failed to get content with id={id}");
|
2019-06-18 09:46:29 +02:00
|
|
|
|
|
|
|
|
|
|
// if IsPreviewing is false, get the unpublished child nevertheless
|
|
|
|
|
|
// we need it to keep enumerating children! but we don't return it
|
|
|
|
|
|
content = getById(publishedSnapshot, true, id);
|
|
|
|
|
|
if (content == null)
|
2019-08-16 16:18:58 +10:00
|
|
|
|
throw new PanicException($"failed to get content with id={id}");
|
2019-06-18 11:57:36 +10:00
|
|
|
|
}
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2019-06-06 16:54:00 +02:00
|
|
|
|
id = UnwrapIPublishedContent(content)._contentNode.NextSiblingContentId;
|
|
|
|
|
|
}
|
2019-04-22 17:51:07 +02:00
|
|
|
|
}
|
2016-05-27 14:26:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Properties
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc cref="IPublishedElement.Properties"/>
|
2016-06-10 16:37:28 +02:00
|
|
|
|
public override IEnumerable<IPublishedProperty> Properties => PropertiesArray;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
2018-04-28 16:34:43 +02:00
|
|
|
|
/// <inheritdoc cref="IPublishedElement.GetProperty(string)"/>
|
2016-05-27 14:26:28 +02:00
|
|
|
|
public override IPublishedProperty GetProperty(string alias)
|
|
|
|
|
|
{
|
|
|
|
|
|
var index = _contentNode.ContentType.GetPropertyIndex(alias);
|
2018-04-25 15:55:27 +02:00
|
|
|
|
if (index < 0) return null; // happens when 'alias' does not match a content type property alias
|
|
|
|
|
|
if (index >= PropertiesArray.Length) // should never happen - properties array must be in sync with property type
|
|
|
|
|
|
throw new IndexOutOfRangeException("Index points outside the properties array, which means the properties array is corrupt.");
|
2018-04-24 17:11:09 +10:00
|
|
|
|
var property = PropertiesArray[index];
|
2016-05-27 14:26:28 +02:00
|
|
|
|
return property;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-30 19:54:36 +02:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Caching
|
|
|
|
|
|
|
|
|
|
|
|
// beware what you use that one for - you don't want to cache its result
|
2019-01-17 11:01:23 +01:00
|
|
|
|
private IAppCache GetAppropriateCache()
|
2016-05-30 19:54:36 +02:00
|
|
|
|
{
|
2018-04-27 11:38:50 +10:00
|
|
|
|
var publishedSnapshot = (PublishedSnapshot)_publishedSnapshotAccessor.PublishedSnapshot;
|
2017-10-31 12:48:24 +01:00
|
|
|
|
var cache = publishedSnapshot == null
|
2016-05-30 19:54:36 +02:00
|
|
|
|
? null
|
2019-04-16 21:15:13 +02:00
|
|
|
|
: ((IsPreviewing == false || PublishedSnapshotService.FullCacheWhenPreviewing) && (ContentType.ItemType != PublishedItemType.Member)
|
2017-10-31 12:48:24 +01:00
|
|
|
|
? publishedSnapshot.ElementsCache
|
|
|
|
|
|
: publishedSnapshot.SnapshotCache);
|
2016-05-30 19:54:36 +02:00
|
|
|
|
return cache;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-01-17 11:01:23 +01:00
|
|
|
|
private IAppCache GetCurrentSnapshotCache()
|
2016-05-27 14:26:28 +02:00
|
|
|
|
{
|
2018-04-27 11:38:50 +10:00
|
|
|
|
var publishedSnapshot = (PublishedSnapshot)_publishedSnapshotAccessor.PublishedSnapshot;
|
2017-10-31 12:48:24 +01:00
|
|
|
|
return publishedSnapshot?.SnapshotCache;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Internal
|
|
|
|
|
|
|
2018-05-02 09:31:30 +02:00
|
|
|
|
// used by property
|
2018-04-30 21:29:49 +02:00
|
|
|
|
internal IVariationContextAccessor VariationContextAccessor { get; }
|
2018-04-18 19:46:47 +02:00
|
|
|
|
|
2016-05-27 14:26:28 +02:00
|
|
|
|
// used by navigable content
|
2016-05-30 19:54:36 +02:00
|
|
|
|
internal IPublishedProperty[] PropertiesArray { get; }
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
|
|
|
|
|
// used by navigable content
|
2016-05-30 19:54:36 +02:00
|
|
|
|
internal int ParentId => _contentNode.ParentContentId;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
|
|
|
|
|
// used by navigable content
|
|
|
|
|
|
// includes all children, published or unpublished
|
|
|
|
|
|
// NavigableNavigator takes care of selecting those it wants
|
2019-04-22 17:51:07 +02:00
|
|
|
|
// note: this is not efficient - we do not try to be (would require a double-linked list)
|
2019-06-06 16:54:00 +02:00
|
|
|
|
internal IList<int> ChildIds => Children.Select(x => x.Id).ToList();
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
|
|
|
|
|
// used by Property
|
|
|
|
|
|
// gets a value indicating whether the content or media exists in
|
|
|
|
|
|
// a previewing context or not, ie whether its Parent, Children, and
|
|
|
|
|
|
// properties should refer to published, or draft content
|
2016-05-30 19:54:36 +02:00
|
|
|
|
internal bool IsPreviewing { get; }
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
|
|
|
|
|
private string _asPreviewingCacheKey;
|
|
|
|
|
|
|
2016-05-30 19:54:36 +02:00
|
|
|
|
private string AsPreviewingCacheKey => _asPreviewingCacheKey ?? (_asPreviewingCacheKey = CacheKeys.PublishedContentAsPreviewing(Key));
|
2016-05-27 14:26:28 +02:00
|
|
|
|
|
|
|
|
|
|
// used by ContentCache
|
2018-12-13 15:08:12 +01:00
|
|
|
|
internal IPublishedContent AsDraft()
|
2016-05-27 14:26:28 +02:00
|
|
|
|
{
|
2016-05-30 19:54:36 +02:00
|
|
|
|
if (IsPreviewing)
|
2016-05-27 14:26:28 +02:00
|
|
|
|
return this;
|
|
|
|
|
|
|
2016-06-10 16:37:28 +02:00
|
|
|
|
var cache = GetAppropriateCache();
|
2019-04-24 14:25:41 +02:00
|
|
|
|
if (cache == null) return new PublishedContent(this).CreateModel();
|
|
|
|
|
|
return (IPublishedContent)cache.Get(AsPreviewingCacheKey, () => new PublishedContent(this).CreateModel());
|
2016-05-27 14:26:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// used by Navigable.Source,...
|
|
|
|
|
|
internal static PublishedContent UnwrapIPublishedContent(IPublishedContent content)
|
|
|
|
|
|
{
|
2019-04-22 19:49:49 +02:00
|
|
|
|
while (content is PublishedContentWrapped wrapped)
|
2016-05-27 14:26:28 +02:00
|
|
|
|
content = wrapped.Unwrap();
|
2019-04-22 19:49:49 +02:00
|
|
|
|
if (!(content is PublishedContent inner))
|
2016-05-27 14:26:28 +02:00
|
|
|
|
throw new InvalidOperationException("Innermost content is not PublishedContent.");
|
|
|
|
|
|
return inner;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|