1. 程式人生 > >Orchard編寫網上商店模組1

Orchard編寫網上商店模組1

1.介紹
雖然Orchard是一個了不起CMS(內容管理系統),有著強大的功能和令人振奮的架構,可以無限的擴充套件,但它可能需要花費一定時間,以充分了解它的架構,並能夠定製您自己的主題的各個方面或甚至創造整個模組來整合Orchard所有的可擴充套件性點。 你會看到Orchard及其架構之美。它不僅只是在簡單或高階的網站和部落格方面表現很出色,同時它也是一個非常基礎的平臺,用於建立各種基於Web的應用,如電子商務後端, CRM的投票系統,專案管理,社群網站,學習管理系統等等。基本上你打算從頭建立的任何應用都應考慮使用Orchard建立。Orchard實際上是一個可擴充套件的框架,它不僅僅“只是”一個CMS。你可以通過外掛方式做任何常規ASP.NET MVC應用可以做的事,同時Orchard還擁有一套豐富的功能和相容概念,你可以獲得額外的好處。
網上商店功能
我們的網上商店模組將啟用以下功能:
管理員將能夠將任意ContentType(內容型別)通過附加到ProductPart上,從而把它變成產品。
網站訪客(顧客)將能夠把產品新增到購物籃,通過網站註冊,併成為註冊使用者。
使用者將能夠進行結算和通過線上支付服務提供商(PSP)支付(在我們的演示,我們將使用Ogone模擬PSP)選定的產品。
在客戶被重定向到PSP之前,系統將建立一個Order(訂單)記錄,及其OrderDetail (訂單明細)記錄。
在客戶支付訂單後,我們需要處理的產品交付。在實物產品的情況下,我們可能要通知一些航運夥伴。在虛擬產品的情況下,我們可能要產生類似於票據,或其他近似的產品。為了這種靈活性,我們將實現某種介面IShippingProvider,我們將建立兩個簡單的實現:一個是傳送電子郵件通知託運人,另一個會產生票據。
管理後臺,使管理員能夠管理客戶以及訂單。

2.配置開發環境
當建立Orchard模組時,建議您下載完整的原始碼,讓我們從Orchard專案的首頁:http://orchardproject.net/下載
我下載的是1.8.1的版本
下載後,vs開啟,執行,配置資料庫。
啟動成功後,會出現開始頁面。
如果出現錯誤,請百度解決。

3.建立Orchard.Webshop模組專案
可以使用命令列工具來建立模組,也可以手工。
開啟Orchard命令列工具(在你的站點下面的bin或者debug中有一個orchard.exe檔案),輸入命令(建立HelloWorld Module) codegen module HelloWorld
修改Manifest檔案,主要是開啟該Module,告訴呼叫者一些基本資訊。

這裡我進行手工建立:
在Modules資料夾下新建一個類庫專案
建立模組的manifest檔案:Module.txt
Name: Orchard.WebShop
AntiForgery: enabled
Author: Sipke Schoorstra
Website: http://skywalkersoftwaredevelopment.net
Version: 1.0
OrchardVersion: 1.3.10
Description: Orchard Webshop Module Demo
Category: Webshop
啟動網站,控制面板,然後啟用新的Module

4.定義一個Content Part,ProductPart
建立一個ProductPart,從而可以儲存資料到資料庫中,我們需要建立ProductRecord,並繼承自Orchard.ContentManagement.Records.ContentPartRecord。
Orchard使用字尾“Record”作為規範,使用NHibernate ORM持久化。
1. 新增對Orchard.Framework專案的引用,以便能夠從Orchard.ContentManagement.Records.ContentPartRecord上繼承。
2. 新增新資料夾命名為”Models”
3. 在”Models”資料夾中,建立一個新的類命名為ProductRecord。
4. 在”Models”資料夾中,建立一個新的類命名為ProductPart,並從ContentPart 繼承。
5. ProductPart將有以下屬性:Price(價格)和SKU。

namespace Orchard.Webshop.Models
{
public class ProductRecord : ContentPartRecord
{
public virtual decimal Price { get; set; }
public virtual string Sku { get; set; }
}
}

namespace Orchard.Webshop.Models
{
public class ProductPart : ContentPart
{
public decimal Price
{
get { return Record.Price; }
set { Record.Price = value; }
}
public string Sku
{
get { return Record.Sku; }
set { Record.Sku = value; }
}
}
}

在Orchard可以對映,載入和儲存ProductRecord物件的例項到資料庫之前,我們需要告訴它資料庫表結構是什麼樣子。
我們通過建立一個叫Migration的類,一個繼承自
Orchard.Data.Migration.DataMigrationImpl,並呼叫一些方法來定義資料庫結構(schema)的類。
在Migration裡,我們告訴Orchard哪些表要建立和哪些ContenteTypes 和 ContentParts要建立。

在你的模組的跟目錄下,建立一個名為Migrations.cs的新類,並敲入如下程式碼:
namespace Orchard.Webshop
{
public class Migrations : DataMigrationImpl
{

    public int Create()
    {
        SchemaBuilder.CreateTable("ProductRecord", table => table
            .ContentPartRecord()
            .Column<decimal>("Price")
            .Column<string>("Sku", column => column.WithLength(50))
            );

        return 1;
    }
}

}

“Create”是Orchard使用一個規範,在啟用模組時,它將為呼叫。
ContentPartRecord方法是一種簡便的方法,用於建立一個ID列,並設定為主鍵:
///
/// Defines a primary column as for content parts
///
public CreateTableCommand ContentPartRecord()
{
Column(“Id”, column => column.PrimaryKey().NotNull());
return this;
}
在我們的例子中,我們已經啟用了模組。但果Orchard很聰明,它檢測到現有一個DataMigration可用, 然後它會檢查當前儲存的Migration版本號,我們的模組啟用時,沒有Migration可執行,所以在Orchard_Framework_DataMigrationRecord表也找不相應的版本號
當您重新整理Orchard Admin頁面,Orchard將顯示一個通知,顯示需要升級一些功能
點選Orchard.Webshop連結,您將直接調轉到模組頁面,並顯示Orchard.Webshop功能
當您單擊“Upgrade”,Orchard將呼叫我們的Migrations類的Create方法,從而建立名為Orchard_Webshop_ProductRecord表
正如你可以看到,Orchard也在Migrations表插入一個新的記錄,其中包含了我們的Migration類的類名和它返回的最後一個版本號。
Create方法返回值1。
現在我們建立了一個表,可以儲存的產品資訊,但是這還不夠,我們需要告訴Orchard ProductPart是“可以被附加的(attachable)”:這是組合ContentTypes的關鍵,從而使用例子的“書”可以變成商品。
要做到這一點,我們要在Migration類中新增一個名為UpdateFrom1的方法,使ProductPart成為attachable

為了能夠使用AlterPartDefinition方法和Attachable方法,我們需要匯入的名稱空間和引用Orchard.Core專案。
小提示:ReSharper的會告訴你哪些程式集要引用和名稱空間要引用,在大量的專案中,這還是真挺有幫助的。
完整的migration,現在看起來像這樣:
using Orchard.Data.Migration;
using Orchard.Data.Migration.Schema;
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Contents.Extensions;
using Orchard.Webshop.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Orchard.Webshop
{
public class Migrations : DataMigrationImpl
{

    public int Create()
    {
        SchemaBuilder.CreateTable("ProductRecord", table => table
            .ContentPartRecord()
            .Column<decimal>("Price")
            .Column<string>("Sku", column => column.WithLength(50))
            );

        return 1;
    }
    public int UpdateFrom1()
    {
        ContentDefinitionManager.AlterPartDefinition(typeof(ProductPart).Name, part => part
            .Attachable()
            );

        return 2;
    }
}

}
當你修改了你的模組,就像我們只是剛剛作的,你只需要儲存檔案:當你重新整理頁面,Orchard將重新編譯模組。
當你重新整理管理頁面,Orchard將再次顯示一個通知說,一些功能需要進行升級
我們將繼續並更新功能。這樣做將導致migration記錄的版本號被更新為2,並且使ProductPart成為了attachable:它將在Settings_ContentPartDefinitionRecord表建立一條新的記錄,並設定為true
為了驗證,我們有一個ProductPart可用,我們導航到Content -> Content Parts,很神奇,我們幹了這麼多工作

很好!現在,讓我們繼續前進,建立一個新的ContentType,就叫“書”,並給它附上ProductPart:
建立一個新的內容型別:
1. 轉到Content -> Content Type,並點選”Create new Type”按鈕;
2. 輸入“Book”作為顯示名稱和內容型別ID(這個會為你自動完成),然後按“Create”按鈕;
3. 這個叫”Book”的內容型別已經建立好了。現在,我們要真正定義這個書的型別,(說到底,任何內容型別都是一組ContentParts的集合), 所以我們的挑選的以下部分,作為書的型別,使它更一個書的商品:Body, Comments, Containable, Product, Route和Tags, 然後點選“儲存”。

現在我們有一個書的Content Type,這也是一種商品型別。我們還附加了Containable Part,這樣我們可以把Book新增列表或其他包含Container Part的Content Tyeps中。
由於我們還附上了Route,我們還有了書的標題和URL。Comments讓網站的訪問者對本書發表評論和Tags Part,允許管理員給書新增標籤。

然而,當我們試圖建立一個實際的書,我們看到各種輸入欄位,但是還沒有Price和SKU欄位
這是怎麼回事?Orchard的工作方式是這樣的,為了呈現任何內容,Orchard呼叫每個ContentPart為Driver。一個Driver很類似與一個MVC Controller,但它只負責處理Part的內容,而不是整個HTTP請求本身。

Driver通常有3個操作方法:一個用於網站的前端顯示部分,一個用於該網站的後端顯示編輯模式,還有一個處理當管理員儲存內容項時的回發(Postback)。

Driver通常返回的ActionResult是一個ShapeResult。ShapeResult告訴Orchard使用Razor模板呈現這個Part,還包含了動態物件將作為的Razor模板的模型。這種模型被稱為Shape(形狀),是一個動態”粘土”物件。

因此,一個模板可以被看作是“面板”的形狀,使用Rqazor檢視(.cshtml)作為實現。形狀本身則是Razor檢視模型。
在編輯模板的情況下,該模板將包含特定部分內容的編輯欄位。

這種Shapes和Drivers的概念可能是Orchard的最強大的功能之一,也是最具挑戰性的概念,真正挑戰你的大腦。
但實際上,當一旦你看到它是如何工作的,它還是很簡單的,讓我們繼續。
讓我們為我們的ProductPart建立Driver程式:
1. 建一個新的資料夾,起名叫Drivers
2. 在該資料夾內,建立一個新類名為ProductDriver

namespace Orchard.Webshop.Drivers
{
public class ProductDriver : ContentPartDriver
{
protected override DriverResult Editor(ProductPart part, dynamic shapeHelper)
{
return ContentShape(“Parts_Product_Edit”, () => shapeHelper.EditorTemplate(TemplateName: “Parts/Product”, Model: part, Prefix: Prefix));
}

    protected override DriverResult Editor(ProductPart part, IUpdateModel updater, dynamic shapeHelper)
    {
        updater.TryUpdateModel(part, Prefix, null, null);
        return Editor(part, shapeHelper);
    }
}

}
Driver程式類,目前有兩種方法:編輯(Edit)和處理回發的過載方法。現在我跳過了顯示(Display)方法,但我們會稍後補上。
當Orchard想要顯示ProductPart的編輯頁面進,它呼叫Driver程式的Edit(編輯)方法。當管理員提交的編輯結果時,過載的Editor(編輯)方法(帶IUpdateModel引數)將被呼叫。

在ContentShape方法被定義在ContentPartDriver的基類中,並從MVC ActionResult類繼承。一個ContentShape例項告訴Orchard Shape的名稱以及這個Shape(形狀)看起來像什麼:這個Shape有一個TempateName屬性,一個Model屬性和一個Prefix屬性。Orchard要用到這些屬性,因此它可以計算出實際使用哪個模板來呈現的形狀,並給你一個機會,為要使用的模板提供Model(模型)。

在我們的例子中,我們的形狀的名稱是“Parts_Product_Edit”,它的模板放在“Parts/Product”下就可以被找得到。因為我們在談論的編輯一個Content Part, Orchard 將在路上加上字首“~//Orchard.Webshop/Views/EditorTemplates”,所以完整的路徑將是:“~/ Orchard.Webshop /Views/EditorTemplates /Parts/Product.cshtml”。

然後我們就在那裡建立Razor模板檔案,它看起來像這樣:
@using Orchard.Utility.Extensions
@model Orchard.Webshop.Models.ProductPart

Product Fields @Html.LabelFor(x => x.Sku) @Html.EditorFor(x => x.Sku) @Html.ValidationMessageFor(x => x.Sku) @Html.LabelFor(x => x.Price) @Html.EditorFor(x => x.Price) @Html.ValidationMessageFor(x => x.Price)

如果有錯誤,就新增web相關的dll引用
在Orchard呼叫Editor方法返回並實際呈現形狀之前,我們需要定義形狀的位置。

Placement是一個可以幫助確定在什麼位置,和在什麼區域(Zone) (其實它也是一個形狀) 呈現一定的形狀的系統。
我們可以通過在我們的模組專案的根目錄下建立一個名為”Placement.info”的文字檔案, 來 定義我們的“Parts_Product_Edit”(記住,我們在ProductDriver的編輯方法定義的形狀的名稱),它看起來像這樣:


這是告訴Orchard把任何名為“Parts_Product_Edit”的形狀放置在第二的位置上被稱為“內容”區域中的(第一的位置從0開始,由RoutablePart佔用。嘗試不同的位置,找一種你認為最好的樣子)。
為了提高Razor模板的IntelliSense(智慧感知),我們現在應該新增一個web.config專案,以及引用System.Web.Mvc元件(在Orchard原始碼在lib資料夾下)。
web.config看起來像這樣: