CMS:文章管理之模型和Store
文章管理涉及T_Category 、T_Content 、T_Tag 和T_TagInContent 这4个表,在客户端,由于标签的两个表的显示会合并到文章内容里,因而文章管理至少需要2个模型和2个Store,一个是分类的,一个是Content的。
现在的问题是,文章管理界面左边的分类是以树形式显示的,是否需要用到一个完整的模型?完整的模型肯定是需要的,因为分类也要编辑、修改和新增。但树是否直接使用这个完整模型呢?这是要考虑的。首先,树的模型结构与完整模型肯定有区别,它会自动添加不少字段,而且id和text是必须的,这个在定义模型或Store时虽然可以改变,但不是很方便。其次,每次树节点展开,都要返回完整的模型数据,这对通讯来说有点浪费,因为这时候并不需要完整的模型数据,只有编辑节点的时候才需要。综合以上两点,笔者的观点是,还是拆分成两个模型比较合适,尽管返回完整模型有其优点,就是在编辑模型的时候,不用再去服务器取一次数据。
在编辑文章的时候,要通过Combobox选择文章分类,因而这里还需要一个模型和Store,这里要考虑的是使用下拉树选择框还是普通的下拉选择框。如果使用下拉树选择框,可以直接使用树列表的Store,使用树列表的唯一问题是在编辑文章的时候,如果当前树还没展开,会显示为空,因而在打开编辑窗口之前,一定要先展开树,处理起来有点复杂。第二种方式是下拉选择框,一次返回所有节点,或者使用类似搜索网站的查询方式显示结果。笔者比较倾向返回所有节点,在本地实现查询方式,因而,这里还需要一个模型和Store。
那么,文章是否也要拆分为2个模型和Store呢?这个主要考虑的就是通讯问题了。笔者的习惯做法是不拆,就用一个,理由嘛,习惯吧。
综合以上,需要建的模型包括Category、CategoryTree、CategoryCombo和Content这4个,Store则包括CategoriesTree、CategoriesCombo和Contents这3个。这里,少了一个分类的Store,是因为完整的分类模型只有在编辑、新增的时候用到,而这些都是单个模型实例的操作,不需要使用到Store,因而可以不定义。
目前明确后,就可以动手了。在Scripts\app\model目录下,先创建Category.js来定义完整的分类模型,代码如下:
Ext.define('SimpleCMS.model.Category',{
extend: 'Ext.data.Model',
fields: [
{name: "ParentId", type: "int", defaultValue: "-1"},
{ name: "CategoryId", type:"int" },
"Title",
"Image",
"Summary",
"Content",
{name: "Created", type: "date", dateFormat: "Y-m-dH:i:s", defaultValue: new Date() },
{ name: "SortOrder", type:"int", defaultValue: 0 }
],
proxy: {
type: "ajax",
url: "Category/Details",
reader: {
type: 'json',
root: "data",
messageProperty: "Msg"
}
},
idProperty: "CategoryId"
});
从定义代码可以看到,字段名与表格定义的字段名是一样的,这样的好处是方便。如果害怕信息泄露,可根据需要自己修改。有些字段没有定义是因为,在编辑过程中不需要显示这些字段,就省略了。代理的定义与之前的定义基本雷同,目的是保证使用统一的数据返回格式。
接着创建CategoryTree.js文件来定义分类树模型,代码如下:
Ext.define('SimpleCMS.model.CategoryTree',{
extend: 'Ext.data.Model',
fields: ["text",
{ name: "id", type:"int" },
{ name: "parentId", type:"int" }
]
});
代码里没定义代理,这个将由Store进行定义,因为基本操作是在Store层面。
接着是CategoryCombo.js,代码如下:
Ext.define('SimpleCMS.model.CategoryCombo',{
extend: 'Ext.data.Model',
fields: ["text",
{ name: "id", type:"int" },
{ name: "parentId", type:"int" },
"listText",
"fullpath",
{ name: "Hierarchylevel",type: "int" }
]
});
该模型实际只需要2个字段,不过为了显示上的需要,特意添加了另外几个字段。
接着是Content.js,代码如下:
Ext.define('SimpleCMS.model.Content',{
extend: 'Ext.data.Model',
fields: [
{name: "ContentId", type: "int" },
{ name: "CategoryId", type:"int", defaultValue: 10000 },
"Title",
"Image",
"Summary",
"Content",
{name: "Created", type: "date", dateFormat: "Y-m-dH:i:s", defaultValue: new Date() },
{ name: "Hits", type:"int" },
{ name: "SortOrder", type:"int", defaultValue: 0 },
"Tags"
],
proxy: {
type: "ajax",
url: "Content/Details",
reader: {
type: 'json',
root: "data",
messageProperty: "Msg"
}
},
idProperty: "ContentId"
});
代码中添加了一个Tags字段,用来显示标签,该字段将以数组形式返回数据,这样,在后续的处理中会很方便。在CategoryId中,它的默认值为10000,表示文章创建时,默认的分类为“未分类”。
这样,模型就全部定义完了,现在切换到Store目录,先创建CategoriesTree.js,代码如下:
Ext.define("SimpleCMS.store.CategoriesTree",{
extend: 'Ext.data.TreeStore',
batchActions: false,
remoteFilter: false,
remoteSort: false,
model:"SimpleCMS.model.CategoryTree",
root: { text: "文章分类", id: -1 },
proxy: {
api: {
destroy: 'Category/Delete'
},
type: "ajax",
url: "/Category/List",
reader: {
type: 'json',
root: "data",
messageProperty: "Msg"
},
writer: {
type: "json",
encode: true,
root: "data",
allowSingle: true
}
}
})
因为分类的新增和编辑都是通过表单形式完成的,因而在配置项api中只定义了删除地址。
接着是CategoriesCombo.js,代码如下:
Ext.define("SimpleCMS.store.CategoriesCombo",{
extend: 'Ext.data.Store',
batchActions: false,
remoteFilter: false,
remoteSort: false,
autoLoad: true,
model:"SimpleCMS.model.CategoryCombo",
proxy: {
type: "ajax",
url: "/Category/All",
reader: {
type: 'json',
root: "data",
messageProperty: "Msg"
}
}
});
代码中定义了配置项autoLoad为true,说明在Store实例化后会自动加载数据。
最后是Contents.js,代码如下:
Ext.define("SimpleCMS.store.Contents",{
extend: 'Ext.data.Store',
model: 'SimpleCMS.model.Content',
batchActions: false,
remoteFilter: true,
remoteSort: true,
pageSize: 50,
proxy: {
type: "ajax",
url: "Content/List",
reader: {
type: 'json',
root: "data",
messageProperty: "Msg"
}
}
})
从代码可以看到,文章的Store需要支持远程排序和搜索,而且每50条记录为一页。
至此,文章管理的模型和Store就定义完了,下面要开始定义控制器了,这个下文再说。