深入Magento系统配置

http://alanstorm.com/custom_magento_system_configuration 可以看原文。以下的中文不是只能是大概的意译(看了英文,根据自己理解写成中文),所以对于错误之处不要较真。

1 添加系统配置文件
app/code/local/Vfeelit/Helloworld/etc/system.xml
跟全局配置类似,系统配置信息单独存储。可以执行如下的PHP代码查看系统配置:

1
2
3
4
5
6
7
8

//header('Content-Type: text/xml');
header('Content-Type: text/plain');
echo $config = Mage::getConfig()
->loadModulesConfiguration('system.xml')
->getNode()
->asXML();
exit;

loadModulesConfiguration方法查找所有模块的etc的给定的配置文件(这里是system.xml)。Magento还有很多其它的配置文件(apix.xml, wsdl.xml, wsdl2.xml, convert.xml, conplilation.xml, install.xml)

2 添加新的Tab
在System->Configuration,默认的tabs是General, Catalog, Customers, Sale, Services 和 Advanced。
这里创建一个新的叫“Hello Config”的tab。在system.xml文件中添加如下代码:

1
2
3
4
5
6
7
8
9
10

Location: app/code/local/Vfeelit/Helloworld/etc/system.xml
<config>
<tabs>
<helloconfig translate="label" module="helloworld">
<label>Hello Config</label>
<sort_order>99999</sort_order>
</helloconfig>
</tabs>
</config>

helloconfig节点是任意的,但是必须唯一,它作为tab的唯一认证,后面会使用到这个唯一认证(添加Section时用tab标签指定它的Tab)。module=”helloworld”属性说明属于哪个模块,label标签决定了tab的名字,sort_order决定tab的排序码。

导航到System->Configuration。将发生:

页面正常呈现,但是没有出现新的tab
获取一个错误提示:Fatal error: Class ‘Mage_Helloworld_Helper_Data’ not found in

3 针对helper类的简短插曲
helper类是哪些不合适写入MVC中的代码。Helper类是抽象的分组类名之一,用户可以覆盖默认类,模块中需要配置它的基础类名。

很多系统代码假设模块有一个默认的Helper类。如果你获取了类似上面的异常,那是因为没有添加默认Helper类,但是系统试图使用它。

1
2
3
4
5
6
7
8
9
10
11
12
13

File: app/code/local/Alanstormdotcom/Helloworld/etc/config.xml
<!-- ... -->
<global>
<!-- ... -->
<helpers>
<helloworld>
<class>Vfeelit_Helloworld_Helper</class>
</helloworld>
</helpers>
<!-- ... -->
</global>
<!-- ... -->

获取helper类的方法:

1
2
3
4
5

Mage::helper('helloworld/foo');
//将加载下面的类
app/code/local/Vfeelit/Helloworld/Helper/Foo.php
class Vfeelit_Helloworld_Helper_Foo

Magento针对模块有一个默认Helper的概念。如果在提供Helper类时只给出模块名:

1
2
3
4
5
6
7

Mage::helper('helloworld');
//相当于
Mage::helper('helloworld/data');
//都获取如下类:
app/code/local/Vfeelit/Helloworld/Helper/Data.php
class Vfeelit _Helloworld_Helper_Dara

最终,我们需要添加一个实际的Helper类。

1
2
3
4
5

File: app/code/local/Vfeelit/Helloworld/Helper/Data.php
class Vfeelit_Helloworld_Helper_Data extends Mage_Core_Helper_Abstract
{
}

重新加载系统配置页面,发现新的Tab还是没有出现。

4 添加一个新的Section
每个Tab有多个Section。比如,Advanced Tab有Admin,System, Advanced,和Developer Section.

如果Tab没有Section,这个Tab不会显示。所以需要添加section节点到system配置中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

Location: app/code/local/Vfeelit/Helloworld/etc/system.xml
<config>
<tabs>
<helloconfig translate="label" module="helloworld">
<label>Hello Config</label>
<sort_order>99999</sort_order>
</helloconfig>
</tabs>
<sections>
<helloworld_options translate="label" module="helloworld">
<label>Hello World Config Options</label>
<tab>helloconfig</tab>
<frontend_type>text</frontend_type>
<sort_order>1000</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</helloworld_options>
</sections>
</config>

Section节点跟Tab节点很类似,helloworld_options名字也是随意的(必须唯一),module=”helloworld”表示属于哪个模块。label标签指定了这个Section的名字,tab表示这个Section放入哪个tab中,这里放入了helloconfig这个tab中,frontend_type在这里没有作用(实际控制输入类型,Section没有这个概念),sort_order是Section的排序码,show_in_default 和 show_in_website 和 show_in_store 控制Scope显示。

5 访问控制(Access Control)
点击新添加的Section,获得一个404页面。那是因为Adminhtml应用程序无法在访问控制列表(ACL)中为新的Section找到进入点(就是系统不知道有新的Section存在,必须配置告诉它存在,然后可能还要给用户授权)。

在使用特定的资源前需要用户获得授权。Magento对系统配置Section应用了ACL保护。

资源是通过URI定义的。比如在General Tab下的web Section,它用如下URI定义:

admin/system/config/web
//helloworld_options Section有如下URI
admin/system/config/helloworld_options
实际代码通过_isSectionAllowed方法检查授权:
app/code/core/Mage/Adminhtml/controllers/System/ConfigController.php

6 添加一个ACL角色
针对我们的新的Section,需要定义ACL资源,注意,只有新添加的Section需要定义ACL资源。
在config.xml中:

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
26
27

File: app/code/local/Vfeelit/Helloworld/etc/config.xml
<config>
<!-- ... -->
<adminhtml>
<acl>
<resources>
<admin>
<children>
<system>
<children>
<config>
<children>
<helloworld_options>
<title>Store Hello World Module Section</title>
</helloworld_options>
</children>
</config>
</children>
</system>
</children>
</admin>
</resources>
</acl>
</adminhtml>
<!-- ... -->
</config>

分段解释:

1
2
3
4
5
6
7

<adminhtml>
<acl>
<resources>
</resource>
</acl>
</adminhtml>

这个是分配ACL资源的固定格式。在resources后面,每部分都对应URI的一部分:

1
2
3
4
5
6
7
8

<admin>
<children>
<system>
<children>

//得到
admin/system

这样一路下来就得到helloworld_options。Title标签将在分配权限时出现。

刷新缓存重新加载(可能还要重新登录),检查是否能访问新添加的Section。

注意:由于一些原因,Magento从配置对象中去掉了adminhtml节点。

7 添加Groups
现在可以访问Section了,但是它是空的。组用来把不同的配置选项进行分组。下面创建一个叫messages的group节点,groups节点需要嵌套在sections节点中:

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
26
27
28
29
30
31

Location: app/code/local/Vfeelit/Helloworld/etc/system.xml
<config>
<tabs>
<helloconfig translate="label" module="helloworld">
<label>Hello Config</label>
<sort_order>99999</sort_order>
</helloconfig>
</tabs>
<sections>
<helloworld_options translate="label" module="helloworld">
<label>Hello World Config Options</label>
<tab>helloconfig</tab>
<frontend_type>text</frontend_type>
<sort_order>1000</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
<groups>
<messages translate="label">
<label>Demo Of Config Fields</label>
<frontend_type>text</frontend_type>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</messages>
</groups>
</helloworld_options>
</sections>
</config>

这里的配置跟之前的非常类似。刷新页面得到一个空组。

8 往组中添加配置字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

<!-- ... -->
<messages translate="label">
<label>Demo Of Config Fields</label>
<frontend_type>text</frontend_type>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
<fields>
<hello_message>
<label>Message</label>
<frontend_type>text</frontend_type>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</hello_message>
</fields>
</messages>
<!-- ... -->

