Models - JimBobSquarePants/Zoombraco GitHub Wiki
Zoombraco breaks down content types into three types. Page
, Component
, and NestedComponent
providing base classes for each type.
The classification of these types is as follows:
-
Page
Any content representing a web page that has a public url. -
Component
A reusable block of content that can be shared across one or more pages. Generally stored in a library. -
NestedComponent
A non-reusable, nested, block of content that can be used as part of a collection to build page content.
An example Page
implementation would be as follows.
/// <summary>
/// The generic page document type
/// </summary>
public class Generic : Page, INested
{
/// <inheritdoc />
public virtual IEnumerable<NestedComponent> NestedContent { get; set; }
}
Note in this example we are able to automatically bind anything that inherits NestedComponent
without additional attribution.
An example NestedComponent
implementation would be as follows.
/// <summary>
/// A nested rich text editor for adding block of copy to pages
/// </summary>
public class NestedRichText : NestedComponent
{
/// <summary>
/// Gets or sets the body text
/// </summary>
public virtual HtmlString BodyText { get; set; }
}
An example Component
implementation would be as follows.
/// <summary>
/// Global application-wide settings
/// </summary>
public class Settings : Component
{
/// <summary>
/// Gets or sets the LinkedIn Id
/// </summary>
public virtual string LinkedInId { get; set; }
/// <summary>
/// Gets or sets the Twitter Id
/// </summary>
public virtual string TwitterId { get; set; }
/// <summary>
/// Gets or sets the YouTube Id
/// </summary>
public virtual string YouTubeId { get; set; }
/// <summary>
/// Gets or sets the collection of main navigation item links.
/// </summary>
public virtual IEnumerable<RelatedLink> MainNavigationItems { get; set; }
}
Page
and Component
classes come equipped with navigation methods that allow strong-typed retrieval of content using methods similar to that of UmbracoHelper
. They are defined via the INavigation
interface as follows. Each method can accept either concrete classes, base classes or interfaces.
/// <summary>
/// Encapsulates methods that allow the retrieval of relative nodes.
/// </summary>
public interface INavigation
{
/// <summary>
/// Gets the parent of the current instance as the given <see cref="Type"/>.
/// </summary>
/// <typeparam name="T">The type to return</typeparam>
/// <returns>
/// The type instance.
/// </returns>
T Parent<T>();
/// <summary>
/// Gets the ancestors of the current instance as the given <see cref="Type"/>.
/// </summary>
/// <typeparam name="T">The type to return</typeparam>
/// <param name="maxLevel">The maximum level to search.</param>
/// <returns>
/// The <see cref="IEnumerable{T}"/>.
/// </returns>
IEnumerable<T> Ancestors<T>(int maxLevel);
/// <summary>
/// Gets the children of the current instance as the given <see cref="Type"/>.
/// </summary>
/// <typeparam name="T">The type to return</typeparam>
/// <returns>
/// The <see cref="IEnumerable{T}"/>.
/// </returns>
IEnumerable<T> Children<T>();
/// <summary>
/// Gets the descendants of the current instance as the given <see cref="Type"/>.
/// </summary>
/// <typeparam name="T">The type to return</typeparam>
/// <param name="level">The level to search.</param>
/// <returns>
/// The <see cref="IEnumerable{T}"/>.
/// </returns>
IEnumerable<T> Descendents<T>(int level);
}
In order to allow peak performance by reducing the amount of eagerly implemented property mapping it is recommended that you use the virtual
keyword when declaring properties. This allows the Ditto proxy generator to intercept the property generation code and lazily implement the property mapping.
It is recommended to make heavy use of compositions to build up your document types. The most flexible pattern that will allow greater future proofing is to create interfaces to represent each composition and implement them for each class. Do not use inheritance other than inheriting from the base classes.