UmbracoMapper icon indicating copy to clipboard operation
UmbracoMapper copied to clipboard

Umbraco Mapper honouring fallback?

Open shearer3000 opened this issue 4 years ago • 10 comments

Hi Andy

I am trying to extend my IPropertyValueGetter Method to support a language fallback but can’t figure out what’s not working.

Say for example that Umbraco has 2 languages, English and Spanish, and English is defined as the fallback language for Spanish. (English also being the default) Now, consider that I have page nodes in the both content trees that pick a “category” from a common area (just another set of nodes). What I was expecting is that if the Category node isn’t published in Spanish, then the Spanish pages would ‘fallback’ to the Category from the English language tree.

My viewmodel property is decorated with [PropertyMapping(PropertyValueGetter = typeof(CategoriesGetter), FallbackMethods = new[] { Fallback.Language })] And the method passes the fallback onto the Umbraco IPublishedElement Value() method.

Sorry I am not sure if this is a mapping issue or an Umbraco issue, or if I’m misunderstanding how fallbacks work. Does my scenario match your understanding?

Thanks Andrew

shearer3000 avatar Apr 03 '20 03:04 shearer3000

I'll have a look into this Andrew. Meantime, could you share the code of your CategoriesGetter so I can see how you've implemented it please?

AndyButland avatar Apr 04 '20 18:04 AndyButland

Hi Andy The method is like so (basically just attempting to get the Names of the picked content nodes i.e. “category”, there might be multiple picked)

public class CategoriesGetter : IPropertyValueGetter
{
	public object GetPropertyValue(IPublishedElement content, string alias, string culture, string segment, Fallback fallback)
	{
		var categoryIpcs = content.Value<IEnumerable<IPublishedContent>>(alias, fallback: fallback);
		return categoryIpcs?.Select(x=>x.Name).ToList();
	}
 }

When debugging my Spanish site, I can see both cultures on the IPublishedElement content, but after the Value() method is called the IPublishedContent has an object and the culture is English but the Name is null. I was expecting the English node name as there isn’t one published in Spanish.

I was trying to follow some documentation you linked to in an old forum post https://our.umbraco.com/Documentation/Getting-Started/Design/Rendering-Content/#using-fall-back-methods But that is more for the view helper methods. I’m not entirely sure if I need to be on-passing the culture and segment parameters in the Umbraco mapper signature?

Thanks Andrew

shearer3000 avatar Apr 04 '20 20:04 shearer3000

Also, not sure if this is relevant, but the property on the doctype has 'Allow varying by culture' enabled, and only the English site is content loaded. So the understanding would be that the Spanish site would 'fallback' to the English site property value?

shearer3000 avatar Apr 04 '20 20:04 shearer3000

I'm pretty sure you should be passing along the culture parameter, yes. So: var categoryIpcs = content.Value<IEnumerable<IPublishedContent>>(alias, culture, fallback: fallback);.

Otherwise I believe what will be happening is that you are getting the list of categories without specifying the culture, and it'll be using the default.

AndyButland avatar Apr 05 '20 06:04 AndyButland

Thanks Andy - I’ve been trying all number of combinations with the culture and fallback parameters but no amount of trying seems to be getting it to work. I mentioned I wasn’t really sure if this was a core umbraco issue or umbraco mapper so I logged an issue here too https://github.com/umbraco/Umbraco-CMS/issues/7901

Btw do you have an example of how I extend my umbraco mapper property decorator to obtain the culture from the current request context and pass that into the IPropertyValueGetter method as the param?

Thanks for help so far 😊 Andrew

shearer3000 avatar Apr 06 '20 00:04 shearer3000

Hi Andrew

I've set up a simple example of the fallbacks, and think it working. Though I did note that both the node for the page AND the nodes for the picked categories need to be set to "allow varying by culture".

Here's the setup I've got:

One document type for a page, set to "allow varying by culture", with a single property called pickedCategories, that's a multi-node picker that allows picking of nodes of the following type. The property is also set to "allow varying by culture".

The picked document type is set to "allow varying by culture" and it has a single property called categoryName with the same setting.