字段用fields包含,就像组用groups包含一样,每个字段跟组的配置非常类似,不过这里的frontend_type指定了字段输入类型(以前的没有作用?)。类型不仅仅是text,还可以指定其它的,如下,添加一个叫hello_time的字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

<fields>
<hello_message>
<label>Message</label>
<frontend_type>text</frontend_type>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</hello_message>
<hello_time>
<label>Time to Say Hello</label>
<frontend_type>time</frontend_type>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</hello_time>
</fields>

注意这里的类型是time。这样就可以输入时间值了。大多lib/Varien/Data/Form/Element类型的表单类都是支持的。frontend_type tag acts as an identifier for a factory-ish pattern. 把hello_message改为一个下来字段:

1
2
3
4
5
6
7
8
9

<hello_message>
<label>Message</label>
<frontend_type>select</frontend_type>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</hello_message>

这时下拉框没有任何值。我们需要为这个定义的字段给出一个资源模型:

1
2
3
4
5
6
7
8
9
10
11

<hello_message>
<label>Message</label>
<frontend_type>select</frontend_type>
<!-- adding a source model -->
<source_model>helloworld/words</source_model>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</hello_message>

source_model元素定义了一个URI,对应一个模型类,它是我们用来为select提供默认值的。这个需要在config.xml中做配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

File: app/code/local/Alanstormdotcom/Helloworld/etc/config.xml
<config>
<!-- ... -->
<global>
<!-- ... -->
<models>
<!-- ... -->
<helloworld>
<class>Vfeelit_Helloworld_Model</class>
</helloworld>
<!-- ... -->
</models>
</global>
</config>

然后添加模型类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

File: app/code/local/Vfeelit/Helloworld/Model/Words.php
class Vfeelit_Helloworld_Model_Words
{
public function toOptionArray()
{
return array(
array('value'=>1, 'label'=>Mage::helper('helloworld')->__('Hello')),
array('value'=>2, 'label'=>Mage::helper('helloworld')->__('Goodbye')),
array('value'=>3, 'label'=>Mage::helper('helloworld')->__('Yes')),
array('value'=>4, 'label'=>Mage::helper('helloworld')->__('No')),
);
}

}

资源模型类提供了一个叫toOptionsArray的方法。这个方法必须返回一个值的数组,它用来填充表单元素的默认值(它来自Varien_Data_Form_Element_Abstract的要求)。对于一个select元素,意味着需要定义一个键值对集合。在上面的例子中,我们使用默认助手类的(__)翻译方法(非必要,不过一般都这样操作)

如果对Magento内部感兴趣,下面文件的initFields方法实现将资源模型用来设置字段的值:
app/code/core/Mage/Adminhtml/Block/System/Config/Form.php

10 Adding to Existing Config Sections/Groups
不需要新建Tab或Section或Group。可以利用现有的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

File: app/code/local/Alanstormdotcom/Helloworld/etc/system.xml
<config>
<!-- ... -->
<sections>
<!-- ... -->
<general>
<groups>
<example>
<label>Example of Adding a Group</label>
<frontend_type>text</frontend_type>
<sort_order>1</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</example>
</groups>
</general>
<!-- ... -->
</section>
</config>

上面往General Tab的General Section中添加一个example组。这种方法添加配置会和原始的合并。

注意,如果定义了新的Section,应该同时配置它的ACL资源,这样后台才能发现这个资源,然后才能决定用户是否有权限访问它。

11 取回值
配置的这些值是要在模型中使用的,那么如何取回这些值呢?

1
2

Mage::getStoreConfig('helloworld_options/messages/hello_message');

URI参数格式:section_name/group_name/field_name
如果只提供了URI的部分,将获取一个数组:

1
2
3

Mage::getStoreConfig('helloworld_options/messages');
Mage::getStoreConfig('helloworld_options');

如果需要获取不属于当前商店的配置,可以在第二参数指定店铺Id。

1
2

Mage::getStoreConfig('helloworld_options',1);
坚持原创技术分享,您的支持将鼓励我继续创作!