Magento开发系列之九 后台开发进阶

前面一节我们讨论了后台系统配置,本节我们将进行更深入的探讨,前面讲到了field内可以用到的一些标签:

<fields>
    <!-- ... --->
    <fieldname translate="label">
        <label>Field Name</label>
        <frontend_type>text</frontend_type>
        <sort_order>2</sort_order>
        <show_in_default>1</show_in_default>
        <show_in_website>1</show_in_website>
        <show_in_store>0</show_in_store>
    </fieldname>
    <!-- ... --->
</fields>

本节将对这些标签进行更深度的剖析,首先查看<label /><comment />标签,<label />标签中的内容将出现在文本框左侧,而<comment />标签则出现在文本框的下方

<fields>
	<demo_text>
		<label>This is a label</label>
		<frontend_type>text</frontend_type>
		<comment>While this is a comment</comment>
		<show_in_default>1</show_in_default>
		<show_in_website>1</show_in_website>
		<show_in_store>1</show_in_store>
	</demo_text>
</fields>

<labe />和<comment />标签

<show_in_default />, <show_in_website />,和<show_in_store />

这几个标签内都使用布尔型的0或1,用于定义在defautl视图、website视图或store视图中是否显示所添加的field。同时通过这一配置也可以控制选项在哪个视图里是可编辑的,比如可以设定在store视图里不可用:

<show_in_store>0</show_in_store>

当然通过编辑还可以在store社图级别设定或获取其中的值,但我们不推荐这么去做。

<sort_order />

<sort_order />中传入的是数值,用于决定在分组中field的排序,数值越大,则会出现在越下面。

<frontend_type />

<frontend_type />用于定义在配置中field的类型,所支持的类型有:

  1. allowspecific
  2. export
  3. image
  4. import
  5. label
  6. multiselect
  7. obscure
  8. password
  9. select
  10. text
  11. textarea
  12. time

这些值会按照工厂模式实例如下格式的类:

Varien_Data_Form_Element_Type

其中的Type对应的就是<frontend_type />中的值,这个动作是在Varien_Data_Form_Abstract(lib/Varien/Data/Form/Abstract.php)类中addField方法内进行的

class Varien_Data_Form_Abstract extends Varien_Object
{
... ...
public function addField($elementId, $type, $config, $after=false)
    {
        if (isset($this->_types[$type])) {
            $className = $this->_types[$type];
        }
        else {
            $className = 'Varien_Data_Form_Element_'.ucfirst(strtolower($type));
        }
        $element = new $className($config);
        $element->setId($elementId);
        $this->addElement($element, $after);
        return $element;
    }
... ...
}

<frontend_class />

<frontend_class />不是一个类群的名称,该标签可用于修改给field生成的表单元素标签的class属性,也就是说可以通过这个配置可以为表单属性添加一个CSS的类。比如:

<frontend_type>select</frontend_type>
<frontend_class>free-method</frontend_class>

会在结果页面变成:

<select class="free-method">

<validate />

<validate />这个标签看上去会让人误解,它只是在标签中添加一个CSS类

<frontend_type>text</frontend_type>
<validate>validate-email</validate>

上述代码会在结果页面变成:

<input class="validate-email">

Magento中还有更多的配置,这个CSS会在客户端触发验证机制,比如上面的代码会调用javascript来对表单的输入内容进行email验证。如果验证失败的话,就无法完成配置表单的提交。可以在以下文件中查看验证规则:

js/prototype/validation.js

email验证规则如下:

