Cleanup IPublishedContent

This commit is contained in:
Stephan
2018-04-28 16:34:43 +02:00
parent 27390afe86
commit ce8775b3e7
30 changed files with 855 additions and 540 deletions

View File

@@ -104,8 +104,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
// hideTopLevelNode = support legacy stuff, look for /*/path/to/node
// else normal, look for /path/to/node
content = hideTopLevelNode.Value
? GetAtRoot(preview).SelectMany(x => x.Children).FirstOrDefault(x => x.GetUrlName(_localizationService, culture) == parts[0])
: GetAtRoot(preview).FirstOrDefault(x => x.GetUrlName(_localizationService, culture) == parts[0]);
? GetAtRoot(preview).SelectMany(x => x.Children).FirstOrDefault(x => x.GetCulture(culture).UrlSegment == parts[0])
: GetAtRoot(preview).FirstOrDefault(x => x.GetCulture(culture).UrlSegment == parts[0]);
content = FollowRoute(content, parts, 1, culture);
}
@@ -114,7 +114,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// have to look for /foo (see note in ApplyHideTopLevelNodeFromPath).
if (content == null && hideTopLevelNode.Value && parts.Length == 1)
{
content = GetAtRoot(preview).FirstOrDefault(x => x.GetUrlName(_localizationService, culture) == parts[0]);
content = GetAtRoot(preview).FirstOrDefault(x => x.GetCulture(culture).UrlSegment == parts[0]);
}
return content;
@@ -147,9 +147,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
var hasDomains = _domainHelper.NodeHasDomains(n.Id);
while (hasDomains == false && n != null) // n is null at root
{
var urlName = n.GetUrlName(_localizationService, culture);
var urlSegment = n.GetCulture(culture).UrlSegment;
pathParts.Add(urlName);
pathParts.Add(urlSegment);
// move to parent node
n = n.Parent;
@@ -178,14 +178,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
var part = parts[i++];
content = content.Children.FirstOrDefault(x =>
{
// fixme - should use ISystemDefaultCultureAccessor NOT ILocalizationService!
var urlName = x.GetUrlName(_localizationService, culture);
return urlName == part;
var urlSegment = x.GetCulture(culture).UrlSegment;
return urlSegment == part;
});
// fixme - if content has a wildcard domain, switch culture! or, shall we?
// no - do NOT support wildcard domains, it makes no sense
// OTOH support '*/en' as a valid domain
}
return content;
}

View File

