在这一章节里,我们将学习如何将 Grid 表正确的添加至后台表单选项卡所对应的 content 区块里
这一章节只针对于对 Magento 有深刻了解的开发者,并已成功在后台选项卡所对应的 Content 区块里添加过 Grid 表,及有能力解决所碰到的问题
下载: Grid Serializer Module Source (17.19KB)
为了更好的讲解,我们来拿一个客户的需求当作实例,需求方案如下,建立一个实体叫’Customer Manager’, 随之分配一批客户给这个’Customer Manager’来管理,在后台页面,我们需要能够从整个客户表里选择客户,然后保存或者关系到某一个指定的 Customer Manager。所以在’Customer Manager’编辑页面中要显示出一个完整的客户 Grid 表, 这个表里会有 checkbox 列可以多选客户,这个类似于在后台编辑商品页面里的 Related Products 和 Cross-sell Products
默认或者简单的操作方法是: 在 Tabs.php 文件里创建一个后台视窗,这里有个 addTab() 方法来定义我们想要添加的视窗路径(指: block 文件路径),代码如下:
1
2
3
4
5
6
7
|
$this
->
addTab
(
'form_section'
,
array
(
'label'
=
>
Mage::
helper
(
'test'
)
->
__
(
'Sample Grid'
)
,
'title'
=
>
Mage::
helper
(
'test'
)
->
__
(
'Sample Grid'
)
,
'content'
=
>
$this
->
getLayout
(
)
->
createBlock
(
'fav/adminhtml_fav_edit_tab_grid'
)
->
toHtml
(
)
,
)
)
;
|
这样一个 Grid 表会显示在新增选项卡(Tab)所对应的 Content 区块里, 但是在运行的时候会有许多问题产生。比如在搜索或分页的时候,和添加/删除条目有关操作的时候
正确的操作方法
在 Tabs.php 中的 addTab() 方法应该如下:
1
2
3
4
5
6
|
$this
->
addTab
(
'form_section1'
,
array
(
'label'
=
>
Mage::
helper
(
'test'
)
->
__
(
'Customers'
)
,
'title'
=
>
Mage::
helper
(
'test'
)
->
__
(
'Customers'
)
,
'url'
=
>
$this
->
getUrl
(
'*/*/customer'
,
array
(
'_current'
=
>
true
)
)
,
'class'
=
>
'ajax'
,
)
)
;
|
这样做的话,当你点击 Customers Tab, 它就会以 ajax 方式调用 url 加载,然后显示出 Grid 表
在我们的 controller 文件中, 添加 custoemrAction() 方法,代码如下:
1
2
3
4
5
6
7
8
9
|
public
function
customerAction
(
)
{
$this
->
loadLayout
(
)
;
$this
->
getLayout
(
)
->
getBlock
(
'customer.grid'
)
->
setCustomers
(
$this
->
getRequest
(
)
->
getPost
(
'customers'
,
null
)
)
;
$this
->
renderLayout
(
)
;
}
|
这个操作十分简单, 只是简单的加载和输出 Layout, 所以还有段重要的代码应该写在该模块的 XML 文件里(在 Layout 文件夹下), 如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<
test_adminhtml_test_customer
>
<
block
type
=
"core/text_list"
name
=
"root"
output
=
"toHtml"
>
<
block
type
=
"test/adminhtml_test_edit_tab_grid"
name
=
"customer.grid"
>
<
/
block
>
<
block
type
=
"adminhtml/widget_grid_serializer"
name
=
"grid_serializer"
>
<
reference
name
=
"grid_serializer"
>
<
action
method
=
"initSerializerBlock"
>
<
grid_block_name
>
customer
.
grid
<
/
grid_block_name
>
<
data_callback
>
getSelectedCustomers
<
/
data_callback
>
<
hidden_input_name
>
links
[
customers
]
<
/
hidden_input_name
>
<
reload_param_name
>
customers
<
/
reload_param_name
>
<
/
action
>
<
action
method
=
"addColumnInputName"
>
<
input_name
>
position
<
/
input_name
>
<
/
action
>
<
/
reference
>
<
/
block
>
<
/
block
>
<
/
test_adminhtml_test_customer
>
|
第一个 block 只是简单的定义了我们 Grid 表的 block 文件,第二个 block 非常重要,它增加了一个 grid serializer, 其作用是建立一个 hidden input 框来保存多选框中 check/uncheck 的值
现在来解析下 XMl 中第二个 block:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<
action
method
=
"initSerializerBlock"
>
<
grid_block_name
>
customer
.
grid
<
/
grid_block_name
>
<
data_callback
>
getSelectedCustomers
<
/
data_callback
>
<
hidden_input_name
>
links
[
customers
]
<
/
hidden_input_name
>
<
reload_param_name
>
customers
<
/
reload_param_name
>
<
/
action
>
grid_block_name
//包含了 Grid 表的名字
data_callback
//这个方法定义在 Grid 里, 将 return 出所选中项目的值
hidden_input_name
//包含了 hidden input 框的名字
reload_param_name
//很遗憾,这个我都不知道… 囧
<
action
method
=
"addColumnInputName"
>
<
input_name
>
position
<
/
input_name
>
<
/
action
>
|
postion 是在 Grid 表中一个列的名字(需要是一个 text 文本框), 很显然,在使用 grid serializer 的时候,在 Grid 表中需要一个带有 text 文本框的列(作为搜索的选择之一)
现在,让我们来看一下 Grid.php 文件,里面的内容和通常的 Grid.php 一样,在这里,我只指出不同和新增的地方,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
public
function
__construct
(
)
{
parent
::
__construct
(
)
;
$this
->
setId
(
'customerGrid'
)
;
// 选择是否使用 ajax 十分重要
$this
->
setUseAjax
(
true
)
;
$this
->
setDefaultSort
(
'entity_id'
)
;
// 默认我们已经为行添加了一个过滤器, in_products 的值设置为 1
$this
->
setDefaultFilter
(
array
(
'in_products'
=
>
1
)
)
;
// 不要把参数保存在 Session 里面,这样会产生问题
$this
->
setSaveParametersInSession
(
false
)
;
}
|
接下来,我们为显示的 checkboxes 添加一个自定义的过滤器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
protected
function
_addColumnFilterToCollection
(
$column
)
{
// Set custom filter for in product flag
if
(
$column
->
getId
(
)
==
'in_products'
)
{
$productIds
=
$this
->
_getSelectedCustomers
(
)
;
if
(
empty
(
$productIds
)
)
{
$productIds
=
0
;
}
if
(
$column
->
getFilter
(
)
->
getValue
(
)
)
{
$this
->
getCollection
(
)
->
addFieldToFilter
(
'entity_id'
,
array
(
'in'
=
>
$productIds
)
)
;
}
else
{
if
(
$productIds
)
{
$this
->
getCollection
(
)
->
addFieldToFilter
(
'entity_id'
,
array
(
'nin'
=
>
$productIds
)
)
;
}
}
}
else
{
parent
::
_addColumnFilterToCollection
(
$column
)
;
}
return
$this
;
}
|
从上述代码中可以看出,这个方法已经十分明显, 并且会在下面定义
接下来,我们添加一个 checkbox 列
1
2
3
4
5
6
7
8
|
$this
->
addColumn
(
'in_products'
,
array
(
'header_css_class'
=
>
'a-center'
,
'type'
=
>
'checkbox'
,
'name'
=
>
'customer'
,
'values'
=
>
$this
->
_getSelectedCustomers
(
)
,
'align'
=
>
'center'
,
'index'
=
>
'entity_id'
)
)
;
|
这个 $this->_getSelectedCustomers() 方法会 return 出在数据库中存在的并且被选择的所有 id 号,这里所选择的是指已经指定给一个 customer manager 的客户
再额外增加一列 “position” :
1
2
3
4
5
6
7
8
9
10
|
$this
->
addColumn
(
'position'
,
array
(
'header'
=
>
Mage::
helper
(
'catalog'
)
->
__
(
'ID'
)
,
'name'
=
>
'position'
,
'width'
=
>
60
,
'type'
=
>
'number'
,
'validate_class'
=
>
'validate-number'
,
'index'
=
>
'position'
,
'editable'
=
>
true
,
'edit_only'
=
>
true
)
)
;
|
这一列的增加只是为了保证 serializer 正常工作, 这个列名已在该模块的 XML 文件里声明过了。该列有一个 text input 框,这也是 serializer 正常工作的必须条件
现在我们来增加两个方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
protected
function
_getSelectedCustomers
(
)
{
$customers
=
array_keys
(
$this
->
getSelectedCustomers
(
)
)
;
return
$customers
;
}
public
function
getSelectedCustomers
(
)
{
// Customer Data
$tm_id
=
$this
->
getRequest
(
)
->
getParam
(
'id'
)
;
if
(
!
isset
(
$tm_id
)
)
{
$tm_id
=
0
;
}
$customers
=
array
(
1
,
2
)
;
// 这里是写死的,通常应该从数据库中获得
$custIds
=
array
(
)
;
foreach
(
$customers
as
$customer
)
{
foreach
(
$customer
as
$cust
)
{
$custIds
[
$cust
]
=
array
(
'position'
=
>
$cust
)
;
}
}
return
$custIds
;
}
|
这个方法已在 XML 中声明过是一个 callback 方法, 同样你可以看出 array 的格式 return 出来的时候带有 postion
另外还有一个 getGridUrl() 需要添加
1
2
3
|
<
p
style
=
"color:#FF6600;"
>
另外还有一个
getGridUrl
(
)
需要添加
<
/
p
>
|
这个方法基于 ajax 并且用在所有的 Grid 表中, 在搜索和分页的时候会用到, 为此还要在我们的 controller 文件中添加对应的 Action 方法:
1
2
3
4
5
6
7
|
public
function
customergridAction
(
)
{
$this
->
loadLayout
(
)
;
$this
->
getLayout
(
)
->
getBlock
(
'customer.grid'
)
->
setCustomers
(
$this
->
getRequest
(
)
->
getPost
(
'customers'
,
null
)
)
;
$this
->
renderLayout
(
)
;
}
|
同样在 XML 中添加:
1
2
3
4
5
|
<
test_adminhtml_test_customergrid
>
<
block
type
=
"core/text_list"
name
=
"root"
output
=
"toHtml"
>
<
block
type
=
"test/adminhtml_test_edit_tab_grid"
name
=
"customer.grid"
>
<
/
block
>
<
/
block
>
<
/
test_adminhtml_test_customergrid
>
|
为了让 Grid 表正常工作,这些步骤是不可缺少的,现在,Grid 表应该可以正常工作了, 你也可以用 firebug 查看下你的 HTML 代码, 在 Grid <div> 标签后面, 你应该可以查看到这个 hidden input :
当你选中或者取消选中 checkbox 时, 里面的值应该随之变化。下一步,就是要保存我们的表单,我们需要获得我们所选客户的值,以便保存到数据库, 为了达到,添加如下代码至 saveAction 里面:
1
2
3
4
5
|
if
(
isset
(
$data
[
'links'
]
)
)
{
$customers
=
Mage::
helper
(
'adminhtml/js'
)
->
decodeGridSerializedInput
(
$data
[
'links'
]
[
'customers'
]
)
;
//保存数组到数据库
}
|
你可以使用 customers array 来保存到数据库
source: http://www.sunzhenghua.com/magento-admin-module-development-part6-internal-grid-forms-advanced