[Form] Add input + regions options to TimezoneType
This commit is contained in:
parent
40a3466268
commit
183307b741
|
@ -74,6 +74,38 @@ Finder
|
||||||
deprecated and will be removed in 4.0 as it used to fix a bug which existed
|
deprecated and will be removed in 4.0 as it used to fix a bug which existed
|
||||||
before version 5.5.23/5.6.7.
|
before version 5.5.23/5.6.7.
|
||||||
|
|
||||||
|
Form
|
||||||
|
----
|
||||||
|
|
||||||
|
* Deprecated `ChoiceLoaderInterface` implementation in `TimezoneType`. Use the "choice_loader" option instead.
|
||||||
|
|
||||||
|
Before:
|
||||||
|
```php
|
||||||
|
class MyTimezoneType extends TimezoneType
|
||||||
|
{
|
||||||
|
public function loadChoices()
|
||||||
|
{
|
||||||
|
// override the method
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
After:
|
||||||
|
```php
|
||||||
|
class MyTimezoneType extends AbstractType
|
||||||
|
{
|
||||||
|
public function. getParent()
|
||||||
|
{
|
||||||
|
return TimezoneType::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefault('choice_loader', ...); // override the option instead
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
FrameworkBundle
|
FrameworkBundle
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
|
|
@ -282,6 +282,35 @@ Form
|
||||||
));
|
));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* Removed `ChoiceLoaderInterface` implementation in `TimezoneType`. Use the "choice_loader" option instead.
|
||||||
|
|
||||||
|
Before:
|
||||||
|
```php
|
||||||
|
class MyTimezoneType extends TimezoneType
|
||||||
|
{
|
||||||
|
public function loadChoices()
|
||||||
|
{
|
||||||
|
// override the method
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
After:
|
||||||
|
```php
|
||||||
|
class MyTimezoneType extends AbstractType
|
||||||
|
{
|
||||||
|
public function. getParent()
|
||||||
|
{
|
||||||
|
return TimezoneType::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefault('choice_loader', ...); // override the option instead
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
FrameworkBundle
|
FrameworkBundle
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ CHANGELOG
|
||||||
-----
|
-----
|
||||||
|
|
||||||
* added `DebugCommand`
|
* added `DebugCommand`
|
||||||
|
* deprecated `ChoiceLoaderInterface` implementation in `TimezoneType`
|
||||||
|
* added options "input" and "regions" to `TimezoneType`
|
||||||
|
|
||||||
3.3.0
|
3.3.0
|
||||||
-----
|
-----
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* 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 a timezone identifier string and a DateTimeZone object.
|
||||||
|
*
|
||||||
|
* @author Roland Franssen <franssen.roland@gmai.com>
|
||||||
|
*/
|
||||||
|
class DateTimeZoneToStringTransformer implements DataTransformerInterface
|
||||||
|
{
|
||||||
|
private $multiple;
|
||||||
|
|
||||||
|
public function __construct($multiple = false)
|
||||||
|
{
|
||||||
|
$this->multiple = $multiple;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function transform($dateTimeZone)
|
||||||
|
{
|
||||||
|
if (null === $dateTimeZone) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->multiple) {
|
||||||
|
if (!is_array($dateTimeZone)) {
|
||||||
|
throw new TransformationFailedException('Expected an array.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_map(array(new self(), 'transform'), $dateTimeZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$dateTimeZone instanceof \DateTimeZone) {
|
||||||
|
throw new TransformationFailedException('Expected a \DateTimeZone.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dateTimeZone->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function reverseTransform($value)
|
||||||
|
{
|
||||||
|
if (null === $value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->multiple) {
|
||||||
|
if (!is_array($value)) {
|
||||||
|
throw new TransformationFailedException('Expected an array.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_map(array(new self(), 'reverseTransform'), $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_string($value)) {
|
||||||
|
throw new TransformationFailedException('Expected a string.');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new \DateTimeZone($value);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,10 @@ namespace Symfony\Component\Form\Extension\Core\Type;
|
||||||
|
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\ChoiceList\ArrayChoiceList;
|
use Symfony\Component\Form\ChoiceList\ArrayChoiceList;
|
||||||
|
use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader;
|
||||||
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
|
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
|
||||||
|
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeZoneToStringTransformer;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\Options;
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
@ -25,9 +28,21 @@ class TimezoneType extends AbstractType implements ChoiceLoaderInterface
|
||||||
* The choices are generated from the ICU function \DateTimeZone::listIdentifiers().
|
* The choices are generated from the ICU function \DateTimeZone::listIdentifiers().
|
||||||
*
|
*
|
||||||
* @var ArrayChoiceList
|
* @var ArrayChoiceList
|
||||||
|
*
|
||||||
|
* @deprecated since version 3.4, to be removed in 4.0
|
||||||
*/
|
*/
|
||||||
private $choiceList;
|
private $choiceList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
if ('datetimezone' === $options['input']) {
|
||||||
|
$builder->addModelTransformer(new DateTimeZoneToStringTransformer($options['multiple']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
@ -41,10 +56,20 @@ class TimezoneType extends AbstractType implements ChoiceLoaderInterface
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
$regions = $options['regions'];
|
||||||
|
|
||||||
|
return new CallbackChoiceLoader(function () use ($regions) {
|
||||||
|
return self::getTimezones($regions);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
'choice_translation_domain' => false,
|
'choice_translation_domain' => false,
|
||||||
|
'input' => 'string',
|
||||||
|
'regions' => \DateTimeZone::ALL,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$resolver->setAllowedValues('input', array('string', 'datetimezone'));
|
||||||
|
|
||||||
|
$resolver->setAllowedTypes('regions', 'int');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,21 +90,29 @@ class TimezoneType extends AbstractType implements ChoiceLoaderInterface
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @deprecated since version 3.4, to be removed in 4.0
|
||||||
*/
|
*/
|
||||||
public function loadChoiceList($value = null)
|
public function loadChoiceList($value = null)
|
||||||
{
|
{
|
||||||
|
@trigger_error(sprintf('Method "%s" is deprecated since version 3.4 and will be removed in 4.0.', __METHOD__), E_USER_DEPRECATED);
|
||||||
|
|
||||||
if (null !== $this->choiceList) {
|
if (null !== $this->choiceList) {
|
||||||
return $this->choiceList;
|
return $this->choiceList;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->choiceList = new ArrayChoiceList(self::getTimezones(), $value);
|
return $this->choiceList = new ArrayChoiceList(self::getTimezones(\DateTimeZone::ALL), $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @deprecated since version 3.4, to be removed in 4.0
|
||||||
*/
|
*/
|
||||||
public function loadChoicesForValues(array $values, $value = null)
|
public function loadChoicesForValues(array $values, $value = null)
|
||||||
{
|
{
|
||||||
|
@trigger_error(sprintf('Method "%s" is deprecated since version 3.4 and will be removed in 4.0.', __METHOD__), E_USER_DEPRECATED);
|
||||||
|
|
||||||
// Optimize
|
// Optimize
|
||||||
$values = array_filter($values);
|
$values = array_filter($values);
|
||||||
if (empty($values)) {
|
if (empty($values)) {
|
||||||
|
@ -96,9 +129,13 @@ class TimezoneType extends AbstractType implements ChoiceLoaderInterface
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @deprecated since version 3.4, to be removed in 4.0
|
||||||
*/
|
*/
|
||||||
public function loadValuesForChoices(array $choices, $value = null)
|
public function loadValuesForChoices(array $choices, $value = null)
|
||||||
{
|
{
|
||||||
|
@trigger_error(sprintf('Method "%s" is deprecated since version 3.4 and will be removed in 4.0.', __METHOD__), E_USER_DEPRECATED);
|
||||||
|
|
||||||
// Optimize
|
// Optimize
|
||||||
$choices = array_filter($choices);
|
$choices = array_filter($choices);
|
||||||
if (empty($choices)) {
|
if (empty($choices)) {
|
||||||
|
@ -116,13 +153,15 @@ class TimezoneType extends AbstractType implements ChoiceLoaderInterface
|
||||||
/**
|
/**
|
||||||
* Returns a normalized array of timezone choices.
|
* Returns a normalized array of timezone choices.
|
||||||
*
|
*
|
||||||
|
* @param int $regions
|
||||||
|
*
|
||||||
* @return array The timezone choices
|
* @return array The timezone choices
|
||||||
*/
|
*/
|
||||||
private static function getTimezones()
|
private static function getTimezones($regions)
|
||||||
{
|
{
|
||||||
$timezones = array();
|
$timezones = array();
|
||||||
|
|
||||||
foreach (\DateTimeZone::listIdentifiers() as $timezone) {
|
foreach (\DateTimeZone::listIdentifiers($regions) as $timezone) {
|
||||||
$parts = explode('/', $timezone);
|
$parts = explode('/', $timezone);
|
||||||
|
|
||||||
if (count($parts) > 2) {
|
if (count($parts) > 2) {
|
||||||
|
@ -139,6 +178,6 @@ class TimezoneType extends AbstractType implements ChoiceLoaderInterface
|
||||||
$timezones[$region][str_replace('_', ' ', $name)] = $timezone;
|
$timezones[$region][str_replace('_', ' ', $name)] = $timezone;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $timezones;
|
return 1 === count($timezones) ? reset($timezones) : $timezones;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* 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\DateTimeZoneToStringTransformer;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DateTimeZoneToStringTransformerTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testSingle()
|
||||||
|
{
|
||||||
|
$transformer = new DateTimeZoneToStringTransformer();
|
||||||
|
|
||||||
|
$this->assertNull($transformer->transform(null));
|
||||||
|
$this->assertNull($transformer->reverseTransform(null));
|
||||||
|
|
||||||
|
$this->assertSame('Europe/Amsterdam', $transformer->transform(new \DateTimeZone('Europe/Amsterdam')));
|
||||||
|
$this->assertEquals(new \DateTimeZone('Europe/Amsterdam'), $transformer->reverseTransform('Europe/Amsterdam'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMultiple()
|
||||||
|
{
|
||||||
|
$transformer = new DateTimeZoneToStringTransformer(true);
|
||||||
|
|
||||||
|
$this->assertNull($transformer->transform(null));
|
||||||
|
$this->assertNull($transformer->reverseTransform(null));
|
||||||
|
|
||||||
|
$this->assertSame(array('Europe/Amsterdam'), $transformer->transform(array(new \DateTimeZone('Europe/Amsterdam'))));
|
||||||
|
$this->assertEquals(array(new \DateTimeZone('Europe/Amsterdam')), $transformer->reverseTransform(array('Europe/Amsterdam')));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
|
||||||
|
*/
|
||||||
|
public function testInvalidTimezone()
|
||||||
|
{
|
||||||
|
(new DateTimeZoneToStringTransformer())->transform(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
|
||||||
|
*/
|
||||||
|
public function testUnknownTimezone()
|
||||||
|
{
|
||||||
|
(new DateTimeZoneToStringTransformer(true))->reverseTransform(array('Foo/Bar'));
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,4 +33,31 @@ class TimezoneTypeTest extends BaseTypeTest
|
||||||
{
|
{
|
||||||
parent::testSubmitNull($expected, $norm, '');
|
parent::testSubmitNull($expected, $norm, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testDateTimeZoneInput()
|
||||||
|
{
|
||||||
|
$form = $this->factory->create(static::TESTED_TYPE, new \DateTimeZone('America/New_York'), array('input' => 'datetimezone'));
|
||||||
|
|
||||||
|
$this->assertSame('America/New_York', $form->createView()->vars['value']);
|
||||||
|
|
||||||
|
$form->submit('Europe/Amsterdam');
|
||||||
|
|
||||||
|
$this->assertEquals(new \DateTimeZone('Europe/Amsterdam'), $form->getData());
|
||||||
|
|
||||||
|
$form = $this->factory->create(static::TESTED_TYPE, array(new \DateTimeZone('America/New_York')), array('input' => 'datetimezone', 'multiple' => true));
|
||||||
|
|
||||||
|
$this->assertSame(array('America/New_York'), $form->createView()->vars['value']);
|
||||||
|
|
||||||
|
$form->submit(array('Europe/Amsterdam', 'Europe/Paris'));
|
||||||
|
|
||||||
|
$this->assertEquals(array(new \DateTimeZone('Europe/Amsterdam'), new \DateTimeZone('Europe/Paris')), $form->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFilterByRegions()
|
||||||
|
{
|
||||||
|
$choices = $this->factory->create(static::TESTED_TYPE, null, array('regions' => \DateTimeZone::EUROPE))
|
||||||
|
->createView()->vars['choices'];
|
||||||
|
|
||||||
|
$this->assertContains(new ChoiceView('Europe/Amsterdam', 'Europe/Amsterdam', 'Amsterdam'), $choices, '', false, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue