From 9007911a8594ff6c77e82c877667017b2d797094 Mon Sep 17 00:00:00 2001 From: Valentin Date: Thu, 27 Dec 2018 02:35:06 +0300 Subject: [PATCH 1/5] Do not ignore the choice groups for caching --- .../Factory/CachingFactoryDecorator.php | 31 +------------------ .../Factory/CachingFactoryDecoratorTest.php | 17 ++++++---- 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/CachingFactoryDecorator.php b/src/Symfony/Component/Form/ChoiceList/Factory/CachingFactoryDecorator.php index dba025bc64..ece33ad65c 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/CachingFactoryDecorator.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/CachingFactoryDecorator.php @@ -62,30 +62,6 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface return hash('sha256', $namespace.':'.serialize($value)); } - /** - * Flattens an array into the given output variable. - * - * @param array $array The array to flatten - * @param array $output The flattened output - * - * @internal - */ - private static function flatten(array $array, &$output) - { - if (null === $output) { - $output = array(); - } - - foreach ($array as $key => $value) { - if (\is_array($value)) { - self::flatten($value, $output); - continue; - } - - $output[$key] = $value; - } - } - public function __construct(ChoiceListFactoryInterface $decoratedFactory) { $this->decoratedFactory = $decoratedFactory; @@ -113,12 +89,7 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface // The value is not validated on purpose. The decorated factory may // decide which values to accept and which not. - // We ignore the choice groups for caching. If two choice lists are - // requested with the same choices, but a different grouping, the same - // choice list is returned. - self::flatten($choices, $flatChoices); - - $hash = self::generateHash(array($flatChoices, $value), 'fromChoices'); + $hash = self::generateHash(array($choices, $value), 'fromChoices'); if (!isset($this->lists[$hash])) { $this->lists[$hash] = $this->decoratedFactory->createListFromChoices($choices, $value); diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php index dd6c968bd8..c0d34c1bfd 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php @@ -64,19 +64,24 @@ class CachingFactoryDecoratorTest extends TestCase $this->assertSame($list, $this->factory->createListFromChoices($choices2)); } - public function testCreateFromChoicesFlattensChoices() + public function testCreateFromChoicesGroupedChoices() { $choices1 = array('key' => array('A' => 'a')); $choices2 = array('A' => 'a'); - $list = new \stdClass(); + $list1 = new \stdClass(); + $list2 = new \stdClass(); - $this->decoratedFactory->expects($this->once()) + $this->decoratedFactory->expects($this->at(0)) ->method('createListFromChoices') ->with($choices1) - ->will($this->returnValue($list)); + ->will($this->returnValue($list1)); + $this->decoratedFactory->expects($this->at(1)) + ->method('createListFromChoices') + ->with($choices2) + ->will($this->returnValue($list2)); - $this->assertSame($list, $this->factory->createListFromChoices($choices1)); - $this->assertSame($list, $this->factory->createListFromChoices($choices2)); + $this->assertSame($list1, $this->factory->createListFromChoices($choices1)); + $this->assertSame($list2, $this->factory->createListFromChoices($choices2)); } /** From 3ac98a6a171810b152a51465919411df3054eed2 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Fri, 28 Dec 2018 23:40:08 +0100 Subject: [PATCH 2/5] Revert "minor #28610 [Form] Check for Intl availibility (ro0NL)" This reverts commit 15aa25a1ed7ea6844d6f7873a39a143e3b4587ac, reversing changes made to 3cd411af3e5a0fb74a10f2fbb3575c180b6af1b2. --- .../Component/Form/Extension/Core/Type/CountryType.php | 5 ----- .../Component/Form/Extension/Core/Type/CurrencyType.php | 5 ----- .../Component/Form/Extension/Core/Type/LanguageType.php | 5 ----- .../Component/Form/Extension/Core/Type/LocaleType.php | 5 ----- 4 files changed, 20 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php index c3e381b7c6..195347bc9d 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php @@ -15,7 +15,6 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; -use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Intl\Intl; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -42,10 +41,6 @@ class CountryType extends AbstractType implements ChoiceLoaderInterface { $resolver->setDefaults(array( 'choice_loader' => function (Options $options) { - if (!class_exists(Intl::class)) { - throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s".', static::class)); - } - $choiceTranslationLocale = $options['choice_translation_locale']; return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php index 77ed33b237..4cf76eed58 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php @@ -15,7 +15,6 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; -use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Intl\Intl; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -42,10 +41,6 @@ class CurrencyType extends AbstractType implements ChoiceLoaderInterface { $resolver->setDefaults(array( 'choice_loader' => function (Options $options) { - if (!class_exists(Intl::class)) { - throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s".', static::class)); - } - $choiceTranslationLocale = $options['choice_translation_locale']; return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php index 4ddf80f151..56161563e3 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php @@ -15,7 +15,6 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; -use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Intl\Intl; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -42,10 +41,6 @@ class LanguageType extends AbstractType implements ChoiceLoaderInterface { $resolver->setDefaults(array( 'choice_loader' => function (Options $options) { - if (!class_exists(Intl::class)) { - throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s".', static::class)); - } - $choiceTranslationLocale = $options['choice_translation_locale']; return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php index 6516a692ec..ed8fe5d840 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php @@ -15,7 +15,6 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; -use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Intl\Intl; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -42,10 +41,6 @@ class LocaleType extends AbstractType implements ChoiceLoaderInterface { $resolver->setDefaults(array( 'choice_loader' => function (Options $options) { - if (!class_exists(Intl::class)) { - throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s".', static::class)); - } - $choiceTranslationLocale = $options['choice_translation_locale']; return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { From 6ded31a3b9fcdcfa4f33d1cc812b458cf02f563b Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 31 Dec 2018 18:50:08 +0100 Subject: [PATCH 3/5] [Intl] handle null date and time types --- .../Intl/DateFormatter/IntlDateFormatter.php | 42 +++++++++---------- .../AbstractIntlDateFormatterTest.php | 14 +++++++ 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php b/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php index fe46f3f2b2..be97f93593 100644 --- a/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php +++ b/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php @@ -118,13 +118,13 @@ class IntlDateFormatter private $timeZoneId; /** - * @param string $locale The locale code. The only currently supported locale is "en" (or null using the default locale, i.e. "en") - * @param int $datetype Type of date formatting, one of the format type constants - * @param int $timetype Type of time formatting, one of the format type constants - * @param mixed $timezone Timezone identifier - * @param int $calendar Calendar to use for formatting or parsing. The only currently - * supported value is IntlDateFormatter::GREGORIAN (or null using the default calendar, i.e. "GREGORIAN") - * @param string $pattern Optional pattern to use when formatting + * @param string $locale The locale code. The only currently supported locale is "en" (or null using the default locale, i.e. "en") + * @param int|null $datetype Type of date formatting, one of the format type constants + * @param int|null $timetype Type of time formatting, one of the format type constants + * @param \IntlTimeZone|\DateTimeZone|string|null $timezone Timezone identifier + * @param int $calendar Calendar to use for formatting or parsing. The only currently + * supported value is IntlDateFormatter::GREGORIAN (or null using the default calendar, i.e. "GREGORIAN") + * @param string|null $pattern Optional pattern to use when formatting * * @see http://www.php.net/manual/en/intldateformatter.create.php * @see http://userguide.icu-project.org/formatparse/datetime @@ -142,8 +142,8 @@ class IntlDateFormatter throw new MethodArgumentValueNotImplementedException(__METHOD__, 'calendar', $calendar, 'Only the GREGORIAN calendar is supported'); } - $this->datetype = $datetype; - $this->timetype = $timetype; + $this->datetype = null !== $datetype ? $datetype : self::FULL; + $this->timetype = null !== $timetype ? $timetype : self::FULL; $this->setPattern($pattern); $this->setTimeZone($timezone); @@ -152,13 +152,13 @@ class IntlDateFormatter /** * Static constructor. * - * @param string $locale The locale code. The only currently supported locale is "en" (or null using the default locale, i.e. "en") - * @param int $datetype Type of date formatting, one of the format type constants - * @param int $timetype Type of time formatting, one of the format type constants - * @param string $timezone Timezone identifier - * @param int $calendar Calendar to use for formatting or parsing; default is Gregorian - * One of the calendar constants - * @param string $pattern Optional pattern to use when formatting + * @param string $locale The locale code. The only currently supported locale is "en" (or null using the default locale, i.e. "en") + * @param int|null $datetype Type of date formatting, one of the format type constants + * @param int|null $timetype Type of time formatting, one of the format type constants + * @param \IntlTimeZone|\DateTimeZone|string|null $timezone Timezone identifier + * @param int $calendar Calendar to use for formatting or parsing; default is Gregorian + * One of the calendar constants + * @param string|null $pattern Optional pattern to use when formatting * * @return self * @@ -485,7 +485,7 @@ class IntlDateFormatter /** * Set the formatter's pattern. * - * @param string $pattern A pattern string in conformance with the ICU IntlDateFormatter documentation + * @param string|null $pattern A pattern string in conformance with the ICU IntlDateFormatter documentation * * @return bool true on success or false on failure * @@ -506,9 +506,9 @@ class IntlDateFormatter /** * Set the formatter's timezone identifier. * - * @param string $timeZoneId The time zone ID string of the time zone to use. - * If NULL or the empty string, the default time zone for the - * runtime is used. + * @param string|null $timeZoneId The time zone ID string of the time zone to use. + * If NULL or the empty string, the default time zone for the + * runtime is used. * * @return bool true on success or false on failure * @@ -552,7 +552,7 @@ class IntlDateFormatter /** * This method was added in PHP 5.5 as replacement for `setTimeZoneId()`. * - * @param mixed $timeZone + * @param \IntlTimeZone|\DateTimeZone|string|null $timeZone * * @return bool true on success or false on failure * diff --git a/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php b/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php index 77d3c125c1..1359cc4222 100644 --- a/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php +++ b/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php @@ -46,6 +46,20 @@ abstract class AbstractIntlDateFormatterTest extends TestCase ); } + public function testConstructorWithoutDateType() + { + $formatter = new IntlDateFormatter('en', null, IntlDateFormatter::SHORT, 'UTC', IntlDateFormatter::GREGORIAN); + + $this->assertSame('EEEE, LLLL d, y, h:mm a', $formatter->getPattern()); + } + + public function testConstructorWithoutTimeType() + { + $formatter = new IntlDateFormatter('en', IntlDateFormatter::SHORT, null, 'UTC', IntlDateFormatter::GREGORIAN); + + $this->assertSame('M/d/yy, h:mm:ss a zzzz', $formatter->getPattern()); + } + /** * @dataProvider formatProvider */ From 9f45af4a2b7b6b172029f7bcf6731f579eb3248c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Wed, 2 Jan 2019 23:07:49 +0100 Subject: [PATCH 4/5] Do not risk waiting 100 seconds It this happens, and it happens, this will make the build quite slow. Refs #29760 --- .../Component/Process/Tests/KillableProcessWithOutput.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/Process/Tests/KillableProcessWithOutput.php b/src/Symfony/Component/Process/Tests/KillableProcessWithOutput.php index 6c31ee3054..2bbc386d0f 100644 --- a/src/Symfony/Component/Process/Tests/KillableProcessWithOutput.php +++ b/src/Symfony/Component/Process/Tests/KillableProcessWithOutput.php @@ -14,7 +14,6 @@ $outputs = array( 'Second iteration output', 'One more iteration output', 'This took more time', - 'This one was sooooo slow', ); $iterationTime = 10000; From 6b87b67cf0bb8990671c5dfcbcdcc2e2e7bb07cb Mon Sep 17 00:00:00 2001 From: Eric Stern Date: Wed, 2 Jan 2019 18:50:39 -0800 Subject: [PATCH 5/5] Ensure final input of CommandTester works with default If the final element of `CommandTester::setInputs()` is an empty string (to send the default value), the internal stream the tester uses hits EOF and triggers the `Aborted` exception. This appends an additional EOL to the stream after the `implode` to simulate one final return key, allowing the final input to use the default value when used in the tester's documented style. --- .../Console/Tester/CommandTester.php | 5 +++- .../Tests/Tester/CommandTesterTest.php | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Tester/CommandTester.php b/src/Symfony/Component/Console/Tester/CommandTester.php index 131ca9b160..c2d18fa288 100644 --- a/src/Symfony/Component/Console/Tester/CommandTester.php +++ b/src/Symfony/Component/Console/Tester/CommandTester.php @@ -148,7 +148,10 @@ class CommandTester { $stream = fopen('php://memory', 'r+', false); - fwrite($stream, implode(PHP_EOL, $inputs)); + foreach ($inputs as $input) { + fwrite($stream, $input.PHP_EOL); + } + rewind($stream); return $stream; diff --git a/src/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php b/src/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php index 58eb8103fc..da5f2e7aed 100644 --- a/src/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php +++ b/src/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php @@ -112,6 +112,31 @@ class CommandTesterTest extends TestCase $this->assertEquals(implode('', $questions), $tester->getDisplay(true)); } + public function testCommandWithDefaultInputs() + { + $questions = array( + 'What\'s your name?', + 'How are you?', + 'Where do you come from?', + ); + + $command = new Command('foo'); + $command->setHelperSet(new HelperSet(array(new QuestionHelper()))); + $command->setCode(function ($input, $output) use ($questions, $command) { + $helper = $command->getHelper('question'); + $helper->ask($input, $output, new Question($questions[0], 'Bobby')); + $helper->ask($input, $output, new Question($questions[1], 'Fine')); + $helper->ask($input, $output, new Question($questions[2], 'France')); + }); + + $tester = new CommandTester($command); + $tester->setInputs(array('', '', '')); + $tester->execute(array()); + + $this->assertEquals(0, $tester->getStatusCode()); + $this->assertEquals(implode('', $questions), $tester->getDisplay(true)); + } + /** * @expectedException \RuntimeException * @expectedMessage Aborted