chh / sirel
灵活的SQL构建器,构建SQL的抽象语法树并将其导出。
Requires
- php: >=5.4.0
Requires (Dev)
- chh/bob: ~1.0@dev
- doctrine/dbal: 2.*@stable
- phpunit/dbunit: ~1.2
- phpunit/phpunit: ~3.7
Suggests
- doctrine/dbal: For the Sirel\Visitor\DoctrinePlatform visitor.
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的核心是表。表对象提供了对属性和查询工厂方法的方便访问。
您可以在表实例上调用这些方法以开始构建新查询
- 使用
from
、project
、join
、where
、order
、group
、take
或skip
开始构建一个选择查询 - 使用
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
)。此外,属性实例还提供了asc
和desc
方法来创建排序表达式。
<?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;
限制 & 偏移
限制和偏移对应于 take
和 skip
操作符。这些操作符将行数作为唯一参数。
<?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;