bentools/where

PHP7.1 流式、不可变 SQL 查询构建器。无连接、无框架依赖、无依赖。

1.4 2019-07-22 10:50 UTC

This package is auto-updated.

Last update: 2024-09-22 22:32:45 UTC


README

Latest Stable Version License Build Status Coverage Status Quality Score Total Downloads

Where

最简单的流式 SQL 查询构建器。

在 PHP7.1 中构建,注重不可变性。

功能

  • 无框架依赖,无连接依赖(你只需渲染一个字符串和一个值数组)
  • 自然语言:where,and,or,...
  • 支持命名和数字占位符
  • 构建复杂、嵌套的 WHERE 条件
  • 构建 SELECTINSERTUPDATEDELETEREPLACE 查询的辅助函数
  • 构建 SQL 函数的辅助函数,如 INBETWEENIS NULLCASE ... WHEN

为什么?

在大多数情况下,简单的 SQL 查询就足够了。

但如果你的应用程序逻辑设计成几个类/方法可以修改 SQL 查询(如访问者模式),那么你可能需要查询构建器(例如,您可以在 WHERE 之前定义 LIMIT / OFFSET,查询将按正确的顺序渲染)。

条件构建器

Where 允许您使用 表达式 构建条件。 表达式 是可以

  • 简单表达式:date_added = CURRENT_DATE
  • 复合表达式:date_added = CURRENT_DATE OR date_added = SUBDATE(CURRENT_DATE, INTERVAL 1 DAY)
  • 分组表达式:(country = 'UK' OR country = 'BE')
  • 否定表达式:NOT date_added = CURRENT_DATE

一个 表达式 对象也可以包含一个参数数组来绑定(以避免 SQL 注入)。

您不需要实例化它们。只需依靠库提供的强大功能即可

require_once __DIR__ . '/vendor/autoload.php';

use function BenTools\Where\group;
use function BenTools\Where\not;
use function BenTools\Where\where;

$where = where('country IN (?, ?)', ['FRA', 'UK'])
    ->and(
        not(
            group(
                where('continent = ?', 'Europe')
                    ->or('population < ?', 100000)
            )
        )
    );

print((string) $where);
print_r($where->getValues());
print_r($where->preview());  // For debugging purposes

输出

country IN (?, ?) AND NOT (continent = ? OR population < ?)
Array
(
    [0] => FRA
    [1] => UK
    [2] => Europe
    [3] => 100000
)
country IN ('FRA', 'UK') AND NOT (continent = 'Europe' OR population < 100000)

每个函数 where()group()not() 都接受一个已实例化的 Expression 对象、一个字符串和一些可选参数。

$where = where('date > NOW()'); // valid
$where = where($where); // valid
$where = where(group($where)); // valid
$where = where(not($where)); // valid
$where = where('date = ?', date('Y-m-d')); // valid
$where = where('date BETWEEN ? AND ?', date('Y-m-d'), date('Y-m-d')); // valid
$where = where('date BETWEEN ? AND ?', [date('Y-m-d'), date('Y-m-d')]); // valid
$where = where('date BETWEEN :start AND :end', ['start' => date('Y-m-d'), 'end' => date('Y-m-d')]); // valid
$where = where('date BETWEEN :start AND :end', ['start' => date('Y-m-d')], ['end' => date('Y-m-d')]); // not valid
$where = where($where, date('Y-m-d'), date('Y-m-d')); // not valid (parameters already bound)

感谢流畅的接口,让您的 IDE 帮助您完成剩余部分。别忘了 Where 总是不可变的:每次您进行更改时都要重新分配 $where

选择查询构建器

现在您已经学会了如何构建条件,您将看到构建整个选择查询是多么容易

require_once __DIR__ . '/vendor/autoload.php';

use function BenTools\Where\group;
use function BenTools\Where\not;
use function BenTools\Where\select;
use function BenTools\Where\where;

$select = select('b.id', 'b.name  AS book_name', 'a.name AS author_name')
    ->from('books as b')
    ->innerJoin('authors as a', 'a.id = b.author_id')
    ->limit(10)
    ->orderBy('YEAR(b.published_at) DESC', 'MONTH(b.published_at) DESC', 'b.name')
    ->where(
        group(
            where('b.series = ?', 'Harry Potter')->or('b.series IN (?, ?)', ['A Song of Ice and Fire', 'Game of Thrones'])
        )
            ->and('b.published_at >= ?', new \DateTime('2010-01-01'))
        ->and(
            not('b.reviewed_at BETWEEN ? AND ?', new \DateTime('2016-01-01'), new \DateTime('2016-01-31 23:59:59'))
        )
    );
print_r((string) $select); // The SQL string
print_r($select->preview()); // For debugging purposes
SELECT b.id, b.name  AS book_name, a.name AS author_name 
FROM books as b 
INNER JOIN authors as a ON a.id = b.author_id 
WHERE (b.series = ? OR b.series IN (?, ?)) 
AND b.published_at >= ? 
AND NOT b.reviewed_at BETWEEN ? AND ? 
ORDER BY YEAR(b.published_at) DESC, MONTH(b.published_at) DESC, b.name 
LIMIT 10;
SELECT b.id, b.name  AS book_name, a.name AS author_name 
FROM books as b 
INNER JOIN authors as a ON a.id = b.author_id 
WHERE (b.series = 'Harry Potter' OR b.series IN ('A Song of Ice and Fire', 'Game of Thrones')) 
AND b.published_at >= '2010-01-01 00:00:00' 
AND NOT b.reviewed_at BETWEEN '2016-01-01 00:00:00' AND '2016-01-31 23:59:59' 
ORDER BY YEAR(b.published_at) DESC, MONTH(b.published_at) DESC, b.name 
LIMIT 10;

让您的 IDE 使用自动完成完成剩余部分。

RulerZ

Where 主要与出色的 RulerZ DSL 兼容。

请确保对您的语句进行 group 以避免副作用。

示例

use function BenTools\Where\group;
use function BenTools\Where\not;

$fruits = [
    'banana',
    'apple',
];

$colors = [
    'yellow',
    'red',
];

$condition = group('fruit IN :fruits', ['fruits' => $fruits])->and(group('color IN :colors', ['colors' => $colors]));
$condition = not($condition);

var_dump($rulerz->satisfies(['fruit' => 'strawberry', 'color' => 'red'], (string) $condition, $condition->getValues())); // true
var_dump($rulerz->satisfies(['fruit' => 'apple', 'color' => 'yellow'], (string) $condition, $condition->getValues())); // false

安装

composer require bentools/where

测试

./vendor/bin/phpunit

另请参阅

bentools/simple-dbal - 一个 PHP 7.1+ 的 PDO & Mysqli 包装器。可以绑定 DateTime 参数。

bentools/pager - 一个 PHP 7.1+ 分页器。

bentools/flatten-iterator - 将多个 arrayTraversable 转换为一个迭代器。

bentools/etl - 一个 PHP7.1 ETL 模式实现。

latitude/latitude - 另一个 SQL 查询构建器 Where 受其启发。