WIP - still working on getting the template repository and models working correctly and adding some more tests.

This commit is contained in:
Shannon
2014-12-01 14:14:44 +11:00
parent 520955a8db
commit bf82a70744
7 changed files with 211 additions and 132 deletions

View File

@@ -15,7 +15,7 @@ namespace Umbraco.Core.IO
public PhysicalFileSystem(string virtualRoot)
{
if (virtualRoot == null) throw new ArgumentNullException("virtualRoot");
if (!virtualRoot.StartsWith("~/"))
if (virtualRoot.StartsWith("~/") == false)
throw new ArgumentException("The virtualRoot argument must be a virtual path and start with '~/'");
RootPath = IOHelper.MapPath(virtualRoot);
@@ -65,7 +65,7 @@ namespace Umbraco.Core.IO
public void DeleteDirectory(string path, bool recursive)
{
if (!DirectoryExists(path))
if (DirectoryExists(path) == false)
return;
try

View File

@@ -5,6 +5,7 @@ using System.Runtime.Serialization;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Models
@@ -16,6 +17,7 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public class Template : File, ITemplate
{
private readonly IFileSystem _viewFileSystem;
private string _alias;
private string _name;
private string _masterTemplateAlias;
@@ -29,14 +31,24 @@ namespace Umbraco.Core.Models
{
_name = name;
_alias = alias.ToCleanString(CleanStringType.UnderscoreAlias);
_masterTemplateId = new Lazy<int>(() => -1);
_viewFileSystem = new PhysicalFileSystem(SystemDirectories.MvcViews);
}
public Template(string name, string alias, IFileSystem viewFileSystem)
: this(name, alias)
{
if (viewFileSystem == null) throw new ArgumentNullException("viewFileSystem");
_viewFileSystem = viewFileSystem;
}
[Obsolete("This constructor should not be used, file path is determined by alias, setting the path here will have no affect")]
public Template(string path, string name, string alias)
: base(path)
{
base.Path = path;
_name = name;
_alias = alias.ToCleanString(CleanStringType.UnderscoreAlias);
_masterTemplateId = new Lazy<int>(() => -1);
}
[DataMember]
@@ -102,10 +114,7 @@ namespace Umbraco.Core.Models
/// <returns><see cref="RenderingEngine"/></returns>
public RenderingEngine GetTypeOfRenderingEngine()
{
if(Path.EndsWith("cshtml") || Path.EndsWith("vbhtml"))
return RenderingEngine.Mvc;
return RenderingEngine.WebForms;
return DetermineRenderingEngine();
}
/// <summary>
@@ -169,6 +178,52 @@ namespace Umbraco.Core.Models
return clone;
}
/// <summary>
/// This checks what the default rendering engine is set in config but then also ensures that there isn't already
/// a template that exists in the opposite rendering engine's template folder, then returns the appropriate
/// rendering engine to use.
/// </summary>
/// <returns></returns>
/// <remarks>
/// The reason this is required is because for example, if you have a master page file already existing under ~/masterpages/Blah.aspx
/// and then you go to create a template in the tree called Blah and the default rendering engine is MVC, it will create a Blah.cshtml
/// empty template in ~/Views. This means every page that is using Blah will go to MVC and render an empty page.
/// This is mostly related to installing packages since packages install file templates to the file system and then create the
/// templates in business logic. Without this, it could cause the wrong rendering engine to be used for a package.
/// </remarks>
private RenderingEngine DetermineRenderingEngine()
{
var engine = UmbracoConfig.For.UmbracoSettings().Templates.DefaultRenderingEngine;
if (Content.IsNullOrWhiteSpace() == false && MasterPageHelper.IsMasterPageSyntax(Content))
{
//there is a design but its definitely a webforms design
return RenderingEngine.WebForms;
}
var viewHelper = new ViewHelper(_viewFileSystem);
switch (engine)
{
case RenderingEngine.Mvc:
//check if there's a view in ~/masterpages
if (MasterPageHelper.MasterPageExists(this) && viewHelper.ViewExists(this) == false)
{
//change this to webforms since there's already a file there for this template alias
engine = RenderingEngine.WebForms;
}
break;
case RenderingEngine.WebForms:
//check if there's a view in ~/views
if (viewHelper.ViewExists(this) && MasterPageHelper.MasterPageExists(this) == false)
{
//change this to mvc since there's already a file there for this template alias
engine = RenderingEngine.Mvc;
}
break;
}
return engine;
}
}
}

View File

@@ -136,7 +136,6 @@ namespace Umbraco.Core.Persistence.Repositories
protected override IEnumerable<string> GetDeleteClauses()
{
//TODO check for references in DocumentDto and remove value (nullable)
var list = new List<string>
{
"DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id",
@@ -175,7 +174,7 @@ namespace Umbraco.Core.Persistence.Repositories
//TODO: Integrate the ViewHelper, MasterPageHelper stuff for when saving the template content
//Save to db
var template = entity as Template;
var template = (Template)entity;
template.AddingEntity();
var factory = new TemplateFactory(NodeObjectTypeId);
@@ -289,25 +288,17 @@ namespace Umbraco.Core.Persistence.Repositories
//now we can delete this one
base.PersistDeletedItem(entity);
//Check for file under the Masterpages filesystem
if (_masterpagesFileSystem.FileExists(entity.Name))
if (entity.GetTypeOfRenderingEngine() == RenderingEngine.Mvc)
{
_masterpagesFileSystem.DeleteFile(entity.Name);
var viewName = string.Concat(entity.Alias, ".cshtml");
_viewsFileSystem.DeleteFile(viewName);
}
else if (_masterpagesFileSystem.FileExists(entity.Path))
else
{
_masterpagesFileSystem.DeleteFile(entity.Path);
var masterpageName = string.Concat(entity.Alias, ".master");
_masterpagesFileSystem.DeleteFile(masterpageName);
}
//Check for file under the Views/Mvc filesystem
if (_viewsFileSystem.FileExists(entity.Name))
{
_viewsFileSystem.DeleteFile(entity.Name);
}
else if (_viewsFileSystem.FileExists(entity.Path))
{
_viewsFileSystem.DeleteFile(entity.Path);
}
}
#endregion
@@ -514,7 +505,7 @@ namespace Umbraco.Core.Persistence.Repositories
//need to get the top-most node of the current tree
var top = selfDto;
while (top.Master.HasValue)
while (top.Master.HasValue && top.Master.Value != -1)
{
top = allDtos.Single(x => x.NodeId == top.Master.Value);
}

View File

@@ -1,3 +1,4 @@
using System;
using System.IO;
using System.Text;
using Umbraco.Core.IO;
@@ -7,60 +8,94 @@ namespace Umbraco.Core.Services
{
internal class ViewHelper
{
internal static bool ViewExists(ITemplate t)
private readonly IFileSystem _viewFileSystem;
public ViewHelper(IFileSystem viewFileSystem)
{
string path = GetFilePath(t);
return System.IO.File.Exists(path);
if (viewFileSystem == null) throw new ArgumentNullException("viewFileSystem");
_viewFileSystem = viewFileSystem;
}
internal static string GetFilePath(ITemplate t)
internal bool ViewExists(ITemplate t)
{
return IOHelper.MapPath(ViewPath(t.Alias));
return _viewFileSystem.FileExists(ViewPath(t.Alias));
}
internal static string GetFileContents(ITemplate t)
[Obsolete("This is only used for legacy purposes and will be removed in future versions")]
internal string GetPhysicalFilePath(ITemplate t)
{
return _viewFileSystem.GetFullPath(ViewPath(t.Alias));
}
internal string GetFileContents(ITemplate t)
{
string viewContent = "";
string path = IOHelper.MapPath(ViewPath(t.Alias));
string path = ViewPath(t.Alias);
if (System.IO.File.Exists(path))
if (_viewFileSystem.FileExists(path))
{
TextReader tr = new StreamReader(path);
viewContent = tr.ReadToEnd();
tr.Close();
using (var tr = new StreamReader(_viewFileSystem.OpenFile(path)))
{
viewContent = tr.ReadToEnd();
tr.Close();
}
}
return viewContent;
}
internal static string CreateViewFile(ITemplate t, bool overWrite = false)
internal string CreateViewFile(ITemplate t, bool overWrite = false)
{
string viewContent;
string path = IOHelper.MapPath(ViewPath(t.Alias));
string path = ViewPath(t.Alias);
if (System.IO.File.Exists(path) == false || overWrite)
viewContent = SaveTemplateToFile(t, t.Alias);
if (_viewFileSystem.FileExists(path) == false || overWrite)
{
viewContent = SaveTemplateToFile(t, t.Alias);
}
else
{
TextReader tr = new StreamReader(path);
viewContent = tr.ReadToEnd();
tr.Close();
using (var tr = new StreamReader(_viewFileSystem.OpenFile(path)))
{
viewContent = tr.ReadToEnd();
tr.Close();
}
}
return viewContent;
}
internal static string SaveTemplateToFile(ITemplate template, string currentAlias)
internal static string GetDefaultFileContent(string layoutPageAlias = null)
{
var design = @"@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
Layout = null;
}";
if (layoutPageAlias.IsNullOrWhiteSpace() == false)
design = design.Replace("null", string.Format("\"{0}.cshtml\"", layoutPageAlias));
return design;
}
internal string SaveTemplateToFile(ITemplate template, string currentAlias)
{
var design = EnsureInheritedLayout(template);
System.IO.File.WriteAllText(IOHelper.MapPath(ViewPath(template.Alias)), design, Encoding.UTF8);
var path = ViewPath(template.Alias);
using (var ms = new MemoryStream())
using (var writer = new StreamWriter(ms, Encoding.UTF8))
{
writer.Write(design);
_viewFileSystem.AddFile(path, ms, true);
}
return template.Content;
}
internal static string UpdateViewFile(ITemplate t, string currentAlias = null)
internal string UpdateViewFile(ITemplate t, string currentAlias = null)
{
var path = IOHelper.MapPath(ViewPath(t.Alias));
var path = ViewPath(t.Alias);
if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != t.Alias)
{
@@ -75,43 +110,44 @@ namespace Umbraco.Core.Services
//}
//then kill the old file..
var oldFile = IOHelper.MapPath(ViewPath(currentAlias));
if (System.IO.File.Exists(oldFile))
System.IO.File.Delete(oldFile);
var oldFile = ViewPath(currentAlias);
if (_viewFileSystem.FileExists(oldFile))
_viewFileSystem.DeleteFile(oldFile);
}
System.IO.File.WriteAllText(path, t.Content, Encoding.UTF8);
using (var ms = new MemoryStream())
using (var writer = new StreamWriter(ms, Encoding.UTF8))
{
writer.Write(t.Content);
_viewFileSystem.AddFile(path, ms, true);
}
return t.Content;
}
internal static void RemoveViewFile(string alias)
internal void RemoveViewFile(string alias)
{
if (string.IsNullOrWhiteSpace(alias) == false)
{
var file = IOHelper.MapPath(ViewPath(alias));
if (System.IO.File.Exists(file))
System.IO.File.Delete(file);
var file = ViewPath(alias);
if (_viewFileSystem.FileExists(file))
_viewFileSystem.DeleteFile(file);
}
}
public static string ViewPath(string alias)
public string ViewPath(string alias)
{
return SystemDirectories.MvcViews + "/" + alias.Replace(" ", "") + ".cshtml";
return _viewFileSystem.GetRelativePath(alias.Replace(" ", "") + ".cshtml");
//return SystemDirectories.MvcViews + "/" + alias.Replace(" ", "") + ".cshtml";
}
private static string EnsureInheritedLayout(ITemplate template)
private string EnsureInheritedLayout(ITemplate template)
{
string design = template.Content;
if (string.IsNullOrEmpty(design))
{
design = @"@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
Layout = null;
}";
if (template.MasterTemplateAlias.IsNullOrWhiteSpace() == false)
design = design.Replace("null", string.Format("\"{0}.cshtml\"", template.MasterTemplateAlias));
design = GetDefaultFileContent(template.MasterTemplateAlias);
}
return design;

View File

@@ -10,6 +10,7 @@ using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
@@ -74,7 +75,7 @@ namespace Umbraco.Tests.Persistence.Repositories
using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
{
// Act
var template = new Template("test-add-masterpage.master", "test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
var template = new Template("test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
repository.AddOrUpdate(template);
unitOfWork.Commit();
@@ -85,6 +86,46 @@ namespace Umbraco.Tests.Persistence.Repositories
}
[Test]
public void Can_Perform_Add_View()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider();
var unitOfWork = provider.GetUnitOfWork();
using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
{
// Act
var template = new Template("test", "test") { Content = ViewHelper.GetDefaultFileContent() };
repository.AddOrUpdate(template);
unitOfWork.Commit();
//Assert
Assert.That(repository.Get("test"), Is.Not.Null);
Assert.That(_viewsFileSystem.FileExists("test.cshtml"), Is.True);
}
}
//[Test]
//public void Can_Perform_Add_Unique_Alias()
//{
// // Arrange
// var provider = new PetaPocoUnitOfWorkProvider();
// var unitOfWork = provider.GetUnitOfWork();
// using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
// {
// // Act
// var template = new Template("test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
// repository.AddOrUpdate(template);
// unitOfWork.Commit();
// //Assert
// Assert.That(repository.Get("test"), Is.Not.Null);
// Assert.That(_masterPageFileSystem.FileExists("test.master"), Is.True);
// }
//}
[Test]
public void Can_Perform_Update_MasterPage()
{
@@ -94,7 +135,7 @@ namespace Umbraco.Tests.Persistence.Repositories
using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
{
// Act
var template = new Template("test-updated-masterpage.master", "test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
var template = new Template("test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
repository.AddOrUpdate(template);
unitOfWork.Commit();
@@ -120,17 +161,19 @@ namespace Umbraco.Tests.Persistence.Repositories
var unitOfWork = provider.GetUnitOfWork();
using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
{
var template = new Template("test-add-masterpage.master", "test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
var template = new Template("test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
repository.AddOrUpdate(template);
unitOfWork.Commit();
// Act
var templates = repository.Get("test");
Assert.That(_masterPageFileSystem.FileExists("test.master"), Is.True);
repository.Delete(templates);
unitOfWork.Commit();
// Assert
Assert.IsNull(repository.Get("test"));
Assert.That(_masterPageFileSystem.FileExists("test.master"), Is.False);
}
@@ -158,7 +201,7 @@ namespace Umbraco.Tests.Persistence.Repositories
using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
{
var template = new Template("test-add-masterpage.master", "test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
var template = new Template("test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
repository.AddOrUpdate(template);
unitOfWork.Commit();
@@ -186,9 +229,9 @@ namespace Umbraco.Tests.Persistence.Repositories
var unitOfWork = provider.GetUnitOfWork();
using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
{
var parent = new Template("test-parent-masterpage.master", "parent", "parent") { Content = @"<%@ Master Language=""C#"" %>" };
var child = new Template("test-child-masterpage.master", "child", "child") { Content = @"<%@ Master Language=""C#"" %>" };
var baby = new Template("test-baby-masterpage.master", "baby", "baby") { Content = @"<%@ Master Language=""C#"" %>" };
var parent = new Template("parent", "parent") { Content = @"<%@ Master Language=""C#"" %>" };
var child = new Template("child", "child") { Content = @"<%@ Master Language=""C#"" %>" };
var baby = new Template("baby", "baby") { Content = @"<%@ Master Language=""C#"" %>" };
child.MasterTemplateAlias = parent.Alias;
child.MasterTemplateId = new Lazy<int>(() => parent.Id);
baby.MasterTemplateAlias = child.Alias;
@@ -218,17 +261,17 @@ namespace Umbraco.Tests.Persistence.Repositories
var unitOfWork = provider.GetUnitOfWork();
using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
{
var parent = new Template("test-parent-masterpage.master", "parent", "parent") { Content = @"<%@ Master Language=""C#"" %>" };
var parent = new Template("parent", "parent") { Content = @"<%@ Master Language=""C#"" %>" };
var child1 = new Template("test-child1-masterpage.master", "child1", "child1") { Content = @"<%@ Master Language=""C#"" %>" };
var toddler1 = new Template("test-toddler1-masterpage.master", "toddler1", "toddler1") { Content = @"<%@ Master Language=""C#"" %>" };
var toddler2 = new Template("test-toddler2-masterpage.master", "toddler2", "toddler2") { Content = @"<%@ Master Language=""C#"" %>" };
var baby1 = new Template("test-baby1-masterpage.master", "baby1", "baby1") { Content = @"<%@ Master Language=""C#"" %>" };
var child1 = new Template("child1", "child1") { Content = @"<%@ Master Language=""C#"" %>" };
var toddler1 = new Template("toddler1", "toddler1") { Content = @"<%@ Master Language=""C#"" %>" };
var toddler2 = new Template("toddler2", "toddler2") { Content = @"<%@ Master Language=""C#"" %>" };
var baby1 = new Template("baby1", "baby1") { Content = @"<%@ Master Language=""C#"" %>" };
var child2 = new Template("test-child2-masterpage.master", "child2", "child2") { Content = @"<%@ Master Language=""C#"" %>" };
var toddler3 = new Template("test-toddler3-masterpage.master", "toddler3", "toddler3") { Content = @"<%@ Master Language=""C#"" %>" };
var toddler4 = new Template("test-toddler4-masterpage.master", "toddler4", "toddler4") { Content = @"<%@ Master Language=""C#"" %>" };
var baby2 = new Template("test-baby2-masterpage.master", "baby2", "baby2") { Content = @"<%@ Master Language=""C#"" %>" };
var child2 = new Template("child2", "child2") { Content = @"<%@ Master Language=""C#"" %>" };
var toddler3 = new Template("toddler3", "toddler3") { Content = @"<%@ Master Language=""C#"" %>" };
var toddler4 = new Template("toddler4", "toddler4") { Content = @"<%@ Master Language=""C#"" %>" };
var baby2 = new Template("baby2", "baby2") { Content = @"<%@ Master Language=""C#"" %>" };
child1.MasterTemplateAlias = parent.Alias;

View File

@@ -40,6 +40,8 @@ namespace umbraco
{
public loadTemplates(string application) : base(application) {}
private ViewHelper _viewHelper = new ViewHelper(new PhysicalFileSystem(SystemDirectories.MvcViews));
protected override void CreateRootNode(ref XmlTreeNode rootNode)
{
rootNode.NodeType = "init" + TreeAlias;
@@ -199,7 +201,7 @@ namespace umbraco
xNode.Source = GetTreeServiceUrl(t.Id);
xNode.HasChildren = t.HasChildren;
if (UmbracoConfig.For.UmbracoSettings().Templates.DefaultRenderingEngine == RenderingEngine.Mvc && ViewHelper.ViewExists(t.TemplateEntity))
if (UmbracoConfig.For.UmbracoSettings().Templates.DefaultRenderingEngine == RenderingEngine.Mvc && _viewHelper.ViewExists(t.TemplateEntity))
{
xNode.Action = "javascript:openView(" + t.Id + ");";
xNode.Icon = "icon-newspaper-alt";

View File

@@ -29,6 +29,7 @@ namespace umbraco.cms.businesslogic.template
#region Private members
private ViewHelper _viewHelper = new ViewHelper(new PhysicalFileSystem(SystemDirectories.MvcViews));
internal ITemplate TemplateEntity;
//private string _OutputContentType;
//private string _design;
@@ -64,12 +65,10 @@ namespace umbraco.cms.businesslogic.template
{
get
{
return TemplateEntity.Path;
switch (DetermineRenderingEngine(TemplateEntity))
switch (TemplateEntity.GetTypeOfRenderingEngine())
{
case RenderingEngine.Mvc:
return ViewHelper.GetFilePath(TemplateEntity);
return _viewHelper.GetPhysicalFilePath(TemplateEntity);
case RenderingEngine.WebForms:
return MasterPageHelper.GetFilePath(TemplateEntity);
default:
@@ -371,53 +370,6 @@ namespace umbraco.cms.businesslogic.template
return DocumentType.GetAllAsList().Where(x => x.allowedTemplates.Select(t => t.Id).Contains(this.Id));
}
/// <summary>
/// This checks what the default rendering engine is set in config but then also ensures that there isn't already
/// a template that exists in the opposite rendering engine's template folder, then returns the appropriate
/// rendering engine to use.
/// </summary>
/// <param name="t"></param>
/// <param name="design">If a template body is specified we'll check if it contains master page markup, if it does we'll auto assume its webforms </param>
/// <returns></returns>
/// <remarks>
/// The reason this is required is because for example, if you have a master page file already existing under ~/masterpages/Blah.aspx
/// and then you go to create a template in the tree called Blah and the default rendering engine is MVC, it will create a Blah.cshtml
/// empty template in ~/Views. This means every page that is using Blah will go to MVC and render an empty page.
/// This is mostly related to installing packages since packages install file templates to the file system and then create the
/// templates in business logic. Without this, it could cause the wrong rendering engine to be used for a package.
/// </remarks>
private static RenderingEngine DetermineRenderingEngine(ITemplate t, string design = null)
{
var engine = UmbracoConfig.For.UmbracoSettings().Templates.DefaultRenderingEngine;
if (!design.IsNullOrWhiteSpace() && MasterPageHelper.IsMasterPageSyntax(design))
{
//there is a design but its definitely a webforms design
return RenderingEngine.WebForms;
}
switch (engine)
{
case RenderingEngine.Mvc:
//check if there's a view in ~/masterpages
if (MasterPageHelper.MasterPageExists(t) && !ViewHelper.ViewExists(t))
{
//change this to webforms since there's already a file there for this template alias
engine = RenderingEngine.WebForms;
}
break;
case RenderingEngine.WebForms:
//check if there's a view in ~/views
if (ViewHelper.ViewExists(t) && !MasterPageHelper.MasterPageExists(t))
{
//change this to mvc since there's already a file there for this template alias
engine = RenderingEngine.Mvc;
}
break;
}
return engine;
}
public static Template MakeNew(string Name, User u, Template master)
{
return MakeNew(Name, u, master, null);