bogdanpet/orthite-db

PDO 封装,用于更方便地访问数据库

v1.0.3-stable 2018-08-30 09:48 UTC

This package is not auto-updated.

Last update: 2024-09-29 05:27:55 UTC


README

PDO 封装,用于更方便地访问数据库。目前处于原型阶段,仅支持 mysql。有些功能可能也适用于 postgres 或 sqlite,但将稍后添加对这些驱动器的完整支持。

目录

安装

使用命令通过 composer 安装包

composer require bogdanpet/orthite-db

创建连接

使用 dsn、用户名和密码字符串创建连接

创建连接与使用 dsn、用户名和密码字符串创建新的 PDO 连接相同。

$db = new \Orthite\Database\Database($dsn, $user, $password)

回收现有的 PDO 连接

如果已经存在一个 PDO 连接,可以将其传递给 Orthite 的 Database 类构造函数。

$pdo = new \PDO($dsn, $user, $password);

.  .  .

$db = new \Orthite\Database\Database($pdo);

使用数组创建连接

可以使用包含连接详细信息的数组创建数据库对象:驱动程序、主机、端口、用户、密码和数据库名称。

$conn = [
    'driver' => 'mysql',
    'host' => 'localhost',
    'port' => 3306,
    'user' => 'root',
    'password' => 'secret',
    'database' => 'database_name',
    'charset' => 'utf8',
    'collation' => 'utf8_unicode_ci'
];

$db = new \Orthite\Database\Database($conn);

当连接详情存储在某种配置文件中时,这种情况很有用。必需的参数是数据库、用户名和密码。其他参数有默认值

  • 驱动程序默认为 mysql
  • 主机默认为 localhost
  • 端口默认为 3306
  • 字符集默认为 utf8
  • 校对默认为 utf8_unicode_ci

创建子类并配置连接。

如果整个应用程序中使用了相同的连接,但需要在多个地方设置数据库对象,则创建一个子 Database 类并通过重写连接属性来使连接持久化是很好的。

<?php

namespace App;

class Database extends \Orthite\Database\Database
{

    protected $connection = [
        'driver' => 'mysql',
        'host' => 'localhost',
        'port' => 3306,
        'user' => 'root',
        'password' => 'secret',
        'database' => 'database_name'
    ];
}

或者,连接详情可能应该从某些配置文件(如 dotenv)中返回

<?php

namespace App;

class Database extends \Orthite\Database\Database
{

    public function __construct() {
        $this->connection['driver'] = getenv('DB_DRIVER');
        $this->connection['host'] = getenv('DB_HOST');
        $this->connection['port'] = getenv('DB_PORT');
        $this->connection['user'] = getenv('DB_USER');
        $this->connection['password'] = getenv('DB_PASSWORD');
        $this->connection['database'] = getenv('DB_NAME');
        
        parent::_construct();
    }
}

然后,只需实例化子类即可。

$db = new App\Database();

CRUD 操作

插入

要向数据库表插入记录,请调用 insert 方法并传递要插入的表名和数据数组。数组键必须与列名匹配。假设我们有一个包含 id、first_name、age、email、created_at、updated_at 列的 users 表,其中 id 是自增主键,updated_at 是可空的。要插入记录

$data = [
    'first_name' => 'Anika',
    'age' => 28,
    'email' => 'anika@example.com',
    'created_at' => date()
];

$db->insert('users', $data);

要一次插入多条记录,请使用 insertMany() 方法并传递数组数组(每个数组代表一条记录)。

$data = [
    [
        'first_name' => 'Anika',
        'age' => 28,
        'email' => 'anika@example.com',
        'created_at' => date()
    ],
    [
        'first_name' => 'Bob',
        'age' => 29,
        'email' => 'bob@example.com',
        'created_at' => date()
    ]
];

$db->insertMany('users', $data);

insertMany 方法返回成功插入的记录数。

选择

使用 select() 方法从数据库中获取数据。必需参数是表名。

$users = $db->select('users');

这将将 users 表中的所有列的所有记录获取到关联数组中。要获取仅某些列,请传递列名数组作为第二个参数。

$users = $db->select('users', ['name', 'email']);

这将仅获取名称和电子邮件列。

可选地,作为第三个参数可以传递获取样式。默认值为 FETCH_ASSOC。请参阅 PDO 获取样式

限制结果

在 select 之前使用 limit() 方法来限制获取的记录数。

$users = $db->limit(10)->select('users');

这将返回数据库中的前 10 条记录。limit 方法可以接受第二个参数,该参数定义了一个 'chunk',默认值为 1。因此,要获取第二块(从数据库中的第 11 条到第 20 条记录)的用户,请使用

