Question

I want to create an admin config with "exception dates".

Since the number of these dates can vary, I cannot just put a constant number of input fields in the config.

Is there a way to automatically add more fields or have a button to add extra fields? Then perhaps collecting the values into an array...

Was it helpful?

Solution

To add an "Add field" button to you config field, you can use this:

app/code/POOL/My/Module/etc/system.xml

<delay_by_country translate="label">
    <label>Email delay per country</label>
    <frontend_model>mx_custom_emails/adminhtml_config_countryDays</frontend_model>
    <backend_model>adminhtml/system_config_backend_serialized_array</backend_model>
    <sort_order>110</sort_order>
    <show_in_default>1</show_in_default>
    <show_in_website>1</show_in_website>
    <show_in_store>0</show_in_store>
    <depends><enabled>1</enabled></depends>
</delay_by_country>

See <frontend_model> and <backend_model>. Frontend model is responsable for you system config output and backend model adminhtml/system_config_backend_serialized_array to store data as serialized array.

For set frontend model you have to create an new block class to generate the field form.

app\code\local\Mx\CustomEmails\Block\Adminhtml\Config\CountryDays.php

class Mx_CustomEmails_Block_Adminhtml_Config_CountryDays extends Mage_Adminhtml_Block_System_Config_Form_Field_Array_Abstract
{
    protected $_itemRenderer;

    /**
     * Fix for ignored "depends enabled"
     * See: https://magento.stackexchange.com/questions/15500/configuration-depends-with-front-and-backend-model
     */
    public function _toHtml()
    {
        return '<div id="' . $this->getElement()->getId(). '">' . parent::_toHtml() . '</div>';
    }

    public function _prepareToRender()
    {
        $this->addColumn('country_id', array(
            'label' => Mage::helper('mx_custom_emails')->__('Country'),
            'renderer' => $this->_getRenderer(),
        ));
        $this->addColumn('email_delay', array(
            'label' => Mage::helper('mx_custom_emails')->__('Email Delay in Days'),
            'style' => 'width:100px',
            'class' => 'validate-zero-or-greater input-text',
        ));

        $this->_addAfter = false;
        $this->_addButtonLabel = Mage::helper('mx_custom_emails')->__('Add');
    }

    protected function _getRenderer()
    {
        if (!$this->_itemRenderer) {
            $this->_itemRenderer = $this->getLayout()->createBlock(
                'mx_custom_emails/adminhtml_config_form_field_country',
                '',
                array('is_render_to_js_template' => true)
            );
        }
        return $this->_itemRenderer;
    }

    protected function _prepareArrayRow(Varien_Object $row)
    {
        $row->setData(
            'option_extra_attr_' . $this->_getRenderer()
                ->calcOptionHash($row->getData('country_id')),
            'selected="selected"'
        );
    }
}

Within the _getRenderer() method you define another block class that's responable for rendering a column (in my case a dropdown for all countries)

app\code\local\Mx\CustomEmails\Block\Adminhtml\Config\Form\Field\Country.php

class Mx_CustomEmails_Block_Adminhtml_Config_Form_Field_Country extends Mage_Core_Block_Html_Select
{
    /**
     * Prepare HTML output
     *
     * @return Mage_Core_Block_Html_Select
     */
    public function _toHtml()
    {
        $options = Mage::getSingleton('adminhtml/system_config_source_country')
            ->toOptionArray();
        foreach ($options as $option) {
            $this->addOption($option['value'], $option['label']);
        }

        return parent::_toHtml();
    }

    /**
     * Set field name
     *
     * @param string $value
     */
    public function setInputName($value)
    {
        return $this->setName($value);
    }
}

To access the serialized config data you can do this (just as example from an observer, you have to replace config path and add your logic):

$delay = Mage::getStoreConfig('sales_email/mx_custom_emails/delay_by_country');
# important line
$delay = unserialize($delay);
if (is_array($delay) || sizeof($delay)) {
    $shippingAddressCountryId = $order->getShippingAddress()->getCountryId();
    # important lines
    foreach ($delay as $row) {
        if ($shippingAddressCountryId == $row['country_id']) {
            return $row['email_delay'];
        }
    }
}

Finally cou have to create your modules XML file and a config.xml where you define helper (for translation), block and model classes:

app/code/POOL/My/Module/etc/config.xml

<blocks>
    <mx_custom_emails>
        <class>Mx_CustomEmails_Block</class>
    </mx_custom_emails>
</blocks>
<helpers>
    <mx_custom_emails>
        <class>Mx_CustomEmails_Helper</class>
    </mx_custom_emails>
</helpers>
<models>
    <mx_custom_emails>
        <class>Mx_CustomEmails_Model</class>
    </mx_custom_emails>
</models>

You can also create fields/groups and sections dynamically ... therefor i recommend reading Create system config section with dynamic number of fields @ Marius blog.

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top