Advanced

IUIOMaticRepository/AbstractUIOMaticRepository

By default, UI-O-Matic handles all CRUD operations of UIOMatic types out of the box for you, but if you'd like more fine grained control of how your entities are fetched, or if you'd like to perform CRUD operations yourself as well, for example, in an API layer, then you might want to take a look at creating your own repository.

To help, and to ensure your repository exposes the necesary methods for UI-O-Matic to do it's thing, we have created an interface for you to implement, IUIOMaticRepository

public interface IUIOMaticRepository
{
    IEnumerable<object> GetAll(string sortColumn = "", string sortOrder = "");

    UIOMaticPagedResult GetPaged(int pageNumber, int itemsPerPage,
        string searchTerm = "",
        IDictionary<string, string> filters = null,
        string sortColumn = "", string sortOrder = "");

    object Get(string id);

    object Create(object entity);

    object Update(object entity);

    void Delete(string[] id);

    long GetTotalRecordCount();
}

If you want a more strongly typed experience though, you may prefer to inherit the base class AbstractUIOMaticRepository

public abstract class AbstractUIOMaticRepository<TEntity, TId> : IUIOMaticRepository
{
    public abstract IEnumerable<TEntity> GetAll(string sortColumn = "", string sortOrder = "");

    public abstract UIOMaticPagedResult<TEntity> GetPaged(int pageNumber, int itemsPerPage,
        string searchTerm = "",
        IDictionary<string, string> filters = null,
        string sortColumn = "", string sortOrder = "");

    public abstract TEntity Get(TId id);

    public abstract TEntity Create(TEntity entity);

    public abstract TEntity Update(TEntity entity);

    public abstract void Delete(TId[] ids);

    long GetTotalRecordCount();
}

For example

public class PersonRepository : AbstractUIOMaticRepository<Person, int>
{
    public override IEnumerable<Person> GetAll(string sortColumn = "", string sortOrder = "")
    {
    	....
    }

    public override UIOMaticPagedResult<Person> GetPaged(int pageNumber, int itemsPerPage,
        string searchTerm = "",
        IDictionary<string, string> filters = null,
        string sortColumn = "", string sortOrder = "")
    {
    	....
    }

    public override Person Get(int id)
    {
    	....
    }

    public override Person Create(Person entity)
    {
    	....
    }

    public override Person Update(Person entity)
    {
    	....
    }

    public override void Delete(int[] ids)
    {
    	....
    }

    long GetTotalRecordCount()
    {
    	....
    }
}

Once you have a repository setup however, all you have to do is tell UI-O-Matic to use it by setting the RepositoryType parameter on the UIOMatic attribute of your type.

[UIOMatic("person", "People", "Person", RepositoryType = typeof(PersonRepository))]
public class Person
{ 
    ....
}

A complete example can be found in this gist https://gist.github.com/TimGeyssens/cff7e3ea5a31849cc71407ba1b6b4886 (it allows UI-0-Matic to CRUD issues on Github)

IUIOMaticObjectService

By default UIOMatic is using PetaPoco as it's ObjectService but you could swap that with a custom one by implementing the IUIOMaticObjectService interface and then switching the default provider type in the App_Plugins\UIOMatic\UIOMatic.config file

So you could replace PetaPoco for another ORM like Entity Framework

Custom Sections

UI-O-Matic exposes a single section by default. If you want to have multiple sections, or if you want to change the section name, you can do so with a few classes.

Composer

First you will need a composer that removes the current section, and adds any new sections you want to add. In this composer, there are two new UI-O-Matic sections added, namely Incidents and Instruction.

[ComposeAfter(typeof(UIOMatic.Sections.SectionComposer))]
public class SectionComposer : IUserComposer
{
	public void Compose(Composition composition)
	{
		composition.Sections().Append<IncidentsSection>();
		composition.Sections().Append<InstructionSection>();
		composition.Sections().Remove<UIOMatic.Sections.UIOMaticSection>();
	}

	private class IncidentsSection : ISection
	{
		public string Alias => IncidentsTreeController.IncidentsAlias;
		public string Name => IncidentsTreeController.IncidentsName;
	}

	private class InstructionSection : ISection
	{
		public string Alias => InstructionTreeController.InstructionAlias;
		public string Name => InstructionTreeController.InstructionName;
	}
}

Mapping Tree Controller

