五、扩展Orchard(四) Creating a module
Generating Code for the Module
打开命令行工具,输入下面命令:
codegen module SimpleCommerce
然后到新建的目录中编辑module.txt文件:
Name: SimpleCommerce AntiForgery: enabled Author: The Orchard Team Website: http://orchardproject.net Version: 0.5.0 OrchardVersion: 0.5.0 Description: A simple commerce module Features: SimpleCommerce: Name: Simple Commerce Description: A simple product part. Category: Commerce
Creating the Model for the Part
下面将创建一个数据模型,用于显示存储在数据库中的内容。
在Models目录中创建Product.cs文件:
using System.ComponentModel.DataAnnotations; using Orchard.ContentManagement; using Orchard.ContentManagement.Records; namespace SimpleCommerce.Models { public class ProductPartRecord : ContentPartRecord { public virtual string Sku { get; set; } public virtual float Price { get; set; } } public class ProductPart : ContentPart<ProductPartRecord> { [Required] public string Sku { get { return Record.Sku; } set { Record.Sku = value; } } [Required] public float Price { get { return Record.Price; } set { Record.Price = value; } } } }
这段代码有两个属性,Sku和Price,这是虚拟的,以便启用动态代理的创建将透明地处理持久化。
代码同样定义了一个content part从ContentPart<ProductPartRecord>并暴露了记录的Sku和Price,这两个属性有特性用于验证测试在UI中浮出。
需要将这个文件加入到模块的项目文件中,打开SimpleCommerce.csproj,查找"assemblyinfo.cs",添加下面信息
<Compile Include="Models\Product.cs" />
保存文件。在浏览器打开网站,确保启用了动态编译功能,启用SimpleCommerce功能。
reating the Initial Data Migration File
数据迁移是一个模式,使应该程序或组件在不丢失数据前提下完美的升级到新版本。主要思想是保持对当前版本安装的跟踪和每个数据迁移的变化,从一个版本到下一个版本。如果系统检测到有一个新版本安装当前的数据是之前版本的,将提示网站管理员进行升级。系统之前版本的数据和代码同步了,然后运行所有必要的迁移方法。
开始创建新的模块的初始迁移,仅仅创建需要的数据表,在命令行窗口输入下面命令:
codegen datamigration SimpleCommerce
这将创建下面的Migrations.cs文件:
using System; using System.Collections.Generic; using System.Data; using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement.MetaData; using Orchard.ContentManagement.MetaData.Builders; using Orchard.Core.Contents.Extensions; using Orchard.Data.Migration; namespace SimpleCommerce.DataMigrations { public class Migrations : DataMigrationImpl { public int Create() { // Creating table ProductPartRecord SchemaBuilder.CreateTable("ProductPartRecord", table => table .ContentPartRecord() .Column("Sku", DbType.String) .Column("Price", DbType.Single) ); return 1; } } }
Create方法为初始数据迁移约定,它调用SchemaBuilder.CreateTable方法创建一个ProductPartRecord数据表的Sku和Price列,除了基本的ContentPartRecord表。
注意这个方法返回1,迁移的版本号。
为了说明如何能修改架构和类型的元数据加入另一个迁移步骤,你将以此为契机,添加一个功能,这将使部分被附加到任何内容类型。数据迁移类添加以下方法
public int UpdateFrom1() { ContentDefinitionManager.AlterPartDefinition("ProductPart", builder => builder.Attachable()); return 2; }
这个新的迁移被命名为UpdateFrom1,这是该公约从版本1升级。
下个迁移应该叫UpdateFrom2、UpdateFrom3,依此类推。
确保.csproj文件中有下面一行:
<Compile Include="Migrations.cs" />
导航到Features面板,将看到警告升级,点击 update ,迁移将运行,模块也升级了。
Adding a Handler
Orchard中的handler与ASP.NET MVC的filter相似,它是特定事件发生时运行的一段代码,但不具体到一个给定的内容类型。例如:你可以创建一个统计模块,为了记录使用统计监听Loaded事件。
创建Handlers文件夹,添加ProductHandler.cs文件:
using Orchard.ContentManagement.Handlers; using SimpleCommerce.Models; using Orchard.Data; namespace SimpleCommerce.Handlers { public class ProductHandler : ContentHandler { public ProductHandler(IRepository<ProductPartRecord> repository) { Filters.Add(StorageFilter.For(repository)); } } }
在.csproj文件中加入动态编译
<Compile Include="Handlers\ProductHandler.cs" />
Adding a Driver
Orchard中的driver与ASP.NET MVC中的控制器相似,但在web CMS中很好的适应必要的组成方面。它是为专为指定content part,并可指定知名的行为像在前端显示一条或在管理界面中编辑它。
一个driver通常重写display和editor行为,对于product part,创建一个新Drivers文件夹, 创建ProductDriver.cs文件:
using SimpleCommerce.Models; using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement; namespace SimpleCommerce.Drivers { public class ProductDriver : ContentPartDriver<ProductPart> { protected override DriverResult Display( ProductPart part, string displayType, dynamic shapeHelper) { return ContentShape("Parts_Product", () => shapeHelper.Parts_Product( Sku: part.Sku, Price: part.Price)); } //GET protected override DriverResult Editor(ProductPart part, dynamic shapeHelper) { return ContentShape("Parts_Product_Edit", () => shapeHelper.EditorTemplate( TemplateName: "Parts/Product", Model: part, Prefix: Prefix)); } //POST protected override DriverResult Editor( ProductPart part, IUpdateModel updater, dynamic shapeHelper) { updater.TryUpdateModel(part, Prefix, null, null); return Editor(part, shapeHelper); } } }
在Display代码中创建一个shape当在前端渲染时使用。
这个shape有Sku和Price属性从part复制。
更新.csproj文件:
<Compile Include="Drivers\ProductDriver.cs" />
Editor方法也创建一个shape叫EditorTemplate,这个shape有TemplateName属性指示Orchard到哪里寻找这个渲染模板。访代码还指定该模板模型的一部分,而不是shape(这是默认的)。在较大的前端或仪表盘中的这个parts的placement必须指定使用placement.info文件,位于模块的根目录。这个文件,像一个视图,从一个主题重写,用下面内容创建placement.info文件:
<Placement> <Place Parts_Product_Edit="Content:3"/> <Place Parts_Product="Content:3"/> </Placement>
修改.csproj文件:
<Content Include="placement.info" />
Building the Templates
为了新content part能工作要做的最后事情是写两个模板(前端和后端),在driver中配置。
首先,创建前端模板,在Views文件夹下创建Parts文件夹并添加Product.cshtml文件:
<br/> @T("Price"): <b>$@Model.Price</b><br /> @Model.Sku<br/>
这是shape的一个非常清晰的渲染,注意这里使用了localization的T方法。
然后,在Views文件夹下创建EditorTemplates文件夹,并在Parts文件夹添加Product.cshtml文件:
@model SimpleCommerce.Models.ProductPart <fieldset> <label class="sub" for="Sku">@T("Sku")</label><br /> @Html.TextBoxFor(m => m.Sku, new { @class = "text" })<br /> <label class="sub" for="Price">@T("Price")</label><br /> @Html.TextBoxFor(m => m.Price, new { @class = "text" }) </fieldset>
将上面两个模板加入.csproj文件:
<Content Include="Views\Parts\Product.cshtml" /> <Content Include="Views\EditorTemplates\Parts\Product.cshtml" />
Putting it All Together into a Content Type
将建立一个新Product 内容类型,包含Product part和一些Orchard中的part,到目前为止,你一直关注特定的领域,下面将改变,你将开始整合到Orchard中。
为一个新迁移建立内容类型,打开Migrations.cs文件,添加下面的类:
public int UpdateFrom2() { ContentDefinitionManager.AlterTypeDefinition("Product", cfg => cfg .WithPart("CommonPart") .WithPart("RoutePart") .WithPart("BodyPart") .WithPart("ProductPart") .WithPart("CommentsPart") .WithPart("TagsPart") .WithPart("LocalizationPart") .Creatable() .Indexed()); return 3; }
你正在做的是创建(或更新)一个Product内容类型,添加自己的URL和Title(RoutePart),有一个描述(BodyPart),对产品可以评论(CommentsPart),能标记(TagsPart),本地化(LocalizationPart),
它也可以被创建,这将添加一个创建产品菜单项,它也将进入搜索索引(Indexed)。
启用新模块,
添加一个新Product 内容类型,点击Content,