Implements U4-943 to the extent its currently possible.

Refactoring publishing methods in the ContentService.
Adding tests for the QueryBuilder.
This commit is contained in:
sitereactor
2012-10-29 14:28:16 -01:00
parent c20072c01d
commit 0c4c429b68
20 changed files with 490 additions and 128 deletions

View File

@@ -0,0 +1,32 @@
using Umbraco.Core.Models;
namespace Umbraco.Core
{
//Publishing Events
public class PublishEventArgs : System.ComponentModel.CancelEventArgs { }
public class UnPublishEventArgs : System.ComponentModel.CancelEventArgs { }
public class SendToPublishEventArgs : System.ComponentModel.CancelEventArgs { }
//Moving Content Events
public class MoveEventArgs : System.ComponentModel.CancelEventArgs { }
public class MoveToTrashEventArgs : System.ComponentModel.CancelEventArgs { }
//Copying Content Events
public class CopyEventArgs : System.ComponentModel.CancelEventArgs
{
public int CopyTo { get; set; }
public IContent NewContent { get; set; }
}
//Rollback Content Event
public class RollbackEventArgs : System.ComponentModel.CancelEventArgs { }
//Content Cache Event args
public class ContentCacheEventArgs : System.ComponentModel.CancelEventArgs { }
public class RefreshContentEventArgs : System.ComponentModel.CancelEventArgs { }
//Generel eventArgs
public class DeleteEventArgs : System.ComponentModel.CancelEventArgs { }
public class SaveEventArgs : System.ComponentModel.CancelEventArgs { }
public class NewEventArgs : System.ComponentModel.CancelEventArgs { }
}

View File

@@ -225,7 +225,7 @@ namespace Umbraco.Core.Models
/// Changes the Published state of the content object
/// </summary>
/// <param name="isPublished">Boolean indicating whether content is published (true) or unpublished (false)</param>
internal void ChangePublishedState(bool isPublished)
public void ChangePublishedState(bool isPublished)
{
Published = isPublished;
//NOTE Should this be checked against the Expire/Release dates?
@@ -237,7 +237,7 @@ namespace Umbraco.Core.Models
/// </summary>
/// <param name="isTrashed">Boolean indicating whether content is trashed (true) or not trashed (false)</param>
/// <param name="parentId"> </param>
internal void ChangeTrashedState(bool isTrashed, int parentId = -1)
public void ChangeTrashedState(bool isTrashed, int parentId = -1)
{
Trashed = isTrashed;

View File

@@ -136,7 +136,7 @@ namespace Umbraco.Core.Models.EntityBase
/// <summary>
/// Resets dirty properties by clearing the dictionary used to track changes.
/// </summary>
internal void ResetDirtyProperties()
public void ResetDirtyProperties()
{
_propertyChangedInfo.Clear();
}

View File

@@ -7,5 +7,6 @@
{
bool IsDirty();
bool IsPropertyDirty(string propName);
void ResetDirtyProperties();
}
}

View File

@@ -52,5 +52,18 @@ namespace Umbraco.Core.Models
/// <param name="contentType">New ContentType for this content</param>
/// <param name="clearProperties">Boolean indicating whether to clear PropertyTypes upon change</param>
void ChangeContentType(IContentType contentType, bool clearProperties);
/// <summary>
/// Changes the Published state of the content object
/// </summary>
/// <param name="isPublished">Boolean indicating whether content is published (true) or unpublished (false)</param>
void ChangePublishedState(bool isPublished);
/// <summary>
/// Changes the Trashed state of the content object
/// </summary>
/// <param name="isTrashed">Boolean indicating whether content is trashed (true) or not trashed (false)</param>
/// <param name="parentId"> </param>
void ChangeTrashedState(bool isTrashed, int parentId = -1);
}
}

View File

@@ -52,6 +52,9 @@ namespace Umbraco.Core.Persistence.Mappers
internal override string Map(string propertyName)
{
if (!PropertyInfoCache.ContainsKey(propertyName))
return string.Empty;
var dtoTypeProperty = PropertyInfoCache[propertyName];
return base.GetColumnName(dtoTypeProperty.Type, dtoTypeProperty.PropertyInfo);

View File

@@ -12,29 +12,29 @@ namespace Umbraco.Core.Persistence.Mappers
public void GetTableInfo(Type t, TableInfo ti)
{ }
public bool MapPropertyToColumn(PropertyInfo pi, ref string columnName, ref bool resultColumn)
public bool MapPropertyToColumn(Type t, PropertyInfo pi, ref string columnName, ref bool resultColumn)
{
if (pi.DeclaringType == typeof(Content) || pi.DeclaringType == typeof(IContent))
if (t == typeof(Content) || t == typeof(IContent))
{
var mappedName = ContentMapper.Instance.Map(pi.Name);
if (mappedName == string.Empty)
return false;
columnName = mappedName;
if (!string.IsNullOrEmpty(mappedName))
{
columnName = mappedName;
}
return true;
}
if (pi.DeclaringType == typeof(Models.Media) || pi.DeclaringType == typeof(IMedia))
if (t == typeof(Models.Media) || t == typeof(IMedia))
{
var mappedName = MediaMapper.Instance.Map(pi.Name);
if (mappedName == string.Empty)
return false;
columnName = mappedName;
if (!string.IsNullOrEmpty(mappedName))
{
columnName = mappedName;
}
return true;
}
if (pi.DeclaringType == typeof(ContentType) || pi.DeclaringType == typeof(IContentType) || pi.DeclaringType == typeof(IMediaType))
if (t == typeof(ContentType) || t == typeof(IContentType) || t == typeof(IMediaType))
{
var mappedName = ContentTypeMapper.Instance.Map(pi.Name);
if (!string.IsNullOrEmpty(mappedName))
@@ -44,47 +44,47 @@ namespace Umbraco.Core.Persistence.Mappers
return true;
}
if (pi.DeclaringType == typeof(DataTypeDefinition) || pi.DeclaringType == typeof(IDataTypeDefinition))
if (t == typeof(DataTypeDefinition) || t == typeof(IDataTypeDefinition))
{
var mappedName = DataTypeDefinitionMapper.Instance.Map(pi.Name);
if (mappedName == string.Empty)
return false;
columnName = mappedName;
if (!string.IsNullOrEmpty(mappedName))
{
columnName = mappedName;
}
return true;
}
if (pi.DeclaringType == typeof(DictionaryItem) || pi.DeclaringType == typeof(IDictionaryItem))
if (t == typeof(DictionaryItem) || t == typeof(IDictionaryItem))
{
var mappedName = DictionaryMapper.Instance.Map(pi.Name);
if (mappedName == string.Empty)
return false;
columnName = mappedName;
if (!string.IsNullOrEmpty(mappedName))
{
columnName = mappedName;
}
return true;
}
if (pi.DeclaringType == typeof(DictionaryTranslation) || pi.DeclaringType == typeof(IDictionaryTranslation))
if (t == typeof(DictionaryTranslation) || t == typeof(IDictionaryTranslation))
{
var mappedName = DictionaryTranslationMapper.Instance.Map(pi.Name);
if (mappedName == string.Empty)
return false;
columnName = mappedName;
if (!string.IsNullOrEmpty(mappedName))
{
columnName = mappedName;
}
return true;
}
if (pi.DeclaringType == typeof(Language) || pi.DeclaringType == typeof(ILanguage))
if (t == typeof(Language) || t == typeof(ILanguage))
{
var mappedName = LanguageMapper.Instance.Map(pi.Name);
if (mappedName == string.Empty)
return false;
columnName = mappedName;
if (!string.IsNullOrEmpty(mappedName))
{
columnName = mappedName;
}
return true;
}
if (pi.DeclaringType == typeof(Relation))
if (t == typeof(Relation))
{
var mappedName = RelationMapper.Instance.Map(pi.Name);
if (!string.IsNullOrEmpty(mappedName))
@@ -94,33 +94,33 @@ namespace Umbraco.Core.Persistence.Mappers
return true;
}
if (pi.DeclaringType == typeof(RelationType))
if (t == typeof(RelationType))
{
var mappedName = RelationTypeMapper.Instance.Map(pi.Name);
if (mappedName == string.Empty)
return false;
columnName = mappedName;
if (!string.IsNullOrEmpty(mappedName))
{
columnName = mappedName;
}
return true;
}
if (pi.DeclaringType == typeof(PropertyType))
if (t == typeof(PropertyType))
{
var mappedName = PropertyTypeMapper.Instance.Map(pi.Name);
if (mappedName == string.Empty)
return false;
columnName = mappedName;
if (!string.IsNullOrEmpty(mappedName))
{
columnName = mappedName;
}
return true;
}
if (pi.DeclaringType == typeof(PropertyGroup))
if (t == typeof(PropertyGroup))
{
var mappedName = PropertyGroupMapper.Instance.Map(pi.Name);
if (mappedName == string.Empty)
return false;
columnName = mappedName;
if (!string.IsNullOrEmpty(mappedName))
{
columnName = mappedName;
}
return true;
}

View File

@@ -118,7 +118,7 @@ namespace Umbraco.Core.Persistence
public interface IMapper
{
void GetTableInfo(Type t, TableInfo ti);
bool MapPropertyToColumn(PropertyInfo pi, ref string columnName, ref bool resultColumn);
bool MapPropertyToColumn(Type t, PropertyInfo pi, ref string columnName, ref bool resultColumn);
Func<object, object> GetFromDbConverter(PropertyInfo pi, Type SourceType);
Func<object, object> GetToDbConverter(Type SourceType);
}
@@ -1802,7 +1802,7 @@ namespace Umbraco.Core.Persistence
if (pc.ColumnName == null)
{
pc.ColumnName = pi.Name;
if (Database.Mapper != null && !Database.Mapper.MapPropertyToColumn(pi, ref pc.ColumnName, ref pc.ResultColumn))
if (Database.Mapper != null && !Database.Mapper.MapPropertyToColumn(t, pi, ref pc.ColumnName, ref pc.ResultColumn))
continue;
}

View File

@@ -265,7 +265,7 @@ namespace Umbraco.Core.Persistence.Querying
case "ToLower":
return string.Format("lower({0})", r);
case "StartsWith":
return string.Format("upper({0}) starting with {1} ", r, args[0].ToString().ToUpper());
return string.Format("upper({0}) like '{1}%'", r, RemoveQuote(args[0].ToString().ToUpper()));
case "EndsWith":
return string.Format("upper({0}) like '%{1}'", r, RemoveQuote(args[0].ToString()).ToUpper());
case "Contains":

View File

@@ -4,6 +4,10 @@ using System.Linq.Expressions;
namespace Umbraco.Core.Persistence.Querying
{
/// <summary>
/// Represents the Query Builder for building LINQ translatable queries
/// </summary>
/// <typeparam name="T"></typeparam>
public class Query<T> : IQuery<T>
{
private readonly ExpressionHelper<T> _expresionist = new ExpressionHelper<T>();
@@ -32,7 +36,7 @@ namespace Umbraco.Core.Persistence.Querying
}
return this;
}
public List<string> WhereClauses()
{
return _wheres;

View File

@@ -2,6 +2,10 @@
namespace Umbraco.Core.Persistence.Querying
{
/// <summary>
/// Represents the Sql Translator for translating a <see cref="IQuery"/> object to Sql
/// </summary>
/// <typeparam name="T"></typeparam>
public class SqlTranslator<T>
{
private readonly Sql _sql;

View File

@@ -70,6 +70,7 @@
<Compile Include="DictionaryExtensions.cs" />
<Compile Include="Dictionary\CultureDictionaryFactoryResolver.cs" />
<Compile Include="Dictionary\ICultureDictionaryFactory.cs" />
<Compile Include="EventArgs.cs" />
<Compile Include="Models\ContentBase.cs" />
<Compile Include="Models\ContentExtensions.cs" />
<Compile Include="Enum.cs" />

View File

@@ -0,0 +1,82 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Persistence.Querying
{
[TestFixture]
public class QueryBuilderTests : BaseUsingSqlCeSyntax
{
[Test]
public void Can_Build_StartsWith_Query_For_IContent()
{
// Arrange
var sql = new Sql();
sql.Select("*");
sql.From("umbracoNode");
var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith("-1"));
// Act
var translator = new SqlTranslator<IContent>(sql, query);
var result = translator.Translate();
var strResult = result.SQL;
string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE (upper([umbracoNode].[path]) like '-1%')";
// Assert
Assert.That(strResult, Is.Not.Empty);
Assert.That(strResult, Is.EqualTo(expectedResult));
Console.WriteLine(strResult);
}
[Test]
public void Can_Build_ParentId_Query_For_IContent()
{
// Arrange
var sql = new Sql();
sql.Select("*");
sql.From("umbracoNode");
var query = Query<IContent>.Builder.Where(x => x.ParentId == -1);
// Act
var translator = new SqlTranslator<IContent>(sql, query);
var result = translator.Translate();
var strResult = result.SQL;
string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE (([umbracoNode].[parentID]=-1))";
// Assert
Assert.That(strResult, Is.Not.Empty);
Assert.That(strResult, Is.EqualTo(expectedResult));
Console.WriteLine(strResult);
}
[Test]
public void Can_Build_ContentTypeAlias_Query_For_IContentType()
{
// Arrange
var sql = new Sql();
sql.Select("*");
sql.From("umbracoNode");
var query = Query<IContentType>.Builder.Where(x => x.Alias == "umbTextpage");
// Act
var translator = new SqlTranslator<IContentType>(sql, query);
var result = translator.Translate();
var strResult = result.SQL;
string expectedResult = "SELECT *\nFROM umbracoNode\nWHERE (([cmsContentType].[alias]='umbTextpage'))";
// Assert
Assert.That(strResult, Is.Not.Empty);
Assert.That(strResult, Is.EqualTo(expectedResult));
Console.WriteLine(strResult);
}
}
}

View File

@@ -0,0 +1,20 @@
using NUnit.Framework;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Tests.TestHelpers
{
[TestFixture]
public abstract class BaseUsingSqlCeSyntax
{
[SetUp]
public virtual void Initialize()
{
SyntaxConfig.SqlSyntaxProvider = SqlCeSyntaxProvider.Instance;
SetUp();
}
public virtual void SetUp()
{}
}
}

View File

@@ -109,6 +109,7 @@
<Compile Include="Persistence\Mappers\RelationTypeMapperTest.cs" />
<Compile Include="Persistence\MySqlDatabaseCreationTest.cs" />
<Compile Include="Persistence\MySqlTableByTableTest.cs" />
<Compile Include="Persistence\Querying\QueryBuilderTests.cs" />
<Compile Include="Persistence\RepositoryResolverTests.cs" />
<Compile Include="Persistence\SqlCeTableByTableTest.cs" />
<Compile Include="Persistence\SqlTableByTableTest.cs" />
@@ -144,6 +145,7 @@
<Compile Include="Routing\RenderRouteHandlerTests.cs" />
<Compile Include="Routing\RouteTestExtensions.cs" />
<Compile Include="Stubs\TestControllerFactory.cs" />
<Compile Include="TestHelpers\BaseUsingSqlCeSyntax.cs" />
<Compile Include="TestHelpers\BaseWebTest.cs" />
<Compile Include="TestHelpers\BaseDatabaseTest.cs" />
<Compile Include="TestHelpers\Entities\MockedContent.cs" />
@@ -261,6 +263,9 @@
<Content Include="Masterpages\dummy.txt" />
<Content Include="Views\dummy.txt" />
</ItemGroup>
<ItemGroup>
<Folder Include="Persistence\Repositories\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>xcopy "$(ProjectDir)"..\..\lib\SQLCE4\amd64\*.* "$(TargetDir)amd64\" /Y /F /E /D

View File

@@ -0,0 +1,87 @@
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core;
namespace Umbraco.Web.Publishing
{
public abstract class BasePublishingStrategy : IPublishingStrategy
{
public abstract bool Publish(IContent content, int userId);
public abstract bool PublishWithChildren(IEnumerable<IContent> children, int userId);
public abstract bool UnPublish(IContent content, int userId);
/// <summary>
/// The publish event handler
/// </summary>
public delegate void PublishEventHandler(IContent sender, PublishEventArgs e);
/// <summary>
/// The unpublish event handler
/// </summary>
public delegate void UnPublishEventHandler(IContent sender, UnPublishEventArgs e);
/// <summary>
/// Occurs before publish
/// </summary>
public static event PublishEventHandler BeforePublish;
/// <summary>
/// Raises the <see cref="E:BeforePublish"/> event
/// </summary>
/// <param name="content"> </param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void FireBeforePublish(IContent content, PublishEventArgs e)
{
if (BeforePublish != null)
BeforePublish(content, e);
}
/// <summary>
/// Occurs after publish
/// </summary>
public static event PublishEventHandler AfterPublish;
/// <summary>
/// Raises the <see cref="E:AfterPublish"/> event
/// </summary>
/// <param name="content"> </param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void FireAfterPublish(IContent content, PublishEventArgs e)
{
if (AfterPublish != null)
AfterPublish(content, e);
}
/// <summary>
/// Occurs before unpublish
/// </summary>
public static event UnPublishEventHandler BeforeUnPublish;
/// <summary>
/// Raises the <see cref="E:BeforeUnPublish"/> event
/// </summary>
/// <param name="content"> </param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void FireBeforeUnPublish(IContent content, UnPublishEventArgs e)
{
if (BeforeUnPublish != null)
BeforeUnPublish(content, e);
}
/// <summary>
/// Occurs after unpublish
/// </summary>
public static event UnPublishEventHandler AfterUnPublish;
/// <summary>
/// Raises the <see cref="E:AfterUnPublish"/> event
/// </summary>
/// <param name="content"> </param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected virtual void FireAfterUnPublish(IContent content, UnPublishEventArgs e)
{
if (AfterUnPublish != null)
AfterUnPublish(content, e);
}
}
}

View File

@@ -7,7 +7,6 @@ namespace Umbraco.Web.Publishing
{
bool Publish(IContent content, int userId);
bool PublishWithChildren(IEnumerable<IContent> children, int userId);
void PublishWithSubs(IContent content, int userId);
bool UnPublish(IContent content, int userId);
}
}

View File

@@ -1,67 +1,109 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.web;
namespace Umbraco.Web.Publishing
{
/// <summary>
/// Currently acts as an interconnection between the new public api and the legacy api for publishing
/// </summary>
internal class PublishingStrategy : IPublishingStrategy
internal class PublishingStrategy : BasePublishingStrategy
{
internal PublishingStrategy()
{
}
public bool Publish(IContent content, int userId)
/// <summary>
/// Publishes a single piece of content
/// </summary>
/// <param name="content"><see cref="IContent"/> to publish</param>
/// <param name="userId">Id of the user issueing the publish</param>
/// <returns>True if the content was published, otherwise false</returns>
public override bool Publish(IContent content, int userId)
{
//Fire BeforePublish event
/*PublishEventArgs e = new PublishEventArgs();
FireBeforePublish(e);*/
//Create new (unpublished) version - Guid is returned
//Log Publish
//Update all cmsDocument entries with Id to newest=0
//Insert new version in cmsDocument table
//Set Release and Expire date on newly created version
var e = new PublishEventArgs();
FireBeforePublish(content, e);
// Update xml in db using the new document (has correct version date)
//newDoc.XmlGenerate(new XmlDocument());
if (!e.Cancel)
{
content.ChangePublishedState(true);
//Fire AfterPublish event
//FireAfterPublish(e);
//Fire AfterPublish event
FireAfterPublish(content, e);
//Updating the cache is not done in the Document-Publish methods, so this part should be added
//global::umbraco.library.UpdateDocumentCache(doc.Id);
LogHelper.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' has been published.",
content.Name, content.Id));
int contentId = content.Id;
//NOTE: Ideally the xml cache should be refreshed here - as part of the publishing
var doc = new Document(contentId, true);
var user = new User(userId);
return doc.PublishWithResult(user);
return true;
}
return false;
}
public bool PublishWithChildren(IEnumerable<IContent> children, int userId)
/// <summary>
/// Publishes a list of content
/// </summary>
/// <param name="children">List of <see cref="IContent"/> to publish</param>
/// <param name="userId">Id of the user issueing the publish</param>
/// <returns>True if the content was published, otherwise false</returns>
public override bool PublishWithChildren(IEnumerable<IContent> children, int userId)
{
int contentId = children.Last().Id;
var doc = new Document(contentId, true);
var user = new User(userId);
return doc.PublishWithChildrenWithResult(user);
//Fire BeforePublish event
var e = new PublishEventArgs();
if (e.Cancel)
return false;
foreach (var content in children)
{
FireBeforePublish(content, e);
content.ChangePublishedState(true);
//Fire AfterPublish event
FireAfterPublish(content, e);
LogHelper.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' has been published.",
content.Name, content.Id));
}
//NOTE: Ideally the xml cache should be refreshed here - as part of the publishing
return true;
}
public void PublishWithSubs(IContent content, int userId)
/// <summary>
/// Unpublishes a single piece of content
/// </summary>
/// <param name="content"><see cref="IContent"/> to unpublish</param>
/// <param name="userId">Id of the user issueing the unpublish</param>
/// <returns>True is the content was unpublished, otherwise false</returns>
public override bool UnPublish(IContent content, int userId)
{
int contentId = content.Id;
var doc = new Document(contentId, true);
var user = new User(userId);
doc.PublishWithSubs(user);
}
var e = new UnPublishEventArgs();
FireBeforeUnPublish(content, e);
if (!e.Cancel)
{
content.ChangePublishedState(false);
FireAfterUnPublish(content, e);
LogHelper.Info<PublishingStrategy>(
string.Format("Content '{0}' with Id '{1}' has been unpublished.",
content.Name, content.Id));
//NOTE: Ideally the xml cache should be refreshed here - as part of the unpublishing
return true;
}
public bool UnPublish(IContent content, int userId)
{
return false;
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
@@ -204,27 +205,34 @@ namespace Umbraco.Web.Services
var list = new List<IContent>();
//Consider creating a Path query instead of recursive method
//Consider creating a Path query instead of recursive method:
//var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith("-1"));
var rootContent = GetRootContent();
foreach (var content in rootContent)
{
list.AddRange(GetChildrenDeep(content.Id));
}
foreach (var item in list)
{
//Only publish valid content - Might need to change the flat list as it could pose problems for children of invalid content
if(item.IsValid())
if(content.IsValid())
{
((Content)item).ChangePublishedState(true);
repository.AddOrUpdate(item);
list.AddRange(GetChildrenDeep(content.Id));
}
}
unitOfWork.Commit();
//Publish and then update the database with new status
var published = _publishingStrategy.PublishWithChildren(list, userId);
if (published)
{
foreach (var item in list)
{
repository.AddOrUpdate(item);
}
return _publishingStrategy.PublishWithChildren(list, userId);
unitOfWork.Commit();
//TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
global::umbraco.library.RefreshContent();
}
return published;
}
/// <summary>
@@ -249,25 +257,48 @@ namespace Umbraco.Web.Services
var unitOfWork = _provider.GetUnitOfWork();
var repository = RepositoryResolver.ResolveByType<IContentRepository, IContent, int>(unitOfWork);
//Consider creating a Path query instead of recursive method
//Check if parent is published - if parent isn't published this Content cannot be published
var parent = GetById(content.ParentId);
if (!parent.Published)
{
LogHelper.Info<ContentService>(
string.Format("Content '{0}' with Id '{1}' could not be published because its parent is not published.",
content.Name, content.Id));
return false;
}
//Content contains invalid property values and can therefore not be published - fire event?
if (!content.IsValid())
{
LogHelper.Info<ContentService>(
string.Format("Content '{0}' with Id '{1}' could not be published because of invalid properties.",
content.Name, content.Id));
return false;
}
//Consider creating a Path query instead of recursive method:
//var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith(content.Path));
var list = GetChildrenDeep(content.Id);
list.Add(content);
foreach (var item in list)
//Publish and then update the database with new status
var published = _publishingStrategy.PublishWithChildren(list, userId);
if (published)
{
//TODO Test and correct this so children of unpublished content isn't published.
//Only publish valid content - Might need to change the flat list as it could pose problems for children of invalid content
if (item.IsValid())
foreach (var item in list)
{
((Content) item).ChangePublishedState(true);
repository.AddOrUpdate(item);
}
unitOfWork.Commit();
//TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
//TODO Need to investigate if it will also update the cache for children of the Content object
global::umbraco.library.UpdateDocumentCache(content.Id);
}
unitOfWork.Commit();
return _publishingStrategy.PublishWithChildren(list, userId);
return published;
}
/// <summary>
@@ -281,26 +312,42 @@ namespace Umbraco.Web.Services
var unitOfWork = _provider.GetUnitOfWork();
var repository = RepositoryResolver.ResolveByType<IContentRepository, IContent, int>(unitOfWork);
((Content)content).ChangePublishedState(false);
repository.AddOrUpdate(content);
unitOfWork.Commit();
var unpublished = _publishingStrategy.UnPublish(content, userId);
return _publishingStrategy.UnPublish(content, userId);
if (unpublished)
{
repository.AddOrUpdate(content);
unitOfWork.Commit();
//TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content class.
global::umbraco.library.UnPublishSingleNode(content.Id);
}
return unpublished;
}
/// <summary>
/// Gets a flat list of decendents of content from parent id
/// </summary>
/// <param name="parentId"></param>
/// <returns></returns>
/// <remarks>
/// Only contains valid <see cref="IContent"/> objects, which means
/// that everything in the returned list can be published.
/// If an invalid <see cref="IContent"/> object is found it will not
/// be added to the list neither will its children.
/// </remarks>
/// <param name="parentId">Id of the parent to retrieve children from</param>
/// <returns>A list of valid <see cref="IContent"/> that can be published</returns>
private List<IContent> GetChildrenDeep(int parentId)
{
var list = new List<IContent>();
var children = GetChildren(parentId);
foreach (var child in children)
{
list.Add(child);
list.AddRange(GetChildrenDeep(child.Id));
if (child.IsValid())
{
list.Add(child);
list.AddRange(GetChildrenDeep(child.Id));
}
}
return list;
}
@@ -316,16 +363,37 @@ namespace Umbraco.Web.Services
var unitOfWork = _provider.GetUnitOfWork();
var repository = RepositoryResolver.ResolveByType<IContentRepository, IContent, int>(unitOfWork);
//NOTE: Should also check if parent is published - if parent isn't published this Content cannot be published
//Check if parent is published - if parent isn't published this Content cannot be published
var parent = GetById(content.ParentId);
if(!parent.Published)
{
LogHelper.Info<ContentService>(
string.Format("Content '{0}' with Id '{1}' could not be published because its parent is not published.",
content.Name, content.Id));
return false;
}
//Content contains invalid property values and can therefore not be published - fire event?
if (!content.IsValid())
return false;//Content contains invalid property values and can therefore not be published
{
LogHelper.Info<ContentService>(
string.Format("Content '{0}' with Id '{1}' could not be published because of invalid properties.",
content.Name, content.Id));
return false;
}
((Content)content).ChangePublishedState(true);
repository.AddOrUpdate(content);
unitOfWork.Commit();
//Publish and then update the database with new status
bool published = _publishingStrategy.Publish(content, userId);
if (published)
{
repository.AddOrUpdate(content);
unitOfWork.Commit();
return _publishingStrategy.Publish(content, userId);
//TODO Change this so we can avoid a depencency to the horrible library method / umbraco.content (singleton) class.
global::umbraco.library.UpdateDocumentCache(content.Id);
}
return published;
}
/// <summary>

View File

@@ -306,6 +306,7 @@
<Compile Include="Mvc\UmbracoPageResult.cs" />
<Compile Include="PropertyEditors\RteMacroRenderingPropertyEditorValueConverter.cs" />
<Compile Include="PublishedMediaStoreResolver.cs" />
<Compile Include="Publishing\BasePublishingStrategy.cs" />
<Compile Include="Publishing\IPublishingStrategy.cs" />
<Compile Include="Publishing\PublishingStrategy.cs" />
<Compile Include="RenderFieldCaseType.cs" />