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 { /// /// Event handler that will convert a CSV into Relations /// public class PickerRelationsEventHandler : ApplicationBase { private enum PickerStorageFormat { Csv, Xml } /// /// Initializes a new instance of PickerRelationsEventHandler, /// hooks into the after event of saving a Content node, Media item or a Member /// 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); } /// /// Event after all properties have been saved /// /// /// 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 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 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 } } } /// /// Clears any existing relations when deleting a node with a PickerRelations datatype /// /// The sender. /// The instance containing the event data. 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); } } } /// /// Delete all relations using the content node for a given RelationType /// /// /// /// /// NOT USED ATM 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(); } } } } /// /// /// /// /// id sourced from the Content / Media / Member /// id sourced from the Picker /// if true, reverses the parentId and child Id /// JSON string with id of Picker Relations property instance 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); } } } }