跳至主要内容
版本:5.1

SQL 表单字段

限制

使用此通用表单字段类型会迫使你在 XML 文件中编写 SQL 语句,而且功能比较受限。为获得更高的灵活性,请考虑通过对 Joomla\CMS\Form\FormField 类进行子类化来创建你自己的特定表单字段类型。

sql 表单字段类型通过运行对 Joomla 数据库的查询提供了一个下拉列表条目的条目。如果该字段有已保存值,则该值会在页面首次加载时予以选中。如果没有,则选中默认值(如果有)。

  • type(必填)必须为 sql
  • name(必填)是该字段的唯一名称。这必须与查询结果中包含要向用户显示在下拉列表中值的那个列的名称相匹配,但 **value_field** 属性中指定了不同的名称除外。
  • label(必填)(可翻译)是该字段的 HTML 标签。
  • query(不使用 sql_* 属性时必填)是对 Joomla 数据库运行查询提供的下拉菜单数据。查询必须返回两列:一列称为 'value'(但 **key_field** 属性另有规定除外),其中会保存列表项的值;另一列与 name 属性值的名称相同(但 **value_field** 属性另有规定除外),其中包含要在下拉列表中显示的文本。
  • default(可选)是默认值。这是 'value' 列的值,但 **key_field** 属性另有规定除外。
  • description(可选)(可翻译的)是字段描述
  • multiple(可选)将该字段变成一个多选器。使用 multiple="multiple"。
  • key_field(可选)是将包含参数值的列的名称。如果省略,则将使用名为'value'的列(如果存在)。
  • value_field(可选)是将包含用户在下拉列表中看到的值的列的名称。如果省略,则将使用与 name 属性同名的列(如果存在)。
  • translate(可选)如果将 value_field 设置为 true,则将翻译输出。其默认值为 false。
  • header(可选)(可翻译的)将在选项列表的顶部添加一个条目,该条目为空值。这通常用于在列表中添加一个“- 选择某项 -”条目。请参阅示例,了解实现此目的的另一种方法。
  • sql_select(如果未使用 query 属性,则为必需的)是 SQL 语句的 SELECT 子句。只允许有一个这样的子句。
  • sql_from(如果未使用 query 属性,则为必需的)是 SQL 语句的 FROM 子句。
  • sql_join(可选)是 SQL 语句的 LEFT JOIN 子句。只允许有一个这样的子句。
  • sql_where(可选)是 SQL 语句的 WHERE 子句。只允许有一个这样的子句。
  • sql_group(可选)是 SQL 语句的 GROUP BY 子句。
  • sql_order(可选)是 SQL 语句的 ORDER BY 子句。
  • sql_filter(可选)按照另一个字段的值过滤该列表。可以给出一个字段名或一个以逗号分隔的字段名列表。这些字段名必须与所查询数据库表中的列名相对应。有关进一步的说明,请参阅示例。
  • sql_default_{FIELD_NAME}(可选)当未设置{FIELD_NAME} 过滤器值时,由 sql_filter 属性使用的默认值。有关进一步的说明,请参阅示例。

通过以下方式实施:libraries/src/Form/Field/SqlField.php

示例 XML 参数定义

<field
name="title"
type="sql"
default="10"
label="Select an article"
query="SELECT id AS value, title AS text FROM #__content"
/>

请注意,在这个示例中已经使用了 AS 子句,因为jos_content 表中没有名为'value'的列。事实上,Joomla 数据库中几乎没有哪张表具有名为'value'的列。

或者,你可以使用 key_field 属性定义要用作'value'的列

<field
name="title"
type="sql"
default="10"
label="Select an article"
query="SELECT id, title FROM #__content"
key_field="id"
/>

这样将会得出与上一个示例相同的结果。

两个列名可能都需要别名为。例如,假设您希望在前面的示例中您的字段被称作 'myfield' 而不是 'title'。那么您可以这样做

<field
name="myfield"
type="sql"
default="10"
label="Select an article"
query="SELECT id AS value, title AS myfield FROM #__content"
/>

