Skip to content

Commit

Permalink
Merge branch '3.4'
Browse files Browse the repository at this point in the history
* 3.4:
  [FrameworkBundle] Deprecate useless --no-prefix option
  Add Doctrine Cache to dev dependencies to fix failing unit tests.
  Give info about called security listeners in profiler
  Fix the usage of FrameworkBundle in debug mode without Stopwatch
  • Loading branch information
nicolas-grekas committed Jun 14, 2017
2 parents bf97f03 + 936c1a5 commit 9e680f0
Show file tree
Hide file tree
Showing 17 changed files with 330 additions and 20 deletions.
4 changes: 4 additions & 0 deletions UPGRADE-3.4.md
Expand Up @@ -34,6 +34,10 @@ FrameworkBundle
* The `KernelTestCase::getPhpUnitXmlDir()` and `KernelTestCase::getPhpUnitCliConfigArgument()`
methods are deprecated since 3.4 and will be removed in 4.0.

* The `--no-prefix` option of the `translation:update` command is deprecated and
will be removed in 4.0. Use the `--prefix` option with an empty string as value
instead (e.g. `--prefix=""`)

Process
-------

Expand Down
3 changes: 3 additions & 0 deletions UPGRADE-4.0.md
Expand Up @@ -345,6 +345,9 @@ FrameworkBundle
* The `Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory` class has been removed.
Use `Symfony\Component\Validator\ContainerConstraintValidatorFactory` instead.

* The `--no-prefix` option of the `translation:update` command has
been removed.

HttpFoundation
--------------

Expand Down
Expand Up @@ -39,7 +39,6 @@ protected function configure()
new InputArgument('locale', InputArgument::REQUIRED, 'The locale'),
new InputArgument('bundle', InputArgument::OPTIONAL, 'The bundle name or directory where to load the messages, defaults to app/Resources folder'),
new InputOption('prefix', null, InputOption::VALUE_OPTIONAL, 'Override the default prefix', '__'),
new InputOption('no-prefix', null, InputOption::VALUE_NONE, 'If set, no prefix is added to the translations'),
new InputOption('output-format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format', 'yml'),
new InputOption('dump-messages', null, InputOption::VALUE_NONE, 'Should the messages be dumped in the console'),
new InputOption('force', null, InputOption::VALUE_NONE, 'Should the update be done'),
Expand Down Expand Up @@ -135,7 +134,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$extractedCatalogue = new MessageCatalogue($input->getArgument('locale'));
$errorIo->comment('Parsing templates...');
$extractor = $this->getContainer()->get('translation.extractor');
$extractor->setPrefix($input->getOption('no-prefix') ? '' : $input->getOption('prefix'));
$extractor->setPrefix($input->getOption('prefix'));
foreach ($transPaths as $path) {
$path .= 'views';
if (is_dir($path)) {
Expand Down
Expand Up @@ -582,6 +582,10 @@ private function registerDebugConfiguration(array $config, ContainerBuilder $con

$debug = $container->getParameter('kernel.debug');

if ($debug) {
$container->setParameter('debug.container.dump', '%kernel.cache_dir%/%kernel.container_class%.xml');
}

if ($debug && class_exists(Stopwatch::class)) {
$loader->load('debug.xml');
}
Expand Down
4 changes: 0 additions & 4 deletions src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml
Expand Up @@ -4,10 +4,6 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<parameters>
<parameter key="debug.container.dump">%kernel.cache_dir%/%kernel.container_class%.xml</parameter>
</parameters>

<services>
<defaults public="false" />

Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Bundle/SecurityBundle/CHANGELOG.md
Expand Up @@ -13,6 +13,7 @@ CHANGELOG
-----

* [BC BREAK] `FirewallContext::getListeners()` now returns `\Traversable|array`
* added info about called security listeners in profiler

3.3.0
-----
Expand Down
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Bundle\SecurityBundle\DataCollector;

use Symfony\Bundle\SecurityBundle\Debug\TraceableFirewallListener;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
Expand Down Expand Up @@ -38,6 +39,7 @@ class SecurityDataCollector extends DataCollector implements LateDataCollectorIn
private $logoutUrlGenerator;
private $accessDecisionManager;
private $firewallMap;
private $firewall;
private $hasVarDumper;

/**
Expand All @@ -48,14 +50,16 @@ class SecurityDataCollector extends DataCollector implements LateDataCollectorIn
* @param LogoutUrlGenerator|null $logoutUrlGenerator
* @param AccessDecisionManagerInterface|null $accessDecisionManager
* @param FirewallMapInterface|null $firewallMap
* @param TraceableFirewallListener|null $firewall
*/
public function __construct(TokenStorageInterface $tokenStorage = null, RoleHierarchyInterface $roleHierarchy = null, LogoutUrlGenerator $logoutUrlGenerator = null, AccessDecisionManagerInterface $accessDecisionManager = null, FirewallMapInterface $firewallMap = null)
public function __construct(TokenStorageInterface $tokenStorage = null, RoleHierarchyInterface $roleHierarchy = null, LogoutUrlGenerator $logoutUrlGenerator = null, AccessDecisionManagerInterface $accessDecisionManager = null, FirewallMapInterface $firewallMap = null, TraceableFirewallListener $firewall = null)
{
$this->tokenStorage = $tokenStorage;
$this->roleHierarchy = $roleHierarchy;
$this->logoutUrlGenerator = $logoutUrlGenerator;
$this->accessDecisionManager = $accessDecisionManager;
$this->firewallMap = $firewallMap;
$this->firewall = $firewall;
$this->hasVarDumper = class_exists(ClassStub::class);
}

Expand Down Expand Up @@ -158,6 +162,12 @@ public function collect(Request $request, Response $response, \Exception $except
);
}
}

// collect firewall listeners information
$this->data['listeners'] = array();
if ($this->firewall) {
$this->data['listeners'] = $this->firewall->getWrappedListeners();
}
}

