Categories


Archives


Recent Posts


Categories


Validating System Configuration Values in Magento

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

The Magento Admin Console’s System Configuration section is almost an application framework in and of itself. The ability to quickly add form fields in a “zero code” way is a powerful feature, but it only touches the tip of the iceberg of what’s possible. This article will cover validating your configuration values, and sending appropriate error and/or warnings back to the end-user.

This article assumes an intermediate understanding of Magento coding conventions. You should be able to setup a new module for adding code to the system, configuring that module to use models, as well as configuring it to add a custom System Configuration field. If that all sounded greek to you, start reading

Let’s start by adding a custom module that sets up a System Configuration field for keeping track of a Store Fax Number.

Open up your Admin Panel and navigate to

System -> Configuration -> General -> Store Information

You should see three fields.

  1. Store Name
  2. Store Contact Telephone
  3. Store Contact Address

Create a custom module, and add a the following system.xml file. For the purposes of this tutorial, we’ll be using a custom module named Validationexample in the Alanstormdotcom namespace.

<!-- File: app/code/local/Alanstormdotcom/Validationexample/etc/system.xml -->
<config>
    <sections>
        <general>
            <groups>
                <store_information>
                    <fields>
                        <alanstormdotcom_validationexample_fax translate="label">
                            <label>Store Fax Number</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>20</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                        </alanstormdotcom_validationexample_fax>    
                    </fields>
                </store_information>
            </groups>
        </general>
    </sections>
</config>            

The alanstormdotcom_validationexample_fax doesn’t need to be named that way. However, by going out of our way to to use a unique string for the final path in our configuration node, we help ensure there’s no possible conflicts with other modules that might want to setup a variable in the general/store_information hierarchy.

Before we continue, reload the page (clearing your Magento cache if needed) and ensure that your new field is showing up.

image of configuration group with fax number

Adding a Backend Model

Now that we have a field setup, lets get to setting up our field validation. We’re going to want to add a <backend_model /> node to our configuration.

<backend_model>alanstormdotcomvalidationexample/fax</backend_model>

The URI like string alanstormdotcomvalidationexample/fax is a standard class alias that will be used to instantiate a model.

//you won't need to call this, but this is what magento will be doing behind the scenes
Mage::getModel('alanstormdotcomvalidationexample/fax');

The above example assumes you’re setup your module config for Models with something like

<models>
    <alanstormdotcomvalidationexample>
        <class>Alanstormdotcom_Validationexample_Model</class>
    </alanstormdotcomvalidationexample>
</models>

If you’re not sure what that means a review may be in order.

So, let’s add the backend model to our system.xml

<alanstormdotcom_validationexample_fax translate="label">
    <!-- NEW --> <backend_model>alanstormdotcomvalidationexample/fax</backend_model> 
    <label>Store Fax Number</label>
    <frontend_type>text</frontend_type>
    <sort_order>20</sort_order>
    <show_in_default>1</show_in_default>
    <show_in_website>1</show_in_website>
    <show_in_store>1</show_in_store>
</alanstormdotcom_validationexample_fax>    

Next, enter a value for our new Store Fax Number field, and attempt to save it. You’ll see an error something like

Warning: include(Alanstormdotcom/Validationexample/Model/Fax.php) [function.include]: failed to open stream: No such file or directory  in /path/to/magento/lib/Varien/Autoload.php on line 93

Magento has taken our class alias and attempted to instantiate it. Not finding a file for the class, PHP complains. We’d better one

#File: app/code/local/Alanstormdotcom/Validationexample/Model/Fax.php
class Alanstormdotcom_Validationexample_Model_Fax extends Mage_Core_Model_Config_Data
{
    //empty for now
}

With that in place, let’s try a reload and/or saving again. The warning that halted execution should be gone, and your value should be properly saved.

Saving Configuration Data

Whenever you save a set of System Configuration options Magento scans the POST variables, and for each configuration field it finds it will instantiate a model object. That means for our configuration group, four objects are instantiated. One for Store Name, one for Store Contact Number, one for Store Contact Address, and finally one for our new Store Fax Number.

If no <backend_model/> value is found, magento will use the Mage_Core_Model_Config_Data class to instantiate the object. This Model knows how to save a configuration value. What we’ve done above is tell Magento to use our class instead of the default Mage_Core_Model_Config_Data class. By extending Mage_Core_Model_Config_Data we ensure that all existing functionality is maintained, and we can add our validation on top. The configuration system actually enforces this class hierarchy. If we attempt to extends from, say, Mage_Core_Model_Abstract

#File: app/code/local/Alanstormdotcom/Validationexample/Model/Fax.php
class Alanstormdotcom_Validationexample_Model_Fax extends Mage_Core_Model_Abstract
{

}

we’ll get an error something like

Invalid config field backend model: alanstormdotcomvalidationexample/fax

Your backend model must have Mage_Core_Model_Config_Data in its inheritance chain.

Creating our Validation

So, we have a backend model. Now we need to add our validation method. The steps we’ll need to take are

  1. Redefine the save method in our class

  2. Add some code to check the value of our class prior to saving

  3. If that value doesn’t resemble a fax number, do something appropriate

  4. Otherwise, call the parent class’s save method

This could look something like the following

#File: app/code/local/Alanstormdotcom/Validationexample/Model/Fax.php
class Alanstormdotcom_Validationexample_Model_Fax extends Mage_Core_Model_Config_Data
{
    public function save()
    {
        $fax = $this->getValue(); //get the value from our config
        $fax = preg_replace('#[^0-9]#','',$fax); //strip non numeric
        if(strlen($fax) < 10)    //exit if we're less than 10 digits long
        {
            exit("Fax Numbers need 10 digits. For American Numbers. Programming examples
            are often horribly US-ethnocentric.");
        }

        return parent::save();     //call original save method so whatever happened 
                                //before still happens (the value saves)
    }
}

With the above code in place, try to save a fax number less than 10 digits long. You should see a white screen with

Fax Numbers need 10 digits. For American Numbers. Programming is horribly ethnocentric sometimes.

If you go back and enter a “proper” fax number, the value will save correctly.

So, we’ve added our validation, and it works. However, it’s not a friendly user error experience. Let’s try changing that exit to the following

Mage::throwException("Fax Numbers need 10 digits. For American Numbers. Programming 
examples are horribly US-ethnocentric sometimes.");            
#exit("Fax Numbers need 10 digits. For American Numbers. Programming is
#horribly ethnocentric sometimes.");

Try saving a bogus fax number now, and you’ll end up with an error message being displayed without stopping execution.

Fax Numbers need 10 digits. For American Numbers. Programming examples are horribly US-ethnocentric sometimes.

The Magento Admin Console application is smart enough to take any Exception throw at this level, and display it back to the end user. This allows you, the end-user-programmer, to not worry about how errors are displayed. Run into a problem, throw an Exception, and be done with it.

Other Messaging Features

If you’ve spent anytime using Magento, you’ve probably seen the red error message box featured above. In fact, you’ve probably seen a green “everything went peachy” message box as well.

All Magento session objects have methods to allow you add these messages to your page. Said more accurately, all Magento session objects have methods that allow you to indicate a message should be sent to the end user, which is subsequently read by the messaging block in the layout, and displayed to the end user. When you throw an exception Magento is adding a message of type error to the session, with code that looks something like this

Mage::getSingleton('adminhtml/session')->addError('This is my error message.  There are many like it, but this one in mine.');

As mentioned, this is a feature shared by all session objects, not just adminhtml/session.

Mage::getSingleton('core/session')->addError('This is my error message.  There are many like it, but this one in mine.');

In addition to errors, there are three other message types you may add: notices, warnings, and successes.

Mage::getSingleton('core/session')->addError('An Error');
Mage::getSingleton('core/session')->addWarning('A Warning'); 
Mage::getSingleton('core/session')->addNotice ('A  Notice');
Mage::getSingleton('core/session')->addSuccess('A Success');    

Less Strict

In our example above we were pretty inflexible about how we handled improperly entered fax numbers. If we wanted to be a little more flexible and encourage a 10 digit fax number rather than require one, we could change our backend model to notify the end-user that something doesn’t look right with their fax number, but allow them to save it anyway.

Let’s do that that by removing our save method, and adding a check in the _afterSave method that will add a notice to request if something looks fishy about the fax number.

#File: app/code/local/Alanstormdotcom/Validationexample/Model/Fax.php
class Alanstormdotcom_Validationexample_Model_Fax extends Mage_Core_Model_Config_Data
{        
    public function _afterSave()
    {
        $fax = $this->getValue(); //get the value from our config
        $fax = preg_replace('[^0-9]','',$fax); //strip non numberic
        if(strlen($fax) < 10)    //exit if we're less than 10 digits long
        {
            Mage::getSingleton('core/session')->addNotice('Fax numbers contains less than 10 digits.  Please check your new value and change if desired.');
        }
        return parent::_afterSave();
    }
}

With the above backend model in place, attempting to save a fax number with less than 10 digits should result in the following messages being displayed to the user.

Wrapup

Error handling is never glamorous. It’s often overlooked or over complicated in PHP frameworks, which leads to a morass of different validation styles and practices across an application. By leveraging Magento’s already powerful Model hierarchy and Session messaging system, not only can you provide a consistent experience for the users of your store, but also provide a consistent data validation pattern for your programming team.

Like this article? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Originally published December 5, 2010