@@ -18,7 +18,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// ReSharper disable once InconsistentNaming
internal readonly ContentData _contentData; // internal for ContentNode cloning
private readonly string _urlName;
private readonly string _urlSegment;
private IReadOnlyDictionary<string, PublishedCultureName> _cultureNames;
#region Constructors
@@ -28,9 +28,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
_contentNode = contentNode;
_contentData = contentData;
_publishedSnapshotAccessor = publishedSnapshotAccessor;
VariationContextAccessor = variationContextAccessor;
VariationContextAccessor = variationContextAccessor; // fixme why is this a property? should be be on the base class?
_urlName = _contentData.Name.ToUrlSegment();
_urlSegment = _contentData.Name.ToUrlSegment();
IsPreviewing = _contentData.Published == false;
var properties = new List<IPublishedProperty>();
@@ -74,7 +74,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
VariationContextAccessor = origin.VariationContextAccessor;
_contentData = origin._contentData;
_urlName = origin._urlName;
_urlSegment = origin._urlSegment;
IsPreviewing = origin.IsPreviewing;
// here is the main benefit: we do not re-create properties so if anything
@@ -91,7 +91,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
_contentNode = origin._contentNode;
_contentData = origin._contentData;
_urlName = origin._urlName;
_urlSegment = origin._urlSegment;
IsPreviewing = true;
// clone properties so _isPreviewing is true
@@ -155,51 +155,131 @@ namespace Umbraco.Web.PublishedCache.NuCache
#endregion
#region IPublishedContent
#region Content Type
public override int Id => _contentNode.Id;
/// <inheritdoc />
public override PublishedContentType ContentType => _contentNode.ContentType;
#endregion
#region PublishedElement
/// <inheritdoc />
public override Guid Key => _contentNode.Uid;
public override int DocumentTypeId => _contentNode.ContentType.Id;
public override string DocumentTypeAlias => _contentNode.ContentType.Alias;
public override PublishedItemType ItemType => _contentNode.ContentType.ItemType;
public override string Name => _contentData.Name;
public override IReadOnlyDictionary<string, PublishedCultureName> CultureNames
#endregion
#region PublishedContent
/// <inheritdoc />
public override int Id => _contentNode.Id;
/// <inheritdoc />
public override string Name
{
get
{
if (!ContentType.Variations.HasFlag(ContentVariation.CultureNeutral))
return null;
if (!ContentType.Variations.Has(ContentVariation.CultureNeutral)) // fixme CultureSegment?
return _contentData.Name;
if (_cultureNames == null)
{
var d = new Dictionary<string, PublishedCultureName>(StringComparer.InvariantCultureIgnoreCase);
foreach(var c in _contentData.CultureInfos)
{
d[c.Key] = new PublishedCultureName(c.Value.Name, c.Value.Name.ToUrlSegment());
}
_cultureNames = d;
}
return _cultureNames;
var culture = VariationContextAccessor.Context.Culture;
if (culture == null)
return _contentData.Name;
return Cultures.TryGetValue(culture, out var cultureInfos) ? cultureInfos.Name : null;
}
}
public override int Level => _contentNode.Level;
public override string Path => _contentNode.Path;
/// <inheritdoc />
public override string UrlName
{
get
{
if (!ContentType.Variations.Has(ContentVariation.CultureNeutral)) // fixme CultureSegment?
return _urlSegment;
var culture = VariationContextAccessor.Context.Culture;
if (culture == null)
return _urlSegment;
return Cultures.TryGetValue(culture, out var cultureInfos) ? cultureInfos.UrlSegment : null;
}
}
/// <inheritdoc />
public override int SortOrder => _contentNode.SortOrder;
/// <inheritdoc />
public override int Level => _contentNode.Level;
/// <inheritdoc />
public override string Path => _contentNode.Path;
/// <inheritdoc />
public override int TemplateId => _contentData.TemplateId;
public override string UrlName => _urlName;
public override DateTime CreateDate => _contentNode.CreateDate;
public override DateTime UpdateDate => _contentData.VersionDate;
/// <inheritdoc />
public override int CreatorId => _contentNode.CreatorId;
/// <inheritdoc />
public override string CreatorName => GetProfileNameById(_contentNode.CreatorId);
/// <inheritdoc />
public override DateTime CreateDate => _contentNode.CreateDate;
/// <inheritdoc />
public override int WriterId => _contentData.WriterId;
/// <inheritdoc />
public override string WriterName => GetProfileNameById(_contentData.WriterId);
/// <inheritdoc />
public override DateTime UpdateDate => _contentData.VersionDate;
private IReadOnlyDictionary<string, PublishedCultureInfos> _cultureInfos;
private static readonly IReadOnlyDictionary<string, PublishedCultureInfos> NoCultureInfos = new Dictionary<string, PublishedCultureInfos>();
/// <inheritdoc />
public override PublishedCultureInfos GetCulture(string culture = ".")
{
// handle context culture
if (culture == ".")
culture = VariationContextAccessor.Context.Culture;
// no invariant culture infos
if (culture == null) return null;
// get
return Cultures.TryGetValue(culture, out var cultureInfos) ? cultureInfos : null;
}
/// <inheritdoc />
public override IReadOnlyDictionary<string, PublishedCultureInfos> Cultures
{
get
{
if (!ContentType.Variations.Has(ContentVariation.CultureNeutral)) // fixme CultureSegment?
return NoCultureInfos;
if (_cultureInfos != null) return _cultureInfos;
return _cultureInfos = _contentData.CultureInfos // fixme can it be null?
.ToDictionary(x => x.Key, x => new PublishedCultureInfos(x.Key, x.Value.Name, false, DateTime.MinValue)); // fixme values!
}
}
/// <inheritdoc />
public override PublishedItemType ItemType => _contentNode.ContentType.ItemType;
/// <inheritdoc />
public override bool IsDraft => _contentData.Published == false;
#endregion
#region Tree
/// <inheritdoc />
public override IPublishedContent Parent
{
get
@@ -218,10 +298,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
}
private string _childrenCacheKey;
private string ChildrenCacheKey => _childrenCacheKey ?? (_childrenCacheKey = CacheKeys.PublishedContentChildren(Key, IsPreviewing));
/// <inheritdoc />
public override IEnumerable<IPublishedContent> Children
{
get
@@ -235,6 +312,10 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
}
private string _childrenCacheKey;
private string ChildrenCacheKey => _childrenCacheKey ?? (_childrenCacheKey = CacheKeys.PublishedContentChildren(Key, IsPreviewing));
private IEnumerable<IPublishedContent> GetChildren()
{
IEnumerable<IPublishedContent> c;
@@ -258,8 +339,15 @@ namespace Umbraco.Web.PublishedCache.NuCache
// Q: perfs-wise, is it better than having the store managed an ordered list
}
#endregion
#region Properties
/// <inheritdoc cref="IPublishedElement.Properties"/>
public override IEnumerable<IPublishedProperty> Properties => PropertiesArray;
/// <inheritdoc cref="IPublishedElement.GetProperty(string)"/>
public override IPublishedProperty GetProperty(string alias)
{
var index = _contentNode.ContentType.GetPropertyIndex(alias);
@@ -270,6 +358,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
return property;
}
/// <inheritdoc cref="IPublishedContent.GetProperty(string, bool)"/>
public override IPublishedProperty GetProperty(string alias, bool recurse)
{
var property = GetProperty(alias);
@@ -283,8 +372,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
return (Property)cache.GetCacheItem(key, () => base.GetProperty(alias, true));
}
public override PublishedContentType ContentType => _contentNode.ContentType;
#endregion
#region Caching

