diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig
index ef2035ab43f04..8eba307890d91 100644
--- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig
+++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig
@@ -87,6 +87,25 @@
{% endif %}
{%- endblock time_widget %}
+{% block dateinterval_widget %}
+ {% if widget == 'single_text' %}
+ {{- block('form_widget_simple') -}}
+ {% else %}
+ {% set attr = attr|merge({class: (attr.class|default('') ~ ' form-inline')|trim}) %}
+
+ {{ form_errors(form) }}
+ {% if with_years %}{{ form_widget(form.years) }}{% endif %}
+ {% if with_months %}{{ form_widget(form.months) }}{% endif %}
+ {% if with_weeks %}{{ form_widget(form.weeks) }}{% endif %}
+ {% if with_days %}{{ form_widget(form.days) }}{% endif %}
+ {% if with_hours %}{{ form_widget(form.hours) }}{% endif %}
+ {% if with_minutes %}{{ form_widget(form.minutes) }}{% endif %}
+ {% if with_seconds %}{{ form_widget(form.seconds) }}{% endif %}
+ {% if with_invert %}{{ form_widget(form.invert) }}{% endif %}
+
+ {% endif %}
+{% endblock dateinterval_widget %}
+
{% block choice_widget_collapsed -%}
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-control')|trim}) %}
{{- parent() -}}
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 63104def7d3eb..cac4077a4368b 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
@@ -131,6 +131,24 @@
{%- endif -%}
{%- endblock time_widget -%}
+{% block dateinterval_widget %}
+ {% if widget == 'single_text' %}
+ {{- block('form_widget_simple') -}}
+ {% else %}
+
+ {{ form_errors(form) }}
+ {% if with_years %}{{ form_widget(form.years) }}{% endif %}
+ {% if with_months %}{{ form_widget(form.months) }}{% endif %}
+ {% if with_weeks %}{{ form_widget(form.weeks) }}{% endif %}
+ {% if with_days %}{{ form_widget(form.days) }}{% endif %}
+ {% if with_hours %}{{ form_widget(form.hours) }}{% endif %}
+ {% if with_minutes %}{{ form_widget(form.minutes) }}{% endif %}
+ {% if with_seconds %}{{ form_widget(form.seconds) }}{% endif %}
+ {% if with_invert %}{{ form_widget(form.invert) }}{% endif %}
+
+ {% endif %}
+{% endblock dateinterval_widget %}
+
{%- block number_widget -%}
{# type="number" doesn't work with floats #}
{%- set type = type|default('text') -%}
diff --git a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php
index 96e6c1961a803..156d5568801a8 100644
--- a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php
+++ b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php
@@ -51,6 +51,7 @@ protected function loadTypes()
new Type\ChoiceType($this->choiceListFactory),
new Type\CollectionType(),
new Type\CountryType(),
+ new Type\DateIntervalType(),
new Type\DateType(),
new Type\DateTimeType(),
new Type\EmailType(),
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php
new file mode 100644
index 0000000000000..c7a4f692533f3
--- /dev/null
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php
@@ -0,0 +1,173 @@
+
+ *
+ * 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;
+use Symfony\Component\Form\Exception\UnexpectedTypeException;
+
+/**
+ * Transforms between a normalized date interval and an interval string/array.
+ *
+ * @author Steffen Roßkamp
+ */
+class DateIntervalToArrayTransformer implements DataTransformerInterface
+{
+ const YEARS = 'years';
+ const MONTHS = 'months';
+ const DAYS = 'days';
+ const HOURS = 'hours';
+ const MINUTES = 'minutes';
+ const SECONDS = 'seconds';
+ const INVERT = 'invert';
+
+ private static $availableFields = array(
+ self::YEARS => 'y',
+ self::MONTHS => 'm',
+ self::DAYS => 'd',
+ self::HOURS => 'h',
+ self::MINUTES => 'i',
+ self::SECONDS => 's',
+ self::INVERT => 'r',
+ );
+ private $fields;
+
+ /**
+ * @param string[] $fields The date fields
+ * @param bool $pad Whether to use padding
+ */
+ public function __construct(array $fields = null, $pad = false)
+ {
+ if (null === $fields) {
+ $fields = array('years', 'months', 'days', 'hours', 'minutes', 'seconds', 'invert');
+ }
+ $this->fields = $fields;
+ $this->pad = (bool) $pad;
+ }
+
+ /**
+ * Transforms a normalized date interval into an interval array.
+ *
+ * @param \DateInterval $dateInterval Normalized date interval.
+ *
+ * @return array Interval array.
+ *
+ * @throws UnexpectedTypeException If the given value is not a \DateInterval instance.
+ */
+ public function transform($dateInterval)
+ {
+ if (null === $dateInterval) {
+ return array_intersect_key(
+ array(
+ 'years' => '',
+ 'months' => '',
+ 'weeks' => '',
+ 'days' => '',
+ 'hours' => '',
+ 'minutes' => '',
+ 'seconds' => '',
+ 'invert' => false,
+ ),
+ array_flip($this->fields)
+ );
+ }
+ if (!$dateInterval instanceof \DateInterval) {
+ throw new UnexpectedTypeException($dateInterval, '\DateInterval');
+ }
+ $result = array();
+ foreach (self::$availableFields as $field => $char) {
+ $result[$field] = $dateInterval->format('%'.($this->pad ? strtoupper($char) : $char));
+ }
+ if (in_array('weeks', $this->fields, true)) {
+ $result['weeks'] = 0;
+ if (isset($result['days']) && (int) $result['days'] >= 7) {
+ $result['weeks'] = (string) floor($result['days'] / 7);
+ $result['days'] = (string) ($result['days'] % 7);
+ }
+ }
+ $result['invert'] = '-' === $result['invert'];
+ $result = array_intersect_key($result, array_flip($this->fields));
+
+ return $result;
+ }
+
+ /**
+ * Transforms an interval array into a normalized date interval.
+ *
+ * @param array $value Interval array
+ *
+ * @return \DateInterval Normalized date interval
+ *
+ * @throws UnexpectedTypeException If the given value is not an array.
+ * @throws TransformationFailedException If the value could not be transformed.
+ */
+ public function reverseTransform($value)
+ {
+ if (null === $value) {
+ return;
+ }
+ if (!is_array($value)) {
+ throw new UnexpectedTypeException($value, 'array');
+ }
+ if ('' === implode('', $value)) {
+ return;
+ }
+ $emptyFields = array();
+ foreach ($this->fields as $field) {
+ if (!isset($value[$field])) {
+ $emptyFields[] = $field;
+ }
+ }
+ if (count($emptyFields) > 0) {
+ throw new TransformationFailedException(sprintf('The fields "%s" should not be empty', implode('", "', $emptyFields)));
+ }
+ if (isset($value['invert']) && !is_bool($value['invert'])) {
+ throw new TransformationFailedException('The value of "invert" must be boolean');
+ }
+ foreach (self::$availableFields as $field => $char) {
+ if ($field !== 'invert' && isset($value[$field]) && !ctype_digit((string) $value[$field])) {
+ throw new TransformationFailedException(sprintf('This amount of "%s" is invalid', $field));
+ }
+ }
+ try {
+ if (!empty($value['weeks'])) {
+ $interval = sprintf(
+ 'P%sY%sM%sWT%sH%sM%sS',
+ empty($value['years']) ? '0' : $value['years'],
+ empty($value['months']) ? '0' : $value['months'],
+ empty($value['weeks']) ? '0' : $value['weeks'],
+ empty($value['hours']) ? '0' : $value['hours'],
+ empty($value['minutes']) ? '0' : $value['minutes'],
+ empty($value['seconds']) ? '0' : $value['seconds']
+ );
+ } else {
+ $interval = sprintf(
+ 'P%sY%sM%sDT%sH%sM%sS',
+ empty($value['years']) ? '0' : $value['years'],
+ empty($value['months']) ? '0' : $value['months'],
+ empty($value['days']) ? '0' : $value['days'],
+ empty($value['hours']) ? '0' : $value['hours'],
+ empty($value['minutes']) ? '0' : $value['minutes'],
+ empty($value['seconds']) ? '0' : $value['seconds']
+ );
+ }
+ $dateInterval = new \DateInterval($interval);
+ if (isset($value['invert'])) {
+ $dateInterval->invert = $value['invert'] ? 1 : 0;
+ }
+ } catch (\Exception $e) {
+ throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
+ }
+
+ return $dateInterval;
+ }
+}
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php
new file mode 100644
index 0000000000000..7b9cca0fbd151
--- /dev/null
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php
@@ -0,0 +1,104 @@
+
+ *
+ * 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;
+use Symfony\Component\Form\Exception\UnexpectedTypeException;
+
+/**
+ * Transforms between a date string and a DateInterval object.
+ *
+ * @author Steffen Roßkamp
+ */
+class DateIntervalToStringTransformer implements DataTransformerInterface
+{
+ private $format;
+ private $parseSigned;
+
+ /**
+ * Transforms a \DateInterval instance to a string.
+ *
+ * @see \DateInterval::format() for supported formats
+ *
+ * @param string $format The date format
+ * @param bool $parseSigned Whether to parse as a signed interval
+ */
+ public function __construct($format = 'P%yY%mM%dDT%hH%iM%sS', $parseSigned = false)
+ {
+ $this->format = $format;
+ $this->parseSigned = $parseSigned;
+ }
+
+ /**
+ * Transforms a DateInterval object into a date string with the configured format.
+ *
+ * @param \DateInterval $value A DateInterval object
+ *
+ * @return string An ISO 8601 or relative date string like date interval presentation
+ *
+ * @throws UnexpectedTypeException If the given value is not a \DateInterval instance.
+ */
+ public function transform($value)
+ {
+ if (null === $value) {
+ return '';
+ }
+ if (!$value instanceof \DateInterval) {
+ throw new UnexpectedTypeException($value, '\DateInterval');
+ }
+
+ return $value->format($this->format);
+ }
+
+ /**
+ * Transforms a date string in the configured format into a DateInterval object.
+ *
+ * @param string $value An ISO 8601 or date string like date interval presentation
+ *
+ * @return \DateInterval An instance of \DateInterval
+ *
+ * @throws UnexpectedTypeException If the given value is not a string.
+ * @throws TransformationFailedException If the date interval could not be parsed.
+ */
+ public function reverseTransform($value)
+ {
+ if (null === $value) {
+ return;
+ }
+ if (!is_string($value)) {
+ throw new UnexpectedTypeException($value, 'string');
+ }
+ if ('' === $value) {
+ return;
+ }
+ if (!$this->isISO8601($value)) {
+ throw new TransformationFailedException('Non ISO 8601 date strings are not supported yet');
+ }
+ $valuePattern = '/^'.preg_replace('/%([yYmMdDhHiIsSwW])(\w)/', '(?P<$1>\d+)$2', $this->format).'$/';
+ if (!preg_match($valuePattern, $value)) {
+ throw new TransformationFailedException(sprintf('Value "%s" contains intervals not accepted by format "%s".', $value, $this->format));
+ }
+ try {
+ $dateInterval = new \DateInterval($value);
+ } catch (\Exception $e) {
+ throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
+ }
+
+ return $dateInterval;
+ }
+
+ private function isISO8601($string)
+ {
+ return preg_match('/^P(?=\w*(?:\d|%\w))(?:\d+Y|%[yY]Y)?(?:\d+M|%[mM]M)?(?:(?:\d+D|%[dD]D)|(?:\d+W|%[wW]W))?(?:T(?:\d+H|[hH]H)?(?:\d+M|[iI]M)?(?:\d+S|[sS]S)?)?$/', $string);
+ }
+}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateIntervalType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateIntervalType.php
new file mode 100644
index 0000000000000..fb2b7d7ff3ec8
--- /dev/null
+++ b/src/Symfony/Component/Form/Extension/Core/Type/DateIntervalType.php
@@ -0,0 +1,273 @@
+
+ *
+ * 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\InvalidConfigurationException;
+use Symfony\Component\Form\Extension\Core\DataTransformer\DateIntervalToArrayTransformer;
+use Symfony\Component\Form\Extension\Core\DataTransformer\DateIntervalToStringTransformer;
+use Symfony\Component\Form\Extension\Core\DataTransformer\IntegerToLocalizedStringTransformer;
+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;
+
+/**
+ * @author Steffen Roßkamp
+ */
+class DateIntervalType extends AbstractType
+{
+ private $timeParts = array(
+ 'years',
+ 'months',
+ 'weeks',
+ 'days',
+ 'hours',
+ 'minutes',
+ 'seconds',
+ );
+ private static $widgets = array(
+ 'text' => 'Symfony\Component\Form\Extension\Core\Type\TextType',
+ 'integer' => 'Symfony\Component\Form\Extension\Core\Type\IntegerType',
+ 'choice' => 'Symfony\Component\Form\Extension\Core\Type\ChoiceType',
+ );
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildForm(FormBuilderInterface $builder, array $options)
+ {
+ if (!$options['with_years'] && !$options['with_months'] && !$options['with_weeks'] && !$options['with_days'] && !$options['with_hours'] && !$options['with_minutes'] && !$options['with_seconds']) {
+ throw new InvalidConfigurationException('You must enable at least one interval field.');
+ }
+ if ($options['with_invert'] && 'single_text' === $options['widget']) {
+ throw new InvalidConfigurationException('The single_text widget does not support invertible intervals.');
+ }
+ if ($options['with_weeks'] && $options['with_days']) {
+ throw new InvalidConfigurationException('You can not enable weeks and days fields together.');
+ }
+ $format = 'P';
+ $parts = array();
+ if ($options['with_years']) {
+ $format .= '%yY';
+ $parts[] = 'years';
+ }
+ if ($options['with_months']) {
+ $format .= '%mM';
+ $parts[] = 'months';
+ }
+ if ($options['with_weeks']) {
+ $format .= '%wW';
+ $parts[] = 'weeks';
+ }
+ if ($options['with_days']) {
+ $format .= '%dD';
+ $parts[] = 'days';
+ }
+ if ($options['with_hours'] || $options['with_minutes'] || $options['with_seconds']) {
+ $format .= 'T';
+ }
+ if ($options['with_hours']) {
+ $format .= '%hH';
+ $parts[] = 'hours';
+ }
+ if ($options['with_minutes']) {
+ $format .= '%iM';
+ $parts[] = 'minutes';
+ }
+ if ($options['with_seconds']) {
+ $format .= '%sS';
+ $parts[] = 'seconds';
+ }
+ if ($options['with_invert']) {
+ $parts[] = 'invert';
+ }
+ if ('single_text' === $options['widget']) {
+ $builder->addViewTransformer(new DateIntervalToStringTransformer($format));
+ } else {
+ $childOptions = array();
+ foreach ($this->timeParts as $part) {
+ if ($options['with_'.$part]) {
+ $childOptions[$part] = array();
+ $childOptions[$part]['error_bubbling'] = true;
+ if ('choice' === $options['widget']) {
+ $childOptions[$part]['choices'] = $options[$part];
+ $childOptions[$part]['placeholder'] = $options['placeholder'][$part];
+ }
+ }
+ }
+ $invertOptions = array(
+ 'error_bubbling' => true,
+ );
+ // Append generic carry-along options
+ foreach (array('required', 'translation_domain') as $passOpt) {
+ foreach ($this->timeParts as $part) {
+ if ($options['with_'.$part]) {
+ $childOptions[$part][$passOpt] = $options[$passOpt];
+ }
+ }
+ if ($options['with_invert']) {
+ $invertOptions[$passOpt] = $options[$passOpt];
+ }
+ }
+ foreach ($this->timeParts as $part) {
+ if ($options['with_'.$part]) {
+ $childForm = $builder->create($part, self::$widgets[$options['widget']], $childOptions[$part]);
+ if ('integer' === $options['widget']) {
+ $childForm->addModelTransformer(
+ new ReversedTransformer(
+ new IntegerToLocalizedStringTransformer()
+ )
+ );
+ }
+ $builder->add($childForm);
+ }
+ }
+ if ($options['with_invert']) {
+ $builder->add('invert', 'Symfony\Component\Form\Extension\Core\Type\CheckboxType', $invertOptions);
+ }
+ $builder->addViewTransformer(new DateIntervalToArrayTransformer($parts, 'text' === $options['widget']));
+ }
+ if ('string' === $options['input']) {
+ $builder->addModelTransformer(
+ new ReversedTransformer(
+ new DateIntervalToStringTransformer($format)
+ )
+ );
+ } elseif ('array' === $options['input']) {
+ $builder->addModelTransformer(
+ new ReversedTransformer(
+ new DateIntervalToArrayTransformer($parts)
+ )
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildView(FormView $view, FormInterface $form, array $options)
+ {
+ $vars = array(
+ 'widget' => $options['widget'],
+ 'with_invert' => $options['with_invert'],
+ );
+ foreach ($this->timeParts as $part) {
+ $vars['with_'.$part] = $options['with_'.$part];
+ }
+ $view->vars = array_replace($view->vars, $vars);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function configureOptions(OptionsResolver $resolver)
+ {
+ $timeParts = $this->timeParts;
+ $compound = function (Options $options) {
+ return $options['widget'] !== 'single_text';
+ };
+
+ $placeholderDefault = function (Options $options) {
+ return $options['required'] ? null : '';
+ };
+
+ $placeholderNormalizer = function (Options $options, $placeholder) use ($placeholderDefault, $timeParts) {
+ if (is_array($placeholder)) {
+ $default = $placeholderDefault($options);
+
+ return array_merge(array_fill_keys($timeParts, $default), $placeholder);
+ }
+
+ return array_fill_keys($timeParts, $placeholder);
+ };
+
+ $resolver->setDefaults(
+ array(
+ '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,
+ )
+ );
+ $resolver->setNormalizer('placeholder', $placeholderNormalizer);
+
+ $resolver->setAllowedValues(
+ 'input',
+ array(
+ 'dateinterval',
+ 'string',
+ 'array',
+ )
+ );
+ $resolver->setAllowedValues(
+ 'widget',
+ array(
+ 'single_text',
+ 'text',
+ 'integer',
+ 'choice',
+ )
+ );
+ // Don't clone \DateInterval classes, as i.e. format()
+ // does not work after that
+ $resolver->setAllowedValues('by_reference', true);
+
+ $resolver->setAllowedTypes('years', 'array');
+ $resolver->setAllowedTypes('months', 'array');
+ $resolver->setAllowedTypes('weeks', 'array');
+ $resolver->setAllowedTypes('days', 'array');
+ $resolver->setAllowedTypes('hours', 'array');
+ $resolver->setAllowedTypes('minutes', 'array');
+ $resolver->setAllowedTypes('seconds', 'array');
+ $resolver->setAllowedTypes('with_years', 'bool');
+ $resolver->setAllowedTypes('with_months', 'bool');
+ $resolver->setAllowedTypes('with_weeks', 'bool');
+ $resolver->setAllowedTypes('with_days', 'bool');
+ $resolver->setAllowedTypes('with_hours', 'bool');
+ $resolver->setAllowedTypes('with_minutes', 'bool');
+ $resolver->setAllowedTypes('with_seconds', 'bool');
+ $resolver->setAllowedTypes('with_invert', 'bool');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getBlockPrefix()
+ {
+ return 'dateinterval';
+ }
+}
diff --git a/src/Symfony/Component/Form/Test/TypeTestCase.php b/src/Symfony/Component/Form/Test/TypeTestCase.php
index 87797757ff3de..9e0b2cf8677cb 100644
--- a/src/Symfony/Component/Form/Test/TypeTestCase.php
+++ b/src/Symfony/Component/Form/Test/TypeTestCase.php
@@ -38,4 +38,9 @@ public static function assertDateTimeEquals(\DateTime $expected, \DateTime $actu
{
self::assertEquals($expected->format('c'), $actual->format('c'));
}
+
+ public static function assertDateIntervalEquals(\DateInterval $expected, \DateInterval $actual)
+ {
+ self::assertEquals($expected->format('%RP%yY%mM%dDT%hH%iM%sS'), $actual->format('%RP%yY%mM%dDT%hH%iM%sS'));
+ }
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalTestCase.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalTestCase.php
new file mode 100644
index 0000000000000..f65e79f262ae8
--- /dev/null
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalTestCase.php
@@ -0,0 +1,20 @@
+
+ *
+ * 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;
+
+abstract class DateIntervalTestCase extends \PHPUnit_Framework_TestCase
+{
+ public static function assertDateIntervalEquals(\DateInterval $expected, \DateInterval $actual)
+ {
+ self::assertEquals($expected->format('%RP%yY%mM%dDT%hH%iM%sS'), $actual->format('%RP%yY%mM%dDT%hH%iM%sS'));
+ }
+}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToArrayTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToArrayTransformerTest.php
new file mode 100644
index 0000000000000..488ea3c06bec0
--- /dev/null
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToArrayTransformerTest.php
@@ -0,0 +1,263 @@
+
+ *
+ * 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 Symfony\Component\Form\Extension\Core\DataTransformer\DateIntervalToArrayTransformer;
+
+/**
+ * @author Steffen Roßkamp
+ */
+class DateIntervalToArrayTransformerTest extends DateIntervalTestCase
+{
+ public function testTransform()
+ {
+ $transformer = new DateIntervalToArrayTransformer();
+ $input = new \DateInterval('P1Y2M3DT4H5M6S');
+ $output = array(
+ 'years' => '1',
+ 'months' => '2',
+ 'days' => '3',
+ 'hours' => '4',
+ 'minutes' => '5',
+ 'seconds' => '6',
+ 'invert' => false,
+ );
+ $this->assertSame($output, $transformer->transform($input));
+ }
+
+ public function testTransformEmpty()
+ {
+ $transformer = new DateIntervalToArrayTransformer();
+ $output = array(
+ 'years' => '',
+ 'months' => '',
+ 'days' => '',
+ 'hours' => '',
+ 'minutes' => '',
+ 'seconds' => '',
+ 'invert' => false,
+ );
+ $this->assertSame($output, $transformer->transform(null));
+ }
+
+ public function testTransformEmptyWithFields()
+ {
+ $transformer = new DateIntervalToArrayTransformer(array('years', 'weeks', 'minutes', 'seconds'));
+ $output = array(
+ 'years' => '',
+ 'weeks' => '',
+ 'minutes' => '',
+ 'seconds' => '',
+ );
+ $this->assertSame($output, $transformer->transform(null));
+ }
+
+ public function testTransformWithFields()
+ {
+ $transformer = new DateIntervalToArrayTransformer(array('years', 'minutes', 'seconds'));
+ $input = new \DateInterval('P1Y2M3DT4H5M6S');
+ $output = array(
+ 'years' => '1',
+ 'minutes' => '5',
+ 'seconds' => '6',
+ );
+ $this->assertSame($output, $transformer->transform($input));
+ }
+
+ public function testTransformWithWeek()
+ {
+ $transformer = new DateIntervalToArrayTransformer(array('weeks', 'minutes', 'seconds'));
+ $input = new \DateInterval('P1Y2M3WT4H5M6S');
+ $output = array(
+ 'weeks' => '3',
+ 'minutes' => '5',
+ 'seconds' => '6',
+ );
+ $input = $transformer->transform($input);
+ ksort($input);
+ ksort($output);
+ $this->assertSame($output, $input);
+ }
+
+ public function testTransformDaysToWeeks()
+ {
+ $transformer = new DateIntervalToArrayTransformer(array('weeks', 'minutes', 'seconds'));
+ $input = new \DateInterval('P1Y2M23DT4H5M6S');
+ $output = array(
+ 'weeks' => '3',
+ 'minutes' => '5',
+ 'seconds' => '6',
+ );
+ $input = $transformer->transform($input);
+ ksort($input);
+ ksort($output);
+ $this->assertSame($output, $input);
+ }
+
+ public function testTransformDaysNotOverflowingToWeeks()
+ {
+ $transformer = new DateIntervalToArrayTransformer(array('days', 'minutes', 'seconds'));
+ $input = new \DateInterval('P1Y2M23DT4H5M6S');
+ $output = array(
+ 'days' => '23',
+ 'minutes' => '5',
+ 'seconds' => '6',
+ );
+ $this->assertSame($output, $transformer->transform($input));
+ }
+
+ public function testTransformWithInvert()
+ {
+ $transformer = new DateIntervalToArrayTransformer(array('years', 'invert'));
+ $input = new \DateInterval('P1Y');
+ $input->invert = 1;
+ $output = array(
+ 'years' => '1',
+ 'invert' => true,
+ );
+ $this->assertSame($output, $transformer->transform($input));
+ }
+
+ public function testTransformWithPadding()
+ {
+ $transformer = new DateIntervalToArrayTransformer(null, true);
+ $input = new \DateInterval('P1Y2M3DT4H5M6S');
+ $output = array(
+ 'years' => '01',
+ 'months' => '02',
+ 'days' => '03',
+ 'hours' => '04',
+ 'minutes' => '05',
+ 'seconds' => '06',
+ 'invert' => false,
+ );
+ $this->assertSame($output, $transformer->transform($input));
+ }
+
+ public function testTransformWithFieldsAndPadding()
+ {
+ $transformer = new DateIntervalToArrayTransformer(array('years', 'minutes', 'seconds'), true);
+ $input = new \DateInterval('P1Y2M3DT4H5M6S');
+ $output = array(
+ 'years' => '01',
+ 'minutes' => '05',
+ 'seconds' => '06',
+ );
+ $this->assertSame($output, $transformer->transform($input));
+ }
+
+ public function testReverseTransformRequiresDateTime()
+ {
+ $transformer = new DateIntervalToArrayTransformer();
+ $this->assertNull($transformer->reverseTransform(null));
+ $this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
+ $transformer->reverseTransform('12345');
+ }
+
+ public function testReverseTransformWithUnsetFields()
+ {
+ $transformer = new DateIntervalToArrayTransformer();
+ $input = array('years' => '1');
+ $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
+ $transformer->reverseTransform($input);
+ }
+
+ public function testReverseTransformWithEmptyFields()
+ {
+ $transformer = new DateIntervalToArrayTransformer(array('years', 'minutes', 'seconds'));
+ $input = array(
+ 'years' => '1',
+ 'minutes' => '',
+ 'seconds' => '6',
+ );
+ $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException', 'This amount of "minutes" is invalid');
+ $transformer->reverseTransform($input);
+ }
+
+ public function testReverseTransformWithWrongInvertType()
+ {
+ $transformer = new DateIntervalToArrayTransformer(array('invert'));
+ $input = array(
+ 'invert' => '1',
+ );
+ $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException', 'The value of "invert" must be boolean');
+ $transformer->reverseTransform($input);
+ }
+
+ public function testReverseTransform()
+ {
+ $transformer = new DateIntervalToArrayTransformer();
+ $input = array(
+ 'years' => '1',
+ 'months' => '2',
+ 'days' => '3',
+ 'hours' => '4',
+ 'minutes' => '5',
+ 'seconds' => '6',
+ 'invert' => false,
+ );
+ $output = new \DateInterval('P01Y02M03DT04H05M06S');
+ $this->assertDateIntervalEquals($output, $transformer->reverseTransform($input));
+ }
+
+ public function testReverseTransformWithWeek()
+ {
+ $transformer = new DateIntervalToArrayTransformer(
+ array('years', 'months', 'weeks', 'hours', 'minutes', 'seconds')
+ );
+ $input = array(
+ 'years' => '1',
+ 'months' => '2',
+ 'weeks' => '3',
+ 'hours' => '4',
+ 'minutes' => '5',
+ 'seconds' => '6',
+ );
+ $output = new \DateInterval('P1Y2M21DT4H5M6S');
+ $this->assertDateIntervalEquals($output, $transformer->reverseTransform($input));
+ }
+
+ public function testReverseTransformWithFields()
+ {
+ $transformer = new DateIntervalToArrayTransformer(array('years', 'minutes', 'seconds'));
+ $input = array(
+ 'years' => '1',
+ 'minutes' => '5',
+ 'seconds' => '6',
+ );
+ $output = new \DateInterval('P1Y0M0DT0H5M6S');
+ $this->assertDateIntervalEquals($output, $transformer->reverseTransform($input));
+ }
+
+ public function testBothTransformsWithWeek()
+ {
+ $transformer = new DateIntervalToArrayTransformer(
+ array('years', 'months', 'weeks', 'hours', 'minutes', 'seconds')
+ );
+ $interval = new \DateInterval('P1Y2M21DT4H5M6S');
+ $array = array(
+ 'years' => '1',
+ 'months' => '2',
+ 'weeks' => '3',
+ 'hours' => '4',
+ 'minutes' => '5',
+ 'seconds' => '6',
+ );
+ $input = $transformer->transform($interval);
+ ksort($input);
+ ksort($array);
+ $this->assertSame($array, $input);
+ $interval = new \DateInterval('P1Y2M0DT4H5M6S');
+ $input['weeks'] = '0';
+ $this->assertDateIntervalEquals($interval, $transformer->reverseTransform($input));
+ }
+}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToStringTransformerTest.php
new file mode 100644
index 0000000000000..9815b70bff8fb
--- /dev/null
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToStringTransformerTest.php
@@ -0,0 +1,120 @@
+
+ *
+ * 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 Symfony\Component\Form\Extension\Core\DataTransformer\DateIntervalToStringTransformer;
+
+/**
+ * @author Steffen Roßkamp
+ */
+class DateIntervalToStringTransformerTest extends DateIntervalTestCase
+{
+ public function dataProviderISO()
+ {
+ $data = array(
+ array('P%YY%MM%DDT%HH%IM%SS', 'P00Y00M00DT00H00M00S', 'PT0S'),
+ array('P%yY%mM%dDT%hH%iM%sS', 'P0Y0M0DT0H0M0S', 'PT0S'),
+ array('P%yY%mM%dDT%hH%iM%sS', 'P10Y2M3DT16H5M6S', 'P10Y2M3DT16H5M6S'),
+ array('P%yY%mM%dDT%hH%iM', 'P10Y2M3DT16H5M', 'P10Y2M3DT16H5M'),
+ array('P%yY%mM%dDT%hH', 'P10Y2M3DT16H', 'P10Y2M3DT16H'),
+ array('P%yY%mM%dD', 'P10Y2M3D', 'P10Y2M3DT0H'),
+ );
+
+ return $data;
+ }
+
+ public function dataProviderDate()
+ {
+ $data = array(
+ array(
+ '%y years %m months %d days %h hours %i minutes %s seconds',
+ '10 years 2 months 3 days 16 hours 5 minutes 6 seconds',
+ 'P10Y2M3DT16H5M6S',
+ ),
+ array(
+ '%y years %m months %d days %h hours %i minutes',
+ '10 years 2 months 3 days 16 hours 5 minutes',
+ 'P10Y2M3DT16H5M',
+ ),
+ array('%y years %m months %d days %h hours', '10 years 2 months 3 days 16 hours', 'P10Y2M3DT16H'),
+ array('%y years %m months %d days', '10 years 2 months 3 days', 'P10Y2M3D'),
+ array('%y years %m months', '10 years 2 months', 'P10Y2M'),
+ array('%y year', '1 year', 'P1Y'),
+ );
+
+ return $data;
+ }
+
+ /**
+ * @dataProvider dataProviderISO
+ */
+ public function testTransform($format, $output, $input)
+ {
+ $transformer = new DateIntervalToStringTransformer($format);
+ $input = new \DateInterval($input);
+ $this->assertEquals($output, $transformer->transform($input));
+ }
+
+ public function testTransformEmpty()
+ {
+ $transformer = new DateIntervalToStringTransformer();
+ $this->assertSame('', $transformer->transform(null));
+ }
+
+ public function testTransformExpectsDateTime()
+ {
+ $transformer = new DateIntervalToStringTransformer();
+ $this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
+ $transformer->transform('1234');
+ }
+
+ /**
+ * @dataProvider dataProviderISO
+ */
+ public function testReverseTransform($format, $input, $output)
+ {
+ $reverseTransformer = new DateIntervalToStringTransformer($format, true);
+ $interval = new \DateInterval($output);
+ $this->assertDateIntervalEquals($interval, $reverseTransformer->reverseTransform($input));
+ }
+
+ /**
+ * @dataProvider dataProviderDate
+ */
+ public function testReverseTransformDateString($format, $input, $output)
+ {
+ $reverseTransformer = new DateIntervalToStringTransformer($format, true);
+ $interval = new \DateInterval($output);
+ $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
+ $this->assertDateIntervalEquals($interval, $reverseTransformer->reverseTransform($input));
+ }
+
+ public function testReverseTransformEmpty()
+ {
+ $reverseTransformer = new DateIntervalToStringTransformer();
+ $this->assertNull($reverseTransformer->reverseTransform(''));
+ }
+
+ public function testReverseTransformExpectsString()
+ {
+ $reverseTransformer = new DateIntervalToStringTransformer();
+ $this->setExpectedException('Symfony\Component\Form\Exception\UnexpectedTypeException');
+ $reverseTransformer->reverseTransform(1234);
+ }
+
+ public function testReverseTransformExpectsValidIntervalString()
+ {
+ $reverseTransformer = new DateIntervalToStringTransformer();
+ $this->setExpectedException('Symfony\Component\Form\Exception\TransformationFailedException');
+ $reverseTransformer->reverseTransform('10Y');
+ }
+}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateIntervalTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateIntervalTypeTest.php
new file mode 100644
index 0000000000000..e40c0949f6961
--- /dev/null
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateIntervalTypeTest.php
@@ -0,0 +1,367 @@
+
+ *
+ * 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;
+use Symfony\Component\Form\Test\TypeTestCase as TestCase;
+
+class DateIntervalTypeTest extends TestCase
+{
+ public function testSubmitDateInterval()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'input' => 'dateinterval',
+ )
+ );
+ $form->submit(
+ array(
+ 'years' => '7',
+ 'months' => '6',
+ 'days' => '5',
+ )
+ );
+ $dateInterval = new \DateInterval('P7Y6M5D');
+ $this->assertDateIntervalEquals($dateInterval, $form->getData());
+ }
+
+ public function testSubmitString()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'input' => 'string',
+ )
+ );
+ $form->submit(
+ array(
+ 'years' => '7',
+ 'months' => '6',
+ 'days' => '5',
+ )
+ );
+ $this->assertEquals('P7Y6M5D', $form->getData());
+ }
+
+ public function testSubmitArray()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'input' => 'array',
+ )
+ );
+ $form->submit(
+ array(
+ 'years' => '7',
+ 'months' => '6',
+ 'days' => '5',
+ )
+ );
+ $this->assertEquals(array('years' => '7', 'months' => '6', 'days' => '5'), $form->getData());
+ }
+
+ public function testSubmitWithoutMonths()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'input' => 'dateinterval',
+ 'with_months' => false,
+ )
+ );
+ $form->setData(new \DateInterval('P7Y5D'));
+ $input = array(
+ 'years' => '7',
+ 'months' => '6',
+ 'days' => '5',
+ );
+ $form->submit($input);
+ $this->assertDateIntervalEquals(new \DateInterval('P7Y5D'), $form->getData());
+ }
+
+ public function testSubmitWithTime()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'input' => 'dateinterval',
+ 'with_hours' => true,
+ 'with_minutes' => true,
+ 'with_seconds' => true,
+ )
+ );
+ $form->setData(new \DateInterval('P7Y6M5DT4H3M2S'));
+ $input = array(
+ 'years' => '7',
+ 'months' => '6',
+ 'days' => '5',
+ 'hours' => '4',
+ 'minutes' => '3',
+ 'seconds' => '2',
+ );
+ $form->submit($input);
+ $this->assertDateIntervalEquals(new \DateInterval('P7Y6M5DT4H3M2S'), $form->getData());
+ }
+
+ public function testSubmitWithWeeks()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'input' => 'dateinterval',
+ 'with_years' => false,
+ 'with_months' => false,
+ 'with_weeks' => true,
+ 'with_days' => false,
+ )
+ );
+ $form->setData(new \DateInterval('P0Y'));
+ $input = array(
+ 'weeks' => '30',
+ );
+ $form->submit($input);
+ $this->assertDateIntervalEquals(new \DateInterval('P30W'), $form->getData());
+ }
+
+ public function testSubmitWithInvert()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'input' => 'dateinterval',
+ 'with_invert' => true,
+ )
+ );
+ $input = array(
+ 'years' => '7',
+ 'months' => '6',
+ 'days' => '5',
+ 'invert' => true,
+ );
+ $form->submit($input);
+ $interval = new \DateInterval('P7Y6M5D');
+ $interval->invert = 1;
+ $this->assertDateIntervalEquals($interval, $form->getData());
+ }
+
+ public function testSubmitStringSingleText()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'input' => 'string',
+ 'widget' => 'single_text',
+ )
+ );
+ $form->submit('P7Y6M5D');
+ $this->assertEquals('P7Y6M5D', $form->getData());
+ $this->assertEquals('P7Y6M5D', $form->getViewData());
+ }
+
+ public function testSubmitStringSingleTextWithSeconds()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'input' => 'string',
+ 'widget' => 'single_text',
+ 'with_hours' => true,
+ 'with_minutes' => true,
+ 'with_seconds' => true,
+ )
+ );
+ $form->submit('P7Y6M5DT4H3M2S');
+ $this->assertEquals('P7Y6M5DT4H3M2S', $form->getData());
+ $this->assertEquals('P7Y6M5DT4H3M2S', $form->getViewData());
+ }
+
+ public function testSubmitArrayInteger()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'widget' => 'integer',
+ 'with_invert' => true,
+ )
+ );
+ $input = array(
+ 'years' => '7',
+ 'months' => '6',
+ 'days' => '5',
+ 'invert' => true,
+ );
+ $form->submit($input);
+ $this->assertSame('7', $form['years']->getData());
+ $this->assertSame('7', $form['years']->getViewData());
+ }
+
+ public function testInitializeWithDateInterval()
+ {
+ // Throws an exception if "data_class" option is not explicitly set
+ // to null in the type
+ $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateIntervalType', new \DateInterval('P0Y'));
+ }
+
+ public function testPassDefaultPlaceholderToViewIfNotRequired()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'required' => false,
+ 'with_seconds' => true,
+ )
+ );
+ $view = $form->createView();
+ $this->assertSame('', $view['years']->vars['placeholder']);
+ $this->assertSame('', $view['months']->vars['placeholder']);
+ $this->assertSame('', $view['days']->vars['placeholder']);
+ $this->assertSame('', $view['seconds']->vars['placeholder']);
+ }
+
+ public function testPassNoPlaceholderToViewIfRequired()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'required' => true,
+ 'with_seconds' => true,
+ )
+ );
+ $view = $form->createView();
+ $this->assertNull($view['years']->vars['placeholder']);
+ $this->assertNull($view['months']->vars['placeholder']);
+ $this->assertNull($view['days']->vars['placeholder']);
+ $this->assertNull($view['seconds']->vars['placeholder']);
+ }
+
+ public function testPassPlaceholderAsString()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'placeholder' => 'Empty',
+ 'with_seconds' => true,
+ )
+ );
+ $view = $form->createView();
+ $this->assertSame('Empty', $view['years']->vars['placeholder']);
+ $this->assertSame('Empty', $view['months']->vars['placeholder']);
+ $this->assertSame('Empty', $view['days']->vars['placeholder']);
+ $this->assertSame('Empty', $view['seconds']->vars['placeholder']);
+ }
+
+ public function testPassPlaceholderAsArray()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'placeholder' => array(
+ 'years' => 'Empty years',
+ 'months' => 'Empty months',
+ 'days' => 'Empty days',
+ 'hours' => 'Empty hours',
+ 'minutes' => 'Empty minutes',
+ 'seconds' => 'Empty seconds',
+ ),
+ 'with_hours' => true,
+ 'with_minutes' => true,
+ 'with_seconds' => true,
+ )
+ );
+ $view = $form->createView();
+ $this->assertSame('Empty years', $view['years']->vars['placeholder']);
+ $this->assertSame('Empty months', $view['months']->vars['placeholder']);
+ $this->assertSame('Empty days', $view['days']->vars['placeholder']);
+ $this->assertSame('Empty hours', $view['hours']->vars['placeholder']);
+ $this->assertSame('Empty minutes', $view['minutes']->vars['placeholder']);
+ $this->assertSame('Empty seconds', $view['seconds']->vars['placeholder']);
+ }
+
+ public function testPassPlaceholderAsPartialArrayAddEmptyIfNotRequired()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'required' => false,
+ 'placeholder' => array(
+ 'years' => 'Empty years',
+ 'days' => 'Empty days',
+ 'hours' => 'Empty hours',
+ 'seconds' => 'Empty seconds',
+ ),
+ 'with_hours' => true,
+ 'with_minutes' => true,
+ 'with_seconds' => true,
+ )
+ );
+ $view = $form->createView();
+ $this->assertSame('Empty years', $view['years']->vars['placeholder']);
+ $this->assertSame('', $view['months']->vars['placeholder']);
+ $this->assertSame('Empty days', $view['days']->vars['placeholder']);
+ $this->assertSame('Empty hours', $view['hours']->vars['placeholder']);
+ $this->assertSame('', $view['minutes']->vars['placeholder']);
+ $this->assertSame('Empty seconds', $view['seconds']->vars['placeholder']);
+ }
+
+ public function testPassPlaceholderAsPartialArrayAddNullIfRequired()
+ {
+ $form = $this->factory->create(
+ 'Symfony\Component\Form\Extension\Core\Type\DateIntervalType',
+ null,
+ array(
+ 'required' => true,
+ 'placeholder' => array(
+ 'years' => 'Empty years',
+ 'days' => 'Empty days',
+ 'hours' => 'Empty hours',
+ 'seconds' => 'Empty seconds',
+ ),
+ 'with_hours' => true,
+ 'with_minutes' => true,
+ 'with_seconds' => true,
+ )
+ );
+ $view = $form->createView();
+ $this->assertSame('Empty years', $view['years']->vars['placeholder']);
+ $this->assertNull($view['months']->vars['placeholder']);
+ $this->assertSame('Empty days', $view['days']->vars['placeholder']);
+ $this->assertSame('Empty hours', $view['hours']->vars['placeholder']);
+ $this->assertNull($view['minutes']->vars['placeholder']);
+ $this->assertSame('Empty seconds', $view['seconds']->vars['placeholder']);
+ }
+
+ public function testDateTypeChoiceErrorsBubbleUp()
+ {
+ $error = new FormError('Invalid!');
+ $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateIntervalType', null);
+ $form['years']->addError($error);
+ $this->assertSame(array(), iterator_to_array($form['years']->getErrors()));
+ $this->assertSame(array($error), iterator_to_array($form->getErrors()));
+ }
+}