Merge branch '5.2' into 5.x

* 5.2:
  skip intl dependent tests if the extension is missing
  make DateCaster tests timezone-agnostic
  error if the input string couldn't be parsed as a date
  IntegerType: Always use en for IntegerToLocalizedStringTransformer Fixes #40456
  Uses the correct assignment action for console options depending if they are short or long
  [HttpKernel] ConfigDataCollector to return known data without the need of a Kernel
  [HttpClient] fix using stream_copy_to_stream() with responses cast to php streams
  FIx Trying to clone an uncloneable object of class
This commit is contained in:
Christian Flothmann 2021-03-28 11:44:11 +02:00
commit 42a56528e9
13 changed files with 111 additions and 23 deletions

View File

@ -108,12 +108,13 @@ class ArrayInput extends Input
$params = [];
foreach ($this->parameters as $param => $val) {
if ($param && \is_string($param) && '-' === $param[0]) {
$glue = ('-' === $param[1]) ? '=' : ' ';
if (\is_array($val)) {
foreach ($val as $v) {
$params[] = $param.('' != $v ? '='.$this->escapeToken($v) : '');
$params[] = $param.('' != $v ? $glue.$this->escapeToken($v) : '');
}
} else {
$params[] = $param.('' != $val ? '='.$this->escapeToken($val) : '');
$params[] = $param.('' != $val ? $glue.$this->escapeToken($val) : '');
}
} else {
$params[] = \is_array($val) ? implode(' ', array_map([$this, 'escapeToken'], $val)) : $this->escapeToken($val);

View File

@ -162,10 +162,10 @@ class ArrayInputTest extends TestCase
public function testToString()
{
$input = new ArrayInput(['-f' => null, '-b' => 'bar', '--foo' => 'b a z', '--lala' => null, 'test' => 'Foo', 'test2' => "A\nB'C"]);
$this->assertEquals('-f -b=bar --foo='.escapeshellarg('b a z').' --lala Foo '.escapeshellarg("A\nB'C"), (string) $input);
$this->assertEquals('-f -b bar --foo='.escapeshellarg('b a z').' --lala Foo '.escapeshellarg("A\nB'C"), (string) $input);
$input = new ArrayInput(['-b' => ['bval_1', 'bval_2'], '--f' => ['fval_1', 'fval_2']]);
$this->assertSame('-b=bval_1 -b=bval_2 --f=fval_1 --f=fval_2', (string) $input);
$this->assertSame('-b bval_1 -b bval_2 --f=fval_1 --f=fval_2', (string) $input);
$input = new ArrayInput(['array_arg' => ['val_1', 'val_2']]);
$this->assertSame('val_1 val_2', (string) $input);

View File

@ -130,6 +130,10 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
} elseif ($timestamp > 253402214400) {
// This timestamp represents UTC midnight of 9999-12-31 to prevent 5+ digit years
throw new TransformationFailedException('Years beyond 9999 are not supported.');
} elseif (false === $timestamp) {
// the value couldn't be parsed but the Intl extension didn't report an error code, this
// could be the case when the Intl polyfill is used which always returns 0 as the error code
throw new TransformationFailedException(sprintf('"%s" could not be parsed as a date.', $value));
}
try {

View File

@ -24,12 +24,13 @@ class IntegerToLocalizedStringTransformer extends NumberToLocalizedStringTransfo
/**
* Constructs a transformer.
*
* @param bool $grouping Whether thousands should be grouped
* @param int $roundingMode One of the ROUND_ constants in this class
* @param bool $grouping Whether thousands should be grouped
* @param int $roundingMode One of the ROUND_ constants in this class
* @param string|null $locale locale used for transforming
*/
public function __construct(?bool $grouping = false, ?int $roundingMode = \NumberFormatter::ROUND_DOWN)
public function __construct(?bool $grouping = false, ?int $roundingMode = \NumberFormatter::ROUND_DOWN, ?string $locale)
{
parent::__construct(0, $grouping, $roundingMode);
parent::__construct(0, $grouping, $roundingMode, $locale);
}
/**

View File

@ -26,7 +26,7 @@ class IntegerType extends AbstractType
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addViewTransformer(new IntegerToLocalizedStringTransformer($options['grouping'], $options['rounding_mode']));
$builder->addViewTransformer(new IntegerToLocalizedStringTransformer($options['grouping'], $options['rounding_mode'], !$options['grouping'] ? 'en' : null));
}
/**

View File

@ -17,13 +17,48 @@ class IntegerTypeTest extends BaseTypeTest
{
public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\IntegerType';
private $previousLocale;
protected function setUp(): void
{
IntlTestHelper::requireIntl($this, false);
$this->previousLocale = \Locale::getDefault();
parent::setUp();
}
protected function tearDown(): void
{
\Locale::setDefault($this->previousLocale);
}
/**
* @requires extension intl
*/
public function testArabicLocale()
{
\Locale::setDefault('ar');
$form = $this->factory->create(static::TESTED_TYPE);
$form->submit('123456');
$this->assertSame(123456, $form->getData());
$this->assertSame('123456', $form->getViewData());
}
/**
* @requires extension intl
*/
public function testArabicLocaleNonHtml5()
{
\Locale::setDefault('ar');
$form = $this->factory->create(static::TESTED_TYPE, null, ['grouping' => true]);
$form->submit('123456');
$this->assertSame(123456, $form->getData());
$this->assertSame('١٢٣٬٤٥٦', $form->getViewData());
}
public function testSubmitRejectsFloats()
{
$form = $this->factory->create(static::TESTED_TYPE);

View File

@ -289,7 +289,7 @@ class StreamWrapper
'uid' => 0,
'gid' => 0,
'rdev' => 0,
'size' => (int) ($headers['content-length'][0] ?? 0),
'size' => (int) ($headers['content-length'][0] ?? -1),
'atime' => 0,
'mtime' => strtotime($headers['last-modified'][0] ?? '') ?: 0,
'ctime' => 0,

View File

@ -75,6 +75,19 @@ abstract class HttpClientTestCase extends BaseHttpClientTestCase
$this->assertTrue(feof($stream));
}
public function testStreamCopyToStream()
{
$client = $this->getHttpClient(__FUNCTION__);
$response = $client->request('GET', 'http://localhost:8057');
$h = fopen('php://temp', 'w+');
stream_copy_to_stream($response->toStream(), $h);
$this->assertTrue(rewind($h));
$this->assertSame("{\n \"SER", fread($h, 10));
$this->assertSame('VER_PROTOCOL', fread($h, 12));
$this->assertFalse(feof($h));
}
public function testToStream404()
{
$client = $this->getHttpClient(__FUNCTION__);

View File

@ -42,10 +42,17 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
*/
public function collect(Request $request, Response $response, \Throwable $exception = null)
{
$eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);
$eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);
$this->data = [
'token' => $response->headers->get('X-Debug-Token'),
'symfony_version' => Kernel::VERSION,
'symfony_state' => 'unknown',
'symfony_minor_version' => sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION),
'symfony_lts' => 4 === Kernel::MINOR_VERSION,
'symfony_state' => $this->determineSymfonyState(),
'symfony_eom' => $eom->format('F Y'),
'symfony_eol' => $eol->format('F Y'),
'env' => isset($this->kernel) ? $this->kernel->getEnvironment() : 'n/a',
'debug' => isset($this->kernel) ? $this->kernel->isDebug() : 'n/a',
'php_version' => \PHP_VERSION,
@ -63,14 +70,6 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
foreach ($this->kernel->getBundles() as $name => $bundle) {
$this->data['bundles'][$name] = new ClassStub(\get_class($bundle));
}
$this->data['symfony_state'] = $this->determineSymfonyState();
$this->data['symfony_minor_version'] = sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION);
$this->data['symfony_lts'] = 4 === Kernel::MINOR_VERSION;
$eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);
$eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);
$this->data['symfony_eom'] = $eom->format('F Y');
$this->data['symfony_eol'] = $eol->format('F Y');
}
if (preg_match('~^(\d+(?:\.\d+)*)(.+)?$~', $this->data['php_version'], $matches) && isset($matches[2])) {

View File

@ -41,6 +41,41 @@ class ConfigDataCollectorTest extends TestCase
$this->assertSame(\extension_loaded('xdebug'), $c->hasXDebug());
$this->assertSame(\extension_loaded('Zend OPcache') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN), $c->hasZendOpcache());
$this->assertSame(\extension_loaded('apcu') && filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN), $c->hasApcu());
$this->assertSame(sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION), $c->getSymfonyMinorVersion());
$this->assertContains($c->getSymfonyState(), ['eol', 'eom', 'dev', 'stable']);
$eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->format('F Y');
$eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->format('F Y');
$this->assertSame($eom, $c->getSymfonyEom());
$this->assertSame($eol, $c->getSymfonyEol());
}
public function testCollectWithoutKernel()
{
$c = new ConfigDataCollector();
$c->collect(new Request(), new Response());
$this->assertSame('n/a', $c->getEnv());
$this->assertSame('n/a', $c->isDebug());
$this->assertSame('config', $c->getName());
$this->assertMatchesRegularExpression('~^'.preg_quote($c->getPhpVersion(), '~').'~', \PHP_VERSION);
$this->assertMatchesRegularExpression('~'.preg_quote((string) $c->getPhpVersionExtra(), '~').'$~', \PHP_VERSION);
$this->assertSame(\PHP_INT_SIZE * 8, $c->getPhpArchitecture());
$this->assertSame(class_exists(\Locale::class, false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a', $c->getPhpIntlLocale());
$this->assertSame(date_default_timezone_get(), $c->getPhpTimezone());
$this->assertSame(Kernel::VERSION, $c->getSymfonyVersion());
$this->assertSame(4 === Kernel::MINOR_VERSION, $c->isSymfonyLts());
$this->assertNull($c->getToken());
$this->assertSame(\extension_loaded('xdebug'), $c->hasXDebug());
$this->assertSame(\extension_loaded('Zend OPcache') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN), $c->hasZendOpcache());
$this->assertSame(\extension_loaded('apcu') && filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN), $c->hasApcu());
$this->assertSame(sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION), $c->getSymfonyMinorVersion());
$this->assertContains($c->getSymfonyState(), ['eol', 'eom', 'dev', 'stable']);
$eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->format('F Y');
$eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->format('F Y');
$this->assertSame($eom, $c->getSymfonyEom());
$this->assertSame($eol, $c->getSymfonyEol());
}
}