View File

@@ -144,14 +144,12 @@ namespace Umbraco.Web.PublishedCache
public override string Name => _member.Name;
public override IReadOnlyDictionary<string, PublishedCultureName> CultureNames => throw new NotSupportedException();
public override PublishedCultureInfos GetCulture(string culture = ".") => throw new NotSupportedException();
public override IReadOnlyDictionary<string, PublishedCultureInfos> Cultures => throw new NotSupportedException();
public override string UrlName => throw new NotSupportedException();
public override string DocumentTypeAlias => _member.ContentTypeAlias;
public override int DocumentTypeId => _member.ContentType.Id;
//TODO: ARGH! need to fix this - this is not good because it uses ApplicationContext.Current
public override string WriterName => _member.GetCreatorProfile().Name;

View File

@@ -0,0 +1,237 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Xml.XPath;
using Examine.LuceneEngine.Providers;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Composing;
using Umbraco.Web.Models;
namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
/// <summary>
/// An IPublishedContent that is represented all by a dictionary.
/// </summary>
/// <remarks>
/// This is a helper class and definitely not intended for public use, it expects that all of the values required
/// to create an IPublishedContent exist in the dictionary by specific aliases.
/// </remarks>
internal class DictionaryPublishedContent : PublishedContentBase
{
// note: I'm not sure this class fully complies with IPublishedContent rules especially
// I'm not sure that _properties contains all properties including those without a value,
// neither that GetProperty will return a property without a value vs. null... @zpqrtbnk
// List of properties that will appear in the XML and do not match
// anything in the ContentType, so they must be ignored.
private static readonly string[] IgnoredKeys = { "version", "isDoc" };
public DictionaryPublishedContent(
IReadOnlyDictionary<string, string> valueDictionary,
Func<int, IPublishedContent> getParent,
Func<int, XPathNavigator, IEnumerable<IPublishedContent>> getChildren,
Func<DictionaryPublishedContent, string, IPublishedProperty> getProperty,
ICacheProvider cacheProvider,
PublishedContentTypeCache contentTypeCache,
XPathNavigator nav,
bool fromExamine)
{
if (valueDictionary == null) throw new ArgumentNullException(nameof(valueDictionary));
if (getParent == null) throw new ArgumentNullException(nameof(getParent));
if (getProperty == null) throw new ArgumentNullException(nameof(getProperty));
_getParent = new Lazy<IPublishedContent>(() => getParent(ParentId));
_getChildren = new Lazy<IEnumerable<IPublishedContent>>(() => getChildren(Id, nav));
_getProperty = getProperty;
_cacheProvider = cacheProvider;
LoadedFromExamine = fromExamine;
ValidateAndSetProperty(valueDictionary, val => _id = Int32.Parse(val), "id", "nodeId", "__NodeId"); //should validate the int!
ValidateAndSetProperty(valueDictionary, val => _key = Guid.Parse(val), "key");
//ValidateAndSetProperty(valueDictionary, val => _templateId = int.Parse(val), "template", "templateId");
ValidateAndSetProperty(valueDictionary, val => _sortOrder = Int32.Parse(val), "sortOrder");
ValidateAndSetProperty(valueDictionary, val => _name = val, "nodeName", "__nodeName");
ValidateAndSetProperty(valueDictionary, val => _urlName = val, "urlName");
ValidateAndSetProperty(valueDictionary, val => _documentTypeAlias = val, "nodeTypeAlias", LuceneIndexer.ItemTypeFieldName);
ValidateAndSetProperty(valueDictionary, val => _documentTypeId = Int32.Parse(val), "nodeType");
//ValidateAndSetProperty(valueDictionary, val => _writerName = val, "writerName");
ValidateAndSetProperty(valueDictionary, val => _creatorName = val, "creatorName", "writerName"); //this is a bit of a hack fix for: U4-1132
//ValidateAndSetProperty(valueDictionary, val => _writerId = int.Parse(val), "writerID");
ValidateAndSetProperty(valueDictionary, val => _creatorId = Int32.Parse(val), "creatorID", "writerID"); //this is a bit of a hack fix for: U4-1132
ValidateAndSetProperty(valueDictionary, val => _path = val, "path", "__Path");
ValidateAndSetProperty(valueDictionary, val => _createDate = ParseDateTimeValue(val), "createDate");
ValidateAndSetProperty(valueDictionary, val => _updateDate = ParseDateTimeValue(val), "updateDate");
ValidateAndSetProperty(valueDictionary, val => _level = Int32.Parse(val), "level");
ValidateAndSetProperty(valueDictionary, val =>
{
int pId;
ParentId = -1;
if (Int32.TryParse(val, out pId))
{
ParentId = pId;
}
}, "parentID");
_contentType = contentTypeCache.Get(PublishedItemType.Media, _documentTypeAlias);
_properties = new Collection<IPublishedProperty>();
//handle content type properties
//make sure we create them even if there's no value
foreach (var propertyType in _contentType.PropertyTypes)
{
var alias = propertyType.Alias;
_keysAdded.Add(alias);
string value;
const bool isPreviewing = false; // false :: never preview a media
var property = valueDictionary.TryGetValue(alias, out value) == false || value == null
? new XmlPublishedProperty(propertyType, this, isPreviewing)
: new XmlPublishedProperty(propertyType, this, isPreviewing, value);
_properties.Add(property);
}
//loop through remaining values that haven't been applied
foreach (var i in valueDictionary.Where(x =>
_keysAdded.Contains(x.Key) == false // not already processed
&& IgnoredKeys.Contains(x.Key) == false)) // not ignorable
{
if (i.Key.InvariantStartsWith("__"))
{
// no type for that one, dunno how to convert, drop it
//IPublishedProperty property = new PropertyResult(i.Key, i.Value, PropertyResultType.CustomProperty);
//_properties.Add(property);
}
else
{
// this is a property that does not correspond to anything, ignore and log
Current.Logger.Warn<PublishedMediaCache>("Dropping property \"" + i.Key + "\" because it does not belong to the content type.");
}
}
}
private DateTime ParseDateTimeValue(string val)
{
if (LoadedFromExamine == false)
return DateTime.Parse(val);
//we need to parse the date time using Lucene converters
var ticks = Int64.Parse(val);
return new DateTime(ticks);
}
/// <summary>
/// Flag to get/set if this was laoded from examine cache
/// </summary>
internal bool LoadedFromExamine { get; }
//private readonly Func<DictionaryPublishedContent, IPublishedContent> _getParent;
private readonly Lazy<IPublishedContent> _getParent;
//private readonly Func<DictionaryPublishedContent, IEnumerable<IPublishedContent>> _getChildren;
private readonly Lazy<IEnumerable<IPublishedContent>> _getChildren;
private readonly Func<DictionaryPublishedContent, string, IPublishedProperty> _getProperty;
private readonly ICacheProvider _cacheProvider;
/// <summary>
/// Returns 'Media' as the item type
/// </summary>
public override PublishedItemType ItemType => PublishedItemType.Media;
public override IPublishedContent Parent => _getParent.Value;
public int ParentId { get; private set; }
public override int Id => _id;
public override Guid Key => _key;
public override int TemplateId => 0;
public override int SortOrder => _sortOrder;
public override string Name => _name;
public override PublishedCultureInfos GetCulture(string culture = ".") => throw new NotSupportedException();
public override IReadOnlyDictionary<string, PublishedCultureInfos> Cultures => throw new NotSupportedException();
public override string UrlName => _urlName;
public override string WriterName => _creatorName;
public override string CreatorName => _creatorName;
public override int WriterId => _creatorId;
public override int CreatorId => _creatorId;
public override string Path => _path;
public override DateTime CreateDate => _createDate;
public override DateTime UpdateDate => _updateDate;
public override int Level => _level;
public override bool IsDraft => false;
public override IEnumerable<IPublishedProperty> Properties => _properties;
public override IEnumerable<IPublishedContent> Children => _getChildren.Value;
public override IPublishedProperty GetProperty(string alias)
{
return _getProperty(this, alias);
}
public override PublishedContentType ContentType => _contentType;
// override to implement cache
// cache at context level, ie once for the whole request
// but cache is not shared by requests because we wouldn't know how to clear it
public override IPublishedProperty GetProperty(string alias, bool recurse)
{
if (recurse == false) return GetProperty(alias);
var key = $"XmlPublishedCache.PublishedMediaCache:RecursiveProperty-{Id}-{alias.ToLowerInvariant()}";
var cacheProvider = _cacheProvider;
return cacheProvider.GetCacheItem<IPublishedProperty>(key, () => base.GetProperty(alias, true));
}
private readonly List<string> _keysAdded = new List<string>();
private int _id;
private Guid _key;
//private int _templateId;
private int _sortOrder;
private string _name;
private string _urlName;
private string _documentTypeAlias;
private int _documentTypeId;
//private string _writerName;
private string _creatorName;
//private int _writerId;
private int _creatorId;
private string _path;
private DateTime _createDate;
private DateTime _updateDate;
//private Guid _version;
private int _level;
private readonly ICollection<IPublishedProperty> _properties;
private readonly PublishedContentType _contentType;
private void ValidateAndSetProperty(IReadOnlyDictionary<string, string> valueDictionary, Action<string> setProperty, params string[] potentialKeys)
{
var key = potentialKeys.FirstOrDefault(x => valueDictionary.ContainsKey(x) && valueDictionary[x] != null);
if (key == null)
{
throw new FormatException("The valueDictionary is not formatted correctly and is missing any of the '" + String.Join(",", potentialKeys) + "' elements");
}
setProperty(valueDictionary[key]);
_keysAdded.Add(key);
}
}
}

