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:
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = "");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user