Skip to content

Conversation

Zeegaan
Copy link
Member

@Zeegaan Zeegaan commented Sep 29, 2025

Notes

  • This is a feature, that aims to let the user know, if the document type is referenced anywhere, the most common use case is, when you go to delete a document type, you would like to know if it is used somewhere before deleting it, as it can have massive consequences.
  • This PR remedies that, by implemeting a service that covers 3 different uses:
    • Referenced by documents, supply a document type key, and you will get back a list of all the document keys that is created from that document type
    • Referenced by other document types, supply a document type key, and you will get back a list of all the document type keys, that inherit from that document type.
    • Datatypes referincing that document type, supply a document type key (element), and it will return a list of all the data type keys, (blocklist, blockgrid & richtext data types) that references this doucment type (element type)

How to test

  • You can look at the integration tests created for inspiration.
  • For the first use case, create a document type (or multiple)
  • Create some content from this document type, keep a track of how many you create
    • Call the service with the document type you created, and assert it returns the correct number and correct guids
  • For the second use case, create 2 document types, 1 inheriting from the other. ( again you can do multiple here)
    • Call the service with the document type that is inherited FROM, assert it returns the correct number of document types and the GUIDS are correct
  • For the third and last use case, this time, start by creating a document type, but create it as an element.
    • Create a document type, with a block list/blockgrid/richtext, that uses the element you've created
    • Call the service with the element type key you've created, assert it returns the correct number and GUIDS

@Zeegaan Zeegaan marked this pull request as ready for review September 29, 2025 15:25
@Copilot Copilot AI review requested due to automatic review settings September 29, 2025 15:25
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements a new feature to track document type references across the Umbraco CMS system. The implementation provides backend services and API endpoints to help users understand dependencies before deleting document types.

  • Implements service layer for tracking three types of document type references: documents using a document type, document types inheriting from another, and data types (block list/grid/rich text) referencing element types
  • Adds repository methods for querying document and content type relationships
  • Creates API controllers with pagination support for exposing reference information via REST endpoints

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
ContentTypeReferenceServiceTests.cs Integration tests covering all three reference scenarios with multiple block editor types
DocumentRepository.cs Repository method to find documents by document type key using SQL joins
DataTypeRepository.cs Repository method to find block editors referencing content types by parsing configurations
ContentTypeRepository.cs Repository method to find child content types using composition relationships
IContentTypeReferenceService.cs Service interface defining three async methods for getting references
ContentTypeReferenceService.cs Service implementation coordinating repository calls within database scopes
IDocumentRepository.cs Interface extension adding document reference query method
IDataTypeRepository.cs Interface extension adding block editor reference query method
IContentTypeRepository.cs Interface extension adding child content type query method
UmbracoBuilder.cs Dependency injection registration for the new service
ReferencedByDocumentTypeDocumentTypeController.cs API controller for document types that inherit from a given type
ReferencedByDocumentDocumentTypeController.cs API controller for documents using a given document type
ReferencedByDataTypeDocumentTypeController.cs API controller for data types referencing a given element type

Copy link
Contributor

@AndyButland AndyButland left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks really good @Zeegaan. I haven't done a thorough review with testing as I saw Kenn already had 👀on it, but have left a few small formatting suggestions and a question about whether the paging should be introduced on the methods where you return PagedModel but don't currently accept skip and take.

/// </summary>
bool RecycleBinSmells();

PagedModel<Guid> GetReferencingDocumentsByDocumentTypeKey(Guid documentTypeKey) => throw new NotImplementedException();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this have the skip and take parameters? Maybe in practice it's fine to get all, but it feels a little odd to return PagedModel without them.

{
using ICoreScope scope = _coreScopeProvider.CreateCoreScope();

PagedModel<Guid> keys = _contentTypeRepository.GetChildren(key);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this will get the inheriting document types - i.e. the children. But should it also get document types that are use the provided document type key as a composition?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What @AndyButland said. Also, it applies to all descendants, not just immediate children.

Historically we've "just" loaded all content types and handled these kind of reference detection/validation in memory, from the notion that there really isn't that many content types for it to be a problem. See for example GetAvailableCompositeContentTypes(), which is used to figure out applicable content types available for composition given certain filtering requirements. It expects allContentTypes.

Constants.PropertyEditors.Aliases.BlockList,
Constants.PropertyEditors.Aliases.RichText,
};
// Get All contentTypes where isContainer (list view enabled) is set to true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Get All contentTypes where isContainer (list view enabled) is set to true
// Get All contentTypes where isContainer (list view enabled) is set to true

.From<DataTypeDto>()
.InnerJoin<NodeDto>()
.On<DataTypeDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.WhereIn<DataTypeDto>(n => n.EditorAlias, blockEditorAliases );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.WhereIn<DataTypeDto>(n => n.EditorAlias, blockEditorAliases );
.WhereIn<DataTypeDto>(n => n.EditorAlias, blockEditorAliases);

case Constants.PropertyEditors.Aliases.BlockGrid:
BlockGridConfiguration? blockGridConfigurations = ConfigurationEditor.ConfigurationAs<BlockGridConfiguration>(dataType.ConfigurationObject);

if(blockGridConfigurations is null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if(blockGridConfigurations is null)
if (blockGridConfigurations is null)


IEnumerable<int> GetAllContentTypeIds(string[] aliases);

PagedModel<Guid> GetChildren(Guid parentKey) => throw new NotImplementedException();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this method is necessary ref. the comments in ContentTypeReferenceService

Comment on lines +222 to +224
Constants.PropertyEditors.Aliases.BlockGrid,
Constants.PropertyEditors.Aliases.BlockList,
Constants.PropertyEditors.Aliases.RichText,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While this is true from a core perspective, it does not take into account that extensions might also reference content types. Specifically custom block editors will do, but in theory - any extension can utilize a content type.

_dataTypeRepository = dataTypeRepository;
}

public Task<PagedModel<Guid>> GetReferencedDocumentKeysAsync(Guid key, CancellationToken cancellationToken, int skip, int take)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like skip and take is ever applied here.

Comment on lines +1540 to +1545
Sql<ISqlContext> sqlContentTypeId = Sql()
.Select<ContentTypeDto>(x => x.NodeId)
.From<ContentTypeDto>()
.InnerJoin<NodeDto>()
.On<ContentTypeDto, NodeDto>((c, n) => c.NodeId == n.NodeId)
.Where<NodeDto>(x => x.UniqueId == documentTypeKey);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any chance the IIdKeyMap service could be applied here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants