Files
faveo/vendor/itsgoingd/clockwork/Clockwork/DataSource/DBALDataSource.php
2023-06-08 18:56:00 +05:30

192 lines
5.1 KiB
PHP

<?php namespace Clockwork\DataSource;
use Clockwork\Request\Request;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Logging\LoggerChain;
use Doctrine\DBAL\Logging\SQLLogger;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type;
// Data source for DBAL, provides database queries
class DBALDataSource extends DataSource implements SQLLogger
{
// Array of collected queries
protected $queries = [];
// Current running query
protected $query = null;
// DBAL connection
protected $connection;
// DBAL connection name
protected $connectionName;
// Create a new data source instance, takes a DBAL connection instance as an argument
public function __construct(Connection $connection)
{
$this->connection = $connection;
$this->connectionName = $this->connection->getDatabase();
$configuration = $this->connection->getConfiguration();
$currentLogger = $configuration->getSQLLogger();
if ($currentLogger === null) {
$configuration->setSQLLogger($this);
} else {
$loggerChain = new LoggerChain;
$loggerChain->addLogger($currentLogger);
$loggerChain->addLogger($this);
$configuration->setSQLLogger($loggerChain);
}
}
// Adds executed database queries to the request
public function resolve(Request $request)
{
$request->databaseQueries = array_merge($request->databaseQueries, $this->queries);
return $request;
}
// Reset the data source to an empty state, clearing any collected data
public function reset()
{
$this->queries = [];
$this->query = null;
}
// DBAL SQLLogger event
public function startQuery($sql, array $params = null, array $types = null)
{
$this->query = [
'query' => $sql,
'params' => $params,
'types' => $types,
'time' => microtime(true)
];
}
// DBAL SQLLogger event
public function stopQuery()
{
$this->registerQuery($this->query);
$this->query = null;
}
// Collect an executed database query
protected function registerQuery($query)
{
$query = [
'query' => $this->createRunnableQuery($query['query'], $query['params'], $query['types']),
'bindings' => $query['params'],
'duration' => (microtime(true) - $query['time']) * 1000,
'connection' => $this->connectionName,
'time' => $query['time']
];
if ($this->passesFilters([ $query ])) {
$this->queries[] = $query;
}
}
// Takes a query, an array of params and types as arguments, returns runnable query with upper-cased keywords
protected function createRunnableQuery($query, $params, $types)
{
// add params to query
$query = $this->replaceParams($this->connection->getDatabasePlatform(), $query, $params, $types);
// highlight keywords
$keywords = [
'select', 'insert', 'update', 'delete', 'into', 'values', 'set', 'where', 'from', 'limit', 'is', 'null',
'having', 'group by', 'order by', 'asc', 'desc'
];
$regexp = '/\b' . implode('\b|\b', $keywords) . '\b/i';
return preg_replace_callback($regexp, function ($match) { return strtoupper($match[0]); }, $query);
}
/**
* Source at laravel-doctrine/orm LaravelDoctrine\ORM\Loggers\Formatters\ReplaceQueryParams::format().
*
* @param AbstractPlatform $platform
* @param string $sql
* @param array|null $params
* @param array|null $types
*
*
* @return string
*/
public function replaceParams($platform, $sql, array $params = null, array $types = null)
{
if (is_array($params)) {
foreach ($params as $key => $param) {
$type = isset($types[$key]) ? $types[$key] : null; // Originally used null coalescing
$param = $this->convertParam($platform, $param, $type);
$sql = preg_replace('/\?/', "$param", $sql, 1);
}
}
return $sql;
}
/**
* Source at laravel-doctrine/orm LaravelDoctrine\ORM\Loggers\Formatters\ReplaceQueryParams::convertParam().
*
* @param mixed $param
*
* @throws \Exception
* @return string
*/
protected function convertParam($platform, $param, $type = null)
{
if (is_object($param)) {
if (!method_exists($param, '__toString')) {
if ($param instanceof \DateTimeInterface) {
$param = $param->format('Y-m-d H:i:s');
} elseif (Type::hasType($type)) {
$type = Type::getType($type);
$param = $type->convertToDatabaseValue($param, $platform);
} else {
throw new \Exception('Given query param is an instance of ' . get_class($param) . ' and could not be converted to a string');
}
}
} elseif (is_array($param)) {
if ($this->isNestedArray($param)) {
$param = json_encode($param, JSON_UNESCAPED_UNICODE);
} else {
$param = implode(
', ',
array_map(
function ($part) {
return '"' . (string) $part . '"';
},
$param
)
);
return '(' . $param . ')';
}
} else {
$param = htmlspecialchars((string) $param); // Originally used the e() Laravel helper
}
return '"' . (string) $param . '"';
}
/**
* Source at laravel-doctrine/orm LaravelDoctrine\ORM\Loggers\Formatters\ReplaceQueryParams::isNestedArray().
*
* @param array $array
* @return bool
*/
private function isNestedArray(array $array)
{
foreach ($array as $key => $value) {
if (is_array($value)) {
return true;
}
}
return false;
}
}