added Picker Relations datatype - previously uComponents: MultiPicker Relations (renamed as can work with single item pickers as well as multipickers)
This commit is contained in:
@@ -0,0 +1,267 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using umbraco.BusinessLogic; // ApplicationBase
|
||||
using umbraco.cms.businesslogic; // SaveEventArgs
|
||||
using umbraco.cms.businesslogic.media; // Media
|
||||
using umbraco.cms.businesslogic.member; // Member
|
||||
using umbraco.cms.businesslogic.web; // Documentusing umbraco.cms.businesslogic.propertytype;
|
||||
using umbraco.cms.businesslogic.property;
|
||||
using umbraco.cms.businesslogic.relation;
|
||||
using umbraco.DataLayer;
|
||||
|
||||
namespace umbraco.editorControls.PickerRelations
|
||||
{
|
||||
/// <summary>
|
||||
/// Event handler that will convert a CSV into Relations
|
||||
/// </summary>
|
||||
public class PickerRelationsEventHandler : ApplicationBase
|
||||
{
|
||||
private enum PickerStorageFormat
|
||||
{
|
||||
Csv,
|
||||
Xml
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of PickerRelationsEventHandler,
|
||||
/// hooks into the after event of saving a Content node, Media item or a Member
|
||||
/// </summary>
|
||||
public PickerRelationsEventHandler()
|
||||
{
|
||||
Document.AfterSave += new Document.SaveEventHandler(this.AfterSave);
|
||||
Media.AfterSave += new Media.SaveEventHandler(this.AfterSave);
|
||||
Member.AfterSave += new Member.SaveEventHandler(this.AfterSave);
|
||||
|
||||
Document.BeforeDelete += new Document.DeleteEventHandler(this.BeforeDelete);
|
||||
Media.BeforeDelete += new Media.DeleteEventHandler(this.BeforeDelete);
|
||||
Member.BeforeDelete += new Member.DeleteEventHandler(this.BeforeDelete);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Event after all properties have been saved
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void AfterSave(Content sender, SaveEventArgs e)
|
||||
{
|
||||
Guid pickerRelationsId = new Guid(DataTypeGuids.PickerRelationsId);
|
||||
|
||||
// For each PickerRelations datatype
|
||||
foreach (Property pickerRelationsProperty in from property in sender.GenericProperties
|
||||
where property.PropertyType.DataTypeDefinition.DataType.Id == pickerRelationsId
|
||||
select property)
|
||||
{
|
||||
// used to identify this datatype instance - relations created are marked with this in the comment field
|
||||
string instanceIdentifier = "[\"PropertyTypeId\":" + pickerRelationsProperty.PropertyType.Id.ToString() + "]";
|
||||
|
||||
// get configuration options for datatype
|
||||
PickerRelationsOptions options = ((PickerRelationsPreValueEditor)pickerRelationsProperty.PropertyType.DataTypeDefinition.DataType.PrevalueEditor).Options;
|
||||
|
||||
// find Picker source propertyAlias field on sender
|
||||
Property pickerProperty = sender.getProperty(options.PropertyAlias);
|
||||
|
||||
if (pickerProperty != null)
|
||||
{
|
||||
// get relationType from options
|
||||
RelationType relationType = RelationType.GetById(options.RelationTypeId);
|
||||
|
||||
if (relationType != null)
|
||||
{
|
||||
// validate: 1) check current type of sender matches that expected by the relationType, validation method is in the DataEditor
|
||||
uQuery.UmbracoObjectType contextObjectType = uQuery.UmbracoObjectType.Unknown;
|
||||
switch (sender.GetType().ToString())
|
||||
{
|
||||
case "umbraco.cms.businesslogic.web.Document": contextObjectType = uQuery.UmbracoObjectType.Document; break;
|
||||
case "umbraco.cms.businesslogic.media.Media": contextObjectType = uQuery.UmbracoObjectType.Media; break;
|
||||
case "umbraco.cms.businesslogic.member.Member": contextObjectType = uQuery.UmbracoObjectType.Member; break;
|
||||
}
|
||||
|
||||
if (((PickerRelationsDataEditor)pickerRelationsProperty.PropertyType.DataTypeDefinition.DataType.DataEditor)
|
||||
.IsContextUmbracoObjectTypeValid(contextObjectType, relationType))
|
||||
{
|
||||
|
||||
uQuery.UmbracoObjectType pickerUmbracoObjectType = uQuery.UmbracoObjectType.Unknown;
|
||||
|
||||
// Get the object type expected by the associated relation type and if this datatype has been configures as a rever index
|
||||
pickerUmbracoObjectType = ((PickerRelationsDataEditor)pickerRelationsProperty.PropertyType.DataTypeDefinition.DataType.DataEditor)
|
||||
.GetPickerUmbracoObjectType(relationType);
|
||||
|
||||
|
||||
// clear all exisitng relations (or look to see previous verion of sender to delete changes ?)
|
||||
DeleteRelations(relationType, sender.Id, options.ReverseIndexing, instanceIdentifier);
|
||||
|
||||
string pickerPropertyValue = pickerProperty.Value.ToString();
|
||||
|
||||
var pickerStorageFormat = PickerStorageFormat.Csv; // Assume default of csv
|
||||
|
||||
if (xmlHelper.CouldItBeXml(pickerPropertyValue))
|
||||
{
|
||||
pickerStorageFormat = PickerStorageFormat.Xml;
|
||||
}
|
||||
|
||||
// Creating instances of Documents / Media / Members ensures the IDs are of a valid type - be quicker to check with GetUmbracoObjectType(int)
|
||||
Dictionary<int, string> pickerItems = null;
|
||||
switch (pickerUmbracoObjectType)
|
||||
{
|
||||
case uQuery.UmbracoObjectType.Document:
|
||||
switch (pickerStorageFormat)
|
||||
{
|
||||
case PickerStorageFormat.Csv:
|
||||
pickerItems = uQuery.GetDocumentsByCsv(pickerPropertyValue).ToNameIds();
|
||||
break;
|
||||
case PickerStorageFormat.Xml:
|
||||
pickerItems = uQuery.GetDocumentsByXml(pickerPropertyValue).ToNameIds();
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case uQuery.UmbracoObjectType.Media:
|
||||
switch (pickerStorageFormat)
|
||||
{
|
||||
case PickerStorageFormat.Csv:
|
||||
pickerItems = uQuery.GetMediaByCsv(pickerPropertyValue).ToNameIds();
|
||||
break;
|
||||
case PickerStorageFormat.Xml:
|
||||
pickerItems = uQuery.GetMediaByXml(pickerPropertyValue).ToNameIds();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case uQuery.UmbracoObjectType.Member:
|
||||
switch (pickerStorageFormat)
|
||||
{
|
||||
case PickerStorageFormat.Csv:
|
||||
pickerItems = uQuery.GetMembersByCsv(pickerPropertyValue).ToNameIds();
|
||||
break;
|
||||
case PickerStorageFormat.Xml:
|
||||
pickerItems = uQuery.GetMembersByXml(pickerPropertyValue).ToNameIds();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (pickerItems != null)
|
||||
{
|
||||
foreach (KeyValuePair<int, string> pickerItem in pickerItems)
|
||||
{
|
||||
CreateRelation(relationType, sender.Id, pickerItem.Key, options.ReverseIndexing, instanceIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error: content object type invalid with relation type
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error: relation type is null
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error: pickerProperty alias not found
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears any existing relations when deleting a node with a PickerRelations datatype
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender.</param>
|
||||
/// <param name="e">The <see cref="umbraco.cms.businesslogic.DeleteEventArgs"/> instance containing the event data.</param>
|
||||
private void BeforeDelete(Content sender, DeleteEventArgs e)
|
||||
{
|
||||
Guid pickerRelationsId = new Guid(DataTypeGuids.PickerRelationsId);
|
||||
|
||||
// Clean up any relations
|
||||
|
||||
// For each PickerRelations datatype
|
||||
foreach (Property pickerRelationsProperty in from property in sender.GenericProperties
|
||||
where property.PropertyType.DataTypeDefinition.DataType.Id == pickerRelationsId
|
||||
select property)
|
||||
{
|
||||
// used to identify this datatype instance - relations created are marked with this in the comment field
|
||||
string instanceIdentifier = "[\"PropertyTypeId\":" + pickerRelationsProperty.PropertyType.Id.ToString() + "]";
|
||||
|
||||
// get configuration options for datatype
|
||||
PickerRelationsOptions options = ((PickerRelationsPreValueEditor)pickerRelationsProperty.PropertyType.DataTypeDefinition.DataType.PrevalueEditor).Options;
|
||||
|
||||
// get relationType from options
|
||||
RelationType relationType = RelationType.GetById(options.RelationTypeId);
|
||||
|
||||
if (relationType != null)
|
||||
{
|
||||
// clear all exisitng relations
|
||||
DeleteRelations(relationType, sender.Id, options.ReverseIndexing, instanceIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete all relations using the content node for a given RelationType
|
||||
/// </summary>
|
||||
/// <param name="relationType"></param>
|
||||
/// <param name="contentNodeId"></param>
|
||||
/// <param name="reverseIndexing"></param>
|
||||
/// <param name="instanceIdentifier">NOT USED ATM</param>
|
||||
private static void DeleteRelations(RelationType relationType, int contentNodeId, bool reverseIndexing, string instanceIdentifier)
|
||||
{
|
||||
//if relationType is bi-directional or a reverse index then we can't get at the relations via the API, so using SQL
|
||||
string getRelationsSql = "SELECT id FROM umbracoRelation WHERE relType = " + relationType.Id.ToString() + " AND ";
|
||||
|
||||
if (reverseIndexing || relationType.Dual)
|
||||
{
|
||||
getRelationsSql += "childId = " + contentNodeId.ToString();
|
||||
}
|
||||
if (relationType.Dual) // need to return relations where content node id is used on both sides
|
||||
{
|
||||
getRelationsSql += " OR ";
|
||||
}
|
||||
if (!reverseIndexing || relationType.Dual)
|
||||
{
|
||||
getRelationsSql += "parentId = " + contentNodeId.ToString();
|
||||
}
|
||||
|
||||
getRelationsSql += " AND comment = '" + instanceIdentifier + "'";
|
||||
|
||||
using (IRecordsReader relations = uQuery.SqlHelper.ExecuteReader(getRelationsSql))
|
||||
{
|
||||
//clear data
|
||||
Relation relation;
|
||||
if (relations.HasRecords)
|
||||
{
|
||||
while (relations.Read())
|
||||
{
|
||||
relation = new Relation(relations.GetInt("id"));
|
||||
|
||||
// TODO: [HR] check to see if an instance identifier is used
|
||||
relation.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="relationType"></param>
|
||||
/// <param name="contentNodeId">id sourced from the Content / Media / Member</param>
|
||||
/// <param name="pickerNodeId">id sourced from the Picker</param>
|
||||
/// <param name="reverseIndexing">if true, reverses the parentId and child Id</param>
|
||||
/// <param name="instanceIdentifier">JSON string with id of Picker Relations property instance</param>
|
||||
private static void CreateRelation(RelationType relationType, int contentNodeId, int pickerNodeId, bool reverseIndexing, string instanceIdentifier)
|
||||
{
|
||||
if (reverseIndexing)
|
||||
{
|
||||
Relation.MakeNew(pickerNodeId, contentNodeId, relationType, instanceIdentifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
Relation.MakeNew(contentNodeId, pickerNodeId, relationType, instanceIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user