$users = $db->limit(10, 2)->select('users');
在 select 中连接其他表

在 select 之前可以使用 innerJoin()(或别名 join,即内连接)、leftJoin()、rightJoin()、fullJoin() 连接其他表。

$users = $db->join('cities', 'city_id', 'id')->select('users');

此操作将在条件 users.city_id = cities.id 下将 cities 表与 users 表进行内连接。其他类型的连接操作与此类似。

由于 select() 方法必须在链的最后,因此有些人可能觉得先设置连接表然后是主表的方式不太自然。在这种情况下,可以使用 table() 方法,以下是如何达到相同结果的示例。

$users = $db->table('users')->join('cities', 'city_id', 'id')->select();
分组和排序结果

使用 groupBy() 方法,可以通过字符串传递单个列或通过数组传递多个列来生成 `GROUP BY` 声明。

$users = $db->groupBy('age')->select('users');

这将生成查询 SELECT * FROM users GROUP BY age

与分组类似,也可以使用 orderBy() 方法进行排序。

$users = $db->orderBy(['age', 'first_name'])->select('users');

生成的查询是 SELECT * FROM users ORDER BY age, first_name。对于排序,可以传递 ASC 或 DESC,并通过竖线 '|' 分隔。

$users = $db->orderBy(['age|ASC', 'first_name|DESC'])->select('users');

生成的查询是 SELECT * FROM users ORDER BY age ASC, first_name DESC

where 条件

在查看更新和删除操作之前,让我们先看看 WHERE 条件。要添加 WHERE 条件,请使用常规的 where() 方法。

$user = $db->where('id', 3)->select('users');

第一个参数是列名,第二个是值。另外,第三个参数是比较器,默认为 '=', 但可以是 '<', '>', '<=' 或 '>='。另外,第四个参数是关键字 'WHERE',但可以更改为 'AND' 或 'OR' 以添加多个条件。

$user = $db->where('id', 3)->where('age', 18, '>=', 'AND')->select('users');

这将生成 WHERE id=3 AND age >= 18。这是可能的,但与其更改第三和第四个参数,不如推荐并更直观地使用包装方法。

  • and() - 使用 'AND' 的 where() 方法
  • or() - 使用 'OR' 的 where() 方法
  • whereGreaterThan(); andGreaterThan(); orGreaterThan() - 与 '>' 比较器相对应的函数
  • whereLessThan(); andLessThan(); orLessThan() - 与 '<' 比较器相对应的函数
  • whereGreaterOrEquals(); andGreaterOrEquals(); orGreaterOrEquals() - 与 '>=' 比较器相对应的函数
  • whereLessOrEquals(); andLessOrEquals(); orLessOrEquals() - 与 '<=' 比较器相对应的函数

因此,将上述查询写成这样会更容易阅读

$user = $db->where('id', 3)->andGreaterOrEquals('age', 18)->select('users');

为了提高可读性,可以使用动态方法,其中列名在 'where'、'and' 或 'or' 关键字之后立即以驼峰式注入到方法名称中,并且只传递值作为参数。

$user = $db->whereId(3)->andAgeGreaterOrEquals(18)->select('users');

对于像 'first_name' 这样由下划线分隔的单词列名,使用驼峰式 whereFirstName()。

其他比较

Orthite-db 还提供了 whereLike()、andLike() 和 orLike() 方法。例如

$users = $db->whereFirstNameLike('Ani%')->select('users');

将生成 WHERE first_name LIKE 'Ani%',这将获取以 'Ani' 开头的用户。

与 LIKE 类似,还有用于 IN 比较的方法:whereIn()、andIn() 和 orIn(),它们接受一个要比较的值数组。

$users = $db->whereIdIn([1, 2, 3])->select('users');

生成 WHERE id IN (1, 2, 3) 并获取 id 为 1、2 和 3 的用户。

最后,对于 'BETWEEN' 比较操作,有 whereBetween()、andBetween() 和 orBetween() 方法,它们接受两个值参数。示例

$users = $db->whereIdBetween(1, 10)->select('users');

这将生成 WHERE id BETWEEN 1 and 10

更新

要更新数据库中的记录,请使用 update() 方法,它接受与 insert() 相同的参数:表名和数据。如果您不想更新表中的所有行,请别忘了结合使用 WHERE 条件。

$data = [
    'email' => 'anika@example.com'
];

$db->whereFirstName('Anika')->update('users', $data);

删除

要删除表中的一行或多行,请使用具有表名参数的 delete() 方法,并结合 WHERE 条件。

