Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • David McDonnell 53 posts 251 karma points
    Apr 11, 2020 @ 17:18
    David McDonnell
    0

    Umbraco 8 Usync include Relation Types

    Hi all, just wanted to document extending uSync for relation types or any other type that is not included for that matter to help anyone else who might want to do this. will save you a couple of hours research and work.

    For Umbraco 8: Managed to do this by copying the Macro Handler, Macro Serializer, Macro Tracker and Macro Checker from: [https://github.com/KevinJump/uSync8][1]

    Process Create following files:

    RelationTypeHandler

    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using Umbraco.Core;
    using Umbraco.Core.Cache;
    using Umbraco.Core.Logging;
    using Umbraco.Core.Models;
    using Umbraco.Core.Models.Entities;
    using Umbraco.Core.Services;
    using Umbraco.Core.Services.Implement;
    using uSync8.BackOffice;
    using uSync8.BackOffice.Configuration;
    using uSync8.BackOffice.Services;
    using uSync8.BackOffice.SyncHandlers;
    using uSync8.Core;
    using uSync8.Core.Dependency;
    using uSync8.Core.Extensions;
    using uSync8.Core.Serialization;
    using uSync8.Core.Tracking;
    
    using static Umbraco.Core.Constants;
    
    
    namespace CustomNameSpace
    {
        [SyncHandler("relationTypeHandler", "Relation Types", "RelationTypes", uSyncBackOfficeConstants.Priorites.MemberTypes,
            Icon = "icon-diagonal-arrow-alt", EntityType = UdiEntityType.RelationType, IsTwoPass = true)]
        public class RelationTypeHandler : SyncHandlerBase<IRelationType, IRelationService>, ISyncExtendedHandler
        {
            private readonly IRelationService relationService;
    
            public RelationTypeHandler(
                IEntityService entityService,
                IProfilingLogger logger,
                IRelationService relationService,
                ISyncSerializer<IRelationType> serializer,
                ISyncTracker<IRelationType> tracker,
                AppCaches appCaches,
                ISyncDependencyChecker<IRelationType> checker,
                SyncFileService syncFileService)
                : base(entityService, logger, serializer, tracker, appCaches, checker, syncFileService)
            {
                this.relationService = relationService;
            }
    
    
    
    
            /// <summary>
            ///  overrider the default export, because macros, don't exist as an object type???
            /// </summary>
            public override IEnumerable<uSyncAction> ExportAll(int parent, string folder, HandlerSettings config, SyncUpdateCallback callback)
            {
                // we clean the folder out on an export all. 
                syncFileService.CleanFolder(folder);
    
                var actions = new List<uSyncAction>();
    
                var items = relationService.GetAllRelationTypes().ToList();
                int count = 0;
                foreach (var item in items)
                {
                    count++;
                    callback?.Invoke(item.Name, count, items.Count);
                    actions.AddRange(Export(item, folder, config));
                }
    
                return actions;
            }
    
            protected override IRelationType GetFromService(int id)
                => relationService.GetRelationTypeById(id);
    
            // not sure we can trust macro guids in the path just yet.
            protected override string GetItemPath(IRelationType item, bool useGuid, bool isFlat)
            {
                if (useGuid) return item.Key.ToString();
                return item.Alias.ToSafeAlias();
            }
    
            protected override void InitializeEvents(HandlerSettings settings)
            {
                RelationService.SavedRelationType += EventSavedItem;
                RelationService.DeletedRelationType += EventDeletedItem;
            }
    
            protected override IRelationType GetFromService(Guid key)
            {
                return relationService.GetAllRelationTypes().FirstOrDefault(rt => rt.Key == key);
            }
    
            protected override IRelationType GetFromService(string alias)
                => relationService.GetRelationTypeByAlias(alias);
    
            protected override void DeleteViaService(IRelationType item)
                => relationService.Delete(item);
    
            protected override string GetItemName(IRelationType item)
                => item.Name;
            protected override string GetItemAlias(IRelationType item)
                => item.Alias;
    
            protected override IEnumerable<IEntity> GetChildItems(int parent)
            {
                if (parent == -1)
                {
                    return relationService.GetAllRelationTypes().Where(x => x is IEntity)
                        .Select(x => x as IEntity);
                }
    
                return Enumerable.Empty<IEntity>();
            }
    
        }
    
    }
    

    RelationTypeSerializer

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Xml.Linq;
    using Umbraco.Core.Logging;
    using Umbraco.Core.Models;
    using Umbraco.Core.Services;
    using uSync8.Core;
    using uSync8.Core.Extensions;
    using uSync8.Core.Models;
    using uSync8.Core.Serialization;
    
    namespace CustomNameSpace
    {
        [SyncSerializer("EE5439FF-37B5-4C2C-A396-233FE0563825", "RelationTypeSerializer", "RelationType")]
            public class RelationTypeSerializer: SyncSerializerBase<IRelationType>, ISyncSerializer<IRelationType>
        {
            private readonly IRelationService relationTypeService;
    
            public RelationTypeSerializer(
                IEntityService entityService, ILogger logger,
                IRelationService relationTypeService)
                : base(entityService, logger)
            {
                this.relationTypeService = relationTypeService;
            }
    
            protected override SyncAttempt<IRelationType> DeserializeCore(XElement node)
            {
                var changes = new List<uSyncChange>();
    
                if (node.Element("Name") == null)
                    throw new ArgumentNullException("XML missing Name parameter");
    
                var item = default(IRelationType);
    
                var key = node.GetKey();
                var alias = node.GetAlias();
                var name = node.Element("Name").ValueOrDefault(string.Empty);
    
                var realtionType = node.Element("RelationType").ValueOrDefault(string.Empty);
    
                logger.Debug<RelationTypeSerializer>("Relation Type by Alias [{0}]", key);
                item = relationTypeService.GetRelationTypeByAlias(alias);
    
                /*
                if (item == null)
                {
                    logger.Debug<RelationTypeSerializer>("Relation Type by Key [{0}]", key);
                    item = relationTypeService.GetRelationTypeById(key);
                }
                */
                if (item == null)
                {
                    logger.Debug<RelationTypeSerializer>("Creating New [{0}]", key);
                    item = new RelationType(Guid.Empty, Guid.Empty, alias, name);
                    changes.Add(uSyncChange.Create(alias, name, "New RelationType"));
                }
    
                item.Key = key;
                item.Name = name;
                item.Alias = alias;
    
                item.ParentObjectType = node.Element("parent").ValueOrDefault(Guid.Empty);
                item.ChildObjectType = node.Element("child").ValueOrDefault(Guid.Empty);
                item.IsBidirectional = node.Element("direction").ValueOrDefault(false);
    
                var attempt = SyncAttempt<IRelationType>.Succeed(item.Name, item, ChangeType.Import);
                if (changes.Any())
                    attempt.Details = changes;
    
                return attempt;
            }
    
            private void RemoveOrphanProperties(IRelationType item, XElement properties)
            {
                var removalKeys = new List<string>();
    
    
            }
    
            protected override SyncAttempt<XElement> SerializeCore(IRelationType item)
            {
                var node = this.InitializeBaseNode(item, item.Alias);
    
                node.Add(new XElement("Name", item.Name));
    
    
                node.Add(new XElement("parent", item.ParentObjectType));
                node.Add(new XElement("child", item.ChildObjectType));
                node.Add(new XElement("direction", item.IsBidirectional));
    
                return SyncAttempt<XElement>.SucceedIf(
                    node != null,
                    item.Name,
                    node,
                    typeof(IRelationType),
                    ChangeType.Export);
            }
    
    
    
            protected override IRelationType FindItem(string alias)
                => relationTypeService.GetRelationTypeByAlias(alias);
    
            protected override void SaveItem(IRelationType item)
                => relationTypeService.Save(item);
    
            protected override void DeleteItem(IRelationType item)
                => relationTypeService.Delete(item);
    
            protected override string ItemAlias(IRelationType item)
                => item.Alias;
    
            protected override IRelationType FindItem(Guid key)
            {
                return relationTypeService.GetAllRelationTypes().FirstOrDefault(rt => rt.Key == key);
            }
        }
    }
    

    RelationTypeTracker

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Umbraco.Core.Models;
    using uSync8.Core.Serialization;
    using uSync8.Core.Tracking;
    
    namespace CustomNamespace
    {
        public class RelationTypeTracker : SyncBaseTracker<IRelationType>, ISyncTracker<IRelationType>
        {
            public RelationTypeTracker(ISyncSerializer<IRelationType> serializer) : base(serializer)
            {
            }
    
            protected override TrackedItem TrackChanges()
            {
                return new TrackedItem(serializer.ItemType, true)
                {
                    Children = new List<TrackedItem>()
                    {
                        new TrackedItem("Name", "/Name", true),
                        new TrackedItem("parent", "/parent", true),
                        new TrackedItem("child", "/child", true),
                        new TrackedItem("direction", "/direction", true)
    
                    }
    
                };
            }
        }
    }
    

    RelationTypeChecker

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Umbraco.Core;
    using Umbraco.Core.Models;
    using uSync8.Core.Dependency;
    
    namespace CustomNameSpace
    {
        public class RelationTypeChecker : ISyncDependencyChecker<IRelationType>
        {
            public UmbracoObjectTypes ObjectType => UmbracoObjectTypes.Unknown;
    
            public IEnumerable<uSyncDependency> GetDependencies(IRelationType item, DependencyFlags flags)
            {
                var dependencies = new List<uSyncDependency>
                {
                    new uSyncDependency()
                    {
                        Name = item.Name,
                        Udi = item.GetUdi(),
                        Order = DependencyOrders.Media,
                        Flags = flags
    
                    }
                };
    
                return dependencies;
            }
        }
    }
    

    Then resolve the dependencies in your composer:

                composition.Register<ISyncSerializer<IRelationType>, RelationTypeSerializer>();
                composition.Register<ISyncTracker<IRelationType>, RelationTypeTracker>();
                composition.Register<ISyncDependencyChecker<IRelationType>, RelationTypeChecker>();
    

    Update your usync.config file

    <?xml version="1.0" encoding="utf-8"?>
    <uSync>
      <BackOffice>
        <Folder>~/uSync/v8/</Folder>
        <FlatFolders>True</FlatFolders>
        <ImportAtStartup>True</ImportAtStartup>
        <ExportAtStartup>False</ExportAtStartup>
        <ExportOnSave>True</ExportOnSave>
        <UseGuidFilenames>False</UseGuidFilenames>
        <BatchSave>False</BatchSave>
        <!-- calls a rebuild cache when an import completes
            (for Umbraco 8.3+ recommended value is false)  -->
        <RebuildCacheOnCompletion>False</RebuildCacheOnCompletion>
        <!-- handler sets -->
        <HandlerSets default="default" Default="default">
          <Handlers Name="default">
            <Handler Alias="dataTypeHandler" Enabled="true" Actions="All" />
            <Handler Alias="languageHandler" Enabled="true" Actions="All" />
            <Handler Alias="macroHandler" Enabled="true" Actions="All" />
            <Handler Alias="mediaTypeHandler" Enabled="true" Actions="All" />
            <Handler Alias="memberTypeHandler" Enabled="true" Actions="All" />
            <Handler Alias="templateHandler" Enabled="true" Actions="All" />
            <Handler Alias="contentTypeHandler" Enabled="true" Actions="All" />
            <Handler Alias="contentHandler" Enabled="true" Actions="All" />
            <Handler Alias="contentTemplateHandler" Enabled="true" Actions="All" />
            <Handler Alias="dictionaryHandler" Enabled="true" Actions="All" />
            <Handler Alias="domainHandler" Enabled="true" Actions="All" />
            <Handler Alias="mediaHandler" Enabled="true" Actions="All" />
            <Handler Alias="relationTypeHandler" Enabled="true" Actions="All" />
          </Handlers>
        </HandlerSets>
        <ReportDebug>False</ReportDebug>
        <FailOnMissingParent>True</FailOnMissingParent>
      </BackOffice>
    </uSync>
    

    Compile your code, open umbraco and just click save on all existing Relation Types

    Then import and export to include files in source control usync folder

  • Kevin Jump 2309 posts 14673 karma points MVP 7x c-trib
    Apr 16, 2020 @ 15:53
    Kevin Jump
    0

    HI David,

    This is cool, I've created an uSync.Relations project based on this code.

    https://github.com/KevinJump/uSync8/tree/v8/relations/uSync8.Relations (along with an associated git hub issue to track it )

    I think we will look into having this as either part of the core uSync package or as a add on nuget package should people want it.

    I've also added the code to sync the relations beneath the relations types, I am not sure if you would always want that, So I am going to look at the config options for this,

    I suspect people might want to turn relation syncing off either compleatly or for certain relation types (e.g the internal media/content tracking ones built into Umbraco 8.6 - might not be things you want to sync.)

    Also syncing relations probably means more events need trapping, (like the create relation one - will have to look into that too).

    Feel free to add comments and code the repo, and we could package it up for others to enjoy :)

  • David McDonnell 53 posts 251 karma points
    Apr 20, 2020 @ 10:33
    David McDonnell
    0

    Hi Kevin, thanks for the reply. Yeah great idea to set it up as part of the core.

    Definitely feel there should be configurable options as I did not want to sync the actual relations just the types, as the actual relations would be different in development, testing and live environments.

    Great work to get all that packaged up already.

Please Sign in or register to post replies

Write your reply to:

Draft