Skip to content

Commit

Permalink
Merge branch 'master' of github.com:beyondcode/laravel-query-detector
Browse files Browse the repository at this point in the history
  • Loading branch information
mpociot committed Jul 18, 2018
2 parents 308eba2 + d3763f5 commit b2b58c3
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 11 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ composer.lock
docs
vendor
coverage
.idea
.idea
nbproject
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

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).

![Example alert](https://beyondco.de/github/n+1/alert.png)
![Example alert](https://beyondco.de/github/n+1/alert.png)

## Installation

Expand Down Expand Up @@ -42,7 +42,7 @@ return [
* 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.
Expand All @@ -64,7 +64,7 @@ return [
],

/*
* Define the output format that you want to use.
* Define the output format that you want to use. Multiple classes are supported
* Available options are:
*
* Alert:
Expand All @@ -75,11 +75,19 @@ return [
* Writes the N+1 queries into the Laravel.log file
* \BeyondCode\QueryDetector\Outputs\Log::class
*/
'output' => \BeyondCode\QueryDetector\Outputs\Alert::class,
'output' => [
\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
$this->app->register(\BeyondCode\QueryDetector\LumenQueryDetectorServiceProvider::class);
```

### Testing

``` bash
Expand Down
14 changes: 10 additions & 4 deletions config/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,23 @@
],

/*
* Define the output format that you want to use.
* Define the output formats that you want to use.
* Available options are:
*
* Alert:
* Displays an alert on the website
* \BeyondCode\QueryDetector\Outputs\Alert::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
*
* Log:
* Writes the N+1 queries into the Laravel.log file
* \BeyondCode\QueryDetector\Outputs\Log::class
*/
'output' => \BeyondCode\QueryDetector\Outputs\Alert::class,

];
'output' => [
\BeyondCode\QueryDetector\Outputs\Log::class,
\BeyondCode\QueryDetector\Outputs\Alert::class,
]
];
21 changes: 21 additions & 0 deletions src/LumenQueryDetectorServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php
namespace BeyondCode\QueryDetector;

use Illuminate\Support\ServiceProvider;

class LumenQueryDetectorServiceProvider extends ServiceProvider
{

public function register()
{
$this->app->configure('querydetector');
$this->mergeConfigFrom(__DIR__ . '/../config/config.php', 'querydetector');

$this->app->middleware([
QueryDetectorMiddleware::class
]);

$this->app->singleton(QueryDetector::class);
$this->app->alias(QueryDetector::class, 'querydetector');
}
}
38 changes: 38 additions & 0 deletions src/Outputs/Console.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php
namespace BeyondCode\QueryDetector\Outputs;
use Illuminate\Support\Collection;
use Symfony\Component\HttpFoundation\Response;

class Console implements Output
{
public function output(Collection $detectedQueries, Response $response)
{
if ($response->isRedirection()) {
return;
}
$content = $response->getContent();
$outputContent = $this->getOutputContent($detectedQueries);
$pos = strripos($content, '</body>');
if (false !== $pos) {
$content = substr($content, 0, $pos) . $outputContent . substr($content, $pos);
} else {
$content = $content . $outputContent;
}
// Update the new content and reset the content length
$response->setContent($content);
$response->headers->remove('Content-Length');
}
protected function getOutputContent(Collection $detectedQueries)
{
$output = '<script type="text/javascript">';
$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 .= "\\n";
}
$output .= "')";
$output .= '</script>';
return $output;
}
}
27 changes: 27 additions & 0 deletions src/Outputs/Debugbar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace BeyondCode\QueryDetector\Outputs;

use Illuminate\Support\Collection;
use Symfony\Component\HttpFoundation\Response;

use Debugbar as LaravelDebugbar;
use DebugBar\DataCollector\MessagesCollector;

class Debugbar implements Output
{
public function output(Collection $detectedQueries, Response $response)
{
$collector = new MessagesCollector('N+1 Queries');

foreach ($detectedQueries as $detectedQuery) {
$collector->addMessage(sprintf('Model: %s => Relation: %s - You should add with(%s) to eager-load this relation.',
$detectedQuery['model'],
$detectedQuery['relation'],
$detectedQuery['relation']
));
}

LaravelDebugbar::addCollector($collector);
}
}
11 changes: 9 additions & 2 deletions src/QueryDetector.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,15 @@ public function getDetectedQueries(): Collection

protected function applyOutput(Response $response)
{
$outputType = app(config('querydetector.output'));
$outputType->output($this->getDetectedQueries(), $response);
$outputTypes = app(config('querydetector.output'));

if (! is_array($outputTypes)) {
$types = [$outputTypes];
}

foreach ($outputTypes as $type) {
$type->output($this->getDetectedQueries(), $response);
}
}

public function output($request, $response)
Expand Down

0 comments on commit b2b58c3

Please sign in to comment.