Merge branch '3.4' into 4.2

* 3.4:
  Show more accurate message in profiler when missing stopwatch
  CS Fixes: Not double split with one array argument
  Remove redundant animation prefixes
  Remove redundant `box-sizing` prefixes
  Rework firewall access denied rule
  fixed CS
  Fix missing $extraDirs when open_basedir returns
This commit is contained in:
Fabien Potencier 2019-04-10 18:20:36 +02:00
commit b13a23fe45
14 changed files with 151 additions and 113 deletions

View File

@ -126,14 +126,12 @@ class UserPasswordEncoderCommandTest extends WebTestCase
public function testEncodePasswordEmptySaltOutput() public function testEncodePasswordEmptySaltOutput()
{ {
$this->passwordEncoderCommandTester->execute( $this->passwordEncoderCommandTester->execute([
[ 'command' => 'security:encode-password',
'command' => 'security:encode-password', 'password' => 'p@ssw0rd',
'password' => 'p@ssw0rd', 'user-class' => 'Symfony\Component\Security\Core\User\User',
'user-class' => 'Symfony\Component\Security\Core\User\User', '--empty-salt' => true,
'--empty-salt' => true, ]);
]
);
$this->assertContains('Password encoding succeeded', $this->passwordEncoderCommandTester->getDisplay()); $this->assertContains('Password encoding succeeded', $this->passwordEncoderCommandTester->getDisplay());
$this->assertContains(' Encoded password p@ssw0rd', $this->passwordEncoderCommandTester->getDisplay()); $this->assertContains(' Encoded password p@ssw0rd', $this->passwordEncoderCommandTester->getDisplay());

View File

@ -97,7 +97,11 @@
<h2>Execution timeline</h2> <h2>Execution timeline</h2>
{% if collector.events is empty %} {% if not collector.isStopwatchInstalled() %}
<div class="empty">
<p>The Stopwatch component is not installed. If you want to see timing events, run: <code>composer require symfony/stopwatch</code>.</p>
</div>
{% elseif collector.events is empty %}
<div class="empty"> <div class="empty">
<p>No timing events have been recorded. Check that symfony/stopwatch is installed and debugging enabled in the kernel.</p> <p>No timing events have been recorded. Check that symfony/stopwatch is installed and debugging enabled in the kernel.</p>
</div> </div>

View File

@ -5,8 +5,6 @@
background-color: #222; background-color: #222;
border-top-left-radius: 4px; border-top-left-radius: 4px;
bottom: 0; bottom: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
display: none; display: none;
height: 36px; height: 36px;
@ -36,8 +34,6 @@
} }
.sf-toolbarreset * { .sf-toolbarreset * {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box; box-sizing: content-box;
vertical-align: baseline; vertical-align: baseline;
letter-spacing: normal; letter-spacing: normal;
@ -371,21 +367,8 @@ div.sf-toolbar .sf-toolbar-block a:hover {
text-align: right; text-align: right;
} }
.sf-ajax-request-loading { .sf-ajax-request-loading {
-webkit-animation: sf-blink .5s ease-in-out infinite;
-o-animation: sf-blink .5s ease-in-out infinite;
-moz-animation: sf-blink .5s ease-in-out infinite;
animation: sf-blink .5s ease-in-out infinite; animation: sf-blink .5s ease-in-out infinite;
} }
@-webkit-keyframes sf-blink {
0% { background: #222; }
50% { background: #444; }
100% { background: #222; }
}
@-moz-keyframes sf-blink {
0% { background: #222; }
50% { background: #444; }
100% { background: #222; }
}
@keyframes sf-blink { @keyframes sf-blink {
0% { background: #222; } 0% { background: #222; }
50% { background: #444; } 50% { background: #444; }

View File

@ -18,7 +18,7 @@
"require": { "require": {
"php": "^7.1.3", "php": "^7.1.3",
"symfony/config": "^4.2", "symfony/config": "^4.2",
"symfony/http-kernel": "~4.2", "symfony/http-kernel": "^4.2.6",
"symfony/routing": "~3.4|~4.0", "symfony/routing": "~3.4|~4.0",
"symfony/twig-bundle": "~4.2", "symfony/twig-bundle": "~4.2",
"symfony/var-dumper": "~3.4|~4.0", "symfony/var-dumper": "~3.4|~4.0",

View File

@ -205,38 +205,36 @@ class DateIntervalType extends AbstractType
})); }));
}; };
$resolver->setDefaults( $resolver->setDefaults([
[ 'with_years' => true,
'with_years' => true, 'with_months' => true,
'with_months' => true, 'with_days' => true,
'with_days' => true, 'with_weeks' => false,
'with_weeks' => false, 'with_hours' => false,
'with_hours' => false, 'with_minutes' => false,
'with_minutes' => false, 'with_seconds' => false,
'with_seconds' => false, 'with_invert' => false,
'with_invert' => false, 'years' => range(0, 100),
'years' => range(0, 100), 'months' => range(0, 12),
'months' => range(0, 12), 'weeks' => range(0, 52),
'weeks' => range(0, 52), 'days' => range(0, 31),
'days' => range(0, 31), 'hours' => range(0, 24),
'hours' => range(0, 24), 'minutes' => range(0, 60),
'minutes' => range(0, 60), 'seconds' => range(0, 60),
'seconds' => range(0, 60), 'widget' => 'choice',
'widget' => 'choice', 'input' => 'dateinterval',
'input' => 'dateinterval', 'placeholder' => $placeholderDefault,
'placeholder' => $placeholderDefault, 'by_reference' => true,
'by_reference' => true, 'error_bubbling' => false,
'error_bubbling' => false, // If initialized with a \DateInterval object, FormType initializes
// If initialized with a \DateInterval object, FormType initializes // this option to "\DateInterval". Since the internal, normalized
// this option to "\DateInterval". Since the internal, normalized // representation is not \DateInterval, but an array, we need to unset
// representation is not \DateInterval, but an array, we need to unset // this option.
// this option. 'data_class' => null,
'data_class' => null, 'compound' => $compound,
'compound' => $compound, 'empty_data' => $emptyData,
'empty_data' => $emptyData, 'labels' => [],
'labels' => [], ]);
]
);
$resolver->setNormalizer('placeholder', $placeholderNormalizer); $resolver->setNormalizer('placeholder', $placeholderNormalizer);
$resolver->setNormalizer('labels', $labelsNormalizer); $resolver->setNormalizer('labels', $labelsNormalizer);

View File

@ -144,12 +144,10 @@ class DefaultChoiceListFactoryTest extends TestCase
public function testCreateFromChoicesGrouped() public function testCreateFromChoicesGrouped()
{ {
$list = $this->factory->createListFromChoices( $list = $this->factory->createListFromChoices([
[ 'Group 1' => ['A' => $this->obj1, 'B' => $this->obj2],
'Group 1' => ['A' => $this->obj1, 'B' => $this->obj2], 'Group 2' => ['C' => $this->obj3, 'D' => $this->obj4],
'Group 2' => ['C' => $this->obj3, 'D' => $this->obj4], ]);
]
);
$this->assertObjectListWithGeneratedValues($list); $this->assertObjectListWithGeneratedValues($list);
} }

View File

@ -47,6 +47,7 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
'token' => $response->headers->get('X-Debug-Token'), 'token' => $response->headers->get('X-Debug-Token'),
'start_time' => $startTime * 1000, 'start_time' => $startTime * 1000,
'events' => [], 'events' => [],
'stopwatch_installed' => \class_exists(Stopwatch::class, false),
]; ];
} }
@ -139,6 +140,14 @@ class TimeDataCollector extends DataCollector implements LateDataCollectorInterf
return $this->data['start_time']; return $this->data['start_time'];
} }
/**
* @return bool whether or not the stopwatch component is installed
*/
public function isStopwatchInstalled()
{
return $this->data['stopwatch_installed'];
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */

View File

@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\TimeDataCollector; use Symfony\Component\HttpKernel\DataCollector\TimeDataCollector;
use Symfony\Component\Stopwatch\Stopwatch;
/** /**
* @group time-sensitive * @group time-sensitive
@ -51,5 +52,6 @@ class TimeDataCollectorTest extends TestCase
$c->collect($request, new Response()); $c->collect($request, new Response());
$this->assertEquals(123456000, $c->getStartTime()); $this->assertEquals(123456000, $c->getStartTime());
$this->assertSame(\class_exists(Stopwatch::class, false), $c->isStopwatchInstalled());
} }
} }

View File

@ -851,13 +851,11 @@ class OptionsResolverTest extends TestCase
$this->resolver->setDefined('foo'); $this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'int[][]'); $this->resolver->setAllowedTypes('foo', 'int[][]');
$this->resolver->resolve( $this->resolver->resolve([
[ 'foo' => [
'foo' => [ [1.2],
[1.2], ],
], ]);
]
);
} }
/** /**
@ -1918,13 +1916,11 @@ class OptionsResolverTest extends TestCase
1, 2, 1, 2,
], ],
], ],
], $this->resolver->resolve( ], $this->resolver->resolve([
[ 'foo' => [
'foo' => [ [1, 2],
[1, 2], ],
], ]));
]
));
} }
public function testNested2Arrays() public function testNested2Arrays()
@ -1964,17 +1960,15 @@ class OptionsResolverTest extends TestCase
$this->resolver->setDefined('foo'); $this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'float[][][][]'); $this->resolver->setAllowedTypes('foo', 'float[][][][]');
$this->resolver->resolve( $this->resolver->resolve([
[ 'foo' => [
'foo' => [ [
[ [
[ [1, 2],
[1, 2],
],
], ],
], ],
] ],
); ]);
} }
/** /**

View File

@ -51,7 +51,7 @@ class ExecutableFinder
public function find($name, $default = null, array $extraDirs = []) public function find($name, $default = null, array $extraDirs = [])
{ {
if (ini_get('open_basedir')) { if (ini_get('open_basedir')) {
$searchPath = explode(PATH_SEPARATOR, ini_get('open_basedir')); $searchPath = array_merge(explode(PATH_SEPARATOR, ini_get('open_basedir')), $extraDirs);
$dirs = []; $dirs = [];
foreach ($searchPath as $path) { foreach ($searchPath as $path) {
// Silencing against https://bugs.php.net/69240 // Silencing against https://bugs.php.net/69240

View File

@ -131,8 +131,6 @@ class ExceptionListener
} catch (\Exception $e) { } catch (\Exception $e) {
$event->setException($e); $event->setException($e);
} }
return;
} }
if (null !== $this->logger) { if (null !== $this->logger) {
@ -150,7 +148,7 @@ class ExceptionListener
$subRequest = $this->httpUtils->createRequest($event->getRequest(), $this->errorPage); $subRequest = $this->httpUtils->createRequest($event->getRequest(), $this->errorPage);
$subRequest->attributes->set(Security::ACCESS_DENIED_ERROR, $exception); $subRequest->attributes->set(Security::ACCESS_DENIED_ERROR, $exception);
$event->setResponse($event->getKernel()->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true)); $event->setResponse($event->getKernel()->handle($subRequest, HttpKernelInterface::SUB_REQUEST));
$event->allowCustomResponseCode(); $event->allowCustomResponseCode();
} }
} catch (\Exception $e) { } catch (\Exception $e) {

View File

@ -130,10 +130,8 @@ class ExceptionListenerTest extends TestCase
{ {
$event = $this->createEvent($exception); $event = $this->createEvent($exception);
$accessDeniedHandler = $this->getMockBuilder('Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface')->getMock(); $listener = $this->createExceptionListener(null, $this->createTrustResolver(true), null, null, null, $this->createCustomAccessDeniedHandler(new Response('error')));
$accessDeniedHandler->expects($this->once())->method('handle')->will($this->returnValue(new Response('error')));
$listener = $this->createExceptionListener(null, $this->createTrustResolver(true), null, null, null, $accessDeniedHandler);
$listener->onKernelException($event); $listener->onKernelException($event);
$this->assertEquals('error', $event->getResponse()->getContent()); $this->assertEquals('error', $event->getResponse()->getContent());
@ -147,16 +145,51 @@ class ExceptionListenerTest extends TestCase
{ {
$event = $this->createEvent($exception); $event = $this->createEvent($exception);
$tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock(); $listener = $this->createExceptionListener($this->createTokenStorage(), $this->createTrustResolver(false), null, $this->createEntryPoint());
$tokenStorage->expects($this->once())->method('getToken')->will($this->returnValue($this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock()));
$listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false), null, $this->createEntryPoint());
$listener->onKernelException($event); $listener->onKernelException($event);
$this->assertEquals('OK', $event->getResponse()->getContent()); $this->assertEquals('OK', $event->getResponse()->getContent());
$this->assertSame(null === $eventException ? $exception : $eventException, $event->getException()->getPrevious()); $this->assertSame(null === $eventException ? $exception : $eventException, $event->getException()->getPrevious());
} }
/**
* @dataProvider getAccessDeniedExceptionProvider
*/
public function testAccessDeniedExceptionNotFullFledgedAndWithAccessDeniedHandlerAndWithoutErrorPage(\Exception $exception, \Exception $eventException = null)
{
$event = $this->createEvent($exception);
$listener = $this->createExceptionListener($this->createTokenStorage(), $this->createTrustResolver(false), null, $this->createEntryPoint(), null, $this->createCustomAccessDeniedHandler(new Response('denied', 403)));
$listener->onKernelException($event);
$this->assertEquals('denied', $event->getResponse()->getContent());
$this->assertEquals(403, $event->getResponse()->getStatusCode());
$this->assertSame(null === $eventException ? $exception : $eventException, $event->getException()->getPrevious());
}
/**
* @dataProvider getAccessDeniedExceptionProvider
*/
public function testAccessDeniedExceptionNotFullFledgedAndWithoutAccessDeniedHandlerAndWithErrorPage(\Exception $exception, \Exception $eventException = null)
{
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
$kernel->expects($this->once())->method('handle')->will($this->returnValue(new Response('Unauthorized', 401)));
$event = $this->createEvent($exception, $kernel);
$httpUtils = $this->getMockBuilder('Symfony\Component\Security\Http\HttpUtils')->getMock();
$httpUtils->expects($this->once())->method('createRequest')->will($this->returnValue(Request::create('/error')));
$listener = $this->createExceptionListener($this->createTokenStorage(), $this->createTrustResolver(true), $httpUtils, null, '/error');
$listener->onKernelException($event);
$this->assertTrue($event->isAllowingCustomResponseCode());
$this->assertEquals('Unauthorized', $event->getResponse()->getContent());
$this->assertEquals(401, $event->getResponse()->getStatusCode());
$this->assertSame(null === $eventException ? $exception : $eventException, $event->getException()->getPrevious());
}
public function getAccessDeniedExceptionProvider() public function getAccessDeniedExceptionProvider()
{ {
return [ return [
@ -168,6 +201,22 @@ class ExceptionListenerTest extends TestCase
]; ];
} }
private function createTokenStorage()
{
$tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();
$tokenStorage->expects($this->once())->method('getToken')->will($this->returnValue($this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock()));
return $tokenStorage;
}
private function createCustomAccessDeniedHandler(Response $response)
{
$accessDeniedHandler = $this->getMockBuilder('Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface')->getMock();
$accessDeniedHandler->expects($this->once())->method('handle')->will($this->returnValue($response));
return $accessDeniedHandler;
}
private function createEntryPoint(Response $response = null) private function createEntryPoint(Response $response = null)
{ {
$entryPoint = $this->getMockBuilder('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface')->getMock(); $entryPoint = $this->getMockBuilder('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface')->getMock();

View File

@ -20,11 +20,10 @@ class YamlFileDumperTest extends TestCase
public function testTreeFormatCatalogue() public function testTreeFormatCatalogue()
{ {
$catalogue = new MessageCatalogue('en'); $catalogue = new MessageCatalogue('en');
$catalogue->add( $catalogue->add([
[ 'foo.bar1' => 'value1',
'foo.bar1' => 'value1', 'foo.bar2' => 'value2',
'foo.bar2' => 'value2', ]);
]);
$dumper = new YamlFileDumper(); $dumper = new YamlFileDumper();
@ -34,11 +33,10 @@ class YamlFileDumperTest extends TestCase
public function testLinearFormatCatalogue() public function testLinearFormatCatalogue()
{ {
$catalogue = new MessageCatalogue('en'); $catalogue = new MessageCatalogue('en');
$catalogue->add( $catalogue->add([
[ 'foo.bar1' => 'value1',
'foo.bar1' => 'value1', 'foo.bar2' => 'value2',
'foo.bar2' => 'value2', ]);
]);
$dumper = new YamlFileDumper(); $dumper = new YamlFileDumper();

View File

@ -54,11 +54,9 @@ class ChoiceValidatorTest extends ConstraintValidatorTestCase
{ {
$this->validator->validate( $this->validator->validate(
null, null,
new Choice( new Choice([
[ 'choices' => ['foo', 'bar'],
'choices' => ['foo', 'bar'], ])
]
)
); );
$this->assertNoViolation(); $this->assertNoViolation();
@ -100,6 +98,7 @@ class ChoiceValidatorTest extends ConstraintValidatorTestCase
public function testValidChoiceCallbackClosure() public function testValidChoiceCallbackClosure()
{ {
<<<<<<< HEAD
$constraint = new Choice( $constraint = new Choice(
[ [
'callback' => function () { 'callback' => function () {
@ -107,6 +106,14 @@ class ChoiceValidatorTest extends ConstraintValidatorTestCase
}, },
] ]
); );
=======
$constraint = new Choice([
'strict' => true,
'callback' => function () {
return ['foo', 'bar'];
},
]);
>>>>>>> 3.4
$this->validator->validate('bar', $constraint); $this->validator->validate('bar', $constraint);