2014-02-05 78 views
1

我有一個名爲Property的內容類型,它是在Orchard管理Web界面中創建的。物業包含多個字段,其中2個是地址和價格。Orchard Query基於URL參數的內容類型查詢排序提供程序

我已經創建了一個Query過濾屬性內容類型,並希望通過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"); 
     } 
    } 

} 

上面的代碼是基於關閉ContentFieldsSortCriterion在Orchard.Projections.Providers.SortCriteria

請提供你的答案的代碼示例。

乾杯,

安德魯

+0

我有一個預感,這可以完全通過預測沒有任何代碼。你試過這個嗎?您可以在投影過濾器中使用查詢字符串標記。 –

+0

是的,我試過沒有運氣。如果我在一個方向上對單個領域進行排序,那麼不用擔心。但我不知道基於查詢字符串參數選擇字段的方法,然後在基於另一個查詢字符串參數的方向上對該字段進行排序。 – Andrew

+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)"); 
     } 
    } 

}