kaizencoders/wp-fluent

一个轻量级、表达式的WordPress数据库查询构建器,也可以称之为数据库抽象层。WP Fluent使用相同的**wpdb**实例,并使用统一的API处理查询清理、表前缀以及其他许多事情。

1.0.0 2021-05-01 21:24 UTC

This package is auto-updated.

Last update: 2024-09-29 05:56:34 UTC


README

一个轻量级、表达式的WordPress数据库查询构建器,也可以称之为数据库抽象层。WP Fluent使用相同的wpdb实例,并使用统一的API处理查询清理、表前缀以及其他许多事情。

它具有一些高级功能,如

  • 查询事件
  • 嵌套条件
  • 子查询
  • 嵌套查询

语法与Laravel的查询构建器非常相似。

示例

// You can use the global wpFluent() function
$user = wpFluent()->table('users')->find(1);

// Or, create a connection using $wpdb, only once.
global $wpdb;
new \WpFluent\Connection($wpdb, ['prefix' => $wpdb->prefix], 'DB');

简单查询

以下查询返回id = 3的行,如果没有行则返回null

$user = DB::table('users')->find(3);

完整查询

$query = DB::table('users')->where('display_name', 'LIKE', '%admin%');

// Get result
$query->get();

查询事件

以下代码之后,每次在posts表上执行选择查询时,都会添加此where条件,因此草稿帖子不会显示。

DB::registerEvent('before-select', 'posts', function ($qb) {
    $qb->where('psot_status', '!=', 'draft');
});

以下有许多高级选项进行了文档说明。准备好了吗?让我们开始安装。

完整使用API

目录

连接

WP Fluent支持多个数据库连接,但您一次只能使用一个别名。只需在连接时传递全局wpdb和必要的配置即可。

// Get the global wpdb instance.
global $wpdb;

new \WpFluent\Connection($wpdb, ['prefix' => $wpdb->prefix], 'DB');

// Run query
$query = DB::table('my_table')->where('name', '=', 'admin');

// Or, simply use the global wpFluent() function.
// It handles all the ncessary initial setup.
wpFluent()->table('my_table')->where('name', '=', 'admin');

别名

当您创建连接时

new \WpFluent\Connection($wpdb, ['prefix' => $wpdb->prefix], 'MyAlias');

MyAlias是要使用的类别名的名称,例如MyAlias::table(...)

您可以使用任何名称(包括命名空间,例如MyNamespace\\MyClass),或者如果您不需要别名,也可以跳过它。别名可以让您轻松地在应用程序中访问QueryBuilder类。

当不使用别名时,您可以单独实例化QueryBuilder处理器,这对于依赖注入和测试非常有帮助。

$connection = new \WpFluent\Connection($wpdb, ['prefix' => $wpdb->prefix]);

$db = new \WpFluent\QueryBuilder\QueryBuilderHandler($connection);

$query = $db->table('my_table')->where('name', '=', 'admin');

var_dump($query->get());

查询

除了原始的query()之外,您必须在每个查询之前使用table()方法。要从多个表中选择,只需传递一个数组。

DB::table(array('mytable1', 'mytable2'));

轻松获取

以下查询返回id = 3的第一行,如果没有行则返回null

$row = DB::table('my_table')->find(3);

可以像这样访问行:echo $row->name。如果您的字段名不是id,则将字段名作为第二个参数传递DB::table('my_table')->find(3, 'person_id');

以下查询返回所有name = 'Frost'的行,如果没有行则返回null

$result = DB::table('my_table')->findAll('name', 'admin');

选择

$query = DB::table('my_table')->select('*');

多选

->select(array('mytable.myfield1', 'mytable.myfield2', 'another_table.myfield3'));

多次使用select方法select('a')->select('b')也会选择ab。如果您想要进行条件选择(在PHP的if中),这可能会很有用。

选择唯一

->selectDistinct(array('mytable.myfield1', 'mytable.myfield2'));

获取全部

返回一个数组。

$query = DB::table('my_table')->where('name', '=', 'admin');
$result = $query->get();

您可以像这样遍历它

foreach ($result as $row) {
    echo $row->name;
}

获取第一行

$query = DB::table('my_table')->where('name', '=', 'admin');
$row = $query->first();

返回第一行,或者如果没有记录则返回null。使用此方法,您还可以确保记录是否存在。可以像这样访问它:$row->name

获取行数

$query = DB::table('my_table')->where('name', '=', 'admin');
$query->count();

where

基本语法是 (字段名, 操作符, 值),如果你提供两个参数,则假定使用 = 操作符。因此,where('name', 'admin')where('name', '=', 'admin') 是相同的。

DB::table('my_table')
    ->where('name', '=', 'admin')
    ->whereNot('age', '>', 25)
    ->orWhere('type', '=', 'admin')
    ->orWhereNot('description', 'LIKE', '%query%');

where in

DB::table('my_table')
    ->whereIn('name', array('rabindranath', 'najrul'))
    ->orWhereIn('name', array('homer', 'frost'));

DB::table('my_table')
    ->whereNotIn('name', array('homer', 'frost'))
    ->orWhereNotIn('name', array('rabindranath', 'najrul'));

where between

DB::table('my_table')
    ->whereBetween('id', 10, 100)
    ->orWhereBetween('status', 5, 8);

where null

DB::table('my_table')
    ->whereNull('modified')
    ->orWhereNull('field2')
    ->whereNotNull('field3')
    ->orWhereNotNull('field4');

分组where

有时查询变得复杂,需要分组条件,例如 WHERE age = 10 and (name like '%frost%' or description LIKE '%najrul%')

WP Fluent 允许你这样做,你可以嵌套任意数量的闭包,如下所示。

DB::table('my_table')
    ->where('my_table.age', 10)
    ->where(function ($q) {
        $q->where('name', 'LIKE', '%najrul%');
        
        // You can provide a closure on these wheres too, to nest further.
        $q->orWhere('description', 'LIKE', '%frost%');
    });

分组by和排序by

$query = DB::table('my_table')->groupBy('age')->orderBy('created_at', 'ASC');

多重分组

->groupBy(array('mytable.myfield1', 'mytable.myfield2', 'another_table.myfield3'));

->orderBy(array('mytable.myfield1', 'mytable.myfield2', 'another_table.myfield3'));

使用 groupBy()orderBy() 方法多次 groupBy('a')->groupBy('b') 也会先按 a 分组,然后按 b 分组。如果你想在 PHP if 中进行条件分组,这很有用。同样适用于 orderBy()

having

->having('total_count', '>', 2)
->orHaving('type', '=', 'admin');

限制和偏移

->limit(30);

->offset(10);

连接

DB::table('my_table')
    ->join('another_table', 'another_table.person_id', '=', 'my_table.id')

可用方法:

  • join() 或 innerJoin
  • leftJoin()
  • rightJoin()

如果你需要 FULL OUTER 连接或任何其他连接,只需将连接作为 join 方法的第五个参数传递。

->join('another_table', 'another_table.person_id', '=', 'my_table.id', 'FULL OUTER')

多个连接条件

如果你需要多个条件来连接一个表,则将闭包作为第二个参数传递。

->join('another_table', function ($table) {
    $table->on('another_table.person_id', '=', 'my_table.id');
    $table->on('another_table.person_id2', '=', 'my_table.id2');
    $table->orOn('another_table.age', '>', DB::raw(1));
})

原始查询

如果你需要,始终可以使用原始查询:

$query = DB::query('select * from cb_my_table where age = 12');

var_dump($query->get());

你也可以传递你的绑定

DB::query('select * from cb_my_table where age = ? and name = ?', array(10, 'najrul'));

原始表达式

