Created
May 18, 2017 01:22
-
-
Save Shazwazza/007d4e2b1000efae127757219b68ca70 to your computer and use it in GitHub Desktop.
Using the Umbraco Relation Service to relate items on a saved event based on property values
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using System.Text.RegularExpressions; | |
using Umbraco.Core; | |
using Umbraco.Core.Models; | |
using Umbraco.Core.Services; | |
using HtmlAgilityPack; | |
using Umbraco.Web; | |
using Umbraco.Web.Templates; | |
namespace Test | |
{ | |
public class MyStartup : ApplicationEventHandler | |
{ | |
/// <summary> | |
/// Bind to umbraco events when the application is ready | |
/// </summary> | |
/// <param name="umbracoApplication"></param> | |
/// <param name="applicationContext"></param> | |
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) | |
{ | |
ContentService.Saved += ContentService_Saved; | |
MediaService.Saved += MediaService_Saved; | |
} | |
private static readonly string[] KnownPickerAliases = new[] { "myContentPicker", "myMediaPicker" }; | |
//TODO: You would need to create this relation type in the back office developer section! | |
private const string MyRelationType = "myRelationType"; | |
//This is used to parse LocalLinks in a rich text string - this is copied from Umbraco because unfortuantely there is no public APIs to do this | |
private static readonly Regex LocalLinkPattern = new Regex(@"href=""[/]?(?:\{|\%7B)localLink:([a-zA-Z0-9-://]+)(?:\}|\%7D)", | |
RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); | |
/// <summary> | |
/// Execute when a content item is saved | |
/// </summary> | |
/// <param name="sender"></param> | |
/// <param name="e"></param> | |
private void ContentService_Saved(IContentService sender, Umbraco.Core.Events.SaveEventArgs<IContent> e) | |
{ | |
var relationService = ApplicationContext.Current.Services.RelationService; | |
var myRelationType = relationService.GetRelationTypeByAlias(MyRelationType); | |
if (myRelationType == null) | |
throw new InvalidOperationException("No relation type found with alias " + MyRelationType); | |
foreach (var entity in e.SavedEntities) | |
{ | |
foreach (var prop in entity.Properties) | |
{ | |
if (KnownPickerAliases.Contains(prop.Alias)) | |
{ | |
//this is a known property that may contain a relation | |
var propValue = prop.Value; | |
if (propValue == null) continue; | |
//TODO: Need to determine what type if value this is based on what type of property editor it is, example: | |
switch (prop.PropertyType.PropertyEditorAlias) | |
{ | |
case Constants.PropertyEditors.ContentPickerAlias: | |
case Constants.PropertyEditors.MediaPickerAlias: | |
//We know these property editors store Integer values | |
int relatedContentId; | |
if (int.TryParse(propValue.ToString(), out relatedContentId)) | |
{ | |
//In this case we know that this content item has referenced another content item, so create a relation for that | |
relationService.Save(new Relation(entity.Id, relatedContentId, myRelationType)); | |
} | |
break; | |
case Constants.PropertyEditors.TinyMCEAlias: | |
//This one is tricky because it will just contain text that needs to be parsed | |
//We want to find: Links to other documents, Images to media items | |
//Links are easier since these are stored as a special 'locallink' value, media items are more difficult | |
//because they are just stored with image elements like like: | |
// <img src="/media/1235/mypicture.jpg" rel=1235 /> | |
// But as you can see there is a "rel" attribute which denotes the media id so you can use that. | |
var propertyValueAsString = propValue.ToString(); | |
//This is one way to do the media: | |
var html = new HtmlDocument(); | |
html.LoadHtml(propertyValueAsString); | |
var imgTags = html.DocumentNode.FirstChild.SelectNodes(".//img"); | |
if (imgTags != null) | |
{ | |
foreach (var img in imgTags) | |
{ | |
//is element | |
if (img.NodeType != HtmlNodeType.Element) continue; | |
var mediaId = img.GetAttributeValue("rel", 0); | |
if (mediaId != 0) | |
{ | |
relationService.Save(new Relation(entity.Id, mediaId, myRelationType)); | |
} | |
} | |
} | |
//This is how you can parse locallinks | |
var tags = LocalLinkPattern.Matches(propertyValueAsString); | |
foreach (Match tag in tags) | |
{ | |
if (tag.Groups.Count > 0) | |
{ | |
var id = tag.Groups[1].Value; | |
int intId; | |
if (int.TryParse(id, out intId)) | |
{ | |
relationService.Save(new Relation(entity.Id, intId, myRelationType)); | |
} | |
} | |
} | |
break; | |
//TODO: Add more case statements | |
} | |
} | |
} | |
} | |
} | |
/// <summary> | |
/// Execute when a media item is saved | |
/// </summary> | |
/// <param name="sender"></param> | |
/// <param name="e"></param> | |
private void MediaService_Saved(IMediaService sender, Umbraco.Core.Events.SaveEventArgs<IMedia> e) | |
{ | |
//TODO: Similar implementation for media as content | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment