从头开始编写一个Orchard网上商店模块(5) - 创建和渲染ProductCatalog的内容类型

原文地址: http://skywalkersoftwaredevelopment.net/blog/writing-an-orchard-webshop-module-from-scratch-part-5
创建和渲染ProductCatalog的内容类型

这是从头开始编写一个新的Orchard模块的教程的第5篇。
对于本教程的概述,请参阅介绍

为了网站的访问者能够将产品添加到他们的购物车,我们需要一个产品目录。
产品目录可以是一个简单的产品清单。然而,在本教程中,我们希望主题作者能够接管渲染(rendering)工作,例好对商品按照某种类别分类进行分类。为了做到这一点,我们需要能够‘换肤(sknnable)‘的东西,清单本身是不容易换肤的(它是可以换肤,但所有的清单将有着相同的外观,这不是我们想要的。我不得不承认我不知道这个案件是否可行,但我曾在定制清单渲染时遇到过一些问题,我不得不给它改成别的样子)。

所以,我们将介绍ProductCatalog内容类型,从中我们可以创建一个ProductCatalog内容项,反过来,如果我们决定,我们要自定义渲染,我们可以创建一个模板。
我们的产品目录的要求如下:

  • 每个目录显示一类产品(如书籍,DVD光盘,CD)。没有技术上的限制,以防止其他产品类型显示,这只是我们的演示需要。
  • 目录的呈现应该可以被其他主题重写,所以我们将它创建作为一个内容类型(而不是让用户自已创建一个新的列表)。

让我们开始定义ProductCatalog到Migration类,添加以下代码定义:

public int UpdateFrom2()        {            ContentDefinitionManager.AlterTypeDefinition("ProductCatalog", type => type                .WithPart(typeof(ContainerPart).Name)                .WithPart(typeof(MenuPart).Name)                .WithPart(typeof(AdminMenuPart).Name)                .WithPart(typeof(RoutePart).Name)                .Creatable()                );

            return 3;        }

这段代码使用ContentDefinitionManager了一个新的Content Type名为的“ProductCatalog”,它包含3个部件(Part),并可以从管理界面上创建。最后,它返回一个新的Ochard Migration的版本号,以保持我们的模块的当前版本的跟踪。

关于部件(Parts):

以便ProductCatalog可以包含其他内容项,ContainerPart是必要。
MenuPart是可选的,但它使我们的网站管理员可以添加产品目录到主菜单上。
AdminMenuPart也是可选,但它可以让我们的网站管理员添加产品目录到管理界面的主菜单上,这是很方便的。
RoutePart事实上是为了能够从前端访问,并同时给ProductCatalog提供了Slug(缩略词)和title属性。

提示一句,正如你可以看到,我使用了typeof(ContainerPart).Name表达式。这是因为我们的模块添加了对项目Orchard.Core的引用,才可以这样。
对于其他类型的内容,你可能要附加的一些在第三方模块中已经定义了的Content Part。然而,当你添加其他模块的引用,你应该提醒你的模块的用户,他们必须先安装依赖的模块。如果他们先安装了你的模块,而没有安装依赖模块,Orchard将抛出一个异常,要恢复该网站的唯一方法是删除你的模块。
这意味着,如果你只是要简单的附加其他模块的某些部件,只用的名称就可以(如“AdvancedMenuPart”,而不是typeof(AdvancedMenuPart).Name)。

当你刷新管理页面,Orchard将通知您,您需要升级您的模块。当我们继续并更新模块,我们将看到,果园创建了一个新的内容类型(Content Type):

 我们也看到,在管理界面的“New”节点,多了一个新的菜单项:

在我们继续之前,我只是想提一提,我们不是一定要使用Migration来创建一个新的内容类型,我们可以在管理界面上作到同样的事。
但是,在代码中这样做可以省掉指导我们的模块的用户如何配置一个新的产品目录(product catalog)。作为模块的开发者,我们应该努力使我们的模块尽可能的易用。

我们将继续创建(并发布)一个新的图书目录,它将能够通过指“Books”作为名称来包含Book的内容类型,“Book”作为Content Type, “Books”作为菜单项的名称。我们也将在管理页面显示菜单作为快捷方式。

下一步,我们将新增的3本书到我们之前创建的图书目录:


现在让我们来看看页面:

我们现在有一个基本的产品目录模块,我们的网站管理员可以对它进行管理。
当你点击“More”链接,你会看到该产品的详细资料:

这是Orchard美妙的地方之一:你不必只是盯着有一组属性的集合的网页:一个页面也是一个可以附加某些部件的内容类型,你可以自由添加更多的部件。
在我们的演示,我们能够构建一个全新的类型和可重用的功能,如标签和评论部件。
等一下:我们没有附加ProductPart到我们的图书内容类型吗?我们作了,不是吗?但它们却没有出现在目录中,也没有产品的详细信息。我们还漏掉什么呢?

我们没有看到这些字段的原因,是因为我们没有实现ProductPart驱动程序的显示方法。驱动程序的部件内容(主要)是负责创建形状,它代表部件内容的视图。

现在,我们要在页面上显示我们ProductPart,让我们回到我们的ProductDriver并添加以下代码:

protected override DriverResult Display(ProductPart part, string displayType, dynamic shapeHelper) {            return ContentShape("Parts_Product", () => shapeHelper.Parts_Product(                    Price: part.Price,                    Sku: part.Sku                ));        }

前端页面要显示的内容项目具有附加的ProductPart时,Orchard将调用Display方法,Display方法将调用ContentShape方法并返回ContentShapeResult,这类似于ASP.NET MVC中的PartialView()方法。
ContentShapeResult将包含形状的名称,以及本身形状,这仅仅是一个动态的Clay对象。我们使用shapeHelper对象创建一个形状,并调用一个动态定义的方法。我们通过提交一组参数给这个方法,它将被转化成属性并存储在我们的形状中。产生的形状将成为Razor模板文件的模型,他的名字将根据形状的命名规则进行匹配。关于形状请参见这篇出色的介绍文档!

我们正在创建一个形状名为“Parts_Product”。按照Orchard的规范,这意味着要有一个文件名为“Parts.Product.cshtml”的模版文件存在(下划线取代了.)。
如果我们命名我们的形状“Jacky_Chan_Goes_Mad”,我们的Razor文件应为“Jacky.Chan.Goes.Mad.cshtml”。很显然,我们应该使用有意义的名称,准确地描述我们的形状的特点。以 “Part”作为前缀是一个很好的规范,就像我们的ProductPart。

所以,不要忘记在Views文件夹下创建一个名为“Parts.Product.cshtml”的文件:

否则你会很痛苦的:

在Orchard渲染我们的ProductPart形状之前,我们还需要使用Placement.info配置它的位置(placement):

<Placement>  <Place Parts_Product_Edit="Content:1" />  <Place Parts_Product="Content:0" /></Placement>

如果您忘记了创建形状的位置,它不会被渲染。

在粗线指示名为“Parts_Product”的形状被添加到区域命名为“Content”在位置0上。位置是用来作为排序指标,以确定的顺序来呈现一个区域内的形状。
有关位置(Placement)的更多的信息,我鼓励您阅读更多关于它的文档

现在刷新前端页面(不要忘记保存您的更改):

详细页面现在看起来像这样:

这就是创建一个功能性的产品目录所要作的工作。对于这个例子,我们创建了一个单一的产品类型和目录,它很容易让网站管理员定义新的产品类型和产品目录!

在接下来的部分,我们将创建一个购物车的功能,使我们的网站的访问者实际地添加产品并进行结算。

时间: 2024-10-03 21:53:18

从头开始编写一个Orchard网上商店模块(5) - 创建和渲染ProductCatalog的内容类型的相关文章

从头开始编写一个Orchard网上商店模块(6) - 创建购物车服务和控制器

原文地址: http://skywalkersoftwaredevelopment.net/blog/writing-an-orchard-webshop-module-from-scratch-part-6创建购物车服务和控制器 这是从头开始编写一个新的Orchard模块的教程的第6篇.对于本教程的概述,请参阅介绍. 在本篇,我们将使我们的用户可以添加商品到他们的购物车.要创建这样的功能,我们需要: 一个“添加到购物车”按钮,要被添加我们的产品目录上,将产品添加到购物车 某种购物车服务,以存储

从头开始编写一个Orchard网上商店模块(3) - 创建Orchard.Webshop模块项目

原文地址:http://skywalkersoftwaredevelopment.net/blog/writing-an-orchard-webshop-module-from-scratch-part-3创建Orchard.Webshop模块项目 这是从头开始编写一个新的Orchard模块的教程的第3篇.对于本教程的概述,请参阅介绍. Orchard模块是一个真正的ASP.NET MVC的Area类库,同时遵循了ASP.NET MVC和Orchard的特定的规范.Orchard 规范提升了您的

手把手教你编写一个简单的PHP模块形态的后门

看到Freebuf 小编发表的用这个隐藏于PHP模块中的rootkit,就能持久接管服务器文章,很感兴趣,苦无作者没留下PoC,自己研究一番,有了此文 0×00. 引言 PHP是一个非常流行的web server端的script语言.目前很多web应用程序都基于php语言实现.由于php是个开源软件并易于扩展,所以我们可以通过编写一个PHP模块(module 或者叫扩展 extension)来实现一个Backdoor. 本文就简单介下如何一步步编写一个简单的php 动态扩展后门. 0×01. p

从头开始编写一个实时嵌入式操作系统的内核(二)

一.RTOS里面的重要数据结构----链表 很多RTOS包括Linux的内核在内,内核里面都大量使用了链表这一种数据结构.内核的链表一般都是双向循环链表,这是因为双向循环链表的效率是最高的,找头节点.尾节点,直接前驱.直接后继时间复杂度都是O(1),这是使用单链表.单向循环链表或其他形式的链表是不能完成的.我们平时上课所学的链表一般都是指针域和数据域,但是如果有研究过Linux内核里面链表的人应该知道和我之前见到的链表结构不一样,只有前驱和后继指针,而没有数据域.Linux内核链表在linux源

从头开始编写一个实时嵌入式操作系统的内核(一)

今年大四,在准备自己的毕业设计.因为毕设题目是一个比较复杂的多传感器监控的嵌入式系统,然后最近自己有使用一些rtos,比方说freertos和ucos,感觉比起单纯对单片机的裸机开发还是有很多好玩的地方.特别喜欢这种抢占式和时间片轮询这两种内核调度模式,所以最近在开始想自己尝试去写一个实时的操作系统的内核调度,看看用自己浅薄的技术,自己去实现会怎么弄,纯粹为了好玩哈哈哈.花了大概几天左右的时间,现在已完成了一个时间片轮询和优先级抢占的实时任务调度内核了,可能有些地方还有些bug,后面有空再慢慢修

4-1:编写一个简单的留言簿,写入留言提交后显示留言内容。

login.jsp <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+re

MFC+WinPcap编写一个嗅探器之六(分析模块)

这一节是程序的核心,也是最复杂的地方 首先需要明白的一点是,一般对于一个有界面的程序来说,往往需要多线程.本程序中除了界面线程外,抓包需要另外创建一个新的线程.在写抓包函数之前,首先要将前面两个模块的结果返回到主对话框界面对应的类实现中,在SnifferDlg.cpp中,修改之前增加的两个模块的触发函数如下: 1 void CSnifferDlg::OnAdp() 2 { 3 // TODO: 在此添加命令处理程序代码 4 CAdpDlg adpdlg; 5 if(adpdlg.DoModal(

MFC+WinPcap编写一个嗅探器之五(过滤模块)

这一节主要介绍如何获设置捕获过滤,这里的过滤是指在捕获前过滤 设置捕获过滤主要是在CFilterDlg中完成,也就是对应之前创建的设置过滤规则对话框,如图: 首先要根据用户的选择来生成一个合法的过滤规则字符串,根据WinPcap的要求,合法的过滤规则可以是如下几种: 1) 表达式支持逻辑操作符,可以使用关键字 and.or.not对子表达式进行组合,同时支持使用小括号.2) 基于协议的过滤要使用协议限定符,协议限定符可以为ip.arp.rarp.tcp.udp等.3) 基于MAC地址的过滤要使用

MFC+WinPcap编写一个嗅探器之四(获取模块)

这一节主要介绍如何获取设备列表,比较简单 获取设备列表主要是在CAdpDlg中完成,也就是对应之前创建的选择适配器模块,如图: 当打开选择适配器对话框后,在列表视图控件中显示当前主机所有适配器及适配器的描述,当选中一个适配器时,在下方的编辑框中会显示当前选中的适配器,单击绑定会提示网卡绑定成功. 本节中代码都在AdpDlg.cpp中完成,当然变量的声明要在其对应的头文件中去做,这里就不再叙述. 首先要获取设备列表,在OnInitDialog函数中加入如下代码: 1 if (pcap_findal