rain1/pdo-powered

PDO 封装库,简化数据库交互

1.0.0 2024-04-23 20:17 UTC

This package is auto-updated.

Last update: 2024-09-23 21:06:23 UTC


README

Build Status Coverage Status

PDOPowered 是一个提供以下功能的 PDO 封装库

  • 延迟连接 仅在需要时创建 PDO 实例。配置凭据在连接后删除。
    • 使用 $db->onConnect($closure) 在连接后执行操作。
  • 失败时重新连接 如果连接失败,则尝试重新连接(最多 PDOPowered::$MAX_TRY_CONNECTION 次尝试)。
    • 使用 $db->onConnectionFailure($closure) 在每次连接失败后执行操作(例如,休眠和/或错误报告)。
  • 快速查询参数query 方法中调用 prepare 和 execute。 $db->query("SELECT ?,?,?", [1,2,3])
  • 查询方法返回一个带有增强方法的 PDOStatement 封装器。
    • fetchObjects 对每一行调用 fetchObject 并将结果存储在数组中。
    • getPDOStatement 用于获取原生 PDOStatement。
  • 快速查询 提供快速查询的助手。
    • 插入 用于快速插入 $db->insert("tableName",$arrayValues) 返回最后一个插入 ID。
    • 更新 用于快速更新 $db->update("tableName", $valuesToUpdate, $arrayCondition) 返回受影响行数。
    • insertOnDuplicateKeyUpdate 用于在重复键更新插入 $db->insertOnDuplicateKeyUpdate($tableName, $arrayValues) 返回最后一个插入 ID。
    • 删除 用于快速删除 $db->delete("tableName", $arrayWhereCondition) 返回受影响行数。
  • 简单调试 使用 $db->onDebug($closure) 可以访问调试输出并执行操作(例如,记录到文件、发送到标准输出等)。
  • 访问原生 PDO 实例 通过扩展 PDOPowered,您可以通过 getPDO() 方法访问原生 PDO 实例。

基本用法

安装

composer require rain1/pdo-powered

或检出 https://github.com/LucaRainone/pdo-powered.git

