internal async Task <object> GetContentItemModelAsync(Type modelType, JToken serializedItem, JObject linkedItems, Dictionary <string, object> processedItems = null, HashSet <RichTextContentElements> currentlyResolvedRichStrings = null) { processedItems ??= new Dictionary <string, object>(); IContentItemSystemAttributes itemSystemAttributes = serializedItem["system"].ToObject <IContentItemSystemAttributes>(Serializer); var instance = CreateInstance(modelType, ref itemSystemAttributes, ref processedItems); if (instance == null) { // modelType could not be resolved or instance could not be created return(null); } var elementsData = GetElementData(serializedItem); var context = CreateResolvingContext(linkedItems, processedItems); var richTextPropertiesToBeProcessed = new List <PropertyInfo>(); foreach (var property in instance.GetType().GetProperties().Where(property => property.SetMethod != null)) { if (typeof(IContentItemSystemAttributes).IsAssignableFrom(property.PropertyType)) { // Handle the system metadata if (itemSystemAttributes != null) { property.SetValue(instance, itemSystemAttributes); } } else { var value = await GetPropertyValueAsync(elementsData, property, linkedItems, context, itemSystemAttributes, processedItems, richTextPropertiesToBeProcessed); if (value != null) { property.SetValue(instance, value); } } } // Rich-text elements need to be processed last, so in case of circular dependency, content items resolved by // resolvers would have all elements already processed currentlyResolvedRichStrings ??= new HashSet <RichTextContentElements>(); foreach (var property in richTextPropertiesToBeProcessed) { var currentValue = property.GetValue(instance)?.ToString(); var value = await GetRichTextValueAsync(currentValue, elementsData, property, linkedItems, itemSystemAttributes, processedItems, currentlyResolvedRichStrings); if (value != null) { property.SetValue(instance, value); } } return(instance); }
private static string GetPageUrl(IContentItemSystemAttributes system) { // TODO: The URL generation logic should be adjusted to match your website var url = string.Empty; if (system.SitemapLocation.Any()) { url = $"/{system.SitemapLocation[0]}"; } url = $"{url}/{system.Codename.Replace("_", "-").TrimEnd('-')}"; return(url); }
private object CreateInstance(Type detectedModelType, ref IContentItemSystemAttributes itemSystemAttributes, ref Dictionary <string, object> processedItems) { if (detectedModelType == typeof(object) || detectedModelType.IsInterface) { // Try to find a more specific type or a type that can be instantiated detectedModelType = TypeProvider?.GetType(itemSystemAttributes.Type); } if (detectedModelType == null) { return(null); } var instance = Activator.CreateInstance(detectedModelType); if (!processedItems.ContainsKey(itemSystemAttributes.Codename)) { processedItems.Add(itemSystemAttributes.Codename, instance); } return(instance); }
private async Task <object> GetPropertyValueAsync(JObject elementsData, PropertyInfo property, JObject linkedItems, ResolvingContext context, IContentItemSystemAttributes itemSystemAttributes, Dictionary <string, object> processedItems, List <PropertyInfo> richTextPropertiesToBeProcessed) { var elementDefinition = GetElementData(elementsData, property, itemSystemAttributes); var elementValue = elementDefinition?.Value; if (elementValue != null) { var valueConverter = GetValueConverter(property); if (valueConverter != null) { return((elementValue["type"].ToString()) switch { "rich_text" => await GetElementModelAsync <RichTextElementValue, string>(property, context, elementValue, valueConverter), "asset" => await GetElementModelAsync <ContentElementValue <Asset>, Asset>(property, context, elementValue, valueConverter), "number" => await GetElementModelAsync <ContentElementValue <decimal?>, decimal?>(property, context, elementValue, valueConverter), "date_time" => await GetElementModelAsync <ContentElementValue <DateTime>, DateTime>(property, context, elementValue, valueConverter), "multiple_choice" => await GetElementModelAsync <ContentElementValue <List <MultipleChoiceOption> >, List <MultipleChoiceOption> >(property, context, elementValue, valueConverter), "taxonomy" => await GetElementModelAsync <TaxonomyElementValue, IEnumerable <ITaxonomyTerm> >(property, context, elementValue, valueConverter), // Custom element, text element, URL slug element _ => await GetElementModelAsync <ContentElementValue <string>, string>(property, context, elementValue, valueConverter), });
private async Task <object> GetRichTextValueAsync(string value, JObject elementsData, PropertyInfo property, JObject linkedItems, IContentItemSystemAttributes itemSystemAttributes, Dictionary <string, object> processedItems, HashSet <RichTextContentElements> currentlyResolvedRichStrings) { var currentlyProcessedString = new RichTextContentElements(itemSystemAttributes?.Codename, property.Name); if (currentlyResolvedRichStrings.Contains(currentlyProcessedString)) { // If this element is already being processed it's necessary to use it as is (with removed inline content items) // otherwise resolving would be stuck in an infinite loop return(await RemoveInlineContentItemsAsync(value)); } currentlyResolvedRichStrings.Add(currentlyProcessedString); var elementData = GetElementData(elementsData, property, itemSystemAttributes); var linkedItemsInRichText = GetLinkedItemsInRichText(elementData?.Value); value = await ProcessInlineContentItemsAsync(linkedItems, processedItems, value, linkedItemsInRichText, currentlyResolvedRichStrings); currentlyResolvedRichStrings.Remove(currentlyProcessedString); return(value); }