diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index 0a5cd42cfda41..ff8faad141cff 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -255,6 +255,17 @@ {{ block('form_widget_simple') }} {%- endblock color_widget -%} +{%- block week_widget -%} + {%- if widget == 'single_text' -%} + {{ block('form_widget_simple') }} + {%- else -%} + {%- set vars = widget == 'text' ? { 'attr': { 'size': 1 }} : {} -%} +
+ {{ form_widget(form.year, vars) }}-{{ form_widget(form.week, vars) }} +
+ {%- endif -%} +{%- endblock week_widget -%} + {# Labels #} {%- block form_label -%} diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php index d7868b274b753..6fb468b9dd7ce 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php @@ -2722,6 +2722,104 @@ public function testColor() [@name="name"] [@class="my&class form-control"] [@value="#0000ff"] +' + ); + } + + public function testWeekSingleText() + { + $this->requiresFeatureSet(404); + + $form = $this->factory->createNamed('holidays', 'Symfony\Component\Form\Extension\Core\Type\WeekType', '1970-W01', [ + 'input' => 'string', + 'widget' => 'single_text', + ]); + + $this->assertWidgetMatchesXpath($form->createView(), ['attr' => ['class' => 'my&class']], + '/input + [@type="week"] + [@name="holidays"] + [@class="my&class form-control"] + [@value="1970-W01"] + [not(@maxlength)] +' + ); + } + + public function testWeekSingleTextNoHtml5() + { + $this->requiresFeatureSet(404); + + $form = $this->factory->createNamed('holidays', 'Symfony\Component\Form\Extension\Core\Type\WeekType', '1970-W01', [ + 'input' => 'string', + 'widget' => 'single_text', + 'html5' => false, + ]); + + $this->assertWidgetMatchesXpath($form->createView(), ['attr' => ['class' => 'my&class']], + '/input + [@type="text"] + [@name="holidays"] + [@class="my&class form-control"] + [@value="1970-W01"] + [not(@maxlength)] +' + ); + } + + public function testWeekChoices() + { + $this->requiresFeatureSet(404); + + $data = ['year' => date('Y'), 'week' => 1]; + + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\WeekType', $data, [ + 'input' => 'array', + 'required' => false, + ]); + + $this->assertWidgetMatchesXpath($form->createView(), ['attr' => ['class' => 'my&class']], + '/div + [@class="my&class"] + [ + ./select + [@id="name_year"] + [@class="form-control"] + [./option[@value="'.$data['year'].'"][@selected="selected"]] + /following-sibling::select + [@id="name_week"] + [@class="form-control"] + [./option[@value="'.$data['week'].'"][@selected="selected"]] + ] + [count(.//select)=2]' + ); + } + + public function testWeekText() + { + $this->requiresFeatureSet(404); + + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\WeekType', '2000-W01', [ + 'input' => 'string', + 'widget' => 'text', + ]); + + $this->assertWidgetMatchesXpath($form->createView(), ['attr' => ['class' => 'my&class']], + '/div + [@class="my&class"] + [ + ./input + [@id="name_year"] + [@type="number"] + [@class="form-control"] + [@value="2000"] + /following-sibling::input + [@id="name_week"] + [@type="number"] + [@class="form-control"] + [@value="1"] + ] + [count(./input)=2] ' ); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/week_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/week_widget.html.php new file mode 100644 index 0000000000000..610b6e0c19eac --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/week_widget.html.php @@ -0,0 +1,14 @@ + + block($form, 'form_widget_simple'); ?> + + ['size' => 1]] : [] ?> +
block($form, 'widget_container_attributes') ?>> + widget($form['year'], $vars); + echo '-'; + echo $view['form']->widget($form['week'], $vars); + ?> +
+ diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index ba3fb1d226afb..99e7078f0f820 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.4.0 ----- + * add new `WeekType` * using different values for the "model_timezone" and "view_timezone" options of the `TimeType` without configuring a reference date is deprecated * preferred choices are repeated in the list of all choices diff --git a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php index b658b9979f64c..1f3431cb49ea7 100644 --- a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php +++ b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php @@ -83,6 +83,7 @@ protected function loadTypes() new Type\CurrencyType(), new Type\TelType(), new Type\ColorType(), + new Type\WeekType(), ]; } diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/WeekToArrayTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/WeekToArrayTransformer.php new file mode 100644 index 0000000000000..51475e235c15a --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/WeekToArrayTransformer.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\Core\DataTransformer; + +use Symfony\Component\Form\DataTransformerInterface; +use Symfony\Component\Form\Exception\TransformationFailedException; + +/** + * Transforms between an ISO 8601 week date string and an array. + * + * @author Damien Fayet + */ +class WeekToArrayTransformer implements DataTransformerInterface +{ + /** + * Transforms a string containing an ISO 8601 week date into an array. + * + * @param string|null $value A week date string + * + * @return array A value containing year and week + * + * @throws TransformationFailedException If the given value is not a string, + * or if the given value does not follow the right format + */ + public function transform($value) + { + if (null === $value) { + return ['year' => null, 'week' => null]; + } + + if (!\is_string($value)) { + throw new TransformationFailedException(sprintf('Value is expected to be a string but was "%s".', \is_object($value) ? \get_class($value) : \gettype($value))); + } + + if (0 === preg_match('/^(?P\d{4})-W(?P\d{2})$/', $value, $matches)) { + throw new TransformationFailedException('Given data does not follow the date format "Y-\WW".'); + } + + return [ + 'year' => (int) $matches['year'], + 'week' => (int) $matches['week'], + ]; + } + + /** + * Transforms an array into a week date string. + * + * @param array $value An array containing a year and a week number + * + * @return string|null A week date string following the format Y-\WW + * + * @throws TransformationFailedException If the given value can not be merged in a valid week date string, + * or if the obtained week date does not exists + */ + public function reverseTransform($value) + { + if (null === $value || [] === $value) { + return null; + } + + if (!\is_array($value)) { + throw new TransformationFailedException(sprintf('Value is expected to be an array, but was "%s".', \is_object($value) ? \get_class($value) : \gettype($value))); + } + + if (!\array_key_exists('year', $value)) { + throw new TransformationFailedException('Key "year" is missing.'); + } + + if (!\array_key_exists('week', $value)) { + throw new TransformationFailedException('Key "week" is missing.'); + } + + if ($additionalKeys = array_diff(array_keys($value), ['year', 'week'])) { + throw new TransformationFailedException(sprintf('Expected only keys "year" and "week" to be present, but also got ["%s"].', implode('", "', $additionalKeys))); + } + + if (null === $value['year'] && null === $value['week']) { + return null; + } + + if (!\is_int($value['year'])) { + throw new TransformationFailedException(sprintf('Year is expected to be an integer, but was "%s".', \is_object($value['year']) ? \get_class($value['year']) : \gettype($value['year']))); + } + + if (!\is_int($value['week'])) { + throw new TransformationFailedException(sprintf('Week is expected to be an integer, but was "%s".', \is_object($value['week']) ? \get_class($value['week']) : \gettype($value['week']))); + } + + // The 28th December is always in the last week of the year + if (date('W', strtotime('28th December '.$value['year'])) < $value['week']) { + throw new TransformationFailedException(sprintf('Week "%d" does not exist for year "%d".', $value['week'], $value['year'])); + } + + return sprintf('%d-W%02d', $value['year'], $value['week']); + } +} diff --git a/src/Symfony/Component/Form/Extension/Core/Type/WeekType.php b/src/Symfony/Component/Form/Extension/Core/Type/WeekType.php new file mode 100644 index 0000000000000..70e0000ad9912 --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Core/Type/WeekType.php @@ -0,0 +1,192 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\Core\Type; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Exception\LogicException; +use Symfony\Component\Form\Extension\Core\DataTransformer\WeekToArrayTransformer; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormView; +use Symfony\Component\Form\ReversedTransformer; +use Symfony\Component\OptionsResolver\Options; +use Symfony\Component\OptionsResolver\OptionsResolver; + +class WeekType extends AbstractType +{ + private static $widgets = [ + 'text' => IntegerType::class, + 'choice' => ChoiceType::class, + ]; + + /** + * {@inheritdoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + if ('string' === $options['input']) { + $builder->addModelTransformer(new WeekToArrayTransformer()); + } + + if ('single_text' === $options['widget']) { + $builder->addViewTransformer(new ReversedTransformer(new WeekToArrayTransformer())); + } else { + $yearOptions = $weekOptions = [ + 'error_bubbling' => true, + 'empty_data' => '', + ]; + // when the form is compound the entries of the array are ignored in favor of children data + // so we need to handle the cascade setting here + $emptyData = $builder->getEmptyData() ?: []; + + $yearOptions['empty_data'] = $emptyData['year'] ?? ''; + $weekOptions['empty_data'] = $emptyData['week'] ?? ''; + + if (isset($options['invalid_message'])) { + $yearOptions['invalid_message'] = $options['invalid_message']; + $weekOptions['invalid_message'] = $options['invalid_message']; + } + + if (isset($options['invalid_message_parameters'])) { + $yearOptions['invalid_message_parameters'] = $options['invalid_message_parameters']; + $weekOptions['invalid_message_parameters'] = $options['invalid_message_parameters']; + } + + if ('choice' === $options['widget']) { + // Only pass a subset of the options to children + $yearOptions['choices'] = array_combine($options['years'], $options['years']); + $yearOptions['placeholder'] = $options['placeholder']['year']; + $yearOptions['choice_translation_domain'] = $options['choice_translation_domain']['year']; + + $weekOptions['choices'] = array_combine($options['weeks'], $options['weeks']); + $weekOptions['placeholder'] = $options['placeholder']['week']; + $weekOptions['choice_translation_domain'] = $options['choice_translation_domain']['week']; + + // Append generic carry-along options + foreach (['required', 'translation_domain'] as $passOpt) { + $yearOptions[$passOpt] = $options[$passOpt]; + $weekOptions[$passOpt] = $options[$passOpt]; + } + } + + $builder->add('year', self::$widgets[$options['widget']], $yearOptions); + $builder->add('week', self::$widgets[$options['widget']], $weekOptions); + } + } + + /** + * {@inheritdoc} + */ + public function buildView(FormView $view, FormInterface $form, array $options) + { + $view->vars['widget'] = $options['widget']; + + if ($options['html5']) { + $view->vars['type'] = 'week'; + } + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $compound = function (Options $options) { + return 'single_text' !== $options['widget']; + }; + + $placeholderDefault = function (Options $options) { + return $options['required'] ? null : ''; + }; + + $placeholderNormalizer = function (Options $options, $placeholder) use ($placeholderDefault) { + if (\is_array($placeholder)) { + $default = $placeholderDefault($options); + + return array_merge( + ['year' => $default, 'week' => $default], + $placeholder + ); + } + + return [ + 'year' => $placeholder, + 'week' => $placeholder, + ]; + }; + + $choiceTranslationDomainNormalizer = function (Options $options, $choiceTranslationDomain) { + if (\is_array($choiceTranslationDomain)) { + $default = false; + + return array_replace( + ['year' => $default, 'week' => $default], + $choiceTranslationDomain + ); + } + + return [ + 'year' => $choiceTranslationDomain, + 'week' => $choiceTranslationDomain, + ]; + }; + + $resolver->setDefaults([ + 'years' => range(date('Y') - 10, date('Y') + 10), + 'weeks' => array_combine(range(1, 53), range(1, 53)), + 'widget' => 'single_text', + 'input' => 'array', + 'placeholder' => $placeholderDefault, + 'html5' => static function (Options $options) { + return 'single_text' === $options['widget']; + }, + 'error_bubbling' => false, + 'empty_data' => function (Options $options) { + return $options['compound'] ? [] : ''; + }, + 'compound' => $compound, + 'choice_translation_domain' => false, + ]); + + $resolver->setNormalizer('placeholder', $placeholderNormalizer); + $resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer); + $resolver->setNormalizer('html5', function (Options $options, $html5) { + if ($html5 && 'single_text' !== $options['widget']) { + throw new LogicException(sprintf('The "widget" option of %s must be set to "single_text" when the "html5" option is enabled.', self::class)); + } + + return $html5; + }); + + $resolver->setAllowedValues('input', [ + 'string', + 'array', + ]); + + $resolver->setAllowedValues('widget', [ + 'single_text', + 'text', + 'choice', + ]); + + $resolver->setAllowedTypes('years', 'int[]'); + $resolver->setAllowedTypes('weeks', 'int[]'); + } + + /** + * {@inheritdoc} + */ + public function getBlockPrefix() + { + return 'week'; + } +} diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index 8f1231e3bc293..c565894ccc513 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -2765,4 +2765,87 @@ public function submitFormNoValidateProvider() [true], ]; } + + public function testWeekSingleText() + { + $form = $this->factory->createNamed('holidays', 'Symfony\Component\Form\Extension\Core\Type\WeekType', '1970-W01', [ + 'input' => 'string', + 'widget' => 'single_text', + ]); + + $this->assertWidgetMatchesXpath($form->createView(), ['attr' => ['class' => 'my&class']], + '/input + [@type="week"] + [@name="holidays"] + [@class="my&class"] + [@value="1970-W01"] +' + ); + } + + public function testWeekSingleTextNoHtml5() + { + $form = $this->factory->createNamed('holidays', 'Symfony\Component\Form\Extension\Core\Type\WeekType', '1970-W01', [ + 'input' => 'string', + 'widget' => 'single_text', + 'html5' => false, + ]); + + $this->assertWidgetMatchesXpath($form->createView(), ['attr' => ['class' => 'my&class']], + '/input + [@type="text"] + [@name="holidays"] + [@class="my&class"] + [@value="1970-W01"] +' + ); + } + + public function testWeekChoices() + { + $data = ['year' => date('Y'), 'week' => 1]; + + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\WeekType', $data, [ + 'input' => 'array', + 'required' => false, + ]); + + $this->assertWidgetMatchesXpath($form->createView(), ['attr' => ['class' => 'my&class']], + '/div + [@class="my&class"] + [ + ./select + [@id="name_year"] + [./option[@value="'.$data['year'].'"][@selected="selected"]] + /following-sibling::select + [@id="name_week"] + [./option[@value="'.$data['week'].'"][@selected="selected"]] + ] + [count(.//select)=2]' + ); + } + + public function testWeekText() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\WeekType', '2000-W01', [ + 'input' => 'string', + 'widget' => 'text', + ]); + + $this->assertWidgetMatchesXpath($form->createView(), ['attr' => ['class' => 'my&class']], + '/div + [@class="my&class"] + [ + ./input + [@id="name_year"] + [@type="number"] + [@value="2000"] + /following-sibling::input + [@id="name_week"] + [@type="number"] + [@value="1"] + ] + [count(./input)=2]' + ); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/WeekToArrayTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/WeekToArrayTransformerTest.php new file mode 100644 index 0000000000000..3f681622a8a1c --- /dev/null +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/WeekToArrayTransformerTest.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\DataTransformer\WeekToArrayTransformer; + +class WeekToArrayTransformerTest extends TestCase +{ + public function testTransform() + { + $transformer = new WeekToArrayTransformer(); + + $this->assertSame(['year' => 2019, 'week' => 1], $transformer->transform('2019-W01')); + } + + public function testTransformEmpty() + { + $transformer = new WeekToArrayTransformer(); + + $this->assertSame(['year' => null, 'week' => null], $transformer->transform(null)); + } + + /** + * @dataProvider transformationFailuresProvider + */ + public function testTransformationFailures($input, string $message) + { + $this->expectException(TransformationFailedException::class); + $this->expectExceptionMessage($message); + + $transformer = new WeekToArrayTransformer(); + $transformer->transform($input); + } + + public function transformationFailuresProvider(): array + { + return [ + 'malformed string' => ['lorem', 'Given data does not follow the date format "Y-\WW".'], + 'non-string' => [[], 'Value is expected to be a string but was "array".'], + ]; + } + + public function testReverseTransform() + { + $transformer = new WeekToArrayTransformer(); + + $input = [ + 'year' => 2019, + 'week' => 1, + ]; + + $this->assertEquals('2019-W01', $transformer->reverseTransform($input)); + } + + public function testReverseTransformCompletelyEmpty() + { + $transformer = new WeekToArrayTransformer(); + + $input = [ + 'year' => null, + 'week' => null, + ]; + + $this->assertNull($transformer->reverseTransform($input)); + } + + public function testReverseTransformNull() + { + $transformer = new WeekToArrayTransformer(); + + $this->assertNull($transformer->reverseTransform(null)); + } + + public function testReverseTransformEmpty() + { + $transformer = new WeekToArrayTransformer(); + + $this->assertNull($transformer->reverseTransform([])); + } + + /** + * @dataProvider reverseTransformationFailuresProvider + */ + public function testReverseTransformFailures($input, string $message) + { + $this->expectException(TransformationFailedException::class); + $this->expectExceptionMessage($message); + + $transformer = new WeekToArrayTransformer(); + $transformer->reverseTransform($input); + } + + public function reverseTransformationFailuresProvider(): array + { + return [ + 'missing year' => [['week' => 1], 'Key "year" is missing.'], + 'missing week' => [['year' => 2019], 'Key "week" is missing.'], + 'integer instead of array' => [0, 'Value is expected to be an array, but was "integer"'], + 'string instead of array' => ['12345', 'Value is expected to be an array, but was "string"'], + 'week invalid' => [['year' => 2019, 'week' => 66], 'Week "66" does not exist for year "2019".'], + 'year null' => [['year' => null, 'week' => 1], 'Year is expected to be an integer, but was "NULL".'], + 'week null' => [['year' => 2019, 'week' => null], 'Week is expected to be an integer, but was "NULL".'], + 'year non-integer' => [['year' => '2019', 'week' => 1], 'Year is expected to be an integer, but was "string".'], + 'week non-integer' => [['year' => 2019, 'week' => '1'], 'Week is expected to be an integer, but was "string".'], + 'unexpected key' => [['year' => 2019, 'bar' => 'baz', 'week' => 1, 'foo' => 'foobar'], 'Expected only keys "year" and "week" to be present, but also got ["bar", "foo"].'], + ]; + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/WeekTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/WeekTypeTest.php new file mode 100644 index 0000000000000..aea4c064b33c9 --- /dev/null +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/WeekTypeTest.php @@ -0,0 +1,323 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests\Extension\Core\Type; + +use Symfony\Component\Form\FormError; + +class WeekTypeTest extends BaseTypeTest +{ + const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\WeekType'; + + public function testSubmitArray() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'widget' => 'choice', + 'input' => 'array', + ]); + + $form->submit([ + 'year' => '2019', + 'week' => '1', + ]); + + $this->assertSame(['year' => 2019, 'week' => 1], $form->getData()); + } + + public function testSubmitString() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'years' => [2019], + 'input' => 'string', + 'widget' => 'choice', + ]); + + $form->submit([ + 'year' => '2019', + 'week' => '1', + ]); + + $this->assertEquals('2019-W01', $form->getData()); + } + + public function testSubmitStringSingleText() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'years' => [2019], + 'input' => 'string', + 'widget' => 'single_text', + ]); + + $form->submit('2019-W01'); + + $this->assertEquals('2019-W01', $form->getData()); + } + + public function testPassDefaultPlaceholderToViewIfNotRequired() + { + $view = $this->factory->create(static::TESTED_TYPE, null, [ + 'required' => false, + 'widget' => 'choice', + ]) + ->createView(); + + $this->assertSame('', $view['year']->vars['placeholder']); + $this->assertSame('', $view['week']->vars['placeholder']); + } + + public function testPassNoPlaceholderToViewIfRequired() + { + $view = $this->factory->create(static::TESTED_TYPE, null, [ + 'required' => true, + 'widget' => 'choice', + ]) + ->createView(); + + $this->assertNull($view['year']->vars['placeholder']); + $this->assertNull($view['week']->vars['placeholder']); + } + + public function testPassPlaceholderAsString() + { + $view = $this->factory->create(static::TESTED_TYPE, null, [ + 'placeholder' => 'Empty', + 'widget' => 'choice', + ]) + ->createView(); + + $this->assertSame('Empty', $view['year']->vars['placeholder']); + $this->assertSame('Empty', $view['week']->vars['placeholder']); + } + + public function testPassPlaceholderAsArray() + { + $view = $this->factory->create(static::TESTED_TYPE, null, [ + 'placeholder' => [ + 'year' => 'Empty year', + 'week' => 'Empty week', + ], + 'widget' => 'choice', + ]) + ->createView(); + + $this->assertSame('Empty year', $view['year']->vars['placeholder']); + $this->assertSame('Empty week', $view['week']->vars['placeholder']); + } + + public function testPassPlaceholderAsPartialArrayAddEmptyIfNotRequired() + { + $view = $this->factory->create(static::TESTED_TYPE, null, [ + 'required' => false, + 'placeholder' => [ + 'year' => 'Empty year', + ], + 'widget' => 'choice', + ]) + ->createView(); + + $this->assertSame('Empty year', $view['year']->vars['placeholder']); + $this->assertSame('', $view['week']->vars['placeholder']); + } + + public function testPassPlaceholderAsPartialArrayAddNullIfRequired() + { + $view = $this->factory->create(static::TESTED_TYPE, null, [ + 'required' => true, + 'placeholder' => [ + 'year' => 'Empty year', + ], + 'widget' => 'choice', + ]) + ->createView(); + + $this->assertSame('Empty year', $view['year']->vars['placeholder']); + $this->assertNull($view['week']->vars['placeholder']); + } + + public function testPassHtml5TypeIfSingleTextAndHtml5Format() + { + $view = $this->factory->create(static::TESTED_TYPE, null, [ + 'widget' => 'single_text', + ]) + ->createView(); + + $this->assertSame('week', $view->vars['type']); + } + + public function testDontPassHtml5TypeIfHtml5NotAllowed() + { + $view = $this->factory->create(static::TESTED_TYPE, null, [ + 'widget' => 'single_text', + 'html5' => false, + ]) + ->createView(); + + $this->assertArrayNotHasKey('type', $view->vars); + } + + public function testDontPassHtml5TypeIfNotSingleText() + { + $view = $this->factory->create(static::TESTED_TYPE, null, [ + 'widget' => 'text', + ]) + ->createView(); + + $this->assertArrayNotHasKey('type', $view->vars); + } + + public function testYearTypeChoiceErrorsBubbleUp() + { + $error = new FormError('Invalid!'); + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'widget' => 'choice', + ]); + + $form['year']->addError($error); + + $this->assertSame([], iterator_to_array($form['year']->getErrors())); + $this->assertSame([$error], iterator_to_array($form->getErrors())); + } + + public function testWeekTypeChoiceErrorsBubbleUp() + { + $error = new FormError('Invalid!'); + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'widget' => 'choice', + ]); + + $form['week']->addError($error); + + $this->assertSame([], iterator_to_array($form['week']->getErrors())); + $this->assertSame([$error], iterator_to_array($form->getErrors())); + } + + public function testPassDefaultChoiceTranslationDomain() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'widget' => 'choice', + ]); + + $view = $form->createView(); + + $this->assertFalse($view['year']->vars['choice_translation_domain']); + $this->assertFalse($view['week']->vars['choice_translation_domain']); + } + + public function testPassChoiceTranslationDomainAsString() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'choice_translation_domain' => 'messages', + 'widget' => 'choice', + ]); + + $view = $form->createView(); + $this->assertSame('messages', $view['year']->vars['choice_translation_domain']); + $this->assertSame('messages', $view['week']->vars['choice_translation_domain']); + } + + public function testPassChoiceTranslationDomainAsArray() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'choice_translation_domain' => [ + 'year' => 'foo', + 'week' => 'test', + ], + 'widget' => 'choice', + ]); + + $view = $form->createView(); + $this->assertSame('foo', $view['year']->vars['choice_translation_domain']); + $this->assertSame('test', $view['week']->vars['choice_translation_domain']); + } + + public function testSubmitNull($expected = null, $norm = null, $view = null) + { + $form = $this->factory->create($this->getTestedType(), null, [ + 'widget' => 'choice', + ]); + $form->submit(null); + + $this->assertSame(['year' => null, 'week' => null], $form->getData()); + $this->assertSame(['year' => null, 'week' => null], $form->getNormData()); + $this->assertSame(['year' => null, 'week' => null], $form->getViewData()); + } + + public function testSubmitFromChoiceEmpty() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'widget' => 'choice', + 'required' => false, + ]); + + $form->submit([ + 'year' => '', + 'week' => '', + ]); + + $this->assertSame(['year' => null, 'week' => null], $form->getData()); + } + + public function testSubmitNullWithText() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'widget' => 'text', + ]); + $form->submit(null); + + $this->assertSame(['year' => null, 'week' => null], $form->getViewData()); + } + + public function testSubmitNullWithSingleText() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'widget' => 'single_text', + 'input' => 'string', + ]); + $form->submit(null); + + $this->assertNull($form->getData()); + $this->assertNull($form->getNormData()); + $this->assertSame('', $form->getViewData()); + } + + public function testSubmitNullUsesDefaultEmptyData($emptyData = [], $expectedData = null) + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'empty_data' => $emptyData, + 'widget' => 'choice', + ]); + $form->submit(null); + + $this->assertSame(['year' => null, 'week' => null], $form->getData()); + } + + /** + * @dataProvider provideEmptyData + */ + public function testSubmitNullUsesDateEmptyDataString($widget, $emptyData, $expectedData) + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'widget' => $widget, + 'empty_data' => $emptyData, + ]); + $form->submit(null); + + $this->assertSame($expectedData, $form->getData()); + } + + public function provideEmptyData() + { + return [ + 'Compound text field' => ['text', ['year' => '2019', 'week' => '1'], ['year' => 2019, 'week' => 1]], + 'Compound choice field' => ['choice', ['year' => '2019', 'week' => '1'], ['year' => 2019, 'week' => 1]], + ]; + } +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy