ProjectionManager Extension (#7417)

- Defined a new interface IProjectionManagerExtension that inherits from IProjectionManager
- ProjectionManager now implements IProjectionManagerExtension, so we can pass a part to GetCount and GetContentItems
- GetCount and GetContentItems transform the part into a Content token, so you can filter data with informations contained in the Projection itself
This commit is contained in:
Hermes Sbicego
2016-12-01 22:00:13 +01:00
committed by Sébastien Ros
parent 83f47ac148
commit 8a328902fd
4 changed files with 65 additions and 26 deletions

View File

@@ -24,7 +24,7 @@ using Orchard.Utility.Extensions;
namespace Orchard.Projections.Drivers { namespace Orchard.Projections.Drivers {
public class ProjectionPartDriver : ContentPartDriver<ProjectionPart> { public class ProjectionPartDriver : ContentPartDriver<ProjectionPart> {
private readonly IRepository<QueryPartRecord> _queryRepository; private readonly IRepository<QueryPartRecord> _queryRepository;
private readonly IProjectionManager _projectionManager; private readonly IProjectionManagerExtension _projectionManager;
private readonly IFeedManager _feedManager; private readonly IFeedManager _feedManager;
private readonly ITokenizer _tokenizer; private readonly ITokenizer _tokenizer;
private readonly IDisplayHelperFactory _displayHelperFactory; private readonly IDisplayHelperFactory _displayHelperFactory;
@@ -34,7 +34,7 @@ namespace Orchard.Projections.Drivers {
public ProjectionPartDriver( public ProjectionPartDriver(
IOrchardServices services, IOrchardServices services,
IRepository<QueryPartRecord> queryRepository, IRepository<QueryPartRecord> queryRepository,
IProjectionManager projectionManager, IProjectionManagerExtension projectionManager,
IFeedManager feedManager, IFeedManager feedManager,
ITokenizer tokenizer, ITokenizer tokenizer,
IDisplayHelperFactory displayHelperFactory, IDisplayHelperFactory displayHelperFactory,
@@ -110,7 +110,7 @@ namespace Orchard.Projections.Drivers {
_feedManager.Register(metaData.DisplayText, "rss", new RouteValueDictionary { { "projection", part.Id } }); _feedManager.Register(metaData.DisplayText, "rss", new RouteValueDictionary { { "projection", part.Id } });
// execute the query // execute the query
var contentItems = _projectionManager.GetContentItems(query.Id, pager.GetStartIndex() + part.Record.Skip, pager.PageSize).ToList(); var contentItems = _projectionManager.GetContentItems(query.Id, part, pager.GetStartIndex() + part.Record.Skip, pager.PageSize).ToList();
// sanity check so that content items with ProjectionPart can't be added here, or it will result in an infinite loop // sanity check so that content items with ProjectionPart can't be added here, or it will result in an infinite loop
contentItems = contentItems.Where(x => !x.Has<ProjectionPart>()).ToList(); contentItems = contentItems.Where(x => !x.Has<ProjectionPart>()).ToList();
@@ -122,7 +122,7 @@ namespace Orchard.Projections.Drivers {
// create pager shape // create pager shape
if (part.Record.DisplayPager) { if (part.Record.DisplayPager) {
var contentItemsCount = _projectionManager.GetCount(query.Id) - part.Record.Skip; var contentItemsCount = _projectionManager.GetCount(query.Id, part) - part.Record.Skip;
contentItemsCount = Math.Max(0, contentItemsCount); contentItemsCount = Math.Max(0, contentItemsCount);
pagerShape.TotalItemCount(contentItemsCount); pagerShape.TotalItemCount(contentItemsCount);
} }

View File

@@ -175,6 +175,7 @@
<Compile Include="Providers\Layouts\ShapeLayoutForms.cs" /> <Compile Include="Providers\Layouts\ShapeLayoutForms.cs" />
<Compile Include="Providers\Properties\CustomValueProperties.cs" /> <Compile Include="Providers\Properties\CustomValueProperties.cs" />
<Compile Include="Navigation\NavigationQueryProvider.cs" /> <Compile Include="Navigation\NavigationQueryProvider.cs" />
<Compile Include="Services\IProjectionManagerExtension.cs" />
<Compile Include="Shapes.cs" /> <Compile Include="Shapes.cs" />
<Compile Include="Descriptors\Layout\LayoutComponentResult.cs" /> <Compile Include="Descriptors\Layout\LayoutComponentResult.cs" />
<Compile Include="Descriptors\Layout\LayoutContext.cs" /> <Compile Include="Descriptors\Layout\LayoutContext.cs" />

View File

@@ -0,0 +1,16 @@
using System.Collections.Generic;
using Orchard.ContentManagement;
using Orchard.Projections.Descriptors;
using Orchard.Projections.Descriptors.Property;
using Orchard.Projections.Descriptors.Filter;
using Orchard.Projections.Descriptors.Layout;
using Orchard.Projections.Descriptors.SortCriterion;
namespace Orchard.Projections.Services {
public interface IProjectionManagerExtension : IProjectionManager {
IEnumerable<ContentItem> GetContentItems(int queryId, ContentPart part, int skip = 0, int count = 0);
int GetCount(int queryId, ContentPart part);
}
}

View File

@@ -14,7 +14,7 @@ using Orchard.Projections.Models;
using Orchard.Tokens; using Orchard.Tokens;
namespace Orchard.Projections.Services { namespace Orchard.Projections.Services {
public class ProjectionManager : IProjectionManager{ public class ProjectionManager : IProjectionManagerExtension {
private readonly ITokenizer _tokenizer; private readonly ITokenizer _tokenizer;
private readonly IEnumerable<IFilterProvider> _filterProviders; private readonly IEnumerable<IFilterProvider> _filterProviders;
private readonly IEnumerable<ISortCriterionProvider> _sortCriterionProviders; private readonly IEnumerable<ISortCriterionProvider> _sortCriterionProviders;
@@ -104,6 +104,33 @@ namespace Orchard.Projections.Services {
} }
public int GetCount(int queryId) { public int GetCount(int queryId) {
return GetCount(queryId, null);
}
public int GetCount(int queryId, ContentPart part) {
var queryRecord = _queryRepository.Get(queryId);
if (queryRecord == null) {
throw new ArgumentException("queryId");
}
// prepares tokens
Dictionary<string, object> tokens = new Dictionary<string, object>();
if (part != null) {
tokens.Add("Content", part.ContentItem);
}
// aggregate the result for each group query
return GetContentQueries(queryRecord, Enumerable.Empty<SortCriterionRecord>(), tokens)
.Sum(contentQuery => contentQuery.Count());
}
public IEnumerable<ContentItem> GetContentItems(int queryId, int skip = 0, int count = 0) {
return GetContentItems(queryId, null, skip, count);
}
public IEnumerable<ContentItem> GetContentItems(int queryId, ContentPart part, int skip = 0, int count = 0) {
var availableSortCriteria = DescribeSortCriteria().ToList();
var queryRecord = _queryRepository.Get(queryId); var queryRecord = _queryRepository.Get(queryId);
@@ -111,36 +138,27 @@ namespace Orchard.Projections.Services {
throw new ArgumentException("queryId"); throw new ArgumentException("queryId");
} }
// aggregate the result for each group query
return GetContentQueries(queryRecord, Enumerable.Empty<SortCriterionRecord>())
.Sum(contentQuery => contentQuery.Count());
}
public IEnumerable<ContentItem> GetContentItems(int queryId, int skip = 0, int count = 0) {
var availableSortCriteria = DescribeSortCriteria().ToList();
var queryRecord = _queryRepository.Get(queryId);
if(queryRecord == null) {
throw new ArgumentException("queryId");
}
var contentItems = new List<ContentItem>(); var contentItems = new List<ContentItem>();
// prepares tokens
Dictionary<string, object> tokens = new Dictionary<string, object>();
if (part != null) {
tokens.Add("Content", part.ContentItem);
}
// aggregate the result for each group query // aggregate the result for each group query
foreach(var contentQuery in GetContentQueries(queryRecord, queryRecord.SortCriteria.OrderBy(sc => sc.Position))) { foreach (var contentQuery in GetContentQueries(queryRecord, queryRecord.SortCriteria.OrderBy(sc => sc.Position), tokens)) {
contentItems.AddRange(contentQuery.Slice(skip, count)); contentItems.AddRange(contentQuery.Slice(skip, count));
} }
if(queryRecord.FilterGroups.Count <= 1) { if (queryRecord.FilterGroups.Count <= 1) {
return contentItems; return contentItems;
} }
// re-executing the sorting with the cumulated groups // re-executing the sorting with the cumulated groups
var ids = contentItems.Select(c => c.Id).ToArray(); var ids = contentItems.Select(c => c.Id).ToArray();
if(ids.Length == 0) { if (ids.Length == 0) {
return Enumerable.Empty<ContentItem>(); return Enumerable.Empty<ContentItem>();
} }
@@ -173,9 +191,13 @@ namespace Orchard.Projections.Services {
return groupQuery.Slice(skip, count); return groupQuery.Slice(skip, count);
} }
public IEnumerable<IHqlQuery> GetContentQueries(QueryPartRecord queryRecord, IEnumerable<SortCriterionRecord> sortCriteria) { public IEnumerable<IHqlQuery> GetContentQueries(QueryPartRecord queryRecord, IEnumerable<SortCriterionRecord> sortCriteria, Dictionary<string, object> tokens) {
var availableFilters = DescribeFilters().ToList(); var availableFilters = DescribeFilters().ToList();
var availableSortCriteria = DescribeSortCriteria().ToList(); var availableSortCriteria = DescribeSortCriteria().ToList();
if (tokens == null) {
tokens = new Dictionary<string, object>();
}
// pre-executing all groups // pre-executing all groups
foreach (var group in queryRecord.FilterGroups) { foreach (var group in queryRecord.FilterGroups) {
@@ -184,7 +206,7 @@ namespace Orchard.Projections.Services {
// iterate over each filter to apply the alterations to the query object // iterate over each filter to apply the alterations to the query object
foreach (var filter in group.Filters) { foreach (var filter in group.Filters) {
var tokenizedState = _tokenizer.Replace(filter.State, new Dictionary<string, object>()); var tokenizedState = _tokenizer.Replace(filter.State, tokens);
var filterContext = new FilterContext { var filterContext = new FilterContext {
Query = contentQuery, Query = contentQuery,
State = FormParametersHelper.ToDynamic(tokenizedState) State = FormParametersHelper.ToDynamic(tokenizedState)
@@ -237,7 +259,7 @@ namespace Orchard.Projections.Services {
yield return contentQuery; yield return contentQuery;
} }
} }
} }
} }