Skip to content

Instantly share code, notes, and snippets.

@mattbrailsford
Created February 11, 2022 09:52
Show Gist options
  • Save mattbrailsford/cfce147963103dc47247454796840dc6 to your computer and use it in GitHub Desktop.
Save mattbrailsford/cfce147963103dc47247454796840dc6 to your computer and use it in GitHub Desktop.
Published Content Wrapper for v8 + v9
public class MyController : Controller
{
private readonly PublishedContentWrapperFactory _publishedContentWrapper;
public MyController(PublishedContentWrapperFactory publishedContentWrapper)
=> _publishedContentWrapper = publishedContentWrapper;
[HttpGet]
public IActionResult DoSomething()
{
var content = _someUmbracoContentApi.GetContent(nodeId);
var publishedContent = _publishedContentWrapper.Wrap(content);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using Vendr.Common;
using Vendr.Extensions;
#if NETFRAMEWORK
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using IFactory = Vendr.Common.IFactory;
using IProperty = Umbraco.Core.Models.Property;
#else
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Strings;
using Umbraco.Extensions;
#endif
namespace Vendr.Umbraco.Content
{
public class PublishedContentWrapperFactory
{
private readonly IFactory _factory;
public PublishedContentWrapperFactory(IFactory factory)
{
_factory = factory;
}
internal IPublishedContent Wrap(IContent content, bool isPreview = false)
{
return new PublishedContentWrapper(_factory, this, content, isPreview);
}
#region PublishedContentWrapper
private class PublishedContentWrapper : IPublishedContent
{
private static readonly IReadOnlyDictionary<string, PublishedCultureInfo> NoCultureInfos = new Dictionary<string, PublishedCultureInfo>();
private readonly IContent _inner;
private readonly bool _isPreviewing;
private readonly IFactory _factory;
private readonly Lazy<string> _creatorName;
private readonly Lazy<string> _writerName;
private readonly Lazy<IPublishedContentType> _contentType;
private readonly Lazy<IPublishedProperty[]> _properties;
private readonly Lazy<IPublishedContent> _parent;
private readonly Lazy<IEnumerable<IPublishedContent>> _children;
private readonly Lazy<IReadOnlyDictionary<string, PublishedCultureInfo>> _cultureInfos;
private readonly PublishedContentWrapperFactory _contentWrapperFactory;
private readonly IUserService _userService;
private readonly IContentTypeService _contentTypeService;
private readonly IPublishedContentTypeFactory _publishedContentTypeFactory;
private readonly IContentService _contentService;
public PublishedContentWrapper(IFactory factory, PublishedContentWrapperFactory contentWrapperFactory, IContent inner, bool isPreviewing)
{
_factory = factory;
_contentWrapperFactory = contentWrapperFactory;
_userService = factory.GetInstance<IUserService>();
_contentTypeService = factory.GetInstance<IContentTypeService>();
_publishedContentTypeFactory = factory.GetInstance<IPublishedContentTypeFactory>();
_contentService = factory.GetInstance<IContentService>();
_inner = inner ?? throw new NullReferenceException("inner");
_isPreviewing = isPreviewing;
_creatorName = new Lazy<string>(() => _inner.GetCreatorProfile(_userService)?.Name);
_writerName = new Lazy<string>(() => _inner.GetWriterProfile(_userService)?.Name);
_contentType = new Lazy<IPublishedContentType>(() =>
{
var ct = _contentTypeService.Get(_inner.ContentTypeId);
return _publishedContentTypeFactory.CreateContentType(ct);
});
_properties = new Lazy<IPublishedProperty[]>(() => ContentType.PropertyTypes
.Select(x =>
{
var p = _inner.Properties.SingleOrDefault(xx => xx.Alias == x.Alias);
return new PublishedPropertyWrapper(this, x, p, _isPreviewing);
})
.Cast<IPublishedProperty>()
.ToArray());
_parent = new Lazy<IPublishedContent>(() =>
{
var content = _contentService.GetById(_inner.ParentId);
return content != null
? _contentWrapperFactory.Wrap(content, _isPreviewing)
: null;
});
_children = new Lazy<IEnumerable<IPublishedContent>>(() =>
{
var c = _contentService.GetPagedChildren(_inner.Id, 0, 2000000000, out var totalRecords);
return c.Select(x => _contentWrapperFactory.Wrap(x, _isPreviewing)).OrderBy(x => x.SortOrder);
});
_cultureInfos = new Lazy<IReadOnlyDictionary<string, PublishedCultureInfo>>(() =>
{
if (!_inner.ContentType.VariesByCulture())
return NoCultureInfos;
return _inner.PublishCultureInfos.Values
.ToDictionary(x => x.Culture, x => new PublishedCultureInfo(x.Culture,
x.Name,
GetUrlSegment(x.Culture),
x.Date));
});
}
public IPublishedContentType ContentType
=> _contentType.Value;
public int Id
=> _inner.Id;
public Guid Key
=> _inner.Key;
public int? TemplateId
=> _inner.TemplateId;
public int SortOrder
=> _inner.SortOrder;
public string Name
=> _inner.Name;
public IReadOnlyDictionary<string, PublishedCultureInfo> Cultures
=> _cultureInfos.Value;
public string UrlSegment
=> GetUrlSegment();
public string WriterName
=> _writerName.Value;
public string CreatorName
=> _creatorName.Value;
public int WriterId
=> _inner.WriterId;
public int CreatorId
=> _inner.CreatorId;
public string Path
=> _inner.Path;
public DateTime CreateDate
=> _inner.CreateDate;
public DateTime UpdateDate
=> _inner.UpdateDate;
public int Level
=> _inner.Level;
public string Url
=> null; // TODO: Implement?
public PublishedItemType ItemType
=> PublishedItemType.Content;
public bool IsDraft(string culture = null)
=> !IsPublished(culture);
public bool IsPublished(string culture = null)
=> _inner.IsCulturePublished(culture);
public IPublishedContent Parent
=> _parent.Value;
public IEnumerable<IPublishedContent> Children
=> _children.Value; // TODO: Filter by current culture?
public IEnumerable<IPublishedContent> ChildrenForAllCultures
=> _children.Value;
public IEnumerable<IPublishedProperty> Properties
=> _properties.Value;
public IPublishedProperty GetProperty(string alias)
=> _properties.Value.FirstOrDefault(x => Extensions.StringExtensions.InvariantEquals(x.Alias, alias));
private string GetUrlSegment(string culture = null)
{
var urlSegmentProviders = _factory.GetInstance<UrlSegmentProviderCollection>();
#if NETFRAMEWORK
var defaultUrlSegmentProvider = new DefaultUrlSegmentProvider();
#else
var defaultUrlSegmentProvider = new DefaultUrlSegmentProvider(_factory.GetInstance<IShortStringHelper>());
#endif
var url = urlSegmentProviders.Select(p => p.GetUrlSegment(_inner, culture)).FirstOrDefault(u => u != null);
url = url ?? defaultUrlSegmentProvider.GetUrlSegment(_inner, culture); // be safe
return url;
}
}
private class PublishedPropertyWrapper : IPublishedProperty
{
private readonly object _sourceValue;
private readonly IPublishedContent _content;
private readonly bool _isPreviewing;
public PublishedPropertyWrapper(IPublishedContent content, IPublishedPropertyType propertyType, IProperty property, bool isPreviewing)
: this(propertyType, PropertyCacheLevel.Unknown) // cache level is ignored
{
_sourceValue = property?.GetValue();
_content = content;
_isPreviewing = isPreviewing;
}
protected PublishedPropertyWrapper(IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel)
{
PropertyType = propertyType ?? throw new ArgumentNullException(nameof(propertyType));
ReferenceCacheLevel = referenceCacheLevel;
}
public IPublishedPropertyType PropertyType { get; }
public PropertyCacheLevel ReferenceCacheLevel { get; }
public string Alias => PropertyType.Alias;
public bool HasValue(string culture = null, string segment = null)
{
return _sourceValue != null && ((_sourceValue is string) == false || string.IsNullOrWhiteSpace((string)_sourceValue) == false);
}
public object GetSourceValue(string culture = null, string segment = null)
{
return _sourceValue;
}
public object GetValue(string culture = null, string segment = null)
{
var source = PropertyType.ConvertSourceToInter(_content, _sourceValue, _isPreviewing);
return PropertyType.ConvertInterToObject(_content, PropertyCacheLevel.Unknown, source, _isPreviewing);
}
public object GetXPathValue(string culture = null, string segment = null)
{
var source = PropertyType.ConvertSourceToInter(_content, _sourceValue, _isPreviewing);
return PropertyType.ConvertInterToXPath(_content, PropertyCacheLevel.Unknown, source, _isPreviewing);
}
}
#endregion
}
}
...
builder.Services.AddSingleton<PublishedContentWrapperFactory>();
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment