Skip to content

Instantly share code, notes, and snippets.

@Shazwazza
Created May 18, 2017 01:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Shazwazza/007d4e2b1000efae127757219b68ca70 to your computer and use it in GitHub Desktop.
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
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