protected void SetPropertyOnContent(IContentBase content, PropertyRegistration property, object propertyValue) { object convertedValue; if (property.DataType.ConverterType != null) { object toConvert; var attr = property.Metadata.GetCodeFirstAttribute <ContentPropertyAttribute>(); if (attr != null && attr is IDataTypeRedirect) { toConvert = (attr as IDataTypeRedirect).GetOriginalDataTypeObject(propertyValue); } else { toConvert = propertyValue; } IDataTypeConverter converter = (IDataTypeConverter)Activator.CreateInstance(property.DataType.ConverterType); convertedValue = converter.Serialise(toConvert); } else if (!property.DataType.CodeFirstControlled && property.DataType.DbType == DatabaseType.None) { throw new CodeFirstException("Cannot persist PEVC-based properties or use events which attempt to persist PEVC-based properties. " + Environment.NewLine + "PEVCs only support retrieving a value from IPublishedContent & cannot persist a property back to IContent." + Environment.NewLine + "Property: " + property.Metadata.DeclaringType.FullName + "." + property.Name); } else { //No converter is given so we push the value back into umbraco as is (this will fail in many cases for PEVC properties) convertedValue = propertyValue; } content.SetValue(property.Alias, convertedValue); }
private void SetPropertyValueOnModel(object objectInstance, PropertyRegistration registration, object umbracoStoredValue) { if (registration.DataType.ConverterType != null) { IDataTypeConverter converter = (IDataTypeConverter)Activator.CreateInstance(registration.DataType.ConverterType); var val = converter.Create(umbracoStoredValue, x => CodeFirstModelContext.MoveNextContext(x, registration)); if (val != null) { CodeFirstModelContext.MoveNextContext(val, registration); var attr = registration.Metadata.GetCodeFirstAttribute <ContentPropertyAttribute>(); if (attr != null && attr is IDataTypeRedirect) { val = (attr as IDataTypeRedirect).GetRedirectedValue(val); if (val != null) { //Keep a second context so wrapped types can still find their property //Will add nothing if the Redirector registered a context already (e.g. called ConvertToModel to create the value). //Hopefully said redirector passed in a parent context so the converted value can still find its way back here. CodeFirstModelContext.MoveNextContext(val, registration); } } registration.Metadata.SetValue(objectInstance, val); } } else if (umbracoStoredValue != null) { //Context currently not supported for PEVCs - many are value types, very unlikely to have unique hashes for all values in a request context, none except custom ones would have //code to use the context anyway. registration.Metadata.SetValue(objectInstance, umbracoStoredValue); } }
/// <summary> /// Creates a new property on the ContentType under the correct tab /// </summary> /// <param name="newContentType"></param> /// <param name="tabName"></param> /// <param name="dataTypeService"></param> /// <param name="atTabGeneric"></param> /// <param name="item"></param> public PropertyRegistration CreateProperty(IContentTypeBase newContentType, TabRegistration tab, PropertyInfo item, Type documentClrType) { ContentPropertyAttribute attribute = item.GetCodeFirstAttribute <ContentPropertyAttribute>(); var tabPostfix = tab == null || !attribute.AddTabAliasToPropertyAlias ? null : tab.OriginalName == null ? tab.Name : tab.OriginalName; var dataType = _dataTypeModule.GetDataType(item); var property = new PropertyRegistration(); property.Name = attribute.Name; property.Alias = tabPostfix == null ? attribute.Alias : StringHelperExtensions.HyphenToUnderscore(StringHelperExtensions.ParseUrl(attribute.Alias + "_" + tabPostfix, false)); property.DataType = dataType; property.PropertyAttribute = attribute; property.Metadata = item; PropertyType propertyType = new PropertyType(dataType.Definition); propertyType.Name = property.Name; propertyType.Alias = property.Alias; propertyType.Description = attribute.Description; propertyType.Mandatory = attribute.Mandatory; propertyType.SortOrder = attribute.SortOrder; propertyType.ValidationRegExp = attribute.ValidationRegularExpression; var propertyDeclaredOnThisDocType = property.Metadata.DeclaringType == documentClrType || property.Metadata.DeclaringType.GetCodeFirstAttribute <CodeFirstCommonBaseAttribute>(false) != null; var propertyDeclaredOnThisTab = tab == null ? false : property.Metadata.DeclaringType == tab.ClrType; var tabDeclaredOnThisDocType = tab == null ? false : tab.PropertyOfParent.DeclaringType == documentClrType || tab.PropertyOfParent.DeclaringType.GetCodeFirstAttribute <CodeFirstCommonBaseAttribute>() != null; var declaringTypeIsDocType = property.Metadata.DeclaringType.GetCodeFirstAttribute <ContentTypeAttribute>(false) != null; var propertyIsFromCommonBase = tab == null? property.Metadata.DeclaringType.GetCodeFirstAttribute <CodeFirstCommonBaseAttribute>() != null && property.Metadata.DeclaringType == documentClrType.BaseType : property.Metadata.DeclaringType.GetCodeFirstAttribute <CodeFirstCommonBaseAttribute>() != null && property.Metadata.DeclaringType == tab.ClrType.BaseType; if (tab == null) { if (propertyDeclaredOnThisDocType || propertyIsFromCommonBase) //only if property declared at this level (or inherited from a non-doctype class) { if (!propertyIsFromCommonBase || !newContentType.PropertyTypeExists(propertyType.Alias)) //check if common base properties already exist { CodeFirstManager.Current.Log("Adding property " + property.Name + " on content type " + newContentType.Name, this); newContentType.AddPropertyType(propertyType); } } } else if (tabDeclaredOnThisDocType || propertyIsFromCommonBase) //only if tab declared at this level { if (propertyDeclaredOnThisTab || propertyIsFromCommonBase) //only if property declared at this level { if (!propertyIsFromCommonBase || !newContentType.PropertyTypeExists(propertyType.Alias)) //check if common base properties already exist { CodeFirstManager.Current.Log("Adding property " + property.Name + " on tab " + tab.Name + " of content type " + newContentType.Name, this); newContentType.AddPropertyType(propertyType, tab.Name); } } } return(property); }
private bool IsInheritedProperty(TabRegistration tab, Type documentClrType, PropertyRegistration property) { //If there is no current tab if (tab == null) { //and the declaring type is not the current type if (property.Metadata.DeclaringType != documentClrType) { //and the declaring type is also an Umbraco content type if (property.Metadata.DeclaringType.GetCodeFirstAttribute <ContentTypeAttribute>(false) != null) { //Inherited property. Don't persist at this level. return(true); } } } //else if the current tab is not directly declared on the current type else if (tab.PropertyOfParent.DeclaringType != documentClrType) { //and the declaring type of the tab is also an Umbraco content type if (tab.PropertyOfParent.DeclaringType.GetCodeFirstAttribute <ContentTypeAttribute>(false) != null) { //Inherited property. Don't persist at this level. return(true); } } //else if the current property is not directly declared on the current tab type else if (property.Metadata.DeclaringType != tab.ClrType) { var parent = documentClrType.BaseType.GetProperties().Where(x => x.IsParentTabFor(tab)).FirstOrDefault(); //If any property (inherited or otherwise) of the document type's parent declares a parent tab for the current tab if (parent != null) { //and that parent tab has this property on it if (parent.PropertyType.GetProperties().Any(x => x.MetadataToken == property.Metadata.MetadataToken)) { //Inherited property. Don't persist at this level. return(true); } } } return(false); }
private void LogPropertySyncInfo(IContentTypeBase contentType, TabRegistration tab, PropertyRegistration property, string action, [CallerMemberName] string sourceMethod = null) { if (tab == null) { CodeFirstManager.Current.Log(string.Format("{0} property {1} on content type {2}", action, property.Name, contentType.Name), this, sourceMethod); } else { CodeFirstManager.Current.Log(string.Format("{0} property {1} on tab {2} of content type {3}", action, tab.Name, property.Name, contentType.Name), this, sourceMethod); } }
/// <summary> /// Checks whether a property exists and adds if if it does not. The data type, alias, description and mandatory flag are update for existing properties, but not persisted. /// Callers should persist the value. /// </summary> public PropertyRegistration VerifyExistingProperty(IContentTypeBase contentType, TabRegistration tab, PropertyInfo item, Type documentClrType, ref bool modified) { ContentPropertyAttribute attribute = item.GetCodeFirstAttribute <ContentPropertyAttribute>(); var tabPostfix = tab == null || !attribute.AddTabAliasToPropertyAlias ? null : tab.OriginalName == null ? tab.Name : tab.OriginalName; var property = new PropertyRegistration(); var alias = property.Alias = tabPostfix == null ? attribute.Alias : StringHelperExtensions.HyphenToUnderscore(StringHelperExtensions.ParseUrl(attribute.Alias + "_" + tabPostfix, false)); var dataType = property.DataType = _dataTypeModule.GetDataType(item); property.Name = attribute.Name; property.PropertyAttribute = attribute; property.Metadata = item; LogPropertySyncInfo(contentType, tab, property, "Syncing"); bool alreadyExisted = contentType.PropertyTypeExists(alias); PropertyType umbracoProperty = contentType.PropertyTypes.FirstOrDefault(x => x.Alias == alias); if (umbracoProperty == null && alreadyExisted) { //This is a property from an underlying tab. Leave it alone. Log a warning in case this is an orphaned property. LogPropertySyncInfo(contentType, tab, property, "Ignoring inherited"); return(property); } if (alreadyExisted) { modified = modified || !umbracoProperty.Name.Equals(attribute.Name, StringComparison.InvariantCultureIgnoreCase) || umbracoProperty.Mandatory != attribute.Mandatory || (umbracoProperty.SortOrder != attribute.SortOrder && attribute.SortOrder != 0); //don't count sort order changes if no sort order is specified, as Umbraco will have assigned an automatic one if (umbracoProperty.ValidationRegExp != attribute.ValidationRegularExpression) { //If not both null/empty if (!(string.IsNullOrEmpty(umbracoProperty.ValidationRegExp) && string.IsNullOrEmpty(attribute.ValidationRegularExpression))) { modified = true; LogPropertySyncInfo(contentType, tab, property, "ValidationRegExp changed on"); } } if (umbracoProperty.Description != attribute.Description) { //If not both null/empty if (!(string.IsNullOrEmpty(umbracoProperty.Description) && string.IsNullOrEmpty(attribute.Description))) { modified = true; LogPropertySyncInfo(contentType, tab, property, "Description changed on"); } } if (modified) { if (!umbracoProperty.Name.Equals(attribute.Name, StringComparison.InvariantCultureIgnoreCase)) { LogPropertySyncInfo(contentType, tab, property, "Name changed on"); } if (umbracoProperty.Mandatory != attribute.Mandatory) { LogPropertySyncInfo(contentType, tab, property, "Mandatory changed on"); } if ((umbracoProperty.SortOrder != attribute.SortOrder && attribute.SortOrder != 0)) { LogPropertySyncInfo(contentType, tab, property, "SortOrder changed on"); } } } if (umbracoProperty == null) { try { modified = true; umbracoProperty = new PropertyType(dataType.Definition); LogPropertySyncInfo(contentType, tab, property, "Creating new"); } catch (Exception ex) { } } else if (umbracoProperty.DataTypeDefinitionId != dataType.Definition.Id) { modified = true; umbracoProperty.DataTypeDefinitionId = dataType.Definition.Id; LogPropertySyncInfo(contentType, tab, property, "Data type changed for"); } umbracoProperty.Name = attribute.Name; umbracoProperty.Alias = alias; umbracoProperty.Description = attribute.Description; umbracoProperty.Mandatory = attribute.Mandatory; umbracoProperty.SortOrder = attribute.SortOrder; umbracoProperty.ValidationRegExp = attribute.ValidationRegularExpression; var propertyDeclaredOnThisDocType = property.Metadata.DeclaringType == documentClrType; var propertyDeclaredOnThisTab = tab == null ? false : property.Metadata.DeclaringType == tab.ClrType; var tabDeclaredOnThisDocType = tab == null ? false : tab.PropertyOfParent.DeclaringType == documentClrType || tab.PropertyOfParent.DeclaringType.GetCustomAttribute <ContentTypeAttribute>() == null; var declaringTypeIsDocType = property.Metadata.DeclaringType.GetCodeFirstAttribute <ContentTypeAttribute>(false) != null; var propertyIsFromCommonBase = tab == null? property.Metadata.DeclaringType.GetCodeFirstAttribute <CodeFirstCommonBaseAttribute>() != null && property.Metadata.DeclaringType == documentClrType.BaseType : property.Metadata.DeclaringType.GetCodeFirstAttribute <CodeFirstCommonBaseAttribute>() != null && property.Metadata.DeclaringType == tab.ClrType.BaseType; if (alreadyExisted) { if (propertyIsFromCommonBase || (tabDeclaredOnThisDocType && propertyDeclaredOnThisTab)) { var currentTab = contentType.PropertyGroups.Where(x => x.PropertyTypes.Any(y => y.Alias == alias)).FirstOrDefault(); if (currentTab == null || !currentTab.Name.Equals(tab.Name, StringComparison.InvariantCultureIgnoreCase)) { modified = true; contentType.MovePropertyType(alias, tab.Name); LogPropertySyncInfo(contentType, tab, property, string.Format("Moved from tab {0}:", tab.Name)); } } } else { if (tab == null) { if (propertyDeclaredOnThisDocType || !declaringTypeIsDocType) //only if property declared at this level (or inherited from common base) { if (!propertyIsFromCommonBase || !contentType.PropertyTypeExists(umbracoProperty.Alias)) //check if common base properties already exist { LogPropertySyncInfo(contentType, tab, property, "Adding"); contentType.AddPropertyType(umbracoProperty); } } } else if (tabDeclaredOnThisDocType || propertyIsFromCommonBase) //only if tab declared at this level { if (propertyDeclaredOnThisTab || propertyIsFromCommonBase) //only if property declared at this level { if (!propertyIsFromCommonBase || (tabDeclaredOnThisDocType && !contentType.PropertyTypeExists(umbracoProperty.Alias))) //check if common base properties already exist { LogPropertySyncInfo(contentType, tab, property, "Adding"); contentType.AddPropertyType(umbracoProperty, tab.Name); } } } } return(property); }
private void CopyPropertyValueToModel(IPublishedContent content, object objectInstance, PropertyRegistration registration) { object umbracoStoredValue = null; var converterType = registration.DataType.ConverterType; //If a data type converter is used then bypass Umbraco's property value converter if (converterType != null) { var property = content.GetProperty(registration.Alias); object propertyValue; if (TryGetPropertyAsDbType(property, registration.DataType.DbType, out propertyValue, registration.DataType.DataTypeInstanceName)) { //Always prefer the underlying value, cast to the database type (int, string or DateTime), as this //matches the type of the property on an instance of IContent, therefore allowing converters to be used for //both IContent and IPublishedContent umbracoStoredValue = propertyValue; } else { umbracoStoredValue = content.GetPropertyValue(registration.Alias); } } else { umbracoStoredValue = content.GetPropertyValue(registration.Alias); } SetPropertyValueOnModel(objectInstance, registration, umbracoStoredValue); }
private void CopyPropertyValueToModel(IContentBase content, object objectInstance, PropertyRegistration registration) { var umbracoStoredValue = content.GetValue(registration.Alias); SetPropertyValueOnModel(objectInstance, registration, umbracoStoredValue); }