['validate-email', 'Please enter a valid email address. For example johndoe@domain.com.', function (v) {
                return Validation.get('IsEmpty').test(v) || /^([a-z0-9,!\#\$%&amp;'\*\+\/=\?\^_<code>\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9,!\#\$%&amp;'\*\+\/=\?\^_</code>\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*@([a-z0-9-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*\.(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]){2,})$/i.test(v)
            }],

这是一条功能很强大的正则表达式。

<can_be_empty />

<can_be_empty />标签针对多选框,也就是在提交时允许不选择任何选项。在设置can_be_empty为真时,实际上是在系统配置页面添加了一个hidden的input标签(文件地址:/lib/Varien/Data/Form/Element/Multiselect.php):

if ($this->getCanBeEmpty() && empty($this->_data['disabled'])) {
	$html .= '<input type="hidden" name="' . parent::getName() . '" value="" />';
}

这样在执行的时候就可以允许不予选择。

<depends />

<depends />标签用于设置仅在本组内其它配置项为指定值时显示某一配置项。比如,PayPal Express系统配置中有有如下的定义:

<specificcountry translate="label">
    <label>Countries Payment Applicable From</label>
    <frontend_type>multiselect</frontend_type>
    <sort_order>110</sort_order>
    <source_model>adminhtml/system_config_source_country</source_model>
    <show_in_default>1</show_in_default>
    <show_in_website>1</show_in_website>
    <show_in_store>0</show_in_store>
    <depends><allowspecific>1</allowspecific></depends>
</specificcountry>

上述代码中有一段

<depends><allowspecific>1</allowspecific></depends>

<allowspecific />在以下代码中定义:

<allowspecific translate="label">
   <label>Payment Applicable From</label>
   <frontend_type>select</frontend_type>
   <sort_order>100</sort_order>    <source_model>adminhtml/system_config_source_payment_allspecificcountries</source_model>
   <show_in_default>1</show_in_default>
   <show_in_website>1</show_in_website>
   <show_in_store>0</show_in_store>
</allowspecific>

如果<allowspecific>选项中的值为1,就会显示<specificcountry>版块,这个是通过后台的JS来即时实现的。虽然所有的表单项都可以使用onchange事件,但在Magento中只针对父级选项是select时才使用这一功能。

<source_model />

<source_model />标签通过以UR/类群名称格式指定模型类来设置field的默认选项,它可以与select和multi-select一起使用。除了标准的类群命名,还可以采用扩展形式:

module/modelname::methodName

系统会使用getModel(‘module/modulename’)来实例化模型,然后调用methodName来获取值-标签对来作为数据源。假如没有添加methodName,默认会调用toOptionArray方法。

<frontend_model />

默认情况下,Magento的表单元素使用Block类来进行处理

Mage_Adminhtml_Block_System_Config_Form_Field

但是如果想要自己指定系统配置选项的处理文件时,可以通过<frontend_model />标签以URI/类群名称的方式来指定另一个block类。比如针对adminnotification组中的<last_update />项可以进行如下配置:

<last_update translate="label">
    <label>Last update</label>
    <frontend_type>label</frontend_type>
    <frontend_model>adminhtml/system_config_form_field_notification</frontend_model>
    <sort_order>3</sort_order>
    <show_in_default>1</show_in_default>
    <show_in_website>0</show_in_website>
    <show_in_store>0</show_in_store>
</last_update>

这里就指定了system_config_form_field_notification来进行处理,对应的类就是app/code/core/Mage/Adminhtml/Block/System/Config/Form/Field/Notification.php文件中的如下类

class Mage_Adminhtml_Block_System_Config_Form_Field_Notification extends Mage_Adminhtml_Block_System_Config_Form_Field
{
    protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
    {
        $element->setValue(Mage::app()->loadCache('admin_notifications_lastcheck'));
        $format = Mage::app()->getLocale()->getDateTimeFormat(Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM);
        return Mage::app()->getLocale()->date(intval($element->getValue()))->toString($format);
    }
}

这里通过重载_getElementHtml方法确保所输入日期会以相同格式进行显示。

<backend_model />

一旦在Magento中进行表单提交,数据就会被存储起来,对于系统配置项,通常是由以下的模型类来进行处理的

 Mage_Core_Model_Config_Data

但在开发中经常会想要使用其它的后台模型,同样地,可以通过<backend_model />标签以URI/类群名称的方式来指定另一个模型类。通常这样做不是因为想要修改数据存储地址,而是想在field保存时进行一些其它的操作。通过自建模型继承Mage_Core_Model_Config_Data类并在模型中定义_beforeSave和_afterSave方法,可以在配置值发生更改时进行其它的操作。

以tablerate组内的import项为例

<import translate="label">
    <label>Import</label>
    <frontend_type>import</frontend_type>
    <backend_model>adminhtml/system_config_backend_shipping_tablerate</backend_model>
    <sort_order>6</sort_order>
    <show_in_default>0</show_in_default>
    <show_in_website>1</show_in_website>
    <show_in_store>0</show_in_store>
</import>

类群名adminhtml/system_config_backend_shipping_tablerate表示app/code/core/Mage/Adminhtml/Model/System/Config/Backend/Shipping/Tablerate.php文件中下面这个类

class Mage_Adminhtml_Model_System_Config_Backend_Shipping_Tablerate extends Mage_Core_Model_Config_Data
{
    public function _afterSave()
    {
        Mage::getResourceModel('shipping/carrier_tablerate')->uploadAndImport($this);
    }
}

这里通过在模型保存后调用的_afterSave方法,将刚刚上传的文件信息来更新shipping/carrier_tablerate模型。

<upload_dir />和<base_url />

这两个标签都用于拥有<backend_model>adminhtml/system_config_backend_image</backend_model>后台模型的<frontend_type>image</frontend_type>项。用于指定上传图片存储地址以及在<img>标签中调取图片基础的网址路径。

我们先来说说<upload_dir />标签

<upload_dir config="system/filesystem/media" scope_info="1">sales/store/logo</upload_dir>

上面的代码指定了三个内容

  1. 上传图片的基本路径
  2. 相对基本路径这个图片项上传的路径
  3. 当前配置域是否添加到路径之中

上传图片基本路径通过config属性指定,即为system/filesystem/media,这个指定的是系统配置路径,也就是说图片上传的路径不是system/filesystem/media,而是安装Magento后系统system/filesystem/media配置值,即{{root_dir}}/media。

一旦找到了上传图片的基本路径,需要在其后添加子目录来指定图片传的地址,这是通过<upload_dir />中的值来指定的,这里是sales/store/logo,添加完成后整个路径即为:

/path/to/magento/install/media/sales/store/logo

如果scope属性值为1,则当前配置域会转变为路径,假设将图片上传到default域中,上传路径即为:

/path/to/magento/install/media/sales/store/logo/default

而如果在某一个store中上传图片的话,就会得到类似下面这样的路径:

/path/to/magento/install/media/sales/store/logo/store/5

在上传图片时,只有路径中的作用域(scope)和图片名称会保存到配置中,也就是说我们需要指定图片的基础url

<base_url type="media" scope_info="1">sales/store/logo</base_url>

scope_info和文本节点与<upload_dir />相同,<base_url />的不同之处在于它设置的是图片网址的基础地址。你可能已经猜到,基础路径通过type属性来进行设置,其值会通过全局Mage对象传入getBaseUrl方法来设定图片的基础路径。上例中如得到如下这样的调用:

Mage::getBaseUrl('media')

实际代码可以查看在app/code/core/Mage/Adminhtml/Block/System/Config/Form/Field/Image.php中的如下类:

class Mage_Adminhtml_Block_System_Config_Form_Field_Image extends Varien_Data_Form_Element_Image
{

    /**
     * Get image preview url
     *
     * @return string
     */
    protected function _getUrl()
    {
        $url = parent::_getUrl();

        $config = $this->getFieldConfig();
        /* @var $config Varien_Simplexml_Element */
        if (!empty($config->base_url)) {
            $el = $config->descend('base_url');
            $urlType = empty($el['type']) ? 'link' : (string)$el['type'];
            $url = Mage::getBaseUrl($urlType) . (string)$config->base_url . '/' . $url;
        }

        return $url;
    }

}

需要注意的是这个基础地址并不是在Magento中各处用于生成配置过图片的完整路径,应该只是作用于后台配置中的图片预览。

 

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.