Open Simply007 opened 4 years ago
@petrsvihlik the KontentModelGenerator currently outputs releated pages as IEnumerable<object>
. Will it stay like that or will that ever change to explicitly typed collections?
@alanta we track an issue for that here: https://github.com/Kentico/kontent-generators-net/issues/90
We could overcome this drawback with a Management API key, as described at https://github.com/Kentico/kontent-generators-net/issues/90#issuecomment-723428223.
Since there's not going to be a new version of the Delivery API any time soon, it seems like a good approach (if we keep it optional).
But why are you asking? What's your use-case?
@petrsvihlik I was trying to figure out if it was possible to automatically map related content as child documents in the Statiq IDocument metadata. But it seems I'd need more info than is available through reflection.
Would the explicitly typed collections solve your problem?
@Simply007 I've pushed an initial implementation. I've implemented basically what you've proposed. I have tried to make it convenient to work with both typed content and still be able to leverage the all the goodness provided by Statiq.
The core of it is that I've introduced a KontentConfig
class with helpers to construct Statiq Config declarations aimed at Kontent content. For example, this code will add documents from a collection if linked content to the document metadata:
new Kontent<Root>(client)
.WithQuery(
new LimitParameter(1),
new DepthParameter(3)
),
new AddDocumentsToMetadata(Keys.Children, KontentConfig.GetChildren<Root>(page => page.Subpages)),
// or, with the convenience module:
new AddKontentDocumentsToMetadata<Root>(page => page.Subpages),
This gives you a document hierarchy and at a later moment you'd be able to pull the child pages out again through the standard Statiq methods.
Now for your exact example, where you're replacing the parent document with it's children, this should do it:
new Kontent<Root>(client)
.WithQuery(
new LimitParameter(1),
new DepthParameter(3)
),
// dig up the content and set that as the pipeline documents
new ReplaceDocuments( KontentConfig.GetChildren<Root>( page => page.SubPages.OfType<Page>()
.Content.OfType<LandingPage>() ) ),
Since KontentConfig.GetChildren
should handle null values and empty collections gracefully, this single expression should be enough to handle most of the code in your example. The output of that step will contain only pages of the LandingPage
type.
Then to finish it off, this should render that landing page content:
new MergeContent(new ReadFiles("LandingPage.cshtml")),
new RenderRazor()
.WithModel( KontentConfig.As<LandingPage>() )
Note how the KontentConfig.As<T>
helper makes the expression a lot easier to grok.
@petrsvihlik For now, I've decided not to try to map out the document hierarchy automatically. There doesn't seem to be an easy way to do delayed expansion of child document collections. So any automatic expansion has the potential to become an epic fail with lots of unnecessary procssing.
The proposed solution requires the dev to specify what collections to break out into Statiq document metadata. But I think that's reasonable.
@alanta I think that's better. The important part is that we support it, we can always improve the support later.
I have done some testing and everything looks fine!
I have been playing mainly around web spotlight model and now I think it is OK to use.
Basically, I have created a pipeline that loads the "Root" of the web spotlight content model, and based on the content pages types linked in the "tree" structure (just one level) it loads the template, prepares the view model, and defines the destination file based on the data.
https://github.com/Kentico/jamstackon.net/blob/test-linked-items/Pipelines/RootPipeline.cs
There is one "tricky" part. Apart from the "Content" page (in the example LandingPage
content type) the data required during the rendering might be stored in Page
˙ type, like URL slug (showcased in the sample), Show in the menu, .... So flattening the list of input files to just a list of "Content" pages is not sufficient.
https://github.com/Kentico/jamstackon.net/blob/test-linked-items/Pipelines/RootPipeline.cs#L40
The current implementation is using SetMetadata to append the extra information to Metadata of the Content pages under specific COntent page, and it should be possible to use this approach even if you need the data from multiple level of the menu, but it does not look really nice.
https://github.com/Kentico/jamstackon.net/blob/test-linked-items/Pipelines/RootPipeline.cs#L32
Ideally, if there was a way to link the parents and then from child call something like document.AsKontent().GetParent()...
it would be great. But i think this is a bit complicated and out of scope if this issue, I would vote to split this to a separate issue.
Maybe @daveaglick can shine a light on this particular scenario. I'm not quite sure what the best way is to deal with hierarchical data like this in Statiq.
@Simply007 One more thing I introduced in this commit is an easier way to get values from the Kontent data model. So you should be able to replace this:
new SetMetadata(URL_PATH_KEY, Config.FromDocument((doc, ctx) =>
{
return doc.AsKontent<Page>().Url;
})),
with this
new SetMetadata(URL_PATH_KEY, KontentConfig.Get( (Page page) => page.Url ))
It's essentially the same but the KontentConfig helper removes a lot of the noise, making the code easier to read.
I'm going to push out a new release with what we have now.
Oops, the PR closed the issue. I think we still need to figure out how to work with document hierarchies.
Hello @alanta,
We are at the final stage of releasing the first version of the know types linked items generator: https://github.com/kontent-ai/model-generator-net/pull/165 => If you want, reach out on https://kontent.ai/discord/ and we can discuss this further.
Is your feature request related to a problem? Please describe. If you want to load Linked Items of the particular item, it is required to transform them into
IDocument
to be able to pass them through the pipeline and i.e. use them to create a view model for the Razor view. It would be great to have this feature out of the box.I will describe the situation in the example: You have a "Root" item that is the root of your website, this contains the Linked Items element (
Subpages
) model menu structure. Every item (Page
type) then contains anotherSubpages
element to allow having a multilevel navigation menu. Plus thePage
model contains "Content" Linked items element containing typically one item holding the channel-agnostic content. This is basically a Webspotlight setup.Example model structure:
Now if you want to load the data from
Root
and render data from the linked items in razor views, you would do something like:Describe the solution you'd like
It would be great to have the functionality to transfer Linked Items to
IEnumerable<IDocument>
right in the SDK.Describe alternatives you've considered I was thinking about a separate module, but I think it is overengineering.
Additional context I have the solution in the https://github.com/Kentico/jamstackon.net/blob/linked-items-idocument-transformation/Pipelines/RootPipeline.cs