Skip to content

Commit

Permalink
[WebProfilerBundle] Try to display the most useful panel by default
Browse files Browse the repository at this point in the history
  • Loading branch information
fancyweb committed Oct 2, 2019
1 parent d4f3b68 commit a45dd98
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 10 deletions.
Expand Up @@ -17,6 +17,8 @@
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag;
use Symfony\Component\HttpKernel\DataCollector\DumpDataCollector;
use Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Profiler\Profiler;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
Expand Down Expand Up @@ -78,7 +80,7 @@ public function panelAction(Request $request, $token)
$this->cspHandler->disableCsp();
}

$panel = $request->query->get('panel', 'request');
$panel = $request->query->get('panel');
$page = $request->query->get('page', 'home');

if ('latest' === $token && $latest = current($this->profiler->find(null, null, 1, null, null, null))) {
Expand All @@ -89,6 +91,22 @@ public function panelAction(Request $request, $token)
return new Response($this->twig->render('@WebProfiler/Profiler/info.html.twig', ['about' => 'no_token', 'token' => $token, 'request' => $request]), 200, ['Content-Type' => 'text/html']);
}

if (null === $panel) {
$panel = 'request';

foreach ($profile->getCollectors() as $collector) {
if ($collector instanceof ExceptionDataCollector && $collector->hasException()) {
$panel = $collector->getName();

break;
}

if ($collector instanceof DumpDataCollector && $collector->getDumpsCount() > 0) {
$panel = $collector->getName();
}
}
}

if (!$profile->hasCollector($panel)) {
throw new NotFoundHttpException(sprintf('Panel "%s" is not available for token "%s".', $panel, $token));
}
Expand Down
Expand Up @@ -267,7 +267,7 @@
if (request.profilerUrl) {
profilerCell.textContent = '';
var profilerLink = document.createElement('a');
profilerLink.setAttribute('href', request.statusCode < 400 ? request.profilerUrl : request.profilerUrl + '?panel=exception');
profilerLink.setAttribute('href', request.profilerUrl);
profilerLink.textContent = request.profile;
profilerCell.appendChild(profilerLink);
}
Expand Down
Expand Up @@ -15,8 +15,16 @@
use Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController;
use Symfony\Bundle\WebProfilerBundle\Csp\ContentSecurityPolicyHandler;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DumpDataCollector;
use Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector;
use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Profiler\Profile;
use Symfony\Component\HttpKernel\Profiler\Profiler;
use Twig\Environment;
use Twig\Loader\LoaderInterface;
use Twig\Loader\SourceContextLoaderInterface;

class ProfilerControllerTest extends TestCase
{
Expand Down Expand Up @@ -185,17 +193,107 @@ public function provideCspVariants()
];
}

private function createController($profiler, $twig, $withCSP): ProfilerController
/**
* @dataProvider defaultPanelProvider
*/
public function testDefaultPanel(string $expectedPanel, Profile $profile)
{
$profiler = $this->createMock(Profiler::class);
$profiler
->expects($this->atLeastOnce())
->method('loadProfile')
->with($profile->getToken())
->willReturn($profile);

$profiler
->expects($this->atLeastOnce())
->method('has')
->with($this->logicalXor($collectorsNames = array_keys($profile->getCollectors())))
->willReturn(true);

$expectedTemplate = 'expected_template.html.twig';

if (Environment::MAJOR_VERSION > 1) {
$loader = $this->createMock(LoaderInterface::class);
$loader
->expects($this->atLeastOnce())
->method('exists')
->with($this->logicalXor($expectedTemplate, 'other_template.html.twig'))
->willReturn(true);
} else {
$loader = $this->createMock(SourceContextLoaderInterface::class);
}

$twig = $this->createMock(Environment::class);
$twig
->expects($this->atLeastOnce())
->method('getLoader')
->willReturn($loader);
$twig
->expects($this->once())
->method('render')
->with($expectedTemplate);

$this
->createController($profiler, $twig, false, array_map(function (string $collectorName) use ($expectedPanel, $expectedTemplate): array {
if ($collectorName === $expectedPanel) {
return [$expectedPanel, $expectedTemplate];
}

return [$collectorName, 'other_template.html.twig'];
}, $collectorsNames))
->panelAction(new Request(), $profile->getToken());
}

public function defaultPanelProvider(): \Generator
{
// Test default behavior
$profile = new Profile('xxxxxx');
$profile->addCollector($requestDataCollector = new RequestDataCollector());
yield [$requestDataCollector->getName(), $profile];

// Test exception
$profile = new Profile('xxxxxx');
$profile->addCollector($exceptionDataCollector = new ExceptionDataCollector());
$exceptionDataCollector->collect(new Request(), new Response(), new \DomainException());
yield [$exceptionDataCollector->getName(), $profile];

// Test exception priority
$dumpDataCollector = $this->createMock(DumpDataCollector::class);
$dumpDataCollector
->expects($this->atLeastOnce())
->method('getName')
->willReturn('dump');
$dumpDataCollector
->expects($this->atLeastOnce())
->method('getDumpsCount')
->willReturn(1);
$profile = new Profile('xxxxxx');
$profile->setCollectors([$exceptionDataCollector, $dumpDataCollector]);
yield [$exceptionDataCollector->getName(), $profile];

// Test exception priority when defined afterwards
$profile = new Profile('xxxxxx');
$profile->setCollectors([$dumpDataCollector, $exceptionDataCollector]);
yield [$exceptionDataCollector->getName(), $profile];

// Test dump
$profile = new Profile('xxxxxx');
$profile->addCollector($dumpDataCollector);
yield [$dumpDataCollector->getName(), $profile];
}

private function createController($profiler, $twig, $withCSP, array $templates = []): ProfilerController
{
$urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock();

if ($withCSP) {
$nonceGenerator = $this->getMockBuilder('Symfony\Bundle\WebProfilerBundle\Csp\NonceGenerator')->getMock();
$nonceGenerator->method('generate')->willReturn('dummy_nonce');

return new ProfilerController($urlGenerator, $profiler, $twig, [], new ContentSecurityPolicyHandler($nonceGenerator));
return new ProfilerController($urlGenerator, $profiler, $twig, $templates, new ContentSecurityPolicyHandler($nonceGenerator));
}

return new ProfilerController($urlGenerator, $profiler, $twig, []);
return new ProfilerController($urlGenerator, $profiler, $twig, $templates);
}
}
Expand Up @@ -15,7 +15,8 @@
use Symfony\Bundle\WebProfilerBundle\Tests\TestCase;
use Symfony\Component\HttpKernel\Profiler\Profile;
use Twig\Environment;
use Twig\Source;
use Twig\Loader\LoaderInterface;
use Twig\Loader\SourceContextLoaderInterface;

/**
* Test for TemplateManager class.
Expand Down Expand Up @@ -104,11 +105,14 @@ protected function mockTwigEnvironment()
{
$this->twigEnvironment = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock();

if (interface_exists('Twig\Loader\SourceContextLoaderInterface')) {
$loader = $this->getMockBuilder('Twig\Loader\SourceContextLoaderInterface')->getMock();
if (Environment::MAJOR_VERSION > 1) {
$loader = $this->createMock(LoaderInterface::class);
$loader
->expects($this->any())
->method('exists')
->willReturn(true);
} else {
$loader = $this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock();
$loader->method('getSourceContext')->willReturn(new Source('source-code', 'source-name'));
$loader = $this->createMock(SourceContextLoaderInterface::class);
}

$this->twigEnvironment->expects($this->any())->method('getLoader')->willReturn($loader);
Expand Down

0 comments on commit a45dd98

Please sign in to comment.