#20577: Fixing Orchard.Templates

Work Item: 20577
This commit is contained in:
Sebastien Ros
2014-03-26 12:21:36 -07:00
parent 365060b7c6
commit 35d2a6c8fd
33 changed files with 127 additions and 393 deletions

View File

@@ -150,6 +150,9 @@
<Install>true</Install> <Install>true</Install>
</BootstrapperPackage> </BootstrapperPackage>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -121,6 +121,9 @@
<Install>true</Install> <Install>true</Install>
</BootstrapperPackage> </BootstrapperPackage>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -488,6 +488,9 @@
<Install>true</Install> <Install>true</Install>
</BootstrapperPackage> </BootstrapperPackage>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -309,6 +309,9 @@
<EmbeddedResource Include="Recipes\Services\FoldersData\Sample1\Module.txt" /> <EmbeddedResource Include="Recipes\Services\FoldersData\Sample1\Module.txt" />
<EmbeddedResource Include="Recipes\Services\FoldersData\Sample1\Recipes\cms.recipe.xml" /> <EmbeddedResource Include="Recipes\Services\FoldersData\Sample1\Recipes\cms.recipe.xml" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -9,6 +9,8 @@ using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation; using Orchard.DisplayManagement.Implementation;
using Orchard.DisplayManagement.Shapes; using Orchard.DisplayManagement.Shapes;
using Orchard.Environment.Extensions.Models; using Orchard.Environment.Extensions.Models;
using Orchard.Mvc;
using Orchard.Tests.Stubs;
namespace Orchard.Tests.DisplayManagement { namespace Orchard.Tests.DisplayManagement {
[TestFixture] [TestFixture]
@@ -25,6 +27,7 @@ namespace Orchard.Tests.DisplayManagement {
CurrentTheme = new ExtensionDescriptor { Id = "Hello" } CurrentTheme = new ExtensionDescriptor { Id = "Hello" }
}; };
builder.RegisterType<StubHttpContextAccessor>().As<IHttpContextAccessor>();
builder.RegisterType<DefaultDisplayManager>().As<IDisplayManager>(); builder.RegisterType<DefaultDisplayManager>().As<IDisplayManager>();
builder.RegisterType<TestShapeTableManager>().As<IShapeTableManager>(); builder.RegisterType<TestShapeTableManager>().As<IShapeTableManager>();
builder.RegisterType<ShapeTableLocator>().As<IShapeTableLocator>(); builder.RegisterType<ShapeTableLocator>().As<IShapeTableLocator>();

View File

@@ -1,166 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Autofac;
using Moq;
using NUnit.Framework;
using Orchard.Caching;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy;
using Orchard.Environment.Descriptor.Models;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.VirtualPath;
using Orchard.Tests.Stubs;
namespace Orchard.Tests.DisplayManagement.Descriptors {
[TestFixture]
public class ShapeTemplateBindingStrategyTests : ContainerTestBase {
private ShellDescriptor _descriptor;
private IList<FeatureDescriptor> _features;
private TestViewEngine _testViewEngine;
private TestVirtualPathProvider _testVirtualPathProvider;
protected override void Register(ContainerBuilder builder) {
_descriptor = new ShellDescriptor();
_testViewEngine = new TestViewEngine();
_testVirtualPathProvider = new TestVirtualPathProvider();
builder.Register(ctx => _descriptor);
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
builder.RegisterType<StubVirtualPathMonitor>().As<IVirtualPathMonitor>();
builder.RegisterType<ShapeTemplateBindingStrategy>().As<IShapeTableProvider>();
builder.RegisterType<BasicShapeTemplateHarvester>().As<IShapeTemplateHarvester>();
builder.RegisterInstance(_testViewEngine).As<IShapeTemplateViewEngine>();
builder.RegisterInstance(_testVirtualPathProvider).As<IVirtualPathProvider>();
var extensionManager = new Mock<IExtensionManager>();
builder.Register(ctx => extensionManager);
builder.Register(ctx => extensionManager.Object);
}
public class TestViewEngine : Dictionary<string, object>, IShapeTemplateViewEngine {
public IEnumerable<string> DetectTemplateFileNames(IEnumerable<string> fileNames) {
return fileNames;
}
}
public class TestVirtualPathProvider : IVirtualPathProvider {
public string Combine(params string[] paths) {
throw new NotImplementedException();
}
public string ToAppRelative(string virtualPath) {
throw new NotImplementedException();
}
public string MapPath(string virtualPath) {
throw new NotImplementedException();
}
public bool FileExists(string virtualPath) {
throw new NotImplementedException();
}
public Stream OpenFile(string virtualPath) {
throw new NotImplementedException();
}
public StreamWriter CreateText(string virtualPath) {
throw new NotImplementedException();
}
public Stream CreateFile(string virtualPath) {
throw new NotImplementedException();
}
public DateTime GetFileLastWriteTimeUtc(string virtualPath) {
throw new NotImplementedException();
}
public string GetFileHash(string virtualPath) {
throw new NotImplementedException();
}
public string GetFileHash(string virtualPath, IEnumerable<string> dependencies) {
throw new NotImplementedException();
}
public void DeleteFile(string virtualPath) {
throw new NotImplementedException();
}
public bool DirectoryExists(string virtualPath) {
return true;
}
public void CreateDirectory(string virtualPath) {
throw new NotImplementedException();
}
public virtual void DeleteDirectory(string virtualPath) {
throw new NotImplementedException();
}
public string GetDirectoryName(string virtualPath) {
throw new NotImplementedException();
}
public IEnumerable<string> ListFiles(string path) {
return new List<string> {"~/Modules/Alpha/Views/AlphaShape.blah"};
}
public IEnumerable<string> ListDirectories(string path) {
throw new NotImplementedException();
}
public bool TryFileExists(string virtualPath) {
throw new NotImplementedException();
}
}
protected override void Resolve(ILifetimeScope container) {
_features = new List<FeatureDescriptor>();
container.Resolve<Mock<IExtensionManager>>()
.Setup(em => em.AvailableFeatures())
.Returns(_features);
}
void AddFeature(string name, params string[] dependencies) {
var featureDescriptor = new FeatureDescriptor {
Id = name,
Dependencies = dependencies,
Extension = new ExtensionDescriptor {
Id = name,
Location = "~/Modules"
}
};
featureDescriptor.Extension.Features = new[] { featureDescriptor };
_features.Add(featureDescriptor);
}
void AddEnabledFeature(string name, params string[] dependencies) {
AddFeature(name, dependencies);
_descriptor.Features = _descriptor.Features.Concat(new[] { new ShellFeature { Name = name } });
}
[Test]
public void TemplateResolutionWorks() {
AddEnabledFeature("Alpha");
_testViewEngine.Add("~/Modules/Alpha/Views/AlphaShape.blah", null);
var strategy = _container.Resolve<IShapeTableProvider>();
var builder = new ShapeTableBuilder(null);
strategy.Discover(builder);
var alterations = builder.BuildAlterations();
Assert.That(alterations.Any(alteration => alteration.ShapeType.Equals("AlphaShape", StringComparison.OrdinalIgnoreCase)));
}
}
}

View File

@@ -232,7 +232,6 @@
<Compile Include="DisplayManagement\Descriptors\InMemoryWebSiteFolder.cs" /> <Compile Include="DisplayManagement\Descriptors\InMemoryWebSiteFolder.cs" />
<Compile Include="DisplayManagement\Descriptors\PlacementFileParserTests.cs" /> <Compile Include="DisplayManagement\Descriptors\PlacementFileParserTests.cs" />
<Compile Include="DisplayManagement\Descriptors\ShapeAttributeBindingStrategyTests.cs" /> <Compile Include="DisplayManagement\Descriptors\ShapeAttributeBindingStrategyTests.cs" />
<Compile Include="DisplayManagement\Descriptors\ShapeTemplateBindingStrategyTests.cs" />
<Compile Include="DisplayManagement\ShapeFactoryTests.cs" /> <Compile Include="DisplayManagement\ShapeFactoryTests.cs" />
<Compile Include="DisplayManagement\SubsystemTests.cs" /> <Compile Include="DisplayManagement\SubsystemTests.cs" />
<Compile Include="DisplayManagement\ShapeHelperTests.cs" /> <Compile Include="DisplayManagement\ShapeHelperTests.cs" />
@@ -370,6 +369,9 @@
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Environment\Extensions\FoldersData\Sample7\Module.txt" /> <EmbeddedResource Include="Environment\Extensions\FoldersData\Sample7\Module.txt" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -115,6 +115,9 @@
<Install>true</Install> <Install>true</Install>
</BootstrapperPackage> </BootstrapperPackage>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -92,6 +92,9 @@
<Name>Orchard.Projections</Name> <Name>Orchard.Projections</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Xml.Linq; using System.Xml.Linq;
using Orchard.Compilation.Razor;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
@@ -16,15 +15,12 @@ using Orchard.Utility.Extensions;
namespace Orchard.Templates.Drivers { namespace Orchard.Templates.Drivers {
public class ShapePartDriver : ContentPartDriver<ShapePart> { public class ShapePartDriver : ContentPartDriver<ShapePart> {
private readonly IEnumerable<ITemplateProcessor> _processors; private readonly IEnumerable<ITemplateProcessor> _processors;
private readonly IRazorTemplateHolder _templateHolder;
private readonly ITransactionManager _transactions; private readonly ITransactionManager _transactions;
public ShapePartDriver( public ShapePartDriver(
IEnumerable<ITemplateProcessor> processors, IEnumerable<ITemplateProcessor> processors,
IRazorTemplateHolder templateHolder,
ITransactionManager transactions) { ITransactionManager transactions) {
_processors = processors; _processors = processors;
_templateHolder = templateHolder;
_transactions = transactions; _transactions = transactions;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
} }
@@ -48,7 +44,6 @@ namespace Orchard.Templates.Drivers {
try { try {
var processor = _processors.FirstOrDefault(x => String.Equals(x.Type, part.ProcessorName, StringComparison.OrdinalIgnoreCase)) ?? _processors.First(); var processor = _processors.FirstOrDefault(x => String.Equals(x.Type, part.ProcessorName, StringComparison.OrdinalIgnoreCase)) ?? _processors.First();
processor.Verify(part.Template); processor.Verify(part.Template);
_templateHolder.Set(part.Name, part.Template);
} }
catch (Exception ex) { catch (Exception ex) {
updater.AddModelError("", T("Template processing error: {0}", ex.Message)); updater.AddModelError("", T("Template processing error: {0}", ex.Message));

View File

@@ -1,19 +1,22 @@
using Orchard.Caching; using Orchard.Caching;
using Orchard.Compilation.Razor;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
using Orchard.Templates.Models; using Orchard.Templates.Models;
using Orchard.Templates.Services; using Orchard.Templates.Services;
namespace Orchard.Templates.Handlers { namespace Orchard.Templates.Handlers {
public class ShapePartHandler : ContentHandler { public class ShapePartHandler : ContentHandler {
private readonly IRazorTemplateHolder _razorTemplateHolder; private ISignals _signals;
public ShapePartHandler(ISignals signals, IRazorTemplateHolder razorTemplateHolder) { public ShapePartHandler(ISignals signals) {
_razorTemplateHolder = razorTemplateHolder; _signals = signals;
OnUpdated<ShapePart>((ctx, part) => _razorTemplateHolder.Set(part.Name, part.Template)); OnPublished<ShapePart>((ctx, part) => InvalidateTemplatesCache());
OnCreated<ShapePart>((ctx, part) => signals.Trigger(DefaultTemplateService.TemplatesSignal)); OnUnpublished<ShapePart>((ctx, part) => InvalidateTemplatesCache());
OnRemoved<ShapePart>((ctx, part) => signals.Trigger(DefaultTemplateService.TemplatesSignal)); OnRemoved<ShapePart>((ctx, part) => InvalidateTemplatesCache());
}
public void InvalidateTemplatesCache() {
_signals.Trigger(DefaultTemplateService.TemplatesSignal);
} }
} }
} }

View File

@@ -169,10 +169,13 @@
<Compile Include="Migrations.cs" /> <Compile Include="Migrations.cs" />
<Compile Include="Services\ITemplateProcessor.cs" /> <Compile Include="Services\ITemplateProcessor.cs" />
<Compile Include="Services\ITemplateService.cs" /> <Compile Include="Services\ITemplateService.cs" />
<Compile Include="Services\Razor\IRazorCompiler.cs" />
<Compile Include="Services\Razor\RazorCompiler.cs" />
<Compile Include="Services\Razor\RazorTemplateBase.cs" />
<Compile Include="Services\TemplateProcessorImpl.cs" /> <Compile Include="Services\TemplateProcessorImpl.cs" />
<Compile Include="Services\RazorTemplateProcessor.cs" /> <Compile Include="Services\RazorTemplateProcessor.cs" />
<Compile Include="Services\TemplateBindingStrategy.cs" />
<Compile Include="Services\DefaultTemplateService.cs" /> <Compile Include="Services\DefaultTemplateService.cs" />
<Compile Include="Services\TemplateShapeDisplayEvent.cs" />
<Compile Include="Settings\ShapePartSettings.cs" /> <Compile Include="Settings\ShapePartSettings.cs" />
<Compile Include="Settings\ShapePartSettingsEvents.cs" /> <Compile Include="Settings\ShapePartSettingsEvents.cs" />
<Compile Include="ViewModels\ShapePartSettingsViewModel.cs" /> <Compile Include="ViewModels\ShapePartSettingsViewModel.cs" />

View File

@@ -10,13 +10,9 @@ namespace Orchard.Templates.Services {
public const string TemplatesSignal = "Orchard.Templates"; public const string TemplatesSignal = "Orchard.Templates";
private readonly IContentManager _contentManager;
private readonly IEnumerable<ITemplateProcessor> _processors; private readonly IEnumerable<ITemplateProcessor> _processors;
public DefaultTemplateService( public DefaultTemplateService(IEnumerable<ITemplateProcessor> processors) {
IContentManager contentManager,
IEnumerable<ITemplateProcessor> processors) {
_contentManager = contentManager;
_processors = processors; _processors = processors;
} }
@@ -28,10 +24,6 @@ namespace Orchard.Templates.Services {
var processor = _processors.FirstOrDefault(x => String.Equals(x.Type, processorName, StringComparison.OrdinalIgnoreCase)) ?? _processors.First(); var processor = _processors.FirstOrDefault(x => String.Equals(x.Type, processorName, StringComparison.OrdinalIgnoreCase)) ?? _processors.First();
return processor.Process(template, name, context, model); return processor.Process(template, name, context, model);
} }
public IEnumerable<ShapePart> GetTemplates(VersionOptions versionOptions = null) {
return _contentManager.Query<ShapePart>(versionOptions ?? VersionOptions.Published).List();
}
} }
} }

View File

@@ -7,6 +7,5 @@ namespace Orchard.Templates.Services {
public interface ITemplateService : IDependency { public interface ITemplateService : IDependency {
string Execute<TModel>(string template, string name, string processorName, TModel model = default(TModel)); string Execute<TModel>(string template, string name, string processorName, TModel model = default(TModel));
string Execute<TModel>(string template, string name, string processorName, DisplayContext context, TModel model = default(TModel)); string Execute<TModel>(string template, string name, string processorName, DisplayContext context, TModel model = default(TModel));
IEnumerable<ShapePart> GetTemplates(VersionOptions versionOptions = null);
} }
} }

View File

@@ -1,8 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Orchard.Compilation.Razor { namespace Orchard.Templates.Compilation.Razor {
public interface IRazorCompiler : ICompiler { public interface IRazorCompiler : IDependency {
IRazorTemplateBase<TModel> CompileRazor<TModel>(string code, string name, IDictionary<string, object> parameters); IRazorTemplateBase<TModel> CompileRazor<TModel>(string code, string name, IDictionary<string, object> parameters);
IRazorTemplateBase CompileRazor(string code, string name, IDictionary<string, object> parameters); IRazorTemplateBase CompileRazor(string code, string name, IDictionary<string, object> parameters);
} }

View File

@@ -13,7 +13,7 @@ using Orchard.Caching;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Utility.Extensions; using Orchard.Utility.Extensions;
namespace Orchard.Compilation.Razor { namespace Orchard.Templates.Compilation.Razor {
public class RazorCompiler : IRazorCompiler { public class RazorCompiler : IRazorCompiler {
private readonly ICacheManager _cache; private readonly ICacheManager _cache;
private readonly ISignals _signals; private readonly ISignals _signals;
@@ -34,7 +34,7 @@ namespace Orchard.Compilation.Razor {
"System.Web.Mvc.Ajax", "System.Web.Mvc.Ajax",
"System.Web.UI", "System.Web.UI",
"System.Web.Routing", "System.Web.Routing",
"Orchard.Compilation.Razor", "Orchard.Templates.Compilation.Razor",
"Orchard.ContentManagement", "Orchard.ContentManagement",
"Orchard.DisplayManagement", "Orchard.DisplayManagement",
"Orchard.DisplayManagement.Shapes", "Orchard.DisplayManagement.Shapes",
@@ -63,14 +63,6 @@ namespace Orchard.Compilation.Razor {
return (IRazorTemplateBase) Compile(code, name, null, parameters); return (IRazorTemplateBase) Compile(code, name, null, parameters);
} }
public object Compile(string code, IDictionary<string, object> parameters) {
return CompileRazor<RazorTemplateBase<dynamic>>(code, null, parameters);
}
public T Compile<T>(string code, IDictionary<string, object> parameters) {
return (T) Compile(code, null, null, parameters);
}
private object Compile(string code, string name, Type modelType, IDictionary<string, object> parameters) { private object Compile(string code, string name, Type modelType, IDictionary<string, object> parameters) {
var cacheKey = (name ?? DynamicallyGeneratedClassName) + GetHash(code); var cacheKey = (name ?? DynamicallyGeneratedClassName) + GetHash(code);

View File

@@ -2,7 +2,7 @@
using System.Web.Mvc; using System.Web.Mvc;
using System.Web.WebPages; using System.Web.WebPages;
namespace Orchard.Compilation.Razor { namespace Orchard.Templates.Compilation.Razor {
public interface IRazorTemplateBase public interface IRazorTemplateBase
{ {
dynamic Model { get; } dynamic Model { get; }

View File

@@ -6,9 +6,10 @@ using System.Web;
using System.Web.Mvc; using System.Web.Mvc;
using System.Web.UI; using System.Web.UI;
using System.Web.WebPages; using System.Web.WebPages;
using Orchard.Compilation.Razor;
using Orchard.DisplayManagement.Implementation; using Orchard.DisplayManagement.Implementation;
using Orchard.Logging;namespace Orchard.Templates.Services { using Orchard.Logging;
using Orchard.Templates.Compilation.Razor;
namespace Orchard.Templates.Services {
public class RazorTemplateProcessor : TemplateProcessorImpl { public class RazorTemplateProcessor : TemplateProcessorImpl {
private readonly IRazorCompiler _compiler; private readonly IRazorCompiler _compiler;
private readonly HttpContextBase _httpContextBase; private readonly HttpContextBase _httpContextBase;

View File

@@ -1,116 +0,0 @@
using System;
using System.Linq;
using System.Web;
using Orchard.Caching;
using Orchard.Compilation.Razor;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation;
using Orchard.Environment.Extensions.Models;
using Orchard.Mvc.Spooling;
namespace Orchard.Templates.Services {
public class TemplateBindingStrategy : IShapeTableProvider, IShapeTableMonitor {
private readonly ITemplateService _templateService;
private readonly IRazorTemplateHolder _templateProvider;
private readonly ISignals _signals;
public TemplateBindingStrategy(
ITemplateService templateService,
IRazorTemplateHolder templateProvider,
ISignals signals) {
_templateService = templateService;
_templateProvider = templateProvider;
_signals = signals;
}
public virtual Feature Feature { get; set; }
public void Discover(ShapeTableBuilder builder) {
BuildShapes(builder);
}
private void BuildShapes(ShapeTableBuilder builder) {
var shapes = _templateService.GetTemplates().Select(r =>
new {
r.Name,
r.ProcessorName,
r.Template
})
.ToList();
// Use a fake theme descriptor which will ensure the shape is used over
// any other extension. It's also necessary to define them in the Admin
// theme in order to process tokens
var fakeThemeDescriptor = new FeatureDescriptor {
Id = "", // so that the binding is not filtered out
Priority = 10, // so that it's higher than the themes' priority
Extension = new ExtensionDescriptor {
ExtensionType = DefaultExtensionTypes.Theme, // so that the binding is overriding modules
}
};
foreach (var record in shapes) {
_templateProvider.Set(record.Name, record.Template);
var shapeType = AdjustName(record.Name);
builder.Describe(shapeType)
.From(new Feature { Descriptor = fakeThemeDescriptor })
.BoundAs("Template::" + shapeType,
descriptor => context => {
var template = _templateProvider.Get(record.Name);
return template != null ? PerformInvoke(context, record.Name, record.ProcessorName, template) : new HtmlString("");
});
}
}
private IHtmlString PerformInvoke(DisplayContext displayContext, string name, string type, string template)
{
if (String.IsNullOrEmpty(template)) {
return null;
}
var output = new HtmlStringWriter();
output.Write(CoerceHtmlString(_templateService.Execute(template, name, type, displayContext, displayContext.Value)));
return output;
}
private string AdjustName(string name) {
var lastDash = name.LastIndexOf('-');
var lastDot = name.LastIndexOf('.');
if (lastDot <= 0 || lastDot < lastDash) {
name = Adjust(name, null);
return name;
}
var displayType = name.Substring(lastDot + 1);
name = Adjust(name.Substring(0, lastDot), displayType);
return name;
}
private static string Adjust(string name, string displayType) {
// Canonical shape type names must not have - or . to be compatible with display and shape api calls.
var shapeType = name.Replace("--", "__").Replace("-", "__").Replace('.', '_');
if (String.IsNullOrEmpty(displayType)) {
return shapeType;
}
var firstBreakingSeparator = shapeType.IndexOf("__", StringComparison.OrdinalIgnoreCase);
if (firstBreakingSeparator <= 0) {
return (shapeType + "_" + displayType);
}
return (shapeType.Substring(0, firstBreakingSeparator) + "_" + displayType + shapeType.Substring(firstBreakingSeparator));
}
private static IHtmlString CoerceHtmlString(object invoke) {
return invoke as IHtmlString ?? (invoke != null ? new HtmlString(invoke.ToString()) : null);
}
public void Monitor(Action<IVolatileToken> monitor) {
monitor(_signals.When(DefaultTemplateService.TemplatesSignal));
}
}
}

View File

@@ -0,0 +1,59 @@
using Orchard.Caching;
using Orchard.ContentManagement;
using Orchard.DisplayManagement.Implementation;
using Orchard.Templates.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Orchard.Templates.Services {
public class TemplateShapeDisplayEvent : IShapeDisplayEvents {
private ICacheManager _cacheManager;
private ISignals _signals;
private IContentManager _contentManager;
private ITemplateService _templateService;
public TemplateShapeDisplayEvent (
ICacheManager cacheManager,
ISignals signals,
IContentManager contentManager,
ITemplateService templateService
) {
_cacheManager = cacheManager;
_signals = signals;
_contentManager = contentManager;
_templateService = templateService;
}
public void Displaying(ShapeDisplayingContext context) {
var processors = BuildShapeProcessors();
Func<dynamic, IHtmlString> processor;
if (processors.TryGetValue(context.ShapeMetadata.Type, out processor)) {
context.ChildContent = processor(context.Shape);
}
}
public void Displayed(ShapeDisplayedContext context) {
}
public IDictionary<string, Func<dynamic, IHtmlString>> BuildShapeProcessors() {
return _cacheManager.Get("Template.ShapeProcessors", ctx => {
ctx.Monitor(_signals.When(DefaultTemplateService.TemplatesSignal));
var allTemplates = _contentManager.Query<ShapePart>().List();
return allTemplates.Select(x => new KeyValuePair<string, Func<dynamic, IHtmlString>>(
x.Name,
d => CoerceHtmlString(_templateService.Execute(x.Template, x.Name, x.ProcessorName, d))
)).ToDictionary(x => x.Key, x => x.Value);
});
}
private static IHtmlString CoerceHtmlString(object invoke) {
return invoke as IHtmlString ?? (invoke != null ? new HtmlString(invoke.ToString()) : null);
}
}
}

View File

@@ -75,6 +75,9 @@
<Name>Orchard.Templates</Name> <Name>Orchard.Templates</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -1,6 +1,10 @@
using Autofac; using System.Web;
using Autofac;
using NUnit.Framework; using NUnit.Framework;
using Orchard.Caching;
using Orchard.Templates.Compilation.Razor;
using Orchard.Templates.Services; using Orchard.Templates.Services;
using Orchard.Tests.Stubs;
namespace Orchard.Templates.Tests { namespace Orchard.Templates.Tests {
[TestFixture] [TestFixture]
@@ -11,6 +15,11 @@ namespace Orchard.Templates.Tests {
public void Init() { public void Init() {
var builder = new ContainerBuilder(); var builder = new ContainerBuilder();
builder.RegisterType<RazorTemplateProcessor>().As<ITemplateProcessor>(); builder.RegisterType<RazorTemplateProcessor>().As<ITemplateProcessor>();
builder.RegisterType<RazorCompiler>().As<IRazorCompiler>();
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
builder.RegisterType<Signals>().As<ISignals>();
builder.RegisterType<StubHttpContext>().As<HttpContextBase>();
_container = builder.Build(); _container = builder.Build();
} }

View File

@@ -75,6 +75,9 @@
<Name>Orchard.Tokens</Name> <Name>Orchard.Tokens</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -1,8 +0,0 @@
using Autofac;
namespace Orchard.Compilation {
public class CompilersModule : Module {
protected override void Load(ContainerBuilder builder) {
}
}
}

View File

@@ -1,8 +0,0 @@
using System.Collections.Generic;
namespace Orchard.Compilation {
public interface ICompiler : IDependency {
object Compile(string code, IDictionary<string, object> parameters);
T Compile<T>(string code, IDictionary<string, object> parameters);
}
}

View File

@@ -1,6 +0,0 @@
namespace Orchard.Compilation.Razor {
public interface IRazorTemplateHolder : ISingletonDependency {
string Get(string name);
void Set(string name, string template);
}
}

View File

@@ -1,10 +0,0 @@
using Autofac;
using Orchard.ContentManagement;
namespace Orchard.Compilation.Razor {
public class RazorModule : Module {
protected override void Load(ContainerBuilder builder) {
}
}
}

View File

@@ -1,19 +0,0 @@
using System.Collections.Concurrent;
namespace Orchard.Compilation.Razor {
public class RazorTemplateHolder : IRazorTemplateHolder {
private readonly ConcurrentDictionary<string, string> _cache;
public RazorTemplateHolder() {
_cache = new ConcurrentDictionary<string, string>();
}
public string Get(string name) {
string template;
return _cache.TryGetValue(name, out template) ? template : null;
}
public void Set(string name, string template) {
_cache.AddOrUpdate(name, template, (s, s1) => template);
}
}
}

View File

@@ -17,21 +17,18 @@ namespace Orchard.DisplayManagement.Descriptors {
private readonly ICacheManager _cacheManager; private readonly ICacheManager _cacheManager;
private readonly IParallelCacheContext _parallelCacheContext; private readonly IParallelCacheContext _parallelCacheContext;
private readonly IEnumerable<IShapeTableEventHandler> _shapeTableEventHandlers; private readonly IEnumerable<IShapeTableEventHandler> _shapeTableEventHandlers;
private readonly IEnumerable<IShapeTableMonitor> _shapeTableMonitors;
public DefaultShapeTableManager( public DefaultShapeTableManager(
IEnumerable<Meta<IShapeTableProvider>> bindingStrategies, IEnumerable<Meta<IShapeTableProvider>> bindingStrategies,
IExtensionManager extensionManager, IExtensionManager extensionManager,
ICacheManager cacheManager, ICacheManager cacheManager,
IParallelCacheContext parallelCacheContext, IParallelCacheContext parallelCacheContext,
IEnumerable<IShapeTableEventHandler> shapeTableEventHandlers, IEnumerable<IShapeTableEventHandler> shapeTableEventHandlers
IEnumerable<IShapeTableMonitor> shapeTableMonitors
) { ) {
_extensionManager = extensionManager; _extensionManager = extensionManager;
_cacheManager = cacheManager; _cacheManager = cacheManager;
_parallelCacheContext = parallelCacheContext; _parallelCacheContext = parallelCacheContext;
_shapeTableEventHandlers = shapeTableEventHandlers; _shapeTableEventHandlers = shapeTableEventHandlers;
_shapeTableMonitors = shapeTableMonitors;
_bindingStrategies = bindingStrategies; _bindingStrategies = bindingStrategies;
Logger = NullLogger.Instance; Logger = NullLogger.Instance;
} }
@@ -81,8 +78,6 @@ namespace Orchard.DisplayManagement.Descriptors {
_shapeTableEventHandlers.Invoke(ctx => ctx.ShapeTableCreated(result), Logger); _shapeTableEventHandlers.Invoke(ctx => ctx.ShapeTableCreated(result), Logger);
_shapeTableMonitors.Invoke(ctx => ctx.Monitor(x.Monitor), Logger);
Logger.Information("Done building shape table"); Logger.Information("Done building shape table");
return result; return result;
}); });

View File

@@ -16,8 +16,4 @@ namespace Orchard.DisplayManagement.Descriptors {
void ShapeTableCreated(ShapeTable shapeTable); void ShapeTableCreated(ShapeTable shapeTable);
} }
public interface IShapeTableMonitor : IDependency {
void Monitor(Action<IVolatileToken> monitor);
}
} }

View File

@@ -9,7 +9,6 @@ using System.Web.Mvc;
using Autofac; using Autofac;
using Autofac.Configuration; using Autofac.Configuration;
using Orchard.Caching; using Orchard.Caching;
using Orchard.Compilation.Razor;
using Orchard.Data; using Orchard.Data;
using Orchard.Environment.AutofacUtil; using Orchard.Environment.AutofacUtil;
using Orchard.Environment.Configuration; using Orchard.Environment.Configuration;

View File

@@ -146,14 +146,6 @@
<Compile Include="Caching\DefaultParallelCacheContext.cs" /> <Compile Include="Caching\DefaultParallelCacheContext.cs" />
<Compile Include="Caching\ICacheContextAccessor.cs" /> <Compile Include="Caching\ICacheContextAccessor.cs" />
<Compile Include="Caching\IParallelCacheContext.cs" /> <Compile Include="Caching\IParallelCacheContext.cs" />
<Compile Include="Compilation\CompilersModule.cs" />
<Compile Include="Compilation\ICompiler.cs" />
<Compile Include="Compilation\Razor\RazorModule.cs" />
<Compile Include="Compilation\Razor\IRazorCompiler.cs" />
<Compile Include="Compilation\Razor\IRazorTemplateHolder.cs" />
<Compile Include="Compilation\Razor\RazorCompiler.cs" />
<Compile Include="Compilation\Razor\RazorTemplateBase.cs" />
<Compile Include="Compilation\Razor\RazorTemplateCache.cs" />
<Compile Include="ContentManagement\Aspects\IAliasAspect.cs" /> <Compile Include="ContentManagement\Aspects\IAliasAspect.cs" />
<Compile Include="ContentManagement\Aspects\ITitleAspect.cs" /> <Compile Include="ContentManagement\Aspects\ITitleAspect.cs" />
<Compile Include="ContentManagement\Aspects\ILocalizableAspect.cs" /> <Compile Include="ContentManagement\Aspects\ILocalizableAspect.cs" />

View File

@@ -104,6 +104,9 @@
<Name>Orchard</Name> <Name>Orchard</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.