Adds GetPagedDescendants to media/content services. Fixes PDF reader disposal. Updates the umb examine indexers to use the services layer, now reindexing is far more efficient. Fixes the examine mgmt dashboard with $timeout. Updates GetPagedResultsByQuery to be more readable. Fixes GetPagedResultsByQuery to use SQL parameters.

This commit is contained in:
Shannon
2014-09-30 15:13:10 +10:00
parent c49560f39d
commit 4c0f95a93a
18 changed files with 466 additions and 80 deletions

View File

@@ -4,6 +4,7 @@ using System.Data;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Dynamics;
@@ -617,16 +618,26 @@ namespace Umbraco.Core.Persistence.Repositories
public IEnumerable<IContent> GetPagedResultsByQuery(IQuery<IContent> query, int pageIndex, int pageSize, out int totalRecords,
string orderBy, Direction orderDirection, string filter = "")
{
//NOTE: This uses the GetBaseQuery method but that does not take into account the required 'newest' field which is
// what we always require for a paged result, so we'll ensure it's included in the filter
var args = new List<object>();
var sbWhere = new StringBuilder("AND (cmsDocument.newest = 1)");
if (filter.IsNullOrWhiteSpace() == false)
{
sbWhere.Append(" AND (cmsDocument." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + " LIKE @" + args.Count + ")");
args.Add("%" + filter + "%");
}
Func<Tuple<string, object[]>> filterCallback = () => new Tuple<string, object[]>(sbWhere.ToString(), args.ToArray());
return GetPagedResultsByQuery<DocumentDto, Content>(query, pageIndex, pageSize, out totalRecords,
"SELECT cmsDocument.nodeId",
ProcessQuery, orderBy, orderDirection,
filter.IsNullOrWhiteSpace()
//NOTE: This uses the GetBaseQuery method but that does not take into account the required 'newest' field which is
// what we always require for a paged result, so we'll ensure it's included in the filter
? new Func<string>(() => "AND (cmsDocument.newest = 1)")
: new Func<string>(() => "AND (cmsDocument.newest = 1) AND (cmsDocument." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + " LIKE '%" + filter + "%')"));
filterCallback);
}

View File

@@ -79,7 +79,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IContent> GetPagedResultsByQuery(IQuery<IContent> query, int pageIndex, int pageSize, out int totalRecords,
IEnumerable<IContent> GetPagedResultsByQuery(IQuery<IContent> query, int pageIndex, int pageSize, out int totalRecords,
string orderBy, Direction orderDirection, string filter = "");
}
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Dynamics;
@@ -376,12 +377,20 @@ namespace Umbraco.Core.Persistence.Repositories
public IEnumerable<IMedia> GetPagedResultsByQuery(IQuery<IMedia> query, int pageIndex, int pageSize, out int totalRecords,
string orderBy, Direction orderDirection, string filter = "")
{
var args = new List<object>();
var sbWhere = new StringBuilder();
Func<Tuple<string, object[]>> filterCallback = null;
if (filter.IsNullOrWhiteSpace() == false)
{
sbWhere.Append("AND (umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + " LIKE @" + args.Count + ")");
args.Add("%" + filter + "%");
filterCallback = () => new Tuple<string, object[]>(sbWhere.ToString().Trim(), args.ToArray());
}
return GetPagedResultsByQuery<ContentVersionDto, Models.Media>(query, pageIndex, pageSize, out totalRecords,
"SELECT cmsContentVersion.contentId",
ProcessQuery, orderBy, orderDirection,
filter.IsNullOrWhiteSpace()
? (Func<string>)null
: () => "AND (umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + " LIKE '%" + filter + "%')");
filterCallback);
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
@@ -571,13 +572,21 @@ namespace Umbraco.Core.Persistence.Repositories
public IEnumerable<IMember> GetPagedResultsByQuery(IQuery<IMember> query, int pageIndex, int pageSize, out int totalRecords,
string orderBy, Direction orderDirection, string filter = "")
{
var args = new List<object>();
var sbWhere = new StringBuilder();
Func<Tuple<string, object[]>> filterCallback = null;
if (filter.IsNullOrWhiteSpace() == false)
{
sbWhere.Append("AND ((umbracoNode. " + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + " LIKE @" + args.Count + ") " +
"OR (cmsMember.LoginName LIKE @0" + args.Count + "))");
args.Add("%" + filter + "%");
filterCallback = () => new Tuple<string, object[]>(sbWhere.ToString().Trim(), args.ToArray());
}
return GetPagedResultsByQuery<MemberDto, Member>(query, pageIndex, pageSize, out totalRecords,
"SELECT cmsMember.nodeId",
ProcessQuery, orderBy, orderDirection,
filter.IsNullOrWhiteSpace()
? (Func<string>) null
: () => "AND ((umbracoNode. " + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + " LIKE '%" + filter + "%') " +
"OR (cmsMember.LoginName LIKE '%" + filter + "%'))");
filterCallback);
}
public void AddOrUpdateContentXml(IMember content, Func<IMember, XElement> xml)

View File

@@ -246,7 +246,7 @@ namespace Umbraco.Core.Persistence.Repositories
Func<Sql, IEnumerable<TEntity>> processQuery,
string orderBy,
Direction orderDirection,
Func<string> defaultFilter = null)
Func<Tuple<string, object[]>> defaultFilter = null)
where TContentBase : class, IAggregateRoot, TEntity
{
if (orderBy == null) throw new ArgumentNullException("orderBy");
@@ -265,7 +265,8 @@ namespace Umbraco.Core.Persistence.Repositories
// Apply filter
if (defaultFilter != null)
{
filteredSql.Append(defaultFilter());
var filterResult = defaultFilter();
filteredSql.Append(filterResult.Item1, filterResult.Item2);
}
if (string.IsNullOrEmpty(additionalFilter) == false)
{

View File

@@ -414,6 +414,7 @@ namespace Umbraco.Core.Services
return repository.GetByVersion(versionId);
}
}
/// <summary>
/// Gets a collection of an <see cref="IContent"/> objects versions by Id
@@ -491,7 +492,43 @@ namespace Umbraco.Core.Services
Mandate.ParameterCondition(pageSize > 0, "pageSize");
using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
{
var query = Query<IContent>.Builder.Where(x => x.ParentId == id);
var query = Query<IContent>.Builder;
//if the id is -1, then just get all
if (id > 0)
{
query.Where(x => x.ParentId == id);
}
var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, filter);
return contents;
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Descendants from</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalChildren">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IContent> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "")
{
Mandate.ParameterCondition(pageIndex >= 0, "pageSize");
Mandate.ParameterCondition(pageSize > 0, "pageSize");
using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
{
var query = Query<IContent>.Builder;
//if the id is -1, then just get all
if (id > 0)
{
query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar));
}
var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, filter);
return contents;

View File

@@ -121,7 +121,21 @@ namespace Umbraco.Core.Services
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IContent> GetPagedChildren(int id, int pageIndex, int pageSize, out int totalRecords,
string orderBy, Direction orderDirection, string filter = "");
string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "");
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Descendants from</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IContent> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalRecords,
string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "");
/// <summary>
/// Gets a collection of an <see cref="IContent"/> objects versions by its Id

View File

@@ -74,7 +74,21 @@ namespace Umbraco.Core.Services
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IMedia> GetPagedChildren(int id, int pageIndex, int pageSize, out int totalRecords,
string orderBy, Direction orderDirection, string filter = "");
string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "");
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Descendants from</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IMedia> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalRecords,
string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "");
/// <summary>
/// Gets descendants of a <see cref="IMedia"/> object by its Id

View File

@@ -408,13 +408,48 @@ namespace Umbraco.Core.Services
Mandate.ParameterCondition(pageSize > 0, "pageSize");
using (var repository = _repositoryFactory.CreateMediaRepository(_uowProvider.GetUnitOfWork()))
{
var query = Query<IMedia>.Builder.Where(x => x.ParentId == id);
var query = Query<IMedia>.Builder;
//if the id is -1, then just get all
if (id > 0)
{
query.Where(x => x.ParentId == id);
}
var medias = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, filter);
return medias;
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Descendants from</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalChildren">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IMedia> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "")
{
Mandate.ParameterCondition(pageIndex >= 0, "pageSize");
Mandate.ParameterCondition(pageSize > 0, "pageSize");
using (var repository = _repositoryFactory.CreateMediaRepository(_uowProvider.GetUnitOfWork()))
{
var query = Query<IMedia>.Builder;
//if the id is -1, then just get all
if (id > 0)
{
query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar));
}
var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, filter);
return contents;
}
}
/// <summary>
/// Gets descendants of a <see cref="IMedia"/> object by its Id
/// </summary>

