예제 #1
0
        public static Lazy <IContentType> GetContentTypeDefinition(Type modelType)
        {
            //Check for BaseType different from ContentTypeBase
            bool hasParent = modelType.BaseType != null && modelType.BaseType != typeof(ContentTypeBase) && modelType.BaseType != typeof(object);
            var  parent    = new Lazy <IContentType>();

            if (hasParent)
            {
                var isResolved = _contentTypeCache.ContainsKey(modelType.BaseType.FullName);
                parent = isResolved
                             ? _contentTypeCache[modelType.BaseType.FullName].ContentType
                             : GetContentTypeDefinition(modelType.BaseType);
            }

            var contentTypeAttribute = modelType.FirstAttribute <ContentTypeAttribute>();
            var contentTypeAlias     = contentTypeAttribute == null?modelType.Name.ToUmbracoAlias() : contentTypeAttribute.Alias;

            //Check if ContentType already exists by looking it up by Alias.
            var existing = ApplicationContext.Current.Services.ContentTypeService.GetContentType(contentTypeAlias);

            Lazy <IContentType> contentType = contentTypeAttribute == null
                                                 ? PlainPocoConvention(modelType, existing)
                                                 : ContentTypeConvention(contentTypeAttribute, modelType, existing);

            //Check for interfaces that'll be used for ContentTypeComposition
            var mixins = GetAliasesFromTypeInterfaces(modelType);

            var definitions   = new List <PropertyDefinition>();
            int order         = 0;
            var objProperties = modelType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly).ToList();

            foreach (var propertyInfo in objProperties)
            {
                var propertyTypeAttribute = propertyInfo.FirstAttribute <PropertyTypeConventionAttribute>();
                var definition            = propertyTypeAttribute == null
                                     ? new PropertyDefinition()
                                     : propertyTypeAttribute.GetPropertyConvention();

                //DataTypeDefinition fallback
                if (definition.DataTypeDefinition == null)
                {
                    definition.DataTypeDefinition = Conventions.GetDataTypeDefinitionByAttributeOrType(null, propertyInfo.PropertyType);
                }

                if (string.IsNullOrEmpty(definition.PropertyGroup))
                {
                    definition.PropertyGroup = "Generic Properties";
                }

                //Alias fallback
                if (string.IsNullOrEmpty(definition.Alias))
                {
                    var aliasAttribute = propertyInfo.FirstAttribute <AliasAttribute>();
                    definition.Alias = Conventions.GetPropertyTypeAlias(aliasAttribute, propertyInfo.Name);
                    definition.Name  = Conventions.GetPropertyTypeName(aliasAttribute, propertyInfo.Name);
                }

                //Description fallback
                if (string.IsNullOrEmpty(definition.Description))
                {
                    var descriptionAttribute = propertyInfo.FirstAttribute <DescriptionAttribute>();
                    definition.Description = descriptionAttribute != null
                                                 ? descriptionAttribute.Description
                                                 : string.Empty;
                }

                //SortOrder fallback
                if (definition.Order == default(int))
                {
                    var sortOrderAttribute = propertyInfo.FirstAttribute <SortOrderAttribute>();
                    definition.Order = sortOrderAttribute != null ? sortOrderAttribute.Order : order;
                }

                definitions.Add(definition);
                order++;
            }

            //Loop through definitions for PropertyGroups and create those that not already exists
            var groupDefinitions = definitions.DistinctBy(d => d.PropertyGroup);

            foreach (var groupDefinition in groupDefinitions)
            {
                var groupExists = contentType.Value.PropertyGroups.Contains(groupDefinition.PropertyGroup);
                if (groupExists == false)
                {
                    var propertyGroup = new PropertyGroup {
                        Name = groupDefinition.PropertyGroup
                    };
                    contentType.Value.PropertyGroups.Add(propertyGroup);
                }
            }

            //Loop through definitions for PropertyTypes and add them to the correct PropertyGroup
            foreach (var definition in definitions)
            {
                var group = contentType.Value.PropertyGroups.First(x => x.Name == definition.PropertyGroup);
                //Check if a PropertyType with the same alias already exists, as we don't want to override existing ones
                if (group.PropertyTypes.Contains(definition.Alias))
                {
                    continue;
                }

                var propertyType = new PropertyType(definition.DataTypeDefinition, definition.Alias)
                {
                    Mandatory        = definition.Mandatory,
                    ValidationRegExp = definition.ValidationRegExp,
                    SortOrder        = definition.Order,
                    Name             = definition.Name
                };

                group.PropertyTypes.Add(propertyType);
            }

            //If current ContentType has a Parent the ParentId should be set and the ContentType added to the composition.
            if (hasParent)
            {
                contentType.Value.SetLazyParentId(new Lazy <int>(() => parent.Value.Id));
                contentType.Value.AddContentType(parent.Value);
            }
            //Add the resolved ContentType to the internal cache
            var field = new DependencyField {
                ContentType = contentType, Alias = contentType.Value.Alias
            };
            var dependencies = new List <string>();

            //If current type has a parent (inherited model) we add the alias of that type as a dependency
            if (hasParent)
            {
                dependencies.Add(parent.Value.Alias);
            }
            //Check ContentType for existing 'Allowed ContentTypes'
            if (contentType.Value.AllowedContentTypes.Any())
            {
                dependencies.AddRange(contentType.Value.AllowedContentTypes.Select(allowed => allowed.Alias));
            }
            //Check for interfaces with AliasAttribute and add those as dependencies
            //NOTE: might also be an idea to check if ContentType has already been created/added to cache that implements the interface.
            if (mixins.Any())
            {
                foreach (var mixin in mixins)
                {
                    if (dependencies.Contains(mixin.Item1))
                    {
                        continue;
                    }

                    dependencies.Add(mixin.Item1);
                    var isMixinResolved = _contentTypeCache.ContainsKey(mixin.Item2);

                    Lazy <IContentType> compositionType = null;

                    if (isMixinResolved)
                    {
                        compositionType = _contentTypeCache[mixin.Item2].ContentType;
                    }
                    else
                    {
                        GetContentTypeDefinition(mixin.Item3);
                        compositionType = _contentTypeCache[mixin.Item2].ContentType;
                    }

                    contentType.Value.AddContentType(compositionType.Value);
                }
            }
            field.DependsOn = dependencies.ToArray();
            _contentTypeCache.AddOrUpdate(modelType.FullName, field, (x, y) => field);
            return(contentType);
        }
        public static Lazy<IContentType> GetContentTypeDefinition(Type modelType)
        {
            //Check for BaseType different from ContentTypeBase
            bool hasParent = modelType.BaseType != null && modelType.BaseType != typeof(ContentTypeBase) && modelType.BaseType != typeof(object);
            var parent = new Lazy<IContentType>();
            if(hasParent)
            {
                var isResolved = _contentTypeCache.ContainsKey(modelType.BaseType.FullName);
                parent = isResolved
                             ? _contentTypeCache[modelType.BaseType.FullName].ContentType
                             : GetContentTypeDefinition(modelType.BaseType);
            }

            var contentTypeAttribute = modelType.FirstAttribute<ContentTypeAttribute>();
            var contentTypeAlias = contentTypeAttribute == null ? modelType.Name.ToUmbracoAlias() : contentTypeAttribute.Alias;
            //Check if ContentType already exists by looking it up by Alias.
            var existing = ApplicationContext.Current.Services.ContentTypeService.GetContentType(contentTypeAlias);
            
            Lazy<IContentType> contentType = contentTypeAttribute == null
                                                 ? PlainPocoConvention(modelType, existing)
                                                 : ContentTypeConvention(contentTypeAttribute, modelType, existing);

            //Check for interfaces that'll be used for ContentTypeComposition
            var mixins = GetAliasesFromTypeInterfaces(modelType);

            var definitions = new List<PropertyDefinition>();
            int order = 0;
            var objProperties = modelType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly).ToList();
            foreach (var propertyInfo in objProperties)
            {
                var propertyTypeAttribute = propertyInfo.FirstAttribute<PropertyTypeConventionAttribute>();
                var definition = propertyTypeAttribute == null
                                     ? new PropertyDefinition()
                                     : propertyTypeAttribute.GetPropertyConvention();

                //DataTypeDefinition fallback
                if(definition.DataTypeDefinition == null)
                {
                    definition.DataTypeDefinition = Conventions.GetDataTypeDefinitionByAttributeOrType(null, propertyInfo.PropertyType);
                }

                if(string.IsNullOrEmpty(definition.PropertyGroup))
                {
                    definition.PropertyGroup = "Generic Properties";
                }

                //Alias fallback
                if (string.IsNullOrEmpty(definition.Alias))
                {
                    var aliasAttribute = propertyInfo.FirstAttribute<AliasAttribute>();
                    definition.Alias = Conventions.GetPropertyTypeAlias(aliasAttribute, propertyInfo.Name);
                    definition.Name = Conventions.GetPropertyTypeName(aliasAttribute, propertyInfo.Name);
                }

                //Description fallback
                if (string.IsNullOrEmpty(definition.Description))
                {
                    var descriptionAttribute = propertyInfo.FirstAttribute<DescriptionAttribute>();
                    definition.Description = descriptionAttribute != null
                                                 ? descriptionAttribute.Description
                                                 : string.Empty;
                }

                //SortOrder fallback
                if (definition.Order == default(int))
                {
                    var sortOrderAttribute = propertyInfo.FirstAttribute<SortOrderAttribute>();
                    definition.Order = sortOrderAttribute != null ? sortOrderAttribute.Order : order;
                }

                definitions.Add(definition);
                order++;
            }

            //Loop through definitions for PropertyGroups and create those that not already exists
            var groupDefinitions = definitions.DistinctBy(d => d.PropertyGroup);
            foreach (var groupDefinition in groupDefinitions)
            {
                var groupExists = contentType.Value.PropertyGroups.Contains(groupDefinition.PropertyGroup);
                if(groupExists == false)
                {
                    var propertyGroup = new PropertyGroup {Name = groupDefinition.PropertyGroup};
                    contentType.Value.PropertyGroups.Add(propertyGroup);
                }
            }

            //Loop through definitions for PropertyTypes and add them to the correct PropertyGroup
            foreach (var definition in definitions)
            {
                var group = contentType.Value.PropertyGroups.First(x => x.Name == definition.PropertyGroup);
                //Check if a PropertyType with the same alias already exists, as we don't want to override existing ones
                if(group.PropertyTypes.Contains(definition.Alias)) continue;

                var propertyType = new PropertyType(definition.DataTypeDefinition)
                                       {
                                           Mandatory = definition.Mandatory,
                                           ValidationRegExp = definition.ValidationRegExp,
                                           SortOrder = definition.Order,
                                           Alias = definition.Alias,
                                           Name = definition.Name
                                       };

                group.PropertyTypes.Add(propertyType);
            }

            //If current ContentType has a Parent the ParentId should be set and the ContentType added to the composition.
            if(hasParent)
            {
                contentType.Value.SetLazyParentId(new Lazy<int>(() => parent.Value.Id));
                contentType.Value.AddContentType(parent.Value);
            }
            //Add the resolved ContentType to the internal cache
            var field = new DependencyField {ContentType = contentType, Alias = contentType.Value.Alias};
            var dependencies = new List<string>();
            //If current type has a parent (inherited model) we add the alias of that type as a dependency
            if(hasParent)
            {
                dependencies.Add(parent.Value.Alias);
            }
            //Check ContentType for existing 'Allowed ContentTypes'
            if(contentType.Value.AllowedContentTypes.Any())
            {
                dependencies.AddRange(contentType.Value.AllowedContentTypes.Select(allowed => allowed.Alias));
            }
            //Check for interfaces with AliasAttribute and add those as dependencies 
            //NOTE: might also be an idea to check if ContentType has already been created/added to cache that implements the interface.
            if(mixins.Any())
            {
                foreach (var mixin in mixins)
                {
                    if(dependencies.Contains(mixin.Item1)) continue;

                    dependencies.Add(mixin.Item1);
                    var isMixinResolved = _contentTypeCache.ContainsKey(mixin.Item2);

                    Lazy<IContentType> compositionType = null;

                    if (isMixinResolved)
                    {
                        compositionType = _contentTypeCache[mixin.Item2].ContentType;
                    }
                    else
                    {
                        GetContentTypeDefinition(mixin.Item3);
                        compositionType = _contentTypeCache[mixin.Item2].ContentType;
                    }

                    contentType.Value.AddContentType(compositionType.Value);
                }
            }
            field.DependsOn = dependencies.ToArray();
            _contentTypeCache.AddOrUpdate(modelType.FullName, field, (x, y) => field);
            return contentType;
        }