Orchard查询基于URL参数的内容类型的排序提供程序

时间:2014-02-05 07:29:57

标签: asp.net-mvc-4 sorting orchardcms orchardcms-1.7

我有一个名为Property的内容类型,它是在Orchard管理员Web界面中创建的。属性包含多个字段,其中2个是地址和价格。

我创建了一个查询过滤属性内容类型,并希望通过Projection根据URL查询字符串参数对这些内容进行排序。例如。 〜/ PropertyProjection?sortfield = price& sortasc = true 会按价格升序对属性进行排序。

下面的代码用于分类价格,但我想知道是否有更好,更简单,更有效的方法来实现这一目标。特别是我想自动设置propertyName和dataType变量。

using System;
using System.Collections.Generic;
using System.Linq;
using Orchard;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.MetaData;
using Orchard.Localization;
using Orchard.Projections.Descriptors.SortCriterion;
using Orchard.Projections.FieldTypeEditors;
using Orchard.Projections.Services;
using Orchard.Utility.Extensions;

namespace CustomModule.Providers {
    public class PropertySortCriterionProvider : ISortCriterionProvider {
        private readonly IContentDefinitionManager _contentDefinitionManager;
        private readonly IEnumerable<IContentFieldDriver> _contentFieldDrivers;
        private readonly IEnumerable<IFieldTypeEditor> _fieldTypeEditors;
        private readonly IWorkContextAccessor _workContextAccessor;

        public PropertySortCriterionProvider(
            IContentDefinitionManager contentDefinitionManager,
            IEnumerable<IContentFieldDriver> contentFieldDrivers,
            IEnumerable<IFieldTypeEditor> fieldTypeEditors,
            IWorkContextAccessor workContextAccessor)
        {
            _contentDefinitionManager = contentDefinitionManager;
            _contentFieldDrivers = contentFieldDrivers;
            _fieldTypeEditors = fieldTypeEditors;
            _workContextAccessor = workContextAccessor;
            T = NullLocalizer.Instance;
        }

        public Localizer T { get; set; }

        public void Describe(DescribeSortCriterionContext describe) {


            var descriptor = describe.For("Custom Property", T("Custom Property"), T("Custom Property sorts"));
            descriptor.Element("PropertySortQueryParam", T("PropertySortQueryParam"),
                               T("Sort Property by the HTTP Query Sort parameters"),
                               context => ApplyFilter(context),
                               context => DisplaySortCriterion(context)
                );
        }

        public void ApplyFilter(SortCriterionContext context)
        {
            //bool ascending = Convert.ToBoolean(context.State.Sort);

            var sortField = _workContextAccessor.GetContext().HttpContext.Request.Params["sortfield"];
            var ascending = true;
            if (!bool.TryParse(_workContextAccessor.GetContext().HttpContext.Request.Params["sortasc"], out ascending))
                ascending = true;

            if (!string.IsNullOrEmpty(sortField)) {
                var propertyName = "";
                Type dataType = null;
                var fieldName = "";

                if (sortField.ToLower() == "price") {
                    propertyName = "Property.Price.";
                    dataType = typeof (Decimal);
                    fieldName = "Price";
                }

                //if we have valid sort criteria from the URL param
                if (dataType != null) {
                    IFieldTypeEditor fieldTypeEditor = _fieldTypeEditors.FirstOrDefault(x => x.CanHandle(dataType));
                    var part = _contentDefinitionManager.ListPartDefinitions().First(p => p.Name == "Property");
                    var field = part.Fields.Where(f => f.Name == fieldName);

                    // use an alias with the join so that two filters on the same Field Type wont collide
                    var relationship = fieldTypeEditor.GetFilterRelationship(propertyName.ToSafeName());

                    // generate the predicate based on the editor which has been used
                    Action<IHqlExpressionFactory> predicate = y => y.Eq("PropertyName", propertyName);

                    // combines the predicate with a filter on the specific property name of the storage, as implemented in FieldIndexService

                    // apply where clause
                    context.Query = context.Query.Where(relationship, predicate);

                    // apply sort
                    context.Query = ascending
                        ? context.Query.OrderBy(relationship, x => x.Asc("Value"))
                        : context.Query.OrderBy(relationship, x => x.Desc("Value"));
                }

            }       
        }

        public LocalizedString DisplaySortCriterion(SortCriterionContext context) {
            bool ascending = Convert.ToBoolean(context.State.Sort);

            if (ascending) {
                return T("Ordered by Custom Property HTTP Query Sort parameters ascending");
            }

            return T("Ordered by Custom property HTTP Query Sort parameters descending");
        }
    }

}

