public void Save(TItem?item, int userId = Cms.Core.Constants.Security.SuperUserId)
        {
            if (item is null)
            {
                return;
            }

            using (ICoreScope scope = ScopeProvider.CreateCoreScope())

            {
                EventMessages eventMessages = EventMessagesFactory.Get();
                SavingNotification <TItem> savingNotification = GetSavingNotification(item, eventMessages);
                if (scope.Notifications.PublishCancelable(savingNotification))
                {
                    scope.Complete();
                    return;
                }

                if (string.IsNullOrWhiteSpace(item.Name))
                {
                    throw new ArgumentException("Cannot save item with empty name.");
                }

                if (item.Name != null && item.Name.Length > 255)
                {
                    throw new InvalidOperationException("Name cannot be more than 255 characters in length.");
                }

                scope.WriteLock(WriteLockIds);

                // validate the DAG transform, within the lock
                ValidateLocked(item); // throws if invalid

                item.CreatorId = userId;
                if (item.Description == string.Empty)
                {
                    item.Description = null;
                }

                Repository.Save(item); // also updates content/media/member items

                // figure out impacted content types
                ContentTypeChange <TItem>[] changes = ComposeContentTypeChanges(item).ToArray();

                // Publish this in scope, see comment at GetContentTypeRefreshedNotification for more info.
                _eventAggregator.Publish(GetContentTypeRefreshedNotification(changes, eventMessages));

                scope.Notifications.Publish(GetContentTypeChangedNotification(changes, eventMessages));

                SavedNotification <TItem> savedNotification = GetSavedNotification(item, eventMessages);
                savedNotification.WithStateFrom(savingNotification);
                scope.Notifications.Publish(savedNotification);

                Audit(AuditType.Save, userId, item.Id);
                scope.Complete();
            }
        }
        public void Save(IEnumerable <TItem> items, int userId = Cms.Core.Constants.Security.SuperUserId)
        {
            TItem[] itemsA = items.ToArray();

            using (IScope scope = ScopeProvider.CreateScope())
            {
                EventMessages eventMessages = EventMessagesFactory.Get();
                SavingNotification <TItem> savingNotification = GetSavingNotification(itemsA, eventMessages);
                if (scope.Notifications.PublishCancelable(savingNotification))
                {
                    scope.Complete();
                    return;
                }

                scope.WriteLock(WriteLockIds);

                // all-or-nothing, validate them all first
                foreach (TItem contentType in itemsA)
                {
                    ValidateLocked(contentType); // throws if invalid
                }
                foreach (TItem contentType in itemsA)
                {
                    contentType.CreatorId = userId;
                    if (contentType.Description == string.Empty)
                    {
                        contentType.Description = null;
                    }

                    Repository.Save(contentType);
                }

                // figure out impacted content types
                ContentTypeChange <TItem>[] changes = ComposeContentTypeChanges(itemsA).ToArray();

                // Publish this in scope, see comment at GetContentTypeRefreshedNotification for more info.
                _eventAggregator.Publish(GetContentTypeRefreshedNotification(changes, eventMessages));;

                scope.Notifications.Publish(GetContentTypeChangedNotification(changes, eventMessages));

                SavedNotification <TItem> savedNotification = GetSavedNotification(itemsA, eventMessages);
                savedNotification.WithStateFrom(savingNotification);
                scope.Notifications.Publish(savedNotification);

                Audit(AuditType.Save, userId, -1);
                scope.Complete();
            }
        }
    public Attempt <OperationResult <MoveOperationStatusType, TItem>?> Copy(TItem copying, int containerId)
    {
        EventMessages eventMessages = EventMessagesFactory.Get();

        TItem copy;

        using (ICoreScope scope = ScopeProvider.CreateCoreScope())
        {
            scope.WriteLock(WriteLockIds);

            try
            {
                if (containerId > 0)
                {
                    EntityContainer?container = _containerRepository?.Get(containerId);
                    if (container == null)
                    {
                        throw new DataOperationException <MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound); // causes rollback
                    }
                }

                var alias = Repository.GetUniqueAlias(copying.Alias);

                // this is illegal
                //var copyingb = (ContentTypeCompositionBase) copying;
                // but we *know* it has to be a ContentTypeCompositionBase anyways
                var copyingb = (ContentTypeCompositionBase)(object)copying;
                copy = (TItem)(object)copyingb.DeepCloneWithResetIdentities(alias);

                copy.Name = copy.Name + " (copy)"; // might not be unique

                // if it has a parent, and the parent is a content type, unplug composition
                // all other compositions remain in place in the copied content type
                if (copy.ParentId > 0)
                {
                    TItem?parent = Repository.Get(copy.ParentId);
                    if (parent != null)
                    {
                        copy.RemoveContentType(parent.Alias);
                    }
                }

                copy.ParentId = containerId;

                SavingNotification <TItem> savingNotification = GetSavingNotification(copy, eventMessages);
                if (scope.Notifications.PublishCancelable(savingNotification))
                {
                    scope.Complete();
                    return(OperationResult.Attempt.Fail(MoveOperationStatusType.FailedCancelledByEvent, eventMessages, copy));
                }

                Repository.Save(copy);

                ContentTypeChange <TItem>[] changes = ComposeContentTypeChanges(copy).ToArray();

                _eventAggregator.Publish(GetContentTypeRefreshedNotification(changes, eventMessages));
                scope.Notifications.Publish(GetContentTypeChangedNotification(changes, eventMessages));

                SavedNotification <TItem> savedNotification = GetSavedNotification(copy, eventMessages);
                savedNotification.WithStateFrom(savingNotification);
                scope.Notifications.Publish(savedNotification);

                scope.Complete();
            }
            catch (DataOperationException <MoveOperationStatusType> ex)
            {
                return(OperationResult.Attempt.Fail <MoveOperationStatusType, TItem>(ex.Operation, eventMessages)); // causes rollback
            }
        }

        return(OperationResult.Attempt.Succeed(MoveOperationStatusType.Success, eventMessages, copy));
    }