Closed mattnield closed 2 years ago
Hi, thank you for submitting this issue!
Unfortunately, we need to know the type of the element (it can't be deduced from its shape as it is not unique) in order to create a strongly typed object. One way how we it can be done:
public async static Task<IEnumerable<BaseElement>> GetStronglyTypedElements(this IManagementClient client, LanguageVariantModel variant)
{
var item = await client.GetContentItemAsync(variant.Item);
var type = await client.GetContentTypeAsync(item.Type);
var results = new List<BaseElement>();
foreach (dynamic element in variant.Elements)
{
var typeElement = type.Elements.FirstOrDefault(x => x.Id == Guid.Parse(element.element.id));
if (typeElement != null)
{
var strongyTypedElement = typeElement.Type switch
{
ElementMetadataType.Text => ElementModelProvider.ToElement(element, typeof(TextElement)),
ElementMetadataType.RichText => ElementModelProvider.ToElement(element, typeof(RichTextElement)),
ElementMetadataType.Number => ElementModelProvider.ToElement(element, typeof(NumberElement)),
ElementMetadataType.MultipleChoice => ElementModelProvider.ToElement(element, typeof(MultipleChoiceElement)),
ElementMetadataType.DateTime => ElementModelProvider.ToElement(element, typeof(DateTimeElement)),
ElementMetadataType.Asset => ElementModelProvider.ToElement(element, typeof(AssetElement)),
ElementMetadataType.LinkedItems => ElementModelProvider.ToElement(element, typeof(LinkedItemsElement)),
ElementMetadataType.Taxonomy => ElementModelProvider.ToElement(element, typeof(TaxonomyElement)),
ElementMetadataType.UrlSlug => ElementModelProvider.ToElement(element, typeof(UrlSlugElement)),
ElementMetadataType.Custom => ElementModelProvider.ToElement(element, typeof(CustomElement)),
ElementMetadataType.Subpages => ElementModelProvider.ToElement(element, typeof(SubpagesElement)),
_ => throw new InvalidOperationException("Unknow element type"),
};
results.Add(strongyTypedElement);
}
}
return results;
}
What do you think? Another option is to take ContentTypeModel
as parameter...
Hi @gormal ,
With the help of @Simply007, I've got something similar to the above for the time being by copying out the ToElement
function to m own code for now. Exposing that would certainly help. I know the type of the element in what I'm doing, but only at run time, not design time. So being able to pass the type model in might be a good additional solution.
Yes, we can either do
IManagementClient .GetStronglyTypedElements(LanguageVariantModel variant, ContentTypeModel type = null)
to provide a way to pass the type.
Or we can do
IManagementClient .GetStronglyTypedElement(dynamic element, ElementMetadataType elementType)
which might be more flexible, because you might want to use projection and gen only some elements.
What do you think @mattnield @gormal - and maybe @mcbeev?
So - being greedy - could we do both? 🫢
I can think of places where both would be really useful. In my case right now, it's the second case, but equally being able to do the first is really helpful.
Let's start with the IManagementClient.GetStronglyTypedElement(dynamic element, ElementMetadataType elementType)
extension method which might is more flexible and "low-level". The wrapper is basically loading a content type and iteration through the element and calling this method.
@mattnield - it is out -> https://github.com/Kentico/kontent-management-sdk-net/releases/tag/3.0.4
Could you test it out?
Motivation
Why is this feature required? What problems does it solve? Being able to retrieve a strong-typed language variant, and/or its elements when processing content items
Proposed solution
Add an extension method to
LanguageVariantModel
that makes use of the functionality inKentico.Kontent.Management.Modules.ModelBuilders.ElementModelProvider
to return all of the boxed element in anIEnumerable<BaseElement>
. Also, possibly exposing theToElement(...)
.Additional context
The reason I came across this issue is that I'm writing an integration with a 3rd party translation service. The service uses a mixture of machine and human translation, so providing to a readable structure is a must. T do this I currently use the Devliery API (DAPI) rather than the Management API (MAPI) and recusrively create a JSON document that presents a hierarchy of a content item and it 'children', focussing on Text, RichText element. This looks similar to the below:
RichText
however obviously provides some complications due to modular content and component etc. These cannot be resolved for translation, so I want to use the MAPI to deal with exporting theRichText
fields. Possibly if things get easier I can also use MAPI for the entire export, though the rate limit on the MAPI may be prohibitive. Due to how this is working, I don't know the Conent Item's type at design time and dependon on what can be determined at runtime.I'm using the following code to work things through:
As it stands,
mapiItemElement
is anExpandoObject
, so needs to be cast using(dynamic)mapiItemElement
before thecomponents
,element
, andvalue
properties can be accessed. Copying theToElement
method as mentioned above provides a much smoother and more readable codebase:We now have
typedElement.Components
👌 However, being able to do that with themapiLanguageVariant
as an extension method would make this a simpler task. I.e.(if we can do it without passing the type in, that's even better!)