前面一节我们讨论了后台系统配置,本节我们将进行更深入的探讨,前面讲到了field内可以用到的一些标签:
1 2 3 4 5 6 7 8 9 10 11 12 | <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 />标签则出现在文本框的下方
1 2 3 4 5 6 7 8 9 10 | <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视图里不可用:
1 | <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
这些值会按照工厂模式实例如下格式的类:
1 | Varien_Data_Form_Element_Type |
其中的Type对应的就是<frontend_type />中的值,这个动作是在Varien_Data_Form_Abstract(lib/Varien/Data/Form/Abstract.php)类中addField方法内进行的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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的类。比如:
1 2 | <frontend_type>select</frontend_type> <frontend_class>free-method</frontend_class> |
会在结果页面变成:
1 | <select class = "free-method" > |
<validate />
<validate />这个标签看上去会让人误解,它只是在标签中添加一个CSS类
1 2 | <frontend_type>text</frontend_type> <validate>validate-email</validate> |
上述代码会在结果页面变成:
1 | <input class = "validate-email" > |
Magento中还有更多的配置,这个CSS会在客户端触发验证机制,比如上面的代码会调用javascript来对表单的输入内容进行email验证。如果验证失败的话,就无法完成配置表单的提交。可以在以下文件中查看验证规则:
1 | js/prototype/validation.js |
email验证规则如下:
1 2 3 | [ '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):
1 2 3 | if ( $this ->getCanBeEmpty() && empty ( $this ->_data[ 'disabled' ])) { $html .= '<input type="hidden" name="' . parent::getName() . '" value="" />' ; } |
这样在执行的时候就可以允许不予选择。
<depends />
<depends />标签用于设置仅在本组内其它配置项为指定值时显示某一配置项。比如,PayPal Express系统配置中有有如下的定义:
1 2 3 4 5 6 7 8 9 10 | <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> |
上述代码中有一段
1 | <depends><allowspecific>1</allowspecific></depends> |
<allowspecific />在以下代码中定义:
1 2 3 4 5 6 7 8 | <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一起使用。除了标准的类群命名,还可以采用扩展形式:
1 | module/modelname::methodName |
系统会使用getModel(‘module/modulename’)来实例化模型,然后调用methodName来获取值-标签对来作为数据源。假如没有添加methodName,默认会调用toOptionArray方法。
<frontend_model />
默认情况下,Magento的表单元素使用Block类来进行处理
1 | Mage_Adminhtml_Block_System_Config_Form_Field |
但是如果想要自己指定系统配置选项的处理文件时,可以通过<frontend_model />标签以URI/类群名称的方式来指定另一个block类。比如针对adminnotification组中的<last_update />项可以进行如下配置:
1 2 3 4 5 6 7 8 9 | <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文件中的如下类
1 2 3 4 5 6 7 8 9 | 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中进行表单提交,数据就会被存储起来,对于系统配置项,通常是由以下的模型类来进行处理的
1 | Mage_Core_Model_Config_Data |
但在开发中经常会想要使用其它的后台模型,同样地,可以通过<backend_model />标签以URI/类群名称的方式来指定另一个模型类。通常这样做不是因为想要修改数据存储地址,而是想在field保存时进行一些其它的操作。通过自建模型继承Mage_Core_Model_Config_Data类并在模型中定义_beforeSave和_afterSave方法,可以在配置值发生更改时进行其它的操作。
以tablerate组内的import项为例
1 2 3 4 5 6 7 8 9 | <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文件中下面这个类
1 2 3 4 5 6 7 | 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 />标签
1 | <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,添加完成后整个路径即为:
1 | /path/to/magento/install/media/sales/store/logo |
如果scope属性值为1,则当前配置域会转变为路径,假设将图片上传到default域中,上传路径即为:
1 | /path/to/magento/install/media/sales/store/logo/ default |
而如果在某一个store中上传图片的话,就会得到类似下面这样的路径:
1 | /path/to/magento/install/media/sales/store/logo/store/5 |
在上传图片时,只有路径中的作用域(scope)和图片名称会保存到配置中,也就是说我们需要指定图片的基础url
1 | <base_url type= "media" scope_info= "1" >sales/store/logo</base_url> |
scope_info和文本节点与<upload_dir />相同,<base_url />的不同之处在于它设置的是图片网址的基础地址。你可能已经猜到,基础路径通过type属性来进行设置,其值会通过全局Mage对象传入getBaseUrl方法来设定图片的基础路径。上例中如得到如下这样的调用:
1 | Mage::getBaseUrl( 'media' ) |
实际代码可以查看在app/code/core/Mage/Adminhtml/Block/System/Config/Form/Field/Image.php中的如下类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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中各处用于生成配置过图片的完整路径,应该只是作用于后台配置中的图片预览。