-
-
Save proteux/8501c8e259f9bfdadfff to your computer and use it in GitHub Desktop.
Allows for custom fields and attributes to be easily set on stardard objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/**************************** | |
* | |
* Written by: Jack Whitehouse @ 45 North | |
* Date: 12/12/13 | |
* Purpose: Allows for custom fields and attributes to be easily set on stardard objects | |
* | |
****************************/ | |
using EasyCustomFields.RightNow.Soap; | |
using System; | |
using System.Linq; | |
using System.Reflection; | |
namespace EasyCustomFields | |
{ | |
public static class CustomFields | |
{ | |
/// <summary> | |
/// EXTENSION METHOD (RNObject): returns the value for a custom field or attribute | |
/// </summary> | |
/// <param name="root">the RNObject to look for the custom field in</param> | |
/// <param name="fieldName">the custom field name (c$fieldName or fieldName) or custom attribute (namespace$fieldName)</param> | |
/// <returns>value for a custom field or attribute</returns> | |
public static object GetCustomField(this RNObject root, string fieldName) | |
{ | |
object retVal = null; | |
//split out the field and namespace names | |
string packageName = "c"; | |
if (fieldName.Contains('$')) | |
{ | |
string[] parts = fieldName.Split('$'); | |
packageName = parts[0]; | |
fieldName = parts[1]; | |
} | |
//pull out the custom field array based on name | |
GenericObject customFields; | |
try | |
{ | |
PropertyInfo cf_prop = root.GetType().GetProperty("CustomFields"); | |
customFields = cf_prop.GetValue(root, null) as GenericObject; | |
} | |
catch (Exception ex) | |
{ | |
throw new ArgumentException("Root RNObject does not contain a 'CustomFields' property", "root", ex); | |
} | |
//make sure we found 'em | |
if (customFields == null) | |
throw new Exception("Object doesn't contain custom fields, validate SOAP template"); | |
//find the package | |
GenericField package = customFields.GenericFields.FirstOrDefault(o => o.name == packageName); | |
if (package != null && | |
package.DataValue != null && | |
package.DataValue.Items != null && | |
package.DataValue.Items.Length > 0) | |
{ | |
GenericObject obj = package.DataValue.Items[0] as GenericObject; | |
//find the object | |
if (obj != null) | |
{ | |
GenericField field = obj.GenericFields.FirstOrDefault(o => o.name.ToLower() == fieldName.ToLower()); | |
//find the field | |
if (field == null) | |
{ | |
throw new Exception("Could not find custom field: " + packageName + "$" + fieldName); | |
} | |
else if (field.DataValue != null && field.DataValue.Items != null && field.DataValue.Items.Length > 0) | |
{ | |
retVal = field.DataValue.Items[0]; | |
} | |
} | |
} | |
else | |
{ | |
throw new Exception("Could not find custom field package: " + packageName); | |
} | |
return retVal; | |
} | |
/// <summary> | |
/// | |
/// </summary> | |
/// <param name="root"></param> | |
/// <param name="fieldName">the custom field name (c$fieldName or fieldName) or custom attribute (namespace$fieldName)</param> | |
/// <param name="value">value to set the custom field or attribute to. NamedIDs can be passed in as a NamedID, int, long or string</param> | |
/// <param name="typeEnum">data type of the field</param> | |
public static void SetCustomField(this RNObject root, string fieldName, object value, DataTypeEnum typeEnum) | |
{ | |
ItemsChoiceType choiceEnum = GetChoiceByType(typeEnum); | |
Type type = root.GetType(); | |
GenericObject customFields; | |
PropertyInfo cf_prop; | |
//break out the field name | |
string packageName = "c"; | |
if (fieldName.Contains('$')) | |
{ | |
string[] parts = fieldName.Split('$'); | |
packageName = parts[0]; | |
fieldName = parts[1]; | |
} | |
//create the layer names | |
string objectTypeName = type.Name; | |
string fieldTypeName = objectTypeName + "CustomFieldsc"; | |
string fieldArrayTypeName = objectTypeName + "CustomFields"; | |
try | |
{ | |
//get the custom field property on the object | |
cf_prop = root.GetType().GetProperty("CustomFields"); | |
customFields = cf_prop.GetValue(root, null) as GenericObject; | |
} | |
catch (Exception ex) | |
{ | |
throw new ArgumentException("Root RNObject does not contain a 'CustomFields' property", "root", ex); | |
} | |
//create the field | |
GenericField newField = new GenericField | |
{ | |
name = packageName, | |
dataType = DataTypeEnum.OBJECT, | |
dataTypeSpecified = true, | |
DataValue = new DataValue | |
{ | |
Items = new object[] | |
{ | |
new GenericObject | |
{ | |
GenericFields = new GenericField[] | |
{ | |
CreateGenericField(fieldName,typeEnum, choiceEnum, value), | |
}, | |
ObjectType = new RNObjectType() | |
{ | |
TypeName = fieldTypeName | |
} | |
}, | |
}, | |
ItemsElementName = new ItemsChoiceType[] | |
{ | |
ItemsChoiceType.ObjectValue | |
}, | |
} | |
}; | |
// Update existing custom field array | |
if (customFields != null && customFields.GenericFields != null && customFields.GenericFields.Count() > 0) | |
{ | |
foreach (GenericField field in customFields.GenericFields) | |
{ | |
if (field.name == fieldName) | |
{ | |
// Found the field, ensure that all the ridiculous extra meta-junk is correct | |
if (field.dataType == typeEnum && field.DataValue.ItemsElementName.Contains(choiceEnum)) | |
{ | |
field.DataValue.Items = new object[] { value }; | |
return; | |
} | |
else | |
{ | |
throw new Exception(String.Format("Field types do not match for {0} field {1}.", objectTypeName, fieldName)); | |
} | |
} | |
} | |
// Not found in existing custom fields list, so add it | |
customFields.GenericFields = customFields.GenericFields.Concat(new[] { newField }).ToArray(); | |
} | |
else | |
{ | |
//set new custom field array | |
customFields = new GenericObject | |
{ | |
GenericFields = new GenericField[] | |
{ | |
newField | |
}, | |
ObjectType = new RNObjectType | |
{ | |
TypeName = fieldArrayTypeName | |
} | |
}; | |
} | |
//store the updated custom field array back on the root object | |
cf_prop.SetValue(root, customFields, null); | |
} | |
/*================================ PRIVATE ================================*/ | |
/// <summary> | |
/// HELPER: to get the appropriate item type for the given data type | |
/// </summary> | |
/// <param name="typeEnum">Data type choice</param> | |
private static ItemsChoiceType GetChoiceByType(DataTypeEnum typeEnum) | |
{ | |
ItemsChoiceType choiceEnum = ItemsChoiceType.ObjectValue; | |
switch (typeEnum) | |
{ | |
case DataTypeEnum.BASE64_BINARY: | |
choiceEnum = ItemsChoiceType.Base64BinaryValue; | |
break; | |
case DataTypeEnum.BOOLEAN: | |
choiceEnum = ItemsChoiceType.BooleanValue; | |
break; | |
case DataTypeEnum.BOOLEAN_LIST: | |
choiceEnum = ItemsChoiceType.BooleanValueList; | |
break; | |
case DataTypeEnum.DATETIME: | |
choiceEnum = ItemsChoiceType.DateTimeValue; | |
break; | |
case DataTypeEnum.DATETIME_LIST: | |
choiceEnum = ItemsChoiceType.DateTimeValueList; | |
break; | |
case DataTypeEnum.DATE: | |
choiceEnum = ItemsChoiceType.DateValue; | |
break; | |
case DataTypeEnum.DATE_LIST: | |
choiceEnum = ItemsChoiceType.DateValueList; | |
break; | |
case DataTypeEnum.DECIMAL: | |
choiceEnum = ItemsChoiceType.DecimalValue; | |
break; | |
case DataTypeEnum.DECIMAL_LIST: | |
choiceEnum = ItemsChoiceType.DecimalValueList; | |
break; | |
case DataTypeEnum.ID: | |
choiceEnum = ItemsChoiceType.IDValue; | |
break; | |
case DataTypeEnum.ID_LIST: | |
choiceEnum = ItemsChoiceType.IDValueList; | |
break; | |
case DataTypeEnum.INTEGER: | |
choiceEnum = ItemsChoiceType.IntegerValue; | |
break; | |
case DataTypeEnum.INTEGER_LIST: | |
choiceEnum = ItemsChoiceType.IntegerValueList; | |
break; | |
case DataTypeEnum.LONG: | |
choiceEnum = ItemsChoiceType.LongValue; | |
break; | |
case DataTypeEnum.LONG_LIST: | |
choiceEnum = ItemsChoiceType.LongValueList; | |
break; | |
case DataTypeEnum.NAMED_ID: | |
choiceEnum = ItemsChoiceType.NamedIDValue; | |
break; | |
case DataTypeEnum.NAMED_ID_LIST: | |
choiceEnum = ItemsChoiceType.NamedIDValueList; | |
break; | |
case DataTypeEnum.NAMED_ID_DELTA_LIST: | |
choiceEnum = ItemsChoiceType.NamedIDDeltaValueList; | |
break; | |
case DataTypeEnum.NAMED_ID_HIERARCHY: | |
choiceEnum = ItemsChoiceType.NamedIDHierarchyValue; | |
break; | |
case DataTypeEnum.NAMED_ID_HIERARCHY_LIST: | |
choiceEnum = ItemsChoiceType.NamedIDHierarchyValueList; | |
break; | |
case DataTypeEnum.OBJECT: | |
choiceEnum = ItemsChoiceType.ObjectValue; | |
break; | |
case DataTypeEnum.OBJECT_LIST: | |
choiceEnum = ItemsChoiceType.ObjectValueList; | |
break; | |
case DataTypeEnum.STRING: | |
choiceEnum = ItemsChoiceType.StringValue; | |
break; | |
case DataTypeEnum.STRING_LIST: | |
choiceEnum = ItemsChoiceType.StringValueList; | |
break; | |
default: | |
break; | |
} | |
return choiceEnum; | |
} | |
/// <summary> | |
/// HELPER: creates generic fields | |
/// </summary> | |
/// <param name="name">field name</param> | |
/// <param name="type">field type</param> | |
/// <param name="valueType">value type (must match field type)</param> | |
/// <param name="value">value must be of the correct type</param> | |
/// <returns>Generic field matching the specified values</returns> | |
private static GenericField CreateGenericField(string name, DataTypeEnum type, ItemsChoiceType valueType, object value) | |
{ | |
object updatedObj = value; | |
//if it's a named ID handle the passing of a string or int w/o fuss | |
if (type == DataTypeEnum.NAMED_ID) | |
{ | |
if (value is int || value is long) | |
{ | |
updatedObj = new NamedID | |
{ | |
ID = new ID | |
{ | |
id = (value is int) ? (int)value : (long)value, | |
idSpecified = true | |
} | |
}; | |
} | |
else if (value is string) | |
{ | |
if (string.IsNullOrWhiteSpace((string)value)) | |
{ | |
updatedObj = null; | |
} | |
else | |
{ | |
updatedObj = new NamedID | |
{ | |
Name = (string)value | |
}; | |
} | |
} | |
} | |
else if (type == DataTypeEnum.STRING && (string)value == "") | |
updatedObj = null; | |
GenericField retVal = new GenericField | |
{ | |
name = name, | |
dataTypeSpecified = true, | |
dataType = type, | |
DataValue = (updatedObj == null) ? null : new DataValue | |
{ | |
Items = new object[] { updatedObj }, | |
ItemsElementName = new ItemsChoiceType[] { valueType } | |
} | |
}; | |
return retVal; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment