Joomla field showon属性的进一步说明 原
Joomla的field字段中有一个showon属性,用来设置该字段显示的条件。之前使用这个属性在相同的fields里面,完全没有问题。但如果两个字段在不同的fields里面,需要进行条件控制,此时应该如何做呢?查找了很多的文档,都没有找到答案,最后自己通过分析joomla的源码,找到了解决方案。
问题描述
在开发在线视频教程组件的时候,有这样的一个需求,如果视频为付费,则显示价格字段。如果视频为免费,则显示是否要求注册字段。
实现这个需求在joomla中很简单,只需要使用showon字段就行了。但这次遇到了问题。价格字段可以使用showon控制,但登录观看字段却不行,经过分析师因为登录观看字段在另外的一个fields里面。表单的XML结构如下:
<fieldset label="费用信息" name="price" addfieldpath="administrator/components/com_zmedia/models/fields" > <field name="type" type="zradio" label="付费类型" default="0" class="btn-group btn-group-yesno" description="该课程是收费课程还是免费课程" > <option value="1">付费</option> <option value="0">免费</option> </field> <field name="price" type="ztext" label="价格" showlist="0" default="0.1" showon="type:1" description="如果课程为付费课程,则该课程的价格" > </field> <fields name="params"> <field name="visit_type" type="zradio" class="btn-group-yesno btn-group" label="登录观看" default="0" showlist="0" showon="type:0" description="该课程的观看类型,如何设置为登录观看,那么该课程中的视频都需要登录才能观看。" > <option value="1">JYES</option> <option value="0">JNO</option> </field> <field name="preview" type="zradio" label="允许试看" default="1" showlist="false" class="btn-group btn-group-yesno" description="当你在创建视频的时候设置了试看,那么你可以启用这个" > <option value="1">JYES</option> <option value="0">JNO</option> </field> </fields> </fieldset>
问题如何解决
在所有介绍showon字段的文档中,都是假设字段都在同一个分组中,并没有介绍不在同一分组中的情况。使用chatGPT咨询后,它建议我自己写一个。感觉说了和没说一样。最后我决定分析一下源码。
在网站根目录 \libraries\src\Form\FormHelper.php,期中关于showon的代码部分如下:
public static function parseShowOnConditions($showOn, $formControl = null, $group = null) { // Process the showon data. if (!$showOn) { return array(); } $formPath = $formControl ?: ''; if ($group) { $groups = explode('.', $group); // An empty formControl leads to invalid shown property // Use the 1st part of the group instead to avoid. if (empty($formPath) && isset($groups[0])) { $formPath = $groups[0]; array_shift($groups); } foreach ($groups as $group) { $formPath .= '[' . $group . ']'; } } $showOnData = array(); $showOnParts = preg_split('#(\[AND\]|\[OR\])#', $showOn, -1, PREG_SPLIT_DELIM_CAPTURE); $op = ''; foreach ($showOnParts as $showOnPart) { if (($showOnPart === '[AND]') || $showOnPart === '[OR]') { $op = trim($showOnPart, '[]'); continue; } $compareEqual = strpos($showOnPart, '!:') === false; $showOnPartBlocks = explode(($compareEqual ? ':' : '!:'), $showOnPart, 2); $dotPos = strpos($showOnPartBlocks[0], '.'); if ($dotPos === false) { $field = $formPath ? $formPath . '[' . $showOnPartBlocks[0] . ']' : $showOnPartBlocks[0]; } else { if ($dotPos === 0) { $fieldName = substr($showOnPartBlocks[0], 1); $field = $formControl ? $formControl . '[' . $fieldName . ']' : $fieldName; } else { if ($formControl) { $field = $formControl . ('[' . str_replace('.', '][', $showOnPartBlocks[0]) . ']'); } else { $groupParts = explode('.', $showOnPartBlocks[0]); $field = array_shift($groupParts) . '[' . join('][', $groupParts) . ']'; } } } $showOnData[] = array( 'field' => $field, 'values' => explode(',', $showOnPartBlocks[1]), 'sign' => $compareEqual === true ? '=' : '!=', 'op' => $op, ); if ($op !== '') { $op = ''; } } return $showOnData; }
通过上面的代码,返现实际上传递来的$showon会自动分成两个部分,一个是分组,一个是真正的字段名称。看到这里我有一个大胆的猜想,也许我可以给字段前面加一个点(.),高速系统使用上一个分组。经过测试,发现这个想法完美的实现我的需求。
总结
在showon中,关于条件字段的名称,实际是两部分组件,第一部分是字段分组,第二部分才是字段的名称,如果没有分组,则默认使用当前的分组。如果不使用分组,则在字段的前面加一个点(.).如下:
<field name="visit_type" type="zradio" class="btn-group-yesno btn-group" label="登录观看" default="0" showlist="0" showon=".type:0" description="该课程的观看类型,如何设置为登录观看,那么该课程中的视频都需要登录才能观看。" > <option value="1">JYES</option> <option value="0">JNO</option> </field>
说明
如果在Joomla3上面使用.type的方式没有作用,那么是joomla核心的bug.直接替换文件FormHelper.php。文件路径如下:网站根目录/libraries/src/Form/FormHelper.php
FormHelper.php文件的下载
FormHelper.php