以上代码基于Orchard.Projections.Providers.SortCriteria中的ContentFieldsSortCriterion

请在答案中提供代码示例。

干杯,

安德鲁

1 个答案:

答案 0 :(得分:0)

这是一个查询排序提供程序,它允许对HTTP请求查询参数中指定的任何字段进行排序。

using System;
using System.Collections.Generic;
using System.Linq;
using Orchard;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.MetaData;
using Orchard.Localization;
using Orchard.Projections.Descriptors.SortCriterion;
using Orchard.Projections.FieldTypeEditors;
using Orchard.Projections.Services;
using Orchard.Utility.Extensions;
using Orchard.Events;
using Orchard.Environment.Extensions;
using Orchard.ContentManagement.Handlers;

namespace CustomModule.Providers.SortCriteria {
    public class QueryParamSortCriterionProvider : ISortCriterionProvider {
        private readonly IContentDefinitionManager _contentDefinitionManager;
        private readonly IEnumerable<IContentFieldDriver> _contentFieldDrivers;
        private readonly IEnumerable<IFieldTypeEditor> _fieldTypeEditors;
        private readonly IWorkContextAccessor _workContextAccessor;

        public QueryParamSortCriterionProvider(
            IContentDefinitionManager contentDefinitionManager,
            IEnumerable<IContentFieldDriver> contentFieldDrivers,
            IEnumerable<IFieldTypeEditor> fieldTypeEditors,
            IWorkContextAccessor workContextAccessor)
        {
            _contentDefinitionManager = contentDefinitionManager;
            _contentFieldDrivers = contentFieldDrivers;
            _fieldTypeEditors = fieldTypeEditors;
            _workContextAccessor = workContextAccessor;
            T = NullLocalizer.Instance;
        }

        public Localizer T { get; set; }

        public void Describe(DescribeSortCriterionContext describe) {
            var descriptor = describe.For("General", T("General"), T("General sort criteria"));
            descriptor.Element("QueryParamField", T("Query Param Field"),
                               T("Sorts results using query parameters on the HTTP request"),
                               context => ApplyFilter(context),
                               context => DisplaySortCriterion(context)
                );
        }

        public void ApplyFilter(SortCriterionContext context)
        {
            var sortField = _workContextAccessor.GetContext().HttpContext.Request.Params["sortby"];

            if (string.IsNullOrWhiteSpace(sortField)) {
                return;
            }

            var ascending = true;
            if (!bool.TryParse(_workContextAccessor.GetContext().HttpContext.Request.Params["sortasc"], out ascending))
                ascending = true;

            var sortFieldElements = sortField.Split(new []{'.'}, 2);

            if (sortFieldElements.Length != 2) {
                return;
            }

            var part = _contentDefinitionManager.ListPartDefinitions().FirstOrDefault(p => p.Name == sortFieldElements[0]);

            if (part == null) {
                return;
            }

            var field = part.Fields.FirstOrDefault(f => f.Name == sortFieldElements[1]);

            if (field == null) {
                return;
            }

            var drivers = _contentFieldDrivers.Where(x => x.GetFieldInfo().Any(fi => fi.FieldTypeName == field.FieldDefinition.Name)).ToList();

            var membersContext = new DescribeMembersContext(
                (storageName, storageType, displayName, description) => {
                    // look for a compatible field type editor
                    IFieldTypeEditor fieldTypeEditor = _fieldTypeEditors.FirstOrDefault(x => x.CanHandle(storageType));

                    if (fieldTypeEditor != null) {

                        var propertyName = String.Join(".", part.Name, field.Name, storageName ?? "");

                        // use an alias with the join so that two filters on the same Field Type wont collide
                        var relationship = fieldTypeEditor.GetFilterRelationship(propertyName.ToSafeName());

                        // generate the predicate based on the editor which has been used
                        Action<IHqlExpressionFactory> predicate = y => y.Eq("PropertyName", propertyName);

                        // combines the predicate with a filter on the specific property name of the storage, as implemented in FieldIndexService

                        // apply where clause
                        context.Query = context.Query.Where(relationship, predicate);

                        // apply sort
                        context.Query = ascending
                            ? context.Query.OrderBy(relationship, x => x.Asc("Value"))
                            : context.Query.OrderBy(relationship, x => x.Desc("Value"));
                    }
                });

            foreach (var driver in drivers) {
                driver.Describe(membersContext);
            }

        }

        public LocalizedString DisplaySortCriterion(SortCriterionContext context) {
            return T("Ordered by fields specified by HTTP query parameters (eg. ?sortby=PartName.FieldName&sortasc=true)");
        }
    }

}