View File

@ -43,7 +43,7 @@ class StoreFactoryTest extends TestCase
public function validConnections()
{
if (class_exists(\Redis::class)) {
yield [$this->createMock(\Redis::class), RedisStore::class];
yield [new \Redis(), RedisStore::class];
}
if (class_exists(RedisProxy::class)) {
yield [$this->createMock(RedisProxy::class), RedisStore::class];

View File

@ -91,7 +91,7 @@ class DateCaster
$dates = [];
foreach (clone $p as $i => $d) {
if (self::PERIOD_LIMIT === $i) {
$now = new \DateTimeImmutable();
$now = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
$dates[] = sprintf('%s more', ($end = $p->getEndDate())
? ceil(($end->format('U.u') - $d->format('U.u')) / ((int) $now->add($p->getDateInterval())->format('U.u') - (int) $now->format('U.u')))
: $p->recurrences - $i

View File

@ -341,7 +341,7 @@ EODUMP;
*/
public function testCastPeriod($start, $interval, $end, $options, $xPeriod, $xDates)
{
$p = new \DatePeriod(new \DateTime($start), new \DateInterval($interval), \is_int($end) ? $end : new \DateTime($end), $options);
$p = new \DatePeriod(new \DateTime($start, new \DateTimeZone('UTC')), new \DateInterval($interval), \is_int($end) ? $end : new \DateTime($end, new \DateTimeZone('UTC')), $options);
$stub = new Stub();
$cast = DateCaster::castPeriod($p, [], $stub, false, 0);