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