I've then created a piece of content in en-US (the default culture) and picked two categories that are also fully populated in that language. I've picked the same categories and published the same page in a second language (Italian).

For one of the categories I've translated it into Italian, and for the other I haven't.

Italian falls back to US English.

Then I've got this view model:

    public class CategoryListViewModel
    {
        public List<CategoryDetail> PickedCategories { get; set; } = new List<CategoryDetail>();

        public class CategoryDetail
        {
            public string Name { get; set; }

            [PropertyMapping(FallbackMethods = new[] { Fallback.Language })]
            public string CategoryName { get; set; }
        }
    }

And this controller:

    public class CategoryListController : BaseController
    {
        public CategoryListController(IUmbracoMapper mapper)
            : base(mapper)
        {
        }

        public ActionResult CategoryList(string culture = "")
        {
            var model = new CategoryListViewModel();
            Mapper.Map(CurrentPage, model, culture);
            return CurrentTemplate(model);
        }
    }

And this view:

@inherits Umbraco.Web.Mvc.UmbracoViewPage<TestWebApp80.Models.CategoryListViewModel>

@foreach(var category in Model.PickedCategories)
{
	<div>@category.Name - @category.CategoryName</div>
}

When requesting with /categories/?culture=en-US I see:

Fruit - Fruit
Vegetables - Vegetables

And with /categories/?culture=it:

Vegetables - Verdure
Fruit - Fruit

Note that "vegetables" is translated but "fruit" isn't, it's falling back.

Maybe you can use this to see why your version isn't working as you'd expect, or perhaps to see if there's a simpler way to do what you need.

It does seem that it's not ideal that I have to make the page "allow varying by culture" - as it means I've got to pick the categories in both languages, whereas ideally they'd be picked once, and the same categories would be displayed in both languages, just translated. But I couldn't get that to work - I think because the first mapping operation (for the pickedCategories property) will fail if you pass a culture and it doesn't vary by culture.

AndyButland avatar Apr 06 '20 19:04 AndyButland

Hi Andy

Many thanks for taking the time out to test that and verify its working as expected for you.

I have all doctypes set as "allow varying by culture" but yes that is a useful nugget of information 😊

Sebastiaan also set up a working example and explained in https://github.com/umbraco/Umbraco-CMS/issues/7901 that it all appears working for him too.

So at this point I need to work out what is different about my set up (screenshots also added to # 7901 now too) but it all looks the same as what you and Sebastiaan have set up.

Andrew

shearer3000 avatar Apr 06 '20 21:04 shearer3000

Also, to you point about “it's not ideal that I have to make the page "allow varying by culture" - as it means I've got to pick the categories in both languages, whereas ideally they'd be picked once, and the same categories would be displayed in both languages, just translated”

Yes, maybe my understanding of what "allow varying by culture" actually means isn’t 100% yet either. My expectation from the docs is that it would mean, assuming in this case that my ‘categories’ field didn’t have "allow varying by culture", is that the value method would return the IPC from the English site, or the Spanish variant of that node (if there was one published) but my site doesn’t seem to do either.

shearer3000 avatar Apr 06 '20 22:04 shearer3000

I've realised there's an improvement I could make to my example above, which avoids having the make the page and it's picker property varying by culture, which it so map the picked collection explicitly, only providing the culture there.

I.e. instead of:

public ActionResult CategoryList(string culture = "")
{
    var model = new CategoryListViewModel();
    Mapper.Map(CurrentPage, model, culture);
    return CurrentTemplate(model);
}

This:

public ActionResult CategoryList(string culture = "")
{
    var model = new CategoryListViewModel();
    Mapper.Map(CurrentPage, model)
        .MapCollection(CurrentPage.Value<IEnumerable<IPublishedContent>>("pickedCategories"), model.PickedCategories, culture);
    return CurrentTemplate(model);
}

AndyButland avatar Apr 12 '20 10:04 AndyButland

hi Andy - thanks for that extra suggestion. I feel like there's another issue with Umbraco going on where it returns an IPC when arguably it shouldn't be, and that could be contributing to this issue too. I described that here https://github.com/umbraco/Umbraco-CMS/issues/7979

shearer3000 avatar Apr 20 '20 02:04 shearer3000