2020 年 5 月 12 日星期二
作者:Sandy Galloway

使用 Editor 库进行服务器端处理

随着 SearchPanes 1.1 现在发布并支持服务器端处理,我们认为有必要编写一篇博客文章详细介绍如何在 Editor 库中使用服务器端处理来代替演示服务器端处理脚本。这些库不仅是开源的,而且还支持演示脚本未涵盖的各种功能。

这篇文章将介绍如何在服务器端使用 Editor 库而无需在客户端使用 Editor,并演示它们如何与 SearchPanes 协同工作。需要重复的是 - 你不需要 Editor 许可证就可以使用 Editor 的服务器端库!

使用 Editor 库进行服务器端处理

简介

使用 Editor 库进行服务器端处理有多种优势。

  • 它们是开源的,可以在没有 Editor 的客户端部分(具有商业许可证)的情况下使用
  • 它们支持联接
  • 从 Editor 1.9.3 开始,它们从 SearchPanes 1.1 开始支持 SearchPanes
  • 它们支持 PHP、NodeJS 和 .NET,每个都包含多个不同的数据库
  • 它们可以用作只读
  • 它还具有定义明确且记录良好的 API

虽然 DataTables 示例中使用的 演示服务器端处理 PHP 脚本 有用并有其目的,但 Editor 库要广泛得多,专注于这些库使我们能够提供高质量的代码,我们也可以将其维护到较高的标准。因此,我们没有计划扩展演示服务器端处理脚本以包括对 SearchPanes 的支持。

安装

在客户端设置服务器端处理时,您首先需要做几件事。首先,您必须在服务器端下载 Editor 服务器端库(.NET | NodeJS | PHP)。这些是开源的,可以免费使用。

每个平台都有自己的连接到数据库的配置选项 - 例如,对于 PHP,您可以在 config.php 中配置数据库连接选项。有关完整详细信息,请参阅上面的链接。

编写控制器

PHP

编写控制器非常简单。您首先包含 DataTables PHP 库。

include("../lib/DataTables.php");

然后为 Editor 类创建别名,以便稍后更容易使用它们。首先,我们将考虑一个非常基本的初始化来掌握概念,因此我们只需要使用 2 个类。

use
    DataTables\Editor,
    DataTables\Editor\Field;

接下来是初始化 Editor 类的一个实例,以及我们要使用的字段。fields() 方法可以接受任意数量的字段实例以供定义,也可以多次调用。每个 Field 实例都接受一个表示要从中读取数据的列名称的参数。

Editor::inst( $db, 'datatables_demo' )
    ->field(
        Field::inst( 'first_name' ),
        Field::inst( 'last_name' ),
        Field::inst( 'position' ),
        Field::inst( 'office' ),
        Field::inst( 'extn' ),
        Field::inst( 'start_date' ),
        Field::inst( 'salary' )
    )

然后重要的是禁用 Editor 类中的任何写入功能,因为我们只执行只读操作,而没有 Editor 客户端许可证。这是通过添加以下方法调用来完成的。

    ->write( false )

当 DataTables 和 Editor 向服务器发出请求以获取或更新数据时,它们使用 HTTP 参数发送数据。DataTables 默认使用 GET,而 POST 是 Editor 的默认值 - 在这些示例中,我们将使用 POST 数据。PHP 在其全局 $_POST(或 $_GET,如果您使用的是 GET)变量中提供此信息,该信息可以提供给 Editor 实例进行处理。

然后使用 Editor 类的 process() 方法处理数据,将从客户端发送的数据传递给它。因此,我们现在必须添加以下方法调用。

    ->process( $_POST )

此过程的最后一步是将数据发送回客户端。为了保持简单,我们将使用 Editor 类的 json() 方法。

    ->json();

因此,您的初始化现在应该类似于以下代码。

Editor::inst( $db, 'datatables_demo' )
    ->field(
        Field::inst( 'first_name' ),
        Field::inst( 'last_name' ),
        Field::inst( 'position' ),
        Field::inst( 'office' ),
        Field::inst( 'extn' ),
        Field::inst( 'start_date' ),
        Field::inst( 'salary' )
    )
    ->write( false )
    ->process( $_POST )
    ->json();

将此与库包含和别名结合使用,您将获得一个完整的控制器。

NodeJS

NodeJS 的等效代码如下。

let editor = new Editor(db, 'datatables_demo')
    .fields(
        new Field('first_name'),
        new Field('last_name'),
        new Field('position'),
        new Field('office'),
        new Field('extn'),
        new Field('start_date'),
        new Field('salary'),
    )
    .write(false);

await editor.process(req.body);
res.json(editor.data());

.NET

.NET 的等效代码如下。

