在Magento System Configuration新增内容

piaoling  2011-06-13 17:27:07

Custom Magento System Configuration

Magento之所以非常强大,一部分是由于它有非常强大的后台(Admin’s System Config section)配置能力。它允许开发者通过添加一些表单元素就可以配置Magento系统和用户新增的模块。

在我们刚开始在Magento中新增一些自定义的内容时,由于Magento自身原因(复杂但灵活),往往会望而生畏,但是当你着手去做的时候,你就会喜欢上它的灵活。

下面我们通过一个简单的例子来学习Magento System Configuration(system.xml).
例:新增一个module Helloworld

app/code/local/Alanstormdotcom/Helloworld/etc/ 目录下新建system.xml(当然system.xml不同于

app/code/local/Alanstormdotcom/Helloworld/etc/system.xml    

就像Magento其他的 the global config,system.xml 也是在各个模块中分别定义. 如果你想知道该system.xml配置信息是否已加载到系统中可以通过执行下面的代码来实现。

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

loadModulesConfiguration 方法将在每个module下的etc文件夹下查找system.xml(当然也查找config.xml).Magento还有其他的一些配置文件(如:api.xml, wsdl.xml, wsdl2.xml, convert.xml, compilation.xml, install.xml), 作为一名开发者可以根据自己的需要和能力选择是否定义这些文件。

新增一个Tab(就像system->configuration页面左边的列表一样,如General, Catalog, Customers, Sales, Services and Advanced,一个Tab下面再定义它自己的内容).

下面我们新建一个name为"Hello Config"的Tad,然后新增一个system.xml文件,内容如下:

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

我们来逐一对每个定义进行分析.Node <helloconfig /> 的名字是任意的(仅用来区别于其他Tabs), 但是在所有定义的Tabs中唯一. 属性 module="helloworld" 用来定义该Tab属于哪个module, <label> 用来定义Tab的名字(就是在它下一级的<label />中定义它的名字), <sort_order> 中的值决定了该Tab,在configuration页面中左边导航中的所有Tabs中的排列的顺序.

在我们完成上面的工作之后,进入 System -> Configuration页面,将会出现一下两种情况:

  1. 该页面正常载入,但是没有你新增的Tab.
  2. 出现如下error:
    Fatal error: Class 'Mage_Helloworld_Helper_Data' not found in

A Brief Interlude for Helper Classes

类似于大部分流行的PHP MVC 系统,Magento需要Helper classes,用来完成很多不太适合用Model,View,或者Controller完成的任务。 Helper classes 是一种 abstracted grouped class names, 意味着开发者可以 override系统默认的Helper classes 和需要在config.xml中增加一个Helper section来具体化Helpers的基类。Magento 系统中大部分的代码已经假设每个module都有一个默认的Helper class.如果出现了上面的error,是由于你新增的模块Helloworld没有定义这个默认的Helper class(系统会自动尝试调用它),下面我们把Helper class的定义加上 。

首先我们需要在module下的etc文件夹下的config.xml中添加一个section (注意非system.xml)

就像Magento中其他的config一样,上面的定义相当直观明了。<helloworld />是module的名字。<class />中包含你将定义的Helper classes(这种写法是Magento中默认的)

Packagename_Modulename_Helper 

 File: app/code/local/Alanstormdotcom/Helloworld/etc/config.xml

<!-- ... -->
<global>
    <!-- ... -->
    <helpers>
        <helloworld>
            <class>Alanstormdotcom_Helloworld_Helper</class>
        </helloworld>
    </helpers> 
    <!-- ... -->
</global>
<!-- ... -->   

  

Helper’s 和 Mage Object 的 static helper 方法一起被系统加载,下面的方法将被调用 (assuming the above config file) 

Mage::helper('helloworld/foo');  

同时加载下面的class

app/code/local/Alanstormdorcom/Helper/Foo.php class Alanstormdotcom_Helloworld_Helper_Foo 

   
Magento 同时也为每个module定义默认的Helper,如果你仅仅为Helper class 提供了module 的名字,如 

Mage::helper('helloworld');

Magento将在下面的地方查找 

app/code/local/Alanstormdorcom/Helper/Data.php

class Alanstormdotcom_Helloworld_Helper_Data  

那将意味着,下面的写法和上面的是一样的。 

e::helper('helloworld');

e::helper('helloworld/data');

   

最后我们来添加这个Helper class。添加下面的文件。

File: app/code/local/Alanstormdorcom/Helper/Data.php

class Alanstormdotcom_Helloworld_Helper_Data extends Mage_Core_Helper_Abstract

{

 

 }

 

 完成上面的步骤后,并在admin中clear cache,上面的error已经消失了,但是Tab还是没有出现。

Note: 如果你想知道helper能完成什么功能,请查看Mage_Core_Helper_Abstract 类,它提供了一系列非常用用的方法且所有的Helper都将拥有。

哎!编辑的格式不可逆,重新编辑文章后格式就变了。不爽,下面的就不翻译了

Adding A New Section

The Helper interlude out of the way, our next step is figuring out why our configured Tab isn’t showing up. Each Tab has a number of sections. For example, the Advanced tab has (by default) an Admin, System, Advanced, and Developer section.

If a Tab is configured with no sections, it won’t show up. Let’s fix this by adding a <section /> node to our system config

Location: app/code/local/Alanstormdotcom/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>

There’s some familiar nodes in this new configuration section, as well as a few new faces.

What is a <helloworld_options/>?

Similar to the <helloconfig /> tag above, this in a artibrary name that’s used to identify your new section.

What is a <label />?

A label defines the display value used in the HTML interface for your new section.

What is a <tab />?

This identifies which Tab your new section should be grouped under. We want our section to show up under our new helloconfig Tab. The helloconfig name comes from the tag used to create the Tab (<helloconfig/>)

What is a <frontend_type />?

This one it tricky. <frontend_type /> has meaning in other sections of the configuration (see below), but it doesn’t appear to do anything here. However, sections in the Core modules use this tag, so it’s best to follow the convention, even when you’re not sure what it does.

What is a <sort_order />?

Again, <sort_order /> determines where this sections shows up vertically compared to other sections in the Tab.

What is a <show_in_default />, <show_in_website />, <show_in_store />?

These are boolean config options, with a valid value of 1 or 0. They determine the level of configuration score/granularity this section has.

With our section configured, Let’s head over to System -> Config again (reloading the Admin page often won’t be enough). You should now see your section and tab near the bottom of the left hand navigation. You can add more sections by adding additional nodes to the <sections /> node.

Access Control

If you click your new section link you’ll be disappointed by the results. A blank admin page will load, and the entire left hand navigation will vanish. That’s because the Adminhtml application can’t find an entry for our new section in the Access Control List (ACL).

ACL is a topic all its own, but I’ll try to explain enough here so this doesn’t seem like total magic. This section is optional, and if you’re not interested skip to the end for the magic XML to paste into your config.xml

There are certain resources (where resource is a loosely defined term) that require a user to be authenticated before using them. Resource here is an abstracted term. It might be a page in the admin, or it might be access to a certain feature. The Magento team decided that System Config sections should have ACL protection.

Resources are defined via URI’s. For example, the “web” config section (under the General tab), if defined with a URI of

admin/system/config/web

Our helloworld_options section would have a URI of

admin/system/config/helloworld_options

The Admin application (often called Adminhtml) is built using the same framework as the store application (the store application is often called the frontend application). In Adminhtml action controllers, whenever a user needs to access a resource protected by ACL, the Adminhtml developer must

  1. Derive a URI for whatever resource the end-user is trying to access
  2. Check that URI against the ACL system, which will determine if the
    logged in user has the right privileges that particular resource
  3. If the user does have the correct privileges, proceed. If they don’t, boot them
    or do something appropriate (like stop rendering the navigation and content areas)

For those interested, this is done for the System Config sections in the _isSectionAllowed method in the following controller

app/code/core/Mage/Adminhtml/controllers/System/ConfigController.php

If you go to System -> Permissions -> Roles, add click the Add a new role button, you can see a graphical tree representation of all the Role Resources defined in your Magento install.

Adding an ACL role

That out of the way, we need to define an ACL resource for our new section. You only need to do this if you’re adding a new section. If you’re adding config options to an existing section you don’t need to touch ACL.

In your module’s config.xml, add the following section

File: app/code/local/Alanstormdotcom/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>

Yes, that’s a mouthful. Let’s break it down a bit. First off, all defined resources are contained in the following node structure.

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

Within resource, each descending node represents a URI portion. So, this far down

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

gives us a URI of

admin/system

If you follow that all the way down, you get to the node for our config

<helloworld_options>
    <title>Store Hello World Module Section</title>
</helloworld_options>

Title is what will show up in the Permissions admin.

With this in your config and your Magento cache cleared, you should now be able to view your config section. You may need to log out of the application and back into to see it. The Admin has some additional caching beyond the standard Magento cache that I haven’t been able to track down. Ig you log out, log back in, and navigate to your section you should now see a blank config page titled “Hello World Config Options”.

Note: For some reason Magento strips the <adminhtml /> section of the config from the config object. This means you can’t use the Configviewer to check your work here. I’m investigating where (if anywhere) the <adminhtml /> section gets stored.

Adding Groups

So, we now have a blank config section. Our next step is adding a group.

Groups are used to group together different configuration options, and are displayed in the Magento admin with a pop-open widget. For example, in a stock install the Advanced section has a single group named “Disable modules output”. Let’s create a group named “messages” by adding a <groups /> node to our config, nested within the <sections> node

Location: app/code/local/Alanstormdotcom/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>

Each tag within this node is analogous to the tags from the top level <section /> node.

If you reload your page, you’ll now see an empty pop-open box with the title “Demo Of Config Fields”.

Adding Config Fields

Finally, we need to add our individual configuration fields. You’ll do this by adding a <fields /> node to your <messages /> node. We’ll start with a field name “hello_message”.

<!-- ... -->
<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>
<!-- ... -->    

Again, fields within your new <hello_message> node are analogous to the other nodes you’ve added so far. However, this time <frontend_type>text</frontend_type> actually does something useful by letting the system know what kind of form element you want. Reload your page, and you should now see an individual text field in the popup box.

Once all this configuration information is in place, you’re done. No code is needed to save/load/update your config value. The system handles that all for you.

You’re not limited to text fields. Let’s add a field called <hello_time/>

<!-- ...-->
<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>
<!-- ... -->

Notice that the main difference here is the

<frontend_type>time</frontend_type>

tag. Reload your page, and you’ve now got a config field for saving a time value.

Many, but not all, of the built in Varien data form classes (lib/Varien/Data/Form/Element) are supported. The <frontend_type /> tag acts as an identifier for a factory-ish pattern. Let’s try changing our hello message to a select field.

<!-- ... -->
<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>
<!-- ... -->

If you reload your page you’ll see that you have an HTML select, but without any values. We’re going to need to add a source model to our field definition. Try this instead.

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

The <source_model> element defines a URI for a Model class that we’ll use to provide default values for the select. This means we’ll need to make sure that our module config.xml has its models section setup

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

See the Magento Models and ORM Basics and the Class Instantiation Abstraction and Autoload article if you’re not sure what’s going on in that config.

So, with that in place, if we reload our page after a cache clearing, we’ll end up with an Error something like

Warning: include(Alanstormdotcom/Helloworld/Model/Words.php)

That’s because we haven’t defined our source Model class. Let’s do that now.

Note: If the warning you’re getting uses a Mage/Helloworld/... path, that means you haven’t setup your <model /> section correctly in config.xml.

To define our source Model, add the following file

File: app/code/local/Alanstormdotcom/Helloworld/Model/Words.php
class Alanstormdotcom_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')),                       
        );
    }

}

