MVC Developers Part 7 – Custom System Configuration

One of the most powerful elements of the Magento e-commerce system is the System Admin Config section. As a developer, will it allow you to quickly and easily set, elements that allow your end-users to their system and your Magento custom modules to configure.

My wife glad to see me in action again 🙂 I’m gonna buy new bed this week, haha. Online viagra. We also dispense your medications from international fulfillment centers that are approved by the regulatory bodies from their respective countries.

Like a lot of things in Magento can be intimidating the first time you try to install a new configuration section from scratch, but once you done it once the power of (almost) code will form a less addictive. Let us begin.

We will build the module in Magento we Controller and Hello World Dispatch article, but an empty module would be sufficient. The impatient can download complete module for this article.

The following is part of a longer series on Magento aimed at developers familiar with PHP MVC development. Although each article can be read stand alone, each article is based on concepts and code covered in previous articles. If you are confused, especially to catch up on the earlier work first.

Adding A System Config File

The first thing to do is add a system configuration file for our module. This config.xml file is separate from, and can be found at the following location

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

Although similar to the global configuration, the system configuration information stored separately. If you need to check the system config file, it exists as an entity. You can configure the entire system by running the following PHP code of each controller action

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

The method will look Load Module Configuration etc each configured module directory for a file name passed in (in this case, System.Xml). Magento is a number of other configuration files (api.xml, wsdl.xml, wsdl2.xml, convert.xml, compilation.xml, install.xml) and as a module developer you can leverage this functionality to your own make.

Adding a new Tab

The first thing we do is a custom “Tab” to the system configuration. Navigation tabs are the headers down the left side of the Admin in System-> Configuration. The default tabs are General, Catalog, customers, sales, services, and Advanced.

Let’s create a new one called “Hello Config”. Create a new config file system and add the following

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>

A brief explanation is in order. The name of the node <helloconfig /> is arbitrary, but must be unique among the tabs. It will serve as an identifier for your tab, which we later will use in the config.

The module = “helloWorld” attribute indicates which module the tab “belongs” to <label> determines the name that will be used for your tab, and <sort_order> determines where the tab displays in relation to the other tabs in the left hand navigation.

With this in place, the head of the System -> Config section. One of two things must happen

1. The page loads as expected, but without your new tab
2. You receive an error message something like the following:
Fatal error: Class ‘Mage_Helloworld_Helper_Data’ not found in

A Brief Interlude for Helper Classes

Like many of the popular PHP MVC systems, Magento has helper classes, used for a variety of tasks that do not fit neatly into model, view, or controller. Helper classes are grouped in the abstracted class names, which means that users of the system standard classes and module developers need to write a part to add to their base class name for the config.xml specify helpers.

Much of the code Magento system is based on a module has a default helper class. If you have the above exception, it’s because you did not have this module helloWorld default helper class and the system was trying to use. Let’s add one now.

First we need some of the main module to the config.xml file (not the system config to add)

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

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

If you anytime spent in the Magento config This should be straight. The <helloworld /> tag should be named for your module, and <class /> tag the base name of your helper class, called the Convention contain standard Magento

Packagename_Modulename_Helper

Helper programs are loaded with static global object Mage helper method. The following call (assuming the above configuration file)

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

tax would be the next class

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

Magento has the concept of a standard module, a Helper. If you are a helper class with only the module name

Mage::helper('helloworld');

will look for a helper data located

app/code/local/Alanstormdotcom/Helper/Data.php
class Alanstormdotcom_Helloworld_Helper_Dara

That means that the following two calls are equivalent.

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

Finally, we need the real helper class to add. Add the following file, and you’re good to go.

File: app/code/local/Alanstormdotcom/Helper/Data.php
class Alanstormdotcom_Helloworld_Helper_Data extends Mage_Core_Helper_Abstract
{
} 

With all this done, you need your Magento cache and reload the system. Your error message should disappear, but the new tab is still missing.

Note: If you want to know more about the nature of things an assistant can do for you, checkout Mage_Core_Helper_Abstract class for a list of useful methods to all helpers will have.

Adding A New Section

Helper interlude out of the way, our next step is figuring out why our tab configured not show up. Each tab has a number of components. For example, the Advanced tab (default) an Admin, System, Advanced and developers section.

If one tab is configured with no sections, it will not show up. Let’s fix this by adding a node to <section /> 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 are a number of known nodes in this new configuration section, and a few new faces.

What is a <helloworld_options/>?

Similar to the <helloconfig /> tag above, this one artibrary name used to identify your new section.

What is a <label />?

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

What is a <tab />?

This indicates the tab your new section should be grouped under. We want to show our section under our new config hello Tab. Hello the config name comes from the tag used for the tab (create <helloconfig/>)

What is a <frontend_type />?

This is tricky. <frontend_type /> sense in other parts of the configuration (see below), but it does not seem to do nothing. However, sections in the Core modules use this tag, so it is best to follow the convention, even if you are not sure what it does.

What is a <sort_order />?

Again, this section defines where <sort_order /> shows vertically compared to other departments 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 the configuration of host / graininess of this section.

Our section is configured, let’s go to System -> Config again (reload the Admin page not often enough). You will see your department and the tab near the bottom of the left navigation. You can add more sections by adding extra nodes to the node <sections />.

Access Control

If you click your new link section, you’ll be disappointed by the results. A blank admin page is loaded, and the entire left menu will disappear. That’s because the HTML Admin application can not find an entry for our new section in the Access Control List (ACL).

ACL is a subject all its own, but I will try to explain enough here so this does not seem like total magic. This part is optional, and if you are not interested to the end of the XML magic to paste into your config.xml

There are certain resources (where the source is a loosely defined term) that a user needs to be verified before using them. Resource is an abstract term. It may be a page in the admin, or, access to a specific function to be seen. The team decided that Magento System Configuration sections have ACL protection.

Resources are defined by URIs. For example, the “web” config section (under the General tab), if defined with a URI

admin/system/config/web

Helloworld_options our part would have a URI

admin/system/config/helloworld_options

The Admin application (often called Admin HTML) is built the same structure as the store application (the shop is often the front-end application). Admin Html controllers in action, when a user needs to access a resource protected by ACL, the developer must Admin Html

1. Lead to a URI which means the end user tries to access
2. Check URI against the ACL system, which will determine whether the
logged in user has the right privileges given source
3. If the user has the appropriate privileges, to continue. If they do not, they boot
or needed to do something (like stop rendering the navigation and content areas)

For those interested, this is done for the System Configuration section in the _isSectionAllowed method in the next controller

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

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

Adding an ACL role

That out of the way, we need an ACL resource for our new category to define. You need to do this only if you add a new section. If your config options to add to an existing part you do not need to touch ACL.

Config.xml in your modules, add the following paragraph

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 down a bit. Firstly, all defined resources are included in the following node structure.

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

Inside sources, each descending node is a URI part. So, this is far below

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

gives us a URI

admin/system

If you follow it 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 appears in the admin permissions.

With this in your config and your Magento cache cleared, you now need to make your configuration. You may need to log off the application and return to see. The Admin has a few extra caching than the standard Magento cache which I have not been able to trace. Ig you log out, log back in, and the part you need now a blank page with the title config tree “Hello World config options.

Note: For some reason the Magento comics <adminhtml /> section of the config from the config object. This means that you are not the Config Viewer for your work here to check. I go where (if anywhere) the <adminhtml /> block is stored.

Adding Groups

So, we now have an empty config section. Our next step is to add a group.

Groups are used to group together different configuration options, and will appear in the Magento admin with a popup widget to open. For example, in one file to install the Advanced section has a single group called “Disable output modules. Let a group named “messages” by adding a node to <groups /> our config, nestled in the node <sections>

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 of the top level <section /> node.

If you reload your page, you now have a blank pop-open box with the title “Demo of config Fields”.

Adding Config Fields

Finally, we add individual configuration fields. You do this by adding a node to your <fields /> <messages /> node. We start with a field named “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 in 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 doing something useful with the system to know what kind of form element you want. Reload your page, and you should now see an individual text in the popup box.

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

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

Note that the main difference here is the

<frontend_type>time</frontend_type>

tag. Reload your page, and you now have a config field for storing a time value.

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

<!-- ... -->
<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 is that you select HTML, but without values. We’re going to need a source model for our field to add definition. Try this place.

<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 will use the default values for the call. This means we must ensure that our module’s config.xml model setup section has

File: app / code / local / Alan Storm Dotcom / helloWorld / etc / config.xml

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

See Magento Models and ORM basics and the Class Abstraction and Instantiation supply article if you are unsure what is in the config.

So with that in place, if our page reload after clearing a cache, we end up with something like a mistake

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

That’s because we have not defined our source model class. Let’s do that now.

Note: If you get the warning uses a Mage / Hello World / … path, that means you do not set up correctly in your config.xml <model /> section.

To determine our source model, add the 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 called toOptionsArray. This method must return an array of values used to set the default values of our form elements (which are derived from the hierarchy Varien_Data_Form_Element_Abstract populate). To select an element, this means that defining a set of value / label pairs. In the above example, we pass our labels through the translation of the helper method (__). Although not necessary, it is always a good practice. You never know when you’re going to get big in Japan!

Reload your page, and you must select a working area.

For those interested in Magento internals, initFields the method in the next class is where the source model is used to set the field value

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

Adding to Existing Config Sections/Groups

Besides setting up a private config tabs and sections, you can add to an existing system config section by adding appropriate components to create your own file System.Xml.

For example, if you follow

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 have a new group in the General tab named “Example of adding a group.”

Retrieving Values

We have already set up forms to create the configuration. To retrieve values in our client applications and modules, we will getStoreConfig method using the global object Mage. For example, the value of the selection we created above to intervene, we would use

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

GetStoreConfig the method accepts a parameter which URIs 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 store a value that is not used by the store to grab the current session, getStoreConfig accepts a second parameter, the store ID

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

Wrapup

We started to setup some System Config sections, and ended up exploring helper classes, access control lists, and Varian Shape hierarchy. In addition to what we covered above, it is possible to system configuration options that are custom frontend and backend models, I will try to cover in a recent article use.

(Based on Alanstorm Turtorial)

Comments Closed