Merge remote-tracking branch 'origin/6.2.0' into 7.1.2
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user