33using System . Runtime . Serialization ;
44using System . Xml . Linq ;
55using Microsoft . Extensions . Logging ;
6+ using Umbraco . Cms . Core . Cache ;
67using Umbraco . Cms . Core . IO ;
78using Umbraco . Cms . Core . Models ;
89using Umbraco . Cms . Core . Models . Editors ;
910using Umbraco . Cms . Core . Models . Validation ;
1011using Umbraco . Cms . Core . PropertyEditors . Validators ;
1112using Umbraco . Cms . Core . Serialization ;
13+ using Umbraco . Cms . Core . Services ;
1214using Umbraco . Cms . Core . Strings ;
1315using Umbraco . Extensions ;
1416
@@ -20,6 +22,9 @@ namespace Umbraco.Cms.Core.PropertyEditors;
2022[ DataContract ]
2123public class DataValueEditor : IDataValueEditor
2224{
25+ private const string ContentCacheKeyFormat = nameof ( DataValueEditor ) + "_Content_{0}" ;
26+ private const string MediaCacheKeyFormat = nameof ( DataValueEditor ) + "_Media_{0}" ;
27+
2328 private readonly IJsonSerializer ? _jsonSerializer ;
2429 private readonly IShortStringHelper _shortStringHelper ;
2530
@@ -415,4 +420,155 @@ public virtual string ConvertDbToString(IPropertyType propertyType, object? valu
415420
416421 return value . TryConvertTo ( valueType ) ;
417422 }
423+
424+ /// <summary>
425+ /// Retrieves a <see cref="IContent"/> instance by its unique identifier, using the provided request cache to avoid redundant
426+ /// lookups within the same request.
427+ /// </summary>
428+ /// <remarks>
429+ /// This method caches content lookups for the duration of the current request to improve performance when the same content
430+ /// item may be accessed multiple times. This is particularly useful in scenarios involving multiple languages or blocks.
431+ /// </remarks>
432+ /// <param name="key">The unique identifier of the content item to retrieve.</param>
433+ /// <param name="requestCache">The request-scoped cache used to store and retrieve content items for the duration of the current request.</param>
434+ /// <param name="contentService">The content service used to fetch the content item if it is not found in the cache.</param>
435+ /// <returns>The <see cref="IContent"/> instance corresponding to the specified key, or null if no such content item exists.</returns>
436+ [ Obsolete ( "This method is available for support of request caching retrieved entities in derived property value editors. " +
437+ "The intention is to supersede this with lazy loaded read locks, which will make this unnecessary. " +
438+ "Scheduled for removal in Umbraco 19." ) ]
439+ protected static IContent ? GetAndCacheContentById ( Guid key , IRequestCache requestCache , IContentService contentService )
440+ {
441+ if ( requestCache . IsAvailable is false )
442+ {
443+ return contentService . GetById ( key ) ;
444+ }
445+
446+ var cacheKey = string . Format ( ContentCacheKeyFormat , key ) ;
447+ IContent ? content = requestCache . GetCacheItem < IContent ? > ( cacheKey ) ;
448+ if ( content is null )
449+ {
450+ content = contentService . GetById ( key ) ;
451+ if ( content is not null )
452+ {
453+ requestCache . Set ( cacheKey , content ) ;
454+ }
455+ }
456+
457+ return content ;
458+ }
459+
460+ /// <summary>
461+ /// Adds the specified <see cref="IContent"/> item to the request cache using its unique key.
462+ /// </summary>
463+ /// <param name="content">The content item to cache.</param>
464+ /// <param name="requestCache">The request cache in which to store the content item.</param>
465+ [ Obsolete ( "This method is available for support of request caching retrieved entities in derived property value editors. " +
466+ "The intention is to supersede this with lazy loaded read locks, which will make this unnecessary. " +
467+ "Scheduled for removal in Umbraco 19." ) ]
468+ protected static void CacheContentById ( IContent content , IRequestCache requestCache )
469+ {
470+ if ( requestCache . IsAvailable is false )
471+ {
472+ return ;
473+ }
474+
475+ var cacheKey = string . Format ( ContentCacheKeyFormat , content . Key ) ;
476+ requestCache . Set ( cacheKey , content ) ;
477+ }
478+
479+ /// <summary>
480+ /// Retrieves a <see cref="IMedia"/> instance by its unique identifier, using the provided request cache to avoid redundant
481+ /// lookups within the same request.
482+ /// </summary>
483+ /// <remarks>
484+ /// This method caches media lookups for the duration of the current request to improve performance when the same media
485+ /// item may be accessed multiple times. This is particularly useful in scenarios involving multiple languages or blocks.
486+ /// </remarks>
487+ /// <param name="key">The unique identifier of the media item to retrieve.</param>
488+ /// <param name="requestCache">The request-scoped cache used to store and retrieve media items for the duration of the current request.</param>
489+ /// <param name="mediaService">The media service used to fetch the media item if it is not found in the cache.</param>
490+ /// <returns>The <see cref="IMedia"/> instance corresponding to the specified key, or null if no such media item exists.</returns>
491+ [ Obsolete ( "This method is available for support of request caching retrieved entities in derived property value editors. " +
492+ "The intention is to supersede this with lazy loaded read locks, which will make this unnecessary. " +
493+ "Scheduled for removal in Umbraco 19." ) ]
494+ protected static IMedia ? GetAndCacheMediaById ( Guid key , IRequestCache requestCache , IMediaService mediaService )
495+ {
496+ if ( requestCache . IsAvailable is false )
497+ {
498+ return mediaService . GetById ( key ) ;
499+ }
500+
501+ var cacheKey = string . Format ( MediaCacheKeyFormat , key ) ;
502+ IMedia ? media = requestCache . GetCacheItem < IMedia ? > ( cacheKey ) ;
503+
504+ if ( media is null )
505+ {
506+ media = mediaService . GetById ( key ) ;
507+ if ( media is not null )
508+ {
509+ requestCache . Set ( cacheKey , media ) ;
510+ }
511+ }
512+
513+ return media ;
514+ }
515+
516+ /// <summary>
517+ /// Adds the specified <see cref="IMedia"/> item to the request cache using its unique key.
518+ /// </summary>
519+ /// <param name="media">The media item to cache.</param>
520+ /// <param name="requestCache">The request cache in which to store the media item.</param>
521+ [ Obsolete ( "This method is available for support of request caching retrieved entities in derived property value editors. " +
522+ "The intention is to supersede this with lazy loaded read locks, which will make this unnecessary. " +
523+ "Scheduled for removal in Umbraco 19." ) ]
524+ protected static void CacheMediaById ( IMedia media , IRequestCache requestCache )
525+ {
526+ if ( requestCache . IsAvailable is false )
527+ {
528+ return ;
529+ }
530+
531+ var cacheKey = string . Format ( MediaCacheKeyFormat , media . Key ) ;
532+ requestCache . Set ( cacheKey , media ) ;
533+ }
534+
535+ /// <summary>
536+ /// Determines whether the content item identified by the specified key is present in the request cache.
537+ /// </summary>
538+ /// <param name="key">The unique identifier for the content item to check for in the cache.</param>
539+ /// <param name="requestCache">The request cache in which to look for the content item.</param>
540+ /// <returns>true if the content item is already cached in the request cache; otherwise, false.</returns>
541+ [ Obsolete ( "This method is available for support of request caching retrieved entities in derived property value editors. " +
542+ "The intention is to supersede this with lazy loaded read locks, which will make this unnecessary. " +
543+ "Scheduled for removal in Umbraco 19." ) ]
544+ protected static bool IsContentAlreadyCached ( Guid key , IRequestCache requestCache )
545+ {
546+ if ( requestCache . IsAvailable is false )
547+ {
548+ return false ;
549+ }
550+
551+ var cacheKey = string . Format ( ContentCacheKeyFormat , key ) ;
552+ return requestCache . GetCacheItem < IContent ? > ( cacheKey ) is not null ;
553+ }
554+
555+ /// <summary>
556+ /// Determines whether the media item identified by the specified key is present in the request cache.
557+ /// </summary>
558+ /// <param name="key">The unique identifier for the media item to check for in the cache.</param>
559+ /// <param name="requestCache">The request cache in which to look for the media item.</param>
560+ /// <returns>true if the media item is already cached in the request cache; otherwise, false.</returns>
561+ [ Obsolete ( "This method is available for support of request caching retrieved entities in derived property value editors. " +
562+ "The intention is to supersede this with lazy loaded read locks, which will make this unnecessary. " +
563+ "Scheduled for removal in Umbraco 19." ) ]
564+ protected static bool IsMediaAlreadyCached ( Guid key , IRequestCache requestCache )
565+ {
566+ if ( requestCache . IsAvailable is false )
567+ {
568+ return false ;
569+ }
570+
571+ var cacheKey = string . Format ( MediaCacheKeyFormat , key ) ;
572+ return requestCache . GetCacheItem < IMedia ? > ( cacheKey ) is not null ;
573+ }
418574}
0 commit comments