$db->whereId(8)->delete('users');

执行原始查询

提供的 CRUD 操作方法无法满足更复杂的操作,因此可以编写并执行原始查询。

raw() - 返回 PDO 语句

$stmt = $db->raw('SELECT * FROM users WHERE id < 100');

rawFetch() - 用于 SELECT 查询,它返回获取的数据而不是语句

$users = $db->rawFetch('SELECT * FROM users WHERE id < 100');

安全执行查询

而不是运行带有用户输入数据的原始查询,为了防止 SQL 注入,请运行 execute() 方法,该方法准备语句并使用给定的数据执行它。第一个参数是带有占位符的查询,第二个是数据数组。示例使用位置占位符

$stmt = $db->execute('SELECT * FROM users where id = ? and first_name = ?', [$id, $first_name]);

带有命名占位符的示例

$stmt = $db->execute('SELECT * FROM users where id = :id and first_name = :first_name', [
    ':id' => $id,
    ':first_name' => $first_name
]);
自定义带有数据类型指定的占位符

orthite-db 允许在占位符中指定数据类型,以实现更安全的查询。可能的类型有 sibl,分别对应于 PDO 参数类型 中的字符串、整数、布尔值和 lobs。自定义位置占位符使用问号和相应的字母 '?i' 表示。命名占位符的格式为 's:first_name'。在同一个查询中不能混合使用命名和位置占位符。示例

$stmt = $db->execute('SELECT * FROM users where id = ?i and first_name = ?s', [
    ':id' => $id,
    ':first_name' => $first_name
]);
$stmt = $db->execute('SELECT * FROM users where id = i:id and first_name = s:first_name', [
    ':id' => $id,
    ':first_name' => $first_name
]);

迁移

Orthite-db 还提供使用 migrate() 方法编写迁移脚本的功能。migrate() 方法的第一个参数是表名,第二个参数是包含列定义的回调函数。回调函数接受 $schema 参数,用于定义列结构。一个简单的迁移脚本应如下所示

use Orthite\Database\Migrations\SchemaInterface;

$db->migrate('cities', function (SchemaInterface $schema) {
    $schema->integer('id')->unsigned()->autoIncrement()->primary();
    $schema->string('name', 50);

    return $schema;
});

$db->migrate('users', function (SchemaInterface $schema) {
    $schema->increments(); // Alias of $schema->integer('id')->unsigned()->autoIncrement()->primary();
    $schema->string('username', 40)->unique();
    $schema->string('name', 30)->nullable();
    $schema->double('score')->default('0.00');
    $schema->integer('city_id')->unsigned()->foreign('cities', 'id');

    /*
     * Adds created_at, updated_at and deleted_at columns
     * Same as:
     * $this->timestamp('created_at');
     * $this->datetime('updated_at')->nullable();
     * $this->datetime('deleted_at')->nullable();
     */
    $schema->timestamps();

    return $schema;
});

上面的迁移脚本将创建两个表:cities 和 users,其中 users 表的 city_id 外键引用 cities 表的 id。

所以,如上例所示,在 $schema 对象上首先调用一个定义列的方法,并传递列名,然后链式调用可选的约束方法。迁移脚本结束时必须返回 $schema 对象。目前支持的列方法有

  • string($column, $length = 255) - VARCHAR 列
  • text($column) - TEXT 列
  • binary($column) - BLOB 列
  • integer($column, $size = 4) - INT 列
  • double($column, $size = 4, $decimals = 2) - DOUBLE 列
  • decimal($column, $size = 4, $decimals = 2) - DECIMAL 列
  • bool($column) - TINYINT(1) 列
  • date($column) - DATE 列
  • datetime($column) - DATETIME 列
  • timestamp($column) - TIMESTAMP 列
  • time($column) - TIME 列
  • year($column) - YEAR 列

可用的约束方法有

  • nullable() - 从列中移除 NOT NULL
  • unique() - 添加 UNIQUE 约束
  • primary() - 设置为 PRIMARY KEY
  • foreign($refTable, $refColumn) - 添加 FOREIGN KEY 约束
  • check($condition) - 添加 CHECK 约束
  • default($value) - 添加 DEFAULT 值
  • index() - 设置为 INDEXED 列
  • unsigned() - 将整数设置为 UNSIGNED
  • autoIncrement() - 将列设置为 AUTO_INCREMENT

包装方法

  • increments($column = 'id') - integer($column)->unsigned()->autoIncrement()->primary();
  • timestamps() - 创建三个列:created_at TIMESTAMP、updated_at 可空 DATETIME、deleted_at 可空 DATETIME