或在此下载 (https://github.com/LucaRainone/pdo-powered/archive/master.zip)

开始使用

必须将 rain1\PDOPowered\Config\ConfigInterface 的实现传递给构造函数。我们提供以下实现

use \rain1\PDOPowered\Config\Config;
$config = new Config("mysql", "user", "password", "localhost", 3306, "dbname", "utf8", [\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'']);

或等效

use \rain1\PDOPowered\Config\DSN;
$config = new DSN(
    "mysql:host=localhost;port=3306;dbname=dbname;charset=utf8", "user", "password"
);
$config->setOptions([\PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'"]);

因此,我们以这种方式构建实例

$db = new PDOPowered($config);

可以使用预存在的 PDO 实例与 PDOPowered 一起使用。

$db = PDOPowered::buildFromPDOInstance($pdoInstance);

该库为插入/更新/删除和重复键更新提供了快捷方式。

// fast insert. Return the inserted id
$id = $db->insert("tabletest", ['id'=>1, 'col1'=>'col1_1']);

// fast update
$db->update("tabletest", ['col1'=>'updated'], ['id'=>$id]);

// build a "INSERT ON DUPLICATE KEY UPDATE" query
$db->insertOnDuplicateKeyUpdate("tabletest", ['id'=> $id, 'col1'=>'updated']);
$db->insertOnDuplicateKeyUpdate("tabletest", ['id'=> $id+1, 'col1'=>'updated']);

// performs a delete
$db->delete("tabletest", ['id'=>$id]);

// simple query
$row = $db->query("SELECT * FROM tabletest WHERE id = ?", [$id])->fetch();

// or equivalent
$row = $db->query("SELECT * FROM tabletest WHERE id = :id", ['id'=>$id])->fetch();

query 方法返回 \PDOStatement 的封装器。可用的方法有:

  • fetch
  • fetchAll
  • fetchObject
  • fetchColumn
  • rowCount
  • closeCursor
  • getPDOStatement 返回原生 PDOStatement(用于任何情况)。
  • fetchObjects 返回包含所有 fetchObject 调用结果的数组。

高级用法

以下事件被触发:

  • connectionFailure
  • connect
  • debug
// triggered after a connection fails: before the next attempt
$db->onConnectionFailure(function($connectionTry, \Exception $exception) {
    sleep($connectionTry);
    error_log("Unable to connect on mysql: " . $exception->getMessage());
});

// triggered after a connection success
$db->onConnect(function() {
    echo "Db connected\n";
});

// triggered on debug string
$idDebugListener = $db->onDebug(function($debugType, \PDOStatement $PDOStatement = null, ...$args) {
    echo "$debugType\n";
    if($PDOStatement)
        $PDOStatement->debugDumpParams();
    echo "\n".json_encode($args);
});

// for each event we can remove the listener
$db->removeDebugListener($idDebugListener);

我们提供了一个简单的调试助手。

$db->onDebug(DebugParser::onParse(function ($info) {
    print_r($info); // info for timing, query, params and finalized query
}));

其他选项

// set maximum number of connection attempts.
\rain1\PDOPowered\Config\PDOPowered::$MAX_TRY_CONNECTION = 5;

// set pdo attribute after connection. 
$db->setPDOAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);

参数提示

PDOPowered 自动将值参数字符串视为 \PDO::PARAM_STR,将值整数视为 \PDO::PARAM_INT。对于任何情况,您都可以明确地这样做。

$users = $db->query(
    "SELECT * FROM user WHERE email = :email AND id = :id", 
    [
        "email" => new \rain1\PDOPowered\Param\ParamString("me@me.it"),
        "id"=> new \rain1\PDOPowered\Param\ParamInt("123"),
    ]
)->fetchAll();

您可以使用每个 PDO Param 支持。

[
    "param" => new \rain1\PDOPowered\Param\ParamNative("value", \PDO::PARAM_STR)
]

或构建自己的新参数类型,实现 \rain1\PDOPowered\Param\ParamInterface

例如,作为附加功能,我们有一个

[
    "param" => new \rain1\PDOPowered\Param\ParamJSON(["key"=>"value"])
]

这等价于

[
    "param" => json_encode(["key"=>"value"])
]

真实案例(在家试试)

您需要创建一个名为 "test" 的数据库。

use rain1\PDOPowered\Config\Config;
use rain1\PDOPowered\Debug\DebugParser;
use rain1\PDOPowered\Param\ParamJSON;
use rain1\PDOPowered\Param\ParamString;
use rain1\PDOPowered\PDOPowered;

require "vendor/autoload.php";

function output(...$texts) {
    $endline =  php_sapi_name() === "cli" ? "\n" : "<br/>";
    foreach($texts as $text)
        echo str_replace("\n", $endline, $text) .$endline;
}

$config = new Config(
    "mysql",
    "root",
    "vagrant",
    "localhost",
    3306,
    "test",
    "utf8",
    [
        \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
    ]
);


$db = new PDOPowered($config);

output("adding listeners...");

$db->onConnectionFailure(function ($try, \Exception $e) {
    error_log("connection failed: " . $e->getMessage());
    output("connection failed");
});

$db->onConnect(function() {
    output("Connected", "");
});

// only for debug
$debug = 1;
$countQuery = 0;
$debug && $db->onDebug(
    DebugParser::onParse(
        function ($info) use (&$countQuery) {

            $str = "---- DEBUG ROW " . (++$countQuery) .  " ----\n";

            if (isset($info['query']))
                $str .= $info['query']['demo'] . "\nexecution time: " . $info['query']['executionTime'];
            else
                $str .= $info['type'] . " " . json_encode($info['args']);

            output($str, "");
        }
    )
);


output("set attributes");

$db->setPDOAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);

output("first query");

$db->query("DROP TABLE IF EXISTS user");

$db->query("create table user
(
	id int auto_increment
		primary key,
	email varchar(32) null,
	settings text null
)
; ");

$db->beginTransaction();
$id = $db->insert("user", ['email' => 'me@me.com']);

$db->update("user", ["email" => "me2@me.com"], ['id' => (int)$id]);

$db->delete("user", ['id' => 1]);

$db->insert("user", [
    'id' => 1,
    'email' => new ParamString("me@me.com")
]);

$db->insertOnDuplicateKeyUpdate("user", [
    'id' => 1,
    'email' => new ParamString("me3@me.com"),
    'settings' => new ParamJSON(['privacy' => 1, 'newsletter' => 'no'])
]);

$rows = $db->query("SELECT * FROM user WHERE id = :id", ['id' => 1])->fetchAll();
$db->commitTransaction();

$db->query("SELECT SLEEP (1)");

print_r($rows);