feature #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 | #14358, #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 RequestDataCollector227ac77
[WebProfilerBundle] [FrameworkBundle] profile forward controller action0a1b284
[WebProfiler] [HttpKernel] profile redirections
This commit is contained in:
commit
536a6cdbd8
@ -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);
|
||||
}
|
||||
|
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector as BaseRequestCollector;
|
||||
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
/**
|
||||
* RequestDataCollector.
|
||||
*
|
||||
* @author Jules Pietri <jusles@heahprod.com>
|
||||
*/
|
||||
class RequestDataCollector extends BaseRequestCollector implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function collect(Request $request, Response $response, \Exception $exception = null)
|
||||
{
|
||||
parent::collect($request, $response, $exception);
|
||||
|
||||
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')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'request';
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
<call method="setKernel"><argument type="service" id="kernel" on-invalid="ignore" /></call>
|
||||
</service>
|
||||
|
||||
<service id="data_collector.request" class="Symfony\Component\HttpKernel\DataCollector\RequestDataCollector">
|
||||
<service id="data_collector.request" class="Symfony\Bundle\FrameworkBundle\DataCollector\RequestDataCollector">
|
||||
<tag name="kernel.event_subscriber" />
|
||||
<tag name="data_collector" template="@WebProfiler/Collector/request.html.twig" id="request" priority="335" />
|
||||
</service>
|
||||
|
@ -2,59 +2,99 @@
|
||||
|
||||
{% block toolbar %}
|
||||
{% set request_handler %}
|
||||
{% if collector.controller.class is defined %}
|
||||
{% set link = collector.controller.file|file_link(collector.controller.line) %}
|
||||
{% if link %}<a href="{{ link }}" title="{{ collector.controller.file }}">{% else %}<span>{% endif %}
|
||||
|
||||
{{ collector.controller.class|abbr_class|striptags }}
|
||||
|
||||
{%- if collector.controller.method -%}
|
||||
:: {{ collector.controller.method }}
|
||||
{%- endif -%}
|
||||
|
||||
{% if link %}</a>{% else %}</span>{% endif %}
|
||||
{% else %}
|
||||
<span>{{ collector.controller }}</span>
|
||||
{% endif %}
|
||||
{% import _self as helper %}
|
||||
{{ helper.set_handler(collector.controller) }}
|
||||
{% endset %}
|
||||
|
||||
{% if collector.redirect %}
|
||||
{% set redirect_handler %}
|
||||
{% import _self as helper %}
|
||||
{{ helper.set_handler(collector.redirect.controller, collector.redirect.route, 'GET' != collector.redirect.method ? collector.redirect.method) }}
|
||||
{% 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 %}
|
||||
<span class="sf-toolbar-label">@</span>
|
||||
{% if collector.redirect %}{{ include('@WebProfiler/Icon/redirect.svg') }}{% endif %}
|
||||
{% if collector.forward %}{{ include('@WebProfiler/Icon/forward.svg') }}{% endif %}
|
||||
<span class="sf-toolbar-label">{{ 'GET' != collector.method ? collector.method }} @</span>
|
||||
<span class="sf-toolbar-value sf-toolbar-info-piece-additional">{{ collector.route }}</span>
|
||||
{% endif %}
|
||||
{% endset %}
|
||||
|
||||
{% set text %}
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>HTTP status</b>
|
||||
<span>{{ collector.statuscode }} {{ collector.statustext }}</span>
|
||||
</div>
|
||||
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Controller</b>
|
||||
<span>{{ request_handler }}</span>
|
||||
</div>
|
||||
|
||||
{% if collector.controller.class is defined %}
|
||||
<div class="sf-toolbar-info-group">
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Controller class</b>
|
||||
<span>{{ collector.controller.class }}</span>
|
||||
<b>HTTP status</b>
|
||||
<span>{{ collector.statuscode }} {{ collector.statustext }}</span>
|
||||
</div>
|
||||
|
||||
{% if 'GET' != collector.method -%}
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Method</b>
|
||||
<span>{{ collector.method }}</span>
|
||||
</div>
|
||||
{%- endif %}
|
||||
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Controller</b>
|
||||
<span>{{ request_handler }}</span>
|
||||
</div>
|
||||
|
||||
{% if collector.controller.class is defined -%}
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Controller class</b>
|
||||
<span>{{ collector.controller.class }}</span>
|
||||
</div>
|
||||
{%- endif %}
|
||||
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Route name</b>
|
||||
<span>{{ collector.route|default('NONE') }}</span>
|
||||
</div>
|
||||
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Has session</b>
|
||||
<span>{% if collector.sessionmetadata|length %}yes{% else %}no{% endif %}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if redirect_handler is defined -%}
|
||||
<div class="sf-toolbar-info-group">
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>
|
||||
<span class="sf-toolbar-redirection-status sf-toolbar-status-yellow">{{ collector.redirect.status_code }}</span>
|
||||
Redirect from
|
||||
</b>
|
||||
<span>
|
||||
{{ redirect_handler }}
|
||||
(<a href="{{ path('_profiler', { token: collector.redirect.token }) }}">{{ collector.redirect.token }}</a>)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Route name</b>
|
||||
<span>{{ collector.route|default('NONE') }}</span>
|
||||
</div>
|
||||
|
||||
<div class="sf-toolbar-info-piece">
|
||||
<b>Has session</b>
|
||||
<span>{% if collector.sessionmetadata|length %}yes{% else %}no{% endif %}</span>
|
||||
</div>
|
||||
|
||||
{% 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 }) }}
|
||||
@ -224,3 +264,22 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% macro set_handler(controller, route, method) %}
|
||||
{% if controller.class is defined -%}
|
||||
{%- if method|default(false) %}<span class="sf-toolbar-status sf-toolbar-redirection-method">{{ method }}</span>{% endif -%}
|
||||
{%- set link = controller.file|file_link(controller.line) %}
|
||||
{%- if link %}<a href="{{ link }}" title="{{ controller.file }}">{% else %}<span>{% endif %}
|
||||
|
||||
{%- if route|default(false) -%}
|
||||
@{{ route }}
|
||||
{%- else -%}
|
||||
{{- controller.class|abbr_class|striptags -}}
|
||||
{{- controller.method ? ' :: ' ~ controller.method -}}
|
||||
{%- endif -%}
|
||||
|
||||
{%- if link %}</a>{% else %}</span>{% endif %}
|
||||
{%- else -%}
|
||||
<span>{{ route|default(controller) }}</span>
|
||||
{%- endif %}
|
||||
{% endmacro %}
|
||||
|
@ -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 |
@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path style="fill:#aaa" d="M23.06,7.83L14,0.38a1.25,1.25,0,0,0-2,.89V4.09a13.61,13.61,0,0,1-2.2.61l-1.3.47C8,
|
||||
5.35,7.59,5.6,7.12,5.81l-0.69.35-0.72.45a10.62,10.62,0,0,0-1.41,1A13.22,13.22,0,0,0,3,8.82a15.31,15.31,
|
||||
0,0,0-1.13,1.46A17.63,17.63,0,0,0,1,11.93c-0.18.58-.34,1.16-0.48,1.71S0.45,14.76.43,15.29a10.2,10.2,0,0,0,.16,
|
||||
1.5,5.72,5.72,0,0,0,.33,1.34c0.14,0.41.26,0.82,0.42,1.19,0.37,0.71.67,1.38,1,1.94l1,1.46c0.32,0.41.63,0.75,0.87,
|
||||
1s0.51,0.09.43-.22-0.23-.75-0.35-1.23L4,20.69c-0.1-.58-0.09-1.22-0.14-1.86,0-.32.05-0.65,0.08-1a3.44,3.44,0,0,1,
|
||||
.16-1A6.44,6.44,0,0,1,4.41,16l0.41-.8c0.2-.22.38-0.44,0.55-0.65L6,14c0.23-.14.5-0.24,0.72-0.37a7.52,7.52,0,0,1,
|
||||
.79-0.25,4.48,4.48,0,0,1,.84-0.15l0.41-.06H9.22c0.3,0,.56,0,0.85,0l0.72,0.07a3.77,3.77,0,0,1,1.2.21v3.17a1.25,
|
||||
1.25,0,0,0,2,.89l9-7.45A1.46,1.46,0,0,0,23.06,7.83Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 980 B |
@ -19,6 +19,47 @@
|
||||
{% endif %}
|
||||
</h2>
|
||||
|
||||
{% 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">
|
||||
<dt>
|
||||
<span class="label">{{ redirect.status_code }}</span>
|
||||
Redirect from
|
||||
</dt>
|
||||
<dd>
|
||||
{{ 'GET' != redirect.method ? redirect.method }}
|
||||
{% if redirect.controller.class is defined -%}
|
||||
{%- set link = controller.file|file_link(controller.line) -%}
|
||||
{% if link %}<a href="{{ link }}" title="{{ controller.file }}">{% endif -%}
|
||||
{{ redirect_route }}
|
||||
{%- if link %}</a>{% endif -%}
|
||||
{%- else -%}
|
||||
{{ redirect_route }}
|
||||
{%- endif %}
|
||||
(<a href="{{ path('_profiler', { token: redirect.token }) }}">{{ redirect.token }}</a>)
|
||||
</dd>
|
||||
</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>
|
||||
|
@ -483,11 +483,11 @@ tr.status-warning td {
|
||||
#summary .status-error { background: {{ colors.error|raw }}; }
|
||||
|
||||
#summary .status-success h2,
|
||||
#summary .status-success h2 a,
|
||||
#summary .status-success a,
|
||||
#summary .status-warning h2,
|
||||
#summary .status-warning h2 a,
|
||||
#summary .status-warning a,
|
||||
#summary .status-error h2,
|
||||
#summary .status-error h2 a {
|
||||
#summary .status-error a {
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
@ -510,6 +510,10 @@ tr.status-warning td {
|
||||
margin: 0 1.5em 0 0;
|
||||
}
|
||||
|
||||
#summary dl.metadata .label {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
{# Sidebar
|
||||
========================================================================= #}
|
||||
#sidebar {
|
||||
|
@ -36,7 +36,7 @@
|
||||
.sf-toolbarreset {
|
||||
background-color: #222;
|
||||
bottom: 0;
|
||||
box-shadow: 0 -1px 0px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
|
||||
color: #EEE;
|
||||
font: 11px Arial, sans-serif;
|
||||
left: 0;
|
||||
@ -138,7 +138,7 @@
|
||||
|
||||
.sf-toolbar-block .sf-toolbar-info-piece .sf-toolbar-status {
|
||||
padding: 2px 5px;
|
||||
margin-bottom: 0px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.sf-toolbar-block .sf-toolbar-info-piece .sf-toolbar-status + .sf-toolbar-status {
|
||||
margin-left: 4px;
|
||||
@ -232,6 +232,16 @@
|
||||
.sf-toolbar-block-request .sf-toolbar-info-piece a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.sf-toolbar-block-request .sf-toolbar-redirection-status {
|
||||
font-weight: normal;
|
||||
padding: 2px 4px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.sf-toolbar-block-request .sf-toolbar-info-piece span.sf-toolbar-redirection-method {
|
||||
font-size: 12px;
|
||||
height: 17px;
|
||||
line-height: 17px;
|
||||
}
|
||||
|
||||
.sf-toolbar-status-green .sf-toolbar-label,
|
||||
.sf-toolbar-status-yellow .sf-toolbar-label,
|
||||
@ -380,7 +390,7 @@
|
||||
|
||||
.sf-toolbarreset {
|
||||
bottom: auto;
|
||||
box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
|
||||
top: 0;
|
||||
}
|
||||
|
||||
@ -450,9 +460,12 @@
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
.sf-toolbar-block-request .sf-toolbar-status + .sf-toolbar-label {
|
||||
margin-left: 4px;
|
||||
.sf-toolbar-block-request .sf-toolbar-status {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.sf-toolbar-block-request .sf-toolbar-icon svg + .sf-toolbar-label {
|
||||
margin-left: 0;
|
||||
}
|
||||
.sf-toolbar-block-request .sf-toolbar-label + .sf-toolbar-value {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
*/
|
||||
class RequestDataCollector extends DataCollector implements EventSubscriberInterface
|
||||
{
|
||||
/** @var \SplObjectStorage */
|
||||
protected $controllers;
|
||||
|
||||
public function __construct()
|
||||
@ -89,6 +90,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
|
||||
$statusCode = $response->getStatusCode();
|
||||
|
||||
$this->data = array(
|
||||
'method' => $request->getMethod(),
|
||||
'format' => $request->getRequestFormat(),
|
||||
'content' => $content,
|
||||
'content_type' => $response->headers->get('Content-Type', 'text/html'),
|
||||
@ -122,48 +124,42 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
|
||||
}
|
||||
|
||||
if (isset($this->controllers[$request])) {
|
||||
$controller = $this->controllers[$request];
|
||||
if (is_array($controller)) {
|
||||
try {
|
||||
$r = new \ReflectionMethod($controller[0], $controller[1]);
|
||||
$this->data['controller'] = array(
|
||||
'class' => is_object($controller[0]) ? get_class($controller[0]) : $controller[0],
|
||||
'method' => $controller[1],
|
||||
'file' => $r->getFileName(),
|
||||
'line' => $r->getStartLine(),
|
||||
);
|
||||
} catch (\ReflectionException $e) {
|
||||
if (is_callable($controller)) {
|
||||
// using __call or __callStatic
|
||||
$this->data['controller'] = array(
|
||||
'class' => is_object($controller[0]) ? get_class($controller[0]) : $controller[0],
|
||||
'method' => $controller[1],
|
||||
'file' => 'n/a',
|
||||
'line' => 'n/a',
|
||||
);
|
||||
}
|
||||
}
|
||||
} elseif ($controller instanceof \Closure) {
|
||||
$r = new \ReflectionFunction($controller);
|
||||
$this->data['controller'] = array(
|
||||
'class' => $r->getName(),
|
||||
'method' => null,
|
||||
'file' => $r->getFileName(),
|
||||
'line' => $r->getStartLine(),
|
||||
);
|
||||
} elseif (is_object($controller)) {
|
||||
$r = new \ReflectionClass($controller);
|
||||
$this->data['controller'] = array(
|
||||
'class' => $r->getName(),
|
||||
'method' => null,
|
||||
'file' => $r->getFileName(),
|
||||
'line' => $r->getStartLine(),
|
||||
);
|
||||
} else {
|
||||
$this->data['controller'] = (string) $controller ?: 'n/a';
|
||||
}
|
||||
$this->data['controller'] = $this->parseController($this->controllers[$request]);
|
||||
unset($this->controllers[$request]);
|
||||
}
|
||||
|
||||
if ($request->hasSession() && $request->getSession()->has('sf_redirect')) {
|
||||
$this->data['redirect'] = $request->getSession()->get('sf_redirect');
|
||||
$request->getSession()->remove('sf_redirect');
|
||||
}
|
||||
|
||||
if ($request->hasSession() && $response->isRedirect()) {
|
||||
$request->getSession()->set('sf_redirect', array(
|
||||
'token' => $response->headers->get('x-debug-token'),
|
||||
'route' => $request->attributes->get('_route', 'n/a'),
|
||||
'method' => $request->getMethod(),
|
||||
'controller' => $this->parseController($request->attributes->get('_controller')),
|
||||
'status_code' => $statusCode,
|
||||
'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 getMethod()
|
||||
{
|
||||
return $this->data['method'];
|
||||
}
|
||||
|
||||
public function getPathInfo()
|
||||
@ -276,15 +272,27 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controller.
|
||||
* Gets the parsed controller.
|
||||
*
|
||||
* @return string The controller as a string
|
||||
* @return array|string The controller as a string or array of data
|
||||
* with keys 'class', 'method', 'file' and 'line'
|
||||
*/
|
||||
public function getController()
|
||||
{
|
||||
return $this->data['controller'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the previous request attributes.
|
||||
*
|
||||
* @return array|bool A legacy array of data from the previous redirection response
|
||||
* or false otherwise
|
||||
*/
|
||||
public function getRedirect()
|
||||
{
|
||||
return isset($this->data['redirect']) ? $this->data['redirect'] : false;
|
||||
}
|
||||
|
||||
public function onKernelController(FilterControllerEvent $event)
|
||||
{
|
||||
$this->controllers[$event->getRequest()] = $event->getController();
|
||||
@ -303,6 +311,67 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter
|
||||
return 'request';
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a controller.
|
||||
*
|
||||
* @param mixed $controller The controller to parse
|
||||
*
|
||||
* @return array|string An array of controller data or a simple string
|
||||
*/
|
||||
protected function parseController($controller)
|
||||
{
|
||||
if (is_string($controller) && false !== strpos($controller, '::')) {
|
||||
$controller = explode('::', $controller);
|
||||
}
|
||||
|
||||
if (is_array($controller)) {
|
||||
try {
|
||||
$r = new \ReflectionMethod($controller[0], $controller[1]);
|
||||
|
||||
return array(
|
||||
'class' => is_object($controller[0]) ? get_class($controller[0]) : $controller[0],
|
||||
'method' => $controller[1],
|
||||
'file' => $r->getFileName(),
|
||||
'line' => $r->getStartLine(),
|
||||
);
|
||||
} catch (\ReflectionException $e) {
|
||||
if (is_callable($controller)) {
|
||||
// using __call or __callStatic
|
||||
return array(
|
||||
'class' => is_object($controller[0]) ? get_class($controller[0]) : $controller[0],
|
||||
'method' => $controller[1],
|
||||
'file' => 'n/a',
|
||||
'line' => 'n/a',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($controller instanceof \Closure) {
|
||||
$r = new \ReflectionFunction($controller);
|
||||
|
||||
return array(
|
||||
'class' => $r->getName(),
|
||||
'method' => null,
|
||||
'file' => $r->getFileName(),
|
||||
'line' => $r->getStartLine(),
|
||||
);
|
||||
}
|
||||
|
||||
if (is_object($controller)) {
|
||||
$r = new \ReflectionClass($controller);
|
||||
|
||||
return array(
|
||||
'class' => $r->getName(),
|
||||
'method' => null,
|
||||
'file' => $r->getFileName(),
|
||||
'line' => $r->getStartLine(),
|
||||
);
|
||||
}
|
||||
|
||||
return (string) $controller ?: 'n/a';
|
||||
}
|
||||
|
||||
private function getCookieHeader($name, $value, $expires, $path, $domain, $secure, $httponly)
|
||||
{
|
||||
$cookie = sprintf('%s=%s', $name, urlencode($value));
|
||||
|
@ -66,7 +66,7 @@ class RequestDataCollectorTest extends \PHPUnit_Framework_TestCase
|
||||
'"Regular" callable',
|
||||
array($this, 'testControllerInspection'),
|
||||
array(
|
||||
'class' => 'Symfony\Component\HttpKernel\Tests\DataCollector\RequestDataCollectorTest',
|
||||
'class' => __NAMESPACE__.'\RequestDataCollectorTest',
|
||||
'method' => 'testControllerInspection',
|
||||
'file' => __FILE__,
|
||||
'line' => $r1->getStartLine(),
|
||||
@ -86,8 +86,13 @@ class RequestDataCollectorTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
array(
|
||||
'Static callback as string',
|
||||
'Symfony\Component\HttpKernel\Tests\DataCollector\RequestDataCollectorTest::staticControllerMethod',
|
||||
'Symfony\Component\HttpKernel\Tests\DataCollector\RequestDataCollectorTest::staticControllerMethod',
|
||||
__NAMESPACE__.'\RequestDataCollectorTest::staticControllerMethod',
|
||||
array(
|
||||
'class' => 'Symfony\Component\HttpKernel\Tests\DataCollector\RequestDataCollectorTest',
|
||||
'method' => 'staticControllerMethod',
|
||||
'file' => __FILE__,
|
||||
'line' => $r2->getStartLine(),
|
||||
),
|
||||
),
|
||||
|
||||
array(
|
||||
|
Reference in New Issue
Block a user