View File

@@ -13,6 +13,20 @@ namespace Umbraco.Tests.Persistence.Querying
[TestFixture]
public class ExpressionTests : BaseUsingSqlCeSyntax
{
// [Test]
// public void Can_Query_With_Content_Type_Alias()
// {
// //Arrange
// Expression<Func<IMedia, bool>> predicate = content => content.ContentType.Alias == "Test";
// var modelToSqlExpressionHelper = new ModelToSqlExpressionHelper<IContent>();
// var result = modelToSqlExpressionHelper.Visit(predicate);
// Console.WriteLine("Model to Sql ExpressionHelper: \n" + result);
// Assert.AreEqual("[cmsContentType].[alias] = @0", result);
// Assert.AreEqual("Test", modelToSqlExpressionHelper.GetSqlParameters()[0]);
// }
[Test]
public void Can_Verify_Path_StartsWith_Predicate_In_Same_Result()
{

View File

@@ -1,14 +1,19 @@
using System;
using System.Linq;
using System.Net.Mime;
using Examine;
using Examine.LuceneEngine.Config;
using Examine.LuceneEngine.Providers;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Moq;
using Umbraco.Core.Services;
using UmbracoExamine;
using UmbracoExamine.Config;
using UmbracoExamine.DataServices;
using UmbracoExamine.PDF;
using IContentService = UmbracoExamine.DataServices.IContentService;
using IMediaService = UmbracoExamine.DataServices.IMediaService;
namespace Umbraco.Tests.UmbracoExamine
{
@@ -20,12 +25,37 @@ namespace Umbraco.Tests.UmbracoExamine
public static UmbracoContentIndexer GetUmbracoIndexer(
Lucene.Net.Store.Directory luceneDir,
Analyzer analyzer = null,
IDataService dataService = null)
IDataService dataService = null,
Umbraco.Core.Services.IContentService contentService = null,
Umbraco.Core.Services.IMediaService mediaService = null,
IDataTypeService dataTypeService = null,
IContentTypeService contentTypeService = null,
IMemberService memberService = null)
{
if (dataService == null)
{
dataService = new TestDataService();
}
if (contentService == null)
{
contentService = Mock.Of<Umbraco.Core.Services.IContentService>();
}
if (mediaService == null)
{
mediaService = Mock.Of<Umbraco.Core.Services.IMediaService>();
}
if (dataTypeService == null)
{
dataTypeService = Mock.Of<IDataTypeService>();
}
if (contentTypeService == null)
{
contentTypeService = Mock.Of<IContentTypeService>();
}
if (memberService == null)
{
memberService = Mock.Of<IMemberService>();
}
if (analyzer == null)
{
@@ -38,6 +68,10 @@ namespace Umbraco.Tests.UmbracoExamine
var i = new UmbracoContentIndexer(indexCriteria,
luceneDir, //custom lucene directory
dataService,
contentService,
mediaService,
dataTypeService,
contentTypeService,
analyzer,
false);

View File

@@ -1,4 +1,4 @@
function examineMgmtController($scope, umbRequestHelper, $log, $http, $q) {
function examineMgmtController($scope, umbRequestHelper, $log, $http, $q, $timeout) {
$scope.indexerDetails = [];
$scope.searcherDetails = [];
@@ -19,7 +19,7 @@ function examineMgmtController($scope, umbRequestHelper, $log, $http, $q) {
indexer.isProcessing = false;
}
else {
setTimeout(function() {
$timeout(function () {
//don't continue if we've tried 100 times
if (indexer.processingAttempts < 100) {
checkProcessing(indexer, checkActionName);
@@ -76,7 +76,7 @@ function examineMgmtController($scope, umbRequestHelper, $log, $http, $q) {
//rebuilding has started, nothing is returned accept a 200 status code.
//lets poll to see if it is done.
setTimeout(function () {
$timeout(function () {
checkProcessing(indexer, "PostCheckRebuildIndex");
}, 1000);
@@ -97,7 +97,7 @@ function examineMgmtController($scope, umbRequestHelper, $log, $http, $q) {
//optimizing has started, nothing is returned accept a 200 status code.
//lets poll to see if it is done.
setTimeout(function () {
$timeout(function () {
checkProcessing(indexer, "PostCheckOptimizeIndex");
}, 1000);

View File

@@ -232,17 +232,19 @@ namespace UmbracoExamine.PDF
try
{
var reader = new PdfReader(pdfPath);
for (int i = 1; i <= reader.NumberOfPages; i++)
using (var reader = new PdfReader(pdfPath))
{
var result =
ExceptChars(
PdfTextExtractor.GetTextFromPage(reader, i, new SimpleTextExtractionStrategy()),
UnsupportedRange,
ReplaceWithSpace);
output.Write(result);
for (int i = 1; i <= reader.NumberOfPages; i++)
{
var result =
ExceptChars(
PdfTextExtractor.GetTextFromPage(reader, i, new SimpleTextExtractionStrategy()),
UnsupportedRange,
ReplaceWithSpace);
output.Write(result);
}
}
}
catch (Exception ex)
{

View File

@@ -264,8 +264,8 @@ namespace UmbracoExamine
/// <param name="type"></param>
protected override void PerformIndexAll(string type)
{
//TODO: Fix all of this up, the whole xpath thing is horrible and was made sooooooooo long ago to only work with published content
// but not it's being used for all content types and is really bad for performance.
//NOTE: the logic below is ONLY used for published content, for media and members and non-published content, this method is overridden
// and we query directly against the umbraco service layer.
if (!SupportedTypes.Contains(type))
return;
@@ -275,7 +275,7 @@ namespace UmbracoExamine
var sb = new StringBuilder();
//create the xpath statement to match node type aliases if specified
if (IndexerData.IncludeNodeTypes.Count() > 0)
if (IndexerData.IncludeNodeTypes.Any())
{
sb.Append("(");
foreach (var field in IndexerData.IncludeNodeTypes)
@@ -328,6 +328,9 @@ namespace UmbracoExamine
/// <returns>Either the Content or Media xml. If the type is not of those specified null is returned</returns>
protected virtual XDocument GetXDocument(string xPath, string type)
{
//TODO: We need to get rid of this! it will now only ever be called for published content - but we're keeping the other
// logic here for backwards compatibility in case inheritors are calling this for some reason.
if (type == IndexTypes.Content)
{
if (this.SupportUnpublishedContent)

View File

@@ -7,7 +7,9 @@ namespace UmbracoExamine.DataServices
{
public interface IContentService
{
[Obsolete("This should no longer be used, latest content will be indexed by using the IContentService directly")]
XDocument GetLatestContentByXPath(string xpath);
XDocument GetPublishedContentByXPath(string xpath);
/// <summary>

View File

@@ -2,8 +2,10 @@
using System.Xml.Linq;
namespace UmbracoExamine.DataServices
{
[Obsolete("This should no longer be used, latest content will be indexed by using the IMediaService directly")]
public interface IMediaService
{
[Obsolete("This should no longer be used, latest content will be indexed by using the IMediaService directly")]
XDocument GetLatestMediaByXpath(string xpath);
}
}

View File

@@ -14,6 +14,9 @@ using Examine.Providers;
using Lucene.Net.Documents;
using Umbraco.Core;
using umbraco.cms.businesslogic;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Services;
using UmbracoExamine.DataServices;
using Examine.LuceneEngine;
using Examine.LuceneEngine.Config;
@@ -21,6 +24,8 @@ using UmbracoExamine.Config;
using Examine.LuceneEngine.Providers;
using Lucene.Net.Analysis;
using umbraco.BasePages;
using IContentService = Umbraco.Core.Services.IContentService;
using IMediaService = Umbraco.Core.Services.IMediaService;
namespace UmbracoExamine
@@ -30,13 +35,24 @@ namespace UmbracoExamine
/// </summary>
public class UmbracoContentIndexer : BaseUmbracoIndexer
{
private readonly IContentTypeService _contentTypeService;
private readonly IContentService _contentService;
private readonly IMediaService _mediaService;
private readonly IDataTypeService _dataTypeService;
#region Constructors
/// <summary>
/// Default constructor
/// </summary>
public UmbracoContentIndexer()
: base() { }
: base()
{
_contentService = ApplicationContext.Current.Services.ContentService;
_mediaService = ApplicationContext.Current.Services.MediaService;
_dataTypeService = ApplicationContext.Current.Services.DataTypeService;
_contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
}
/// <summary>
/// Constructor to allow for creating an indexer at runtime
@@ -45,21 +61,60 @@ namespace UmbracoExamine
/// <param name="indexPath"></param>
/// <param name="dataService"></param>
/// <param name="analyzer"></param>
public UmbracoContentIndexer(IIndexCriteria indexerData, DirectoryInfo indexPath, IDataService dataService, Analyzer analyzer, bool async)
: base(indexerData, indexPath, dataService, analyzer, async) { }
/// <param name="async"></param>
[Obsolete("Use the overload that specifies the Umbraco services")]
public UmbracoContentIndexer(IIndexCriteria indexerData, DirectoryInfo indexPath, IDataService dataService, Analyzer analyzer, bool async)
: base(indexerData, indexPath, dataService, analyzer, async)
{
_contentService = ApplicationContext.Current.Services.ContentService;
_mediaService = ApplicationContext.Current.Services.MediaService;
_dataTypeService = ApplicationContext.Current.Services.DataTypeService;
_contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
}
/// <summary>
/// Constructor to allow for creating an indexer at runtime
/// </summary>
/// <param name="indexerData"></param>
/// <param name="luceneDirectory"></param>
/// <param name="dataService"></param>
/// <param name="analyzer"></param>
/// <param name="async"></param>
public UmbracoContentIndexer(IIndexCriteria indexerData, Lucene.Net.Store.Directory luceneDirectory, IDataService dataService, Analyzer analyzer, bool async)
: base(indexerData, luceneDirectory, dataService, analyzer, async) { }
/// <summary>
/// Constructor to allow for creating an indexer at runtime
/// </summary>
/// <param name="indexerData"></param>
/// <param name="luceneDirectory"></param>
/// <param name="dataService"></param>
/// <param name="analyzer"></param>
/// <param name="async"></param>
[Obsolete("Use the overload that specifies the Umbraco services")]
public UmbracoContentIndexer(IIndexCriteria indexerData, Lucene.Net.Store.Directory luceneDirectory, IDataService dataService, Analyzer analyzer, bool async)
: base(indexerData, luceneDirectory, dataService, analyzer, async)
{
_contentService = ApplicationContext.Current.Services.ContentService;
_mediaService = ApplicationContext.Current.Services.MediaService;
_dataTypeService = ApplicationContext.Current.Services.DataTypeService;
_contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
}
/// <summary>
/// Constructor to allow for creating an indexer at runtime
/// </summary>
/// <param name="indexerData"></param>
/// <param name="luceneDirectory"></param>
/// <param name="dataService"></param>
/// <param name="contentService"></param>
/// <param name="mediaService"></param>
/// <param name="dataTypeService"></param>
/// <param name="contentTypeService"></param>
/// <param name="analyzer"></param>
/// <param name="async"></param>
public UmbracoContentIndexer(IIndexCriteria indexerData, Lucene.Net.Store.Directory luceneDirectory, IDataService dataService,
IContentService contentService,
IMediaService mediaService,
IDataTypeService dataTypeService,
IContentTypeService contentTypeService,
Analyzer analyzer, bool async)
: base(indexerData, luceneDirectory, dataService, analyzer, async)
{
_contentService = contentService;
_mediaService = mediaService;
_dataTypeService = dataTypeService;
_contentTypeService = contentTypeService;
}
#endregion
@@ -124,10 +179,10 @@ namespace UmbracoExamine
/// <exception cref="T:System.InvalidOperationException">
/// An attempt is made to call <see cref="M:System.Configuration.Provider.ProviderBase.Initialize(System.String,System.Collections.Specialized.NameValueCollection)"/> on a provider after the provider has already been initialized.
/// </exception>
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
//check if there's a flag specifying to support unpublished content,
//if not, set to false;
bool supportUnpublished;
@@ -181,19 +236,19 @@ namespace UmbracoExamine
/// This ensures that the special __Raw_ fields are indexed
/// </summary>
/// <param name="docArgs"></param>
protected override void OnDocumentWriting(DocumentWritingEventArgs docArgs)
{
var d = docArgs.Document;
foreach (var f in docArgs.Fields.Where(x => x.Key.StartsWith(RawFieldPrefix)))
{
{
d.Add(new Field(
f.Key,
f.Value,
Field.Store.YES,
Field.Index.NO, //don't index this field, we never want to search by it
Field.TermVector.NO));
}
Field.TermVector.NO));
}
base.OnDocumentWriting(docArgs);
}
@@ -220,7 +275,7 @@ namespace UmbracoExamine
#region Public methods
/// <summary>
/// Overridden for logging
/// </summary>
@@ -233,14 +288,14 @@ namespace UmbracoExamine
if (node.Attribute("id") != null)
{
DataService.LogService.AddVerboseLog((int) node.Attribute("id"), string.Format("ReIndexNode with type: {0}", type));
DataService.LogService.AddVerboseLog((int)node.Attribute("id"), string.Format("ReIndexNode with type: {0}", type));
base.ReIndexNode(node, type);
}
else
{
DataService.LogService.AddErrorLog(-1, string.Format("ReIndexNode cannot proceed, the format of the XElement is invalid, the xml has no 'id' attribute. {0}", node));
}
}
/// <summary>
@@ -279,7 +334,107 @@ namespace UmbracoExamine
#region Protected
protected override void PerformIndexAll(string type)
{
const int pageSize = 5000;
var pageIndex = 0;
switch (type)
{
case IndexTypes.Content:
if (this.SupportUnpublishedContent == false)
{
//use the base implementation which will use the published XML cache to perform the lookups
base.PerformIndexAll(type);
}
else
{
var contentParentId = -1;
if (IndexerData.ParentNodeId.HasValue && IndexerData.ParentNodeId.Value > 0)
{
contentParentId = IndexerData.ParentNodeId.Value;
}
IContent[] content;
do
{
int total;
var descendants = _contentService.GetPagedDescendants(contentParentId, pageIndex, pageSize, out total);
//if specific types are declared we need to post filter them
//TODO: Update the service layer to join the cmsContentType table so we can query by content type too
if (IndexerData.IncludeNodeTypes.Any())
{
content = descendants.Where(x => IndexerData.IncludeNodeTypes.Contains(x.ContentType.Alias)).ToArray();
}
else
{
content = descendants.ToArray();
}
AddNodesToIndex(GetSerializedContent(content), type);
pageIndex++;
} while (content.Length == pageSize);
}
break;
case IndexTypes.Media:
var mediaParentId = -1;
if (IndexerData.ParentNodeId.HasValue && IndexerData.ParentNodeId.Value > 0)
{
mediaParentId = IndexerData.ParentNodeId.Value;
}
IMedia[] media;
do
{
int total;
var descendants = _mediaService.GetPagedDescendants(mediaParentId, pageIndex, pageSize, out total);
//if specific types are declared we need to post filter them
//TODO: Update the service layer to join the cmsContentType table so we can query by content type too
if (IndexerData.IncludeNodeTypes.Any())
{
media = descendants.Where(x => IndexerData.IncludeNodeTypes.Contains(x.ContentType.Alias)).ToArray();
}
else
{
media = descendants.ToArray();
}
AddNodesToIndex(GetSerializedMedia(media), type);
pageIndex++;
} while (media.Length == pageSize);
break;
}
}
private IEnumerable<XElement> GetSerializedMedia(IEnumerable<IMedia> media)
{
var serializer = new EntityXmlSerializer();
foreach (var m in media)
{
yield return serializer.Serialize(
_mediaService,
_dataTypeService,
m);
}
}
private IEnumerable<XElement> GetSerializedContent(IEnumerable<IContent> content)
{
var serializer = new EntityXmlSerializer();
foreach (var c in content)
{
yield return serializer.Serialize(
_contentService,
_dataTypeService,
c);
}
}
/// <summary>
/// Overridden for logging.
@@ -316,7 +471,7 @@ namespace UmbracoExamine
/// ensure our special Path field is added to the collection
/// </summary>
/// <param name="e"></param>
protected override void OnGatheringNodeData(IndexingNodeDataEventArgs e)
{
//strip html of all users fields if we detect it has HTML in it.
@@ -333,7 +488,7 @@ namespace UmbracoExamine
//First save the raw value to a raw field, we will change the policy of this field by detecting the prefix later
e.Fields[RawFieldPrefix + field.Name] = e.Fields[field.Name];
//now replace the original value with the stripped html
e.Fields[field.Name] = DataService.ContentService.StripHtml(e.Fields[field.Name]);
e.Fields[field.Name] = DataService.ContentService.StripHtml(e.Fields[field.Name]);
}
}
}
@@ -401,7 +556,7 @@ namespace UmbracoExamine
{
return base.GetIndexerData(indexSet);
}
}
/// <summary>

View File

@@ -7,6 +7,7 @@ using System.Xml.XPath;
using Examine.LuceneEngine.Config;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Services;
using UmbracoExamine.Config;
using Examine.LuceneEngine;
@@ -25,22 +26,49 @@ namespace UmbracoExamine
public class UmbracoMemberIndexer : UmbracoContentIndexer
{
private readonly IMemberService _memberService;
private readonly IDataTypeService _dataTypeService;
/// <summary>
/// Default constructor
/// </summary>
public UmbracoMemberIndexer()
: base() { }
/// <summary>
/// Constructor to allow for creating an indexer at runtime
/// </summary>
/// <param name="indexerData"></param>
/// <param name="indexPath"></param>
/// <param name="dataService"></param>
/// <param name="analyzer"></param>
[Obsolete("Use the overload that specifies the Umbraco services")]
public UmbracoMemberIndexer(IIndexCriteria indexerData, DirectoryInfo indexPath, IDataService dataService, Analyzer analyzer, bool async)
: base(indexerData, indexPath, dataService, analyzer, async)
{
_dataTypeService = ApplicationContext.Current.Services.DataTypeService;
_memberService = ApplicationContext.Current.Services.MemberService;
}
/// <summary>
/// Constructor to allow for creating an indexer at runtime
/// </summary>
/// <param name="indexerData"></param>
/// <param name="indexPath"></param>
/// <param name="dataService"></param>
/// <param name="dataTypeService"></param>
/// <param name="memberService"></param>
/// <param name="analyzer"></param>
public UmbracoMemberIndexer(IIndexCriteria indexerData, DirectoryInfo indexPath, IDataService dataService, Analyzer analyzer, bool async)
: base(indexerData, indexPath, dataService, analyzer, async) { }
/// <param name="async"></param>
public UmbracoMemberIndexer(IIndexCriteria indexerData, DirectoryInfo indexPath, IDataService dataService,
IDataTypeService dataTypeService,
IMemberService memberService,
Analyzer analyzer, bool async)
: base(indexerData, indexPath, dataService, analyzer, async)
{
_dataTypeService = dataTypeService;
_memberService = memberService;
}
/// <summary>
/// Ensures that the'_searchEmail' is added to the user fields so that it is indexed - without having to modify the config
@@ -83,23 +111,39 @@ namespace UmbracoExamine
protected override void PerformIndexAll(string type)
{
//This only supports members
if (!SupportedTypes.Contains(type))
if (SupportedTypes.Contains(type) == false)
return;
//Re-index all members in batches of 5000
IEnumerable<IMember> members;
IMember[] members;
const int pageSize = 5000;
var pageIndex = 0;
do
{
int total;
members = ApplicationContext.Current.Services.MemberService.GetAll(pageIndex, pageSize, out total);
AddNodesToIndex(GetSerializedMembers(members), type);
pageIndex++;
} while (members.Count() == pageSize);
if (IndexerData.IncludeNodeTypes.Any())
{
//if there are specific node types then just index those
foreach (var nodeType in IndexerData.IncludeNodeTypes)
{
do
{
int total;
members = _memberService.GetAll(pageIndex, pageSize, out total, "LoginName", Direction.Ascending, nodeType).ToArray();
AddNodesToIndex(GetSerializedMembers(members), type);
pageIndex++;
} while (members.Length == pageSize);
}
}
else
{
//no node types specified, do all members
do
{
int total;
members = _memberService.GetAll(pageIndex, pageSize, out total).ToArray();
AddNodesToIndex(GetSerializedMembers(members), type);
pageIndex++;
} while (members.Length == pageSize);
}
}
private IEnumerable<XElement> GetSerializedMembers(IEnumerable<IMember> members)
@@ -107,7 +151,7 @@ namespace UmbracoExamine
var serializer = new EntityXmlSerializer();
foreach (var member in members)
{
yield return serializer.Serialize(ApplicationContext.Current.Services.DataTypeService, member);
yield return serializer.Serialize(_dataTypeService, member);
}
}