View File

@@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Threading;
using System.Xml.XPath;
using Examine;
using Examine.LuceneEngine.Providers;
using Examine.LuceneEngine.SearchCriteria;
using Examine.Providers;
using Lucene.Net.Store;
@@ -16,7 +14,6 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Xml;
using Umbraco.Web.Models;
using Umbraco.Examine;
using umbraco;
using Umbraco.Core.Cache;
@@ -607,230 +604,6 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
return mediaList;
}
/// <summary>
/// An IPublishedContent that is represented all by a dictionary.
/// </summary>
/// <remarks>
/// This is a helper class and definitely not intended for public use, it expects that all of the values required
/// to create an IPublishedContent exist in the dictionary by specific aliases.
/// </remarks>
internal class DictionaryPublishedContent : PublishedContentBase
{
// note: I'm not sure this class fully complies with IPublishedContent rules especially
// I'm not sure that _properties contains all properties including those without a value,
// neither that GetProperty will return a property without a value vs. null... @zpqrtbnk
// List of properties that will appear in the XML and do not match
// anything in the ContentType, so they must be ignored.
private static readonly string[] IgnoredKeys = { "version", "isDoc" };
public DictionaryPublishedContent(
IReadOnlyDictionary<string, string> valueDictionary,
Func<int, IPublishedContent> getParent,
Func<int, XPathNavigator, IEnumerable<IPublishedContent>> getChildren,
Func<DictionaryPublishedContent, string, IPublishedProperty> getProperty,
ICacheProvider cacheProvider,
PublishedContentTypeCache contentTypeCache,
XPathNavigator nav,
bool fromExamine)
{
if (valueDictionary == null) throw new ArgumentNullException(nameof(valueDictionary));
if (getParent == null) throw new ArgumentNullException(nameof(getParent));
if (getProperty == null) throw new ArgumentNullException(nameof(getProperty));
_getParent = new Lazy<IPublishedContent>(() => getParent(ParentId));
_getChildren = new Lazy<IEnumerable<IPublishedContent>>(() => getChildren(Id, nav));
_getProperty = getProperty;
_cacheProvider = cacheProvider;
LoadedFromExamine = fromExamine;
ValidateAndSetProperty(valueDictionary, val => _id = int.Parse(val), "id", "nodeId", "__NodeId"); //should validate the int!
ValidateAndSetProperty(valueDictionary, val => _key = Guid.Parse(val), "key");
//ValidateAndSetProperty(valueDictionary, val => _templateId = int.Parse(val), "template", "templateId");
ValidateAndSetProperty(valueDictionary, val => _sortOrder = int.Parse(val), "sortOrder");
ValidateAndSetProperty(valueDictionary, val => _name = val, "nodeName", "__nodeName");
ValidateAndSetProperty(valueDictionary, val => _urlName = val, "urlName");
ValidateAndSetProperty(valueDictionary, val => _documentTypeAlias = val, "nodeTypeAlias", LuceneIndexer.ItemTypeFieldName);
ValidateAndSetProperty(valueDictionary, val => _documentTypeId = int.Parse(val), "nodeType");
//ValidateAndSetProperty(valueDictionary, val => _writerName = val, "writerName");
ValidateAndSetProperty(valueDictionary, val => _creatorName = val, "creatorName", "writerName"); //this is a bit of a hack fix for: U4-1132
//ValidateAndSetProperty(valueDictionary, val => _writerId = int.Parse(val), "writerID");
ValidateAndSetProperty(valueDictionary, val => _creatorId = int.Parse(val), "creatorID", "writerID"); //this is a bit of a hack fix for: U4-1132
ValidateAndSetProperty(valueDictionary, val => _path = val, "path", "__Path");
ValidateAndSetProperty(valueDictionary, val => _createDate = ParseDateTimeValue(val), "createDate");
ValidateAndSetProperty(valueDictionary, val => _updateDate = ParseDateTimeValue(val), "updateDate");
ValidateAndSetProperty(valueDictionary, val => _level = int.Parse(val), "level");
ValidateAndSetProperty(valueDictionary, val =>
{
int pId;
ParentId = -1;
if (int.TryParse(val, out pId))
{
ParentId = pId;
}
}, "parentID");
_contentType = contentTypeCache.Get(PublishedItemType.Media, _documentTypeAlias);
_properties = new Collection<IPublishedProperty>();
//handle content type properties
//make sure we create them even if there's no value
foreach (var propertyType in _contentType.PropertyTypes)
{
var alias = propertyType.Alias;
_keysAdded.Add(alias);
string value;
const bool isPreviewing = false; // false :: never preview a media
var property = valueDictionary.TryGetValue(alias, out value) == false || value == null
? new XmlPublishedProperty(propertyType, this, isPreviewing)
: new XmlPublishedProperty(propertyType, this, isPreviewing, value);
_properties.Add(property);
}
//loop through remaining values that haven't been applied
foreach (var i in valueDictionary.Where(x =>
_keysAdded.Contains(x.Key) == false // not already processed
&& IgnoredKeys.Contains(x.Key) == false)) // not ignorable
{
if (i.Key.InvariantStartsWith("__"))
{
// no type for that one, dunno how to convert, drop it
//IPublishedProperty property = new PropertyResult(i.Key, i.Value, PropertyResultType.CustomProperty);
//_properties.Add(property);
}
else
{
// this is a property that does not correspond to anything, ignore and log
Current.Logger.Warn<PublishedMediaCache>("Dropping property \"" + i.Key + "\" because it does not belong to the content type.");
}
}
}
private DateTime ParseDateTimeValue(string val)
{
if (LoadedFromExamine == false)
return DateTime.Parse(val);
//we need to parse the date time using Lucene converters
var ticks = long.Parse(val);
return new DateTime(ticks);
}
/// <summary>
/// Flag to get/set if this was laoded from examine cache
/// </summary>
internal bool LoadedFromExamine { get; }
//private readonly Func<DictionaryPublishedContent, IPublishedContent> _getParent;
private readonly Lazy<IPublishedContent> _getParent;
//private readonly Func<DictionaryPublishedContent, IEnumerable<IPublishedContent>> _getChildren;
private readonly Lazy<IEnumerable<IPublishedContent>> _getChildren;
private readonly Func<DictionaryPublishedContent, string, IPublishedProperty> _getProperty;
private readonly ICacheProvider _cacheProvider;
/// <summary>
/// Returns 'Media' as the item type
/// </summary>
public override PublishedItemType ItemType => PublishedItemType.Media;
public override IPublishedContent Parent => _getParent.Value;
public int ParentId { get; private set; }
public override int Id => _id;
public override Guid Key => _key;
public override int TemplateId => 0;
public override int SortOrder => _sortOrder;
public override string Name => _name;
public override IReadOnlyDictionary<string, PublishedCultureName> CultureNames => throw new NotSupportedException();
public override string UrlName => _urlName;
public override string DocumentTypeAlias => _documentTypeAlias;
public override int DocumentTypeId => _documentTypeId;
public override string WriterName => _creatorName;
public override string CreatorName => _creatorName;
public override int WriterId => _creatorId;
public override int CreatorId => _creatorId;
public override string Path => _path;
public override DateTime CreateDate => _createDate;
public override DateTime UpdateDate => _updateDate;
public override int Level => _level;
public override bool IsDraft => false;
public override IEnumerable<IPublishedProperty> Properties => _properties;
public override IEnumerable<IPublishedContent> Children => _getChildren.Value;
public override IPublishedProperty GetProperty(string alias)
{
return _getProperty(this, alias);
}
public override PublishedContentType ContentType => _contentType;
// override to implement cache
// cache at context level, ie once for the whole request
// but cache is not shared by requests because we wouldn't know how to clear it
public override IPublishedProperty GetProperty(string alias, bool recurse)
{
if (recurse == false) return GetProperty(alias);
var key = $"XmlPublishedCache.PublishedMediaCache:RecursiveProperty-{Id}-{alias.ToLowerInvariant()}";
var cacheProvider = _cacheProvider;
return cacheProvider.GetCacheItem<IPublishedProperty>(key, () => base.GetProperty(alias, true));
}
private readonly List<string> _keysAdded = new List<string>();
private int _id;
private Guid _key;
//private int _templateId;
private int _sortOrder;
private string _name;
private string _urlName;
private string _documentTypeAlias;
private int _documentTypeId;
//private string _writerName;
private string _creatorName;
//private int _writerId;
private int _creatorId;
private string _path;
private DateTime _createDate;
private DateTime _updateDate;
//private Guid _version;
private int _level;
private readonly ICollection<IPublishedProperty> _properties;
private readonly PublishedContentType _contentType;
private void ValidateAndSetProperty(IReadOnlyDictionary<string, string> valueDictionary, Action<string> setProperty, params string[] potentialKeys)
{
var key = potentialKeys.FirstOrDefault(x => valueDictionary.ContainsKey(x) && valueDictionary[x] != null);
if (key == null)
{
throw new FormatException("The valueDictionary is not formatted correctly and is missing any of the '" + string.Join(",", potentialKeys) + "' elements");
}
setProperty(valueDictionary[key]);
_keysAdded.Add(key);
}
}
internal void Resync()
{
// clear recursive properties cached by XmlPublishedContent.GetProperty

View File

@@ -150,25 +150,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
}
}
public override IReadOnlyDictionary<string, PublishedCultureName> CultureNames => throw new NotSupportedException();
public override PublishedCultureInfos GetCulture(string culture = ".") => throw new NotSupportedException();
public override string DocumentTypeAlias
{
get
{
if (_nodeInitialized == false) InitializeNode();
return _docTypeAlias;
}
}
public override int DocumentTypeId
{
get
{
if (_nodeInitialized == false) InitializeNode();
return _docTypeId;
}
}
public override IReadOnlyDictionary<string, PublishedCultureInfos> Cultures => throw new NotSupportedException();
public override string WriterName
{