PublishedContent - the big refactoring
This commit is contained in:
@@ -17,6 +17,7 @@ using umbraco.presentation.preview;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
{
|
||||
// fixme - does not implement the content model factory
|
||||
internal class PublishedContentCache : IPublishedContentCache
|
||||
{
|
||||
#region Routes cache
|
||||
@@ -235,14 +236,14 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
#region Converters
|
||||
|
||||
private static IPublishedContent ConvertToDocument(XmlNode xmlNode)
|
||||
private static IPublishedContent ConvertToDocument(XmlNode xmlNode, bool isPreviewing)
|
||||
{
|
||||
return xmlNode == null ? null : new Models.XmlPublishedContent(xmlNode);
|
||||
}
|
||||
return xmlNode == null ? null : new XmlPublishedContent(xmlNode, isPreviewing);
|
||||
}
|
||||
|
||||
private static IEnumerable<IPublishedContent> ConvertToDocuments(XmlNodeList xmlNodes)
|
||||
private static IEnumerable<IPublishedContent> ConvertToDocuments(XmlNodeList xmlNodes, bool isPreviewing)
|
||||
{
|
||||
return xmlNodes.Cast<XmlNode>().Select(xmlNode => new Models.XmlPublishedContent(xmlNode));
|
||||
return xmlNodes.Cast<XmlNode>().Select(xmlNode => new XmlPublishedContent(xmlNode, isPreviewing));
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -251,12 +252,12 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
public virtual IPublishedContent GetById(UmbracoContext umbracoContext, bool preview, int nodeId)
|
||||
{
|
||||
return ConvertToDocument(GetXml(umbracoContext, preview).GetElementById(nodeId.ToString(CultureInfo.InvariantCulture)));
|
||||
return ConvertToDocument(GetXml(umbracoContext, preview).GetElementById(nodeId.ToString(CultureInfo.InvariantCulture)), preview);
|
||||
}
|
||||
|
||||
public virtual IEnumerable<IPublishedContent> GetAtRoot(UmbracoContext umbracoContext, bool preview)
|
||||
{
|
||||
return ConvertToDocuments(GetXml(umbracoContext, preview).SelectNodes(XPathStrings.RootDocuments));
|
||||
return ConvertToDocuments(GetXml(umbracoContext, preview).SelectNodes(XPathStrings.RootDocuments), preview);
|
||||
}
|
||||
|
||||
public virtual IPublishedContent GetSingleByXPath(UmbracoContext umbracoContext, bool preview, string xpath, params XPathVariable[] vars)
|
||||
@@ -268,7 +269,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
var node = vars == null
|
||||
? xml.SelectSingleNode(xpath)
|
||||
: xml.SelectSingleNode(xpath, vars);
|
||||
return ConvertToDocument(node);
|
||||
return ConvertToDocument(node, preview);
|
||||
}
|
||||
|
||||
public virtual IPublishedContent GetSingleByXPath(UmbracoContext umbracoContext, bool preview, XPathExpression xpath, params XPathVariable[] vars)
|
||||
@@ -279,7 +280,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
var node = vars == null
|
||||
? xml.SelectSingleNode(xpath)
|
||||
: xml.SelectSingleNode(xpath, vars);
|
||||
return ConvertToDocument(node);
|
||||
return ConvertToDocument(node, preview);
|
||||
}
|
||||
|
||||
public virtual IEnumerable<IPublishedContent> GetByXPath(UmbracoContext umbracoContext, bool preview, string xpath, params XPathVariable[] vars)
|
||||
@@ -291,7 +292,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
var nodes = vars == null
|
||||
? xml.SelectNodes(xpath)
|
||||
: xml.SelectNodes(xpath, vars);
|
||||
return ConvertToDocuments(nodes);
|
||||
return ConvertToDocuments(nodes, preview);
|
||||
}
|
||||
|
||||
public virtual IEnumerable<IPublishedContent> GetByXPath(UmbracoContext umbracoContext, bool preview, XPathExpression xpath, params XPathVariable[] vars)
|
||||
@@ -302,7 +303,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
var nodes = vars == null
|
||||
? xml.SelectNodes(xpath)
|
||||
: xml.SelectNodes(xpath, vars);
|
||||
return ConvertToDocuments(nodes);
|
||||
return ConvertToDocuments(nodes, preview);
|
||||
}
|
||||
|
||||
public virtual bool HasContent(UmbracoContext umbracoContext, bool preview)
|
||||
|
||||
@@ -12,6 +12,7 @@ using Umbraco.Core;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Xml;
|
||||
using Umbraco.Web.Models;
|
||||
using UmbracoExamine;
|
||||
@@ -27,7 +28,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
/// <remarks>
|
||||
/// NOTE: In the future if we want to properly cache all media this class can be extended or replaced when these classes/interfaces are exposed publicly.
|
||||
/// </remarks>
|
||||
internal class PublishedMediaCache : IPublishedMediaCache
|
||||
// fixme - does not implement the content model factory
|
||||
internal class PublishedMediaCache : IPublishedMediaCache
|
||||
{
|
||||
public PublishedMediaCache()
|
||||
{
|
||||
@@ -314,7 +316,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
/// <param name="dd"> </param>
|
||||
/// <param name="alias"></param>
|
||||
/// <returns></returns>
|
||||
private IPublishedContentProperty GetProperty(DictionaryPublishedContent dd, string alias)
|
||||
private IPublishedProperty GetProperty(DictionaryPublishedContent dd, string alias)
|
||||
{
|
||||
if (dd.LoadedFromExamine)
|
||||
{
|
||||
@@ -326,7 +328,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
//is cached so will be quicker to look up.
|
||||
if (dd.Properties.Any(x => x.Alias == UmbracoContentIndexer.NodeTypeAliasFieldName))
|
||||
{
|
||||
var aliasesAndNames = ContentType.GetAliasesAndNames(dd.Properties.First(x => x.Alias.InvariantEquals(UmbracoContentIndexer.NodeTypeAliasFieldName)).Value.ToString());
|
||||
var aliasesAndNames = ContentType.GetAliasesAndNames(dd.Properties.First(x => x.Alias.InvariantEquals(UmbracoContentIndexer.NodeTypeAliasFieldName)).RawValue.ToString());
|
||||
if (aliasesAndNames != null)
|
||||
{
|
||||
if (!aliasesAndNames.ContainsKey(alias))
|
||||
@@ -466,12 +468,15 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
/// </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
|
||||
|
||||
public DictionaryPublishedContent(
|
||||
IDictionary<string, string> valueDictionary,
|
||||
Func<DictionaryPublishedContent, IPublishedContent> getParent,
|
||||
Func<DictionaryPublishedContent, IEnumerable<IPublishedContent>> getChildren,
|
||||
Func<DictionaryPublishedContent, string, IPublishedContentProperty> getProperty,
|
||||
Func<DictionaryPublishedContent, string, IPublishedProperty> getProperty,
|
||||
bool fromExamine)
|
||||
{
|
||||
if (valueDictionary == null) throw new ArgumentNullException("valueDictionary");
|
||||
@@ -509,15 +514,27 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
}
|
||||
}, "parentID");
|
||||
|
||||
_properties = new Collection<IPublishedContentProperty>();
|
||||
_contentType = PublishedContentType.Get(PublishedItemType.Media, _documentTypeAlias);
|
||||
_properties = new Collection<IPublishedProperty>();
|
||||
|
||||
//loop through remaining values that haven't been applied
|
||||
foreach (var i in valueDictionary.Where(x => !_keysAdded.Contains(x.Key)))
|
||||
{
|
||||
//this is taken from examine
|
||||
_properties.Add(i.Key.InvariantStartsWith("__")
|
||||
? new PropertyResult(i.Key, i.Value, Guid.Empty, PropertyResultType.CustomProperty)
|
||||
: new PropertyResult(i.Key, i.Value, Guid.Empty, PropertyResultType.UserProperty));
|
||||
IPublishedProperty property;
|
||||
|
||||
if (i.Key.InvariantStartsWith("__"))
|
||||
{
|
||||
// no type for tha tone, dunno how to convert
|
||||
property = new PropertyResult(i.Key, i.Value, Guid.Empty, PropertyResultType.CustomProperty);
|
||||
}
|
||||
else
|
||||
{
|
||||
// use property type to ensure proper conversion
|
||||
var propertyType = _contentType.GetPropertyType(i.Key);
|
||||
property = new XmlPublishedProperty(propertyType, false, i.Value); // false :: never preview a media
|
||||
}
|
||||
|
||||
_properties.Add(property);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,7 +563,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
private readonly Func<DictionaryPublishedContent, IPublishedContent> _getParent;
|
||||
private readonly Func<DictionaryPublishedContent, IEnumerable<IPublishedContent>> _getChildren;
|
||||
private readonly Func<DictionaryPublishedContent, string, IPublishedContentProperty> _getProperty;
|
||||
private readonly Func<DictionaryPublishedContent, string, IPublishedProperty> _getProperty;
|
||||
|
||||
/// <summary>
|
||||
/// Returns 'Media' as the item type
|
||||
@@ -646,7 +663,12 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
get { return _level; }
|
||||
}
|
||||
|
||||
public override ICollection<IPublishedContentProperty> Properties
|
||||
public override bool IsDraft
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override ICollection<IPublishedProperty> Properties
|
||||
{
|
||||
get { return _properties; }
|
||||
}
|
||||
@@ -656,11 +678,49 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
get { return _getChildren(this); }
|
||||
}
|
||||
|
||||
public override IPublishedContentProperty GetProperty(string alias)
|
||||
public override IPublishedProperty GetProperty(string alias)
|
||||
{
|
||||
return _getProperty(this, alias);
|
||||
}
|
||||
|
||||
public override PublishedContentType ContentType
|
||||
{
|
||||
get { return _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);
|
||||
|
||||
IPublishedProperty property;
|
||||
string key = null;
|
||||
var cache = UmbracoContextCache.Current;
|
||||
|
||||
if (cache != null)
|
||||
{
|
||||
key = string.Format("RECURSIVE_PROPERTY::{0}::{1}", Id, alias.ToLowerInvariant());
|
||||
object o;
|
||||
if (cache.TryGetValue(key, out o))
|
||||
{
|
||||
property = o as IPublishedProperty;
|
||||
if (property == null)
|
||||
throw new InvalidOperationException("Corrupted cache.");
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
// else get it for real, no cache
|
||||
property = base.GetProperty(alias, true);
|
||||
|
||||
if (cache != null)
|
||||
cache[key] = property;
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
private readonly List<string> _keysAdded = new List<string>();
|
||||
private int _id;
|
||||
private int _templateId;
|
||||
@@ -678,7 +738,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
private DateTime _updateDate;
|
||||
private Guid _version;
|
||||
private int _level;
|
||||
private readonly ICollection<IPublishedContentProperty> _properties;
|
||||
private readonly ICollection<IPublishedProperty> _properties;
|
||||
private readonly PublishedContentType _contentType;
|
||||
|
||||
private void ValidateAndSetProperty(IDictionary<string, string> valueDictionary, Action<string> setProperty, params string[] potentialKeys)
|
||||
{
|
||||
@@ -691,6 +752,6 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
setProperty(valueDictionary[key]);
|
||||
_keysAdded.Add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
{
|
||||
static class UmbracoContextCache
|
||||
{
|
||||
static readonly ConditionalWeakTable<UmbracoContext, ConcurrentDictionary<string, object>> Caches
|
||||
= new ConditionalWeakTable<UmbracoContext, ConcurrentDictionary<string, object>>();
|
||||
|
||||
public static ConcurrentDictionary<string, object> Current
|
||||
{
|
||||
get
|
||||
{
|
||||
var umbracoContext = UmbracoContext.Current;
|
||||
|
||||
// will get or create a value
|
||||
// a ConditionalWeakTable is thread-safe
|
||||
// does not prevent the context from being disposed, and then the dictionary will be disposed too
|
||||
return umbracoContext == null ? null : Caches.GetOrCreateValue(umbracoContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,448 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using System.Xml.XPath;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Web.Models;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Represents an IPublishedContent which is created based on an Xml structure.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[XmlType(Namespace = "http://umbraco.org/webservices/")]
|
||||
internal class XmlPublishedContent : PublishedContentBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <c>XmlPublishedContent</c> class with an Xml node.
|
||||
/// </summary>
|
||||
/// <param name="xmlNode">The Xml node.</param>
|
||||
/// <param name="isPreviewing">A value indicating whether the published content is being previewed.</param>
|
||||
public XmlPublishedContent(XmlNode xmlNode, bool isPreviewing)
|
||||
{
|
||||
_xmlNode = xmlNode;
|
||||
_isPreviewing = isPreviewing;
|
||||
InitializeStructure();
|
||||
Initialize();
|
||||
InitializeChildren();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <c>XmlPublishedContent</c> class with an Xml node,
|
||||
/// and a value indicating whether to lazy-initialize the instance.
|
||||
/// </summary>
|
||||
/// <param name="xmlNode">The Xml node.</param>
|
||||
/// <param name="isPreviewing">A value indicating whether the published content is being previewed.</param>
|
||||
/// <param name="lazyInitialize">A value indicating whether to lazy-initialize the instance.</param>
|
||||
/// <remarks>Lazy-initializationg is NOT thread-safe.</remarks>
|
||||
internal XmlPublishedContent(XmlNode xmlNode, bool isPreviewing, bool lazyInitialize)
|
||||
{
|
||||
_xmlNode = xmlNode;
|
||||
_isPreviewing = isPreviewing;
|
||||
InitializeStructure();
|
||||
if (lazyInitialize == false)
|
||||
{
|
||||
Initialize();
|
||||
InitializeChildren();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly XmlNode _xmlNode;
|
||||
|
||||
private bool _initialized;
|
||||
private bool _childrenInitialized;
|
||||
|
||||
private readonly ICollection<IPublishedContent> _children = new Collection<IPublishedContent>();
|
||||
private IPublishedContent _parent;
|
||||
|
||||
private int _id;
|
||||
private int _template;
|
||||
private string _name;
|
||||
private string _docTypeAlias;
|
||||
private int _docTypeId;
|
||||
private string _writerName;
|
||||
private string _creatorName;
|
||||
private int _writerId;
|
||||
private int _creatorId;
|
||||
private string _urlName;
|
||||
private string _path;
|
||||
private DateTime _createDate;
|
||||
private DateTime _updateDate;
|
||||
private Guid _version;
|
||||
private IPublishedProperty[] _properties;
|
||||
private int _sortOrder;
|
||||
private int _level;
|
||||
private bool _isDraft;
|
||||
private readonly bool _isPreviewing;
|
||||
private PublishedContentType _contentType;
|
||||
|
||||
public override IEnumerable<IPublishedContent> Children
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
if (_childrenInitialized == false)
|
||||
InitializeChildren();
|
||||
return _children.OrderBy(x => x.SortOrder);
|
||||
}
|
||||
}
|
||||
|
||||
public override IPublishedProperty GetProperty(string alias)
|
||||
{
|
||||
return Properties.FirstOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
}
|
||||
|
||||
// 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 cache = UmbracoContextCache.Current;
|
||||
|
||||
if (cache == null)
|
||||
return base.GetProperty(alias, true);
|
||||
|
||||
var key = string.Format("RECURSIVE_PROPERTY::{0}::{1}", Id, alias.ToLowerInvariant());
|
||||
var value = cache.GetOrAdd(key, k => base.GetProperty(alias, true));
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
var property = value as IPublishedProperty;
|
||||
if (property == null)
|
||||
throw new InvalidOperationException("Corrupted cache.");
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
public override PublishedItemType ItemType
|
||||
{
|
||||
get { return PublishedItemType.Content; }
|
||||
}
|
||||
|
||||
public override IPublishedContent Parent
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _parent;
|
||||
}
|
||||
}
|
||||
|
||||
public override int Id
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _id;
|
||||
}
|
||||
}
|
||||
|
||||
public override int TemplateId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _template;
|
||||
}
|
||||
}
|
||||
|
||||
public override int SortOrder
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _sortOrder;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
public override string DocumentTypeAlias
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _docTypeAlias;
|
||||
}
|
||||
}
|
||||
|
||||
public override int DocumentTypeId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _docTypeId;
|
||||
}
|
||||
}
|
||||
|
||||
public override string WriterName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _writerName;
|
||||
}
|
||||
}
|
||||
|
||||
public override string CreatorName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _creatorName;
|
||||
}
|
||||
}
|
||||
|
||||
public override int WriterId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _writerId;
|
||||
}
|
||||
}
|
||||
|
||||
public override int CreatorId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _creatorId;
|
||||
}
|
||||
}
|
||||
|
||||
public override string Path
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _path;
|
||||
}
|
||||
}
|
||||
|
||||
public override DateTime CreateDate
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _createDate;
|
||||
}
|
||||
}
|
||||
|
||||
public override DateTime UpdateDate
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _updateDate;
|
||||
}
|
||||
}
|
||||
|
||||
public override Guid Version
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _version;
|
||||
}
|
||||
}
|
||||
|
||||
public override string UrlName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _urlName;
|
||||
}
|
||||
}
|
||||
|
||||
public override int Level
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _level;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsDraft
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _isDraft;
|
||||
}
|
||||
}
|
||||
|
||||
public override ICollection<IPublishedProperty> Properties
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _properties;
|
||||
}
|
||||
}
|
||||
|
||||
public override PublishedContentType ContentType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initialized == false)
|
||||
Initialize();
|
||||
return _contentType;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeStructure()
|
||||
{
|
||||
// load parent if it exists and is a node
|
||||
|
||||
var parent = _xmlNode == null ? null : _xmlNode.ParentNode;
|
||||
if (parent == null) return;
|
||||
|
||||
if (parent.Name == "node" || (parent.Attributes != null && parent.Attributes.GetNamedItem("isDoc") != null))
|
||||
_parent = new XmlPublishedContent(parent, _isPreviewing, true);
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
if (_xmlNode == null) return;
|
||||
|
||||
if (_xmlNode.Attributes != null)
|
||||
{
|
||||
_id = int.Parse(_xmlNode.Attributes.GetNamedItem("id").Value);
|
||||
if (_xmlNode.Attributes.GetNamedItem("template") != null)
|
||||
_template = int.Parse(_xmlNode.Attributes.GetNamedItem("template").Value);
|
||||
if (_xmlNode.Attributes.GetNamedItem("sortOrder") != null)
|
||||
_sortOrder = int.Parse(_xmlNode.Attributes.GetNamedItem("sortOrder").Value);
|
||||
if (_xmlNode.Attributes.GetNamedItem("nodeName") != null)
|
||||
_name = _xmlNode.Attributes.GetNamedItem("nodeName").Value;
|
||||
if (_xmlNode.Attributes.GetNamedItem("writerName") != null)
|
||||
_writerName = _xmlNode.Attributes.GetNamedItem("writerName").Value;
|
||||
if (_xmlNode.Attributes.GetNamedItem("urlName") != null)
|
||||
_urlName = _xmlNode.Attributes.GetNamedItem("urlName").Value;
|
||||
// Creatorname is new in 2.1, so published xml might not have it!
|
||||
try
|
||||
{
|
||||
_creatorName = _xmlNode.Attributes.GetNamedItem("creatorName").Value;
|
||||
}
|
||||
catch
|
||||
{
|
||||
_creatorName = _writerName;
|
||||
}
|
||||
|
||||
//Added the actual userID, as a user cannot be looked up via full name only...
|
||||
if (_xmlNode.Attributes.GetNamedItem("creatorID") != null)
|
||||
_creatorId = int.Parse(_xmlNode.Attributes.GetNamedItem("creatorID").Value);
|
||||
if (_xmlNode.Attributes.GetNamedItem("writerID") != null)
|
||||
_writerId = int.Parse(_xmlNode.Attributes.GetNamedItem("writerID").Value);
|
||||
|
||||
if (UmbracoSettings.UseLegacyXmlSchema)
|
||||
{
|
||||
if (_xmlNode.Attributes.GetNamedItem("nodeTypeAlias") != null)
|
||||
_docTypeAlias = _xmlNode.Attributes.GetNamedItem("nodeTypeAlias").Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_docTypeAlias = _xmlNode.Name;
|
||||
}
|
||||
|
||||
if (_xmlNode.Attributes.GetNamedItem("nodeType") != null)
|
||||
_docTypeId = int.Parse(_xmlNode.Attributes.GetNamedItem("nodeType").Value);
|
||||
if (_xmlNode.Attributes.GetNamedItem("path") != null)
|
||||
_path = _xmlNode.Attributes.GetNamedItem("path").Value;
|
||||
if (_xmlNode.Attributes.GetNamedItem("version") != null)
|
||||
_version = new Guid(_xmlNode.Attributes.GetNamedItem("version").Value);
|
||||
if (_xmlNode.Attributes.GetNamedItem("createDate") != null)
|
||||
_createDate = DateTime.Parse(_xmlNode.Attributes.GetNamedItem("createDate").Value);
|
||||
if (_xmlNode.Attributes.GetNamedItem("updateDate") != null)
|
||||
_updateDate = DateTime.Parse(_xmlNode.Attributes.GetNamedItem("updateDate").Value);
|
||||
if (_xmlNode.Attributes.GetNamedItem("level") != null)
|
||||
_level = int.Parse(_xmlNode.Attributes.GetNamedItem("level").Value);
|
||||
|
||||
_isDraft = (_xmlNode.Attributes.GetNamedItem("isDraft") != null);
|
||||
}
|
||||
|
||||
// load data
|
||||
var dataXPath = UmbracoSettings.UseLegacyXmlSchema ? "data" : "* [not(@isDoc)]";
|
||||
var nodes = _xmlNode.SelectNodes(dataXPath);
|
||||
|
||||
_contentType = PublishedContentType.Get(PublishedItemType.Content, _docTypeAlias);
|
||||
|
||||
var propertyNodes = new Dictionary<string, XmlNode>();
|
||||
if (nodes != null)
|
||||
foreach (XmlNode n in nodes)
|
||||
{
|
||||
var alias = UmbracoSettings.UseLegacyXmlSchema
|
||||
? n.Attributes.GetNamedItem("alias").Value
|
||||
: n.Name;
|
||||
propertyNodes[alias.ToLowerInvariant()] = n;
|
||||
}
|
||||
|
||||
_properties = _contentType.PropertyTypes.Select(p =>
|
||||
{
|
||||
XmlNode n;
|
||||
return propertyNodes.TryGetValue(p.Alias.ToLowerInvariant(), out n)
|
||||
? new XmlPublishedProperty(p, _isPreviewing, n)
|
||||
: new XmlPublishedProperty(p, _isPreviewing);
|
||||
}).Cast<IPublishedProperty>().ToArray();
|
||||
|
||||
// warn: this is not thread-safe...
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
private void InitializeChildren()
|
||||
{
|
||||
if (_xmlNode == null) return;
|
||||
|
||||
// load children
|
||||
var childXPath = UmbracoSettings.UseLegacyXmlSchema ? "node" : "* [@isDoc]";
|
||||
var nav = _xmlNode.CreateNavigator();
|
||||
var expr = nav.Compile(childXPath);
|
||||
expr.AddSort("@sortOrder", XmlSortOrder.Ascending, XmlCaseOrder.None, "", XmlDataType.Number);
|
||||
var iterator = nav.Select(expr);
|
||||
while (iterator.MoveNext())
|
||||
_children.Add(new XmlPublishedContent(((IHasXmlNode)iterator.Current).GetNode(), _isPreviewing, true));
|
||||
|
||||
// warn: this is not thread-safe
|
||||
_childrenInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Web.Models;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Represents an IDocumentProperty which is created based on an Xml structure.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[XmlType(Namespace = "http://umbraco.org/webservices/")]
|
||||
internal class XmlPublishedProperty : PublishedPropertyBase
|
||||
{
|
||||
private readonly string _xmlValue; // the raw, xml node value
|
||||
private readonly Lazy<object> _sourceValue;
|
||||
private readonly Lazy<object> _value;
|
||||
private readonly Lazy<object> _xpathValue;
|
||||
private readonly bool _isPreviewing;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the raw value of the property.
|
||||
/// </summary>
|
||||
public override object RawValue { get { return _xmlValue; } }
|
||||
|
||||
// in the Xml cache, everything is a string, and to have a value
|
||||
// you want to have a non-null, non-empty string.
|
||||
public override bool HasValue
|
||||
{
|
||||
get { return _xmlValue.Trim().Length > 0; }
|
||||
}
|
||||
|
||||
public override object Value { get { return _value.Value; } }
|
||||
public override object XPathValue { get { return _xpathValue.Value; } }
|
||||
|
||||
public XmlPublishedProperty(PublishedPropertyType propertyType, bool isPreviewing, XmlNode propertyXmlData)
|
||||
: this(propertyType, isPreviewing)
|
||||
{
|
||||
if (propertyXmlData == null)
|
||||
throw new ArgumentNullException("propertyXmlData", "Property xml source is null");
|
||||
_xmlValue = XmlHelper.GetNodeValue(propertyXmlData);
|
||||
}
|
||||
|
||||
public XmlPublishedProperty(PublishedPropertyType propertyType, bool isPreviewing, string propertyData)
|
||||
: this(propertyType, isPreviewing)
|
||||
{
|
||||
if (propertyData == null)
|
||||
throw new ArgumentNullException("propertyData");
|
||||
_xmlValue = propertyData;
|
||||
}
|
||||
|
||||
public XmlPublishedProperty(PublishedPropertyType propertyType, bool isPreviewing)
|
||||
: base(propertyType)
|
||||
{
|
||||
_xmlValue = string.Empty;
|
||||
_isPreviewing = isPreviewing;
|
||||
|
||||
_sourceValue = new Lazy<object>(() => PropertyType.ConvertDataToSource(_xmlValue, _isPreviewing));
|
||||
_value = new Lazy<object>(() => PropertyType.ConvertSourceToObject(_sourceValue.Value, _isPreviewing));
|
||||
_xpathValue = new Lazy<object>(() => PropertyType.ConvertSourceToXPath(_sourceValue.Value, _isPreviewing));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user