chh/sirel

灵活的SQL构建器,构建SQL的抽象语法树并将其导出。

dev-master / 1.0.x-dev 2014-03-15 20:59 UTC

This package is not auto-updated.

Last update: 2024-09-14 12:21:06 UTC


README

Sirel是PHP中SQL抽象语法树的表示。

Sirel的目标是成为PHP版的Arel(Ruby中的Arel)。

安装

要求

  • PHP 5.4
  • 可选:为更广泛的数据库支持,安装 doctrine/dbal

使用Composer安装

php composer.phar require 'chh/sirel:1.0.*@dev'

然后在您的应用程序中引入vendor/autoload.php

Sirel正处于积极开发中,因此以下缺点和错误仍需解决。

  • 仅与SQLite进行测试,大多数其他数据库管理系统实现的是SQLite SQL的超集,因此也可能与MySQL兼容。
  • 生成特定数据库管理系统的SQL(可能作为启用Doctrine DBAL的访问者出现)
  • 仅支持DML(如果您想运行数据库无关的DDL,请使用Doctrine DBAL

现在让我们从一个宏观的角度来看一下这些功能。

常见问题解答

我如何在使用Sirel时保护自己免受SQL注入攻击?

我建议使用预处理语句。请确保使用Sirel::sql()将占位符标记为原始SQL。

使用PDO的示例

<?php

use Sirel\Sirel;
use Sirel\Table;

$users = $u = new Table("users");
$select = $users->take(1)->where($u->id->eq(Sirel::sql(':id')));

$connSpec = "";
$pdo = new \PDO($connSpec);

$stmt = $pdo->prepare($select->toSql());
$stmt->bindParam(':id', $_GET['id']);
$stmt->execute();

$user = $stmt->fetch();

关系

Sirel查询构建API的核心是。表对象提供了对属性和查询工厂方法的方便访问。

您可以在表实例上调用这些方法以开始构建新查询

  • 使用fromprojectjoinwhereordergrouptakeskip开始构建一个选择查询
  • 使用insert开始构建一个插入查询
  • 使用update开始构建一个更新查询
  • 使用delete开始构建一个删除查询

构造函数接受一个参数:表名。

<?php
use Sirel\Table;

$users = new Table("users");

表实例还可以像数组一样访问,以获取属性实例。如果没有定义属性,则返回一个新的Sirel\Attribute\Attribute实例。

<?php
...
echo $users['username'];
// -> users.username

// If you don't like accessing arrays:
assert($users['username'] === $users->username);

连接

连接看起来与SQL类似。连接由join运算符开始。然后使用对on的下一个调用设置连接的ON表达式。对on的调用期望一个或多个表达式。

示例

<?php
use Sirel\Table;

$profiles = new Table("profiles");

echo $profiles->join($users)->on($profiles['user_id']->eq($users['id']));
// -> SELECT * FROM profiles INNER JOIN users ON profiles.user_id = users.id

可以使用leftJoin运算符创建左连接。

示例

<?php
use Sirel\Table;

$profiles = new Table("profiles");

echo $profiles->leftJoin($users)->on($profiles['user_id']->eq($users['id']));
// -> SELECT * FROM profiles LEFT JOIN users ON profiles.user_id = users.id

选择

在Sirel中使用where运算符进行选择。该运算符接受一个或多个作为参数的表达式,这些表达式可以通过属性创建。然后使用“AND”运算符将这些表达式连接起来。

通过在属性上调用相应的方法创建限制。以下限制被支持(每个都与它们的SQL等效项相对应)

  • eq
  • notEq
  • gt
  • gte
  • lt
  • lte
  • like
  • notLike
  • in
  • notIn

示例

<?php
use Sirel\Table;

$users = new Table("users");

echo $users->where($users['username']->eq("johnny"), $users['password']->eq('superSecretPass'));
// -> SELECT * FROM users WHERE users.username = 'johnny' AND users.password = 'superSecretPass'

echo $users->where($users['username']->like('a%'));
// -> SELECT * FROM users WHERE users.username LIKE 'a%'

echo $users->where($users['id']->in([3, 4, 10]));
// -> SELECT * FROM users WHERE users.id IN (3, 4, 10)

排序

使用order运算符进行排序。它接收一个排序表达式或一个属性名和方向的组合(\Sirel\Node\Order::ASC\Sirel\Node\Order::DESC)。此外,属性实例还提供了ascdesc方法来创建排序表达式。

<?php
...
echo $users->order($users['username']->asc());
// -> SELECT * FROM users ORDER BY users.username ASC

echo $users->order($users['username']->desc());
// -> SELECT * FROM users ORDER BY users.username DESC

echo $users->order($users['username'], \Sirel\Node\Order::DESC);
// -> SELECT * FROM users ORDER BY users.username DESC

使用reorder清除所有当前排序操作

<?php

$select = $users->order($users->username->asc())->order($users->id->asc());

// Now let's reorder:
echo $select->reorder($users->id->desc());
// -> SELECT * FROM users ORDER BY users.id DESC;

您可以使用 ->reverseOrder() 方法来反转现有顺序。

<?php

$select = $users->order($users->username->asc());

echo $select->reverseOrder();
// -> SELECT * FROM users ORDER BY users.username DESC;

通过向 ->reverseOrder() 方法传递属性列表,您可以仅反转某些属性的顺序。

<?php

$select = $users->order($users->username->asc())->order($users->id->desc());

echo $select->reverseOrder([$users->id]);
// -> SELECT * FROM users ORDER BY users.username ASC, users.id ASC;

限制 & 偏移

限制和偏移对应于 takeskip 操作符。这些操作符将行数作为唯一参数。

<?php
...
echo $users->take(5);
// -> SELECT * FROM users LIMIT 5

echo $users->skip(4);
// -> SELECT * FROM users OFFSET 4

唯一

'distinct' 操作符用于 SELECT DISTINCT 查询。

<?php
echo $users->project($users['id'])->distinct();
// -> SELECT DISTINCT id FROM users;

链式调用

使用查询构建器的最大好处是查询的可组合性。因此,对管理器方法的调用不受任何顺序的限制,可以无限地链式调用。

例如

<?php
...
$query = $users->project($users['id']);

$query->take(1)->where($users['username']->eq("johnny"))->where($users['password']->eq('foo'));

$query->project($users['username']);

echo $query;
// -> SELECT users.id, users.username FROM users WHERE users.username = 'johnny' AND users.password = 'foo' LIMIT 1

插入

通过在表上调用 ->insert() 或构造一个新的 Sirel\InsertManager 来获取插入查询管理器。

<?php

$insert = $users->insert();
// is equivalent to
$insert = new Sirel\InsertManager;
$insert->into($users);

您可以使用 ->values() 方法设置列值对列表。

<?php

$insert->values([
    'username' => 'jon',
    'first_name' => 'John',
    'last_name' => 'Doe'
]);

echo $insert->toSql();
// -> INSERT INTO users (users.username, users.first_name, users.last_name) VALUES ('jon', 'John', 'Doe');

更新

可以通过表上的 ->update() 方法创建更新查询。可以使用 ->set() 方法设置值。

更新查询具有与选择查询大多数相同的方法,它们的工作方式与它们的选择对应物相同。

  • where
  • take
  • skip
  • order

注意:如果您创建了一个 Sirel\UpdateManager 实例,您需要使用 ->table() 方法设置表。

<?php

$update = $users->update();
$update->where($users->id->eq(1))->set('last_name' => 'Foobar');

echo $update->toSql();
// -> UPDATE users SET users.last_name = 'Foobar' WHERE users.id = '1';

您还可以使用 ->compileUpdate() 从现有的选择查询编译一个更新查询。

<?php

$select = $users->where($users->first_name->eq("James"))
    ->where($users->last_name->eq("Kirk"))
    ->take(1);

$update = $select->compileUpdate()->set(['first_name' => 'Jim']);

echo $update->toSql();
// -> UPDATE users SET users.first_name = 'Jim' WHERE users.first_name = 'James' AND users.last_name = 'Kirk' LIMIT 1;

删除

可以通过调用表的 ->delete() 方法创建删除查询。

删除查询理解这些操作,它们的工作方式与选择查询的对应物完全相同。

  • from
  • where
  • take
  • skip
  • order
<?php

$delete = $users->delete()
    ->take(1)
    ->where($users->id->eq(1));

echo $delete->toSql();
// -> DELETE FROM users WHERE users.id = '1' LIMIT 1;

您还可以将现有的选择查询编译为删除查询。

<?php

$select = $users->where($users->activated->eq(0))->take(10);

$delete = $select->compileDelete();

echo $delete->toSql();
// -> DELETE FROM users WHERE users.activated = '0' LIMIT 10;