diff --git a/src/Umbraco.Core/Events/CancellableEventArgs.cs b/src/Umbraco.Core/Events/CancellableEventArgs.cs new file mode 100644 index 0000000000..80e69ae353 --- /dev/null +++ b/src/Umbraco.Core/Events/CancellableEventArgs.cs @@ -0,0 +1,51 @@ +using System; +using System.Security.Permissions; + +namespace Umbraco.Core.Events +{ + /// + /// Event args for that can support cancellation + /// + [HostProtection(SecurityAction.LinkDemand, SharedState = true)] + public class CancellableEventArgs : EventArgs + { + private bool _cancel; + + public CancellableEventArgs(bool canCancel) + { + CanCancel = canCancel; + } + + public CancellableEventArgs() + : this(true) + { + } + /// + /// Flag to determine if this instance will support being cancellable + /// + public bool CanCancel { get; set; } + + /// + /// If this instance supports cancellation, this gets/sets the cancel value + /// + public bool Cancel + { + get + { + if (!CanCancel) + { + throw new InvalidOperationException("This event argument class does not support cancelling."); + } + return _cancel; + } + set + { + if (!CanCancel) + { + throw new InvalidOperationException("This event argument class does not support cancelling."); + } + _cancel = value; + } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Events/CancellableObjectEventArgs.cs b/src/Umbraco.Core/Events/CancellableObjectEventArgs.cs new file mode 100644 index 0000000000..cb89ace510 --- /dev/null +++ b/src/Umbraco.Core/Events/CancellableObjectEventArgs.cs @@ -0,0 +1,35 @@ +using System.Security.Permissions; +using Umbraco.Core.Models; +using Umbraco.Core.Models.EntityBase; + +namespace Umbraco.Core.Events +{ + /// + /// Event args for a strongly typed object that can support cancellation + /// + /// + [HostProtection(SecurityAction.LinkDemand, SharedState = true)] + public class CancellableObjectEventArgs : CancellableEventArgs + { + + public CancellableObjectEventArgs(T eventObject, bool canCancel) + : base(canCancel) + { + EventObject = eventObject; + } + + public CancellableObjectEventArgs(T eventObject) + : this(eventObject, true) + { + } + + /// + /// Returns the object relating to the event + /// + /// + /// This is protected so that inheritors can expose it with their own name + /// + protected T EventObject { get; private set; } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Events/CopyEventArgs.cs b/src/Umbraco.Core/Events/CopyEventArgs.cs index 4717e206cd..f53f8a536e 100644 --- a/src/Umbraco.Core/Events/CopyEventArgs.cs +++ b/src/Umbraco.Core/Events/CopyEventArgs.cs @@ -1,10 +1,35 @@ namespace Umbraco.Core.Events { - public class CopyEventArgs : System.ComponentModel.CancelEventArgs + public class CopyEventArgs : CancellableObjectEventArgs { + public CopyEventArgs(TEntity original, TEntity copy, bool canCancel, int parentId) : base(original, canCancel) + { + Copy = copy; + ParentId = parentId; + } + + public CopyEventArgs(TEntity eventObject, TEntity copy, int parentId) : base(eventObject) + { + Copy = copy; + ParentId = parentId; + } + + /// + /// The copied entity + /// + public TEntity Copy { get; set; } + + /// + /// The original entity + /// + public TEntity Original + { + get { return EventObject; } + } + /// /// Gets or Sets the Id of the objects new parent. /// - public int ParentId { get; set; } + public int ParentId { get; private set; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Events/DeleteEventArgs.cs b/src/Umbraco.Core/Events/DeleteEventArgs.cs index a799e39956..5b5bf47336 100644 --- a/src/Umbraco.Core/Events/DeleteEventArgs.cs +++ b/src/Umbraco.Core/Events/DeleteEventArgs.cs @@ -1,10 +1,70 @@ +using System.Collections.Generic; + namespace Umbraco.Core.Events { - public class DeleteEventArgs : System.ComponentModel.CancelEventArgs + public class DeleteEventArgs : CancellableObjectEventArgs> { /// - /// Gets or Sets the Id of the object being deleted. + /// Constructor accepting multiple entities that are used in the delete operation /// - public int Id { get; set; } + /// + /// + public DeleteEventArgs(IEnumerable eventObject, bool canCancel) : base(eventObject, canCancel) + { + } + + /// + /// Constructor accepting multiple entities that are used in the delete operation + /// + /// + public DeleteEventArgs(IEnumerable eventObject) : base(eventObject) + { + } + + /// + /// Constructor accepting a single entity instance + /// + /// + public DeleteEventArgs(TEntity eventObject) + : base(new List { eventObject }) + { + } + + /// + /// Constructor accepting a single entity instance + /// + /// + /// + public DeleteEventArgs(TEntity eventObject, bool canCancel) + : base(new List { eventObject }, canCancel) + { + } + + /// + /// Returns all entities that were deleted during the operation + /// + public IEnumerable DeletedEntities + { + get { return EventObject; } + } + } + + public class DeleteEventArgs : CancellableEventArgs + { + public DeleteEventArgs(int id, bool canCancel) + : base(canCancel) + { + Id = id; + } + + public DeleteEventArgs(int id) + { + Id = id; + } + + /// + /// Gets the Id of the object being deleted. + /// + public int Id { get; private set; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Events/DeleteRevisionsEventArgs.cs b/src/Umbraco.Core/Events/DeleteRevisionsEventArgs.cs new file mode 100644 index 0000000000..4d53270608 --- /dev/null +++ b/src/Umbraco.Core/Events/DeleteRevisionsEventArgs.cs @@ -0,0 +1,35 @@ +using System; + +namespace Umbraco.Core.Events +{ + public class DeleteRevisionsEventArgs : DeleteEventArgs + { + public DeleteRevisionsEventArgs(int id, bool canCancel, Guid specificVersion = default(Guid), bool deletePriorVersions = false, DateTime dateToRetain = default(DateTime)) + : base(id, canCancel) + { + DeletePriorVersions = deletePriorVersions; + SpecificVersion = specificVersion; + DateToRetain = dateToRetain; + } + + public DeleteRevisionsEventArgs(int id, Guid specificVersion = default(Guid), bool deletePriorVersions = false, DateTime dateToRetain = default(DateTime)) + : base(id) + { + DeletePriorVersions = deletePriorVersions; + SpecificVersion = specificVersion; + DateToRetain = dateToRetain; + } + + public bool DeletePriorVersions { get; private set; } + public Guid SpecificVersion { get; private set; } + public DateTime DateToRetain { get; private set; } + + /// + /// Returns true if we are deleting a specific revision + /// + public bool IsDeletingSpecificRevision + { + get { return SpecificVersion != default(Guid); } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Events/EventExtensions.cs b/src/Umbraco.Core/Events/EventExtensions.cs new file mode 100644 index 0000000000..99cf145fe0 --- /dev/null +++ b/src/Umbraco.Core/Events/EventExtensions.cs @@ -0,0 +1,49 @@ +using System; + +namespace Umbraco.Core.Events +{ + /// + /// Extension methods for cancellable event operations + /// + public static class EventExtensions + { + /// + /// Raises the event and returns a boolean value indicating if the event was cancelled + /// + /// + /// + /// + /// + /// + /// + public static bool IsRaisedEventCancelled( + this TypedEventHandler eventHandler, + TArgs args, + TSender sender) + where TArgs : CancellableEventArgs + { + if (eventHandler != null) + eventHandler(sender, args); + + return args.Cancel; + } + + /// + /// Raises the event + /// + /// + /// + /// + /// + /// + public static void RaiseEvent( + this TypedEventHandler eventHandler, + TArgs args, + TSender sender) + where TArgs : EventArgs + { + if (eventHandler != null) + eventHandler(sender, args); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Events/MoveEventArgs.cs b/src/Umbraco.Core/Events/MoveEventArgs.cs index 6226cde7d4..59e7e19f46 100644 --- a/src/Umbraco.Core/Events/MoveEventArgs.cs +++ b/src/Umbraco.Core/Events/MoveEventArgs.cs @@ -1,10 +1,28 @@ namespace Umbraco.Core.Events { - public class MoveEventArgs : System.ComponentModel.CancelEventArgs + public class MoveEventArgs : CancellableObjectEventArgs { + public MoveEventArgs(TEntity eventObject, bool canCancel, int parentId) : base(eventObject, canCancel) + { + ParentId = parentId; + } + + public MoveEventArgs(TEntity eventObject, int parentId) : base(eventObject) + { + ParentId = parentId; + } + + /// + /// The entity being moved + /// + public TEntity Entity + { + get { return EventObject; } + } + /// /// Gets or Sets the Id of the objects new parent. /// - public int ParentId { get; set; } + public int ParentId { get; private set; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Events/NewEventArgs.cs b/src/Umbraco.Core/Events/NewEventArgs.cs index d74cb24b5c..07481df63e 100644 --- a/src/Umbraco.Core/Events/NewEventArgs.cs +++ b/src/Umbraco.Core/Events/NewEventArgs.cs @@ -1,15 +1,35 @@ namespace Umbraco.Core.Events { - public class NewEventArgs : System.ComponentModel.CancelEventArgs + public class NewEventArgs : CancellableObjectEventArgs { + public NewEventArgs(TEntity eventObject, bool canCancel, string @alias, int parentId) : base(eventObject, canCancel) + { + Alias = alias; + ParentId = parentId; + } + + public NewEventArgs(TEntity eventObject, string @alias, int parentId) : base(eventObject) + { + Alias = alias; + ParentId = parentId; + } + + /// + /// The entity being created + /// + public TEntity Entity + { + get { return EventObject; } + } + /// /// Gets or Sets the Alias. /// - public string Alias { get; set; } + public string Alias { get; private set; } /// /// Gets or Sets the Id of the parent. /// - public int ParentId { get; set; } + public int ParentId { get; private set; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Events/PublishingEventArgs.cs b/src/Umbraco.Core/Events/PublishingEventArgs.cs index f762695f70..c58e3bac15 100644 --- a/src/Umbraco.Core/Events/PublishingEventArgs.cs +++ b/src/Umbraco.Core/Events/PublishingEventArgs.cs @@ -1,17 +1,17 @@ namespace Umbraco.Core.Events { - public class PublishingEventArgs : System.ComponentModel.CancelEventArgs + public class PublishingEventArgs : System.ComponentModel.CancelEventArgs { - public PublishingEventArgs() - { - IsAllRepublished = false; - } + public PublishingEventArgs() + { + IsAllRepublished = false; + } - public PublishingEventArgs(bool isAllPublished) - { - IsAllRepublished = isAllPublished; - } + public PublishingEventArgs(bool isAllPublished) + { + IsAllRepublished = isAllPublished; + } - public bool IsAllRepublished { get; private set; } - } + public bool IsAllRepublished { get; private set; } + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Events/RefreshContentEventArgs.cs b/src/Umbraco.Core/Events/RefreshContentEventArgs.cs index 3afac7eca1..a295b239c9 100644 --- a/src/Umbraco.Core/Events/RefreshContentEventArgs.cs +++ b/src/Umbraco.Core/Events/RefreshContentEventArgs.cs @@ -1,4 +1,4 @@ namespace Umbraco.Core.Events { - public class RefreshContentEventArgs : System.ComponentModel.CancelEventArgs { } + //public class RefreshContentEventArgs : System.ComponentModel.CancelEventArgs { } } \ No newline at end of file diff --git a/src/Umbraco.Core/Events/RollbackEventArgs.cs b/src/Umbraco.Core/Events/RollbackEventArgs.cs index 58baa334b7..db9dded08c 100644 --- a/src/Umbraco.Core/Events/RollbackEventArgs.cs +++ b/src/Umbraco.Core/Events/RollbackEventArgs.cs @@ -1,4 +1,21 @@ namespace Umbraco.Core.Events { - public class RollbackEventArgs : System.ComponentModel.CancelEventArgs { } + public class RollbackEventArgs : CancellableObjectEventArgs + { + public RollbackEventArgs(TEntity eventObject, bool canCancel) : base(eventObject, canCancel) + { + } + + public RollbackEventArgs(TEntity eventObject) : base(eventObject) + { + } + + /// + /// The entity being rolledback + /// + public TEntity Entity + { + get { return EventObject; } + } + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Events/SaveEventArgs.cs b/src/Umbraco.Core/Events/SaveEventArgs.cs index c3654586dd..ea1a94e5b3 100644 --- a/src/Umbraco.Core/Events/SaveEventArgs.cs +++ b/src/Umbraco.Core/Events/SaveEventArgs.cs @@ -1,4 +1,57 @@ +using System.Collections.Generic; +using Umbraco.Core.Models.EntityBase; + namespace Umbraco.Core.Events { - public class SaveEventArgs : System.ComponentModel.CancelEventArgs { } + public class SaveEventArgs : CancellableObjectEventArgs> + { + /// + /// Constructor accepting multiple entities that are used in the saving operation + /// + /// + /// + public SaveEventArgs(IEnumerable eventObject, bool canCancel) + : base(eventObject, canCancel) + { + } + + /// + /// Constructor accepting multiple entities that are used in the saving operation + /// + /// + public SaveEventArgs(IEnumerable eventObject) + : base(eventObject) + { + } + + /// + /// Constructor accepting a single entity instance + /// + /// + public SaveEventArgs(TEntity eventObject) + : base(new List { eventObject }) + { + } + + /// + /// Constructor accepting a single entity instance + /// + /// + /// + public SaveEventArgs(TEntity eventObject, bool canCancel) + : base(new List { eventObject }, canCancel) + { + } + + /// + /// Returns all entities that were deleted during the operation + /// + public IEnumerable SavedEntities + { + get { return EventObject; } + } + + + + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Events/SendToPublishEventArgs.cs b/src/Umbraco.Core/Events/SendToPublishEventArgs.cs index 1c2a868e61..b246395a92 100644 --- a/src/Umbraco.Core/Events/SendToPublishEventArgs.cs +++ b/src/Umbraco.Core/Events/SendToPublishEventArgs.cs @@ -1,4 +1,21 @@ namespace Umbraco.Core.Events { - public class SendToPublishEventArgs : System.ComponentModel.CancelEventArgs { } + public class SendToPublishEventArgs : CancellableObjectEventArgs + { + public SendToPublishEventArgs(TEntity eventObject, bool canCancel) : base(eventObject, canCancel) + { + } + + public SendToPublishEventArgs(TEntity eventObject) : base(eventObject) + { + } + + /// + /// The entity being sent to publish + /// + public TEntity Entity + { + get { return EventObject; } + } + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Events/TypedEventHandler.cs b/src/Umbraco.Core/Events/TypedEventHandler.cs new file mode 100644 index 0000000000..a8170190d4 --- /dev/null +++ b/src/Umbraco.Core/Events/TypedEventHandler.cs @@ -0,0 +1,7 @@ +using System; + +namespace Umbraco.Core.Events +{ + [Serializable] + public delegate void TypedEventHandler(TSender sender, TEventArgs e); +} \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs index 43892051df..2e5e7f8383 100644 --- a/src/Umbraco.Core/Models/Content.cs +++ b/src/Umbraco.Core/Models/Content.cs @@ -26,17 +26,32 @@ namespace Umbraco.Core.Models /// /// Id of the Parent content /// ContentType for the current Content object - public Content(int parentId, IContentType contentType) : this(parentId, contentType, new PropertyCollection()) + public Content(int parentId, IContentType contentType) + : this(parentId, contentType, new PropertyCollection()) { } + public Content(IContent parent, IContentType contentType) + : this(parent, contentType, new PropertyCollection()) + { + } + + public Content(IContent parent, IContentType contentType, PropertyCollection properties) + : base(parent, contentType, properties) + { + Mandate.ParameterNotNull(contentType, "contentType"); + + _contentType = contentType; + } + /// /// Constructor for creating a Content object /// /// Id of the Parent content /// ContentType for the current Content object /// Collection of properties - public Content(int parentId, IContentType contentType, PropertyCollection properties) : base(parentId, contentType, properties) + public Content(int parentId, IContentType contentType, PropertyCollection properties) + : base(parentId, contentType, properties) { Mandate.ParameterNotNull(contentType, "contentType"); diff --git a/src/Umbraco.Core/Models/ContentBase.cs b/src/Umbraco.Core/Models/ContentBase.cs index 308c803f73..fd4692cb33 100644 --- a/src/Umbraco.Core/Models/ContentBase.cs +++ b/src/Umbraco.Core/Models/ContentBase.cs @@ -27,7 +27,7 @@ namespace Umbraco.Core.Models protected ContentBase(int parentId, IContentTypeComposition contentType, PropertyCollection properties) { - //Mandate.ParameterCondition(parentId != 0, "parentId"); + Mandate.ParameterCondition(parentId != 0, "parentId"); Mandate.ParameterNotNull(contentType, "contentType"); Mandate.ParameterNotNull(properties, "properties"); @@ -41,7 +41,22 @@ namespace Umbraco.Core.Models Version = Guid.NewGuid(); } - private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); + protected ContentBase(IContentBase parent, IContentTypeComposition contentType, PropertyCollection properties) + { + Mandate.ParameterNotNull(parent, "parent"); + Mandate.ParameterNotNull(contentType, "contentType"); + Mandate.ParameterNotNull(properties, "properties"); + + _parentId = new Lazy(() => parent.Id); + + _contentTypeId = int.Parse(contentType.Id.ToString(CultureInfo.InvariantCulture)); + ContentTypeBase = contentType; + _properties = properties; + _properties.EnsurePropertyTypes(PropertyTypes); + Version = Guid.NewGuid(); + } + + private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentId); private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo(x => x.SortOrder); private static readonly PropertyInfo LevelSelector = ExpressionHelper.GetPropertyInfo(x => x.Level); @@ -63,7 +78,15 @@ namespace Umbraco.Core.Models [DataMember] public virtual int ParentId { - get { return _parentId.Value; } + get + { + var val = _parentId.Value; + if (val == 0) + { + throw new InvalidOperationException("The ParentId cannot be a value of 0. Perhaps the parent object used to instantiate this object has not been persisted to the data store."); + } + return val; + } set { _parentId = new Lazy(() => value); diff --git a/src/Umbraco.Core/Models/ContentExtensions.cs b/src/Umbraco.Core/Models/ContentExtensions.cs index d6c70654ef..2c4b1006c3 100644 --- a/src/Umbraco.Core/Models/ContentExtensions.cs +++ b/src/Umbraco.Core/Models/ContentExtensions.cs @@ -1,7 +1,14 @@ using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; using System.Linq; +using System.Web; +using System.Xml; using System.Xml.Linq; using Umbraco.Core.Configuration; +using Umbraco.Core.IO; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.UnitOfWork; @@ -48,16 +55,295 @@ namespace Umbraco.Core.Models } /// - /// Checks whether an item has any published versions + /// Sets and uploads the file from a HttpPostedFileBase object as the property value /// - /// - /// True if the content has any published versiom otherwise False - public static bool HasPublishedVersion(this IContent content) + /// to add property value to + /// Alias of the property to save the value on + /// The containing the file that will be uploaded + public static void SetValue(this IMedia media, string propertyTypeAlias, HttpPostedFileBase value) { - if (content.HasIdentity == false) - return false; + var name = + IOHelper.SafeFileName( + value.FileName.Substring(value.FileName.LastIndexOf(IOHelper.DirSepChar) + 1, + value.FileName.Length - value.FileName.LastIndexOf(IOHelper.DirSepChar) - 1) + .ToLower()); - return ApplicationContext.Current.Services.ContentService.HasPublishedVersion(content.Id); + if(string.IsNullOrEmpty(name) == false) + SetFileOnContent(media, propertyTypeAlias, name, value.InputStream); + } + + /// + /// Sets and uploads the file from a HttpPostedFile object as the property value + /// + /// to add property value to + /// Alias of the property to save the value on + /// The containing the file that will be uploaded + public static void SetValue(this IMedia media, string propertyTypeAlias, HttpPostedFile value) + { + var name = + IOHelper.SafeFileName( + value.FileName.Substring(value.FileName.LastIndexOf(IOHelper.DirSepChar) + 1, + value.FileName.Length - value.FileName.LastIndexOf(IOHelper.DirSepChar) - 1) + .ToLower()); + + if (string.IsNullOrEmpty(name) == false) + SetFileOnContent(media, propertyTypeAlias, name, value.InputStream); + } + + /// + /// Sets and uploads the file from a HttpPostedFileWrapper object as the property value + /// + /// to add property value to + /// Alias of the property to save the value on + /// The containing the file that will be uploaded + public static void SetValue(this IMedia media, string propertyTypeAlias, HttpPostedFileWrapper value) + { + if (string.IsNullOrEmpty(value.FileName) == false) + SetFileOnContent(media, propertyTypeAlias, value.FileName, value.InputStream); + } + + /// + /// Sets and uploads the file from a HttpPostedFileBase object as the property value + /// + /// to add property value to + /// Alias of the property to save the value on + /// The containing the file that will be uploaded + public static void SetValue(this IContent content, string propertyTypeAlias, HttpPostedFileBase value) + { + var name = + IOHelper.SafeFileName( + value.FileName.Substring(value.FileName.LastIndexOf(IOHelper.DirSepChar) + 1, + value.FileName.Length - value.FileName.LastIndexOf(IOHelper.DirSepChar) - 1) + .ToLower()); + + if (string.IsNullOrEmpty(name) == false) + SetFileOnContent(content, propertyTypeAlias, name, value.InputStream); + } + + /// + /// Sets and uploads the file from a HttpPostedFile object as the property value + /// + /// to add property value to + /// Alias of the property to save the value on + /// The containing the file that will be uploaded + public static void SetValue(this IContent content, string propertyTypeAlias, HttpPostedFile value) + { + var name = + IOHelper.SafeFileName( + value.FileName.Substring(value.FileName.LastIndexOf(IOHelper.DirSepChar) + 1, + value.FileName.Length - value.FileName.LastIndexOf(IOHelper.DirSepChar) - 1) + .ToLower()); + + if (string.IsNullOrEmpty(name) == false) + SetFileOnContent(content, propertyTypeAlias, name, value.InputStream); + } + + /// + /// Sets and uploads the file from a HttpPostedFileWrapper object as the property value + /// + /// to add property value to + /// Alias of the property to save the value on + /// The containing the file that will be uploaded + public static void SetValue(this IContent content, string propertyTypeAlias, HttpPostedFileWrapper value) + { + if (string.IsNullOrEmpty(value.FileName) == false) + SetFileOnContent(content, propertyTypeAlias, value.FileName, value.InputStream); + } + + private static void SetFileOnContent(IContentBase content, string propertyTypeAlias, string name, Stream fileStream) + { + var property = content.Properties.FirstOrDefault(x => x.Alias == propertyTypeAlias); + if(property == null) + return; + + bool supportsResizing = false; + string fileName = UmbracoSettings.UploadAllowDirectories + ? Path.Combine(property.Id.ToString(), name) + : property.Id + "-" + name; + string extension = Path.GetExtension(name); + + var fs = FileSystemProviderManager.Current.GetFileSystemProvider(); + fs.AddFile(fileName, fileStream); + + //Check if file supports resizing and create thumbnails + if (("," + UmbracoSettings.ImageFileTypes + ",").Contains(string.Format(",{0},", extension))) + { + supportsResizing = true; + + // Make default thumbnail + var thumbUrl = Resize(fs, fileName, extension, 100, "thumb"); + + //Look up Prevalues for this upload datatype - if it is an upload datatype + var uploadFieldId = new Guid("5032a6e6-69e3-491d-bb28-cd31cd11086c"); + if (property.PropertyType.DataTypeControlId == uploadFieldId) + { + //Get Prevalues by the DataType's Id: property.PropertyType.DataTypeId + var values = ApplicationContext.Current.Services.DataTypeService.GetPreValuesByDataTypeId(property.PropertyType.DataTypeId); + var thumbnailSizes = values.FirstOrDefault(); + //Additional thumbnails configured as prevalues on the DataType + if (thumbnailSizes != null) + { + char sep = (!thumbnailSizes.Contains("") && thumbnailSizes.Contains(",")) ? ',' : ';'; + + foreach (string thumb in thumbnailSizes.Split(sep)) + { + int thumbSize; + if (thumb != "" && int.TryParse(thumb, out thumbSize)) + { + Resize(fs, fileName, extension, thumbSize, string.Format("thumb_{0}", thumbSize)); + } + } + } + } + } + + //Check for auto fill of additional properties + if (UmbracoSettings.ImageAutoFillImageProperties != null) + { + XmlNode uploadFieldConfigNode = + UmbracoSettings.ImageAutoFillImageProperties.SelectSingleNode( + string.Format("uploadField [@alias = \"{0}\"]", propertyTypeAlias)); + + if (uploadFieldConfigNode != null) + { + //Only add dimensions to web images + if (supportsResizing) + { + SetPropertyValue(content, uploadFieldConfigNode, "widthFieldAlias", GetDimensions(fs, fileName).Item1); + SetPropertyValue(content, uploadFieldConfigNode, "heightFieldAlias", GetDimensions(fs, fileName).Item2); + } + else + { + SetPropertyValue(content, uploadFieldConfigNode, "widthFieldAlias", string.Empty); + SetPropertyValue(content, uploadFieldConfigNode, "heightFieldAlias", string.Empty); + } + + SetPropertyValue(content, uploadFieldConfigNode, "lengthFieldAlias", fs.GetSize(fileName)); + SetPropertyValue(content, uploadFieldConfigNode, "extensionFieldAlias", extension); + } + } + + //Set the value of the property to that of the uploaded file's url + property.Value = fs.GetUrl(fileName); + } + + private static void SetPropertyValue(IContentBase content, XmlNode uploadFieldConfigNode, string propertyAlias, object propertyValue) + { + XmlNode propertyNode = uploadFieldConfigNode.SelectSingleNode(propertyAlias); + if (propertyNode != null && string.IsNullOrEmpty(propertyNode.FirstChild.Value) == false) + { + content.SetValue(propertyNode.FirstChild.Value, propertyValue); + } + } + + private static string Resize(MediaFileSystem fileSystem, string path, string extension, int maxWidthHeight, string fileNameAddition) + { + var fileNameThumb = DoResize(fileSystem, path, extension, GetDimensions(fileSystem, path).Item1, GetDimensions(fileSystem, path).Item2, maxWidthHeight, fileNameAddition); + + return fileSystem.GetUrl(fileNameThumb); + } + + private static Tuple GetDimensions(MediaFileSystem fileSystem, string path) + { + var fs = fileSystem.OpenFile(path); + var image = Image.FromStream(fs); + var fileWidth = image.Width; + var fileHeight = image.Height; + fs.Close(); + image.Dispose(); + + return new Tuple(fileWidth, fileHeight); + } + + private static string DoResize(MediaFileSystem fileSystem, string path, string extension, int width, int height, int maxWidthHeight, string fileNameAddition) + { + var fs = fileSystem.OpenFile(path); + var image = Image.FromStream(fs); + fs.Close(); + + string fileNameThumb = String.IsNullOrEmpty(fileNameAddition) ? + string.Format("{0}_UMBRACOSYSTHUMBNAIL.jpg", path.Substring(0, path.LastIndexOf("."))) : + string.Format("{0}_{1}.jpg", path.Substring(0, path.LastIndexOf(".")), fileNameAddition); + + var thumb = GenerateThumbnail(fileSystem, + image, + maxWidthHeight, + width, + height, + path, + extension, + fileNameThumb, + maxWidthHeight == 0); + + fileNameThumb = thumb.Item3; + + image.Dispose(); + + return fileNameThumb; + } + + private static Tuple GenerateThumbnail(MediaFileSystem fileSystem, Image image, int maxWidthHeight, int fileWidth, + int fileHeight, string fullFilePath, string extension, + string thumbnailFileName, bool useFixedDimensions) + { + // Generate thumbnail + float f = 1; + if (!useFixedDimensions) + { + var fx = (float)image.Size.Width / (float)maxWidthHeight; + var fy = (float)image.Size.Height / (float)maxWidthHeight; + + // must fit in thumbnail size + f = Math.Max(fx, fy); //if (f < 1) f = 1; + } + + var widthTh = (int)Math.Round((float)fileWidth / f); int heightTh = (int)Math.Round((float)fileHeight / f); + + // fixes for empty width or height + if (widthTh == 0) + widthTh = 1; + if (heightTh == 0) + heightTh = 1; + + // Create new image with best quality settings + var bp = new Bitmap(widthTh, heightTh); + var g = Graphics.FromImage(bp); + g.SmoothingMode = SmoothingMode.HighQuality; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.CompositingQuality = CompositingQuality.HighQuality; + + // Copy the old image to the new and resized + var rect = new Rectangle(0, 0, widthTh, heightTh); + g.DrawImage(image, rect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel); + + // Copy metadata + var imageEncoders = ImageCodecInfo.GetImageEncoders(); + ImageCodecInfo codec = null; + if (extension.ToLower() == "png" || extension.ToLower() == "gif") + codec = imageEncoders.Single(t => t.MimeType.Equals("image/png")); + else + codec = imageEncoders.Single(t => t.MimeType.Equals("image/jpeg")); + + + // Set compresion ratio to 90% + var ep = new EncoderParameters(); + ep.Param[0] = new EncoderParameter(Encoder.Quality, 90L); + + // Save the new image using the dimensions of the image + string newFileName = thumbnailFileName.Replace("UMBRACOSYSTHUMBNAIL", + string.Format("{0}x{1}", widthTh, heightTh)); + var ms = new MemoryStream(); + bp.Save(ms, codec, ep); + ms.Seek(0, 0); + + fileSystem.AddFile(newFileName, ms); + + ms.Close(); + bp.Dispose(); + g.Dispose(); + + return new Tuple(widthTh, heightTh, newFileName); } /// diff --git a/src/Umbraco.Core/Models/ContentType.cs b/src/Umbraco.Core/Models/ContentType.cs index e82f27c3b2..edb64622a2 100644 --- a/src/Umbraco.Core/Models/ContentType.cs +++ b/src/Umbraco.Core/Models/ContentType.cs @@ -21,6 +21,11 @@ namespace Umbraco.Core.Models _allowedTemplates = new List(); } + public ContentType(IContentType parent) : base(parent) + { + _allowedTemplates = new List(); + } + private static readonly PropertyInfo DefaultTemplateSelector = ExpressionHelper.GetPropertyInfo(x => x.DefaultTemplateId); private static readonly PropertyInfo AllowedTemplatesSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedTemplates); diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index 03fca722ea..6b01f5b27a 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -33,11 +33,22 @@ namespace Umbraco.Core.Models protected ContentTypeBase(int parentId) { + Mandate.ParameterCondition(parentId != 0, "parentId"); + _parentId = new Lazy(() => parentId); _allowedContentTypes = new List(); _propertyGroups = new PropertyGroupCollection(); } + protected ContentTypeBase(IContentTypeBase parent) + { + Mandate.ParameterNotNull(parent, "parent"); + + _parentId = new Lazy(() => parent.Id); + _allowedContentTypes = new List(); + _propertyGroups = new PropertyGroupCollection(); + } + private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.ParentId); private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo(x => x.SortOrder); @@ -66,7 +77,15 @@ namespace Umbraco.Core.Models [DataMember] public virtual int ParentId { - get { return _parentId.Value; } + get + { + var val = _parentId.Value; + if (val == 0) + { + throw new InvalidOperationException("The ParentId cannot be a value of 0. Perhaps the parent object used to instantiate this object has not been persisted to the data store."); + } + return val; + } set { _parentId = new Lazy(() => value); diff --git a/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs b/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs index e44f7ad2e1..9681e2164e 100644 --- a/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs @@ -13,12 +13,16 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] public abstract class ContentTypeCompositionBase : ContentTypeBase, IContentTypeComposition { - private List _contentTypeComposition = new List(); + private readonly List _contentTypeComposition = new List(); protected ContentTypeCompositionBase(int parentId) : base(parentId) { } + protected ContentTypeCompositionBase(IContentTypeBase parent) : base(parent) + { + } + private static readonly PropertyInfo ContentTypeCompositionSelector = ExpressionHelper.GetPropertyInfo>( x => x.ContentTypeComposition); diff --git a/src/Umbraco.Core/Models/Media.cs b/src/Umbraco.Core/Models/Media.cs index dd2ec17f2a..430d4cd1c6 100644 --- a/src/Umbraco.Core/Models/Media.cs +++ b/src/Umbraco.Core/Models/Media.cs @@ -22,6 +22,18 @@ namespace Umbraco.Core.Models { } + public Media(IMedia parent, IMediaType contentType) + : this(parent, contentType, new PropertyCollection()) + { + } + + public Media(IMedia parent, IMediaType contentType, PropertyCollection properties) + : base(parent, contentType, properties) + { + Mandate.ParameterNotNull(contentType, "contentType"); + _contentType = contentType; + } + /// /// Constructor for creating a Media object /// @@ -30,6 +42,7 @@ namespace Umbraco.Core.Models /// Collection of properties public Media(int parentId, IMediaType contentType, PropertyCollection properties) : base(parentId, contentType, properties) { + Mandate.ParameterNotNull(contentType, "contentType"); _contentType = contentType; } diff --git a/src/Umbraco.Core/Models/MediaType.cs b/src/Umbraco.Core/Models/MediaType.cs index e7521b536d..c734981365 100644 --- a/src/Umbraco.Core/Models/MediaType.cs +++ b/src/Umbraco.Core/Models/MediaType.cs @@ -14,6 +14,10 @@ namespace Umbraco.Core.Models { } + public MediaType(IMediaType parent) : base(parent) + { + } + /// /// Method to call when Entity is being saved /// diff --git a/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs b/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs index b4f328a591..143a4b7fe6 100644 --- a/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs +++ b/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs @@ -142,10 +142,13 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions IsUnique = attribute.IndexType == IndexTypes.UniqueNonClustered }; - var columns = attribute.ForColumns.Split(',').Select(p => p.Trim()); - foreach (var column in columns) + if (string.IsNullOrEmpty(attribute.ForColumns) == false) { - definition.Columns.Add(new IndexColumnDefinition{Name = column, Direction = Direction.Ascending}); + var columns = attribute.ForColumns.Split(',').Select(p => p.Trim()); + foreach (var column in columns) + { + definition.Columns.Add(new IndexColumnDefinition {Name = column, Direction = Direction.Ascending}); + } } return definition; } diff --git a/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/ForeignKeyDefinition.cs b/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/ForeignKeyDefinition.cs index 4d6f1989f3..3012c57b0e 100644 --- a/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/ForeignKeyDefinition.cs +++ b/src/Umbraco.Core/Persistence/DatabaseModelDefinitions/ForeignKeyDefinition.cs @@ -9,6 +9,9 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions { ForeignColumns = new List(); PrimaryColumns = new List(); + //Set to None by Default + OnDelete = Rule.None; + OnUpdate = Rule.None; } public virtual string Name { get; set; } diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs index 7df3463dea..ba13bbcbfe 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs @@ -1,4 +1,5 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions { @@ -15,8 +16,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions public override string ToString() { - //TODO Implement usage of the SqlSyntax provider here to generate the sql statement for this expression. - return TableName + " " + Column.Name + " " + Column.Type ?? Column.CustomType; + return string.Format(SyntaxConfig.SqlSyntaxProvider.AlterColumn, + SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName), + SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(Column.Name)); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterDefaultConstraintExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterDefaultConstraintExpression.cs index a310f850b8..c4c28119ea 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterDefaultConstraintExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterDefaultConstraintExpression.cs @@ -1,3 +1,5 @@ +using Umbraco.Core.Persistence.SqlSyntax; + namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions { public class AlterDefaultConstraintExpression : IMigrationExpression @@ -5,16 +7,16 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions public virtual string SchemaName { get; set; } public virtual string TableName { get; set; } public virtual string ColumnName { get; set; } + public virtual string ConstraintName { get; set; } public virtual object DefaultValue { get; set; } public override string ToString() { - return base.ToString() + - string.Format("{0}.{1} {2} {3}", - SchemaName, - TableName, - ColumnName, - DefaultValue); + //NOTE Should probably investigate if Deleting a Default Constraint is different from deleting a 'regular' constraint + + return string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteConstraint, + SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName), + SyntaxConfig.SqlSyntaxProvider.GetQuotedName(ConstraintName)); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterTableExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterTableExpression.cs index bcff2fbc25..b9482e07e9 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterTableExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterTableExpression.cs @@ -11,7 +11,7 @@ public override string ToString() { - return base.ToString() + TableName; + return string.Format("ALTER TABLE {0}", TableName); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateConstraintExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateConstraintExpression.cs index 32a69e7591..e2d1b0c6e6 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateConstraintExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateConstraintExpression.cs @@ -1,4 +1,6 @@ -using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using System.Linq; +using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions { @@ -13,8 +15,20 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions public override string ToString() { - //TODO replace with sql syntax provider - return base.ToString() + Constraint.ConstraintName; + var constraintType = (Constraint.IsPrimaryKeyConstraint) ? "PRIMARY KEY" : "UNIQUE"; + + string[] columns = new string[Constraint.Columns.Count]; + + for (int i = 0; i < Constraint.Columns.Count; i++) + { + columns[i] = SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(Constraint.Columns.ElementAt(i)); + } + + return string.Format(SyntaxConfig.SqlSyntaxProvider.CreateConstraint, + SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(Constraint.TableName), + SyntaxConfig.SqlSyntaxProvider.GetQuotedName(Constraint.ConstraintName), + constraintType, + string.Join(", ", columns)); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateTableExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateTableExpression.cs index 69c057fd74..8400eeca42 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateTableExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Create/Expressions/CreateTableExpression.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions { @@ -16,8 +17,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions public override string ToString() { - //TODO replace with sql syntax provider - return base.ToString() + TableName; + return string.Format(SyntaxConfig.SqlSyntaxProvider.CreateTable, + SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName), + SyntaxConfig.SqlSyntaxProvider.Format(Columns)); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteColumnExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteColumnExpression.cs index cf11fc7119..a8ec8f3edc 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteColumnExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteColumnExpression.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; using System.Linq; +using System.Text; +using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions { @@ -16,8 +18,16 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions public override string ToString() { - //TODO Change to use sql syntax provider - return base.ToString() + TableName + " " + ColumnNames.Aggregate((a, b) => a + ", " + b); + var sb = new StringBuilder(); + foreach (string columnName in ColumnNames) + { + if (ColumnNames.First() != columnName) sb.AppendLine(";"); + sb.AppendFormat(SyntaxConfig.SqlSyntaxProvider.DropColumn, + SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName), + SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(columnName)); + } + + return sb.ToString(); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteConstraintExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteConstraintExpression.cs index ff449d306c..7833f92ac4 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteConstraintExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteConstraintExpression.cs @@ -1,4 +1,5 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions { @@ -13,8 +14,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions public override string ToString() { - //TODO change to use sql syntax provider - return base.ToString() + Constraint.ConstraintName; + return string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteConstraint, + SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(Constraint.TableName), + SyntaxConfig.SqlSyntaxProvider.GetQuotedName(Constraint.ConstraintName)); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDataExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDataExpression.cs index aa61e8cd6e..a37abf0650 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDataExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDataExpression.cs @@ -1,5 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions { @@ -14,5 +16,35 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions { get { return _rows; } } + + public override string ToString() + { + var deleteItems = new List(); + + if (IsAllRows) + { + deleteItems.Add(string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteData, SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName), "1 = 1")); + } + else + { + foreach (var row in Rows) + { + var whereClauses = new List(); + foreach (KeyValuePair item in row) + { + whereClauses.Add(string.Format("{0} {1} {2}", + SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(item.Key), + item.Value == null ? "IS" : "=", + SyntaxConfig.SqlSyntaxProvider.GetQuotedValue(item.Value.ToString()))); + } + + deleteItems.Add(string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteData, + SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName), + String.Join(" AND ", whereClauses.ToArray()))); + } + } + + return String.Join("; ", deleteItems.ToArray()); + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDefaultConstraintExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDefaultConstraintExpression.cs index 55ee11ca3c..c84d5922da 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDefaultConstraintExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteDefaultConstraintExpression.cs @@ -1,4 +1,6 @@ -namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions { public class DeleteDefaultConstraintExpression : IMigrationExpression { @@ -8,12 +10,9 @@ public override string ToString() { - //TODO Change to use sql syntax provider - return base.ToString() + - string.Format("{0}.{1} {2}", - SchemaName, - TableName, - ColumnName); + return string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteDefaultConstraint, + SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName), + SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(ColumnName)); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteForeignKeyExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteForeignKeyExpression.cs index 3136beefab..8fb4f9e0f7 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteForeignKeyExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteForeignKeyExpression.cs @@ -1,5 +1,6 @@ -using System.Linq; +using System; using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions { @@ -14,10 +15,12 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions public override string ToString() { - //TODO Change to use sql syntax provider - return base.ToString() + ForeignKey.Name + " " - + ForeignKey.ForeignTable + " (" + string.Join(", ", ForeignKey.ForeignColumns.ToArray()) + ") " - + ForeignKey.PrimaryTable + " (" + string.Join(", ", ForeignKey.PrimaryColumns.ToArray()) + ")"; + if (ForeignKey.ForeignTable == null) + throw new ArgumentNullException("Table name not specified, ensure you have appended the OnTable extension. Format should be Delete.ForeignKey(KeyName).OnTable(TableName)"); + + return string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteConstraint, + SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(ForeignKey.ForeignTable), + SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(ForeignKey.Name)); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteIndexExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteIndexExpression.cs index ee9cff2807..38fe9c3563 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteIndexExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteIndexExpression.cs @@ -1,5 +1,5 @@ -using System.Linq; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions { @@ -14,8 +14,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions public override string ToString() { - //TODO Change to use sql syntax provider - return base.ToString() + Index.TableName + " (" + string.Join(", ", Index.Columns.Select(x => x.Name).ToArray()) + ")"; + return string.Format(SyntaxConfig.SqlSyntaxProvider.DropIndex, + SyntaxConfig.SqlSyntaxProvider.GetQuotedName(Index.Name), + SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(Index.TableName)); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteTableExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteTableExpression.cs index 67f2418ec5..017244060f 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteTableExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Delete/Expressions/DeleteTableExpression.cs @@ -1,4 +1,6 @@ -namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions { public class DeleteTableExpression : IMigrationExpression { @@ -7,9 +9,8 @@ public override string ToString() { - //TODO implement the use of sql syntax provider - - return base.ToString() + TableName; + return string.Format(SyntaxConfig.SqlSyntaxProvider.DropTable, + SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName)); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs index 5980bbe75d..31fa681340 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateColumnExpression.cs @@ -1,5 +1,4 @@ -using System; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions @@ -18,10 +17,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions public override string ToString() { - var output = String.Format(SyntaxConfig.SqlSyntaxProvider.AddColumn, - SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName), - SyntaxConfig.SqlSyntaxProvider.Format(Column)); - return output; + return string.Format(SyntaxConfig.SqlSyntaxProvider.AddColumn, + SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName), + SyntaxConfig.SqlSyntaxProvider.Format(Column)); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateForeignKeyExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateForeignKeyExpression.cs index 7dafffcfbd..c9666654b0 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateForeignKeyExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateForeignKeyExpression.cs @@ -1,5 +1,5 @@ -using System.Linq; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions { @@ -14,13 +14,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions public override string ToString() { - return base.ToString() + - string.Format("{0} {1}({2}) {3}({4})", - ForeignKey.Name, - ForeignKey.ForeignTable, - string.Join(", ", ForeignKey.ForeignColumns.ToArray()), - ForeignKey.PrimaryTable, - string.Join(", ", ForeignKey.PrimaryColumns.ToArray())); + return SyntaxConfig.SqlSyntaxProvider.Format(ForeignKey); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateIndexExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateIndexExpression.cs index 3b55c655c4..d15d1a0d97 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateIndexExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Expressions/CreateIndexExpression.cs @@ -1,5 +1,5 @@ -using System.Linq; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions { @@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions public override string ToString() { - return base.ToString() + Index.TableName + " (" + string.Join(", ", Index.Columns.Select(x => x.Name).ToArray()) + ")"; + return SyntaxConfig.SqlSyntaxProvider.Format(Index); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameColumnExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameColumnExpression.cs index 62edf37851..795b65c0ef 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameColumnExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameColumnExpression.cs @@ -1,4 +1,6 @@ -namespace Umbraco.Core.Persistence.Migrations.Syntax.Rename.Expressions +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Core.Persistence.Migrations.Syntax.Rename.Expressions { public class RenameColumnExpression : IMigrationExpression { @@ -9,8 +11,7 @@ public override string ToString() { - //TODO Implement usage of sql syntax provider - return base.ToString() + TableName + " " + OldName + " to " + NewName; + return SyntaxConfig.SqlSyntaxProvider.FormatColumnRename(TableName, OldName, NewName); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameTableExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameTableExpression.cs index 28e733f949..3e3c5d8aee 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameTableExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Rename/Expressions/RenameTableExpression.cs @@ -1,4 +1,6 @@ -namespace Umbraco.Core.Persistence.Migrations.Syntax.Rename.Expressions +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Core.Persistence.Migrations.Syntax.Rename.Expressions { public class RenameTableExpression : IMigrationExpression { @@ -8,8 +10,7 @@ public override string ToString() { - //TODO Implement usage of sql syntax provider - return base.ToString() + OldName + " " + NewName; + return SyntaxConfig.SqlSyntaxProvider.FormatTableRename(OldName, NewName); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/Expressions/UpdateDataExpression.cs b/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/Expressions/UpdateDataExpression.cs index 06e78f7106..cac88440e8 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/Expressions/UpdateDataExpression.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Syntax/Update/Expressions/UpdateDataExpression.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Syntax.Update.Expressions { @@ -10,5 +11,37 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Update.Expressions public List> Set { get; set; } public List> Where { get; set; } public bool IsAllRows { get; set; } + + public override string ToString() + { + var updateItems = new List(); + var whereClauses = new List(); + + foreach (var item in Set) + { + updateItems.Add(string.Format("{0} = {1}", + SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(item.Key), + SyntaxConfig.SqlSyntaxProvider.GetQuotedValue(item.Value.ToString()))); + } + + if (IsAllRows) + { + whereClauses.Add("1 = 1"); + } + else + { + foreach (var item in Where) + { + whereClauses.Add(string.Format("{0} {1} {2}", + SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(item.Key), + item.Value == null ? "IS" : "=", + SyntaxConfig.SqlSyntaxProvider.GetQuotedValue(item.Value.ToString()))); + } + } + return string.Format(SyntaxConfig.SqlSyntaxProvider.UpdateData, + SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName), + string.Join(", ", updateItems.ToArray()), + string.Join(" AND ", whereClauses.ToArray())); + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs b/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs index aed50a889e..8d8157f062 100644 --- a/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs +++ b/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs @@ -1,8 +1,9 @@ using System; +using System.Linq; using Umbraco.Core.Logging; +using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Migrations.Initial; using Umbraco.Core.Persistence.SqlSyntax; -using Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions; namespace Umbraco.Core.Persistence { @@ -28,15 +29,13 @@ namespace Umbraco.Core.Persistence public static void CreateTable(this Database db, bool overwrite, Type modelType) { - //TODO The line below should be refactored to use 'Umbraco.Core.Persistence.DatabaseModelDefinitions.DefinitionFactory.GetTableDefinition(modelType)' - //But first the sql syntax provider should be updated/refactored to format sql statements using the 'new' definitions from the DatabaseModelDefinitions-namespace. var tableDefinition = DefinitionFactory.GetTableDefinition(modelType); - var tableName = tableDefinition.TableName; + var tableName = tableDefinition.Name; - string createSql = SyntaxConfig.SqlSyntaxProvider.ToCreateTableStatement(tableDefinition); - string createPrimaryKeySql = SyntaxConfig.SqlSyntaxProvider.ToCreatePrimaryKeyStatement(tableDefinition); - var foreignSql = SyntaxConfig.SqlSyntaxProvider.ToCreateForeignKeyStatements(tableDefinition); - var indexSql = SyntaxConfig.SqlSyntaxProvider.ToCreateIndexStatements(tableDefinition); + string createSql = SyntaxConfig.SqlSyntaxProvider.Format(tableDefinition); + string createPrimaryKeySql = SyntaxConfig.SqlSyntaxProvider.FormatPrimaryKey(tableDefinition); + var foreignSql = SyntaxConfig.SqlSyntaxProvider.Format(tableDefinition.ForeignKeys); + var indexSql = SyntaxConfig.SqlSyntaxProvider.Format(tableDefinition.Indexes); var tableExist = db.TableExist(tableName); if (overwrite && tableExist) @@ -50,10 +49,14 @@ namespace Umbraco.Core.Persistence { //Execute the Create Table sql int created = db.Execute(new Sql(createSql)); + LogHelper.Info(string.Format("Create Table sql {0}:\n {1}", created, createSql)); //If any statements exists for the primary key execute them here if (!string.IsNullOrEmpty(createPrimaryKeySql)) - db.Execute(new Sql(createPrimaryKeySql)); + { + int createdPk = db.Execute(new Sql(createPrimaryKeySql)); + LogHelper.Info(string.Format("Primary Key sql {0}:\n {1}", createdPk, createPrimaryKeySql)); + } //Fires the NewTable event, which is used internally to insert base data before adding constrants to the schema if (NewTable != null) @@ -61,14 +64,14 @@ namespace Umbraco.Core.Persistence var e = new TableCreationEventArgs(); //Turn on identity insert if db provider is not mysql - if (ApplicationContext.Current.DatabaseContext.ProviderName.Contains("MySql") == false && tableDefinition.IsIdentity) + if (ApplicationContext.Current.DatabaseContext.ProviderName.Contains("MySql") == false && tableDefinition.Columns.Any(x => x.IsIdentity)) db.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName)))); //Call the NewTable-event to trigger the insert of base/default data NewTable(tableName, db, e); //Turn off identity insert if db provider is not mysql - if (ApplicationContext.Current.DatabaseContext.ProviderName.Contains("MySql") == false && tableDefinition.IsIdentity) + if (ApplicationContext.Current.DatabaseContext.ProviderName.Contains("MySql") == false && tableDefinition.Columns.Any(x => x.IsIdentity)) db.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF;", SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName)))); } @@ -76,23 +79,25 @@ namespace Umbraco.Core.Persistence foreach (var sql in foreignSql) { int createdFk = db.Execute(new Sql(sql)); + LogHelper.Info(string.Format("Create Foreign Key sql {0}:\n {1}", createdFk, sql)); } //Loop through index statements and execute sql foreach (var sql in indexSql) { int createdIndex = db.Execute(new Sql(sql)); + LogHelper.Info(string.Format("Create Index sql {0}:\n {1}", createdIndex, sql)); } //Specific to Sql Ce - look for changes to Identity Seed - if (ApplicationContext.Current.DatabaseContext.ProviderName.Contains("SqlServerCe")) - { - var seedSql = SyntaxConfig.SqlSyntaxProvider.ToAlterIdentitySeedStatements(tableDefinition); - foreach (var sql in seedSql) - { - int createdSeed = db.Execute(new Sql(sql)); - } - } + //if (ApplicationContext.Current.DatabaseContext.ProviderName.Contains("SqlServerCe")) + //{ + // var seedSql = SyntaxConfig.SqlSyntaxProvider.ToAlterIdentitySeedStatements(tableDefinition); + // foreach (var sql in seedSql) + // { + // int createdSeed = db.Execute(new Sql(sql)); + // } + //} transaction.Complete(); } diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs index 6930f9d9d8..b59bcf3ec8 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs @@ -1,8 +1,6 @@ -using System; using System.Collections.Generic; -using System.Data; using Umbraco.Core.Persistence.DatabaseAnnotations; -using Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions; +using Umbraco.Core.Persistence.DatabaseModelDefinitions; namespace Umbraco.Core.Persistence.SqlSyntax { @@ -15,17 +13,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax string GetQuotedColumnName(string columnName); string GetQuotedName(string name); bool DoesTableExist(Database db, string tableName); - string ToCreateTableStatement(TableDefinition tableDefinition); - List ToCreateForeignKeyStatements(TableDefinition tableDefinition); - List ToCreateIndexStatements(TableDefinition tableDefinition); - DbType GetColumnDbType(Type valueType); string GetIndexType(IndexTypes indexTypes); - string GetColumnDefinition(ColumnDefinition column, string tableName); - string GetPrimaryKeyStatement(ColumnDefinition column, string tableName); - string ToCreatePrimaryKeyStatement(TableDefinition table); string GetSpecialDbType(SpecialDbTypes dbTypes); - string GetConstraintDefinition(ColumnDefinition column, string tableName); - List ToAlterIdentitySeedStatements(TableDefinition table); string CreateTable { get; } string DropTable { get; } string AddColumn { get; } @@ -44,6 +33,17 @@ namespace Umbraco.Core.Persistence.SqlSyntax string CreateConstraint { get; } string DeleteConstraint { get; } string CreateForeignKeyConstraint { get; } - string Format(DatabaseModelDefinitions.ColumnDefinition column); + string DeleteDefaultConstraint { get; } + string Format(TableDefinition table); + string Format(IEnumerable columns); + List Format(IEnumerable indexes); + List Format(IEnumerable foreignKeys); + string FormatPrimaryKey(TableDefinition table); + string GetQuotedValue(string value); + string Format(ColumnDefinition column); + string Format(IndexDefinition index); + string Format(ForeignKeyDefinition foreignKey); + string FormatColumnRename(string tableName, string oldName, string newName); + string FormatTableRename(string oldName, string newName); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/ColumnDefinition.cs b/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/ColumnDefinition.cs deleted file mode 100644 index 71e1826d8e..0000000000 --- a/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/ColumnDefinition.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using Umbraco.Core.Persistence.DatabaseAnnotations; - -namespace Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions -{ - public class ColumnDefinition - { - public string ColumnName { get; set; } - - public Type PropertyType { get; set; } - public bool HasSpecialDbType { get; set; } - public SpecialDbTypes DbType { get; set; } - public int? DbTypeLength { get; set; } - - public bool IsNullable { get; set; } - - public bool IsPrimaryKey { get; set; } - public bool IsPrimaryKeyIdentityColumn { get; set; } - public bool IsPrimaryKeyClustered { get; set; } - public string PrimaryKeyName { get; set; } - public string PrimaryKeyColumns { get; set; } - public int PrimaryKeySeeding { get; set; } - - public string ConstraintName { get; set; } - public string ConstraintDefaultValue { get; set; } - public bool HasConstraint - { - get { return !string.IsNullOrEmpty(ConstraintName) || !string.IsNullOrEmpty(ConstraintDefaultValue); } - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/DefinitionFactory.cs b/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/DefinitionFactory.cs deleted file mode 100644 index 4e5666bbeb..0000000000 --- a/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/DefinitionFactory.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System; -using System.Linq; -using Umbraco.Core.Persistence.DatabaseAnnotations; - -namespace Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions -{ - public static class DefinitionFactory - { - public static TableDefinition GetTableDefinition(Type modelType) - { - var tableNameAttribute = modelType.FirstAttribute(); - string tableName = tableNameAttribute.Value; - - var tableDefinition = new TableDefinition { TableName = tableName }; - var objProperties = modelType.GetProperties().ToList(); - foreach (var propertyInfo in objProperties) - { - //If current property has an IgnoreAttribute then skip it - var ignoreAttribute = propertyInfo.FirstAttribute(); - if (ignoreAttribute != null) continue; - - //If current property has a ResultColumnAttribute then skip it - var resultColumnAttribute = propertyInfo.FirstAttribute(); - if (resultColumnAttribute != null) continue; - - //Looks for ColumnAttribute with the name of the column, which would exist with ExplicitColumns - //Otherwise use the name of the property itself as the default convention - var columnAttribute = propertyInfo.FirstAttribute(); - string columnName = columnAttribute != null ? columnAttribute.Name : propertyInfo.Name; - - //Use PetaPoco's PrimaryKeyAttribute to set Identity property on TableDefinition - var primaryKeyAttribute = modelType.FirstAttribute(); - tableDefinition.IsIdentity = primaryKeyAttribute != null && primaryKeyAttribute.autoIncrement; - - //Creates a column definition and adds it to the collection on the table definition - var columnDefinition = new ColumnDefinition - { - ColumnName = columnName, - PropertyType = propertyInfo.PropertyType - }; - - //Look for specific DbType attributed a column - var databaseTypeAttribute = propertyInfo.FirstAttribute(); - if (databaseTypeAttribute != null) - { - columnDefinition.HasSpecialDbType = true; - columnDefinition.DbType = databaseTypeAttribute.DatabaseType; - } - - var lengthAttribute = propertyInfo.FirstAttribute(); - if(lengthAttribute != null) - { - columnDefinition.DbTypeLength = lengthAttribute.Length; - } - - //Look for specific Null setting attributed a column - var nullSettingAttribute = propertyInfo.FirstAttribute(); - if (nullSettingAttribute != null) - { - columnDefinition.IsNullable = nullSettingAttribute.NullSetting == NullSettings.Null; - } - - //Look for Primary Key for the current column - var primaryKeyColumnAttribute = propertyInfo.FirstAttribute(); - if (primaryKeyColumnAttribute != null) - { - columnDefinition.IsPrimaryKey = true; - columnDefinition.IsPrimaryKeyIdentityColumn = primaryKeyColumnAttribute.AutoIncrement; - columnDefinition.IsPrimaryKeyClustered = primaryKeyColumnAttribute.Clustered; - columnDefinition.PrimaryKeyName = primaryKeyColumnAttribute.Name ?? string.Empty; - columnDefinition.PrimaryKeyColumns = primaryKeyColumnAttribute.OnColumns ?? string.Empty; - columnDefinition.PrimaryKeySeeding = primaryKeyColumnAttribute.IdentitySeed; - } - - //Look for Constraint for the current column - var constraintAttribute = propertyInfo.FirstAttribute(); - if (constraintAttribute != null) - { - columnDefinition.ConstraintName = constraintAttribute.Name ?? string.Empty; - columnDefinition.ConstraintDefaultValue = constraintAttribute.Default ?? string.Empty; - } - - tableDefinition.ColumnDefinitions.Add(columnDefinition); - - //Creates a foreignkey definition and adds it to the collection on the table definition - var foreignKeyAttributes = propertyInfo.MultipleAttribute(); - if (foreignKeyAttributes != null) - { - foreach (var foreignKeyAttribute in foreignKeyAttributes) - { - var referencedTable = foreignKeyAttribute.Type.FirstAttribute(); - var referencedPrimaryKey = foreignKeyAttribute.Type.FirstAttribute(); - - string referencedColumn = string.IsNullOrEmpty(foreignKeyAttribute.Column) - ? referencedPrimaryKey.Value - : foreignKeyAttribute.Column; - - var foreignKeyDefinition = new ForeignKeyDefinition - { - ColumnName = columnName, - ConstraintName = foreignKeyAttribute.Name, - ReferencedColumnName = referencedColumn, - ReferencedTableName = referencedTable.Value - }; - tableDefinition.ForeignKeyDefinitions.Add(foreignKeyDefinition); - } - } - - //Creates an index definition and adds it to the collection on the table definition - var indexAttribute = propertyInfo.FirstAttribute(); - if (indexAttribute != null) - { - var indexDefinition = new IndexDefinition - { - ColumnNames = indexAttribute.ForColumns, - IndexName = indexAttribute.Name, - IndexType = indexAttribute.IndexType, - IndexForColumn = columnName - }; - tableDefinition.IndexDefinitions.Add(indexDefinition); - } - } - - return tableDefinition; - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/ForeignKeyDefinition.cs b/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/ForeignKeyDefinition.cs deleted file mode 100644 index 06ce016134..0000000000 --- a/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/ForeignKeyDefinition.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions -{ - public class ForeignKeyDefinition - { - public string ConstraintName { get; set; } - public string ColumnName { get; set; } - public string ReferencedTableName { get; set; } - public string ReferencedColumnName { get; set; } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/IndexDefinition.cs b/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/IndexDefinition.cs deleted file mode 100644 index 835a97e746..0000000000 --- a/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/IndexDefinition.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Umbraco.Core.Persistence.DatabaseAnnotations; - -namespace Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions -{ - public class IndexDefinition - { - public string IndexName { get; set; } - public IndexTypes IndexType { get; set; } - public string ColumnNames { get; set; } - public string IndexForColumn { get; set; } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/TableDefinition.cs b/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/TableDefinition.cs deleted file mode 100644 index dfdacc1fbe..0000000000 --- a/src/Umbraco.Core/Persistence/SqlSyntax/ModelDefinitions/TableDefinition.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions -{ - public class TableDefinition - { - public TableDefinition() - { - ColumnDefinitions = new List(); - ForeignKeyDefinitions = new List(); - IndexDefinitions = new List(); - } - - public string TableName { get; set; } - public bool IsIdentity { get; set; } - public bool IsPrimaryKeyClustered - { - get { return ColumnDefinitions.Any(x => x.IsPrimaryKeyClustered); } - } - public string PrimaryKeyName - { - get { return ColumnDefinitions.First(x => x.IsPrimaryKey).PrimaryKeyName ?? string.Empty; } - } - public string PrimaryKeyColumns - { - get { return ColumnDefinitions.First(x => x.IsPrimaryKey).PrimaryKeyColumns ?? string.Empty; } - } - - public List ColumnDefinitions { get; set; } - public List ForeignKeyDefinitions { get; set; } - public List IndexDefinitions { get; set; } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs index 3c484a8ebf..a17b2339e3 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs @@ -1,9 +1,7 @@ -using System.Collections.Generic; -using System.Text; +using System; +using System.Linq; using Umbraco.Core.Persistence.DatabaseAnnotations; using Umbraco.Core.Persistence.DatabaseModelDefinitions; -using ColumnDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.ColumnDefinition; -using TableDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.TableDefinition; namespace Umbraco.Core.Persistence.SqlSyntax { @@ -67,96 +65,20 @@ namespace Umbraco.Core.Persistence.SqlSyntax return "NVARCHAR"; } - public override string GetConstraintDefinition(ColumnDefinition column, string tableName) + public override string Format(IndexDefinition index) { - var sql = new StringBuilder(); + string name = string.IsNullOrEmpty(index.Name) + ? string.Format("IX_{0}_{1}", index.TableName, index.ColumnName) + : index.Name; - if (column.ConstraintDefaultValue.Equals("getdate()")) - { - sql.Append(" DEFAULT CURRENT_TIMESTAMP"); - } - else - { - sql.AppendFormat(DefaultValueFormat, column.ConstraintDefaultValue); - } + string columns = index.Columns.Any() + ? string.Join(",", index.Columns.Select(x => GetQuotedColumnName(x.Name))) + : GetQuotedColumnName(index.ColumnName); - return sql.ToString(); - } - - public override string GetColumnDefinition(ColumnDefinition column, string tableName) - { - string dbTypeDefinition; - if (column.HasSpecialDbType) - { - if (column.DbTypeLength.HasValue) - { - dbTypeDefinition = string.Format("{0}({1})", - GetSpecialDbType(column.DbType), - column.DbTypeLength.Value); - } - else - { - dbTypeDefinition = GetSpecialDbType(column.DbType); - } - } - else if (column.PropertyType == typeof(string)) - { - dbTypeDefinition = string.Format(StringLengthColumnDefinitionFormat, column.DbTypeLength.GetValueOrDefault(DefaultStringLength)); - } - else - { - if (!DbTypeMap.ColumnTypeMap.TryGetValue(column.PropertyType, out dbTypeDefinition)) - { - dbTypeDefinition = ""; - } - } - - var sql = new StringBuilder(); - sql.AppendFormat("{0} {1}", GetQuotedColumnName(column.ColumnName), dbTypeDefinition); - - if (column.IsPrimaryKeyIdentityColumn) - { - sql.Append(" NOT NULL PRIMARY KEY ").Append(AutoIncrementDefinition); - } - else - { - sql.Append(column.IsNullable ? " NULL" : " NOT NULL"); - } - - if (column.HasConstraint) - { - sql.Append(GetConstraintDefinition(column, tableName)); - sql = sql.Replace("DATETIME", "TIMESTAMP"); - } - - return sql.ToString(); - } - - public override string GetPrimaryKeyStatement(ColumnDefinition column, string tableName) - { - return string.Empty; - } - - public override List ToCreateIndexStatements(TableDefinition table) - { - var indexes = new List(); - - foreach (var index in table.IndexDefinitions) - { - string name = string.IsNullOrEmpty(index.IndexName) - ? string.Format("IX_{0}_{1}", table.TableName, index.IndexForColumn) - : index.IndexName; - - string columns = string.IsNullOrEmpty(index.ColumnNames) - ? GetQuotedColumnName(index.IndexForColumn) - : index.ColumnNames; - - indexes.Add(string.Format("CREATE INDEX {0} ON {1} ({2}); \n", - GetQuotedName(name), - GetQuotedTableName(table.TableName), - columns)); - } - return indexes; + return string.Format(CreateIndex, + GetQuotedName(name), + GetQuotedTableName(index.TableName), + columns); } public override bool DoesTableExist(Database db, string tableName) @@ -170,11 +92,40 @@ namespace Umbraco.Core.Persistence.SqlSyntax return result > 0; } - protected override string FormatIdentity(DatabaseModelDefinitions.ColumnDefinition column) + protected override string FormatIdentity(ColumnDefinition column) { return column.IsIdentity ? AutoIncrementDefinition : string.Empty; } + protected override string FormatDefaultValue(ColumnDefinition column) + { + if (column.DefaultValue == null) + return string.Empty; + + // see if this is for a system method + if (column.DefaultValue is SystemMethods) + { + string method = FormatSystemMethods((SystemMethods)column.DefaultValue); + if (string.IsNullOrEmpty(method)) + return string.Empty; + + return string.Format(DefaultValueFormat, method); + } + + if (column.DefaultValue.ToString().Equals("getdate()")) + return "DEFAULT CURRENT_TIMESTAMP"; + + return string.Format(DefaultValueFormat, column.DefaultValue); + } + + protected override string FormatPrimaryKey(ColumnDefinition column) + { + if(column.IsPrimaryKey) + return "PRIMARY KEY"; + + return string.Empty; + } + protected override string FormatSystemMethods(SystemMethods systemMethod) { switch (systemMethod) @@ -192,10 +143,22 @@ namespace Umbraco.Core.Persistence.SqlSyntax return null; } + public override string DeleteDefaultConstraint + { + get + { + throw new NotSupportedException("Default constraints are not supported in MySql"); + } + } + public override string AlterColumn { get { return "ALTER TABLE {0} MODIFY COLUMN {1}"; } } public override string DeleteConstraint { get { return "ALTER TABLE {0} DROP {1}{2}"; } } + public override string DropIndex { get { return "DROP INDEX {0} ON {1}"; } } + public override string CreateTable { get { return "CREATE TABLE {0} ({1}) ENGINE = INNODB"; } } + + public override string CreateIndex { get { return "CREATE INDEX {0} ON {1} ({2})"; } } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs index 13f41903d7..6fb5a123c5 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs @@ -1,6 +1,6 @@ -using Umbraco.Core.Persistence.DatabaseAnnotations; +using System.Linq; +using Umbraco.Core.Persistence.DatabaseAnnotations; using Umbraco.Core.Persistence.DatabaseModelDefinitions; -using ColumnDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.ColumnDefinition; namespace Umbraco.Core.Persistence.SqlSyntax { @@ -68,22 +68,25 @@ namespace Umbraco.Core.Persistence.SqlSyntax return string.Format("[{0}]", name); } - public override string GetPrimaryKeyStatement(ColumnDefinition column, string tableName) + public override string FormatPrimaryKey(TableDefinition table) { - string constraintName = string.IsNullOrEmpty(column.PrimaryKeyName) - ? string.Format("PK_{0}", tableName) - : column.PrimaryKeyName; + var columnDefinition = table.Columns.FirstOrDefault(x => x.IsPrimaryKey); + if (columnDefinition == null) + return string.Empty; - string columns = string.IsNullOrEmpty(column.PrimaryKeyColumns) - ? GetQuotedColumnName(column.ColumnName) - : column.PrimaryKeyColumns; + string constraintName = string.IsNullOrEmpty(columnDefinition.PrimaryKeyName) + ? string.Format("PK_{0}", table.Name) + : columnDefinition.PrimaryKeyName; - string sql = string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY ({2}); \n", - GetQuotedTableName(tableName), - GetQuotedName(constraintName), - columns); + string columns = string.IsNullOrEmpty(columnDefinition.PrimaryKeyColumns) + ? GetQuotedColumnName(columnDefinition.Name) + : columnDefinition.PrimaryKeyColumns; - return sql; + return string.Format(CreateConstraint, + GetQuotedTableName(table.Name), + GetQuotedName(constraintName), + "PRIMARY KEY", + columns); } public override bool DoesTableExist(Database db, string tableName) @@ -95,13 +98,16 @@ namespace Umbraco.Core.Persistence.SqlSyntax return result > 0; } - protected override string FormatIdentity(DatabaseModelDefinitions.ColumnDefinition column) + protected override string FormatIdentity(ColumnDefinition column) { return column.IsIdentity ? GetIdentityString(column) : string.Empty; } - private static string GetIdentityString(DatabaseModelDefinitions.ColumnDefinition column) + private static string GetIdentityString(ColumnDefinition column) { + if (column.Seeding != default(int)) + return string.Format("IDENTITY({0},1)", column.Seeding); + return "IDENTITY(1,1)"; } @@ -123,5 +129,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax } public override string AddColumn { get { return "ALTER TABLE {0} ADD {1}"; } } + + public override string DropIndex { get { return "DROP INDEX {1}.{0}"; } } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs index 527ad161b6..995320a037 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs @@ -34,6 +34,21 @@ namespace Umbraco.Core.Persistence.SqlSyntax InitColumnTypeMap(); } + public override string GetQuotedTableName(string tableName) + { + return string.Format("[{0}]", tableName); + } + + public override string GetQuotedColumnName(string columnName) + { + return string.Format("[{0}]", columnName); + } + + public override string GetQuotedName(string name) + { + return string.Format("[{0}]", name); + } + public override bool DoesTableExist(Database db, string tableName) { var result = @@ -43,6 +58,16 @@ namespace Umbraco.Core.Persistence.SqlSyntax return result > 0; } + public override string FormatColumnRename(string tableName, string oldName, string newName) + { + return string.Format(RenameColumn, tableName, oldName, newName); + } + + public override string FormatTableRename(string oldName, string newName) + { + return string.Format(RenameTable, oldName, newName); + } + protected override string FormatIdentity(ColumnDefinition column) { return column.IsIdentity ? GetIdentityString(column) : string.Empty; @@ -70,6 +95,34 @@ namespace Umbraco.Core.Persistence.SqlSyntax return null; } + public override string DeleteDefaultConstraint + { + get + { + return "DECLARE @default sysname, @sql nvarchar(max);\r\n\r\n" + + "-- get name of default constraint\r\n" + + "SELECT @default = name\r\n" + + "FROM sys.default_constraints\r\n" + + "WHERE parent_object_id = object_id('{0}')\r\n" + "" + + "AND type = 'D'\r\n" + "" + + "AND parent_column_id = (\r\n" + "" + + "SELECT column_id\r\n" + + "FROM sys.columns\r\n" + + "WHERE object_id = object_id('{0}')\r\n" + + "AND name = '{1}'\r\n" + + ");\r\n\r\n" + + "-- create alter table command to drop contraint as string and run it\r\n" + + "SET @sql = N'ALTER TABLE {0} DROP CONSTRAINT ' + @default;\r\n" + + "EXEC sp_executesql @sql;"; + } + } + public override string AddColumn { get { return "ALTER TABLE {0} ADD {1}"; } } + + public override string DropIndex { get { return "DROP INDEX {0} ON {1}"; } } + + public override string RenameColumn { get { return "sp_rename '{0}.{1}', '{2}', 'COLUMN'"; } } + + public override string RenameTable { get { return "sp_rename '{0}', '{1}'"; } } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs index 5e0bd84f4f..15b84189a0 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs @@ -5,8 +5,6 @@ using System.Linq; using System.Text; using Umbraco.Core.Persistence.DatabaseAnnotations; using Umbraco.Core.Persistence.DatabaseModelDefinitions; -using ColumnDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.ColumnDefinition; -using TableDefinition = Umbraco.Core.Persistence.SqlSyntax.ModelDefinitions.TableDefinition; namespace Umbraco.Core.Persistence.SqlSyntax { @@ -22,11 +20,12 @@ namespace Umbraco.Core.Persistence.SqlSyntax { protected SqlSyntaxProviderBase() { - ClauseOrder = new List> + ClauseOrder = new List> { FormatString, FormatType, FormatNullable, + FormatConstraint, FormatDefaultValue, FormatPrimaryKey, FormatIdentity @@ -36,7 +35,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax public string StringLengthNonUnicodeColumnDefinitionFormat = "VARCHAR({0})"; public string StringLengthUnicodeColumnDefinitionFormat = "NVARCHAR({0})"; - public string DefaultValueFormat = " DEFAULT ({0})"; + public string DefaultValueFormat = "DEFAULT ({0})"; public int DefaultStringLength = 255; //Set by Constructor @@ -54,7 +53,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax public string DateTimeColumnDefinition = "DATETIME"; public string TimeColumnDefinition = "DATETIME"; - protected IList> ClauseOrder { get; set; } + protected IList> ClauseOrder { get; set; } protected DbTypes DbTypeMap = new DbTypes(); protected void InitColumnTypeMap() @@ -152,190 +151,69 @@ namespace Umbraco.Core.Persistence.SqlSyntax return "NVARCHAR"; } - public virtual string GetColumnDefinition(ColumnDefinition column, string tableName) - { - string dbTypeDefinition; - if (column.HasSpecialDbType) - { - if (column.DbTypeLength.HasValue) - { - dbTypeDefinition = string.Format("{0}({1})", - GetSpecialDbType(column.DbType), - column.DbTypeLength.Value); - } - else - { - dbTypeDefinition = GetSpecialDbType(column.DbType); - } - } - else if (column.PropertyType == typeof(string)) - { - dbTypeDefinition = string.Format(StringLengthColumnDefinitionFormat, column.DbTypeLength.GetValueOrDefault(DefaultStringLength)); - } - else - { - if (!DbTypeMap.ColumnTypeMap.TryGetValue(column.PropertyType, out dbTypeDefinition)) - { - dbTypeDefinition = ""; - } - } - - var sql = new StringBuilder(); - sql.AppendFormat("{0} {1}", GetQuotedColumnName(column.ColumnName), dbTypeDefinition); - - if (column.IsPrimaryKeyIdentityColumn) - { - sql.Append(" NOT NULL ").Append(AutoIncrementDefinition); - } - else - { - sql.Append(column.IsNullable ? " NULL" : " NOT NULL"); - } - - if(column.HasConstraint) - { - sql.Append(GetConstraintDefinition(column, tableName)); - } - - return sql.ToString(); - } - - public virtual string GetConstraintDefinition(ColumnDefinition column, string tableName) - { - var sql = new StringBuilder(); - sql.AppendFormat(" CONSTRAINT {0}", - string.IsNullOrEmpty(column.ConstraintName) - ? GetQuotedName(string.Format("DF_{0}_{1}", tableName, column.ColumnName)) - : column.ConstraintName); - - string value = column.PropertyType == typeof (string) - ? GetQuotedValue(column.ConstraintDefaultValue) - : column.ConstraintDefaultValue; - - sql.AppendFormat(DefaultValueFormat, value); - return sql.ToString(); - } - - public virtual string GetPrimaryKeyStatement(ColumnDefinition column, string tableName) - { - string constraintName = string.IsNullOrEmpty(column.PrimaryKeyName) - ? string.Format("PK_{0}", tableName) - : column.PrimaryKeyName; - - string columns = string.IsNullOrEmpty(column.PrimaryKeyColumns) - ? GetQuotedColumnName(column.ColumnName) - : column.PrimaryKeyColumns; - - string sql = string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY {2} ({3}); \n", - GetQuotedTableName(tableName), - GetQuotedName(constraintName), - column.IsPrimaryKeyClustered ? "CLUSTERED" : "NONCLUSTERED", - columns); - return sql; - } - - public virtual string ToCreateTableStatement(TableDefinition table) - { - var columns = new StringBuilder(); - - foreach (var column in table.ColumnDefinitions) - { - columns.Append(GetColumnDefinition(column, table.TableName) + ", \n"); - } - - string sql = string.Format("CREATE TABLE {0} \n(\n {1} \n); \n", - table.TableName, - columns.ToString().TrimEnd(", \n".ToCharArray())); - - return sql; - } - - public virtual string ToCreatePrimaryKeyStatement(TableDefinition table) - { - var columnDefinition = table.ColumnDefinitions.FirstOrDefault(x => x.IsPrimaryKey); - if (columnDefinition == null) - return string.Empty; - - var sql = GetPrimaryKeyStatement(columnDefinition, table.TableName); - return sql; - } - - public virtual List ToCreateForeignKeyStatements(TableDefinition table) - { - var foreignKeys = new List(); - - foreach (var key in table.ForeignKeyDefinitions) - { - string constraintName = string.IsNullOrEmpty(key.ConstraintName) - ? string.Format("FK_{0}_{1}_{2}", table.TableName, key.ReferencedTableName, key.ReferencedColumnName) - : key.ConstraintName; - - foreignKeys.Add(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}); \n", - GetQuotedTableName(table.TableName), - GetQuotedName(constraintName), - GetQuotedColumnName(key.ColumnName), - GetQuotedTableName(key.ReferencedTableName), - GetQuotedColumnName(key.ReferencedColumnName))); - } - - return foreignKeys; - } - - public virtual List ToCreateIndexStatements(TableDefinition table) - { - var indexes = new List(); - - foreach (var index in table.IndexDefinitions) - { - string name = string.IsNullOrEmpty(index.IndexName) - ? string.Format("IX_{0}_{1}", table.TableName, index.IndexForColumn) - : index.IndexName; - - string columns = string.IsNullOrEmpty(index.ColumnNames) - ? GetQuotedColumnName(index.IndexForColumn) - : index.ColumnNames; - - indexes.Add(string.Format("CREATE {0} INDEX {1} ON {2} ({3}); \n", - GetIndexType(index.IndexType), - GetQuotedName(name), - GetQuotedTableName(table.TableName), - columns)); - } - return indexes; - } - - public virtual List ToAlterIdentitySeedStatements(TableDefinition table) - { - var seeds = new List(); - - foreach (var definition in table.ColumnDefinitions) - { - if (definition.PrimaryKeySeeding > 0) - { - seeds.Add(string.Format("ALTER TABLE {0} ALTER COLUMN {1} IDENTITY({2},1); \n", - GetQuotedTableName(table.TableName), - GetQuotedColumnName(definition.ColumnName), - definition.PrimaryKeySeeding)); - } - } - - return seeds; - } - public virtual bool DoesTableExist(Database db, string tableName) { return false; } - public virtual DbType GetColumnDbType(Type valueType) + public virtual string Format(TableDefinition table) { - if (valueType.IsEnum) - return DbTypeMap.ColumnDbTypeMap[typeof(string)]; + var statement = string.Format(CreateTable, GetQuotedTableName(table.Name), Format(table.Columns)); - return DbTypeMap.ColumnDbTypeMap[valueType]; + return statement; } - public virtual string Format(DatabaseModelDefinitions.ColumnDefinition column) + public virtual List Format(IEnumerable indexes) + { + return indexes.Select(Format).ToList(); + } + + public virtual string Format(IndexDefinition index) + { + string name = string.IsNullOrEmpty(index.Name) + ? string.Format("IX_{0}_{1}", index.TableName, index.ColumnName) + : index.Name; + + string columns = index.Columns.Any() + ? string.Join(",", index.Columns.Select(x => GetQuotedColumnName(x.Name))) + : GetQuotedColumnName(index.ColumnName); + + return string.Format(CreateIndex, GetIndexType(index.IndexType), " ", GetQuotedName(name), + GetQuotedTableName(index.TableName), columns); + } + + public virtual List Format(IEnumerable foreignKeys) + { + return foreignKeys.Select(Format).ToList(); + } + + public virtual string Format(ForeignKeyDefinition foreignKey) + { + string constraintName = string.IsNullOrEmpty(foreignKey.Name) + ? string.Format("FK_{0}_{1}_{2}", foreignKey.ForeignTable, foreignKey.PrimaryTable, foreignKey.PrimaryColumns.First()) + : foreignKey.Name; + + return string.Format(CreateForeignKeyConstraint, + GetQuotedTableName(foreignKey.ForeignTable), + GetQuotedName(constraintName), + GetQuotedColumnName(foreignKey.ForeignColumns.First()), + GetQuotedTableName(foreignKey.PrimaryTable), + GetQuotedColumnName(foreignKey.PrimaryColumns.First()), + FormatCascade("DELETE", foreignKey.OnDelete), + FormatCascade("UPDATE", foreignKey.OnUpdate)); + } + + public virtual string Format(IEnumerable columns) + { + var sb = new StringBuilder(); + foreach (var column in columns) + { + sb.Append(Format(column) +",\n"); + } + return sb.ToString().TrimEnd(",\n"); + } + + public virtual string Format(ColumnDefinition column) { var clauses = new List(); @@ -349,19 +227,96 @@ namespace Umbraco.Core.Persistence.SqlSyntax return string.Join(" ", clauses.ToArray()); } - public virtual string FormatString(DatabaseModelDefinitions.ColumnDefinition column) + public virtual string FormatPrimaryKey(TableDefinition table) + { + var columnDefinition = table.Columns.FirstOrDefault(x => x.IsPrimaryKey); + if (columnDefinition == null) + return string.Empty; + + string constraintName = string.IsNullOrEmpty(columnDefinition.PrimaryKeyName) + ? string.Format("PK_{0}", table.Name) + : columnDefinition.PrimaryKeyName; + + string columns = string.IsNullOrEmpty(columnDefinition.PrimaryKeyColumns) + ? GetQuotedColumnName(columnDefinition.Name) + : columnDefinition.PrimaryKeyColumns; + + string primaryKeyPart = string.Concat("PRIMARY KEY", columnDefinition.IsIndexed ? " CLUSTERED" : " NONCLUSTERED"); + + return string.Format(CreateConstraint, + GetQuotedTableName(table.Name), + GetQuotedName(constraintName), + primaryKeyPart, + columns); + } + + public virtual string FormatColumnRename(string tableName, string oldName, string newName) + { + return string.Format(RenameColumn, + GetQuotedTableName(tableName), + GetQuotedColumnName(oldName), + GetQuotedColumnName(newName)); + } + + public virtual string FormatTableRename(string oldName, string newName) + { + return string.Format(RenameTable, GetQuotedTableName(oldName), GetQuotedTableName(newName)); + } + + protected virtual string FormatCascade(string onWhat, Rule rule) + { + string action = "NO ACTION"; + switch (rule) + { + case Rule.None: + return ""; + case Rule.Cascade: + action = "CASCADE"; + break; + case Rule.SetNull: + action = "SET NULL"; + break; + case Rule.SetDefault: + action = "SET DEFAULT"; + break; + } + + return string.Format(" ON {0} {1}", onWhat, action); + } + + protected virtual string FormatString(ColumnDefinition column) { return GetQuotedColumnName(column.Name); } - protected virtual string FormatType(DatabaseModelDefinitions.ColumnDefinition column) + protected virtual string FormatType(ColumnDefinition column) { - if (!column.Type.HasValue) + if (column.Type.HasValue == false && string.IsNullOrEmpty(column.CustomType) == false) return column.CustomType; - var dbType = DbTypeMap.ColumnDbTypeMap.First(x => x.Value == column.Type.Value).Key; - var definition = DbTypeMap.ColumnTypeMap.First(x => x.Key == dbType).Value; + if (column.HasSpecialDbType) + { + if (column.Size != default(int)) + { + return string.Format("{0}({1})", + GetSpecialDbType(column.DbType), + column.Size); + } + return GetSpecialDbType(column.DbType); + } + + Type type = column.Type.HasValue + ? DbTypeMap.ColumnDbTypeMap.First(x => x.Value == column.Type.Value).Key + : column.PropertyType; + + if (type == typeof (string)) + { + var valueOrDefault = column.Size != default(int) ? column.Size : DefaultStringLength; + return string.Format(StringLengthColumnDefinitionFormat, valueOrDefault); + } + + string definition = DbTypeMap.ColumnTypeMap.First(x => x.Key == type).Value; string dbTypeDefinition = column.Size != default(int) ? string.Format("{0}({1})", definition, column.Size) : definition; @@ -369,12 +324,23 @@ namespace Umbraco.Core.Persistence.SqlSyntax return dbTypeDefinition; } - protected virtual string FormatNullable(DatabaseModelDefinitions.ColumnDefinition column) + protected virtual string FormatNullable(ColumnDefinition column) { - return column.IsNullable ? string.Empty : "NOT NULL"; + return column.IsNullable ? "NULL" : "NOT NULL"; } - protected virtual string FormatDefaultValue(DatabaseModelDefinitions.ColumnDefinition column) + protected virtual string FormatConstraint(ColumnDefinition column) + { + if (string.IsNullOrEmpty(column.ConstraintName) && column.DefaultValue == null) + return string.Empty; + + return string.Format("CONSTRAINT {0}", + string.IsNullOrEmpty(column.ConstraintName) + ? GetQuotedName(string.Format("DF_{0}_{1}", column.TableName, column.Name)) + : column.ConstraintName); + } + + protected virtual string FormatDefaultValue(ColumnDefinition column) { if (column.DefaultValue == null) return string.Empty; @@ -386,20 +352,28 @@ namespace Umbraco.Core.Persistence.SqlSyntax if (string.IsNullOrEmpty(method)) return string.Empty; - return "DEFAULT " + method; + return string.Format(DefaultValueFormat, method); } - return "DEFAULT " + GetQuotedValue(column.DefaultValue.ToString()); + return string.Format(DefaultValueFormat, GetQuotedValue(column.DefaultValue.ToString())); } - protected virtual string FormatPrimaryKey(DatabaseModelDefinitions.ColumnDefinition column) + protected virtual string FormatPrimaryKey(ColumnDefinition column) { return string.Empty; } protected abstract string FormatSystemMethods(SystemMethods systemMethod); - protected abstract string FormatIdentity(DatabaseModelDefinitions.ColumnDefinition column); + protected abstract string FormatIdentity(ColumnDefinition column); + + public virtual string DeleteDefaultConstraint + { + get + { + throw new NotSupportedException("Default constraints are not supported"); + } + } public virtual string CreateTable { get { return "CREATE TABLE {0} ({1})"; } } public virtual string DropTable { get { return "DROP TABLE {0}"; } } diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 683680cb7c..8f2c76f582 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Web; @@ -90,20 +91,16 @@ namespace Umbraco.Core.Services } content = new Content(parentId, contentType); - var e = new NewEventArgs { Alias = contentTypeAlias, ParentId = parentId }; - if (Creating != null) - Creating(content, e); - if (!e.Cancel) - { - SetUser(content, userId); - SetWriter(content, userId); + if (Creating.IsRaisedEventCancelled(new NewEventArgs(content, contentTypeAlias, parentId), this)) + return content; - if (Created != null) - Created(content, e); + SetUser(content, userId); + SetWriter(content, userId); - Audit.Add(AuditTypes.New, "", content.CreatorId, content.Id); - } + Created.RaiseEvent(new NewEventArgs(content, false, contentTypeAlias, parentId), this); + + Audit.Add(AuditTypes.New, "", content.CreatorId, content.Id); return content; @@ -572,61 +569,59 @@ namespace Umbraco.Core.Services public bool SaveAndPublish(IContent content, int userId = -1, bool omitCacheRefresh = false) { //TODO Refactor this so omitCacheRefresh isn't exposed in the public method, but only in an internal one as its purely there for legacy reasons. - var e = new SaveEventArgs(); - if (Saving != null) - Saving(content, e); + if (Saving.IsRaisedEventCancelled(new SaveEventArgs(content), this)) + return false; - if (!e.Cancel) - { - //Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published + //Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published if (content.ParentId != -1 && content.ParentId != -20 && IsPublishable(content) == false) - { - LogHelper.Info( - string.Format( - "Content '{0}' with Id '{1}' could not be published because its parent or one of its ancestors is not published.", - content.Name, content.Id)); - return false; - } + { + LogHelper.Info( + 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( - string.Format( - "Content '{0}' with Id '{1}' could not be published because of invalid properties.", - content.Name, content.Id)); - return false; - } + //Content contains invalid property values and can therefore not be published - fire event? + if (!content.IsValid()) + { + LogHelper.Info( + string.Format( + "Content '{0}' with Id '{1}' could not be published because of invalid properties.", + content.Name, content.Id)); + return false; + } - //Publish and then update the database with new status - bool published = _publishingStrategy.Publish(content, userId); + //Publish and then update the database with new status + bool published = _publishingStrategy.Publish(content, userId); - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) - { - //Since this is the Save and Publish method, the content should be saved even though the publish fails or isn't allowed - SetWriter(content, userId); - repository.AddOrUpdate(content); + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + //Since this is the Save and Publish method, the content should be saved even though the publish fails or isn't allowed + SetWriter(content, userId); + repository.AddOrUpdate(content); - uow.Commit(); + uow.Commit(); - if (published) - { - var xml = content.ToXml(); - var poco = new ContentXmlDto {NodeId = content.Id, Xml = xml.ToString(SaveOptions.None)}; - var exists = - uow.Database.FirstOrDefault("WHERE nodeId = @Id", new {Id = content.Id}) != - null; - int result = exists - ? uow.Database.Update(poco) - : Convert.ToInt32(uow.Database.Insert(poco)); - } - } + if (published) + { + var xml = content.ToXml(); + var poco = new ContentXmlDto { NodeId = content.Id, Xml = xml.ToString(SaveOptions.None) }; + var exists = + uow.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = content.Id }) != + null; + int result = exists + ? uow.Database.Update(poco) + : Convert.ToInt32(uow.Database.Insert(poco)); + } + } - //Save xml to db and call following method to fire event through PublishingStrategy to update cache - if (omitCacheRefresh == false) - _publishingStrategy.PublishingFinalized(content); + //Save xml to db and call following method to fire event through PublishingStrategy to update cache + if (omitCacheRefresh == false) + _publishingStrategy.PublishingFinalized(content); + Saved.RaiseEvent(new SaveEventArgs(content, false), this); if (HasChildren(content.Id)) { var children = GetChildrenDeep(content.Id); @@ -636,15 +631,10 @@ namespace Umbraco.Core.Services _publishingStrategy.PublishingFinalized(shouldBeRepublished, false); } - if (Saved != null) - Saved(content, e); - Audit.Add(AuditTypes.Publish, "Save and Publish performed by user", userId == -1 ? 0 : userId, content.Id); + Audit.Add(AuditTypes.Publish, "Save and Publish performed by user", userId == -1 ? 0 : userId, content.Id); - return published; - } - - return false; + return published; } /// @@ -654,29 +644,25 @@ namespace Umbraco.Core.Services /// Optional Id of the User saving the Content public void Save(IContent content, int userId = -1) { - var e = new SaveEventArgs(); - if (Saving != null) - Saving(content, e); + if (Saving.IsRaisedEventCancelled(new SaveEventArgs(content), this)) + return; - if (!e.Cancel) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) - { - SetWriter(content, userId); + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + SetWriter(content, userId); - //Only change the publish state if the "previous" version was actually published - if (content.Published) - content.ChangePublishedState(false); + //Only change the publish state if the "previous" version was actually published + if (content.Published) + content.ChangePublishedState(false); - repository.AddOrUpdate(content); - uow.Commit(); - } - if (Saved != null) - Saved(content, e); + repository.AddOrUpdate(content); + uow.Commit(); + } + + Saved.RaiseEvent(new SaveEventArgs(content, false), this); - Audit.Add(AuditTypes.Save, "Save Content performed by user", userId == -1 ? 0 : userId, content.Id); - } + Audit.Add(AuditTypes.Save, "Save Content performed by user", userId == -1 ? 0 : userId, content.Id); } /// @@ -690,88 +676,45 @@ namespace Umbraco.Core.Services /// Optional Id of the User saving the Content public void Save(IEnumerable contents, int userId = -1) { - var containsNew = contents.Any(x => x.HasIdentity == false); + if (Saving.IsRaisedEventCancelled(new SaveEventArgs(contents), this)) + return; - var e = new SaveEventArgs(); - if (Saving != null) - Saving(contents, e); + var containsNew = contents.Any(x => x.HasIdentity == false); - if (!e.Cancel) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) - { - if (containsNew) - { - foreach (var content in contents) - { - SetWriter(content, userId); + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + if (containsNew) + { + foreach (var content in contents) + { - //Only change the publish state if the "previous" version was actually published - if (content.Published) - content.ChangePublishedState(false); + SetWriter(content, userId); - repository.AddOrUpdate(content); - uow.Commit(); - } - } - else - { - foreach (var content in contents) - { - SetWriter(content, userId); - repository.AddOrUpdate(content); - } - uow.Commit(); - } - } - if (Saved != null) - Saved(contents, e); + //Only change the publish state if the "previous" version was actually published + if (content.Published) + content.ChangePublishedState(false); - Audit.Add(AuditTypes.Save, "Bulk Save content performed by user", userId == -1 ? 0 : userId, -1); - } + repository.AddOrUpdate(content); + uow.Commit(); + } + } + else + { + foreach (var content in contents) + { + SetWriter(content, userId); + repository.AddOrUpdate(content); + } + uow.Commit(); + } + } + + Saved.RaiseEvent(new SaveEventArgs(contents, false), this); + + Audit.Add(AuditTypes.Save, "Bulk Save content performed by user", userId == -1 ? 0 : userId, -1); } - - /// - /// Saves a collection of lazy loaded objects. - /// - /// - /// This method ensures that Content is saved lazily, so a new graph of - /// objects can be saved in bulk. But note that objects are saved one at a time to ensure Ids. - /// - /// Collection of Lazy to save - /// Optional Id of the User saving the Content - public void Save(IEnumerable> contents, int userId = -1) - { - var e = new SaveEventArgs(); - if (Saving != null) - Saving(contents, e); - - if (!e.Cancel) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) - { - foreach (var content in contents) - { - SetWriter(content.Value, userId); - - //Only change the publish state if the "previous" version was actually published - if (content.Value.Published) - content.Value.ChangePublishedState(false); - - repository.AddOrUpdate(content.Value); - uow.Commit(); - } - } - - if (Saved != null) - Saved(contents, e); - - Audit.Add(AuditTypes.Save, "Bulk Save (lazy) content performed by user", userId == -1 ? 0 : userId, -1); - } - } - + /// /// Deletes all content of specified type. All children of deleted content is moved to Recycle Bin. /// @@ -779,45 +722,38 @@ namespace Umbraco.Core.Services /// Id of the /// Optional Id of the user issueing the delete operation public void DeleteContentOfType(int contentTypeId, int userId = -1) - { - var uow = _uowProvider.GetUnitOfWork(); - var repository = _repositoryFactory.CreateContentRepository(uow); - //NOTE What about content that has the contenttype as part of its composition? - var query = Query.Builder.Where(x => x.ContentTypeId == contentTypeId); - var contents = repository.GetByQuery(query); + { + using (var uow = _uowProvider.GetUnitOfWork()) + { + var repository = _repositoryFactory.CreateContentRepository(uow); + //NOTE What about content that has the contenttype as part of its composition? + var query = Query.Builder.Where(x => x.ContentTypeId == contentTypeId); + var contents = repository.GetByQuery(query); - var e = new DeleteEventArgs {Id = contentTypeId}; - if (Deleting != null) - Deleting(contents, e); + if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(contents), this)) + return; - if (!e.Cancel) - { - foreach (var content in contents.OrderByDescending(x => x.ParentId)) - { - //Look for children of current content and move that to trash before the current content is deleted - var c = content; - var childQuery = Query.Builder.Where(x => x.Path.StartsWith(c.Path)); - var children = repository.GetByQuery(childQuery); + foreach (var content in contents.OrderByDescending(x => x.ParentId)) + { + //Look for children of current content and move that to trash before the current content is deleted + var c = content; + var childQuery = Query.Builder.Where(x => x.Path.StartsWith(c.Path)); + var children = repository.GetByQuery(childQuery); - foreach (var child in children) - { - if (child.ContentType.Id != contentTypeId) - MoveToRecycleBin(child, userId); - } + foreach (var child in children) + { + if (child.ContentType.Id != contentTypeId) + MoveToRecycleBin(child, userId); + } - //Permantly delete the content - Delete(content, userId); - } + //Permantly delete the content + Delete(content, userId); + } + } - uow.Dispose(); - - if (Deleted != null) - Deleted(contents, e); - - Audit.Add(AuditTypes.Delete, - string.Format("Delete Content of Type {0} performed by user", contentTypeId), - userId == -1 ? 0 : userId, -1); - } + Audit.Add(AuditTypes.Delete, + string.Format("Delete Content of Type {0} performed by user", contentTypeId), + userId == -1 ? 0 : userId, -1); } /// @@ -831,38 +767,34 @@ namespace Umbraco.Core.Services /// Optional Id of the User deleting the Content public void Delete(IContent content, int userId = -1) { - var e = new DeleteEventArgs { Id = content.Id }; - if (Deleting != null) - Deleting(content, e); + if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(content), this)) + return; - if (!e.Cancel) - { - //Make sure that published content is unpublished before being deleted - if (HasPublishedVersion(content.Id)) - { - UnPublish(content, userId); - } + //Make sure that published content is unpublished before being deleted + if (HasPublishedVersion(content.Id)) + { + UnPublish(content, userId); + } - //Delete children before deleting the 'possible parent' - var children = GetChildren(content.Id); - foreach (var child in children) - { - Delete(child, userId); - } + //Delete children before deleting the 'possible parent' + var children = GetChildren(content.Id); + foreach (var child in children) + { + Delete(child, userId); + } - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) - { - SetWriter(content, userId); - repository.Delete(content); - uow.Commit(); - } + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + //TODO: Why are we setting a writer if we are just deleting the object? (I'm probably overlooking something here...?) + SetWriter(content, userId); + repository.Delete(content); + uow.Commit(); + } - if (Deleted != null) - Deleted(content, e); + Deleted.RaiseEvent(new DeleteEventArgs(content, false), this); - Audit.Add(AuditTypes.Delete, "Delete Content performed by user", userId == -1 ? 0 : userId, content.Id); - } + Audit.Add(AuditTypes.Delete, "Delete Content performed by user", userId == -1 ? 0 : userId, content.Id); } /// @@ -873,27 +805,25 @@ namespace Umbraco.Core.Services /// Optional Id of the User deleting versions of a Content object public void DeleteVersions(int id, DateTime versionDate, int userId = -1) { - var e = new DeleteEventArgs { Id = id }; - if (Deleting != null) - Deleting(versionDate, e); + //TODO: We should check if we are going to delete the most recent version because if that happens it means the + // entity is completely deleted and we should raise the normal Deleting/Deleted event - if (!e.Cancel) + if (DeletingVersions.IsRaisedEventCancelled(new DeleteRevisionsEventArgs(id, dateToRetain: versionDate), this)) + return; + + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) - { - repository.DeleteVersions(id, versionDate); - uow.Commit(); - } - - if (Deleted != null) - Deleted(versionDate, e); - - Audit.Add(AuditTypes.Delete, "Delete Content by version date performed by user", userId == -1 ? 0 : userId, -1); + repository.DeleteVersions(id, versionDate); + uow.Commit(); } + + DeletedVersions.RaiseEvent(new DeleteRevisionsEventArgs(id, false, dateToRetain: versionDate), this); + + Audit.Add(AuditTypes.Delete, "Delete Content by version date performed by user", userId == -1 ? 0 : userId, -1); } - /// + /// /// Permanently deletes specific version(s) from an object. /// /// Id of the object to delete a version from @@ -902,30 +832,28 @@ namespace Umbraco.Core.Services /// Optional Id of the User deleting versions of a Content object public void DeleteVersion(int id, Guid versionId, bool deletePriorVersions, int userId = -1) { + //TODO: We should check if we are going to delete the most recent version because if that happens it means the + // entity is completely deleted and we should raise the normal Deleting/Deleted event + if (deletePriorVersions) { var content = GetByVersion(versionId); DeleteVersions(id, content.UpdateDate, userId); } - var e = new DeleteEventArgs {Id = id}; - if (Deleting != null) - Deleting(versionId, e); + if (DeletingVersions.IsRaisedEventCancelled(new DeleteRevisionsEventArgs(id, specificVersion: versionId), this)) + return; - if (!e.Cancel) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) - { - repository.DeleteVersion(versionId); - uow.Commit(); - } + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + repository.DeleteVersion(versionId); + uow.Commit(); + } - if (Deleted != null) - Deleted(versionId, e); + DeletedVersions.RaiseEvent(new DeleteRevisionsEventArgs(id, false, specificVersion:versionId), this); - Audit.Add(AuditTypes.Delete, "Delete Content by version performed by user", userId == -1 ? 0 : userId, -1); - } + Audit.Add(AuditTypes.Delete, "Delete Content by version performed by user", userId == -1 ? 0 : userId, -1); } /// @@ -936,40 +864,35 @@ namespace Umbraco.Core.Services /// Optional Id of the User deleting the Content public void MoveToRecycleBin(IContent content, int userId = -1) { - var e = new MoveEventArgs {ParentId = -20}; - if (Trashing != null) - Trashing(content, e); + if (Trashing.IsRaisedEventCancelled(new MoveEventArgs(content, -20), this)) + return; - if (!e.Cancel) - { - //Make sure that published content is unpublished before being moved to the Recycle Bin - if (HasPublishedVersion(content.Id)) - { - UnPublish(content, userId); - } + //Make sure that published content is unpublished before being moved to the Recycle Bin + if (HasPublishedVersion(content.Id)) + { + UnPublish(content, userId); + } - //Move children to Recycle Bin before the 'possible parent' is moved there - var children = GetChildren(content.Id); - foreach (var child in children) - { - MoveToRecycleBin(child, userId); - } + //Move children to Recycle Bin before the 'possible parent' is moved there + var children = GetChildren(content.Id); + foreach (var child in children) + { + MoveToRecycleBin(child, userId); + } - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) - { - SetWriter(content, userId); - content.ChangeTrashedState(true); - repository.AddOrUpdate(content); - uow.Commit(); - } + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + SetWriter(content, userId); + content.ChangeTrashedState(true); + repository.AddOrUpdate(content); + uow.Commit(); + } - if (Trashed != null) - Trashed(content, e); + Trashed.RaiseEvent(new MoveEventArgs(content, false, -20), this); - Audit.Add(AuditTypes.Move, "Move Content to Recycle Bin performed by user", userId == -1 ? 0 : userId, - content.Id); - } + Audit.Add(AuditTypes.Move, "Move Content to Recycle Bin performed by user", userId == -1 ? 0 : userId, + content.Id); } /// @@ -987,39 +910,35 @@ namespace Umbraco.Core.Services { //TODO Verify that SortOrder + Path is updated correctly //TODO Add a check to see if parentId = -20 because then we should change the TrashState - var e = new MoveEventArgs { ParentId = parentId }; - if (Moving != null) - Moving(content, e); + + if (Moving.IsRaisedEventCancelled(new MoveEventArgs(content, parentId), this)) + return; + + SetWriter(content, userId); - if (!e.Cancel) + //If Content is being moved away from Recycle Bin, its state should be un-trashed + if (content.Trashed && parentId != -20) { - SetWriter(content, userId); - - //If Content is being moved away from Recycle Bin, its state should be un-trashed - if (content.Trashed && parentId != -20) - { - content.ChangeTrashedState(false, parentId); - } - else - { - content.ParentId = parentId; - } - - //If Content is published, it should be (re)published from its new location - if (content.Published) - { - SaveAndPublish(content, userId); - } - else - { - Save(content, userId); - } - - if (Moved != null) - Moved(content, e); - - Audit.Add(AuditTypes.Move, "Move Content performed by user", userId == -1 ? 0 : userId, content.Id); + content.ChangeTrashedState(false, parentId); } + else + { + content.ParentId = parentId; + } + + //If Content is published, it should be (re)published from its new location + if (content.Published) + { + SaveAndPublish(content, userId); + } + else + { + Save(content, userId); + } + + Moved.RaiseEvent(new MoveEventArgs(content, false, parentId), this); + + Audit.Add(AuditTypes.Move, "Move Content performed by user", userId == -1 ? 0 : userId, content.Id); } /// @@ -1027,6 +946,8 @@ namespace Umbraco.Core.Services /// public void EmptyRecycleBin() { + //TODO: Why don't we have a base class to share between MediaService/ContentService as some of this is exacty the same? + var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateContentRepository(uow)) { @@ -1035,7 +956,12 @@ namespace Umbraco.Core.Services foreach (var content in contents) { + if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(content), this)) + continue; + repository.Delete(content); + + Deleted.RaiseEvent(new DeleteEventArgs(content, false), this); } uow.Commit(); } @@ -1054,94 +980,87 @@ namespace Umbraco.Core.Services /// The newly created object public IContent Copy(IContent content, int parentId, bool relateToOriginal, int userId = -1) { - var e = new CopyEventArgs { ParentId = parentId }; - if (Copying != null) - Copying(content, e); + var copy = ((Content)content).Clone(); + copy.ParentId = parentId; + copy.Name = copy.Name + " (1)"; - IContent copy = null; + if (Copying.IsRaisedEventCancelled(new CopyEventArgs(content, copy, parentId), this)) + return null; - if (!e.Cancel) + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) { - copy = ((Content)content).Clone(); - copy.ParentId = parentId; - copy.Name = copy.Name + " (1)"; + SetWriter(content, userId); - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) + repository.AddOrUpdate(copy); + uow.Commit(); + + var uploadFieldId = new Guid("5032a6e6-69e3-491d-bb28-cd31cd11086c"); + if (content.Properties.Any(x => x.PropertyType.DataTypeControlId == uploadFieldId)) { - SetWriter(content, userId); + bool isUpdated = false; + var fs = FileSystemProviderManager.Current.GetFileSystemProvider(); - repository.AddOrUpdate(copy); - uow.Commit(); - - var uploadFieldId = new Guid("5032a6e6-69e3-491d-bb28-cd31cd11086c"); - if (content.Properties.Any(x => x.PropertyType.DataTypeControlId == uploadFieldId)) - { - bool isUpdated = false; - var fs = FileSystemProviderManager.Current.GetFileSystemProvider(); + //Loop through properties to check if the content contains media that should be deleted + foreach (var property in content.Properties.Where(x => x.PropertyType.DataTypeControlId == uploadFieldId + && string.IsNullOrEmpty(x.Value.ToString()) == false)) + { + if (fs.FileExists(IOHelper.MapPath(property.Value.ToString()))) + { + var currentPath = fs.GetRelativePath(property.Value.ToString()); + var propertyId = copy.Properties.First(x => x.Alias == property.Alias).Id; + var newPath = fs.GetRelativePath(propertyId, System.IO.Path.GetFileName(currentPath)); - //Loop through properties to check if the content contains media that should be deleted - foreach (var property in content.Properties.Where(x => x.PropertyType.DataTypeControlId == uploadFieldId - && string.IsNullOrEmpty(x.Value.ToString()) == false)) - { - if (fs.FileExists(IOHelper.MapPath(property.Value.ToString()))) - { - var currentPath = fs.GetRelativePath(property.Value.ToString()); - var propertyId = copy.Properties.First(x => x.Alias == property.Alias).Id; - var newPath = fs.GetRelativePath(propertyId, System.IO.Path.GetFileName(currentPath)); + fs.CopyFile(currentPath, newPath); + copy.SetValue(property.Alias, fs.GetUrl(newPath)); - fs.CopyFile(currentPath, newPath); - copy.SetValue(property.Alias, fs.GetUrl(newPath)); + //Copy thumbnails + foreach (var thumbPath in fs.GetThumbnails(currentPath)) + { + var newThumbPath = fs.GetRelativePath(propertyId, System.IO.Path.GetFileName(thumbPath)); + fs.CopyFile(thumbPath, newThumbPath); + } + isUpdated = true; + } + } - //Copy thumbnails - foreach (var thumbPath in fs.GetThumbnails(currentPath)) - { - var newThumbPath = fs.GetRelativePath(propertyId, System.IO.Path.GetFileName(thumbPath)); - fs.CopyFile(thumbPath, newThumbPath); - } - isUpdated = true; - } - } - - if (isUpdated) - { - repository.AddOrUpdate(copy); - uow.Commit(); - } - } + if (isUpdated) + { + repository.AddOrUpdate(copy); + uow.Commit(); + } } - - //NOTE This 'Relation' part should eventually be delegated to a RelationService - if (relateToOriginal) - { - RelationType relationType = null; - using (var relationTypeRepository = _repositoryFactory.CreateRelationTypeRepository(uow)) - { - relationType = relationTypeRepository.Get(1); - } - - using (var relationRepository = _repositoryFactory.CreateRelationRepository(uow)) - { - var relation = new Relation(content.Id, copy.Id, relationType); - relationRepository.AddOrUpdate(relation); - uow.Commit(); - } - - Audit.Add(AuditTypes.Copy, - string.Format("Copied content with Id: '{0}' related to original content with Id: '{1}'", - copy.Id, content.Id), copy.WriterId, copy.Id); - } - - //Look for children and copy those as well - var children = GetChildren(content.Id); - foreach (var child in children) - { - Copy(child, copy.Id, relateToOriginal, userId); - } } - if (Copied != null) - Copied(copy, e); + //NOTE This 'Relation' part should eventually be delegated to a RelationService + if (relateToOriginal) + { + RelationType relationType = null; + using (var relationTypeRepository = _repositoryFactory.CreateRelationTypeRepository(uow)) + { + relationType = relationTypeRepository.Get(1); + } + + using (var relationRepository = _repositoryFactory.CreateRelationRepository(uow)) + { + var relation = new Relation(content.Id, copy.Id, relationType); + relationRepository.AddOrUpdate(relation); + uow.Commit(); + } + + Audit.Add(AuditTypes.Copy, + string.Format("Copied content with Id: '{0}' related to original content with Id: '{1}'", + copy.Id, content.Id), copy.WriterId, copy.Id); + } + + //Look for children and copy those as well + var children = GetChildren(content.Id); + foreach (var child in children) + { + Copy(child, copy.Id, relateToOriginal, userId); + } + + Copied.RaiseEvent(new CopyEventArgs(content, copy, false, parentId), this); Audit.Add(AuditTypes.Copy, "Copy Content performed by user", content.WriterId, content.Id); @@ -1156,24 +1075,17 @@ namespace Umbraco.Core.Services /// True if sending publication was succesfull otherwise false internal bool SendToPublication(IContent content, int userId = -1) { - //TODO Implement something similar to this - var e = new SendToPublishEventArgs(); - if (SendingToPublish != null) - SendingToPublish(content, e); + if (SendingToPublish.IsRaisedEventCancelled(new SendToPublishEventArgs(content), this)) + return false; - if (!e.Cancel) - { - // Do some stuff here.. RunActionHandlers + //TODO: Do some stuff here.. RunActionHandlers - if (SentToPublish != null) - SentToPublish(content, e); + SentToPublish.RaiseEvent(new SendToPublishEventArgs(content, false), this); - Audit.Add(AuditTypes.SendToPublish, "Send to Publish performed by user", content.WriterId, content.Id); + Audit.Add(AuditTypes.SendToPublish, "Send to Publish performed by user", content.WriterId, content.Id); - return true; - } - return false; + return true; } /// @@ -1190,31 +1102,27 @@ namespace Umbraco.Core.Services /// The newly created object public IContent Rollback(int id, Guid versionId, int userId = -1) { - var e = new RollbackEventArgs(); + var content = GetByVersion(versionId); - if (Rollingback != null) - Rollingback(content, e); + if (RollingBack.IsRaisedEventCancelled(new RollbackEventArgs(content), this)) + return content; - if (!e.Cancel) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) - { - SetUser(content, userId); - SetWriter(content, userId); + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + SetUser(content, userId); + SetWriter(content, userId); - repository.AddOrUpdate(content); - uow.Commit(); - } + repository.AddOrUpdate(content); + uow.Commit(); + } - if (Rolledback != null) - Rolledback(content, e); + RolledBack.RaiseEvent(new RollbackEventArgs(content, false), this); - Audit.Add(AuditTypes.RollBack, "Content rollback performed by user", content.WriterId, content.Id); - } + Audit.Add(AuditTypes.RollBack, "Content rollback performed by user", content.WriterId, content.Id); - return content; + return content; } #region Internal Methods @@ -1352,28 +1260,38 @@ namespace Umbraco.Core.Services #region Event Handlers /// /// Occurs before Delete - /// - public static event EventHandler Deleting; + /// + public static event TypedEventHandler> Deleting; /// /// Occurs after Delete /// - public static event EventHandler Deleted; + public static event TypedEventHandler> Deleted; + + /// + /// Occurs before Delete + /// + public static event TypedEventHandler DeletingVersions; + + /// + /// Occurs after Delete + /// + public static event TypedEventHandler DeletedVersions; /// /// Occurs before Save /// - public static event EventHandler Saving; - + public static event TypedEventHandler> Saving; + /// /// Occurs after Save /// - public static event EventHandler Saved; - + public static event TypedEventHandler> Saved; + /// /// Occurs before Create /// - public static event EventHandler Creating; + public static event TypedEventHandler> Creating; /// /// Occurs after Create @@ -1382,57 +1300,57 @@ namespace Umbraco.Core.Services /// Please note that the Content object has been created, but not saved /// so it does not have an identity yet (meaning no Id has been set). /// - public static event EventHandler Created; + public static event TypedEventHandler> Created; /// /// Occurs before Copy /// - public static event EventHandler Copying; + public static event TypedEventHandler> Copying; /// /// Occurs after Copy /// - public static event EventHandler Copied; + public static event TypedEventHandler> Copied; /// /// Occurs before Content is moved to Recycle Bin /// - public static event EventHandler Trashing; + public static event TypedEventHandler> Trashing; /// /// Occurs after Content is moved to Recycle Bin /// - public static event EventHandler Trashed; + public static event TypedEventHandler> Trashed; /// /// Occurs before Move /// - public static event EventHandler Moving; + public static event TypedEventHandler> Moving; /// /// Occurs after Move /// - public static event EventHandler Moved; + public static event TypedEventHandler> Moved; /// /// Occurs before Rollback /// - public static event EventHandler Rollingback; + public static event TypedEventHandler> RollingBack; /// /// Occurs after Rollback /// - public static event EventHandler Rolledback; + public static event TypedEventHandler> RolledBack; /// /// Occurs before Send to Publish /// - public static event EventHandler SendingToPublish; + public static event TypedEventHandler> SendingToPublish; /// /// Occurs after Send to Publish /// - public static event EventHandler SentToPublish; + public static event TypedEventHandler> SentToPublish; #endregion } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/ContentTypeService.cs b/src/Umbraco.Core/Services/ContentTypeService.cs index 0b74538730..fd4caff1f2 100644 --- a/src/Umbraco.Core/Services/ContentTypeService.cs +++ b/src/Umbraco.Core/Services/ContentTypeService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; @@ -129,26 +130,21 @@ namespace Umbraco.Core.Services /// Optional id of the user saving the ContentType public void Save(IContentType contentType, int userId = -1) { - var e = new SaveEventArgs(); - if (Saving != null) - Saving(contentType, e); + if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs(contentType), this)) + return; + + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentTypeRepository(uow)) + { + SetUser(contentType, userId); + repository.AddOrUpdate(contentType); - if (!e.Cancel) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentTypeRepository(uow)) - { - SetUser(contentType, userId); - repository.AddOrUpdate(contentType); + uow.Commit(); - uow.Commit(); + SavedContentType.RaiseEvent(new SaveEventArgs(contentType, false), this); + } - if (Saved != null) - Saved(contentType, e); - } - - Audit.Add(AuditTypes.Save, string.Format("Save ContentType performed by user"), userId == -1 ? 0 : userId, contentType.Id); - } + Audit.Add(AuditTypes.Save, string.Format("Save ContentType performed by user"), userId == -1 ? 0 : userId, contentType.Id); } /// @@ -158,64 +154,25 @@ namespace Umbraco.Core.Services /// Optional id of the user saving the ContentType public void Save(IEnumerable contentTypes, int userId = -1) { - var e = new SaveEventArgs(); - if (Saving != null) - Saving(contentTypes, e); + if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs(contentTypes), this)) + return; + + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentTypeRepository(uow)) + { + foreach (var contentType in contentTypes) + { + SetUser(contentType, userId); + repository.AddOrUpdate(contentType); + } - if (!e.Cancel) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentTypeRepository(uow)) - { - foreach (var contentType in contentTypes) - { - SetUser(contentType, userId); - repository.AddOrUpdate(contentType); - } + //save it all in one go + uow.Commit(); - uow.Commit(); + SavedContentType.RaiseEvent(new SaveEventArgs(contentTypes, false), this); + } - if (Saved != null) - Saved(contentTypes, e); - } - - Audit.Add(AuditTypes.Save, string.Format("Save ContentTypes performed by user"), userId == -1 ? 0 : userId, -1); - } - } - - /// - /// Saves a collection of lazy loaded objects. - /// - /// - /// This method ensures that ContentType is saved lazily, so a new graph of - /// objects can be saved in bulk. But note that objects are saved one at a time to ensure Ids. - /// - /// Collection of Lazy to save - /// Optional Id of the User saving the ContentTypes - public void Save(IEnumerable> contentTypes, int userId = -1) - { - var e = new SaveEventArgs(); - if (Saving != null) - Saving(contentTypes, e); - - if (!e.Cancel) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentTypeRepository(uow)) - { - foreach (var content in contentTypes) - { - content.Value.CreatorId = 0; - repository.AddOrUpdate(content.Value); - uow.Commit(); - } - - if (Saved != null) - Saved(contentTypes, e); - } - - Audit.Add(AuditTypes.Save, string.Format("Save (lazy) ContentTypes performed by user"), userId == -1 ? 0 : userId, -1); - } + Audit.Add(AuditTypes.Save, string.Format("Save ContentTypes performed by user"), userId == -1 ? 0 : userId, -1); } /// @@ -225,27 +182,22 @@ namespace Umbraco.Core.Services /// Optional id of the user issueing the delete /// Deleting a will delete all the objects based on this public void Delete(IContentType contentType, int userId = -1) - { - var e = new DeleteEventArgs { Id = contentType.Id }; - if (Deleting != null) - Deleting(contentType, e); + { + if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs(contentType), this)) + return; + + _contentService.DeleteContentOfType(contentType.Id); - if (!e.Cancel) - { - _contentService.DeleteContentOfType(contentType.Id); + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentTypeRepository(uow)) + { + repository.Delete(contentType); + uow.Commit(); - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentTypeRepository(uow)) - { - repository.Delete(contentType); - uow.Commit(); + DeletedContentType.RaiseEvent(new DeleteEventArgs(contentType, false), this); + } - if (Deleted != null) - Deleted(contentType, e); - } - - Audit.Add(AuditTypes.Delete, string.Format("Delete ContentType performed by user"), userId == -1 ? 0 : userId, contentType.Id); - } + Audit.Add(AuditTypes.Delete, string.Format("Delete ContentType performed by user"), userId == -1 ? 0 : userId, contentType.Id); } /// @@ -258,34 +210,29 @@ namespace Umbraco.Core.Services /// public void Delete(IEnumerable contentTypes, int userId = -1) { - var e = new DeleteEventArgs(); - if (Deleting != null) - Deleting(contentTypes, e); + if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs(contentTypes), this)) + return; + + var contentTypeList = contentTypes.ToList(); + foreach (var contentType in contentTypeList) + { + _contentService.DeleteContentOfType(contentType.Id); + } - if (!e.Cancel) - { - var contentTypeList = contentTypes.ToList(); - foreach (var contentType in contentTypeList) - { - _contentService.DeleteContentOfType(contentType.Id); - } + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentTypeRepository(uow)) + { + foreach (var contentType in contentTypeList) + { + repository.Delete(contentType); + } - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentTypeRepository(uow)) - { - foreach (var contentType in contentTypeList) - { - repository.Delete(contentType); - } + uow.Commit(); - uow.Commit(); + DeletedContentType.RaiseEvent(new DeleteEventArgs(contentTypes, false), this); + } - if (Deleted != null) - Deleted(contentTypes, e); - } - - Audit.Add(AuditTypes.Delete, string.Format("Delete ContentTypes performed by user"), userId == -1 ? 0 : userId, -1); - } + Audit.Add(AuditTypes.Delete, string.Format("Delete ContentTypes performed by user"), userId == -1 ? 0 : userId, -1); } /// @@ -367,26 +314,20 @@ namespace Umbraco.Core.Services /// Optional Id of the user saving the MediaType public void Save(IMediaType mediaType, int userId = -1) { - var e = new SaveEventArgs(); - if (Saving != null) - Saving(mediaType, e); + if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs(mediaType), this)) + return; + + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow)) + { + SetUser(mediaType, userId); + repository.AddOrUpdate(mediaType); + uow.Commit(); - if (!e.Cancel) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow)) - { - SetUser(mediaType, userId); - repository.AddOrUpdate(mediaType); - uow.Commit(); + SavedMediaType.RaiseEvent(new SaveEventArgs(mediaType, false), this); + } - - if (Saved != null) - Saved(mediaType, e); - } - - Audit.Add(AuditTypes.Save, string.Format("Save MediaType performed by user"), userId == -1 ? 0 : userId, mediaType.Id); - } + Audit.Add(AuditTypes.Save, string.Format("Save MediaType performed by user"), userId == -1 ? 0 : userId, mediaType.Id); } /// @@ -396,29 +337,26 @@ namespace Umbraco.Core.Services /// Optional Id of the user savging the MediaTypes public void Save(IEnumerable mediaTypes, int userId = -1) { - var e = new SaveEventArgs(); - if (Saving != null) - Saving(mediaTypes, e); + if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs(mediaTypes), this)) + return; - if (!e.Cancel) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow)) - { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow)) + { - foreach (var mediaType in mediaTypes) - { - SetUser(mediaType, userId); - repository.AddOrUpdate(mediaType); - } - uow.Commit(); + foreach (var mediaType in mediaTypes) + { + SetUser(mediaType, userId); + repository.AddOrUpdate(mediaType); + } - if (Saved != null) - Saved(mediaTypes, e); - } + //save it all in one go + uow.Commit(); - Audit.Add(AuditTypes.Save, string.Format("Save MediaTypes performed by user"), userId == -1 ? 0 : userId, -1); - } + SavedMediaType.RaiseEvent(new SaveEventArgs(mediaTypes, false), this); + } + + Audit.Add(AuditTypes.Save, string.Format("Save MediaTypes performed by user"), userId == -1 ? 0 : userId, -1); } /// @@ -429,27 +367,22 @@ namespace Umbraco.Core.Services /// Deleting a will delete all the objects based on this public void Delete(IMediaType mediaType, int userId = -1) { - var e = new DeleteEventArgs { Id = mediaType.Id }; - if (Deleting != null) - Deleting(mediaType, e); + if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs(mediaType), this)) + return; + + _mediaService.DeleteMediaOfType(mediaType.Id); - if (!e.Cancel) - { - _mediaService.DeleteMediaOfType(mediaType.Id); + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow)) + { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow)) - { + repository.Delete(mediaType); + uow.Commit(); - repository.Delete(mediaType); - uow.Commit(); + DeletedMediaType.RaiseEvent(new DeleteEventArgs(mediaType, false), this); + } - if (Deleted != null) - Deleted(mediaType, e); - } - - Audit.Add(AuditTypes.Delete, string.Format("Delete MediaType performed by user"), userId == -1 ? 0 : userId, mediaType.Id); - } + Audit.Add(AuditTypes.Delete, string.Format("Delete MediaType performed by user"), userId == -1 ? 0 : userId, mediaType.Id); } /// @@ -459,34 +392,29 @@ namespace Umbraco.Core.Services /// /// Deleting a will delete all the objects based on this public void Delete(IEnumerable mediaTypes, int userId = -1) - { - var e = new DeleteEventArgs(); - if (Deleting != null) - Deleting(mediaTypes, e); + { + if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs(mediaTypes), this)) + return; + + var mediaTypeList = mediaTypes.ToList(); + foreach (var mediaType in mediaTypeList) + { + _mediaService.DeleteMediaOfType(mediaType.Id); + } - if (!e.Cancel) - { - var mediaTypeList = mediaTypes.ToList(); - foreach (var mediaType in mediaTypeList) - { - _mediaService.DeleteMediaOfType(mediaType.Id); - } + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow)) + { + foreach (var mediaType in mediaTypeList) + { + repository.Delete(mediaType); + } + uow.Commit(); - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow)) - { - foreach (var mediaType in mediaTypeList) - { - repository.Delete(mediaType); - } - uow.Commit(); + DeletedMediaType.RaiseEvent(new DeleteEventArgs(mediaTypes, false), this); + } - if (Deleted != null) - Deleted(mediaTypes, e); - } - - Audit.Add(AuditTypes.Delete, string.Format("Delete MediaTypes performed by user"), userId == -1 ? 0 : userId, -1); - } + Audit.Add(AuditTypes.Delete, string.Format("Delete MediaTypes performed by user"), userId == -1 ? 0 : userId, -1); } /// @@ -586,25 +514,47 @@ namespace Umbraco.Core.Services } #region Event Handlers - /// - /// Occurs before Delete - /// - public static event EventHandler Deleting; - /// - /// Occurs after Delete - /// - public static event EventHandler Deleted; + /// + /// Occurs before Delete + /// + public static event TypedEventHandler> DeletingContentType; + /// + /// Occurs after Delete + /// + public static event TypedEventHandler> DeletedContentType; + + /// + /// Occurs before Delete + /// + public static event TypedEventHandler> DeletingMediaType; + + /// + /// Occurs after Delete + /// + public static event TypedEventHandler> DeletedMediaType; + /// /// Occurs before Save /// - public static event EventHandler Saving; + public static event TypedEventHandler> SavingContentType; /// /// Occurs after Save /// - public static event EventHandler Saved; + public static event TypedEventHandler> SavedContentType; + + /// + /// Occurs before Save + /// + public static event TypedEventHandler> SavingMediaType; + + /// + /// Occurs after Save + /// + public static event TypedEventHandler> SavedMediaType; + #endregion } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/DataTypeService.cs b/src/Umbraco.Core/Services/DataTypeService.cs index 76bef9efcb..57ad05f15f 100644 --- a/src/Umbraco.Core/Services/DataTypeService.cs +++ b/src/Umbraco.Core/Services/DataTypeService.cs @@ -4,6 +4,7 @@ using System.Linq; using Umbraco.Core.Auditing; using Umbraco.Core.Events; using Umbraco.Core.Models; +using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.UnitOfWork; @@ -97,6 +98,20 @@ namespace Umbraco.Core.Services } } + /// + /// Gets all values for an + /// + /// Id of the to retrieve prevalues from + /// An enumerable list of string values + public IEnumerable GetPreValuesByDataTypeId(int id) + { + var uow = _uowProvider.GetUnitOfWork(); + var dtos = uow.Database.Fetch("WHERE datatypeNodeId = @Id", new {Id = id}); + var list = dtos.Select(x => x.Value).ToList(); + uow.Dispose(); + return list; + } + /// /// Saves an /// @@ -104,25 +119,20 @@ namespace Umbraco.Core.Services /// Id of the user issueing the save public void Save(IDataTypeDefinition dataTypeDefinition, int userId = -1) { - var e = new SaveEventArgs(); - if (Saving != null) - Saving(dataTypeDefinition, e); + if (Saving.IsRaisedEventCancelled(new SaveEventArgs(dataTypeDefinition), this)) + return; + + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow)) + { + dataTypeDefinition.CreatorId = userId > -1 ? userId : 0; + repository.AddOrUpdate(dataTypeDefinition); + uow.Commit(); - if (!e.Cancel) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow)) - { - dataTypeDefinition.CreatorId = userId > -1 ? userId : 0; - repository.AddOrUpdate(dataTypeDefinition); - uow.Commit(); + Saved.RaiseEvent(new SaveEventArgs(dataTypeDefinition, false), this); + } - if (Saved != null) - Saved(dataTypeDefinition, e); - } - - Audit.Add(AuditTypes.Save, string.Format("Save DataTypeDefinition performed by user"), userId == -1 ? 0 : userId, dataTypeDefinition.Id); - } + Audit.Add(AuditTypes.Save, string.Format("Save DataTypeDefinition performed by user"), userId == -1 ? 0 : userId, dataTypeDefinition.Id); } /// @@ -135,48 +145,43 @@ namespace Umbraco.Core.Services /// to delete /// Optional Id of the user issueing the deletion public void Delete(IDataTypeDefinition dataTypeDefinition, int userId = -1) - { - var e = new DeleteEventArgs { Id = dataTypeDefinition.Id }; - if (Deleting != null) - Deleting(dataTypeDefinition, e); + { + if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(dataTypeDefinition), this)) + return; + + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentTypeRepository(uow)) + { + //Find ContentTypes using this IDataTypeDefinition on a PropertyType + var query = Query.Builder.Where(x => x.DataTypeId == dataTypeDefinition.Id); + var contentTypes = repository.GetByQuery(query); - if (!e.Cancel) - { - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentTypeRepository(uow)) - { - //Find ContentTypes using this IDataTypeDefinition on a PropertyType - var query = Query.Builder.Where(x => x.DataTypeId == dataTypeDefinition.Id); - var contentTypes = repository.GetByQuery(query); + //Loop through the list of results and remove the PropertyTypes that references the DataTypeDefinition that is being deleted + foreach (var contentType in contentTypes) + { + if (contentType == null) continue; - //Loop through the list of results and remove the PropertyTypes that references the DataTypeDefinition that is being deleted - foreach (var contentType in contentTypes) - { - if (contentType == null) continue; + foreach (var group in contentType.PropertyGroups) + { + var types = @group.PropertyTypes.Where(x => x.DataTypeId == dataTypeDefinition.Id); + foreach (var propertyType in types) + { + @group.PropertyTypes.Remove(propertyType); + } + } - foreach (var group in contentType.PropertyGroups) - { - var types = group.PropertyTypes.Where(x => x.DataTypeId == dataTypeDefinition.Id); - foreach (var propertyType in types) - { - group.PropertyTypes.Remove(propertyType); - } - } + repository.AddOrUpdate(contentType); + } - repository.AddOrUpdate(contentType); - } + var dataTypeRepository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow); + dataTypeRepository.Delete(dataTypeDefinition); - var dataTypeRepository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow); - dataTypeRepository.Delete(dataTypeDefinition); + uow.Commit(); - uow.Commit(); + Deleted.RaiseEvent(new DeleteEventArgs(dataTypeDefinition, false), this); + } - if (Deleted != null) - Deleted(dataTypeDefinition, e); - } - - Audit.Add(AuditTypes.Delete, string.Format("Delete DataTypeDefinition performed by user"), userId == -1 ? 0 : userId, dataTypeDefinition.Id); - } + Audit.Add(AuditTypes.Delete, string.Format("Delete DataTypeDefinition performed by user"), userId == -1 ? 0 : userId, dataTypeDefinition.Id); } /// @@ -202,22 +207,22 @@ namespace Umbraco.Core.Services /// /// Occurs before Delete /// - public static event EventHandler Deleting; + public static event TypedEventHandler> Deleting; /// /// Occurs after Delete /// - public static event EventHandler Deleted; + public static event TypedEventHandler> Deleted; /// /// Occurs before Save /// - public static event EventHandler Saving; + public static event TypedEventHandler> Saving; /// /// Occurs after Save /// - public static event EventHandler Saved; + public static event TypedEventHandler> Saved; #endregion } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/FileService.cs b/src/Umbraco.Core/Services/FileService.cs index 74ee65d237..4130da307a 100644 --- a/src/Umbraco.Core/Services/FileService.cs +++ b/src/Umbraco.Core/Services/FileService.cs @@ -65,24 +65,19 @@ namespace Umbraco.Core.Services /// public void SaveStylesheet(Stylesheet stylesheet, int userId = -1) { - var e = new SaveEventArgs(); - if (Saving != null) - Saving(stylesheet, e); + if (SavingStylesheet.IsRaisedEventCancelled(new SaveEventArgs(stylesheet), this)) + return; + + var uow = _fileUowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateStylesheetRepository(uow)) + { + repository.AddOrUpdate(stylesheet); + uow.Commit(); - if (!e.Cancel) - { - var uow = _fileUowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateStylesheetRepository(uow)) - { - repository.AddOrUpdate(stylesheet); - uow.Commit(); + SavedStylesheet.RaiseEvent(new SaveEventArgs(stylesheet, false), this); + } - if (Saved != null) - Saved(stylesheet, e); - } - - Audit.Add(AuditTypes.Save, string.Format("Save Stylesheet performed by user"), userId == -1 ? 0 : userId, -1); - } + Audit.Add(AuditTypes.Save, string.Format("Save Stylesheet performed by user"), userId == -1 ? 0 : userId, -1); } /// @@ -97,20 +92,15 @@ namespace Umbraco.Core.Services { var stylesheet = repository.Get(name); - var e = new DeleteEventArgs(); - if (Deleting != null) - Deleting(stylesheet, e); + if (DeletingStylesheet.IsRaisedEventCancelled(new DeleteEventArgs(stylesheet), this)) + return; - if (!e.Cancel) - { - repository.Delete(stylesheet); - uow.Commit(); + repository.Delete(stylesheet); + uow.Commit(); - if (Deleted != null) - Deleted(stylesheet, e); + DeletedStylesheet.RaiseEvent(new DeleteEventArgs(stylesheet, false), this); - Audit.Add(AuditTypes.Delete, string.Format("Delete Stylesheet performed by user"), userId == -1 ? 0 : userId, -1); - } + Audit.Add(AuditTypes.Delete, string.Format("Delete Stylesheet performed by user"), userId == -1 ? 0 : userId, -1); } } @@ -156,24 +146,19 @@ namespace Umbraco.Core.Services /// public void SaveScript(Script script, int userId = -1) { - var e = new SaveEventArgs(); - if (Saving != null) - Saving(script, e); + if (SavingScript.IsRaisedEventCancelled(new SaveEventArgs