Source Models are classes that respond to a method named toOptionsArray. This method should return an array of values that are used to populate the default values of our form elements (which descend from the Varien_Data_Form_Element_Abstract hierarchy). For a select element, this means defining a set of value/label pairs. In the above example, we’re passing our labels through the Helper’s translation method (__). While not necessary, this is always a good practice. You never know when you’re going to get big in Japan!

Reload your page, and you should have a working select field.

For those interested in the Magento internals, the initFields method in the following class is where the source Model is used to set the field’s value

app/code/core/Mage/Adminhtml/Block/System/Config/Form.php

Adding to Existing Config Sections/Groups

In addition to setting up your own config Tabs and sections, you can add to an existing System Config section by adding appropriate sections to your own system.xml file.

For example, if you add the following

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>

you’ll have a new group in the general Tab called “Example of Adding a Group”.

Retrieving Values

We’ve covered how to setup forms for creating configuration values. To retrieve values in our client applications and modules, we’ll use the getStoreConfig method on the global Mage object. For example, to grab the value of the select we created above, we’d use

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

The getStoreConfig method accepts a single parameter that’s a URI in the following format

section_name/group_name/field_name

You can also grab an array of all your config values by specifying a partial path

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

Finally, if you need to grab a value for a store that isn’t the store being used by the current session, getStoreConfig accepts a second parameter, the store ID

Mage::getStoreConfig('helloworld_options',1);

Wrapup

We started off wanting to setup some System Config sections, and ended up exploring Helper classes, Access Control Lists, and the Varian Form hierarchy. In addition to what we covered above, it’s possible to create System Config options that use custom frontend and backend Models, which I’ll try to cover in a latter article.

You can download the complete module for this article here.

from:http://yanggaojiao.iteye.com/blog/691023

类别 :  magento(258)  |  浏览(3483)  |  评论(0)
发表评论(评论将通过邮件发给作者):

Email: