Internal data structure for model mapping purposes.
コード例 #1
0
 /// <summary>
 /// Initializes a new <see cref="MappingData"/> instance which is a (shallow) copy of another.
 /// </summary>
 /// <param name="other">The other <see cref="MappingData"/> instance to copy.</param>
 public MappingData(MappingData other)
 {
     TargetType = other.TargetType;
     Content = other.Content;
     Meta = other.Meta;
     TargetEntitiesByPrefix = other.TargetEntitiesByPrefix;
     SemanticSchema = other.SemanticSchema;
     EmbeddedSemanticSchemaField = other.EmbeddedSemanticSchemaField;
     EntityNames = other.EntityNames;
     ParentDefaultPrefix = other.ParentDefaultPrefix;
     EmbedLevel = other.EmbedLevel;
     SourceEntity = other.SourceEntity;
     ModelId = other.ModelId;
     Localization = other.Localization;
     ContextXPath = other.ContextXPath;
 }
コード例 #2
0
        private PageModel CreatePageModel(IPage page, Localization localization)
        {
            MvcData pageMvcData = GetMvcData(page);
            Type pageModelType = ModelTypeRegistry.GetViewModelType(pageMvcData);
            string pageId = GetDxaIdentifierFromTcmUri(page.Id);
            ISchema pageMetadataSchema = page.Schema;

            PageModel pageModel;
            if (pageModelType == typeof(PageModel))
            {
                // Standard Page Model
                pageModel = new PageModel(pageId);
            }
            else if (pageMetadataSchema == null)
            {
                // Custom Page Model but no Page metadata that can be mapped; simply create a Page Model instance of the right type.
                pageModel = (PageModel)Activator.CreateInstance(pageModelType, pageId);
            }
            else
            {
                // Custom Page Model and Page metadata is present; do full-blown model mapping.
                string[] schemaTcmUriParts = pageMetadataSchema.Id.Split('-');
                SemanticSchema semanticSchema = SemanticMapping.GetSchema(schemaTcmUriParts[1], localization);

                MappingData mappingData = new MappingData
                {
                    TargetType = pageModelType,
                    SemanticSchema = semanticSchema,
                    EntityNames = semanticSchema.GetEntityNames(),
                    TargetEntitiesByPrefix = GetEntityDataFromType(pageModelType),
                    Meta = page.MetadataFields,
                    ModelId = pageId,
                    Localization = localization
                };

                pageModel = (PageModel) CreateViewModel(mappingData);
            }

            pageModel.MvcData = pageMvcData;
            pageModel.XpmMetadata = GetXpmMetadata(page);
            pageModel.Title = page.Title;

            // add html classes to model from metadata
            // TODO: move to CreateViewModel so it can be merged with the same code for a Component/ComponentTemplate
            IPageTemplate template = page.PageTemplate;
            if (template.MetadataFields != null && template.MetadataFields.ContainsKey("htmlClasses"))
            {
                // strip illegal characters to ensure valid html in the view (allow spaces for multiple classes)
                pageModel.HtmlClasses = template.MetadataFields["htmlClasses"].Value.StripIllegalCharacters(@"[^\w\-\ ]");
            }

            return pageModel;
        }
コード例 #3
0
        private ViewModel MapEmbeddedFields(IFieldSet embeddedFields, Type modelType, MappingData mapData)
        {
            MappingData embeddedMappingData = new MappingData
                {
                    TargetType = modelType,
                    Content = embeddedFields,
                    Meta = null,
                    EntityNames = mapData.EntityNames, // TODO: should this not be re-determined for the embedded model type?
                    ParentDefaultPrefix = mapData.ParentDefaultPrefix,
                    TargetEntitiesByPrefix = mapData.TargetEntitiesByPrefix, // TODO: should this not be re-determined for the embedded model type?
                    SemanticSchema = mapData.SemanticSchema, // TODO: should this not be re-determined for the embedded model type?
                    EmbedLevel = mapData.EmbedLevel + 1,
                    Localization = mapData.Localization
                };

            return CreateViewModel(embeddedMappingData);
        }
コード例 #4
0
        public virtual void BuildEntityModel(ref EntityModel entityModel, IComponent component, Type baseModelType, Localization localization)
        {
            using (new Tracer(entityModel, component, baseModelType, localization))
            {
                string[] schemaTcmUriParts = component.Schema.Id.Split('-');
                SemanticSchema semanticSchema = SemanticMapping.GetSchema(schemaTcmUriParts[1], localization);

                // The semantic mapping may resolve to a more specific model type than specified by the View Model itself (e.g. Image instead of just MediaItem for Teaser.Media)
                Type modelType = semanticSchema.GetModelTypeFromSemanticMapping(baseModelType);

                MappingData mappingData = new MappingData
                {
                    SemanticSchema = semanticSchema,
                    EntityNames = semanticSchema.GetEntityNames(),
                    TargetEntitiesByPrefix = GetEntityDataFromType(modelType),
                    Content = component.Fields,
                    Meta = component.MetadataFields,
                    TargetType = modelType,
                    SourceEntity = component,
                    Localization = localization
                };

                entityModel = (EntityModel)CreateViewModel(mappingData);
                entityModel.Id = GetDxaIdentifierFromTcmUri(component.Id);
                entityModel.XpmMetadata = GetXpmMetadata(component);

                if (entityModel is MediaItem && component.Multimedia != null && component.Multimedia.Url != null)
                {
                    MediaItem mediaItem = (MediaItem)entityModel;
                    mediaItem.Url = component.Multimedia.Url;
                    mediaItem.FileName = component.Multimedia.FileName;
                    mediaItem.FileSize = component.Multimedia.Size;
                    mediaItem.MimeType = component.Multimedia.MimeType;
                }

                if (entityModel is Link)
                {
                    Link link = (Link)entityModel;
                    if (String.IsNullOrEmpty(link.Url))
                    {
                        link.Url = SiteConfiguration.LinkResolver.ResolveLink(component.Id);
                    }
                }
            }
        }
コード例 #5
0
 private static IField GetFieldFromSemantics(MappingData mapData, SemanticProperty info)
 {
     KeyValuePair<string, string>? entityData = GetEntityData(info.Prefix, mapData.TargetEntitiesByPrefix, mapData.ParentDefaultPrefix);
     if (entityData != null)
     {
         // determine field semantics
         string vocab = entityData.Value.Key;
         string prefix = SemanticMapping.GetPrefix(vocab, mapData.Localization);
         if (prefix != null && mapData.EntityNames!=null)
         {
             string property = info.PropertyName;
             string entity = mapData.EntityNames[vocab].FirstOrDefault();
             if (entity != null && mapData.SemanticSchema!=null)
             {
                 FieldSemantics fieldSemantics = new FieldSemantics(prefix, entity, property);
                 // locate semantic schema field
                 SemanticSchemaField matchingField = mapData.SemanticSchema.FindFieldBySemantics(fieldSemantics);
                 if (matchingField != null)
                 {
                     return ExtractMatchedField(matchingField, (matchingField.IsMetadata && mapData.Meta!=null) ? mapData.Meta : mapData.Content, mapData.EmbedLevel);
                 }
             }
         }
     }
     return null;
 }
コード例 #6
0
 protected virtual Dictionary<string, List<SemanticProperty>> FilterPropertySemanticsByEntity(Dictionary<string, List<SemanticProperty>> propertySemantics, MappingData mapData)
 {
     Dictionary<string, List<SemanticProperty>> filtered = new Dictionary<string, List<SemanticProperty>>();
     foreach (KeyValuePair<string, List<SemanticProperty>> property in propertySemantics)
     {
         filtered.Add(property.Key, new List<SemanticProperty>());
         List<SemanticProperty> defaultProperties = new List<SemanticProperty>();
         foreach (SemanticProperty semanticProperty in property.Value)
         {
             //Default prefix is always OK, but should be added last
             if (string.IsNullOrEmpty(semanticProperty.Prefix))
             {
                 defaultProperties.Add(semanticProperty);
             }
             else
             {
                 //Filter out any properties belonging to other entities than the source entity
                 KeyValuePair<string, string>? entityData = GetEntityData(semanticProperty.Prefix, mapData.TargetEntitiesByPrefix, mapData.ParentDefaultPrefix);
                 if (entityData != null && mapData.EntityNames!=null && mapData.EntityNames.Contains(entityData.Value.Key))
                 {
                     if (mapData.EntityNames[entityData.Value.Key].First() == entityData.Value.Value)
                     {
                         filtered[property.Key].Add(semanticProperty);
                     }
                 }
             }
         }
         filtered[property.Key].AddRange(defaultProperties);
     }
     return filtered;
 }
