using System; using System.Collections.Generic; using System.Diagnostics; using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors.ValueConverters; namespace Umbraco.Web.Models { /// /// Provide an abstract base class for IPublishedContent implementations. /// /// This base class does which (a) consistently resolves and caches the Url, (b) provides an implementation /// for this[alias], and (c) provides basic content set management. [DebuggerDisplay("Content Id: {Id}, Name: {Name}")] public abstract class PublishedContentBase : IPublishedContent { protected PublishedContentBase(IUmbracoContextAccessor umbracoContextAccessor) { UmbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); } protected IUmbracoContextAccessor UmbracoContextAccessor { get; } #region ContentType public abstract IPublishedContentType ContentType { get; } #endregion #region PublishedElement /// public abstract Guid Key { get; } #endregion #region PublishedContent /// public abstract int Id { get; } /// public abstract string Name(string culture = null); /// public abstract string UrlSegment(string culture = null); /// public abstract int SortOrder { get; } /// public abstract int Level { get; } /// public abstract string Path { get; } /// public abstract int? TemplateId { get; } /// public abstract int CreatorId { get; } /// public abstract string CreatorName { get; } /// public abstract DateTime CreateDate { get; } /// public abstract int WriterId { get; } /// public abstract string WriterName { get; } /// public abstract DateTime UpdateDate { get; } /// /// /// The url of documents are computed by the document url providers. The url of medias are, at the moment, /// computed here from the 'umbracoFile' property -- but we should move to media url providers at some point. /// public virtual string Url(string culture = null, UrlMode mode = UrlMode.Auto) { switch (ContentType.ItemType) { case PublishedItemType.Content: var umbracoContext = UmbracoContextAccessor.UmbracoContext; if (umbracoContext == null) throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext is null."); if (umbracoContext.UrlProvider == null) throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext.UrlProvider is null."); return umbracoContext.UrlProvider.GetUrl(this, mode, culture); case PublishedItemType.Media: if (mode == UrlMode.Absolute) throw new NotSupportedException("Absolute urls are not supported for media items."); var prop = GetProperty(Constants.Conventions.Media.File); if (prop?.GetValue() == null) { return string.Empty; } var propType = ContentType.GetPropertyType(Constants.Conventions.Media.File); // TODO: consider implementing media url providers // note: that one does not support variations //This is a hack - since we now have 2 properties that support a URL: upload and cropper, we need to detect this since we always // want to return the normal URL and the cropper stores data as json switch (propType.EditorAlias) { case Constants.PropertyEditors.Aliases.UploadField: return prop.GetValue().ToString(); case Constants.PropertyEditors.Aliases.ImageCropper: //get the url from the json format var stronglyTyped = prop.GetValue() as ImageCropperValue; if (stronglyTyped != null) { return stronglyTyped.Src; } return prop.GetValue()?.ToString(); } return string.Empty; default: throw new NotSupportedException(); } } /// public abstract DateTime CultureDate(string culture = null); /// public abstract IReadOnlyList Cultures { get; } /// public abstract bool IsDraft(string culture = null); /// public abstract bool IsPublished(string culture = null); #endregion #region Tree /// public abstract IPublishedContent Parent(); /// public abstract IEnumerable Children { get; } #endregion #region Properties /// public abstract IEnumerable Properties { get; } /// public abstract IPublishedProperty GetProperty(string alias); #endregion } }