当你用 raw() 方法包裹一个表达式时,WP Fluent 不会尝试清理这些内容。

DB::table('my_table')
    ->select(DB::raw('count(cb_my_table.id) as tot'))
    ->where('value', '=', 'Frost')
    ->where(DB::raw('DATE(?)', 'now'))

注意:通过 query() 方法运行的查询直到你通过绑定传递所有值之前都不会清理。通过 raw() 方法运行的查询也不会清理,你必须自己进行清理。当然,这些也不会添加表前缀,但你可以使用 addTablePrefix() 方法。

插入

$data = [
    'name'        => 'Najrul',
    'description' => 'Famous Bengali poet.'
];

$insertId = DB::table('my_table')->insert($data);

insert() 方法返回插入 ID。

批量插入

$data = array(
    [
        'name'        => 'Najrul',
        'description' => 'Famous Bengali poet.'
    ],
    [
        'name'        => 'Rabindranath',
        'description' => 'Nobel winning Bengali poet.'
    ],
);

$insertIds = DB::table('my_table')->insert($data);

在批量插入的情况下,它将返回一个包含插入 ID 的数组。

带有ON DUPLICATE KEY语句的插入

$data = [
    'name'    => 'Najrul',
    'counter' => 1
];

$dataUpdate = [
    'name'    => 'Najrul',
    'counter' => 2
];

$insertId = DB::table('my_table')->onDuplicateKeyUpdate($dataUpdate)->insert($data);

更新

$data = [
    'name'        => 'Najrul',
    'description' => 'Famous Bengali poet.'
];

DB::table('my_table')->where('id', 5)->update($data);

它将 name 字段更新为 Najrul,并将 description 字段更新为 著名的孟加拉诗人。 其中 id = 5

删除

DB::table('my_table')->where('id', '>', 5)->delete();

它将删除所有 id 大于 5 的行。

事务

WP Fluent 具有运行数据库 "事务" 的能力,在这种事务中,所有数据库更改在提交之前都不会保存。这样,如果发生错误或与预期不同,数据库更改将不会保存,也不会进行任何更改。

这是一个基本事务的示例

DB::transaction(function ($qb) {
    $qb->table('my_table')->insert([
        'name' => 'Test',
        'url'  => 'example.com'
    ]);

    $qb->table('my_table')->insert([
        'name' => 'Test2',
        'url'  => 'example.com'
    ]);
});

如果这会导致任何错误(如重复名称或其他此类错误),则两个数据集都不会出现在数据库中。如果没有,更改将成功保存。

如果你希望手动提交或回滚更改,可以使用相应的 commit()rollback() 方法。

DB::transaction(function ($qb) {
    $qb->table('my_table')->insert(array(/* data... */));

    $qb->commit(); // to commit the changes (data would be saved)
    $qb->rollback(); // to rollback the changes (data would be rejected)
});

获取构建的查询

有时你可能需要获取查询字符串,这是可能的。

$query = DB::table('my_table')->where('id', '=', 3);
$queryObj = $query->getQuery();

getQuery() 将返回一个查询对象,你可以从其中获取 SQL、绑定或原始 SQL。

$queryObj->getSql();
// Returns: SELECT * FROM my_table where `id` = ?
$queryObj->getBindings();
// Returns: array(3)
$queryObj->getRawSql();
// Returns: SELECT * FROM my_table where `id` = 3

子查询和嵌套查询

很少,但你可能需要运行子查询或嵌套查询。WP Fluent 足够强大,可以为你做这件事。你可以创建不同的查询对象并使用 DB::subQuery() 方法。

$subQuery = DB::table('person_details')->select('details')->where('person_id', '=', 3);

$query = DB::table('my_table')
            ->select('my_table.*')
            ->select(DB::subQuery($subQuery, 'table_alias1'));

$nestedQuery = DB::table(DB::subQuery($query, 'table_alias2'))->select('*');
$nestedQuery->get();

