147 lines
5.9 KiB
C#
147 lines
5.9 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Xml;
|
|
using System.Xml.Linq;
|
|
using Umbraco.Core.Models;
|
|
using Umbraco.Core.Models.Rdbms;
|
|
using Umbraco.Core.Persistence;
|
|
using umbraco.interfaces;
|
|
|
|
namespace Umbraco.Core.PropertyEditors
|
|
{
|
|
|
|
/// <summary>
|
|
/// This is used purelty to attempt to maintain some backwards compatibility with new property editors that don't have a
|
|
/// legacy property editor predecessor when developers are using the legacy APIs
|
|
/// </summary>
|
|
internal class BackwardsCompatibleData : IData, IDataValueSetter
|
|
{
|
|
private readonly string _propertyEditorAlias;
|
|
private bool _valueLoaded = false;
|
|
private object _value;
|
|
|
|
public BackwardsCompatibleData(string propertyEditorAlias)
|
|
{
|
|
_propertyEditorAlias = propertyEditorAlias;
|
|
}
|
|
|
|
public int PropertyId { set; get; }
|
|
|
|
/// <summary>
|
|
/// This returns the value
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// There's code here to load the data from the db just like the legacy DefaultData does but in theory the value of this
|
|
/// IData should always be set using the IDataValueSetter.SetValue which is done externally. Just in case there's some edge
|
|
/// case out there that doesn't set this value, we'll go and get it based on the same logic in DefaultData.
|
|
/// </remarks>
|
|
public virtual object Value
|
|
{
|
|
get
|
|
{
|
|
//Lazy load the value when it is required.
|
|
if (_valueLoaded == false)
|
|
{
|
|
LoadValueFromDatabase();
|
|
_valueLoaded = true;
|
|
}
|
|
return _value;
|
|
}
|
|
set
|
|
{
|
|
_value = value;
|
|
_valueLoaded = true;
|
|
}
|
|
}
|
|
|
|
|
|
public XmlNode ToXMl(XmlDocument data)
|
|
{
|
|
//we'll get the property editor by alias, if it exists (which it absolutely should), then we'll have to create a
|
|
// fake 'Property' object and pass it to the ConvertDbToXml method so we can get the correct XML fragment that
|
|
// it needs to make.
|
|
var propertyEditor = PropertyEditorResolver.Current.GetByAlias(_propertyEditorAlias);
|
|
if (propertyEditor != null)
|
|
{
|
|
//create a 'fake' property - we will never know the actual db type here so we'll just make it nvarchar, this shouldn't
|
|
// make any difference for the conversion process though.
|
|
var property = new Property(new PropertyType(_propertyEditorAlias, DataTypeDatabaseType.Nvarchar))
|
|
{
|
|
Id = PropertyId,
|
|
Value = Value
|
|
};
|
|
var xd = new XmlDocument();
|
|
var xNode = propertyEditor.ValueEditor.ConvertDbToXml(property, property.PropertyType, ApplicationContext.Current.Services.DataTypeService);
|
|
|
|
//check if this xml fragment can be converted to an XmlNode
|
|
var xContainer = xNode as XContainer;
|
|
if (xContainer != null)
|
|
{
|
|
//imports to the document
|
|
xContainer.GetXmlNode(xd);
|
|
// return the XML node.
|
|
return data.ImportNode(xd.DocumentElement, true);
|
|
}
|
|
|
|
return ReturnCDataElement(data);
|
|
}
|
|
|
|
//if for some reason the prop editor wasn't found we'll default to returning the string value in a CDATA block.
|
|
return ReturnCDataElement(data);
|
|
}
|
|
|
|
private XmlNode ReturnCDataElement(XmlDocument doc)
|
|
{
|
|
var sValue = Value != null ? Value.ToString() : string.Empty;
|
|
return doc.CreateCDataSection(sValue);
|
|
}
|
|
|
|
public void MakeNew(int propertyId)
|
|
{
|
|
//DO nothing
|
|
}
|
|
|
|
public void Delete()
|
|
{
|
|
throw new NotSupportedException(
|
|
typeof(IData)
|
|
+ " is a legacy object and is not supported by runtime generated "
|
|
+ " instances to maintain backwards compatibility with the legacy APIs. Consider upgrading your code to use the new Services APIs.");
|
|
}
|
|
|
|
/// <summary>
|
|
/// This is here for performance reasons since in some cases we will have already resolved the value from the db
|
|
/// and want to just give this object the value so it doesn't go re-look it up from the database.
|
|
/// </summary>
|
|
/// <param name="val"></param>
|
|
/// <param name="strDbType"></param>
|
|
void IDataValueSetter.SetValue(object val, string strDbType)
|
|
{
|
|
_value = val;
|
|
_valueLoaded = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// In the case where the value is not set, this will go get it from the db ourselves - this shouldn't really ever be needed,
|
|
/// the value should always be set with IDataValueSetter.SetValue
|
|
/// </summary>
|
|
private void LoadValueFromDatabase()
|
|
{
|
|
var sql = new Sql();
|
|
sql.Select("*")
|
|
.From<PropertyDataDto>()
|
|
.InnerJoin<PropertyTypeDto>()
|
|
.On<PropertyTypeDto, PropertyDataDto>(x => x.Id, y => y.PropertyTypeId)
|
|
.InnerJoin<DataTypeDto>()
|
|
.On<DataTypeDto, PropertyTypeDto>(x => x.DataTypeId, y => y.DataTypeId)
|
|
.Where<PropertyDataDto>(x => x.Id == PropertyId);
|
|
var dto = ApplicationContext.Current.DatabaseContext.Database.Fetch<PropertyDataDto, PropertyTypeDto, DataTypeDto>(sql).FirstOrDefault();
|
|
|
|
if (dto != null)
|
|
{
|
|
//get the value for the data type, if null, set it to an empty string
|
|
_value = dto.GetValue;
|
|
}
|
|
}
|
|
}
|
|
} |