前面一节我们讨论了后台系统配置,本节我们将进行更深入的探讨,前面讲到了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>
<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的类型,所支持的类型有:
- allowspecific
- export
- image
- import
- label
- multiselect
- obscure
- password
- select
- text
- textarea
- 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,!\#\$%&'\*\+\/=\?\^_<code>\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9,!\#\$%&'\*\+\/=\?\^_</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>
上面的代码指定了三个内容
- 上传图片的基本路径
- 相对基本路径这个图片项上传的路径
- 当前配置域是否添加到路径之中
上传图片基本路径通过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中各处用于生成配置过图片的完整路径,应该只是作用于后台配置中的图片预览。