Ticket (Solved)

Orchard projection with custom Filter

I use projection to display a list of content (CarouselItemPart)

I create 2 queries:

1 for list

1 for search

In my search query, I use filter to provide a way to filter my CarouselItemPart

Here is the model of this part:

public class CarouselItemPartRecord : ContentPartRecord
{
    public virtual string Headline { get; set; }
    public virtual string SubHeadline { get; set; }
    public virtual string LinkUrl { get; set; }
    public virtual bool SeparateLink { get; set; }
    public virtual string LinkText { get; set; }
    public virtual string GroupName { get; set; }
    public virtual int SlideOrder { get; set; }

    public virtual string Address { get; set; }

    public virtual DateTime? EndDate { get; set; }
    public virtual DateTime? StartDate { get; set; }

    public virtual bool Locked { get; set; }

    public virtual GMapZonePartRecord GMapZonePartRecord { get; set; }
    public virtual RealEstateActorItemPartRecord RealEstateActorItemPartRecord { get; set; }
}

I assign a GMapZonePartRecord.Id to CarouselItemPartRecord

I can filter by other part like BodyPart, what I want now to do is to filter by GMapZonePartRecord.

I create for this a custom Filter and Form:

public class CommuneFilter : IFilterProvider
{

    public CommuneFilter()
    {
        T = NullLocalizer.Instance;
    }

    public Localizer T { get; set; }

    public void Describe(DescribeFilterContext describe)
    {
        describe.For(
            "GMapZonePartRecord", // The category of this filter
            T("Commune"), // The name of the filter (not used in 1.4)
            T("Commune")) // The description of the filter (not used in 1.4)

            // Defines the actual filter (we could define multiple filters using the fluent syntax)
            .Element(
                "HasCommunes", // Type of the element
                T("Has communes"), // Name of the element
                T("Commune filter content items"), // Description of the element
                ApplyFilter,
                DisplayFilter,
                "SelectCommunes"
            );
    }

    public void ApplyFilter(FilterContext context)
    {
        var communes = (string)context.State.CommuneIds;

        if (!String.IsNullOrEmpty(communes))
        {
            var ids = communes.Split(new[] { ',' }).Select(Int32.Parse).ToArray();

            if (ids.Length == 0)
            {
                return;
            }

            int op = Convert.ToInt32(context.State.Operator);

            Action<IAliasFactory> selector;
            Action<IHqlExpressionFactory> filter;
            switch (op)
            {
                case 0:
                    // is one of
                    selector = alias => alias.ContentPartRecord<GMapZonePartRecord>();
                    filter = x => x.InG("Id", ids);
                    context.Query.Where(selector, filter);
                    break;
                case 1:
                    // is all of
                    foreach (var id in ids)
                    {
                        int communeId = id;
                        selector = alias => alias.ContentPartRecord<GMapZonePartRecord>();
                        filter = x => x.Eq("Id", communeId);
                        context.Query.Where(selector, filter);
                    }
                    break;
                case 2:
                    // is not one of can't be done without sub queries
                    break;
            }
        }
    }

    public LocalizedString DisplayFilter(FilterContext context)
    {
        string communes = Convert.ToString(context.State.CommuneIds);

        if (String.IsNullOrEmpty(communes))
        {
            return T("Any communes");
        }

        //var communeNames = communes.Split(new[] { ',' }).Select(x => _tagService.GetTag(Int32.Parse(x))).Where(x => x != null).Select(x => x.TagName);

        //return T("Tagged with {0}", String.Join(", ", communeNames));
        return T("Communes in {0}", communes);
    }
}

public interface IFormProvider : IEventHandler {
    void Describe(dynamic context);
}

public class CommuneFilterForms : IFormProvider {
    protected dynamic Shape { get; set; }
    public Localizer T { get; set; }

    public CommuneFilterForms(
        IShapeFactory shapeFactory) {
        Shape = shapeFactory;
        T = NullLocalizer.Instance;
    }

    public void Describe(dynamic context) {
        Func<IShapeFactory, dynamic> form =
            shape => {

                var f = Shape.Form(
                    Id: "SelectCommunes",
                    _Communes: Shape.TextBox(
                        Id: "communeids", Name: "CommuneIds",
                        Title: T("Communes"),
                        Classes: new[] { "text medium", "tokenized" },
                        Description: T("Enter the values of commune you want to.")
                        ),
                    _Exclusion: Shape.FieldSet(
                        _OperatorOneOf: Shape.Radio(
                            Id: "operator-is-one-of", Name: "Operator",
                            Title: T("Is one of"), Value: "0", Checked: true
                            ),
                        _OperatorIsAllOf: Shape.Radio(
                            Id: "operator-is-all-of", Name: "Operator",
                            Title: T("Is all of"), Value: "1"
                            )
                        ));

                //foreach (var tag in _tagService.GetTags()) {
                //    f._Tags.Add(new SelectListItem { Value = tag.Id.ToString(), Text = tag.TagName });
                //}

                return f;
            };

        context.Form("SelectCommunes", form);

    }
}

If I debug, I receive correctly information in ApplyFilter, I put a breakpoint and I have my ids ok.

I don't understand what to write in the Where of the IHqlQuery.

I try to debug to see how orchard convert IHqlQuery but I don't achieve this.

The sql would be:

select distinct civ.Id as Id
from Orchard.ContentManagement.Records.ContentItemVersionRecord as civ
join civ.ContentItemRecord as ci
join ci.CarouselItemPartRecord as carouselItemPartRecord
join carouselItemPartRecord.GMapZonePartRecord_Id as gMapZonePartRecord_Id
where (gMapZonePartRecord_Id in (XXXXX)) AND (civ.Published = True)
order by civ.Id]

Re: Orchard projection with custom Filter

This custom sort class, even if it's doing sorting, should give you a good hint about how to build this: https://vandelay.codeplex.com/SourceControl/latest#Providers/SortCriteria/CustomSortCriteria.cs

Friday, April 11, 2014 4:31:07 AM bybleroy
  • bleroy
  • Lv. 08 Rookie
  • Total EXP: 527

Re: Orchard projection with custom Filter

Thanks for your code, with this I try some possibilities and this one is ok:

(I can't post my code because it's potentially dangerous :) ) The idea is to select CarouselItemPartRecord then select his property GMapZonePartRecord then apply the filter.

Friday, April 11, 2014 10:20:37 AM bylambertjer

Re: Orchard projection with custom Filter

@lambertjer That issue (potentially dangerous request) will be solved in the next release (due end of the weekend).

Friday, April 11, 2014 10:53:03 AM bysfmskywalker

Post a reply

You need to be signed in to post a reply.

Sign In