这将生成如下查询

SELECT * FROM (SELECT `cb_my_table`.*, (SELECT `details` FROM `cb_person_details` WHERE `person_id` = 3) as table_alias1 FROM `cb_my_table`) as table_alias2

注意:WP Fluent 不对子查询和嵌套查询使用绑定。

获取 wpdb 实例

如果你需要获取 wpdb 实例,你可以这样做。

DB::db();

查询事件

WP Fluent 提供强大的查询事件来增强你的应用程序。这些事件类似于数据库触发器,当事件发生时可以执行某些操作。例如,你可以挂钩表的 after-delete 事件并从另一个表中删除相关数据。

可用事件

  • before-select
  • after-select
  • before-insert
  • after-insert
  • before-update
  • after-update
  • before-delete
  • after-delete

注册事件

DB::registerEvent('before-select', 'users', function ($qb) {
    $qb->where('status', '!=', 'banned');
});

现在每次在 users 表上执行选择查询时,都会添加这个 where 条件,这样被禁用的用户就不会获得访问权限。

语法是 registerEvent('事件类型', '表名', 闭包中的操作)

如果你想在 任何表被查询时 执行事件,提供 ':any' 作为表名。

其他示例

在将数据插入到 my_table 后,详情将被插入到另一个表中

DB::registerEvent('after-insert', 'my_table', function ($queryBuilder, $insertId) {
    $data = array('person_id' => $insertId, 'details' => 'Meh', 'age' => 5);
    
    $queryBuilder->table('person_details')->insert($data);
});

每当数据被插入到 person_details 表时,设置时间戳字段 created_at,这样我们就不必在所有地方都指定它

DB::registerEvent('after-insert', 'person_details', function ($queryBuilder, $insertId) {
    $queryBuilder->table('person_details')
                 ->where('id', $insertId)
                 ->update([
                     'created_at' => date('Y-m-d H:i:s')
                 ]);
});

my_table 删除后,删除关系

DB::registerEvent('after-delete', 'my_table', function ($queryBuilder, $queryObject) {
    $bindings = $queryObject->getBindings();
    
    $queryBuilder->table('person_details')->where('person_id', $binding[0])->delete();
});

WP Fluent 将查询构建器的当前实例作为您闭包的第一个参数传递,因此您可以使用此对象构建查询,您可以像通常的查询构建器(DB)一样做任何事情。

如果从 before-* 查询处理程序返回的不是 null,则值将是执行的结果,并且数据库实际上不会被查询(因此,相应的 after-* 处理程序也不会被调用)。

只有在 after-* 事件中您才会得到三个参数:第一个是查询构建器,第三个是执行时间作为浮点数,第二个是变化的。

  • after-select 中,您将得到从 select 获得的结果。
  • after-insert 中,您将得到插入 id(或在批量插入的情况下是 id 的数组)。
  • after-delete 中,您将得到查询对象(与从 getQuery() 获得的对象相同),您可以从其中获取 SQL 和绑定。
  • after-update 中,您将得到类似于 after-delete查询对象

删除事件

DB::removeEvent('event-name', 'table-name');

一些用例

以下是一些查询事件非常有用的案例。

  • 限制被禁用的用户。
  • 只获取 deleted = 0 记录。
  • 实现所有查询的缓存。
  • 在每次条目后触发用户通知。
  • 在删除查询后删除关系数据。
  • 在插入查询后插入关系数据。
  • 在每个更新查询后保留修改记录。
  • 在每个条目后添加/编辑 created_at 和 updated_at 数据。

注意

  • 查询事件是递归的,例如,在向 table_a 插入后,您的事件会插入到 table_b 中,现在您可以在 table_b 上注册另一个事件,该事件会插入到 table_c 中。
  • 当然,查询事件不与原始查询一起工作。
  • 这是从出色的 @usmanhalalit vai 的 Pixie 分支出来,并修改为支持 WordPress。