diff --git a/src/DataListener/QueryListener.php b/src/DataListener/QueryListener.php index ae57303..d8ad268 100644 --- a/src/DataListener/QueryListener.php +++ b/src/DataListener/QueryListener.php @@ -3,8 +3,12 @@ namespace Socialblue\LaravelQueryAdviser\DataListener; use Illuminate\Database\Events\QueryExecuted; +use Illuminate\Database\QueryException; use Illuminate\Support\Facades\Cache; +use Socialblue\LaravelQueryAdviser\DataListener\Services\BindingsMapper; use Socialblue\LaravelQueryAdviser\DataListener\Services\SessionFormatter; +use Socialblue\LaravelQueryAdviser\DataListener\Services\TraceMapper; +use Socialblue\LaravelQueryAdviser\Helper\QueryBuilderHelper; class QueryListener { @@ -34,6 +38,43 @@ public static function listen(QueryExecuted $query) ); } + public static function onQueryException(QueryException $queryException): void + { + if (config('laravel-query-adviser.enable_query_logging') === false) { + return; + } + + $sessionKey = self::getSessionKey(); + + if (empty($sessionKey)) { + return; + } + + $url = url()->current(); + if (str_contains($url, '/query-adviser')) { + return; + } + + $time = time(); + $data = self::getFromCache($time, $sessionKey); + + $key = count($data[$time]); + $data[$time][$key] = [ + 'time' => $time, + 'timeKey' => $key, + 'errorInfo' => $queryException->errorInfo, + 'backtrace' => $queryException->getTrace(), + 'sql' => QueryBuilderHelper::combineQueryAndBindings($queryException->getSql(), $queryException->getBindings()), + 'rawSql' => $queryException->getSql(), + 'bindings' => (new BindingsMapper())->toCache($queryException->getBindings()), + 'queryTime' => 0, + 'url' => empty($url) ? '/' : $url, + 'referer' => empty($referer) ? '/' : $referer, + ]; + self::putToCache($data, $sessionKey); + } + + /** * @param $sessionKey */ diff --git a/src/LaravelQueryAdviserServiceProvider.php b/src/LaravelQueryAdviserServiceProvider.php index b576991..a09bad5 100755 --- a/src/LaravelQueryAdviserServiceProvider.php +++ b/src/LaravelQueryAdviserServiceProvider.php @@ -2,6 +2,7 @@ namespace Socialblue\LaravelQueryAdviser; +use Illuminate\Database\QueryException; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Route; use Illuminate\Support\ServiceProvider; @@ -15,9 +16,6 @@ class LaravelQueryAdviserServiceProvider extends ServiceProvider */ public function boot() { - /* - * Optional methods to load your package assets - */ $this->loadViewsFrom(__DIR__ . '/../resources/views', 'QueryAdviser'); Route::group([ @@ -46,12 +44,10 @@ public function boot() /** * Register the application services. */ - public function register() + public function register(): void { - // Automatically apply the package configuration $this->mergeConfigFrom(__DIR__ . '/../config/config.php', 'laravel-query-adviser'); - // Register the main class to use with the facade $this->app->singleton('laravel-query-adviser', function () { return new LaravelQueryAdviser(); }); @@ -60,12 +56,15 @@ public function register() /** * Add helper functions to app */ - protected function bootLaravelQueryAdviser() + protected function bootLaravelQueryAdviser(): void { - DB::listen(static function ($query) { - QueryListener::listen($query); - }); + $this->setupQueryLog(); + $this->setExceptionHandler(); + $this->setupMacro(); + } + private function setupMacro(): void + { \Illuminate\Database\Eloquent\Builder::macro(config('laravel-query-adviser.macros.dd'), function () { dd(QueryBuilderHelper::infoByBuilder($this)); }); @@ -82,4 +81,19 @@ protected function bootLaravelQueryAdviser() dump(QueryBuilderHelper::infoByBuilder($this)); }); } + + private function setExceptionHandler(): void + { + set_exception_handler(function (QueryException $exception) { + QueryListener::onQueryException($exception); + throw $exception; + }); + } + + private function setupQueryLog(): void + { + DB::listen(static function ($query) { + QueryListener::listen($query); + }); + } }