var response = new Editor(db, "users")
    .Model<StaffModel>()
    .Field(new Field("first_name"))
    .Field(new Field("last_name"))
    .Field(new Field("position"))
    .Field(new Field("office"))
    .Field(new Field("extn"))
    .Field(new Field("start_date"))
    .Field(new Field("salary"))
    .Process(Request)
    .Data()

return Json(response)

客户端配置

编写一个 DataTable 配置以使用 Editor 服务器端库返回的数据同样简单。从您的基本 DataTables 初始化开始,添加一个 ajax 属性,该属性指向您刚刚使用 ajax.url 属性编写的控制器。ajax.type 属性也必须设置为 POST,这是必需的,因为服务器正在查找 POST 数据。

$('#example').DataTable({
    ajax: {
        url: "../php/exampleController.php",
        type: "POST"
    }
});

接下来是添加 columns 配置。columns 配置选项是一个对象数组 - 每个列一个。在这些对象中的每一个中,我们只需要定义一个属性。columns.data 属性必须设置为数据库中列的名称。您最终应该得到类似以下内容的东西。

$('#example').DataTable({
    ajax: {
        url: "../php/clientSide.php",
        type: "POST"
    },
    columns: [
        { data: "first_name" },
        { data: "last_name" },
        { data: "position" },
        { data: "office" },
        { data: "extn" },
        { data: "start_date" },
        { data: "salary" }
    ]
});

您可能还想使用 数据渲染器 来格式化数据以进行显示(例如数字)。

示例

将所有这些放在一起,我们得到以下 DataTable。

名称 职位 办公室 薪水

联接

当然,Editor 库的一大优势是您可以解锁演示 SSP 类中不可用的大量额外功能。在这里,我将介绍联接,但还有更多选项在 手册 中进行了详细说明。

因此,让我们采用以下客户端配置,并使用 Editor 库来执行联接。

$('#example').DataTable({
    ajax: {
        url: "../php/leftJoinExample.php",
        type: "POST"
    },
    columns: [
        { data: "users.first_name" },
        { data: "users.last_name" },
        { data: "users.phone" },
        { data: "sites.name" }
    ]
});

因此,我们正在从 users 表和 sites 表中获取数据。

PHP

现在,像以前一样创建您的控制器,但在声明 Field 的实例时,我们还必须指定数据所在的位置。

Editor::inst( $db, 'users' )
    ->field( 
        Field::inst( 'users.first_name' ),
        Field::inst( 'users.last_name' ),
        Field::inst( 'users.phone' ),
        Field::inst( 'sites.name' )
    )

然后,我们将添加一个对 leftJoin() 的方法调用来执行联接。这应该放在 field() 方法调用之后,以及 process() 方法调用之前。leftJoin() 方法接受 4 个参数。

  • $table 要联接到的表名
  • $field1 用作联接链接的父表的字段
  • $operator 联接条件(=< 等)
  • $field2 用作联接链接的子表的字段

了解这一点,我们应该最终得到一个看起来像以下内容的方法调用。

    ->leftJoin( 'sites', 'sites.id', '=', 'users.site' )

将此放在 field()process() 方法之间应该给出以下控制器初始化。

Editor::inst( $db, 'users' )
    ->field( 
        Field::inst( 'users.first_name' ),
        Field::inst( 'users.last_name' ),
        Field::inst( 'users.phone' ),
        Field::inst( 'sites.name' )
    )
    ->leftJoin( 'sites', 'sites.id', '=', 'users.site' )
    ->process($_POST)
    ->json();

NodeJS

NodeJS 的等效代码是

let editor = new Editor(db, 'users')
    .fields(
        new Field('users.first_name'),
        new Field('users.last_name'),
        new Field('users.phone'),
        new Field('sites.name')
    )
    .write(false)
    .leftJoin('sites', 'sites.id', '=', 'users.site');

await editor.process(req.body);
res.json(editor.data());

.NET

.NET 的等效代码是

var response = new Editor(db, "users")
    .Model<StaffModel>()
    .Field(new Field("users.first_name"))
    .Field(new Field("users.last_name"))
    .Field(new Field("users.phone"))
    .Field(new Field("sites.name"))
    .Write(False)
    .LeftJoin("sites", "sites.id", "=", "users.site")
    .Process(Request)
    .Data()

return Json(response)

SearchPanes 服务器端处理

由于编写这篇文章的最初原因是 SearchPanes 支持服务器端处理,所以让我们深入探讨一下!

客户端

看看这个客户端配置

