Skip to content

Commit 536a6cd

Browse files
committed
feature symfony#17589 [3.1] [WebProfilerBundle] [DX] Feature allow forward and redirection detection in wdt (HeahDude)
This PR was merged into the 3.1-dev branch. Discussion ---------- [3.1] [WebProfilerBundle] [DX] Feature allow forward and redirection detection in wdt | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | symfony#14358, symfony#17501 | License | MIT | Doc PR | ? This PR allows to : - track explicit forward from `\Symfony\Bundle\FrameWorkBundle\Controller\Controller` in the web debug toolbar. - or pass a request attribute `_forwarded` with the current request attributes (an instance of `ParameterBag`) as value to your sub request before handling it. - see if you've been redirected (require session enabled) When redirected you will see the name of the route (if any) and a link to the profile of the original request. ![redirect](https://cloud.githubusercontent.com/assets/10107633/12716952/9aacdcba-c8e4-11e5-9a64-d26fe27f1cae.jpg) In case of forwarding, the name of the controller is a file link and next to it there is a direct link to the profile of the sub request. ![forward](https://cloud.githubusercontent.com/assets/10107633/12716968/ba6b1fbc-c8e4-11e5-85fc-7f71969cb372.jpg) This works pretty well in __Silex__ too by registering `SessionServiceProvider()` for redirections or by providing this method for forwarding : ```php class App extends \Silex\Application // (php7 bootstrap) $app = new class extends \Silex\Application { { public function forward($controller, array $path = array(), array $query = array() { if (!$this->booted) { throw new LogicException(sprintf('Method %s must be called from a controller.', __METHOD__)); } $this->flush(); $request = $this['request_stack']->getCurrentRequest(); $path['_forwarded'] = $request->attributes; $path['_controller'] = $controller; $subRequest = $request->duplicate($query, null, $path); return $this['kernel']->handle($subRequest, HttpKernelInterface::SUB_REQUEST); } } ``` Commits ------- 0a0e8af [WebProfilerBundle] show the http method in wdt if not 'GET' 4f020b5 [FrameworkBundle] Extends the RequestDataCollector 227ac77 [WebProfilerBundle] [FrameworkBundle] profile forward controller action 0a1b284 [WebProfiler] [HttpKernel] profile redirections
2 parents facb21e + 0a0e8af commit 536a6cd

File tree

11 files changed

+372
-88
lines changed

11 files changed

+372
-88
lines changed

src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,10 @@ protected function generateUrl($route, $parameters = array(), $referenceType = U
6565
*/
6666
protected function forward($controller, array $path = array(), array $query = array())
6767
{
68+
$request = $this->container->get('request_stack')->getCurrentRequest();
69+
$path['_forwarded'] = $request->attributes;
6870
$path['_controller'] = $controller;
69-
$subRequest = $this->container->get('request_stack')->getCurrentRequest()->duplicate($query, null, $path);
71+
$subRequest = $request->duplicate($query, null, $path);
7072

7173
return $this->container->get('http_kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
7274
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\DataCollector;
13+
14+
use Symfony\Component\HttpFoundation\ParameterBag;
15+
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\HttpFoundation\Response;
17+
use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector as BaseRequestCollector;
18+
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
19+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
20+
21+
/**
22+
* RequestDataCollector.
23+
*
24+
* @author Jules Pietri <[email protected]>
25+
*/
26+
class RequestDataCollector extends BaseRequestCollector implements EventSubscriberInterface
27+
{
28+
/**
29+
* {@inheritdoc}
30+
*/
31+
public function collect(Request $request, Response $response, \Exception $exception = null)
32+
{
33+
parent::collect($request, $response, $exception);
34+
35+
if ($parentRequestAttributes = $request->attributes->get('_forwarded')) {
36+
if ($parentRequestAttributes instanceof ParameterBag) {
37+
$parentRequestAttributes->set('_forward_token', $response->headers->get('x-debug-token'));
38+
}
39+
}
40+
if ($request->attributes->has('_forward_controller')) {
41+
$this->data['forward'] = array(
42+
'token' => $request->attributes->get('_forward_token'),
43+
'controller' => $this->parseController($request->attributes->get('_forward_controller')),
44+
);
45+
}
46+
}
47+
48+
/**
49+
* Gets the parsed forward controller.
50+
*
51+
* @return array|bool An array with keys 'token' the forward profile token, and
52+
* 'controller' the parsed forward controller, false otherwise
53+
*/
54+
public function getForward()
55+
{
56+
return isset($this->data['forward']) ? $this->data['forward'] : false;
57+
}
58+
59+
public function onKernelController(FilterControllerEvent $event)
60+
{
61+
$this->controllers[$event->getRequest()] = $event->getController();
62+
63+
if ($parentRequestAttributes = $event->getRequest()->attributes->get('_forwarded')) {
64+
if ($parentRequestAttributes instanceof ParameterBag) {
65+
$parentRequestAttributes->set('_forward_controller', $event->getController());
66+
}
67+
}
68+
}
69+
70+
/**
71+
* {@inheritdoc}
72+
*/
73+
public function getName()
74+
{
75+
return 'request';
76+
}
77+
}

src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<call method="setKernel"><argument type="service" id="kernel" on-invalid="ignore" /></call>
1111
</service>
1212

13-
<service id="data_collector.request" class="Symfony\Component\HttpKernel\DataCollector\RequestDataCollector">
13+
<service id="data_collector.request" class="Symfony\Bundle\FrameworkBundle\DataCollector\RequestDataCollector">
1414
<tag name="kernel.event_subscriber" />
1515
<tag name="data_collector" template="@WebProfiler/Collector/request.html.twig" id="request" priority="335" />
1616
</service>

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig

Lines changed: 92 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,99 @@
22

33
{% block toolbar %}
44
{% set request_handler %}
5-
{% if collector.controller.class is defined %}
6-
{% set link = collector.controller.file|file_link(collector.controller.line) %}
7-
{% if link %}<a href="{{ link }}" title="{{ collector.controller.file }}">{% else %}<span>{% endif %}
5+
{% import _self as helper %}
6+
{{ helper.set_handler(collector.controller) }}
7+
{% endset %}
88

9-
{{ collector.controller.class|abbr_class|striptags }}
9+
{% if collector.redirect %}
10+
{% set redirect_handler %}
11+
{% import _self as helper %}
12+
{{ helper.set_handler(collector.redirect.controller, collector.redirect.route, 'GET' != collector.redirect.method ? collector.redirect.method) }}
13+
{% endset %}
14+
{% endif %}
1015

11-
{%- if collector.controller.method -%}
12-
&nbsp;::&nbsp;{{ collector.controller.method }}
13-
{%- endif -%}
14-
15-
{% if link %}</a>{% else %}</span>{% endif %}
16-
{% else %}
17-
<span>{{ collector.controller }}</span>
18-
{% endif %}
19-
{% endset %}
16+
{% if collector.forward %}
17+
{% set forward_handler %}
18+
{% import _self as helper %}
19+
{{ helper.set_handler(collector.forward.controller) }}
20+
{% endset %}
21+
{% endif %}
2022

2123
{% set request_status_code_color = (collector.statuscode >= 400) ? 'red' : (collector.statuscode >= 300) ? 'yellow' : 'green' %}
2224

2325
{% set icon %}
2426
<span class="sf-toolbar-status sf-toolbar-status-{{ request_status_code_color }}">{{ collector.statuscode }}</span>
2527
{% if collector.route %}
26-
<span class="sf-toolbar-label">@</span>
28+
{% if collector.redirect %}{{ include('@WebProfiler/Icon/redirect.svg') }}{% endif %}
29+
{% if collector.forward %}{{ include('@WebProfiler/Icon/forward.svg') }}{% endif %}
30+
<span class="sf-toolbar-label">{{ 'GET' != collector.method ? collector.method }} @</span>
2731
<span class="sf-toolbar-value sf-toolbar-info-piece-additional">{{ collector.route }}</span>
2832
{% endif %}
2933
{% endset %}
3034

3135
{% set text %}
32-
<div class="sf-toolbar-info-piece">
33-
<b>HTTP status</b>
34-
<span>{{ collector.statuscode }} {{ collector.statustext }}</span>
35-
</div>
36+
<div class="sf-toolbar-info-group">
37+
<div class="sf-toolbar-info-piece">
38+
<b>HTTP status</b>
39+
<span>{{ collector.statuscode }} {{ collector.statustext }}</span>
40+
</div>
3641

37-
<div class="sf-toolbar-info-piece">
38-
<b>Controller</b>
39-
<span>{{ request_handler }}</span>
40-
</div>
42+
{% if 'GET' != collector.method -%}
43+
<div class="sf-toolbar-info-piece">
44+
<b>Method</b>
45+
<span>{{ collector.method }}</span>
46+
</div>
47+
{%- endif %}
4148

42-
{% if collector.controller.class is defined %}
4349
<div class="sf-toolbar-info-piece">
44-
<b>Controller class</b>
45-
<span>{{ collector.controller.class }}</span>
50+
<b>Controller</b>
51+
<span>{{ request_handler }}</span>
4652
</div>
47-
{% endif %}
4853

49-
<div class="sf-toolbar-info-piece">
50-
<b>Route name</b>
51-
<span>{{ collector.route|default('NONE') }}</span>
52-
</div>
54+
{% if collector.controller.class is defined -%}
55+
<div class="sf-toolbar-info-piece">
56+
<b>Controller class</b>
57+
<span>{{ collector.controller.class }}</span>
58+
</div>
59+
{%- endif %}
5360

54-
<div class="sf-toolbar-info-piece">
55-
<b>Has session</b>
56-
<span>{% if collector.sessionmetadata|length %}yes{% else %}no{% endif %}</span>
61+
<div class="sf-toolbar-info-piece">
62+
<b>Route name</b>
63+
<span>{{ collector.route|default('NONE') }}</span>
64+
</div>
65+
66+
<div class="sf-toolbar-info-piece">
67+
<b>Has session</b>
68+
<span>{% if collector.sessionmetadata|length %}yes{% else %}no{% endif %}</span>
69+
</div>
5770
</div>
71+
72+
{% if redirect_handler is defined -%}
73+
<div class="sf-toolbar-info-group">
74+
<div class="sf-toolbar-info-piece">
75+
<b>
76+
<span class="sf-toolbar-redirection-status sf-toolbar-status-yellow">{{ collector.redirect.status_code }}</span>
77+
Redirect from
78+
</b>
79+
<span>
80+
{{ redirect_handler }}
81+
(<a href="{{ path('_profiler', { token: collector.redirect.token }) }}">{{ collector.redirect.token }}</a>)
82+
</span>
83+
</div>
84+
</div>
85+
{% endif %}
86+
87+
{% if forward_handler is defined %}
88+
<div class="sf-toolbar-info-group">
89+
<div class="sf-toolbar-info-piece">
90+
<b>Forwarded to</b>
91+
<span>
92+
{{ forward_handler }}
93+
(<a href="{{ path('_profiler', { token: collector.forward.token }) }}">{{ collector.forward.token }}</a>)
94+
</span>
95+
</div>
96+
</div>
97+
{% endif %}
5898
{% endset %}
5999

60100
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: profiler_url }) }}
@@ -224,3 +264,22 @@
224264
{% endif %}
225265
</div>
226266
{% endblock %}
267+
268+
{% macro set_handler(controller, route, method) %}
269+
{% if controller.class is defined -%}
270+
{%- if method|default(false) %}<span class="sf-toolbar-status sf-toolbar-redirection-method">{{ method }}</span>{% endif -%}
271+
{%- set link = controller.file|file_link(controller.line) %}
272+
{%- if link %}<a href="{{ link }}" title="{{ controller.file }}">{% else %}<span>{% endif %}
273+
274+
{%- if route|default(false) -%}
275+
@{{ route }}
276+
{%- else -%}
277+
{{- controller.class|abbr_class|striptags -}}
278+
{{- controller.method ? ' :: ' ~ controller.method -}}
279+
{%- endif -%}
280+
281+
{%- if link %}</a>{% else %}</span>{% endif %}
282+
{%- else -%}
283+
<span>{{ route|default(controller) }}</span>
284+
{%- endif %}
285+
{% endmacro %}
Lines changed: 4 additions & 0 deletions
Loading
Lines changed: 10 additions & 0 deletions
Loading

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,47 @@
1919
{% endif %}
2020
</h2>
2121

22+
{% set request_collector = profile.collectors.request|default(false) %}
23+
{% if request_collector is defined and request_collector.redirect -%}
24+
{%- set redirect = request_collector.redirect -%}
25+
{%- set controller = redirect.controller -%}
26+
{%- set redirect_route = '@' ~ redirect.route %}
27+
<dl class="metadata">
28+
<dt>
29+
<span class="label">{{ redirect.status_code }}</span>
30+
Redirect from
31+
</dt>
32+
<dd>
33+
{{ 'GET' != redirect.method ? redirect.method }}
34+
{% if redirect.controller.class is defined -%}
35+
{%- set link = controller.file|file_link(controller.line) -%}
36+
{% if link %}<a href="{{ link }}" title="{{ controller.file }}">{% endif -%}
37+
{{ redirect_route }}
38+
{%- if link %}</a>{% endif -%}
39+
{%- else -%}
40+
{{ redirect_route }}
41+
{%- endif %}
42+
(<a href="{{ path('_profiler', { token: redirect.token }) }}">{{ redirect.token }}</a>)
43+
</dd>
44+
</dl>
45+
{%- endif %}
46+
47+
{% if request_collector and request_collector.forward and request_collector.forward.controller.class is defined -%}
48+
{%- set forward = request_collector.forward -%}
49+
{%- set controller = forward.controller -%}
50+
<dl class="metadata">
51+
<dt>Forwarded to</dt>
52+
<dd>
53+
{% set link = controller.file|file_link(controller.line) -%}
54+
{%- if link %}<a href="{{ link }}" title="{{ controller.file }}">{% endif -%}
55+
{{- controller.class|abbr_class|striptags -}}
56+
{{- controller.method ? ' :: ' ~ controller.method }}
57+
{%- if link %}</a>{% endif %}
58+
(<a href="{{ path('_profiler', { token: forward.token }) }}">{{ forward.token }}</a>)
59+
</dd>
60+
</dl>
61+
{%- endif %}
62+
2263
<dl class="metadata">
2364
<dt>Method</dt>
2465
<dd>{{ profile.method|upper }}</dd>

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -483,11 +483,11 @@ tr.status-warning td {
483483
#summary .status-error { background: {{ colors.error|raw }}; }
484484

485485
#summary .status-success h2,
486-
#summary .status-success h2 a,
486+
#summary .status-success a,
487487
#summary .status-warning h2,
488-
#summary .status-warning h2 a,
488+
#summary .status-warning a,
489489
#summary .status-error h2,
490-
#summary .status-error h2 a {
490+
#summary .status-error a {
491491
color: #FFF;
492492
}
493493

@@ -510,6 +510,10 @@ tr.status-warning td {
510510
margin: 0 1.5em 0 0;
511511
}
512512

513+
#summary dl.metadata .label {
514+
background: rgba(255, 255, 255, 0.2);
515+
}
516+
513517
{# Sidebar
514518
========================================================================= #}
515519
#sidebar {

0 commit comments

Comments
 (0)