From 3433a74022939d329726a489778e65183e3d7a75 Mon Sep 17 00:00:00 2001 From: Yu Li Date: Wed, 15 Aug 2018 12:30:18 +0800 Subject: [PATCH 01/41] Clockwork Output error fix #33 --- src/Outputs/Clockwork.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Outputs/Clockwork.php b/src/Outputs/Clockwork.php index 533bcbd..fea7055 100644 --- a/src/Outputs/Clockwork.php +++ b/src/Outputs/Clockwork.php @@ -7,6 +7,11 @@ class Clockwork implements Output { + public function boot() + { + // + } + public function output(Collection $detectedQueries, Response $response) { clock()->warning("{$detectedQueries->count()} N+1 queries detected:", $detectedQueries->toArray()); From 5095819b6d8e21c1668818190548d39a5ce385cd Mon Sep 17 00:00:00 2001 From: Bader Almutairi Date: Sat, 18 Aug 2018 11:54:47 +0300 Subject: [PATCH 02/41] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 116389e..05b04ba 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.1", - "illuminate/support": "5.5.*|5.6.*" + "illuminate/support": "5.5.*|5.6.*|5.7.*" }, "require-dev": { "orchestra/testbench": "3.6.*", From 3fa1c580064a9dd66c561a6911f67d7c7254bba7 Mon Sep 17 00:00:00 2001 From: Anders Fajersson Date: Fri, 30 Nov 2018 14:34:46 +0100 Subject: [PATCH 03/41] Add time to logged query --- src/QueryDetector.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/QueryDetector.php b/src/QueryDetector.php index c9b316f..0e24f99 100755 --- a/src/QueryDetector.php +++ b/src/QueryDetector.php @@ -77,9 +77,11 @@ public function logQuery($query, Collection $backtrace) $key = md5($query->sql . $model . $relationName . $sources[0]->name . $sources[0]->line); $count = array_get($this->queries, $key.'.count', 0); + $time = array_get($this->queries, $key.'.time', 0); $this->queries[$key] = [ 'count' => ++$count, + 'time' => $time + $query->time, 'query' => $query->sql, 'model' => $model, 'relatedModel' => $relatedModel, From 420053d3fc5fb06867ebc6cd362a9bc689e178cb Mon Sep 17 00:00:00 2001 From: arubacao Date: Fri, 7 Dec 2018 10:57:09 +0100 Subject: [PATCH 04/41] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 4084157..24c2d6c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: php php: - 7.1 - 7.2 + - 7.3 env: matrix: From 97a61e6864e7ddb9ba592dba78e7f55c1e927165 Mon Sep 17 00:00:00 2001 From: Marcel Pociot Date: Thu, 13 Dec 2018 21:42:53 +0100 Subject: [PATCH 05/41] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f80cab1..853be13 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ If you rather want this information to be written to your `laravel.log` file, wr You can publish the package's configuration using this command: ```bash -php artisan vendor:publish --provider=BeyondCode\\QueryDetector\\QueryDetectorServiceProvider +php artisan vendor:publish --provider=BeyondCode\QueryDetector\QueryDetectorServiceProvider ``` This will add the `querydetector.php` file in your config directory with the following contents: From f9c2595c105e9b03774981b574e43add03102f36 Mon Sep 17 00:00:00 2001 From: Marcel Pociot Date: Thu, 13 Dec 2018 21:47:27 +0100 Subject: [PATCH 06/41] do not log callstack in single steps --- src/Outputs/Log.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Outputs/Log.php b/src/Outputs/Log.php index 2c9349f..9aa2c18 100644 --- a/src/Outputs/Log.php +++ b/src/Outputs/Log.php @@ -16,16 +16,21 @@ public function boot() public function output(Collection $detectedQueries, Response $response) { LaravelLog::info('Detected N+1 Query'); + foreach ($detectedQueries as $detectedQuery) { - LaravelLog::info('Model: '.$detectedQuery['model']); - LaravelLog::info('Relation: '.$detectedQuery['relation']); - LaravelLog::info('Num-Called: '.$detectedQuery['count']); + $logOutput = 'Model: '.$detectedQuery['model'] . PHP_EOL; + + $logOutput .= 'Relation: '.$detectedQuery['relation'] . PHP_EOL; - LaravelLog::info('Call-Stack:'); + $logOutput .= 'Num-Called: '.$detectedQuery['count'] . PHP_EOL; + + $logOutput .= 'Call-Stack:' . PHP_EOL; foreach ($detectedQuery['sources'] as $source) { - LaravelLog::info('#'.$source->index.' '.$source->name.':'.$source->line); + $logOutput .= '#'.$source->index.' '.$source->name.':'.$source->line . PHP_EOL; } + + LaravelLog::info($logOutput); } } } From 2470de036eeccd36463ddaf55ebf52098bcb2ed6 Mon Sep 17 00:00:00 2001 From: Marcel Pociot Date: Thu, 13 Dec 2018 21:56:26 +0100 Subject: [PATCH 07/41] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 853be13..880e79a 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ The Laravel N+1 query detector helps you to increase your application's performa ![Example alert](https://beyondco.de/github/n+1/alert.png) +> If you want to learn how to create reusable PHP packages yourself, take a look at my upcoming [PHP Package Development](https://phppackagedevelopment.com) video course. + + ## Installation You can install the package via composer: From 3551306ce1e31add7a650ef842394ec9831f83fd Mon Sep 17 00:00:00 2001 From: Kris Kelly Date: Tue, 26 Feb 2019 23:03:30 +0000 Subject: [PATCH 08/41] Added support for illuminate/support 5.8 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 05b04ba..6960203 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.1", - "illuminate/support": "5.5.*|5.6.*|5.7.*" + "illuminate/support": "5.5.*|5.6.*|5.7.*|5.8.*" }, "require-dev": { "orchestra/testbench": "3.6.*", From 14c8138abbb6921e16cf3ab5b033aa76a6305c4c Mon Sep 17 00:00:00 2001 From: feek <5747667+mr-feek@users.noreply.github.com> Date: Mon, 11 Mar 2019 12:08:31 -0700 Subject: [PATCH 09/41] add threshold to config file This is listed in the readme, but not in the actual published config --- config/config.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/config.php b/config/config.php index b7c63cf..aa058d8 100644 --- a/config/config.php +++ b/config/config.php @@ -6,6 +6,12 @@ * If this is set to "null", the app.debug config value will be used. */ 'enabled' => env('QUERY_DETECTOR_ENABLED', null), + + /* + * Threshold level for the N+1 query detection. If a relation query will be + * executed more then this amount, the detector will notify you about it. + */ + 'threshold' => 1, /* * Here you can whitelist model relations. From 63dd0a6a3c469d2040a546fd6140aff9373a3ab5 Mon Sep 17 00:00:00 2001 From: feek <5747667+mr-feek@users.noreply.github.com> Date: Tue, 26 Mar 2019 14:35:43 -0700 Subject: [PATCH 10/41] fix: dont add the collector to debugbar twice --- src/Outputs/Debugbar.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Outputs/Debugbar.php b/src/Outputs/Debugbar.php index 31ff9c0..094b8c0 100644 --- a/src/Outputs/Debugbar.php +++ b/src/Outputs/Debugbar.php @@ -15,8 +15,10 @@ class Debugbar implements Output public function boot() { $this->collector = new MessagesCollector('N+1 Queries'); - - LaravelDebugbar::addCollector($this->collector); + + if (!LaravelDebugbar::hasCollector($this->collector->getName())) { + LaravelDebugbar::addCollector($this->collector); + } } public function output(Collection $detectedQueries, Response $response) From 22ed53c198fe0425a0d6e9cdfb43d63579108602 Mon Sep 17 00:00:00 2001 From: Micheal Mand Date: Sun, 12 May 2019 14:50:07 -0600 Subject: [PATCH 11/41] Fix Facade usage If someone (like me) doesn't allow Debugbar to be auto-discovered by Laravel, the Facade might not be aliased to `Debugbar`. The exception `Class 'Debugbar' not found` would be thrown. --- src/Outputs/Debugbar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Outputs/Debugbar.php b/src/Outputs/Debugbar.php index 31ff9c0..3fc0529 100644 --- a/src/Outputs/Debugbar.php +++ b/src/Outputs/Debugbar.php @@ -5,7 +5,7 @@ use Illuminate\Support\Collection; use Symfony\Component\HttpFoundation\Response; -use Debugbar as LaravelDebugbar; +use Barryvdh\Debugbar\Facade as LaravelDebugbar; use DebugBar\DataCollector\MessagesCollector; class Debugbar implements Output From 8b1ee3e219185b0bde8b473028061d9481fc4455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danie=CC=88l=20de=20Wit?= Date: Tue, 17 Sep 2019 16:40:15 +0200 Subject: [PATCH 12/41] Add Laravel 6 support Replaced array_ helpers with underlying classes --- composer.json | 2 +- src/QueryDetector.php | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 6960203..a68a093 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.1", - "illuminate/support": "5.5.*|5.6.*|5.7.*|5.8.*" + "illuminate/support": "^5.5|^6" }, "require-dev": { "orchestra/testbench": "3.6.*", diff --git a/src/QueryDetector.php b/src/QueryDetector.php index 0e24f99..d9c1863 100755 --- a/src/QueryDetector.php +++ b/src/QueryDetector.php @@ -3,6 +3,7 @@ namespace BeyondCode\QueryDetector; use DB; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Database\Eloquent\Builder; use Symfony\Component\HttpFoundation\Response; @@ -47,7 +48,7 @@ public function isEnabled(): bool public function logQuery($query, Collection $backtrace) { $modelTrace = $backtrace->first(function ($trace) { - return array_get($trace, 'object') instanceof Builder; + return Arr::get($trace, 'object') instanceof Builder; }); // The query is coming from an Eloquent model @@ -57,7 +58,7 @@ public function logQuery($query, Collection $backtrace) * or if the class itself is a Relation. */ $relation = $backtrace->first(function ($trace) { - return array_get($trace, 'function') === 'getRelationValue' || array_get($trace, 'class') === Relation::class ; + return Arr::get($trace, 'function') === 'getRelationValue' || Arr::get($trace, 'class') === Relation::class ; }); // We try to access a relation @@ -76,8 +77,8 @@ public function logQuery($query, Collection $backtrace) $key = md5($query->sql . $model . $relationName . $sources[0]->name . $sources[0]->line); - $count = array_get($this->queries, $key.'.count', 0); - $time = array_get($this->queries, $key.'.time', 0); + $count = Arr::get($this->queries, $key.'.count', 0); + $time = Arr::get($this->queries, $key.'.time', 0); $this->queries[$key] = [ 'count' => ++$count, From 4b65a19b5e6cd775f9316ee3660ca3086e453906 Mon Sep 17 00:00:00 2001 From: "@oele_co" Date: Thu, 20 Feb 2020 15:20:02 -0500 Subject: [PATCH 13/41] Prevent Illegal string offset 'warning_queries' Prevent Illegal string offset 'warning_queries' exception from not Arrayable responses. --- src/Outputs/Json.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Outputs/Json.php b/src/Outputs/Json.php index 21b387e..e2f5714 100644 --- a/src/Outputs/Json.php +++ b/src/Outputs/Json.php @@ -16,6 +16,10 @@ public function output(Collection $detectedQueries, Response $response) { if ($response instanceof JsonResponse) { $data = $response->getData(true); + if (! is_array($data)){ + $data = [ $data ]; + } + $data['warning_queries'] = $detectedQueries; $response->setData($data); } From 623075d40ae03823cf372dfc2f52326eb83faf47 Mon Sep 17 00:00:00 2001 From: Matthew Nessworthy Date: Thu, 5 Mar 2020 10:21:55 +0100 Subject: [PATCH 14/41] Laravel 7 Support --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a68a093..314b670 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.1", - "illuminate/support": "^5.5|^6" + "illuminate/support": "^5.5|^6|^7" }, "require-dev": { "orchestra/testbench": "3.6.*", From b0b920b21f1519a75b012b29aeaae91be35061f0 Mon Sep 17 00:00:00 2001 From: Matthew Nessworthy Date: Mon, 9 Mar 2020 17:33:02 +0100 Subject: [PATCH 15/41] Test different laravel versions --- .travis.yml | 39 +++++++++++++++++++++++++++++++++------ composer.json | 6 +++--- tests/TestCase.php | 4 ++-- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 24c2d6c..ddfd84f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,15 +4,42 @@ php: - 7.1 - 7.2 - 7.3 + - 7.4 env: - matrix: - - COMPOSER_FLAGS="--prefer-lowest" - - COMPOSER_FLAGS="" + - LARAVEL="^5.5" COMPOSER_FLAGS="--prefer-lowest" + - LARAVEL="^5.5" COMPOSER_FLAGS="" + - LARAVEL="^6.0" COMPOSER_FLAGS="--prefer-lowest" + - LARAVEL="^6.0" COMPOSER_FLAGS="" + - LARAVEL="^7.0" COMPOSER_FLAGS="--prefer-lowest" + - LARAVEL="^7.0" COMPOSER_FLAGS="" -before_script: - - travis_retry composer self-update - - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-source +matrix: + exclude: + - php: 7.1 + env: LARAVEL="^6.0" COMPOSER_FLAGS="--prefer-lowest" + - php: 7.1 + env: LARAVEL="^6.0" COMPOSER_FLAGS="" + - php: 7.1 + env: LARAVEL="^7.0" COMPOSER_FLAGS="--prefer-lowest" + - php: 7.1 + env: LARAVEL="^7.0" COMPOSER_FLAGS="" + allow_failures: + - php: 7.4 + env: LARAVEL="^5.5" COMPOSER_FLAGS="--prefer-lowest" + - php: 7.4 + env: LARAVEL="^6.0" COMPOSER_FLAGS="--prefer-lowest" + +cache: + directories: + - $HOME/.composer/cache/files + +before_install: + - echo "memory_limit=2G" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini + +install: + - travis_retry composer require laravel/framework:${LARAVEL} --no-interaction --prefer-dist + - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-dist script: - vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover diff --git a/composer.json b/composer.json index 314b670..9db0a09 100644 --- a/composer.json +++ b/composer.json @@ -17,11 +17,11 @@ ], "require": { "php": "^7.1", - "illuminate/support": "^5.5|^6|^7" + "illuminate/support": "^5.5 || ^6.0 || ^7.0" }, "require-dev": { - "orchestra/testbench": "3.6.*", - "phpunit/phpunit": "^7.0" + "orchestra/testbench": "^3.0 || ^4.0 || ^5.0", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "autoload": { "psr-4": { diff --git a/tests/TestCase.php b/tests/TestCase.php index 6f669c4..b981a0a 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -12,7 +12,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase { protected static $setUpRun = false; - public function setUp() + public function setUp(): void { parent::setUp(); @@ -79,4 +79,4 @@ protected function setUpDatabase() $table->morphs('commentable'); }); } -} \ No newline at end of file +} From 548cc1d08179dc4edea24d38da5644a170467d04 Mon Sep 17 00:00:00 2001 From: Zlatoslav Desyatnikov Date: Fri, 3 Apr 2020 16:38:12 +0300 Subject: [PATCH 16/41] Ability to change queries treshold via .env --- README.md | 2 +- config/config.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 880e79a..f39b763 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ return [ * Threshold level for the N+1 query detection. If a relation query will be * executed more then this amount, the detector will notify you about it. */ - 'threshold' => 1, + 'threshold' => (int) env('QUERY_DETECTOR_TRESHOLD', 1), /* * Here you can whitelist model relations. diff --git a/config/config.php b/config/config.php index aa058d8..9ee1bb9 100644 --- a/config/config.php +++ b/config/config.php @@ -11,7 +11,7 @@ * Threshold level for the N+1 query detection. If a relation query will be * executed more then this amount, the detector will notify you about it. */ - 'threshold' => 1, + 'threshold' => (int) env('QUERY_DETECTOR_TRESHOLD', 1), /* * Here you can whitelist model relations. From 450443362eca1157b7d54df7a89a935d78e2e248 Mon Sep 17 00:00:00 2001 From: Daniel Breves Date: Wed, 6 May 2020 18:08:14 +1000 Subject: [PATCH 17/41] Avoid namespace conflicts --- src/Outputs/Log.php | 2 +- src/QueryDetector.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Outputs/Log.php b/src/Outputs/Log.php index 9aa2c18..874b395 100644 --- a/src/Outputs/Log.php +++ b/src/Outputs/Log.php @@ -2,7 +2,7 @@ namespace BeyondCode\QueryDetector\Outputs; -use Log as LaravelLog; +use Illuminate\Support\Facades\Log as LaravelLog; use Illuminate\Support\Collection; use Symfony\Component\HttpFoundation\Response; diff --git a/src/QueryDetector.php b/src/QueryDetector.php index d9c1863..0d3dcc6 100755 --- a/src/QueryDetector.php +++ b/src/QueryDetector.php @@ -2,7 +2,7 @@ namespace BeyondCode\QueryDetector; -use DB; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Database\Eloquent\Builder; From 9938d200b4d75b6b4d374fdc79a0669b756e2e97 Mon Sep 17 00:00:00 2001 From: Marcel Pociot Date: Wed, 20 May 2020 00:25:27 +0200 Subject: [PATCH 18/41] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 880e79a..b4199f7 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ If you rather want this information to be written to your `laravel.log` file, wr You can publish the package's configuration using this command: ```bash -php artisan vendor:publish --provider=BeyondCode\QueryDetector\QueryDetectorServiceProvider +php artisan vendor:publish --provider="BeyondCode\QueryDetector\QueryDetectorServiceProvider" ``` This will add the `querydetector.php` file in your config directory with the following contents: From 5d3bdd0a7d47b0960fb27ab9ffb453e6c181e7e9 Mon Sep 17 00:00:00 2001 From: Arie Visser Date: Fri, 22 May 2020 14:27:30 +0200 Subject: [PATCH 19/41] Fixed typo in threshold --- README.md | 2 +- config/config.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 755f34c..88a85ca 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ return [ * Threshold level for the N+1 query detection. If a relation query will be * executed more then this amount, the detector will notify you about it. */ - 'threshold' => (int) env('QUERY_DETECTOR_TRESHOLD', 1), + 'threshold' => (int) env('QUERY_DETECTOR_THRESHOLD', 1), /* * Here you can whitelist model relations. diff --git a/config/config.php b/config/config.php index 9ee1bb9..e4a6e06 100644 --- a/config/config.php +++ b/config/config.php @@ -11,7 +11,7 @@ * Threshold level for the N+1 query detection. If a relation query will be * executed more then this amount, the detector will notify you about it. */ - 'threshold' => (int) env('QUERY_DETECTOR_TRESHOLD', 1), + 'threshold' => (int) env('QUERY_DETECTOR_THRESHOLD', 1), /* * Here you can whitelist model relations. From de0233f6dabda777f71bc0e11be3ae45da4cf863 Mon Sep 17 00:00:00 2001 From: Marcel Pociot Date: Wed, 3 Jun 2020 16:33:42 +0200 Subject: [PATCH 20/41] wip --- .gitignore | 1 - docs/_index.md | 4 ++ docs/installation.md | 17 ++++++++ docs/usage.md | 92 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 docs/_index.md create mode 100644 docs/installation.md create mode 100644 docs/usage.md diff --git a/.gitignore b/.gitignore index 2e1fc0e..28367bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ build composer.lock -docs vendor coverage .idea diff --git a/docs/_index.md b/docs/_index.md new file mode 100644 index 0000000..ed8a55e --- /dev/null +++ b/docs/_index.md @@ -0,0 +1,4 @@ +--- +packageName: Laravel Query Detector +githubUrl: https://github.com/beyondcode/laravel-query-detector +--- \ No newline at end of file diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..3559ca2 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,17 @@ +--- +title: Installation +order: 1 +--- +# Laravel N+1 Query Detector + +The Laravel N+1 query detector helps you to increase your application's performance by reducing the number of queries it executes. This package monitors your queries in real-time, while you develop your application and notify you when you should add eager loading (N+1 queries). + +# Installation + +You can install the package via composer: + +``` +composer require beyondcode/laravel-query-detector --dev +``` + +The package will automatically register itself. \ No newline at end of file diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000..be34cfd --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,92 @@ +--- +title: Usage +order: 2 +--- + +## Usage + +If you run your application in the `debug` mode, the query monitor will be automatically active. So there is nothing you have to do. + +By default, this package will display an `alert()` message to notify you about an N+1 query found in the current request. + +If you rather want this information to be written to your `laravel.log` file, written to your browser's console log as a warning or listed in a new tab for the [Laravel Debugbar (barryvdh/laravel-debugbar)](https://github.com/barryvdh/laravel-debugbar), you can publish the configuration and change the output behaviour (see example below). + +You can publish the package's configuration using this command: + +```bash +php artisan vendor:publish --provider="BeyondCode\QueryDetector\QueryDetectorServiceProvider" +``` + +This will add the `querydetector.php` file in your config directory with the following contents: + +```php +return [ + /* + * Enable or disable the query detection. + * If this is set to "null", the app.debug config value will be used. + */ + 'enabled' => env('QUERY_DETECTOR_ENABLED', null), + + /* + * Threshold level for the N+1 query detection. If a relation query will be + * executed more then this amount, the detector will notify you about it. + */ + 'threshold' => (int) env('QUERY_DETECTOR_THRESHOLD', 1), + + /* + * Here you can whitelist model relations. + * + * Right now, you need to define the model relation both as the class name and the attribute name on the model. + * So if an "Author" model would have a "posts" relation that points to a "Post" class, you need to add both + * the "posts" attribute and the "Post::class", since the relation can get resolved in multiple ways. + */ + 'except' => [ + //Author::class => [ + // Post::class, + // 'posts', + //] + ], + + /* + * Define the output format that you want to use. Multiple classes are supported. + * Available options are: + * + * Alert: + * Displays an alert on the website + * \BeyondCode\QueryDetector\Outputs\Alert::class + * + * Console: + * Writes the N+1 queries into your browsers console log + * \BeyondCode\QueryDetector\Outputs\Console::class + * + * Clockwork: (make sure you have the itsgoingd/clockwork package installed) + * Writes the N+1 queries warnings to Clockwork log + * \BeyondCode\QueryDetector\Outputs\Clockwork::class + * + * Debugbar: (make sure you have the barryvdh/laravel-debugbar package installed) + * Writes the N+1 queries into a custom messages collector of Debugbar + * \BeyondCode\QueryDetector\Outputs\Debugbar::class + * + * JSON: + * Writes the N+1 queries into the response body of your JSON responses + * \BeyondCode\QueryDetector\Outputs\Json::class + * + * Log: + * Writes the N+1 queries into the Laravel.log file + * \BeyondCode\QueryDetector\Outputs\Log::class + */ + 'output' => [ + \BeyondCode\QueryDetector\Outputs\Log::class, + \BeyondCode\QueryDetector\Outputs\Alert::class, + ] + +]; +``` + +If you use **Lumen**, you need to copy the config file manually and register the Lumen Service Provider in `bootstrap/app.php` file + +```php +$app->register(\BeyondCode\QueryDetector\LumenQueryDetectorServiceProvider::class); +``` + +If you need additional logic to run when the package detects unoptimized queries, you can listen to the `\BeyondCode\QueryDetector\Events\QueryDetected` event and write a listener to run your own handler. (e.g. send warning to Sentry/Bugsnag, send Slack notification, etc.) From d18e95bc093c261514a278f8a34c4b8879f7c59f Mon Sep 17 00:00:00 2001 From: Marcel Pociot Date: Wed, 3 Jun 2020 16:35:00 +0200 Subject: [PATCH 21/41] Update README.md --- README.md | 91 ++----------------------------------------------------- 1 file changed, 2 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index 88a85ca..e356d24 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,6 @@ The Laravel N+1 query detector helps you to increase your application's performa ![Example alert](https://beyondco.de/github/n+1/alert.png) -> If you want to learn how to create reusable PHP packages yourself, take a look at my upcoming [PHP Package Development](https://phppackagedevelopment.com) video course. - ## Installation @@ -22,95 +20,10 @@ composer require beyondcode/laravel-query-detector --dev The package will automatically register itself. -## Usage - -If you run your application in the `debug` mode, the query monitor will be automatically active. So there is nothing you have to do. - -By default, this package will display an `alert()` message to notify you about an N+1 query found in the current request. - -If you rather want this information to be written to your `laravel.log` file, written to your browser's console log as a warning or listed in a new tab for the [Laravel Debugbar (barryvdh/laravel-debugbar)](https://github.com/barryvdh/laravel-debugbar), you can publish the configuration and change the output behaviour (see example below). - -You can publish the package's configuration using this command: - -```bash -php artisan vendor:publish --provider="BeyondCode\QueryDetector\QueryDetectorServiceProvider" -``` - -This will add the `querydetector.php` file in your config directory with the following contents: - -```php - env('QUERY_DETECTOR_ENABLED', null), - - /* - * Threshold level for the N+1 query detection. If a relation query will be - * executed more then this amount, the detector will notify you about it. - */ - 'threshold' => (int) env('QUERY_DETECTOR_THRESHOLD', 1), - - /* - * Here you can whitelist model relations. - * - * Right now, you need to define the model relation both as the class name and the attribute name on the model. - * So if an "Author" model would have a "posts" relation that points to a "Post" class, you need to add both - * the "posts" attribute and the "Post::class", since the relation can get resolved in multiple ways. - */ - 'except' => [ - //Author::class => [ - // Post::class, - // 'posts', - //] - ], - - /* - * Define the output format that you want to use. Multiple classes are supported. - * Available options are: - * - * Alert: - * Displays an alert on the website - * \BeyondCode\QueryDetector\Outputs\Alert::class - * - * Console: - * Writes the N+1 queries into your browsers console log - * \BeyondCode\QueryDetector\Outputs\Console::class - * - * Clockwork: (make sure you have the itsgoingd/clockwork package installed) - * Writes the N+1 queries warnings to Clockwork log - * \BeyondCode\QueryDetector\Outputs\Clockwork::class - * - * Debugbar: (make sure you have the barryvdh/laravel-debugbar package installed) - * Writes the N+1 queries into a custom messages collector of Debugbar - * \BeyondCode\QueryDetector\Outputs\Debugbar::class - * - * JSON: - * Writes the N+1 queries into the response body of your JSON responses - * \BeyondCode\QueryDetector\Outputs\Json::class - * - * Log: - * Writes the N+1 queries into the Laravel.log file - * \BeyondCode\QueryDetector\Outputs\Log::class - */ - 'output' => [ - \BeyondCode\QueryDetector\Outputs\Log::class, - \BeyondCode\QueryDetector\Outputs\Alert::class, - ] - -]; -``` - -If you use **Lumen**, you need to copy the config file manually and register the Lumen Service Provider in `bootstrap/app.php` file +## Documentation -```php -$app->register(\BeyondCode\QueryDetector\LumenQueryDetectorServiceProvider::class); -``` +You can find the documentation on our [website](http://beyondco.de/docs/laravel-query-detector). -If you need additional logic to run when the package detects unoptimized queries, you can listen to the `\BeyondCode\QueryDetector\Events\QueryDetected` event and write a listener to run your own handler. (e.g. send warning to Sentry/Bugsnag, send Slack notification, etc.) ### Testing From d868a211f1254a775e41c69b57f3d351160b446b Mon Sep 17 00:00:00 2001 From: Gianluca Bine Date: Tue, 8 Sep 2020 20:29:17 -0300 Subject: [PATCH 22/41] Laravel 8 support --- composer.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 9db0a09..f7045f2 100644 --- a/composer.json +++ b/composer.json @@ -17,10 +17,11 @@ ], "require": { "php": "^7.1", - "illuminate/support": "^5.5 || ^6.0 || ^7.0" + "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0" }, "require-dev": { - "orchestra/testbench": "^3.0 || ^4.0 || ^5.0", + "laravel/legacy-factories": "^1.0", + "orchestra/testbench": "^3.0 || ^4.0 || ^5.0 || ^6.0", "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "autoload": { From eddeac684a1aadd874dff1b68f5bdefebde05977 Mon Sep 17 00:00:00 2001 From: matt trask Date: Thu, 10 Dec 2020 11:06:10 -0600 Subject: [PATCH 23/41] allow for query logger to write to different logs --- config/config.php | 9 ++++++++- src/Outputs/Log.php | 13 +++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/config/config.php b/config/config.php index e4a6e06..03f5ec7 100644 --- a/config/config.php +++ b/config/config.php @@ -6,7 +6,7 @@ * If this is set to "null", the app.debug config value will be used. */ 'enabled' => env('QUERY_DETECTOR_ENABLED', null), - + /* * Threshold level for the N+1 query detection. If a relation query will be * executed more then this amount, the detector will notify you about it. @@ -27,6 +27,13 @@ //] ], + /* + * Here you can set a specific log channel to write to + * in case you are trying to isolate queries or have a lot + * going on in the laravel.log. Defaults to laravel.log though. + */ + 'log_channel' => env('QUERY_DETECTOR_LOG_CHANNEL', 'daily'), + /* * Define the output format that you want to use. Multiple classes are supported. * Available options are: diff --git a/src/Outputs/Log.php b/src/Outputs/Log.php index 874b395..7563530 100644 --- a/src/Outputs/Log.php +++ b/src/Outputs/Log.php @@ -15,22 +15,27 @@ public function boot() public function output(Collection $detectedQueries, Response $response) { - LaravelLog::info('Detected N+1 Query'); + $this->log('Detected N+1 Query'); foreach ($detectedQueries as $detectedQuery) { $logOutput = 'Model: '.$detectedQuery['model'] . PHP_EOL; - + $logOutput .= 'Relation: '.$detectedQuery['relation'] . PHP_EOL; $logOutput .= 'Num-Called: '.$detectedQuery['count'] . PHP_EOL; - + $logOutput .= 'Call-Stack:' . PHP_EOL; foreach ($detectedQuery['sources'] as $source) { $logOutput .= '#'.$source->index.' '.$source->name.':'.$source->line . PHP_EOL; } - LaravelLog::info($logOutput); + $this->log($logOutput); } } + + private function log(string $message) + { + LaravelLog::channel(config('querydetector.log_channel'))->info($message); + } } From f8f3652b8b665f30fb8cf7c18016777bc1c07363 Mon Sep 17 00:00:00 2001 From: Liam O'Connor <65899150+liamjoc@users.noreply.github.com> Date: Sat, 6 Feb 2021 13:12:05 +0000 Subject: [PATCH 24/41] Update .scrutinizer.yml --- .scrutinizer.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.scrutinizer.yml b/.scrutinizer.yml index df16b68..7f6f12d 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -1,5 +1,12 @@ filter: excluded_paths: [tests/*] + +build: + nodes: + analysis: + tests: + override: + - php-scrutinizer-run checks: php: From 94fc4d747b1569b027d188dc6dd15ee98e9785a3 Mon Sep 17 00:00:00 2001 From: Liam O'Connor Date: Sat, 6 Feb 2021 13:29:28 +0000 Subject: [PATCH 25/41] support php 8 in ci --- .travis.yml | 12 ++++++++++++ composer.json | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ddfd84f..2eb3583 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ php: - 7.2 - 7.3 - 7.4 + - 8.0 env: - LARAVEL="^5.5" COMPOSER_FLAGS="--prefer-lowest" @@ -13,6 +14,8 @@ env: - LARAVEL="^6.0" COMPOSER_FLAGS="" - LARAVEL="^7.0" COMPOSER_FLAGS="--prefer-lowest" - LARAVEL="^7.0" COMPOSER_FLAGS="" + - LARAVEL="^8.0" COMPOSER_FLAGS="--prefer-lowest" + - LARAVEL="^8.0" COMPOSER_FLAGS="" matrix: exclude: @@ -24,11 +27,20 @@ matrix: env: LARAVEL="^7.0" COMPOSER_FLAGS="--prefer-lowest" - php: 7.1 env: LARAVEL="^7.0" COMPOSER_FLAGS="" + - php: 7.1 + env: LARAVEL="^8.0" COMPOSER_FLAGS="--prefer-lowest" + - php: 7.1 + env: LARAVEL="^8.0" COMPOSER_FLAGS="" allow_failures: - php: 7.4 env: LARAVEL="^5.5" COMPOSER_FLAGS="--prefer-lowest" - php: 7.4 env: LARAVEL="^6.0" COMPOSER_FLAGS="--prefer-lowest" + - php: 8.0 + env: LARAVEL="^5.5" COMPOSER_FLAGS="--prefer-lowest" + - php: 8.0 + env: LARAVEL="^6.0" COMPOSER_FLAGS="--prefer-lowest" + cache: directories: diff --git a/composer.json b/composer.json index f7045f2..efb3132 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": "^7.1", + "php": "^7.1 || ^8.0", "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0" }, "require-dev": { From 27a86e8860fce18b02ef52084d6aa8d0055708b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armando=20L=C3=BCscher?= Date: Wed, 23 Jun 2021 10:56:20 +0000 Subject: [PATCH 26/41] Add slashes to relation strings in console output --- src/Outputs/Console.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Outputs/Console.php b/src/Outputs/Console.php index 6b4680f..7a90366 100644 --- a/src/Outputs/Console.php +++ b/src/Outputs/Console.php @@ -42,10 +42,10 @@ protected function getOutputContent(Collection $detectedQueries) $output .= "console.warn('Found the following N+1 queries in this request:\\n\\n"; foreach ($detectedQueries as $detectedQuery) { $output .= "Model: ".addslashes($detectedQuery['model'])." => Relation: ".addslashes($detectedQuery['relation']); - $output .= " - You should add \"with(\'".$detectedQuery['relation']."\')\" to eager-load this relation."; + $output .= " - You should add \"with(\'".addslashes($detectedQuery['relation'])."\')\" to eager-load this relation."; $output .= "\\n\\n"; $output .= "Model: ".addslashes($detectedQuery['model'])."\\n"; - $output .= "Relation: ".$detectedQuery['relation']."\\n"; + $output .= "Relation: ".addslashes($detectedQuery['relation'])."\\n"; $output .= "Num-Called: ".$detectedQuery['count']."\\n"; $output .= "\\n"; $output .= 'Call-Stack:\\n'; From 330113bb34f7b5809db5ef3e92566a0549cc4f21 Mon Sep 17 00:00:00 2001 From: Gustiawan Ouwawi Date: Wed, 9 Feb 2022 13:54:04 +0700 Subject: [PATCH 27/41] Update composer.json --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index efb3132..46eb9e9 100644 --- a/composer.json +++ b/composer.json @@ -16,8 +16,8 @@ } ], "require": { - "php": "^7.1 || ^8.0", - "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0" + "php": "^8.0", + "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "require-dev": { "laravel/legacy-factories": "^1.0", From befd883de2eeffa8956d52018919da33428b8dae Mon Sep 17 00:00:00 2001 From: Gustiawan Ouwawi Date: Wed, 9 Feb 2022 17:17:35 +0700 Subject: [PATCH 28/41] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 46eb9e9..ceafd91 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": "^8.0", + "php": "^7.1 || ^8.0", "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "require-dev": { From 51aca02bc82d1a26457e08f693ef0ad7def2b4f1 Mon Sep 17 00:00:00 2001 From: Scott Zirkel Date: Wed, 21 Sep 2022 11:09:45 -0500 Subject: [PATCH 29/41] Update QueryDetector.php Return if no sources are found. --- src/QueryDetector.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/QueryDetector.php b/src/QueryDetector.php index 0d3dcc6..8deb29a 100755 --- a/src/QueryDetector.php +++ b/src/QueryDetector.php @@ -74,6 +74,10 @@ public function logQuery($query, Collection $backtrace) } $sources = $this->findSource($backtrace); + + if (empty($sources)) { + return; + } $key = md5($query->sql . $model . $relationName . $sources[0]->name . $sources[0]->line); From d12d3b05dd9adec949603d05084ce6cd73e1fb5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Vdovec?= Date: Tue, 11 Oct 2022 10:46:52 +0200 Subject: [PATCH 30/41] Fix typo - then -> than --- config/config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.php b/config/config.php index 03f5ec7..84f1765 100644 --- a/config/config.php +++ b/config/config.php @@ -9,7 +9,7 @@ /* * Threshold level for the N+1 query detection. If a relation query will be - * executed more then this amount, the detector will notify you about it. + * executed more than this amount, the detector will notify you about it. */ 'threshold' => (int) env('QUERY_DETECTOR_THRESHOLD', 1), From 60f0e5602315287c0f5bb9c8854fcda74f9999fc Mon Sep 17 00:00:00 2001 From: Shift Date: Mon, 30 Jan 2023 16:35:54 +0000 Subject: [PATCH 31/41] Bump dependencies for Laravel 10 --- composer.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index ceafd91..23ff06e 100644 --- a/composer.json +++ b/composer.json @@ -17,11 +17,11 @@ ], "require": { "php": "^7.1 || ^8.0", - "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0 || ^9.0|^10.0" }, "require-dev": { "laravel/legacy-factories": "^1.0", - "orchestra/testbench": "^3.0 || ^4.0 || ^5.0 || ^6.0", + "orchestra/testbench": "^3.0 || ^4.0 || ^5.0 || ^6.0|^8.0", "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "autoload": { @@ -37,7 +37,6 @@ "scripts": { "test": "vendor/bin/phpunit", "test-coverage": "vendor/bin/phpunit --coverage-html coverage" - }, "config": { "sort-packages": true From 5e0a19c30e4cb9ac2a56851264e0fedbbeb81649 Mon Sep 17 00:00:00 2001 From: Kewei Yan Date: Thu, 2 Feb 2023 09:51:38 +0800 Subject: [PATCH 32/41] Add empty queries feature --- .gitignore | 3 ++- src/QueryDetector.php | 5 +++++ tests/QueryDetectorTest.php | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 28367bb..219f39f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ composer.lock vendor coverage .idea -nbproject \ No newline at end of file +nbproject +.phpunit.result.cache diff --git a/src/QueryDetector.php b/src/QueryDetector.php index 0d3dcc6..2d31478 100755 --- a/src/QueryDetector.php +++ b/src/QueryDetector.php @@ -213,4 +213,9 @@ public function output($request, $response) return $response; } + + public function emptyQueries() + { + $this->queries = Collection::make(); + } } diff --git a/tests/QueryDetectorTest.php b/tests/QueryDetectorTest.php index b428e2a..97cf4ff 100644 --- a/tests/QueryDetectorTest.php +++ b/tests/QueryDetectorTest.php @@ -288,4 +288,27 @@ public function it_uses_the_trace_line_to_detect_queries() $this->assertSame(Author::class, $queries[0]['model']); $this->assertSame('profile', $queries[0]['relation']); } + + /** @test */ + public function it_empty_queries() + { + Route::get('/', function (){ + $authors = Author::all(); + + foreach ($authors as $author) { + $author->profile; + } + }); + + $this->get('/'); + + $queryDetector = app(QueryDetector::class); + + $queries = $queryDetector->getDetectedQueries(); + $this->assertCount(1, $queries); + + $queryDetector->emptyQueries(); + $queries = $queryDetector->getDetectedQueries(); + $this->assertCount(0, $queries); + } } From 4aa22690155dc96ee80271938ca919f0408fcef7 Mon Sep 17 00:00:00 2001 From: steve-moretz Date: Fri, 15 Sep 2023 17:36:02 +0330 Subject: [PATCH 33/41] Support multiple requests --- src/QueryDetector.php | 32 ++++++++++++++++++------- tests/QueryDetectorTest.php | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 8 deletions(-) diff --git a/src/QueryDetector.php b/src/QueryDetector.php index 0d3dcc6..4832a3b 100755 --- a/src/QueryDetector.php +++ b/src/QueryDetector.php @@ -14,15 +14,29 @@ class QueryDetector { /** @var Collection */ private $queries; + /** + * @var bool + */ + private $booted = false; - public function __construct() + private function resetQueries() { $this->queries = Collection::make(); } + public function __construct() + { + $this->resetQueries(); + } + public function boot() { - DB::listen(function($query) { + if ($this->booted) { + $this->resetQueries(); + return; + } + + DB::listen(function ($query) { $backtrace = collect(debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 50)); $this->logQuery($query, $backtrace); @@ -32,6 +46,8 @@ public function boot() app()->singleton($outputType); app($outputType)->boot(); } + + $this->booted = true; } public function isEnabled(): bool @@ -52,13 +68,13 @@ public function logQuery($query, Collection $backtrace) }); // The query is coming from an Eloquent model - if (! is_null($modelTrace)) { + if (!is_null($modelTrace)) { /* * Relations get resolved by either calling the "getRelationValue" method on the model, * or if the class itself is a Relation. */ $relation = $backtrace->first(function ($trace) { - return Arr::get($trace, 'function') === 'getRelationValue' || Arr::get($trace, 'class') === Relation::class ; + return Arr::get($trace, 'function') === 'getRelationValue' || Arr::get($trace, 'class') === Relation::class; }); // We try to access a relation @@ -77,8 +93,8 @@ public function logQuery($query, Collection $backtrace) $key = md5($query->sql . $model . $relationName . $sources[0]->name . $sources[0]->line); - $count = Arr::get($this->queries, $key.'.count', 0); - $time = Arr::get($this->queries, $key.'.time', 0); + $count = Arr::get($this->queries, $key . '.count', 0); + $time = Arr::get($this->queries, $key . '.time', 0); $this->queries[$key] = [ 'count' => ++$count, @@ -106,7 +122,7 @@ protected function findSource($stack) public function parseTrace($index, array $trace) { - $frame = (object) [ + $frame = (object)[ 'index' => $index, 'name' => null, 'line' => isset($trace['line']) ? $trace['line'] : '?', @@ -191,7 +207,7 @@ protected function getOutputTypes() { $outputTypes = config('querydetector.output'); - if (! is_array($outputTypes)) { + if (!is_array($outputTypes)) { $outputTypes = [$outputTypes]; } diff --git a/tests/QueryDetectorTest.php b/tests/QueryDetectorTest.php index b428e2a..b467d85 100644 --- a/tests/QueryDetectorTest.php +++ b/tests/QueryDetectorTest.php @@ -34,6 +34,54 @@ public function it_detects_n1_query_on_properties() $this->assertSame('profile', $queries[0]['relation']); } + /** @test */ + public function it_detects_n1_query_on_multiple_requests() + { + Route::get('/', function (){ + $authors = Author::get(); + + foreach ($authors as $author) { + $author->profile; + } + }); + + // first request + $this->get('/'); + $queries = app(QueryDetector::class)->getDetectedQueries(); + $this->assertCount(1, $queries); + $this->assertSame(Author::count(), $queries[0]['count']); + $this->assertSame(Author::class, $queries[0]['model']); + $this->assertSame('profile', $queries[0]['relation']); + + // second request + $this->get('/'); + $queries = app(QueryDetector::class)->getDetectedQueries(); + $this->assertCount(1, $queries); + $this->assertSame(Author::count(), $queries[0]['count']); + $this->assertSame(Author::class, $queries[0]['model']); + $this->assertSame('profile', $queries[0]['relation']); + } + + /** @test */ + public function it_does_not_detect_a_false_n1_query_on_multiple_requests() + { + Route::get('/', function (){ + $authors = Author::with("profile")->get(); + + foreach ($authors as $author) { + $author->profile; + } + }); + + // first request + $this->get('/'); + $this->assertCount(0, app(QueryDetector::class)->getDetectedQueries()); + + // second request + $this->get('/'); + $this->assertCount(0, app(QueryDetector::class)->getDetectedQueries()); + } + /** @test */ public function it_ignores_eager_loaded_relationships() { From 70d2888d46c94a148451a450bccf1bafbd7b6066 Mon Sep 17 00:00:00 2001 From: Shift Date: Fri, 1 Mar 2024 22:17:48 +0000 Subject: [PATCH 34/41] Bump dependencies for Laravel 11 --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 23ff06e..1ca8543 100644 --- a/composer.json +++ b/composer.json @@ -17,12 +17,12 @@ ], "require": { "php": "^7.1 || ^8.0", - "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0 || ^9.0|^10.0" + "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0 || ^9.0|^10.0 || ^11.0" }, "require-dev": { "laravel/legacy-factories": "^1.0", - "orchestra/testbench": "^3.0 || ^4.0 || ^5.0 || ^6.0|^8.0", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "orchestra/testbench": "^3.0 || ^4.0 || ^5.0 || ^6.0|^8.0 || ^9.0", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0 || ^10.5" }, "autoload": { "psr-4": { From a4c3b344f9156a2046752e2f19d6b55ec8173606 Mon Sep 17 00:00:00 2001 From: Di Date: Fri, 4 Oct 2024 16:44:11 +0200 Subject: [PATCH 35/41] Closes #43 --- src/QueryDetectorServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QueryDetectorServiceProvider.php b/src/QueryDetectorServiceProvider.php index 8d62987..4efac27 100644 --- a/src/QueryDetectorServiceProvider.php +++ b/src/QueryDetectorServiceProvider.php @@ -15,7 +15,7 @@ public function boot() if ($this->app->runningInConsole()) { $this->publishes([ __DIR__.'/../config/config.php' => config_path('querydetector.php'), - ], 'config'); + ], 'query-detector-config'); } $this->registerMiddleware(QueryDetectorMiddleware::class); From 761a16ceae579df226643e15e0b70f9c8e8a1e43 Mon Sep 17 00:00:00 2001 From: Di Date: Fri, 4 Oct 2024 18:12:18 +0200 Subject: [PATCH 36/41] Updated README --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index e356d24..dee3863 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # Laravel N+1 Query Detector [![Latest Version on Packagist](https://img.shields.io/packagist/v/beyondcode/laravel-query-detector.svg?style=flat-square)](https://packagist.org/packages/beyondcode/laravel-query-detector) -[![Build Status](https://img.shields.io/travis/beyondcode/laravel-query-detector/master.svg?style=flat-square)](https://travis-ci.org/beyondcode/laravel-query-detector) -[![Quality Score](https://img.shields.io/scrutinizer/g/beyondcode/laravel-query-detector.svg?style=flat-square)](https://scrutinizer-ci.com/g/beyondcode/laravel-query-detector) [![Total Downloads](https://img.shields.io/packagist/dt/beyondcode/laravel-query-detector.svg?style=flat-square)](https://packagist.org/packages/beyondcode/laravel-query-detector) The Laravel N+1 query detector helps you to increase your application's performance by reducing the number of queries it executes. This package monitors your queries in real-time, while you develop your application and notify you when you should add eager loading (N+1 queries). From b9dc996fb8fe4f6b17e803994a151d66bd39440f Mon Sep 17 00:00:00 2001 From: Di Date: Fri, 4 Oct 2024 18:14:29 +0200 Subject: [PATCH 37/41] Removed old CI files --- .scrutinizer.yml | 26 --------------------- .styleci.yml | 4 ---- .travis.yml | 60 ------------------------------------------------ 3 files changed, 90 deletions(-) delete mode 100644 .scrutinizer.yml delete mode 100644 .styleci.yml delete mode 100644 .travis.yml diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index 7f6f12d..0000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,26 +0,0 @@ -filter: - excluded_paths: [tests/*] - -build: - nodes: - analysis: - tests: - override: - - php-scrutinizer-run - -checks: - php: - remove_extra_empty_lines: true - remove_php_closing_tag: true - remove_trailing_whitespace: true - fix_use_statements: - remove_unused: true - preserve_multiple: false - preserve_blanklines: true - order_alphabetically: true - fix_php_opening_tag: true - fix_linefeed: true - fix_line_ending: true - fix_identation_4spaces: true - fix_doc_comments: true - diff --git a/.styleci.yml b/.styleci.yml deleted file mode 100644 index f4d3cbc..0000000 --- a/.styleci.yml +++ /dev/null @@ -1,4 +0,0 @@ -preset: laravel - -disabled: - - single_class_element_per_statement diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2eb3583..0000000 --- a/.travis.yml +++ /dev/null @@ -1,60 +0,0 @@ -language: php - -php: - - 7.1 - - 7.2 - - 7.3 - - 7.4 - - 8.0 - -env: - - LARAVEL="^5.5" COMPOSER_FLAGS="--prefer-lowest" - - LARAVEL="^5.5" COMPOSER_FLAGS="" - - LARAVEL="^6.0" COMPOSER_FLAGS="--prefer-lowest" - - LARAVEL="^6.0" COMPOSER_FLAGS="" - - LARAVEL="^7.0" COMPOSER_FLAGS="--prefer-lowest" - - LARAVEL="^7.0" COMPOSER_FLAGS="" - - LARAVEL="^8.0" COMPOSER_FLAGS="--prefer-lowest" - - LARAVEL="^8.0" COMPOSER_FLAGS="" - -matrix: - exclude: - - php: 7.1 - env: LARAVEL="^6.0" COMPOSER_FLAGS="--prefer-lowest" - - php: 7.1 - env: LARAVEL="^6.0" COMPOSER_FLAGS="" - - php: 7.1 - env: LARAVEL="^7.0" COMPOSER_FLAGS="--prefer-lowest" - - php: 7.1 - env: LARAVEL="^7.0" COMPOSER_FLAGS="" - - php: 7.1 - env: LARAVEL="^8.0" COMPOSER_FLAGS="--prefer-lowest" - - php: 7.1 - env: LARAVEL="^8.0" COMPOSER_FLAGS="" - allow_failures: - - php: 7.4 - env: LARAVEL="^5.5" COMPOSER_FLAGS="--prefer-lowest" - - php: 7.4 - env: LARAVEL="^6.0" COMPOSER_FLAGS="--prefer-lowest" - - php: 8.0 - env: LARAVEL="^5.5" COMPOSER_FLAGS="--prefer-lowest" - - php: 8.0 - env: LARAVEL="^6.0" COMPOSER_FLAGS="--prefer-lowest" - - -cache: - directories: - - $HOME/.composer/cache/files - -before_install: - - echo "memory_limit=2G" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - -install: - - travis_retry composer require laravel/framework:${LARAVEL} --no-interaction --prefer-dist - - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-dist - -script: - - vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover - -after_script: - - php vendor/bin/ocular code-coverage:upload --format=php-clover coverage.clover From a6989b0a8b59bd5f8587919f332eedab9a8c0a45 Mon Sep 17 00:00:00 2001 From: Shift Date: Mon, 17 Feb 2025 01:59:14 +0000 Subject: [PATCH 38/41] Bump dependencies for Laravel 12 --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 1ca8543..e6da0e9 100644 --- a/composer.json +++ b/composer.json @@ -17,12 +17,12 @@ ], "require": { "php": "^7.1 || ^8.0", - "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0 || ^9.0|^10.0 || ^11.0" + "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0 || ^9.0|^10.0 || ^11.0 || ^12.0" }, "require-dev": { "laravel/legacy-factories": "^1.0", - "orchestra/testbench": "^3.0 || ^4.0 || ^5.0 || ^6.0|^8.0 || ^9.0", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0 || ^10.5" + "orchestra/testbench": "^3.0 || ^4.0 || ^5.0 || ^6.0|^8.0 || ^9.0 || ^10.0", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0 || ^10.5 || ^11.5.3" }, "autoload": { "psr-4": { From 387dfbd64b0dc92f16005a70ea407e8012b8e314 Mon Sep 17 00:00:00 2001 From: Diana Scharf Date: Tue, 11 Mar 2025 10:30:13 +0100 Subject: [PATCH 39/41] Updated phpunit.xml --- phpunit.xml.dist | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 1eef57c..5119f0b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,12 +1,7 @@ @@ -14,16 +9,4 @@ tests - - - src/ - - - - - - - - - From 2ed0bb5660f459c87156076bfbcd7d9b0dc4b530 Mon Sep 17 00:00:00 2001 From: Diana Scharf Date: Tue, 11 Mar 2025 10:30:28 +0100 Subject: [PATCH 40/41] Workflow --- .github/workflows/tests.yml | 71 +++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..cd7da98 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,71 @@ +name: run-tests + +on: + push: + branches: + - master + - dev + pull_request: + branches: + - master + +jobs: + php-tests: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + php: ['8.4', '8.3', '8.2', '8.1', '8.0'] + laravel: ['8.*', '9.*', '10.*', '11.*', '12.*'] + dependency-version: [prefer-stable] + exclude: + - php: 8.0 + laravel: 10.* + - php: 8.0 + laravel: 11.* + - php: 8.0 + laravel: 12.* + - php: 8.1 + laravel: 11.* + - php: 8.1 + laravel: 12.* + - php: 8.2 + laravel: 8.* + - php: 8.3 + laravel: 8.* + - php: 8.4 + laravel: 8.* + include: + - laravel: 8.* + testbench: 6.23 + - laravel: 9.* + testbench: 7.* + - laravel: 10.* + testbench: 8.* + - laravel: 11.* + testbench: 9.* + - laravel: 12.* + testbench: 10.* + + + name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} - ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick + coverage: none + + - name: Install dependencies + run: | + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update + composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction + + - name: Execute tests + run: vendor/bin/phpunit \ No newline at end of file From ac1506d18f4133a76007f987983053ae6befa4ac Mon Sep 17 00:00:00 2001 From: Diana Scharf Date: Tue, 11 Mar 2025 10:33:20 +0100 Subject: [PATCH 41/41] Workflow --- .github/workflows/tests.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cd7da98..62d0391 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -34,8 +34,12 @@ jobs: laravel: 8.* - php: 8.3 laravel: 8.* + - php: 8.3 + laravel: 9.* - php: 8.4 laravel: 8.* + - php: 8.4 + laravel: 9.* include: - laravel: 8.* testbench: 6.23 @@ -48,7 +52,6 @@ jobs: - laravel: 12.* testbench: 10.* - name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} - ubuntu-latest steps: