[WebProfilerBundle] [FrameworkBundle] profile forward controller action

closes #14358

The `Symfony\Bundle\FrameworkBundle\Controller\Controller::forward()`
now passes request attributes to its sub request, so when the profiler
will profile the sub request it will add its token to its hold by
reference parent request attributes.

The profiler main profiler layout displays a shortcut to the forwarded
sub request profile which is actually responsible for returning the
present response.

The web debug toolbar shows a notifying icon, meaning a shortcut to a
forwarded profile is available in the toolbar request panel.
This commit is contained in:
Jules Pietri 2016-02-24 06:07:15 +01:00
parent 0a1b2841f7
commit 227ac77f11
5 changed files with 75 additions and 3 deletions

View File

@ -65,8 +65,10 @@ abstract class Controller implements ContainerAwareInterface
*/
protected function forward($controller, array $path = array(), array $query = array())
{
$request = $this->container->get('request_stack')->getCurrentRequest();
$path['_forwarded'] = $request->attributes;
$path['_controller'] = $controller;
$subRequest = $this->container->get('request_stack')->getCurrentRequest()->duplicate($query, null, $path);
$subRequest = $request->duplicate($query, null, $path);
return $this->container->get('http_kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}

View File

@ -13,12 +13,20 @@
{% endset %}
{% endif %}
{% if collector.forward %}
{% set forward_handler %}
{% import _self as helper %}
{{ helper.set_handler(collector.forward.controller) }}
{% endset %}
{% endif %}
{% set request_status_code_color = (collector.statuscode >= 400) ? 'red' : (collector.statuscode >= 300) ? 'yellow' : 'green' %}
{% set icon %}
<span class="sf-toolbar-status sf-toolbar-status-{{ request_status_code_color }}">{{ collector.statuscode }}</span>
{% if collector.route %}
{% if collector.redirect %}{{ include('@WebProfiler/Icon/redirect.svg') }}{% endif %}
{% if collector.forward %}{{ include('@WebProfiler/Icon/forward.svg') }}{% endif %}
<span class="sf-toolbar-label">@</span>
<span class="sf-toolbar-value sf-toolbar-info-piece-additional">{{ collector.route }}</span>
{% endif %}
@ -68,6 +76,18 @@
</div>
</div>
{% endif %}
{% if forward_handler is defined %}
<div class="sf-toolbar-info-group">
<div class="sf-toolbar-info-piece">
<b>Forwarded to</b>
<span>
{{ forward_handler }}
(<a href="{{ path('_profiler', { token: collector.forward.token }) }}">{{ collector.forward.token }}</a>)
</span>
</div>
</div>
{% endif %}
{% endset %}
{{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: profiler_url }) }}

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path style="fill:#aaa" d="M23.61,11.07L17.07,4.35A1.2,1.2,0,0,0,15,5.28V9H1.4A1.82,1.82,0,0,0,0,10.82v2.61A1.55,
1.55,0,0,0,1.4,15H15v3.72a1.2,1.2,0,0,0,2.07.93l6.63-6.72A1.32,1.32,0,0,0,23.61,11.07Z"/>
</svg>

After

Width:  |  Height:  |  Size: 307 B

View File

@ -19,8 +19,9 @@
{% endif %}
</h2>
{% if profile.collectors.request is defined and profile.collectors.request.redirect -%}
{%- set redirect = profile.collectors.request.redirect -%}
{% set request_collector = profile.collectors.request|default(false) %}
{% if request_collector is defined and request_collector.redirect -%}
{%- set redirect = request_collector.redirect -%}
{%- set controller = redirect.controller -%}
{%- set redirect_route = '@' ~ redirect.route %}
<dl class="metadata">
@ -43,6 +44,22 @@
</dl>
{%- endif %}
{% if request_collector and request_collector.forward and request_collector.forward.controller.class is defined -%}
{%- set forward = request_collector.forward -%}
{%- set controller = forward.controller -%}
<dl class="metadata">
<dt>Forwarded to</dt>
<dd>
{% set link = controller.file|file_link(controller.line) -%}
{%- if link %}<a href="{{ link }}" title="{{ controller.file }}">{% endif -%}
{{- controller.class|abbr_class|striptags -}}
{{- controller.method ? ' :: ' ~ controller.method }}
{%- if link %}</a>{% endif %}
(<a href="{{ path('_profiler', { token: forward.token }) }}">{{ forward.token }}</a>)
</dd>
</dl>
{%- endif %}
<dl class="metadata">
<dt>Method</dt>
<dd>{{ profile.method|upper }}</dd>

View File

@ -141,6 +141,18 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
'status_text' => Response::$statusTexts[(int) $statusCode],
));
}
if ($parentRequestAttributes = $request->attributes->get('_forwarded')) {
if ($parentRequestAttributes instanceof ParameterBag) {
$parentRequestAttributes->set('_forward_token', $response->headers->get('x-debug-token'));
}
}
if ($request->attributes->has('_forward_controller')) {
$this->data['forward'] = array(
'token' => $request->attributes->get('_forward_token'),
'controller' => $this->parseController($request->attributes->get('_forward_controller')),
);
}
}
public function getPathInfo()
@ -274,9 +286,26 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
return isset($this->data['redirect']) ? $this->data['redirect'] : false;
}
/**
* Gets the parsed forward controller.
*
* @return array|bool An array with keys 'token' the forward profile token, and
* 'controller' the parsed forward controller, false otherwise
*/
public function getForward()
{
return isset($this->data['forward']) ? $this->data['forward'] : false;
}
public function onKernelController(FilterControllerEvent $event)
{
$this->controllers[$event->getRequest()] = $event->getController();
if ($parentRequestAttributes = $event->getRequest()->attributes->get('_forwarded')) {
if ($parentRequestAttributes instanceof ParameterBag) {
$parentRequestAttributes->set('_forward_controller', $event->getController());
}
}
}
public static function getSubscribedEvents()