somnambulist/query-builder

一个面向对象的查询构建器,用于程序化生成SQL查询

0.1.0 2023-04-24 19:17 UTC

This package is auto-updated.

Last update: 2024-09-03 21:52:08 UTC


README

GitHub Actions Build Status Issues License PHP Version Current Version

这是一个用于程序化构建SQL查询的SQL查询构建器实现。主要关注 SELECT 查询,查询构建器提供了一个核心,可以通过事件挂钩或覆盖各种编译器来扩展自定义功能以及针对特定数据库方言的功能。

此库不提供驱动程序实现:它是一个针对特定方言的纯查询构建器/编译器。需要DBAL、Laminas等驱动程序实现。请注意:查询构建器不强制执行数据库服务器之间的可移植性,为某个数据库构建的查询如果在另一个数据库上运行可能不会正常工作。默认支持SQLite、MySQL和Postgres。

此查询构建器源于 Cake软件基金会 的出色工作。有关原始许可协议,请参阅 Cake许可协议

要求

安装

使用composer安装,或从github.com检出/拉取文件。

  • composer require somnambulist/query-builder

使用

配置

在此库可以使用之前,必须使用 TypeCaster 管理器注册一个 TypeCaster。类型转换用于将值转换为适合在查询中使用的数据类型。具体来说:它用于处理在查询编译期间应转换为 Expression 实例的自定义数据类型。

包括了一个Doctrine DBAL转换器(此库旨在与Doctrine DBAL一起使用),允许使用查询构建器和编译器使用DBAL类型。对于其他数据库驱动程序,您需要为该驱动程序实现自己的类型转换器,或提交一个请求以将其添加到项目中。

StringTypeCaster 非常基础,只会将所有内容转换为字符串。或者:注册一个只返回值的匿名类

use Somnambulist\Components\QueryBuilder\TypeCasterManager;

TypeCasterManager::register(new class implements TypeCaster
{
    public function castTo(mixed $value, ?string $type = null): mixed
    {
        return $value;
    }
});

要注册类型转换器,您必须在应用的引导程序中添加

use Somnambulist\Components\QueryBuilder\TypeCasterManager;
use Somnambulist\Components\QueryBuilder\TypeCasters\DbalTypeCaster;

TypeCasterManager::register(new DbalTypeCaster());

要编译查询,编译器必须进行配置。有关详细信息,请参阅 编译器设置

查询

可以使用此库创建 SELECTINSERTUPDATEDELETE 查询。每个查询都由 Query\Type 命名空间中的查询类表示,例如 SelectQuery。通过添加通过可用方法提供的对象表示来构建查询。并非所有方法或函数都适用于每种查询类型。您必须事先知道您针对的是哪种方言。

构建器和编译器不会对您创建的查询是否有效进行检查。不能保证任何特定的组合都适用于任何数据库。您必须编译并针对您选择的数据库运行查询,以避免问题。

包括了一些辅助函数,以使创建查询更加方便。例如

use Somnambulist\Components\QueryBuilder\Query\OrderDirection;
use function Somnambulist\Components\QueryBuilder\Resources\expr;
use function Somnambulist\Components\QueryBuilder\Resources\select;

$qb = select(['a.id', 'a.title', 'a.summary', 'a.published_at'])
    ->from('articles', 'a')
    ->where(expr()->isNotNull('a.published_at'))
    ->orderBy('a.published_at', OrderDirection::DESC)
;

// or

$qb = select(
        fields: ['id', 'title', 'summary', 'published_at'],
        from: 'articles'
    )
    ->where(expr()->isNotNull('published_at'))
    ->orderBy('published_at', OrderDirection::DESC)
;

请参阅查询构建器以获取查询构建器使用详情。

编译查询

查询对象必须编译成SQL语句才能执行。编译器必须针对特定数据库进行配置。有关详细信息,请参阅查询编译器和示例。

可执行查询

作为实验,包含了一个使查询对象自我执行的示例。这是通过扩展单独的查询对象以包含一个execute()方法来实现的。然后通过适配器(包括Doctrine DBAL和PDO)实例化,该适配器自动注入连接。适配器包含连接和编译器实例,允许通过连接编译和运行查询对象。

例如

use PDO;
use Somnambulist\Components\QueryBuilder\Compiler\Dialects\Sqlite\CompilerConfigurator;
use Somnambulist\Components\QueryBuilder\Executors\Adapters\PdoAdapter;

$adapter = new PdoAdapter(
    $conn = new PDO('sqlite::memory:'),
    (new CompilerConfigurator())->configure(),
);

$conn->exec('create table users (id integer, name varchar(100))');
$conn->exec('insert into users values (1, \'bob\'), (2, \'fred\')');

$results = $adapter->select('*')->from('users')->execute();
/**
 * $results = [
 *     [id => 1, name => bob],
 *     [id => 2, name => fred],
 * ]
 */

注意:这是一个实验性添加,可能在未来的更新中删除。

扩展

可以通过替换类、组件或将钩子挂接到编译器的事件系统来轻松扩展查询和编译器。

例如:为了添加特定数据库功能的支持,您可能需要添加一个特定于该功能的表达式和一个处理它的编译器,或者您可能扩展现有功能以涵盖所有方面,然后处理细节。

在更复杂的案例中,其中需要查询本身作为参考,则必须使用事件系统。在以下事件中引发事件:

  • 选择、插入、更新、删除查询的前/后
  • 选择、from、where、having、order、group、with、modifier、epilog、insert、update、delete、comment的前/后

注意,单个表达式编译器不会触发事件。

在事件的后半部分,提供了生成的SQL,并且监听器可以根据需要对其进行修订。对于前半部分,可以通过提供编译后的SQL来提前终止执行流程。这在需要更改特定SQL方言的主要部分时很有用,例如:Postgres的HAVING无法与别名字段一起使用。监听器将这些内容转换为预构建的SQL,避免进一步处理的需要。

如果您针对每个事件有多个监听器,那么您应该考虑使用事件分派器来设置优先级以避免冲突,或者确保监听器按正确顺序注册。

一个用例是添加一个Pre*QueryCompile监听器来检查特定方言的函数使用情况并确保在事先检测到无效或不支持的类型。另一个用例可能是添加智能连接功能,其中使用单独的模式对象自动基于别名等解析连接。

测试

使用PHPUnit 10+进行测试。通过vendor/bin/phpunit运行测试。