diff --git a/src/Umbraco.Core/Models/TemplateNode.cs b/src/Umbraco.Core/Models/TemplateNode.cs
new file mode 100644
index 0000000000..1fc51f8498
--- /dev/null
+++ b/src/Umbraco.Core/Models/TemplateNode.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+
+namespace Umbraco.Core.Models
+{
+ ///
+ /// Represents a template in a template tree
+ ///
+ public class TemplateNode
+ {
+ public TemplateNode(ITemplate template)
+ {
+ Template = template;
+ Children = new List();
+ }
+
+ ///
+ /// The current template
+ ///
+ public ITemplate Template { get; set; }
+
+ ///
+ /// The children of the current template
+ ///
+ public IEnumerable Children { get; set; }
+
+ ///
+ /// The parent template to the current template
+ ///
+ ///
+ /// Will be null if there is no parent
+ ///
+ public TemplateNode Parent { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/ITemplateRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/ITemplateRepository.cs
index 90d6f68adc..318b840819 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/ITemplateRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/ITemplateRepository.cs
@@ -7,5 +7,20 @@ namespace Umbraco.Core.Persistence.Repositories
{
ITemplate Get(string alias);
IEnumerable GetAll(params string[] aliases);
+
+ ///
+ /// Returns a template as a template node which can be traversed (parent, children)
+ ///
+ ///
+ ///
+ TemplateNode GetTemplateNode(string alias);
+
+ ///
+ /// Given a template node in a tree, this will find the template node with the given alias if it is found in the hierarchy, otherwise null
+ ///
+ ///
+ ///
+ ///
+ TemplateNode FindTemplateInTree(TemplateNode anyNode, string alias);
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs b/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs
index 5cc827680b..e3b69a786e 100644
--- a/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs
@@ -273,6 +273,32 @@ namespace Umbraco.Core.Persistence.Repositories
protected override void PersistDeletedItem(ITemplate entity)
{
+
+ //TODO: This isn't the most ideal way to delete a template tree, because below it will actually end up
+ // recursing back to this method for each descendant and re-looking up the template list causing an extrac
+ // SQL call - not ideal but there shouldn't ever be a heaping list of descendant templates.
+ //The easiest way to overcome this is to expose the underlying cache upwards so that the repository has access
+ // to it, then in the PersistDeletedTemplate we wouldn't recurse the underlying function, we'd just call
+ // PersistDeletedItem with a Template object and clear it's cache.
+
+ var sql = new Sql();
+ sql.Select("*").From().Where(dto => dto.Master != null || dto.NodeId == entity.Id);
+ var dtos = Database.Fetch(sql);
+ var self = dtos.Single(x => x.NodeId == entity.Id);
+ var allChildren = dtos.Except(new[] { self });
+ var hierarchy = GenerateTemplateHierarchy(self, allChildren);
+ //remove ourselves
+ hierarchy.Remove(self);
+ //change the order so it goes bottom up!
+ hierarchy.Reverse();
+
+ //delete the hierarchy
+ foreach (var descendant in hierarchy)
+ {
+ PersistDeletedTemplate(descendant);
+ }
+
+ //now we can delete this one
base.PersistDeletedItem(entity);
//Check for file under the Masterpages filesystem
@@ -298,6 +324,34 @@ namespace Umbraco.Core.Persistence.Repositories
#endregion
+ private void PersistDeletedTemplate(TemplateDto dto)
+ {
+ //we need to get the real template for this item unfortunately to remove it
+ var template = Get(dto.NodeId);
+ if (template != null)
+ {
+ //NOTE: We must cast here so that it goes to the outter method to
+ // ensure the cache is updated.
+ PersistDeletedItem((IEntity)template);
+ }
+ }
+
+ ///
+ /// Returns a list of templates in order of descendants from the parent
+ ///
+ ///
+ ///
+ ///
+ private static List GenerateTemplateHierarchy(TemplateDto template, IEnumerable allChildTemplates)
+ {
+ var hierarchy = new List { template };
+ foreach (var t in allChildTemplates.Where(x => x.Master == template.NodeId))
+ {
+ hierarchy.AddRange(GenerateTemplateHierarchy(t, allChildTemplates));
+ }
+ return hierarchy;
+ }
+
private void PopulateViewTemplate(ITemplate template, string fileName)
{
string content = string.Empty;
@@ -379,6 +433,103 @@ namespace Umbraco.Core.Persistence.Repositories
}
+ ///
+ /// Returns a template as a template node which can be traversed (parent, children)
+ ///
+ ///
+ ///
+ public TemplateNode GetTemplateNode(string alias)
+ {
+ //in order to do this we need to get all of the templates and then organize, unfortunately
+ // our db structure does not use the path correctly for templates so we cannot just look
+ // up a template tree easily.
+
+ //first get all template objects
+ var allTemplates = GetAll().ToArray();
+
+ var selfTemplate = allTemplates.SingleOrDefault(x => x.Alias == alias);
+ if (selfTemplate == null)
+ {
+ return null;
+ }
+
+ //then we need to get all template Dto's because those contain the master property
+ var sql = new Sql();
+ sql.Select("*").From();
+ var allDtos = Database.Fetch(sql).ToArray();
+ var selfDto = allDtos.Single(x => x.NodeId == selfTemplate.Id);
+
+ //need to get the top-most node of the current tree
+ var top = selfDto;
+ while (top.Master.HasValue)
+ {
+ top = allDtos.Single(x => x.NodeId == top.Master.Value);
+ }
+
+ var topNode = new TemplateNode(allTemplates.Single(x => x.Id == top.NodeId));
+ var childIds = allDtos.Where(x => x.Master == top.NodeId).Select(x => x.NodeId);
+ //This now creates the hierarchy recursively
+ topNode.Children = CreateChildren(topNode, childIds, allTemplates, allDtos);
+
+ //now we'll return the TemplateNode requested
+ return FindTemplateInTree(topNode, alias);
+ }
+
+ private static TemplateNode WalkTree(TemplateNode current, string alias)
+ {
+ //now walk the tree to find the node
+ if (current.Template.Alias == alias)
+ {
+ return current;
+ }
+ foreach (var c in current.Children)
+ {
+ var found = WalkTree(c, alias);
+ if (found != null) return found;
+ }
+ return null;
+ }
+
+ ///
+ /// Given a template node in a tree, this will find the template node with the given alias if it is found in the hierarchy, otherwise null
+ ///
+ ///
+ ///
+ ///
+ public TemplateNode FindTemplateInTree(TemplateNode anyNode, string alias)
+ {
+ //first get the root
+ var top = anyNode;
+ while (top.Parent != null)
+ {
+ top = top.Parent;
+ }
+ return WalkTree(top, alias);
+ }
+
+ private static IEnumerable CreateChildren(TemplateNode parent, IEnumerable childIds, ITemplate[] allTemplates, TemplateDto[] allDtos)
+ {
+ var children = new List();
+ foreach (var i in childIds)
+ {
+ var template = allTemplates.Single(x => x.Id == i);
+ var child = new TemplateNode(template)
+ {
+ Parent = parent
+ };
+
+ //add to our list
+ children.Add(child);
+
+ //get this node's children
+ var kids = allDtos.Where(x => x.Master == i).Select(x => x.NodeId).ToArray();
+
+ //recurse
+ child.Children = CreateChildren(child, kids, allTemplates, allDtos);
+ }
+ return children;
+ }
+
#endregion
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/FileService.cs b/src/Umbraco.Core/Services/FileService.cs
index c912793e05..5d4f2b1da8 100644
--- a/src/Umbraco.Core/Services/FileService.cs
+++ b/src/Umbraco.Core/Services/FileService.cs
@@ -13,24 +13,24 @@ namespace Umbraco.Core.Services
///
public class FileService : IFileService
{
- private readonly RepositoryFactory _repositoryFactory;
+ private readonly RepositoryFactory _repositoryFactory;
private readonly IUnitOfWorkProvider _fileUowProvider;
private readonly IDatabaseUnitOfWorkProvider _dataUowProvider;
public FileService()
: this(new RepositoryFactory())
- {}
+ { }
public FileService(RepositoryFactory repositoryFactory)
- : this(new FileUnitOfWorkProvider(), new PetaPocoUnitOfWorkProvider(), repositoryFactory)
+ : this(new FileUnitOfWorkProvider(), new PetaPocoUnitOfWorkProvider(), repositoryFactory)
{
}
- public FileService(IUnitOfWorkProvider fileProvider, IDatabaseUnitOfWorkProvider dataProvider, RepositoryFactory repositoryFactory)
+ public FileService(IUnitOfWorkProvider fileProvider, IDatabaseUnitOfWorkProvider dataProvider, RepositoryFactory repositoryFactory)
{
- _repositoryFactory = repositoryFactory;
- _fileUowProvider = fileProvider;
- _dataUowProvider = dataProvider;
+ _repositoryFactory = repositoryFactory;
+ _fileUowProvider = fileProvider;
+ _dataUowProvider = dataProvider;
}
///
@@ -65,19 +65,19 @@ namespace Umbraco.Core.Services
///
public void SaveStylesheet(Stylesheet stylesheet, int userId = 0)
{
- if (SavingStylesheet.IsRaisedEventCancelled(new SaveEventArgs(stylesheet), this))
- return;
-
- var uow = _fileUowProvider.GetUnitOfWork();
+ if (SavingStylesheet.IsRaisedEventCancelled(new SaveEventArgs(stylesheet), this))
+ return;
+
+ var uow = _fileUowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateStylesheetRepository(uow, _dataUowProvider.GetUnitOfWork()))
- {
- repository.AddOrUpdate(stylesheet);
- uow.Commit();
+ {
+ repository.AddOrUpdate(stylesheet);
+ uow.Commit();
- SavedStylesheet.RaiseEvent(new SaveEventArgs(stylesheet, false), this);
- }
+ SavedStylesheet.RaiseEvent(new SaveEventArgs(stylesheet, false), this);
+ }
- Audit.Add(AuditTypes.Save, string.Format("Save Stylesheet performed by user"), userId, -1);
+ Audit.Add(AuditTypes.Save, string.Format("Save Stylesheet performed by user"), userId, -1);
}
///
@@ -92,15 +92,15 @@ namespace Umbraco.Core.Services
{
var stylesheet = repository.Get(name);
- if (DeletingStylesheet.IsRaisedEventCancelled(new DeleteEventArgs(stylesheet), this))
- return;
+ if (DeletingStylesheet.IsRaisedEventCancelled(new DeleteEventArgs(stylesheet), this))
+ return;
- repository.Delete(stylesheet);
- uow.Commit();
+ repository.Delete(stylesheet);
+ uow.Commit();
- DeletedStylesheet.RaiseEvent(new DeleteEventArgs(stylesheet, false), this);
+ DeletedStylesheet.RaiseEvent(new DeleteEventArgs(stylesheet, false), this);
- Audit.Add(AuditTypes.Delete, string.Format("Delete Stylesheet performed by user"), userId, -1);
+ Audit.Add(AuditTypes.Delete, string.Format("Delete Stylesheet performed by user"), userId, -1);
}
}
@@ -146,19 +146,19 @@ namespace Umbraco.Core.Services
///
public void SaveScript(Script script, int userId = 0)
{
- if (SavingScript.IsRaisedEventCancelled(new SaveEventArgs