From 5609aae8568199edee653dde61d82472d9090905 Mon Sep 17 00:00:00 2001 From: Miha Vrhovnik Date: Sat, 5 Jan 2013 10:58:46 +0100 Subject: [PATCH] Added currency form type and validator --- .../FrameworkBundle/Resources/config/form.xml | 3 + .../Form/Extension/Core/CoreExtension.php | 1 + .../Form/Extension/Core/Type/CurrencyType.php | 46 ++++++++ .../Extension/Core/Type/CurrencyTypeTest.php | 37 ++++++ .../Validator/Constraints/Currency.php | 26 +++++ .../Constraints/CurrencyValidator.php | 48 ++++++++ .../Resources/translations/validators.en.xlf | 4 + .../Constraints/CurrencyValidatorTest.php | 109 ++++++++++++++++++ 8 files changed, 274 insertions(+) create mode 100644 src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php create mode 100644 src/Symfony/Component/Form/Tests/Extension/Core/Type/CurrencyTypeTest.php create mode 100644 src/Symfony/Component/Validator/Constraints/Currency.php create mode 100644 src/Symfony/Component/Validator/Constraints/CurrencyValidator.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/CurrencyValidatorTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml index 17e459b9ea..feb009cfd1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml @@ -149,6 +149,9 @@ + + + diff --git a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php index 3934d38261..bbcac4baea 100644 --- a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php +++ b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php @@ -53,6 +53,7 @@ class CoreExtension extends AbstractExtension new Type\ButtonType(), new Type\SubmitType(), new Type\ResetType(), + new Type\CurrencyType(), ); } } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php new file mode 100644 index 0000000000..07b820d823 --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php @@ -0,0 +1,46 @@ + + * + * 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\Intl\Intl; +use Symfony\Component\Locale\Locale; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +class CurrencyType extends AbstractType +{ + /** + * {@inheritdoc} + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'choices' => Intl::getCurrencyBundle()->getCurrencyNames(), + )); + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + return 'choice'; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'currency'; + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CurrencyTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CurrencyTypeTest.php new file mode 100644 index 0000000000..b0eb6dc01c --- /dev/null +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CurrencyTypeTest.php @@ -0,0 +1,37 @@ + + * + * 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\Extension\Core\View\ChoiceView; +use Symfony\Component\Intl\Util\IntlTestHelper; + +class CurrencyTypeTest extends TypeTestCase +{ + protected function setUp() + { + IntlTestHelper::requireIntl($this); + + parent::setUp(); + } + + public function testCurrenciesAreSelectable() + { + $form = $this->factory->create('currency'); + $view = $form->createView(); + $choices = $view->vars['choices']; + + $this->assertContains(new ChoiceView('EUR', 'EUR', 'Euro'), $choices, '', false, false); + $this->assertContains(new ChoiceView('USD', 'USD', 'US Dollar'), $choices, '', false, false); + $this->assertContains(new ChoiceView('SIT', 'SIT', 'Slovenian Tolar'), $choices, '', false, false); + } + +} diff --git a/src/Symfony/Component/Validator/Constraints/Currency.php b/src/Symfony/Component/Validator/Constraints/Currency.php new file mode 100644 index 0000000000..b3bfc8f68b --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/Currency.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; + +/** + * @Annotation + * + * @author Miha Vrhovnik + * + * @api + */ +class Currency extends Constraint +{ + public $message = 'This value is not a valid currency.'; +} diff --git a/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php b/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php new file mode 100644 index 0000000000..4465e46dfe --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Intl\Intl; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; + +/** + * Validates whether a value is a valid currency + * + * @author Miha Vrhovnik + * + * @api + */ +class CurrencyValidator extends ConstraintValidator +{ + /** + * {@inheritDoc} + */ + public function validate($value, Constraint $constraint) + { + if (null === $value || '' === $value) { + return; + } + + if (!is_scalar($value) && !(is_object($value) && method_exists($value, '__toString'))) { + throw new UnexpectedTypeException($value, 'string'); + } + + $value = (string) $value; + $currencies = Intl::getCurrencyBundle()->getCurrencyNames(); + + if (!isset($currencies[$value])) { + $this->context->addViolation($constraint->message, array('{{ value }}' => $value)); + } + } +} diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf index abb849d7b7..70118c3e48 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf @@ -242,6 +242,10 @@ This value is not a valid ISSN. This value is not a valid ISSN. + + This value is not a valid currency. + This value is not a valid currency. + diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CurrencyValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CurrencyValidatorTest.php new file mode 100644 index 0000000000..d2e233ca37 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/CurrencyValidatorTest.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Intl\Util\IntlTestHelper; +use Symfony\Component\Validator\Constraints\Currency; +use Symfony\Component\Validator\Constraints\CurrencyValidator; + +class CurrencyValidatorTest extends \PHPUnit_Framework_TestCase +{ + protected $context; + protected $validator; + + protected function setUp() + { + IntlTestHelper::requireIntl($this); + + $this->context = $this->getMock('Symfony\Component\Validator\ExecutionContext', array(), array(), '', false); + $this->validator = new CurrencyValidator(); + $this->validator->initialize($this->context); + } + + protected function tearDown() + { + $this->context = null; + $this->validator = null; + } + + public function testNullIsValid() + { + $this->context->expects($this->never()) + ->method('addViolation'); + + $this->validator->validate(null, new Currency()); + } + + public function testEmptyStringIsValid() + { + $this->context->expects($this->never()) + ->method('addViolation'); + + $this->validator->validate('', new Currency()); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\UnexpectedTypeException + */ + public function testExpectsStringCompatibleType() + { + $this->validator->validate(new \stdClass(), new Currency()); + } + + /** + * @dataProvider getValidCurrencies + */ + public function testValidCurrencies($currency) + { + $this->context->expects($this->never()) + ->method('addViolation'); + + $this->validator->validate($currency, new Currency()); + } + + public function getValidCurrencies() + { + return array( + array('EUR'), + array('USD'), + array('SIT'), + array('AUD'), + array('CAD'), + ); + } + + /** + * @dataProvider getInvalidCurrencies + */ + public function testInvalidCurrencies($currency) + { + $constraint = new Currency(array( + 'message' => 'myMessage' + )); + + $this->context->expects($this->once()) + ->method('addViolation') + ->with('myMessage', array( + '{{ value }}' => $currency, + )); + + $this->validator->validate($currency, $constraint); + } + + public function getInvalidCurrencies() + { + return array( + array('EN'), + array('foobar'), + ); + } +}