或者

<field
name="myfield"
type="sql"
default="10"
label="Select an article"
query="SELECT id, title FROM #__content"
key_field="id"
value_field="title"
/>

您还可以在 SQL 语句中组合或计算字段。例如,假设您希望在列表中为每篇文章附加创建日期/时间。那么您可以使用这个 SQL 语句

SELECT
id,
concat( title, ' (', created, ')') AS title
FROM
#__content

您还可以在 XML 中使用

标签指定一个静态选项。请查看下面的示例。

<field
name="myfield"
type="sql"
default="10"
label="Select an article"
query="SELECT id, title FROM #__content"
key_field="id"
value_field="title"
required="true"
>
<option value="">Please select your option</option>
</field>

或者,您可以使用 header 属性获得相同的结果,如下所示

<field
name="myfield"
type="sql"
default="10"
label="Select an article"
query="SELECT id, title FROM #__content"
key_field="id"
value_field="title"
required="true"
header="Please select your option"
/>

备用查询句法

Joomla 3.5 中引入的query 属性的备用项允许一些附加功能。这些功能在 query 属性存在时不可用。例如,以下字段定义

<field
name="example_group"
type="sql"
label="COM_EXAMPLE_GROUP"
query="SELECT e.* FROM #__example AS e GROUP BY name ORDER e.id ASC"
key_field="id"
value_field="name"
/>

可表示为

<field
name="example_group"
type="sql"
label="COM_EXAMPLE_GROUP"
sql_select="e.*"
sql_from="#__example AS e"
sql_group="name"
sql_order="e.id ASC"
key_field="id"
value_field="name"
/>

链接字段作为过滤器

使用上述备用语法的一个好处是,它允许链接字段用作过滤器。例如,假设您有一个包含两个选择列表的窗体,一个称为,另一个称为子组字段很简单

<field 
name="groups"
type="sql"
label="COM_EXAMPLE_GROUPS"
sql_select="e.*"
sql_from="#__example_groups AS e"
sql_group="name"
sql_order="e.id ASC"
key_field="id"
value_field="name"
/>

子组字段包含一个sql_filter 属性,该属性按名称引用字段

<field 
name="subgroups"
type="sql"
label="COM_EXAMPLE_SUBGROUPS"
sql_select="e.*"
sql_from="#__example_subgroups AS e"
sql_group="name"
sql_order="e.id ASC"
sql_filter="groups"
key_field="id"
value_field="name"
context="sqlfield"
/>

然后,如果字段具有值99,则以下 SQL 语句将针对子组字段执行

SELECT e.*
FROM
jos_example_subgroups AS e
WHERE
`groups` = 99
GROUP BY `name`
ORDER BY e.id ASC

要对多个字段进行筛选,您可以sql_filter 子句中使用筛选器名称的逗号分隔列表。例如,如果有一个名为的筛选器,其值为99,还有一个名为类别的筛选器,其值为12,那么

sql_filter="groups,categories"

将产生 SQL WHERE 子句

WHERE 
`groups` = 99
AND
`categories` = 12

context=... 属性是必需的,如下所述。

您还可以为任何筛选器定义默认值,该筛选器在通过添加sql_default_{FIELD_NAME} 属性评估字段时可能没有值。例如,假设筛选器的默认值为 0,类别筛选器的默认值为 0,那么这个定义

<field 
name="subgroups"
type="sql"
label="COM_EXAMPLE_SUBGROUPS"
sql_select="e.*"
sql_from="#__example_subgroups AS e"
sql_group="name"
sql_order="e.id ASC"
sql_filter="groups,categories"
sql_default_groups="0"
sql_default_categories="1"
key_field="id"
value_field="name"
/>

将在最初评估时不带任何筛选器产生这个 SQL 语句

SELECT
e.*
FROM
jos_example_subgroups AS e
WHERE
`groups` = 0
AND
`categories` = 1
GROUP BY `name`
ORDER BY e.id ASC