コード例 #7
0
        protected virtual ViewModel CreateViewModel(MappingData mappingData)
        {
            Type modelType = mappingData.TargetType; // TODO: why is this not a separate parameter?

            ViewModel model;
            if (string.IsNullOrEmpty(mappingData.ModelId))
            {
                // Use parameterless constructor
                model = (ViewModel)Activator.CreateInstance(modelType);
            }
            else
            {
                // Pass model Identifier in constructor.
                model = (ViewModel)Activator.CreateInstance(modelType, mappingData.ModelId);
            }

            Dictionary<string, string> xpmPropertyMetadata = new Dictionary<string, string>();
            Dictionary<string, List<SemanticProperty>> propertySemantics = LoadPropertySemantics(modelType);
            propertySemantics = FilterPropertySemanticsByEntity(propertySemantics, mappingData);
            foreach (PropertyInfo pi in modelType.GetProperties())
            {
                bool multival = pi.PropertyType.IsGenericType && (pi.PropertyType.GetGenericTypeDefinition() == typeof(List<>));
                Type propertyType = multival ? pi.PropertyType.GetGenericArguments()[0] : pi.PropertyType;
                if (propertySemantics.ContainsKey(pi.Name))
                {
                    foreach (SemanticProperty info in propertySemantics[pi.Name])
                    {
                        IField field = GetFieldFromSemantics(mappingData, info);
                        if (field != null && (field.Values.Count > 0 || field.EmbeddedValues.Count > 0))
                        {
                            pi.SetValue(model, MapFieldValues(field, propertyType, multival, mappingData));
                            xpmPropertyMetadata.Add(pi.Name, GetFieldXPath(field));
                            break;
                        }

                        // Special mapping cases require SourceEntity to be set
                        if (mappingData.SourceEntity == null)
                        {
                            continue;
                        }

                        bool processed = false;
                        if (info.PropertyName == "_self")
                        {
                            //Map the whole entity to an image property, or a resolved link to the entity to a Url field
                            if (typeof(MediaItem).IsAssignableFrom(propertyType) || typeof(Link).IsAssignableFrom(propertyType) || propertyType == typeof(String))
                            {
                                object mappedSelf = MapComponent(mappingData.SourceEntity, propertyType, mappingData.Localization);
                                if (multival)
                                {
                                    IList genericList = CreateGenericList(propertyType);
                                    genericList.Add(mappedSelf);
                                    pi.SetValue(model, genericList);
                                }
                                else
                                {
                                    pi.SetValue(model, mappedSelf);
                                }
                                processed = true;
                            }
                        }
                        else if (info.PropertyName == "_all" && pi.PropertyType == typeof(Dictionary<string, string>))
                        {
                            //Map all fields into a single (Dictionary) property
                            pi.SetValue(model, GetAllFieldsAsDictionary(mappingData.SourceEntity));
                            processed = true;
                        }

                        if (processed)
                        {
                            break;
                        }
                    }
                }
            }

            EntityModel entityModel = model as EntityModel;
            if (entityModel != null)
            {
                entityModel.XpmPropertyMetadata = xpmPropertyMetadata;
            }

            return model;
        }
コード例 #8
0
        private object MapFieldValues(IField field, Type modelType, bool multival, MappingData mapData)
        {
            try
            {
                // Convert.ChangeType cannot convert non-nullable types to nullable types, so don't try that.
                Type bareModelType = modelType;
                if (modelType.IsGenericType && modelType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    bareModelType = modelType.GenericTypeArguments[0];
                }

                IList mappedValues = CreateGenericList(modelType);
                switch (field.FieldType)
                {
                    case FieldType.Date:
                        foreach (DateTime value in field.DateTimeValues)
                        {
                            mappedValues.Add(Convert.ChangeType(value, bareModelType));
                        }
                        break;

                    case FieldType.Number:
                        foreach (Double value in field.NumericValues)
                        {
                            mappedValues.Add(Convert.ChangeType(value, bareModelType));
                        }
                        break;

                    case FieldType.MultiMediaLink:
                    case FieldType.ComponentLink:
                        foreach (IComponent value in field.LinkedComponentValues)
                        {
                            mappedValues.Add(MapComponent(value, modelType, mapData.Localization));
                        }
                        break;

                    case FieldType.Embedded:
                        foreach (IFieldSet value in field.EmbeddedValues)
                        {
                            mappedValues.Add(MapEmbeddedFields(value, modelType, mapData));
                        }
                        break;

                    case FieldType.Keyword:
                        foreach (IKeyword value in field.Keywords)
                        {
                            mappedValues.Add(MapKeyword(value, modelType));
                        }
                        break;

                    case FieldType.Xhtml:
                        IRichTextProcessor richTextProcessor = SiteConfiguration.RichTextProcessor;
                        foreach (string value in field.Values)
                        {
                            RichText richText = richTextProcessor.ProcessRichText(value, mapData.Localization);
                            if (modelType == typeof(string))
                            {
                                mappedValues.Add(richText.ToString());
                            }
                            else
                            {
                                mappedValues.Add(richText);
                            }
                        }
                        break;

                    default:
                        foreach (string value in field.Values)
                        {
                            object mappedValue = (modelType == typeof(RichText)) ? new RichText(value) : Convert.ChangeType(value, bareModelType);
                            mappedValues.Add(mappedValue);
                        }
                        break;
                }

                if (multival)
                {
                    return mappedValues;
                }

                return mappedValues.Count == 0 ? null : mappedValues[0];

            }
            catch (Exception ex)
            {
                throw new DxaException(String.Format("Unable to map field '{0}' to property of type '{1}'.", field.Name, modelType.FullName), ex);
            }
        }