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()
{
$this->passwordEncoderCommandTester->execute(
[
'command' => 'security:encode-password',
'password' => 'p@ssw0rd',
'user-class' => 'Symfony\Component\Security\Core\User\User',
'--empty-salt' => true,
]
);
$this->passwordEncoderCommandTester->execute([
'command' => 'security:encode-password',
'password' => 'p@ssw0rd',
'user-class' => 'Symfony\Component\Security\Core\User\User',
'--empty-salt' => true,
]);
$this->assertContains('Password encoding succeeded', $this->passwordEncoderCommandTester->getDisplay());
$this->assertContains(' Encoded password p@ssw0rd', $this->passwordEncoderCommandTester->getDisplay());

View File

@ -97,7 +97,11 @@
<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">
<p>No timing events have been recorded. Check that symfony/stopwatch is installed and debugging enabled in the kernel.</p>
</div>

View File

@ -5,8 +5,6 @@
background-color: #222;
border-top-left-radius: 4px;
bottom: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
display: none;
height: 36px;
@ -36,8 +34,6 @@
}
.sf-toolbarreset * {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
vertical-align: baseline;
letter-spacing: normal;
@ -371,21 +367,8 @@ div.sf-toolbar .sf-toolbar-block a:hover {
text-align: right;
}
.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;
}
@-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 {
0% { background: #222; }
50% { background: #444; }

View File

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

View File

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

View File

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

View File

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

View File

@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\TimeDataCollector;
use Symfony\Component\Stopwatch\Stopwatch;
/**
* @group time-sensitive
@ -51,5 +52,6 @@ class TimeDataCollectorTest extends TestCase
$c->collect($request, new Response());
$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->setAllowedTypes('foo', 'int[][]');
$this->resolver->resolve(
[
'foo' => [
[1.2],
],
]
);
$this->resolver->resolve([
'foo' => [
[1.2],
],
]);
}
/**
@ -1918,13 +1916,11 @@ class OptionsResolverTest extends TestCase
1, 2,
],
],
], $this->resolver->resolve(
[
'foo' => [
[1, 2],
],
]
));
], $this->resolver->resolve([
'foo' => [
[1, 2],
],
]));
}
public function testNested2Arrays()
@ -1964,17 +1960,15 @@ class OptionsResolverTest extends TestCase
$this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'float[][][][]');
$this->resolver->resolve(
[
'foo' => [
$this->resolver->resolve([
'foo' => [
[
[
[
[1, 2],
],
[1, 2],
],
],
]
);
],
]);
}
/**

View File

@ -51,7 +51,7 @@ class ExecutableFinder
public function find($name, $default = null, array $extraDirs = [])
{
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 = [];
foreach ($searchPath as $path) {
// Silencing against https://bugs.php.net/69240

View File

@ -131,8 +131,6 @@ class ExceptionListener
} catch (\Exception $e) {
$event->setException($e);
}
return;
}
if (null !== $this->logger) {
@ -150,7 +148,7 @@ class ExceptionListener
$subRequest = $this->httpUtils->createRequest($event->getRequest(), $this->errorPage);
$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();
}
} catch (\Exception $e) {

View File

@ -130,10 +130,8 @@ class ExceptionListenerTest extends TestCase
{
$event = $this->createEvent($exception);
$accessDeniedHandler = $this->getMockBuilder('Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface')->getMock();
$accessDeniedHandler->expects($this->once())->method('handle')->will($this->returnValue(new Response('error')));
$listener = $this->createExceptionListener(null, $this->createTrustResolver(true), null, null, null, $this->createCustomAccessDeniedHandler(new Response('error')));
$listener = $this->createExceptionListener(null, $this->createTrustResolver(true), null, null, null, $accessDeniedHandler);
$listener->onKernelException($event);
$this->assertEquals('error', $event->getResponse()->getContent());
@ -147,16 +145,51 @@ class ExceptionListenerTest extends TestCase
{
$event = $this->createEvent($exception);
$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()));
$listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false), null, $this->createEntryPoint());
$listener = $this->createExceptionListener($this->createTokenStorage(), $this->createTrustResolver(false), null, $this->createEntryPoint());
$listener->onKernelException($event);
$this->assertEquals('OK', $event->getResponse()->getContent());
$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()
{
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)
{
$entryPoint = $this->getMockBuilder('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface')->getMock();

View File

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

View File

@ -54,11 +54,9 @@ class ChoiceValidatorTest extends ConstraintValidatorTestCase
{
$this->validator->validate(
null,
new Choice(
[
'choices' => ['foo', 'bar'],
]
)
new Choice([
'choices' => ['foo', 'bar'],
])
);
$this->assertNoViolation();
@ -100,6 +98,7 @@ class ChoiceValidatorTest extends ConstraintValidatorTestCase
public function testValidChoiceCallbackClosure()
{
<<<<<<< HEAD
$constraint = new Choice(
[
'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);