The UI-O-Matic tree controller is a good starting point that offers integration with any custom service or repositories. While you could write an entirely new tree controller, it often will be simpler to extend the UIOMaticTreeController. In doing this, you'll need to update the route paths to map to your new section names. Below is a generic, abstract mapping controller that can be implemented to easily provide this mapping for you.

public abstract class UIOMaticSubSectionTreeController : UIOMaticTreeController
{
	private const string UIOMaticRoutePath = Constants.SectionAlias + "/" + Constants.TreeAlias + "/";

	public abstract string SubSectionAlias { get; }
	public abstract string SubSectionName { get; }
	protected string BaseRoutePath => $"{SubSectionAlias}/{Constants.TreeAlias}/";

	protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) => UpdateRoutePath(base.GetTreeNodes(GetNodeId(id, queryStrings), queryStrings));

	protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings) => base.GetMenuForNode(GetNodeId(id, queryStrings), queryStrings);

	protected override TreeNode CreateRootNode(FormDataCollection queryStrings) => UpdateRoutePath(base.CreateRootNode(queryStrings));

	protected virtual string GetNodeId(string id, FormDataCollection queryStrings) =>
		!string.IsNullOrWhiteSpace(queryStrings.Get("startNodeId"))
		? queryStrings.Get("startNodeId")
		: (string.IsNullOrEmpty(id) || id == global::Umbraco.Core.Constants.System.RootString ? SubSectionAlias : id);

	protected virtual TreeNodeCollection UpdateRoutePath(TreeNodeCollection nodes)
	{
		if (nodes == null || nodes.Count == 0) return nodes;

		foreach (var node in nodes) UpdateRoutePath(node);

		return nodes;
	}

	protected virtual TreeNode UpdateRoutePath(TreeNode node)
	{
		if (node?.RoutePath != null && node.RoutePath.StartsWith(UIOMaticRoutePath)) node.RoutePath = BaseRoutePath + (node.RoutePath.Length > UIOMaticRoutePath.Length ? node.RoutePath.Substring(UIOMaticRoutePath.Length) : "");
		else if (node?.RoutePath == Constants.SectionAlias) node.RoutePath = SubSectionAlias;
		if (node?.Name == "UI-O-Matic") node.Name = SubSectionName;
		return node;
	}
}

Custom Tree Controllers

With the mapping controller in place, you can now easily create custom tree controllers. Below are two tree controller which will map to the custom sections used above.

[UmbracoApplicationAuthorize(IncidentsAlias)]
[UmbracoTreeAuthorize("content")]
[Tree(IncidentsAlias, "uiomatic", TreeTitle = IncidentsName, SortOrder = 1)]
[PluginController("UIOMatic")]
public class IncidentsTreeController : UIOMaticSubSectionTreeController
{
	public const string IncidentsAlias = "incidents";
	public const string IncidentsName = "Incidents";

	public override string SubSectionAlias => IncidentsAlias;
	public override string SubSectionName => IncidentsName;
}

[UmbracoApplicationAuthorize(InstructionAlias)]
[UmbracoTreeAuthorize("content")]
[Tree(InstructionAlias, "uiomatic", TreeTitle = InstructionName, SortOrder = 1)]
[PluginController("UIOMatic")]
public class InstructionTreeController : UIOMaticSubSectionTreeController
{
	public const string InstructionAlias = "instruction";
	public const string InstructionName = "Instruction";

	public override string SubSectionAlias => InstructionAlias;
	public override string SubSectionName => InstructionName;
}

Language File

Once the composer is in place and you have new trees added, you will need to set the displayed title for your new sections and trees, so that they don't display with brackets in the back-office. To do this, create a new folder under App_Plugins in your web project, and create a lang folder in it, i.e. App_Plugins/UIOMatic.Custom/lang. In this lang folder, create a language file for the languages you support, i.e. en-US.xml. Here are example contents for an en-US.xml file that could be used with the above sections and trees.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<language alias="en_us" intName="English (US)" localName="English (US)" lcid="" culture="en-US">
<area alias="sections">
	<key alias="incidents">Incidents</key>
	<key alias="instruction">Instruction</key>
</area>
<area alias="treeHeaders">
	<key alias="incidents">Incidents</key>
	<key alias="instruction">Instruction</key>
</area>
</language>

Last updated

Was this helpful?