public IHttpActionResult FindContentReferencesByUrl(SearchByUrlRequest request) { if (string.IsNullOrWhiteSpace(request?.TargetUrl) || !Uri.TryCreate(request.TargetUrl, UriKind.Absolute, out Uri uri)) { return(BadRequest($"A valid {nameof(request.TargetUrl)} must be provided. Ensure that the Url you are using is absolute")); } IPublishedContent content = _ReferenceFinderContentService.TypedContent(uri); var references = _ReferenceFinderService.FindContentWithReferences(content.Id); return(Json(new SearchResult(references))); }
private void FindContentWithReferencesToContent_Recursive(int contentId, IPublishedContent content, Dictionary <int, IPublishedContent> haveReferences, HashSet <int> contentSearched) { if (contentSearched.Contains(content.Id)) { return; } contentSearched.Add(content.Id); //loop through all properties with a value foreach (var property in content.Properties.Where(p => p.HasValue)) { var type = property.GetType(); var propertyTypeProp = type.GetField("PropertyType"); //if we fail to determine the type of the property, skip and keep looping if (propertyTypeProp == null) { continue; } var propertyType = propertyTypeProp.GetValue(property); var propertyTypeType = propertyType.GetType(); var propertyEditorAliasProp = propertyTypeType.GetProperty("PropertyEditorAlias"); //if we fail to determine the alias of the property's editor, skip and keep looping if (propertyEditorAliasProp == null) { continue; } var propertyEditorAlias = propertyEditorAliasProp.GetValue(propertyType)?.ToString(); Regex contentPickerPattern = new Regex(@"Umbraco\.ContentPicker", RegexOptions.Compiled); Regex mediaPickerPattern = new Regex(@"Umbraco\.MediaPicker", RegexOptions.Compiled); bool isContentPicker = contentPickerPattern.IsMatch(propertyEditorAlias ?? ""); bool isMediaPicker = mediaPickerPattern.IsMatch(propertyEditorAlias ?? ""); // we only care about content and media picker properties atm if (!isContentPicker && !isMediaPicker) { continue; } if (isContentPicker) { //try to parse the property value as an int. single ints are used for a single content/media item if (int.TryParse(property.Value.ToString(), out int propertyContentId)) { if (contentId == propertyContentId && !haveReferences.ContainsKey(content.Id)) { //this property contains a reference to the id we are searching for, therefore we store the id of the content indicating where the content is referenced haveReferences.Add(content.Id, content); break; } //this property does not contain a reference to the id we are searching for, therefore we need to search each property var innerContent = _ContentService.TypedContent(propertyContentId); FindContentWithReferencesToContent_Recursive(contentId, innerContent, haveReferences, contentSearched); continue; } //property value was not an int, therefore check if it is a collection of IPublishedContents. an array of IPublishedContents are used for multiple content/media items IPublishedContent[] publishedContentCollection = (property.Value as IEnumerable <IPublishedContent>)?.ToArray(); if (publishedContentCollection != null && publishedContentCollection.Any()) { //loop through each id and check if it matches the id we are searching for foreach (var publishedContent in publishedContentCollection) { if (publishedContent.Id == contentId && !haveReferences.ContainsKey(content.Id)) { //this property contains a reference to the id we are searching for, therefore we store the id of the content indicating where the content is referenced haveReferences.Add(content.Id, content); break; } FindContentWithReferencesToContent_Recursive(contentId, publishedContent, haveReferences, contentSearched); } } //property value was not a collection of IPublishedContents, therefore check if it is a collection of ints. an array of ints are used for multiple content/media items int[] publishedContentIdCollection = (property.Value as IEnumerable <int>)?.ToArray(); if (publishedContentIdCollection != null && publishedContentIdCollection.Any()) { //loop through each id and check if it matches the id we are searching for foreach (var id in publishedContentIdCollection) { if (id == contentId && !haveReferences.ContainsKey(content.Id)) { //this property contains a reference to the id we are searching for, therefore we store the id of the content indicating where the content is referenced haveReferences.Add(content.Id, content); break; } var listContent = _ContentService.TypedContent(propertyContentId); FindContentWithReferencesToContent_Recursive(contentId, listContent, haveReferences, contentSearched); } } } if (!isMediaPicker) { continue; } //try to parse the property value as an int. single ints are used for a single content/media item if (int.TryParse(property.Value.ToString(), out int propertyMediaId)) { if (contentId != propertyMediaId || haveReferences.ContainsKey(content.Id)) { continue; } //this property contains a reference to the id we are searching for, therefore we store the id of the content indicating where the content is referenced haveReferences.Add(content.Id, content); } //property value was not an int, therefore check if it is a collection of ints. an array of ints are used for multiple content/media items IPublishedContent[] publishedMediaCollection = (property.Value as IEnumerable <IPublishedContent>)?.ToArray(); if (publishedMediaCollection != null && publishedMediaCollection.Any()) { //loop through each id and check if it matches the id we are searching for foreach (var publishedMedia in publishedMediaCollection) { if (publishedMedia.Id != contentId || haveReferences.ContainsKey(content.Id)) { continue; } //this property contains a reference to the id we are searching for, therefore we store the id of the content indicating where the content is referenced haveReferences.Add(content.Id, content); } } } foreach (var child in content.Children) { FindContentWithReferencesToContent_Recursive(contentId, child, haveReferences, contentSearched); } }