Merge remote-tracking branch 'origin/6.2.0' into 7.1.2

This commit is contained in:
Shannon
2014-04-22 17:49:01 +10:00
11 changed files with 316 additions and 56 deletions

View File

@@ -420,7 +420,17 @@ namespace Umbraco.Core.Models
/// Creates a deep clone of the current entity with its identity and it's property identities reset
/// </summary>
/// <returns></returns>
[Obsolete("Use DeepCloneWithResetIdentities instead")]
public IContent Clone()
{
return DeepCloneWithResetIdentities();
}
/// <summary>
/// Creates a deep clone of the current entity with its identity and it's property identities reset
/// </summary>
/// <returns></returns>
public IContent DeepCloneWithResetIdentities()
{
var clone = (Content)DeepClone();
clone.Key = Guid.Empty;

View File

@@ -120,7 +120,7 @@ namespace Umbraco.Core.Models
return result;
}
/// <summary>
/// Method to call when Entity is being saved
/// </summary>
@@ -142,18 +142,48 @@ namespace Umbraco.Core.Models
base.UpdatingEntity();
}
public override object DeepClone()
{
var clone = (ContentType)base.DeepClone();
var propertyGroups = PropertyGroups.Select(x => (PropertyGroup)x.DeepClone()).ToList();
clone.PropertyGroups = new PropertyGroupCollection(propertyGroups);
//set the property types that are not part of a group
clone.PropertyTypes = PropertyTypeCollection
.Where(x => x.PropertyGroupId == null)
.Select(x => (PropertyType)x.DeepClone()).ToList();
return clone;
}
/// <summary>
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
/// </summary>
/// <returns></returns>
[Obsolete("Use DeepCloneWithResetIdentities instead")]
public IContentType Clone(string alias)
{
return DeepCloneWithResetIdentities(alias);
}
/// <summary>
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
/// </summary>
/// <returns></returns>
public IContentType DeepCloneWithResetIdentities(string alias)
{
var clone = (ContentType)DeepClone();
clone.Alias = alias;
clone.Key = Guid.Empty;
var propertyGroups = PropertyGroups.Select(x => x.Clone()).ToList();
clone.PropertyGroups = new PropertyGroupCollection(propertyGroups);
clone.PropertyTypes = PropertyTypeCollection.Select(x => x.Clone()).ToList();
foreach (var propertyGroup in clone.PropertyGroups)
{
propertyGroup.ResetIdentity();
propertyGroup.ResetDirtyProperties(false);
}
foreach (var propertyType in clone.PropertyTypes)
{
propertyType.ResetIdentity();
propertyType.ResetDirtyProperties(false);
}
clone.ResetIdentity();
clone.ResetDirtyProperties(false);
return clone;

View File

@@ -72,5 +72,11 @@ namespace Umbraco.Core.Models
/// Changes the Published state of the content object
/// </summary>
void ChangePublishedState(PublishedState state);
/// <summary>
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
/// </summary>
/// <returns></returns>
IContent DeepCloneWithResetIdentities();
}
}

View File

@@ -29,5 +29,12 @@ namespace Umbraco.Core.Models
/// <param name="template"><see cref="ITemplate"/> to remove</param>
/// <returns>True if template was removed, otherwise False</returns>
bool RemoveTemplate(ITemplate template);
/// <summary>
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
/// </summary>
/// <param name="newAlias"></param>
/// <returns></returns>
IContentType DeepCloneWithResetIdentities(string newAlias);
}
}

View File

@@ -143,24 +143,5 @@ namespace Umbraco.Core.Models
return hashName ^ hashId;
}
/// <summary>
/// Creates a deep clone of the current entity with its identity and it's property identities reset
/// </summary>
/// <returns></returns>
internal PropertyGroup Clone()
{
var clone = (PropertyGroup)DeepClone();
var collection = new PropertyTypeCollection();
foreach (var propertyType in PropertyTypes)
{
var property = propertyType.Clone();
collection.Add(property);
}
clone.PropertyTypes = collection;
clone.ResetIdentity();
clone.ResetDirtyProperties(false);
return clone;
}
}
}

View File

@@ -443,18 +443,6 @@ namespace Umbraco.Core.Models
return hashName ^ hashAlias;
}
/// <summary>
/// Creates a deep clone of the current entity with its identity and it's property identities reset
/// </summary>
/// <returns></returns>
internal PropertyType Clone()
{
var clone = (PropertyType)DeepClone();
clone.ResetIdentity();
clone.ResetDirtyProperties(false);
return clone;
}
public override object DeepClone()
{
var clone = (PropertyType)base.DeepClone();
@@ -462,8 +450,7 @@ namespace Umbraco.Core.Models
//need to manually assign the Lazy value as it will not be automatically mapped
if (PropertyGroupId != null)
{
var propGroupId = PropertyGroupId.Value;
clone._propertyGroupId = new Lazy<int>(() => propGroupId);
clone._propertyGroupId = new Lazy<int>(() => PropertyGroupId.Value);
}
clone.ResetDirtyProperties(false);

View File

@@ -1152,7 +1152,7 @@ namespace Umbraco.Core.Services
{
using (new WriteLock(Locker))
{
var copy = ((Content)content).Clone();
var copy = content.DeepCloneWithResetIdentities();
copy.ParentId = parentId;
// A copy should never be set to published automatically even if the original was.

View File

@@ -46,6 +46,89 @@ namespace Umbraco.Core.Services
_mediaService = mediaService;
}
/// <summary>
/// Copies a content type as a child under the specified parent if specified (otherwise to the root)
/// </summary>
/// <param name="original">
/// The content type to copy
/// </param>
/// <param name="alias">
/// The new alias of the content type
/// </param>
/// <param name="name">
/// The new name of the content type
/// </param>
/// <param name="parentId">
/// The parent to copy the content type to, default is -1 (root)
/// </param>
/// <returns></returns>
public IContentType Copy(IContentType original, string alias, string name, int parentId = -1)
{
IContentType parent = null;
if (parentId > 0)
{
parent = GetContentType(parentId);
if (parent == null)
{
throw new InvalidOperationException("Could not find content type with id " + parentId);
}
}
return Copy(original, alias, name, parent);
}
/// <summary>
/// Copies a content type as a child under the specified parent if specified (otherwise to the root)
/// </summary>
/// <param name="original">
/// The content type to copy
/// </param>
/// <param name="alias">
/// The new alias of the content type
/// </param>
/// <param name="name">
/// The new name of the content type
/// </param>
/// <param name="parent">
/// The parent to copy the content type to, default is null (root)
/// </param>
/// <returns></returns>
public IContentType Copy(IContentType original, string alias, string name, IContentType parent)
{
Mandate.ParameterNotNull(original, "original");
Mandate.ParameterNotNullOrEmpty(alias, "alias");
if (parent != null)
{
Mandate.That(parent.HasIdentity, () => new InvalidOperationException("The parent content type must have an identity"));
}
var clone = original.DeepCloneWithResetIdentities(alias);
clone.Name = name;
var compositionAliases = clone.CompositionAliases().Except(new[] { alias }).ToList();
//remove all composition that is not it's current alias
foreach (var a in compositionAliases)
{
clone.RemoveContentType(a);
}
//if a parent is specified set it's composition and parent
if (parent != null)
{
//add a new parent composition
clone.AddContentType(parent);
clone.ParentId = parent.Id;
}
else
{
//set to root
clone.ParentId = -1;
}
Save(clone);
return clone;
}
/// <summary>
/// Gets an <see cref="IContentType"/> object by its Id
/// </summary>

View File

@@ -9,6 +9,42 @@ namespace Umbraco.Core.Services
/// </summary>
public interface IContentTypeService : IService
{
/// <summary>
/// Copies a content type as a child under the specified parent if specified (otherwise to the root)
/// </summary>
/// <param name="original">
/// The content type to copy
/// </param>
/// <param name="alias">
/// The new alias of the content type
/// </param>
/// <param name="name">
/// The new name of the content type
/// </param>
/// <param name="parentId">
/// The parent to copy the content type to, default is -1 (root)
/// </param>
/// <returns></returns>
IContentType Copy(IContentType original, string alias, string name, int parentId = -1);
/// <summary>
/// Copies a content type as a child under the specified parent if specified (otherwise to the root)
/// </summary>
/// <param name="original">
/// The content type to copy
/// </param>
/// <param name="alias">
/// The new alias of the content type
/// </param>
/// <param name="name">
/// The new name of the content type
/// </param>
/// <param name="parent">
/// The parent to copy the content type to
/// </param>
/// <returns></returns>
IContentType Copy(IContentType original, string alias, string name, IContentType parent);
/// <summary>
/// Gets an <see cref="IContentType"/> object by its Id
/// </summary>

View File

@@ -300,6 +300,140 @@ namespace Umbraco.Tests.Services
}
[Test]
public void Can_Copy_ContentType_To_New_Parent_By_Performing_Clone()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var parentContentType1 = MockedContentTypes.CreateSimpleContentType("parent1", "Parent1");
service.Save(parentContentType1);
var parentContentType2 = MockedContentTypes.CreateSimpleContentType("parent2", "Parent2");
service.Save(parentContentType2);
var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", parentContentType1);
service.Save(simpleContentType);
// Act
var clone = simpleContentType.Clone("newcategory");
clone.RemoveContentType("parent1");
clone.AddContentType(parentContentType2);
clone.ParentId = parentContentType2.Id;
service.Save(clone);
// Assert
Assert.That(clone.HasIdentity, Is.True);
var clonedContentType = service.GetContentType(clone.Id);
var originalContentType = service.GetContentType(simpleContentType.Id);
Assert.That(clonedContentType.CompositionAliases().Any(x => x.Equals("parent2")), Is.True);
Assert.That(clonedContentType.CompositionAliases().Any(x => x.Equals("parent1")), Is.False);
Assert.AreEqual(clonedContentType.Path, "-1," + parentContentType2.Id + "," + clonedContentType.Id);
Assert.AreEqual(clonedContentType.PropertyTypes.Count(), originalContentType.PropertyTypes.Count());
Assert.AreNotEqual(clonedContentType.ParentId, originalContentType.ParentId);
Assert.AreEqual(clonedContentType.ParentId, parentContentType2.Id);
Assert.AreNotEqual(clonedContentType.Id, originalContentType.Id);
Assert.AreNotEqual(clonedContentType.Key, originalContentType.Key);
Assert.AreNotEqual(clonedContentType.Path, originalContentType.Path);
Assert.AreNotEqual(clonedContentType.PropertyTypes.First(x => x.Alias.Equals("title")).Id, originalContentType.PropertyTypes.First(x => x.Alias.Equals("title")).Id);
Assert.AreNotEqual(clonedContentType.PropertyGroups.First(x => x.Name.Equals("Content")).Id, originalContentType.PropertyGroups.First(x => x.Name.Equals("Content")).Id);
}
[Test]
public void Can_Copy_ContentType_With_Service_To_Root()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var metaContentType = MockedContentTypes.CreateMetaContentType();
service.Save(metaContentType);
var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", metaContentType);
service.Save(simpleContentType);
var categoryId = simpleContentType.Id;
// Act
var clone = service.Copy(simpleContentType, "newcategory", "new category");
// Assert
Assert.That(clone.HasIdentity, Is.True);
var cloned = service.GetContentType(clone.Id);
var original = service.GetContentType(categoryId);
Assert.That(cloned.CompositionAliases().Any(x => x.Equals("meta")), Is.False); //it's been copied to root
Assert.AreEqual(cloned.ParentId, -1);
Assert.AreEqual(cloned.Level, 1);
Assert.AreEqual(cloned.PropertyTypes.Count(), original.PropertyTypes.Count());
Assert.AreEqual(cloned.PropertyGroups.Count(), original.PropertyGroups.Count());
for (int i = 0; i < cloned.PropertyGroups.Count; i++)
{
Assert.AreEqual(cloned.PropertyGroups[i].PropertyTypes.Count, original.PropertyGroups[i].PropertyTypes.Count);
foreach (var propertyType in cloned.PropertyGroups[i].PropertyTypes)
{
Assert.IsTrue(propertyType.HasIdentity);
}
}
foreach (var propertyType in cloned.PropertyTypes)
{
Assert.IsTrue(propertyType.HasIdentity);
}
Assert.AreNotEqual(cloned.Id, original.Id);
Assert.AreNotEqual(cloned.Key, original.Key);
Assert.AreNotEqual(cloned.Path, original.Path);
Assert.AreNotEqual(cloned.SortOrder, original.SortOrder);
Assert.AreNotEqual(cloned.PropertyTypes.First(x => x.Alias.Equals("title")).Id, original.PropertyTypes.First(x => x.Alias.Equals("title")).Id);
Assert.AreNotEqual(cloned.PropertyGroups.First(x => x.Name.Equals("Content")).Id, original.PropertyGroups.First(x => x.Name.Equals("Content")).Id);
}
[Test]
public void Can_Copy_ContentType_To_New_Parent_With_Service()
{
// Arrange
var service = ServiceContext.ContentTypeService;
var parentContentType1 = MockedContentTypes.CreateSimpleContentType("parent1", "Parent1");
service.Save(parentContentType1);
var parentContentType2 = MockedContentTypes.CreateSimpleContentType("parent2", "Parent2");
service.Save(parentContentType2);
var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", parentContentType1);
service.Save(simpleContentType);
// Act
var clone = service.Copy(simpleContentType, "newAlias", "new alias", parentContentType2);
// Assert
Assert.That(clone.HasIdentity, Is.True);
var clonedContentType = service.GetContentType(clone.Id);
var originalContentType = service.GetContentType(simpleContentType.Id);
Assert.That(clonedContentType.CompositionAliases().Any(x => x.Equals("parent2")), Is.True);
Assert.That(clonedContentType.CompositionAliases().Any(x => x.Equals("parent1")), Is.False);
Assert.AreEqual(clonedContentType.Path, "-1," + parentContentType2.Id + "," + clonedContentType.Id);
Assert.AreEqual(clonedContentType.PropertyTypes.Count(), originalContentType.PropertyTypes.Count());
Assert.AreNotEqual(clonedContentType.ParentId, originalContentType.ParentId);
Assert.AreEqual(clonedContentType.ParentId, parentContentType2.Id);
Assert.AreNotEqual(clonedContentType.Id, originalContentType.Id);
Assert.AreNotEqual(clonedContentType.Key, originalContentType.Key);
Assert.AreNotEqual(clonedContentType.Path, originalContentType.Path);
Assert.AreNotEqual(clonedContentType.PropertyTypes.First(x => x.Alias.Equals("title")).Id, originalContentType.PropertyTypes.First(x => x.Alias.Equals("title")).Id);
Assert.AreNotEqual(clonedContentType.PropertyGroups.First(x => x.Name.Equals("Content")).Id, originalContentType.PropertyGroups.First(x => x.Name.Equals("Content")).Id);
}
private ContentType CreateComponent()
{
var component = new ContentType(-1)

View File

@@ -145,31 +145,17 @@ namespace umbraco.dialogs
private void HandleDocumentTypeCopy()
{
//TODO: This should be a method on the service!!!
var contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
var contentType = contentTypeService.GetContentType(
int.Parse(Request.GetItemAsString("id")));
var alias = rename.Text.Trim().Replace("'", "''");
var clone = ((Umbraco.Core.Models.ContentType) contentType).Clone(alias);
clone.Name = rename.Text.Trim();
//set the master
//http://issues.umbraco.org/issue/U4-2843
//http://issues.umbraco.org/issue/U4-3552
var parent = int.Parse(masterType.SelectedValue);
if (parent > 0)
{
clone.ParentId = parent;
}
else
{
clone.ParentId = -1;
}
contentTypeService.Save(clone);
var parentId = int.Parse(masterType.SelectedValue);
var alias = rename.Text.Trim().Replace("'", "''");
var clone = contentTypeService.Copy(contentType, alias, rename.Text.Trim(), parentId);
var returnUrl = string.Format("{0}/settings/editNodeTypeNew.aspx?id={1}", SystemDirectories.Umbraco, clone.Id);