public function lateCollect()
Expand Down Expand Up @@ -296,6 +306,11 @@ public function getFirewall()
return $this->data['firewall'];
}

public function getListeners()
{
return $this->data['listeners'];
}

/**
* {@inheritdoc}
*/
Expand Down
@@ -0,0 +1,43 @@
<?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\SecurityBundle\Debug;

use Symfony\Bundle\SecurityBundle\EventListener\FirewallListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;

/**
* Firewall collecting called listeners.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
final class TraceableFirewallListener extends FirewallListener
{
private $wrappedListeners;

public function getWrappedListeners()
{
return $this->wrappedListeners;
}

protected function handleRequest(GetResponseEvent $event, $listeners)
{
foreach ($listeners as $listener) {
$wrappedListener = new WrappedListener($listener);
$wrappedListener->handle($event);
$this->wrappedListeners[] = $wrappedListener->getInfo();

if ($event->hasResponse()) {
break;
}
}
}
}
76 changes: 76 additions & 0 deletions src/Symfony/Bundle/SecurityBundle/Debug/WrappedListener.php
@@ -0,0 +1,76 @@
<?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\SecurityBundle\Debug;

use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
use Symfony\Component\VarDumper\Caster\ClassStub;

/**
* Wraps a security listener for calls record.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
final class WrappedListener implements ListenerInterface
{
private $response;
private $listener;
private $time;
private $stub;
private static $hasVarDumper;

public function __construct(ListenerInterface $listener)
{
$this->listener = $listener;

if (null === self::$hasVarDumper) {
self::$hasVarDumper = class_exists(ClassStub::class);
}
}

/**
* {@inheritdoc}
*/
public function handle(GetResponseEvent $event)
{
$startTime = microtime(true);
$this->listener->handle($event);
$this->time = microtime(true) - $startTime;
$this->response = $event->getResponse();
}

/**
* Proxies all method calls to the original listener.
*/
public function __call($method, $arguments)
{
return call_user_func_array(array($this->listener, $method), $arguments);
}

public function getWrappedListener()
{
return $this->listener;
}

public function getInfo()
{
if (null === $this->stub) {
$this->stub = self::$hasVarDumper ? new ClassStub(get_class($this->listener)) : get_class($this->listener);
}

return array(
'response' => $this->response,
'time' => $this->time,
'stub' => $this->stub,
);
}
}
Expand Up @@ -14,6 +14,7 @@
<argument type="service" id="security.logout_url_generator" />
<argument type="service" id="security.access.decision_manager" />
<argument type="service" id="security.firewall.map" />
<argument type="service" id="debug.security.firewall" on-invalid="null" />
</service>
</services>
</container>
Expand Up @@ -10,5 +10,14 @@
<service id="debug.security.access.decision_manager" class="Symfony\Component\Security\Core\Authorization\TraceableAccessDecisionManager" decorates="security.access.decision_manager">
<argument type="service" id="debug.security.access.decision_manager.inner" />
</service>

<service id="debug.security.firewall" class="Symfony\Bundle\SecurityBundle\Debug\TraceableFirewallListener">
<tag name="kernel.event_subscriber" />
<argument type="service" id="security.firewall.map" />
<argument type="service" id="event_dispatcher" />
<argument type="service" id="security.logout_url_generator" />
</service>

<service id="security.firewall" alias="debug.security.firewall" public="true" />
</services>
</container>
Expand Up @@ -150,6 +150,8 @@
</div>

{% if collector.firewall.security_enabled %}
<h4>Configuration</h4>

<table>
<thead>
<tr>
Expand Down Expand Up @@ -188,6 +190,46 @@
</tr>
</tbody>
</table>

<h4>Listeners</h4>

{% if collector.listeners|default([]) is empty %}
<div class="empty">
<p>No security listeners have been recorded. Check that debugging is enabled in the kernel.</p>
</div>
{% else %}
<table>
<thead>
<tr>
<th>Listener</th>
<th>Duration</th>
<th>Response</th>
</tr>
</thead>

{% set previous_event = (collector.listeners|first) %}
{% for listener in collector.listeners %}
{% if loop.first or listener != previous_event %}
{% if not loop.first %}
</tbody>
{% endif %}

<tbody>
{% set previous_event = listener %}
{% endif %}

<tr>
<td class="font-normal">{{ profiler_dump(listener.stub) }}</td>
<td class="no-wrap">{{ '%0.2f'|format(listener.time * 1000) }} ms</td>
<td class="font-normal">{{ listener.response ? profiler_dump(listener.response) : '(none)' }}</td>
</tr>

{% if loop.last %}
</tbody>
{% endif %}
{% endfor %}
</table>
{% endif %}
{% endif %}
{% elseif collector.enabled %}
<div class="empty">
Expand Down

0 comments on commit 9e680f0

Please sign in to comment.