$('#example').DataTable( {
    ajax: {
        url: "../php/searchPanes.php",
        type: "POST"
    },
    columns: [
        { data: "users.first_name" },
        { data: "users.last_name" },
        { data: "users.phone" },
        { data: "sites.name" }
    ],
    columnDefs:[{
        searchPanes:{
            show: true,
        },
        targets: '_all',
    }],
    layout: {
        top1: 'searchPanes'
    },
    serverSide: true
} );

这里发生了一些不同的情况,所以让我们来讨论一下。

  • layout 选项设置为确定 SearchPanes 应该放置在页面中的哪个位置,在本例中,它应该直接放置在其他所有内容之上。对于传统的 DataTables 1.x,使用 dom 选项以及 Q 字母来放置 SearchPanes。
  • ajax 选项与我们之前使用它时相同,它指向使用 HTTP POST 的控制器。
  • columns 选项与之前相同,定义用于 DataTable 中每列的数据。
  • columnDefs 选项用于将 columns.searchPanes.show 设置为所有窗格的 true,这意味着它们都将显示。

服务器端

PHP

在控制器文件中,我们希望使用 SearchPaneOptions 类,以及来自库的 EditorField 类,因此我们将其添加到 use 语句中

use
    DataTables\Editor,
    DataTables\Editor\Field,
    DataTables\Editor\SearchPaneOptions;

对于控制器,必须进行一些更改。请考虑以下控制器。

Editor::inst( $db, 'users' )
    ->field(
        Field::inst( 'users.first_name' )
            ->searchPaneOptions( SearchPaneOptions::inst() ),
        Field::inst( 'users.last_name' )
            ->searchPaneOptions( SearchPaneOptions::inst() ),
        Field::inst( 'users.phone' )
            ->searchPaneOptions( SearchPaneOptions::inst()
                ->table( 'users')
                ->value( 'phone' )
            ),
        Field::inst( 'sites.name' )
            ->searchPaneOptions( SearchPaneOptions::inst()
                ->value( 'users.site')
                ->label( 'sites.name' )
                ->leftJoin( 'sites', 'sites.id', '=', 'users.site' )
            )
    )
    ->write(false)
    ->leftJoin( 'sites', 'sites.id', '=', 'users.site' )
    ->process($_POST)
    ->json();

在这里,在每个字段实例上,我们都初始化一个 SearchPaneOptions 类,以指示库确定应该为每列的搜索窗格显示哪些选项。

然后,它可以通过多种不同的方式调用,以确定应该在客户端的窗格中显示哪些选项。最简单的方法是只创建一个没有选项的新 SearchPaneOptions 实例,软件将自动使用字段的名称和表格来确定要从数据库中读取哪些数据。每个库的完整选项集都已记录在案

如果您使用的是自己的服务器端处理脚本,而不是 Editor 库。SearchPanes 文档 详细说明了发送到服务器的参数以及它期望的返回结果。

NodeJS

如果您在 NodeJS 世界中工作,等效代码是

let editor = new Editor(db, 'users')
    .fields(
        new Field('users.first_name')
            .searchPaneOptions(new SearchPaneOptions()),
        new Field('users.last_name')
            .validator(Validate.notEmpty())
            .searchPaneOptions(new SearchPaneOptions()),
        new Field('users.phone')
            .searchPaneOptions(
                new SearchPaneOptions()
                    .table('users')
                    .value('phone')
            ),
        new Field('sites.name')
            .searchPaneOptions(
                new SearchPaneOptions()
                    .value('users.site')
                    .label('sites.name')
                    .leftJoin('sites', 'sites.id', '=', 'users.site')
            )
    )
    .leftJoin('sites', 'sites.id', '=', 'users.site');

await editor.process(req.body);
res.json(editor.data());

.NET

以及 .NET

var response = new Editor(db, "users")
    .Model<UploadManyModel>()
    .Field(new Field("users.first_name")
        .SearchPaneOptions( new SearchPaneOptions() )
    )
    .Field(new Field("users.last_name")
        .SearchPaneOptions( new SearchPaneOptions() )
    )
    .Field(new Field("users.phone")
        .SearchPaneOptions(new SearchPaneOptions()
            .Table("users")
            .Value("phone")
        )
    )
    .Field(new Field("sites.name")
        .SearchPaneOptions(new SearchPaneOptions()
            .Label("sites.name")
            .Value("users.site")
            .LeftJoin("sites", "sites.id", "=", "users.site")
        )
    )
    .LeftJoin("sites", "sites.id", "=", "users.site")
    .Process(Request)
    .Data();

return Json(response);

实际示例

将所有这些放在一起,得到以下表格

电话 网站

反馈

与往常一样,我们热切地希望了解您如何使用 DataTables、Editor 和 SearchPanes。请在 论坛 中给我们留言,告诉我们您对我们软件的使用情况,或者如果您遇到任何问题,或者有任何改进想法。

享受吧!