Skip to content

Commit a0079a4

Browse files
committed
[WebProfilerBundle] Try to display the most useful panel by default
1 parent d4f3b68 commit a0079a4

File tree

4 files changed

+128
-10
lines changed

4 files changed

+128
-10
lines changed

src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php

+19-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
use Symfony\Component\HttpFoundation\Request;
1818
use Symfony\Component\HttpFoundation\Response;
1919
use Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag;
20+
use Symfony\Component\HttpKernel\DataCollector\DumpDataCollector;
21+
use Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector;
2022
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
2123
use Symfony\Component\HttpKernel\Profiler\Profiler;
2224
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
@@ -78,7 +80,7 @@ public function panelAction(Request $request, $token)
7880
$this->cspHandler->disableCsp();
7981
}
8082

81-
$panel = $request->query->get('panel', 'request');
83+
$panel = $request->query->get('panel');
8284
$page = $request->query->get('page', 'home');
8385

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

94+
if (null === $panel) {
95+
$panel = 'request';
96+
97+
foreach ($profile->getCollectors() as $collector) {
98+
if ($collector instanceof ExceptionDataCollector && $collector->hasException()) {
99+
$panel = $collector->getName();
100+
101+
break;
102+
}
103+
104+
if ($collector instanceof DumpDataCollector && $collector->getDumpsCount() > 0) {
105+
$panel = $collector->getName();
106+
}
107+
}
108+
}
109+
92110
if (!$profile->hasCollector($panel)) {
93111
throw new NotFoundHttpException(sprintf('Panel "%s" is not available for token "%s".', $panel, $token));
94112
}

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig

+1-1
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@
267267
if (request.profilerUrl) {
268268
profilerCell.textContent = '';
269269
var profilerLink = document.createElement('a');
270-
profilerLink.setAttribute('href', request.statusCode < 400 ? request.profilerUrl : request.profilerUrl + '?panel=exception');
270+
profilerLink.setAttribute('href', request.profilerUrl);
271271
profilerLink.textContent = request.profile;
272272
profilerCell.appendChild(profilerLink);
273273
}

src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php

+99-3
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,16 @@
1515
use Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController;
1616
use Symfony\Bundle\WebProfilerBundle\Csp\ContentSecurityPolicyHandler;
1717
use Symfony\Component\HttpFoundation\Request;
18+
use Symfony\Component\HttpFoundation\Response;
19+
use Symfony\Component\HttpKernel\DataCollector\DumpDataCollector;
20+
use Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector;
21+
use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector;
1822
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
1923
use Symfony\Component\HttpKernel\Profiler\Profile;
24+
use Symfony\Component\HttpKernel\Profiler\Profiler;
25+
use Twig\Environment;
26+
use Twig\Loader\LoaderInterface;
27+
use Twig\Loader\SourceContextLoaderInterface;
2028

2129
class ProfilerControllerTest extends TestCase
2230
{
@@ -185,17 +193,105 @@ public function provideCspVariants()
185193
];
186194
}
187195

188-
private function createController($profiler, $twig, $withCSP): ProfilerController
196+
/**
197+
* @dataProvider defaultPanelProvider
198+
*/
199+
public function testDefaultPanel(string $expectedPanel, Profile $profile)
200+
{
201+
$profiler = $this->createMock(Profiler::class);
202+
$profiler
203+
->expects($this->atLeastOnce())
204+
->method('loadProfile')
205+
->with($profile->getToken())
206+
->willReturn($profile);
207+
208+
$profiler
209+
->expects($this->atLeastOnce())
210+
->method('has')
211+
->with($this->logicalXor($collectorsNames = array_keys($profile->getCollectors())))
212+
->willReturn(true);
213+
214+
if (Environment::MAJOR_VERSION > 1) {
215+
$loader = $this->createMock(LoaderInterface::class);
216+
$loader
217+
->expects($this->atLeastOnce())
218+
->method('exists')
219+
->with($this->logicalXor($expectedTemplate = 'expected_template.html.twig', 'other_template.html.twig'))
220+
->willReturn(true);
221+
} else {
222+
$loader = $this->createMock(SourceContextLoaderInterface::class);
223+
}
224+
225+
$twig = $this->createMock(Environment::class);
226+
$twig
227+
->expects($this->atLeastOnce())
228+
->method('getLoader')
229+
->willReturn($loader);
230+
$twig
231+
->expects($this->once())
232+
->method('render')
233+
->with($expectedTemplate);
234+
235+
$this
236+
->createController($profiler, $twig, false, array_map(function (string $collectorName) use ($expectedPanel, $expectedTemplate): array {
237+
if ($collectorName === $expectedPanel) {
238+
return [$expectedPanel, $expectedTemplate];
239+
}
240+
241+
return [$collectorName, 'other_template.html.twig'];
242+
}, $collectorsNames))
243+
->panelAction(new Request(), $profile->getToken());
244+
}
245+
246+
public function defaultPanelProvider(): \Generator
247+
{
248+
// Test default behavior
249+
$profile = new Profile('xxxxxx');
250+
$profile->addCollector($requestDataCollector = new RequestDataCollector());
251+
yield [$requestDataCollector->getName(), $profile];
252+
253+
// Test exception
254+
$profile = new Profile('xxxxxx');
255+
$profile->addCollector($exceptionDataCollector = new ExceptionDataCollector());
256+
$exceptionDataCollector->collect(new Request(), new Response(), new \DomainException());
257+
yield [$exceptionDataCollector->getName(), $profile];
258+
259+
// Test exception priority
260+
$dumpDataCollector = $this->createMock(DumpDataCollector::class);
261+
$dumpDataCollector
262+
->expects($this->atLeastOnce())
263+
->method('getName')
264+
->willReturn('dump');
265+
$dumpDataCollector
266+
->expects($this->atLeastOnce())
267+
->method('getDumpsCount')
268+
->willReturn(1);
269+
$profile = new Profile('xxxxxx');
270+
$profile->setCollectors([$exceptionDataCollector, $dumpDataCollector]);
271+
yield [$exceptionDataCollector->getName(), $profile];
272+
273+
// Test exception priority when defined afterwards
274+
$profile = new Profile('xxxxxx');
275+
$profile->setCollectors([$dumpDataCollector, $exceptionDataCollector]);
276+
yield [$exceptionDataCollector->getName(), $profile];
277+
278+
// Test dump
279+
$profile = new Profile('xxxxxx');
280+
$profile->addCollector($dumpDataCollector);
281+
yield [$dumpDataCollector->getName(), $profile];
282+
}
283+
284+
private function createController($profiler, $twig, $withCSP, array $templates = []): ProfilerController
189285
{
190286
$urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock();
191287

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

196-
return new ProfilerController($urlGenerator, $profiler, $twig, [], new ContentSecurityPolicyHandler($nonceGenerator));
292+
return new ProfilerController($urlGenerator, $profiler, $twig, $templates, new ContentSecurityPolicyHandler($nonceGenerator));
197293
}
198294

199-
return new ProfilerController($urlGenerator, $profiler, $twig, []);
295+
return new ProfilerController($urlGenerator, $profiler, $twig, $templates);
200296
}
201297
}

src/Symfony/Bundle/WebProfilerBundle/Tests/Profiler/TemplateManagerTest.php

+9-5
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
use Symfony\Bundle\WebProfilerBundle\Tests\TestCase;
1616
use Symfony\Component\HttpKernel\Profiler\Profile;
1717
use Twig\Environment;
18-
use Twig\Source;
18+
use Twig\Loader\LoaderInterface;
19+
use Twig\Loader\SourceContextLoaderInterface;
1920

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

107-
if (interface_exists('Twig\Loader\SourceContextLoaderInterface')) {
108-
$loader = $this->getMockBuilder('Twig\Loader\SourceContextLoaderInterface')->getMock();
108+
if (Environment::MAJOR_VERSION > 1) {
109+
$loader = $this->createMock(LoaderInterface::class);
110+
$loader
111+
->expects($this->any())
112+
->method('exists')
113+
->willReturn(true);
109114
} else {
110-
$loader = $this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock();
111-
$loader->method('getSourceContext')->willReturn(new Source('source-code', 'source-name'));
115+
$loader = $this->createMock(SourceContextLoaderInterface::class);
112116
}
113117

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

0 commit comments

Comments
 (0)