Cleanup IPublishedContent
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user