Skip to content

Commit

Permalink
Added Db::beforeExecuting() to register a hook which to be run just…
Browse files Browse the repository at this point in the history
… before a database query is executed. (#4908)


Co-authored-by: 李铭昕 <715557344@qq.com>
  • Loading branch information
huangdijia and limingxinleo committed Jul 8, 2022
1 parent 5ed82f8 commit 13ab808
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG-3.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ composer analyse
- [#4700](https://github.com/hyperf/hyperf/pull/4700) Support coroutine style server for `socketio-server`.
- [#4852](https://github.com/hyperf/hyperf/pull/4852) Added `NullDisableEventDispatcher` to disable event dispatcher by default.
- [#4866](https://github.com/hyperf/hyperf/pull/4866) [#4869](https://github.com/hyperf/hyperf/pull/4869) Added Annotation `Scene` which use scene in FormRequest easily.
- [#4908](https://github.com/hyperf/hyperf/pull/4908) Added `Db::beforeExecuting()` to register a hook which to be run just before a database query is executed.

## Optimized

Expand Down
39 changes: 33 additions & 6 deletions src/database/src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ class Connection implements ConnectionInterface
/**
* The active PDO connection.
*
* @var \Closure|\PDO
* @var Closure|PDO
*/
protected $pdo;

/**
* The active PDO connection used for reads.
*
* @var \Closure|\PDO
* @var Closure|PDO
*/
protected $readPdo;

Expand Down Expand Up @@ -149,10 +149,17 @@ class Connection implements ConnectionInterface
*/
protected static array $resolvers = [];

/**
* All the callbacks that should be invoked before a query is executed.
*
* @var Closure[]
*/
protected static array $beforeExecutingCallbacks = [];

/**
* Create a new database connection instance.
*
* @param \Closure|\PDO $pdo
* @param Closure|PDO $pdo
* @param string $database
* @param string $tablePrefix
*/
Expand Down Expand Up @@ -489,6 +496,22 @@ public function disconnect()
$this->setPdo(null)->setReadPdo(null);
}

/**
* Register a hook to be run just before a database query is executed.
*/
public static function beforeExecuting(Closure $callback): void
{
static::$beforeExecutingCallbacks[] = $callback;
}

/**
* Clear all hooks which will be run before a database query.
*/
public static function clearBeforeExecutingCallbacks(): void
{
static::$beforeExecutingCallbacks = [];
}

/**
* Register a database query listener with the connection.
*/
Expand Down Expand Up @@ -623,7 +646,7 @@ public function getReadPdo()
/**
* Set the PDO connection.
*
* @param null|\Closure|\PDO $pdo
* @param null|Closure|PDO $pdo
* @return $this
*/
public function setPdo($pdo)
Expand All @@ -638,7 +661,7 @@ public function setPdo($pdo)
/**
* Set the PDO connection used for reading.
*
* @param null|\Closure|\PDO $pdo
* @param null|Closure|PDO $pdo
* @return $this
*/
public function setReadPdo($pdo)
Expand Down Expand Up @@ -983,7 +1006,7 @@ protected function getPdoForSelect($useReadPdo = true)
/**
* Execute the given callback in "dry run" mode.
*
* @param \Closure $callback
* @param Closure $callback
* @return array
*/
protected function withFreshQueryLog($callback)
Expand Down Expand Up @@ -1014,6 +1037,10 @@ protected function withFreshQueryLog($callback)
*/
protected function run(string $query, array $bindings, Closure $callback)
{
foreach (static::$beforeExecutingCallbacks as $beforeExecutingCallback) {
$beforeExecutingCallback($query, $bindings, $this);
}

$this->reconnectIfMissingConnection();

$start = microtime(true);
Expand Down
29 changes: 29 additions & 0 deletions src/database/tests/ModelRealBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,35 @@ public function testSelectForBindingIntegerWhenUsingVarcharIndex()
$this->assertSame('ref', $res[0]->type);
}

public function testBeforeExecuting()
{
$container = $this->getContainer();
$container->shouldReceive('get')->with(Db::class)->andReturn(new Db($container));

$res = Db::selectOne('SELECT * FROM `user` WHERE id = ?;', [1]);
$this->assertSame('Hyperf', $res->name);

try {
$chan = new Channel(2);
Db::beforeExecuting(function (string $sql, array $bindings, Connection $connection) use ($chan) {
$this->assertSame(null, $connection->getConfig('name'));
$chan->push(1);
});
Db::beforeExecuting(function (string $sql, array $bindings, Connection $connection) use ($chan) {
$this->assertSame('SELECT * FROM `user` WHERE id = ?;', $sql);
$this->assertSame([1], $bindings);
$chan->push(2);
});

$res = Db::selectOne('SELECT * FROM `user` WHERE id = ?;', [1]);
$this->assertSame('Hyperf', $res->name);
$this->assertSame(1, $chan->pop(1));
$this->assertSame(2, $chan->pop(1));
} finally {
Connection::clearBeforeExecutingCallbacks();
}
}

protected function getContainer()
{
$dispatcher = Mockery::mock(EventDispatcherInterface::class);
Expand Down
11 changes: 9 additions & 2 deletions src/db-connection/src/Db.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
*/
namespace Hyperf\DbConnection;

use Closure;
use Generator;
use Hyperf\Database\Connection as Conn;
use Hyperf\Database\ConnectionInterface;
use Hyperf\Database\ConnectionResolverInterface;
use Hyperf\Database\Query\Builder;
Expand All @@ -33,12 +35,12 @@
* @method static int affectingStatement(string $query, array $bindings = [])
* @method static bool unprepared(string $query)
* @method static array prepareBindings(array $bindings)
* @method static mixed transaction(\Closure $callback, int $attempts = 1)
* @method static mixed transaction(Closure $callback, int $attempts = 1)
* @method static void beginTransaction()
* @method static void rollBack()
* @method static void commit()
* @method static int transactionLevel()
* @method static array pretend(\Closure $callback)
* @method static array pretend(Closure $callback)
* @method static ConnectionInterface connection(string $pool)
*/
class Db
Expand Down Expand Up @@ -69,4 +71,9 @@ private function __connection(?string $name = null): ConnectionInterface
$resolver = $this->container->get(ConnectionResolverInterface::class);
return $resolver->connection($name);
}

public static function beforeExecuting(Closure $closure): void
{
Conn::beforeExecuting($closure);
}
}

0 comments on commit 13ab808

Please sign in to comment.