注意:SQL 语句必须针对 Joomla 正在运行的底层数据库的类型和版本正确。这很可能是一个 MySQL 版本,但可能也会是其他版本。无法查询 Joomla 自身正在运行的数据库以外的其他数据库。

注意:如这些示例所示,数据库前缀(通常为 jos)应使用 #__(哈希下划线下划线)形式输入。它将自动替换为 Joomla 使用的实际数据库前缀。

链接的字段 - 其他实现细节

了解此功能支持的内容和不支持的内容非常重要。

此外,您需要实现其他代码以使该功能按预期工作。

让我们举一个例子,其中:

  • 链接的筛选器字段是类别字段,
  • SQL 字段显示在类别字段中选定的文章标题。

您希望允许用户选择类别,然后显示具有该类别的文章的标题,以便他/她可以选中文章。

但是,每当用户选择或更改类别时,代码不会自动更新 SQL 字段中的标题集。(没有 Ajax 请求在幕后操作)。此更新功能并非支持功能的一部分。

也就是说,您可以按照以下方法实现更新标题的功能。

要更新 SQL 字段,您需要通过以下方式重新加载表单:

  1. 将当前表单数据发送到服务器(通过提交表单),
  2. 将当前表单数据中的键值传递到 user 状态中,这样 SQL 字段可以拾取它们,并且,
  3. 通过 View 类和 tmpl 文件重新显示表单

要“发送表单数据”,请对类别字段实现 onchange javascript 侦听器,例如,通过在 XML 中设置文件属性

  onchange="categoryReload(this)"

然后实现 javascript categoryReload 函数

reload.js
function categoryReload(element) {
document.body.appendChild(document.createElement('joomla-core-loader'));
Joomla.submitform(`sqlfield.reload`, element.form, false);
}

首先,这将加载 Joomla 旋转徽标(当重新显示表单时,它将消失)。要调用此项,您需要在组件的 joomla.asset.json 文件中将“webcomponent.core-loader”指定为依赖项。

然后提交表单:

  • 将 task 参数设置为 'sqlfield.reload' - 将字符串 'sqlfield' 更改为自己的组件控制器名称
  • 将第三个参数设置为 false 表示在发送 HTTP POST 之前不会执行字段验证

此 POST 请求将路由到您的 SqlfieldController::reload() 方法。

要“通过用户状态传递键值”,您需要调用 setUserState,使用:

  • 您在 SQL 字段中指定为属性的 **内容**
  • POST 参数中的相关数据项

因此,您需要在 SqlfieldController::reload() 方法中包含类似内容

SqlfieldController.php
public function reload($key = null, $urlVar = null)
{
$this->checkToken();

$app = Factory::getApplication();

$data = $this->input->post->get('jform', array(), 'array');

// This is the usual call to set the state for preserving the form data entered by the user
$app->setUserState('com_sqlfield.example', $data);

$catid = filter_var($data['catid'], FILTER_SANITIZE_NUMBER_INT);
// This is the call you need to make to pass the sql_filter ids to the SQL field
// The first parameter must be `'<context>.filter'` where `context` is what you set
// as the context= ... attribute of the SQL field
$app->setUserState('sqlfield.filter', array('catid' => $catid));

// Then re-present the form
}

当您成功接收经过验证的数据时,应清除过滤器状态(与处理表单数据的方式相同),以便下次显示表单时不包含匹配上一次执行表单中的类别的标题,因为这不太可能匹配类别字段中的初始值。

$app->setUserState('sqlfield.filter', null);

要“重新显示表单”,您可以将表单作为 HTTP 响应发送给 HTTP POST 请求

SqlfieldController.php
    $model = $this->getModel('sqlfield');
$view = $this->getView('sqlfield', 'html');
$view->setModel($model, true);

$view->display();

或使用 Post/Request/Get 模式重定向到 DisplayController。

你可以下载 此 com_sqlfield 组件 作为范例(你可能需要更改 sql_default_catid 属性)。安装 com_sqlfield 组件后,你可以通过导航到你的 Joomla 实例的网站页面 index.php/component/sqlfield/ 运行此表单。

另请参阅