Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When Creating a new content item in BagPart, content item Index don't update #15226

Closed
effapp opened this issue Feb 1, 2024 · 2 comments
Closed
Labels

Comments

@effapp
Copy link

effapp commented Feb 1, 2024

Describe the bug

When Creating a new content item in BagPart, content item Index don't update

To Reproduce

Steps to reproduce the behavior:
(Taking OrchardCore.Commerce solution as example)
1.Create a new ContentType and name "BagTestPage", add BagPart in it
2.Set "Contained Content Types" of Bag in BagTestPage to "Product"
3.Create a new Content Item of BagTestPage and name "ProductBags"
4.Create a couple of Product content items in ProductBags, these Product content items was not updated to ProductPartIndex.

@effapp effapp added the bug 🐛 label Feb 1, 2024
@MikeAlhayek
Copy link
Member

That is by design. BagPart items are stored in the same content item not as a related items. In other words, the content items in the bag are not stored in separate document which mean they will not be indexed separately.

@lampersky
Copy link
Contributor

@effapp in the past I faced the same problem, and ended up with some custom index provider, but please remember you can fill up your index very quickly, this solution is also able to index nested BagParts, inside TextFieldIndex in ContentField column you will get something similar to path "Field.NestedName1.NestedName2.NestedName3". In my case I wanted to have all index values in same table (TextFieldIndex) and avoid creating dedicated one.

    public class BagPartTextFieldIndexProvider : ContentFieldIndexProvider
    {
        private readonly IServiceProvider _serviceProvider;
        private readonly HashSet<string> _ignoredTypes = new();
        private IContentDefinitionManager _contentDefinitionManager;

        public BagPartTextFieldIndexProvider(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public override void Describe(DescribeContext<ContentItem> context)
        {
            context.For<TextFieldIndex>()
                .Map(contentItem =>
                {
                    // Remove index records of soft deleted items.
                    if (!contentItem.Published && !contentItem.Latest)
                    {
                        return null;
                    }

                    // Can we safely ignore this content item?
                    if (_ignoredTypes.Contains(contentItem.ContentType))
                    {
                        return null;
                    }

                    // Lazy initialization because of ISession cyclic dependency
                    _contentDefinitionManager ??= _serviceProvider.GetRequiredService<IContentDefinitionManager>();

                    var items = _contentDefinitionManager.GetAllFields(contentItem, nameof(TextField));

                    var result = new List<TextFieldIndex> { };

                    foreach (var item in items)
                    {
                        foreach (var contentPartFieldDefinition in item.fieldDefinitions)
                        {
                            var field = contentPartFieldDefinition.GetContentField<TextField>(item.contentItem);
                            if (field == null) { continue; }
                            result.Add(                   
                                new TextFieldIndex
                                {
                                    Latest = contentItem.Latest,
                                    Published = contentItem.Published,
                                    ContentItemId = contentItem.ContentItemId,
                                    ContentItemVersionId = contentItem.ContentItemVersionId,
                                    ContentType = contentItem.ContentType,
                                    ContentPart = item.partName,
                                    ContentField = contentPartFieldDefinition.Name,
                                    Text = field.Text?[..Math.Min(field.Text.Length, TextFieldIndex.MaxTextSize)],
                                    BigText = field.Text,
                                }
                            );
                        }
                    }

                    return result;
                });
        }
    }

some extensions:

    public static class IContentDefinitionManagerExtensions
    {
        public static List<(string partName, ContentPartFieldDefinition[] fieldDefinitions, ContentItem contentItem)> GetAllFields(this IContentDefinitionManager contentDefinitionManager, ContentItem rootContentItem, string fieldDefinitionName)
        {
            List<(string, ContentPartFieldDefinition[], ContentItem)> result = new();
            Dictionary<string, ContentTypeDefinition> cache = new();
            Traverse(rootContentItem);
            return result;

            void Traverse(ContentItem contentItem, int level = 0, string partName = null)
            {
                if (!cache.TryGetValue(contentItem.ContentType, out var contentTypeDefinition))
                {
                    contentTypeDefinition = contentDefinitionManager.GetTypeDefinition(contentItem.ContentType);
                    cache.TryAdd(contentItem.ContentType, contentTypeDefinition);
                }

                // zero level items are alredy indexed by main TextFieldIndexProvider
                if (level > 0)
                {
                    var fields = contentTypeDefinition.GetFields(fieldDefinitionName);
                    result.AddRange(fields.Select(f => (PartNameJoin(partName, f.Name), f.Item2, contentItem)));
                }

                foreach ((string Name, List<ContentItem> Items) partContentItems in contentTypeDefinition.GetBagPartsContentItems(contentItem))
                {
                    int position = 0;
                    foreach (var ci in partContentItems.Items)
                    {
                        Traverse(ci, level + 1, PartNameJoin(partName, partContentItems.Name, $"[{position++}]"));
                    }
                }
            }

            string PartNameJoin(params string[] p)
            {
                return string.Join('.', p.Where(x => !string.IsNullOrEmpty(x)));
            }
        }
    }

here it would be good to get rid of those tuples, but it was just a proof of concept:

    public static class ContentTypeDefinitionExtensions
    {
        public static (string Name, ContentPartFieldDefinition[])[] GetFields(this ContentTypeDefinition contentTypeDefinition, string fieldDefinitionName)
        {
            return contentTypeDefinition
                        .Parts
                        .Select(x =>
                            (
                                x.Name,
                                x.PartDefinition.Fields.Where(f => f.FieldDefinition.Name == fieldDefinitionName).ToArray()
                            )
                        )
                        .Where(x => x.Item2.Length > 0)
                        .ToArray();
        }

        public static (string Name, List<ContentItem>)[] GetBagPartsContentItems(this ContentTypeDefinition contentTypeDefinition, ContentItem contentItem)
        {
            var bagParts = contentTypeDefinition
                        .Parts
                        .Where(x => x.PartDefinition.Name == nameof(BagPart))
                        .Select(x => (x.Name, contentItem.Get<BagPart>(x.Name)?.ContentItems))
                        .Where(x => x.ContentItems != null && x.ContentItems?.Count > 0)
                        .ToArray();

            return bagParts;
        }
    }

@OrchardCMS OrchardCMS locked and limited conversation to collaborators Feb 2, 2024
@MikeAlhayek MikeAlhayek converted this issue into discussion #15233 Feb 2, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
Projects
None yet
Development

No branches or pull requests

3 participants