扩展 Laravel/Lumen 查询生成器以自动添加 SQL 评论
Extending Laravel/Lumen Query Builder to automagically add SQL comments
我使用一个大型 RDS 数据库实例,它在几个不同的项目(准确地说不是微服务)之间共享,这个数据库的性能至关重要。因此,每当支持团队提出与我们的服务性能相关的票时,我都会监控查询。因此,为了让我跟踪每个查询的来源,即哪个应用程序、文件和行号,我想为所有查询自动添加 SQL 评论。因此,当我在查询生成器对象上调用 toSql() 时,它必须向我显示评论
-- lumen-api:app/Http/Controllers/APIController.php:85
select * from users;
env(app_name) . ':'. __FILE__ . ':' . __LINE__.
我尝试扩展查询构建器和语法 类 并将它们绑定到服务容器,但我认为我做错了什么。请看一下我是如何扩展这些 类.
的实现的
<?php
// app/Classes/Database/Query/Grammars/QueryGrammar.php
namespace App\Classes\Database\Query\Grammars;
use App\Classes\Database\Query\QueryBuilder;
use Illuminate\Database\Query\Grammars\Grammar;
class QueryGrammar extends Grammar
{
/**
* @param QueryBuilder $query
* @param $comment
* @return string
*/
public function compileComment(QueryBuilder $query, $comment)
{
$this->selectComponents[] = 'comment';
return '-- ' . $comment . PHP_EOL;
}
}
<?php
// app/Classes/Database/Query/QueryBuilder.php
<?php
namespace App\Classes\Database\Query;
use Illuminate\Database\Query\Builder;
class QueryBuilder extends Builder {
/**
* @param $comment
* @return $this
*/
public function comment($comment): QueryBuilder
{
$this->comment = $comment;
return $this;
}
}
<?php
//app/Providers/AppServiceProvider.php
<?php
namespace App\Providers;
use App\Classes\Database\Query\Grammars\QueryGrammar;
use App\Classes\Database\Query\QueryBuilder;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\Grammars\Grammar;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
/**
* Extending Query Builder to support SQL comments
*/
$this->app->bind(Grammar::class, function () {
return new QueryGrammar();
});
$this->app->bind(Builder::class, function () {
return new QueryBuilder(/* how to send params?*/);
});
}
}
我知道此实现不适用于自动添加 sql 评论。所以当我在我的控制器中使用它时:
return Admin::where('login_email','bhargav.nanekalva@mpokket.com')->comment(__FILE__ . __LINE__)->toSql();
Laravel 抛出以下错误:(这意味着绑定没有发生)
(1/1) BadMethodCallException
Call to undefined method Illuminate\Database\Eloquent\Builder::comment()
我需要帮助的是
- 修改这些的正确方法类
- 自动添加 sql 评论
直接覆盖语法 class 可能是可能的,但它在内部将其工作委托给数据库特定语法 classes
例如,如果您在 config/database.php 中配置了 Mysql,那么 Grammer class 会将工作委托给 Illuminate\Database\Query\Grammars\MySqlGrammar
与 Postgres 类似,它将是 Illuminate\Database\Query\Grammars\PostgresGrammar
基于数据库配置
连接工厂[src/Illuminate/Database/Connectors/ConnectionFactory.php->createConnection()
]
为给定的数据库加载正确的连接管理器
我不确定是否可以重写这个 classes,因为 PSR-4 加载是因为命名空间与文件在目录树中的物理位置紧密相关
因此,我建议使用 laravel 宏,您可以将新函数添加到使用 Macroable 特征
的现有 classes
可以在下面找到一个 POC 示例,为了进一步推进,我们鼓励您在 Grammer.php 和 Builder.php
中挖掘更新、插入、删除等代码
<?php
namespace App\Providers;
use Illuminate\Support\Arr;
use Illuminate\Support\ServiceProvider;
use DB;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\Grammars\Grammar;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
Grammar::macro("T_compileSelect", function (Builder $query) {
if ($query->unions && $query->aggregate) {
return $this->compileUnionAggregate($query);
}
$original = $query->columns;
if (is_null($query->columns)) {
$query->columns = ['*'];
}
$sql = trim($this->concatenate(
$this->compileComponents($query))
);
if ($query->unions) {
$sql = $this->wrapUnion($sql).' '.$this->compileUnions($query);
}
$query->columns = $original;
return $sql . ' -- ' . (!empty($query->comment)?$query->comment:'');
});
Builder::macro("T_toSql", function () {
$str = $this->grammar->T_compileSelect($this);
return $str;
});
Builder::macro("T_runSelect", function () {
$str = $this->connection->select(
$this->T_toSql(), $this->getBindings(), ! $this->useWritePdo
);
return $str;
});
Builder::macro("addComment", function ($comment, $columns = ['*']) {
$this->comment = $comment;
$res = collect($this->onceWithColumns(Arr::wrap($columns), function () {
return $this->processor->processSelect($this, $this->T_runSelect());
}));
return $res;
});
}
public function boot()
{
}
}
用法:
Admin::where('login_email','bhargav.nanekalva@mpokket.com')
->addComment(__FILE__ . __LINE__)
->get();
我使用一个大型 RDS 数据库实例,它在几个不同的项目(准确地说不是微服务)之间共享,这个数据库的性能至关重要。因此,每当支持团队提出与我们的服务性能相关的票时,我都会监控查询。因此,为了让我跟踪每个查询的来源,即哪个应用程序、文件和行号,我想为所有查询自动添加 SQL 评论。因此,当我在查询生成器对象上调用 toSql() 时,它必须向我显示评论
-- lumen-api:app/Http/Controllers/APIController.php:85
select * from users;
env(app_name) . ':'. __FILE__ . ':' . __LINE__.
我尝试扩展查询构建器和语法 类 并将它们绑定到服务容器,但我认为我做错了什么。请看一下我是如何扩展这些 类.
的实现的
<?php
// app/Classes/Database/Query/Grammars/QueryGrammar.php
namespace App\Classes\Database\Query\Grammars;
use App\Classes\Database\Query\QueryBuilder;
use Illuminate\Database\Query\Grammars\Grammar;
class QueryGrammar extends Grammar
{
/**
* @param QueryBuilder $query
* @param $comment
* @return string
*/
public function compileComment(QueryBuilder $query, $comment)
{
$this->selectComponents[] = 'comment';
return '-- ' . $comment . PHP_EOL;
}
}
<?php
// app/Classes/Database/Query/QueryBuilder.php
<?php
namespace App\Classes\Database\Query;
use Illuminate\Database\Query\Builder;
class QueryBuilder extends Builder {
/**
* @param $comment
* @return $this
*/
public function comment($comment): QueryBuilder
{
$this->comment = $comment;
return $this;
}
}
<?php
//app/Providers/AppServiceProvider.php
<?php
namespace App\Providers;
use App\Classes\Database\Query\Grammars\QueryGrammar;
use App\Classes\Database\Query\QueryBuilder;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\Grammars\Grammar;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
/**
* Extending Query Builder to support SQL comments
*/
$this->app->bind(Grammar::class, function () {
return new QueryGrammar();
});
$this->app->bind(Builder::class, function () {
return new QueryBuilder(/* how to send params?*/);
});
}
}
我知道此实现不适用于自动添加 sql 评论。所以当我在我的控制器中使用它时:
return Admin::where('login_email','bhargav.nanekalva@mpokket.com')->comment(__FILE__ . __LINE__)->toSql();
Laravel 抛出以下错误:(这意味着绑定没有发生)
(1/1) BadMethodCallException
Call to undefined method Illuminate\Database\Eloquent\Builder::comment()
我需要帮助的是
- 修改这些的正确方法类
- 自动添加 sql 评论
直接覆盖语法 class 可能是可能的,但它在内部将其工作委托给数据库特定语法 classes
例如,如果您在 config/database.php 中配置了 Mysql,那么 Grammer class 会将工作委托给 Illuminate\Database\Query\Grammars\MySqlGrammar
与 Postgres 类似,它将是 Illuminate\Database\Query\Grammars\PostgresGrammar
基于数据库配置
连接工厂[src/Illuminate/Database/Connectors/ConnectionFactory.php->createConnection()
]
为给定的数据库加载正确的连接管理器
我不确定是否可以重写这个 classes,因为 PSR-4 加载是因为命名空间与文件在目录树中的物理位置紧密相关
因此,我建议使用 laravel 宏,您可以将新函数添加到使用 Macroable 特征
的现有 classes可以在下面找到一个 POC 示例,为了进一步推进,我们鼓励您在 Grammer.php 和 Builder.php
中挖掘更新、插入、删除等代码<?php
namespace App\Providers;
use Illuminate\Support\Arr;
use Illuminate\Support\ServiceProvider;
use DB;
use Illuminate\Database\Query\Builder;
use Illuminate\Database\Query\Grammars\Grammar;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
Grammar::macro("T_compileSelect", function (Builder $query) {
if ($query->unions && $query->aggregate) {
return $this->compileUnionAggregate($query);
}
$original = $query->columns;
if (is_null($query->columns)) {
$query->columns = ['*'];
}
$sql = trim($this->concatenate(
$this->compileComponents($query))
);
if ($query->unions) {
$sql = $this->wrapUnion($sql).' '.$this->compileUnions($query);
}
$query->columns = $original;
return $sql . ' -- ' . (!empty($query->comment)?$query->comment:'');
});
Builder::macro("T_toSql", function () {
$str = $this->grammar->T_compileSelect($this);
return $str;
});
Builder::macro("T_runSelect", function () {
$str = $this->connection->select(
$this->T_toSql(), $this->getBindings(), ! $this->useWritePdo
);
return $str;
});
Builder::macro("addComment", function ($comment, $columns = ['*']) {
$this->comment = $comment;
$res = collect($this->onceWithColumns(Arr::wrap($columns), function () {
return $this->processor->processSelect($this, $this->T_runSelect());
}));
return $res;
});
}
public function boot()
{
}
}
用法:
Admin::where('login_email','bhargav.nanekalva@mpokket.com')
->addComment(__FILE__ . __LINE__)
->get();