From 40f25121c3964a8ce72c05727d45954012a910f5 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 2 Nov 2017 13:33:12 +0100 Subject: [PATCH] [DoctrineBridge] Add decimal form type --- .../Doctrine/Form/DoctrineOrmTypeGuesser.php | 2 + .../Bridge/Doctrine/Form/Type/DecimalType.php | 57 +++++++++++ .../Bridge/Doctrine/Tests/Fixtures/Price.php | 36 +++++++ .../Tests/Form/Type/DecimalTypeTest.php | 96 +++++++++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 49dfd9bfbc..78a2ba9510 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -17,6 +17,7 @@ use Doctrine\Common\Persistence\Proxy; use Doctrine\DBAL\Types\Type; use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\Mapping\MappingException as LegacyMappingException; +use Symfony\Bridge\Doctrine\Form\Type\DecimalType; use Symfony\Component\Form\FormTypeGuesserInterface; use Symfony\Component\Form\Guess\Guess; use Symfony\Component\Form\Guess\TypeGuess; @@ -75,6 +76,7 @@ class DoctrineOrmTypeGuesser implements FormTypeGuesserInterface case 'time_immutable': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TimeType', ['input' => 'datetime_immutable'], Guess::HIGH_CONFIDENCE); case Type::DECIMAL: + return new TypeGuess(DecimalType::class, array(), Guess::HIGH_CONFIDENCE); case Type::FLOAT: return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\NumberType', [], Guess::MEDIUM_CONFIDENCE); case Type::INTEGER: diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php new file mode 100644 index 0000000000..9956c3de10 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Form\Type; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\CallbackTransformer; +use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\Type\NumberType; +use Symfony\Component\Form\FormBuilderInterface; + +class DecimalType extends AbstractType +{ + /** + * {@inheritdoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->addModelTransformer(new CallbackTransformer(function ($value) { + if (null === $value) { + return null; + } + + if (!is_string($value)) { + throw new TransformationFailedException('Expected a string.'); + } + + return $value; + }, function ($value) { + if (null === $value) { + return null; + } + + if (!is_int($value) && !is_float($value)) { + throw new TransformationFailedException('Expected an int or a float.'); + } + + return (string) $value; + })); + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + return NumberType::class; + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php new file mode 100644 index 0000000000..bd7c645766 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Tests\Fixtures; + +use Doctrine\ORM\Mapping\Entity; +use Doctrine\ORM\Mapping\Id; +use Doctrine\ORM\Mapping\Column; + +/** @Entity */ +class Price +{ + /** @Id @Column(type="integer") */ + public $id; + + /** @Column(type="decimal") */ + public $value; + + /** + * @param int $id + * @param float $value + */ + public function __construct(int $id, float $value) + { + $this->id = $id; + $this->value = $value; + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php new file mode 100644 index 0000000000..b7601b1a94 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Tests\Form\Type; + +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Tools\SchemaTool; +use Symfony\Bridge\Doctrine\Form\Type\DecimalType; +use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; +use Symfony\Bridge\Doctrine\Tests\Fixtures\Price; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\Tests\Extension\Core\Type\BaseTypeTest; + +class DecimalTypeTest extends BaseTypeTest +{ + /** + * @var string + */ + const TESTED_TYPE = DecimalType::class; + + /** + * @var EntityManager + */ + private $em; + + protected function setUp() + { + $this->em = DoctrineTestHelper::createTestEntityManager(); + + parent::setUp(); + + $schemaTool = new SchemaTool($this->em); + $classes = array( + $this->em->getClassMetadata(Price::class) + ); + + try { + $schemaTool->dropSchema($classes); + } catch (\Exception $e) { + } + + try { + $schemaTool->createSchema($classes); + } catch (\Exception $e) { + } + } + + protected function tearDown() + { + parent::tearDown(); + + $this->em = null; + } + + public function testSubmitWithSameStringValue() + { + $price = new Price(1, 1.23); + $this->em->persist($price); + $this->em->flush(); + + $this->em->refresh($price); + + $this->assertInternalType('string', $price->value); + $stringValue = $price->value; + + $formBuilder = $this->factory->createBuilder(FormType::class, $price, array( + 'data_class' => Price::class + )); + $formBuilder->add('value', static::TESTED_TYPE); + + $form = $formBuilder->getForm(); + $form->submit(array( + 'value' => $stringValue + )); + + $this->assertSame($stringValue, $price->value); + + $unitOfWork = $this->em->getUnitOfWork(); + $unitOfWork->computeChangeSets(); + + $this->assertSame(array(), $unitOfWork->getEntityChangeSet($price)); + } + + public function testSubmitNull($expected = null, $norm = null, $view = null) + { + parent::testSubmitNull($expected, $norm, ''); + } +}