mreschke / dbal
Mreschke 辅助工具
README
简介
这是一个基于 Laravel 的 dbal 辅助库和查询构建器,具有简单的基于类的实体集成。
在我在 Laravel 查询构建器或 Eloquent 之前以及我构建了更强大和功能丰富的 https://github.com/mreschke/repository 之前,我构建了这个。
它还有一些优点,例如
- Mssql 二进制 GUID 转换
- Mssql int 或 decimal 在 PHP 返回中转换为 int。
- 在 MySQL PDO 设置 PDO::ATTR_EMULATE_PREPARES => false 和 PDO::ATTR_STRINGIFY_FETCHES => false 将返回 true 整数,但不适用于 MSSQL dblib 连接。
- 跨/链接服务器支持
- 简单且清晰的实体类集成(但不是实体映射)
但现在,由于我构建了 mreschke/repository
,它主要用于旧版。它主要为我们的小型 SQL farm 构建,但同时也支持 MySQL。
这个 dbal 确实有一个“基本”查询构建器,但也被设计为抛出大量的原始查询...就像你在 SQL IDE 中做的那样。因此,它可以处理大量的完整和部分原始 SQL 查询(其中大多数都没有转义,请注意)。
如果你正在启动一个新项目,只需使用 Laravel 查询构建器或 Eloquent...或者更好的是,https://github.com/mreschke/repository ... 如果你想要具有一致性和实体映射 API 的任何高级功能,请使用 mreschke/repository
。有关更多信息,请参阅以下内容基于实体的集成。
集合信息
所有多返回,如 ->get()
、->all()
、getArray()
、getAssoc()
...都将返回为 Laravel Illuminate\Support\Collection
。这意味着您可以在 dbal 返回后执行许多类似的方法...不要将这些与 dbal 方法混淆。
集合使用示例
$customers = $this->db->query("SELECT * FROM customers")->all();
$customer->count(); //collection level count
$customer->first(); //collection level first
etc...
有关更多信息,请参阅 https://laravel.net.cn/api/master/Illuminate/Support/Collection.html
连接和实例化
Mreschke/dbal
是一个 Laravel 库,因此它利用了 Laravel config/database.php
中现有的数据库配置数组。默认情况下,如果您使用 Mreschke\Dbal\Mssql
,则它将使用 sqlsrv
连接数组,如果您使用 Mreschke\Dbal\Mysql
,则它将使用 mysql
连接数组。
要更改连接,就像 Laravel 查询构建器一样,请使用
$this->db->connection('othercon')->query(...)->get()
Mreschke/dbal
附带了 2 个外观,Mysql
和 Mssql
。因此,您只需使用
Mssql::query('SELECT * FROM customers')->get()
但是,当然,首选的方法是通过构造函数中 Mreschke\Dbal\Mssql
的依赖注入。
基于实体的集成
您可以使用 mreschke/dbal
进行 即兴查询使用。即兴查询与 Laravel 查询构建器(非 Eloquent)同义。只需在需要时按需使用即可。
但是,当您将 mreschke/dbal
查询构建器与单个类关联时,会出现有趣的集成。
考虑一下您的“实体”类,例如 Sso\User.php
。例如,该 User.php
类当然可以有它自己的方法和属性,但它也可以由连接到数据库后端的 mreschke/dbal 支持。您可以通过扩展 Builder 类以添加流畅的实体 API 来将此类与 mreschke/dbal
集成,如下所示
$sso->user->find(45); // provided by dbal
$sso->user->where('email', 'mail@example.com'); // provided by dbal
$sso->user->byServer(1); // custom method in our User.php class, but it uses dbal behind the scenes
因此,将基本的 PHP 类或“实体”对象转换为流畅的模型。就像 Eloquent 做的那样。
注意:我坚信实体应该像API一样被对待,因此应该保持一致性。如果您更改数据库列名,实体的返回值不应改变。在mreschke\dbal中,结果直接与数据库绑定,这对一致性是一个问题。这就是为什么我创建了https://github.com/mreschke/repository
Mreschke/repository
是一个比仅仅将数据库与实体类集成更高级的实体系统。它添加了活动记录、列和实体映射抽象以及可替换的后端。如果您需要这种类型的实体集成,强烈建议使用mreschke/repository
。
对于临时查询,推荐使用Laravel查询构建器(非Eloquent),而对于实体管理和API,推荐使用mreschke/repository
。
以下是使用mreschke/dbal实现的SSO\User.php实体类示例
<?php use Mreschke\Dbal\Builder; use Mreschke\Dbal\Mssql as Dbal; class User extends Builder { /** * Database connection * @var Dbal */ protected $db; /** * Create a new User instance * @param Dbal $db */ public function __construct(Dbal $db) { $this->db = $db; $this->db->connection('sso'); $this->configureBuilder(); } /** * Configure the dbal query builder * @return void */ public function configureBuilder() { $this->key = 'user_id'; $this->select = ['tbl_user.*']; $this->from = 'tbl_user'; $this->where = null; $this->groupBy = null; $this->having = null; $this->orderBy = 'email'; } /** * Return the dbal database instance * @return DbalInterface */ public function dbInstance() { return $this->db; } /** * Get one user by email address * Automatically appends @dynatronsoftware.com if no domain specified * @param string $email * @return dbal resource */ public function byEmail($email) { if (!str_contains($email, "@")) $email .= "@dynatronsoftware.com"; $this->where("email = '$email'"); $this->orderBy(null); return $this->execute(); } /** * Get dealer server manager(s) * @param int $dealerID dp dlr id * @return dbal resource */ public function serviceManagers($dealerID) { $this->from('tbl_user INNER JOIN tbl_perm_group_link pgl on tbl_user.user_id = pgl.user_id INNER JOIN tbl_user_dealer_link udl on tbl_user.user_id = udl.user_id '); $this->where('tbl_user.disabled', false); $this->where('udl.dp_dlr_id', $dealerID); $this->where('pgl.group_id', 10); #10 = Service Manager $this->distinct(); return $this->execute(); } }
因为这个类扩展了Builder
,所以您将获得所有->find()
、->where()
、->select()
、->orderBy
...方法,以及添加您自己的、利用构建器的自定义方法的能力,如上面的byEmail()
或serviceManager()
方法。
即兴查询使用
Mreschke/dbal
也非常适合临时查询。
<?php use Mreschke\Dbal\Mssql; function __construct(Mssql $db) { // Dependency injection. Facades are also available. $this->db = $db; } function rawQueries() { // Get all as collection of objects $customers = $this->db->query("SELECT * FROM customers")->get(); // or all() // Get all as collection of arrays $customers = $this->db->query("SELECT * FROM customers")->getArray(); // or getAssoc() // Get all as key/value array $customers = $this->db->query("SELECT * FROM customers")->pluck('name', 'id'); // Get first record as object $customers = $this->db->query("SELECT * FROM customers")->first(); // Get first record as array $customers = $this->db->query("SELECT * FROM customers")->firstArray(); // or firstAssoc() // Get first column from first record (great for scalar queries) $customers = $this->db->query("SELECT TOP 1 name FROM customers")->pluck(); // Get defined column from first record $customers = $this->db->query("SELECT TOP 1 * FROM customers")->value('adddress'); // Count number of results // NOTICE: This will actually RUN the full query, so inefficient... // A SELECT count(*) is far more efficient. // So if you want the results too, get results, then count them yourself $count = $this->db->query("SELECT * FROM customers")->count(); // runs full query $count = $this->db->query("SELECT count(*) FROM customers")->value(); // db level, very efficient $customers = $this->db->query("SELECT * FROM customers")->get(); count($customers) //or because collection, $customers->count(); // Count number of columns $columnCount = $this->db->query("SELECT * FROM customers")->fieldCount(); // Escape data for raw input $input = $this-db->escape($input); $this->db->query("INSERT INTO customers $input"); } function queryBuilder() { // Query build table does NOT work with databsae or schema names like DB.dbo.my_table // Much like the raw ->query() function above, the terminators are ->get, // ->all(), ->getAssoc(), ->getArray(), ->first()... // Most query builder methods allow RAW entries too, like ->where('raw = this or raw = that')... // TABLE and SELECT // Build can do basic ->table(), ->select() and ->addSelect(). If you want // complex joins, use a full RAW ->query() or add RAW to the ->table() method. // By default select is set to * // Get all records $customers = $this->db->table('customer')->get(); // or all() // Get all records, limited columns $customers = $this->db->select('id', 'name')->table('customer')->get(); // Select as RAW, either as one parameter per column, or as one big string $customers = $this->db->select('id as UID', 'name as Customer')->table('customer')->get(); $customers = $this->db->select('id as UID, name as Customer')->table('customer')->get(); // Complex Raw table and select, but still using build style, not pure ->query() $customers = $this->db->select('c.*, r.name as Role') ->table('customer c INNER JOIN roles r on c.role_id = r.role_id'); $customers->addSelect('r.ID'); $customers->distinct(); $customers = $customers->get(); // WHERE, ORDER GROUP, HAVING // By default, the ->where() method has 2 params, and the = opreator is assumed // But like eloquent, you can override the operator ->where('name', 'like', 'bob')... // Chaining ->where() is by default AND...but you can alter to OR...but it won't // do compled nested AND/OR combinations...for that I just use RAW queries. // Get one with WHERE statement $customers = $this->db->table('customer')->where('name', 'Bob')->first(); // Multiple wheres (AND) $customers = $this->db->table('customer')->where('zip', 75067)->where('disabled', false)->first(); // Multiple wheres (OR) $customers = $this->db->table('customer')->where('zip', '=', 75067, 'or')->where('zip', 75068)->get(); $customers = $this->db->table('customer')->where('zip', '=', 75067)->orWhere('zip', 75068)->get(); // Mixed in RAW where $customers = $this->db->table('customer')->where('(zip = 1 or zip = 2)')->where('disabled', false)->get(); // Mixed RAW complex $customers = $this->db ->table('customer') ->select('name', 'count(*) as cnt') ->where('(x = y AND a = b) OR (c = d)') ->groupBy('name') ->orderBy('cnt desc') ->having('cnt > 1') } function procedures() { // No params $customers = $this->db->procedure('GetAllCustomers')->get() // Params $customers = $this->db->procedure('GetCustomersByState', [ ['name' => 'state', 'value' => 'TX'], ['name' => 'zip', 'value' => 75067], ]); // No return $this->db->procedure('DeleteAllCustomers'); }