diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 99995e7f..8c5df75b 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -55,8 +55,28 @@ private function addCurrencySection(ArrayNodeDefinition $node) ->thenInvalid('Invalid storage "%s"') ->end() ->end() + ->arrayNode('templating') + ->addDefaultsIfNotSet() + ->children() + ->arrayNode('engines') + ->isRequired() + ->requiresAtLeastOneElement() + ->example(array('twig')) + ->beforeNormalization() + ->ifTrue(function($v){ return !is_array($v); }) + ->then(function($v){ return array($v); }) + ->end() + ->prototype('scalar') + ->validate() + ->ifNotInArray(array('twig', 'php')) + ->thenInvalid('Only "twig" and "php" engines are supported.') + ->end() + ->end() + ->defaultValue(array('twig')) + ->end() + ->end() + ->end() ->end() ; } - } diff --git a/DependencyInjection/TbbcMoneyExtension.php b/DependencyInjection/TbbcMoneyExtension.php index 5e745dcf..d6203755 100644 --- a/DependencyInjection/TbbcMoneyExtension.php +++ b/DependencyInjection/TbbcMoneyExtension.php @@ -25,7 +25,14 @@ public function load(array $configs, ContainerBuilder $container) $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.xml'); $loader->load('form_types.xml'); - $loader->load('twig_extension.xml'); + + if (in_array('twig', $config['templating']['engines'])) { + $loader->load('twig_extension.xml'); + } + + if (in_array('php', $config['templating']['engines'])) { + $loader->load('templating_helper.xml'); + } $this->remapParameters($config, $container, array( 'currencies' => 'tbbc_money.currencies', diff --git a/Formatter/MoneyFormatter.php b/Formatter/MoneyFormatter.php new file mode 100644 index 00000000..e1584ba1 --- /dev/null +++ b/Formatter/MoneyFormatter.php @@ -0,0 +1,111 @@ + + */ +class MoneyFormatter +{ + /** + * Formats the given Money object + * INCLUDING the currency symbol + * + * @param Money $money + * @param string $decPoint + * @param string $thousandsSep + * + * @return string + */ + public function formatMoney(Money $money, $decPoint = ',', $thousandsSep = ' ') + { + $symbol = $this->formatCurrency($money); + $amount = $this->formatAmount($money, $decPoint, $thousandsSep); + $price = $amount . " " . $symbol; + + return $price; + } + + /** + * Formats the amount part of the given Money object + * WITHOUT INCLUDING the currency symbol + * + * @param Money $money + * @param string $decPoint + * @param string $thousandsSep + * + * @return string + */ + public function formatAmount(Money $money, $decPoint = ',', $thousandsSep = ' ') + { + $amount = $this->asFloat($money); + $amount = number_format($amount, 2, $decPoint, $thousandsSep); + + return $amount; + } + + /** + * Returns the amount for the given Money object as simple float + * + * @param Money $money + * @return float + */ + public function asFloat(Money $money) + { + $amount = $money->getAmount(); + $amount = (float)$amount; + $amount = $amount / 100; + + return $amount; + } + + /** + * Formats only the currency part of the given Money object + * + * @param Money $money + * @return string + */ + public function formatCurrency(Money $money) + { + return $this->formatCurrencyAsSymbol($money->getCurrency()); + } + + /** + * Returns the symbol corresponding to the given currency + * + * @param Currency $currency + * @return string + */ + public function formatCurrencyAsSymbol(Currency $currency) + { + return Intl::getCurrencyBundle()->getCurrencySymbol($currency->getName()); + } + + /** + * Returns the name as string of the given currency + * + * @param Currency $currency + * @return string + */ + public function formatCurrencyAsName(Currency $currency) + { + return $currency->getName(); + } + + /** + * Returns the Currency object + * + * @param Money $money + * @return \Money\Currency + */ + public function getCurrency(Money $money) + { + return $money->getCurrency(); + } +} diff --git a/README.md b/README.md index ec9cade5..e6eecfc8 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Features -------- * Integrates money library from mathiasverraes -* Twig filters and formater in order to display amounts +* Twig filters and PHP helpers for helping with money and currencies in templates * A storage system for currency ratios * A ratioProvider system for fetching ratio from externals api * Symfony2 form integration @@ -88,6 +88,8 @@ in your config.php, add the currencies you want to use and the reference currenc tbbc_money: currencies: ["USD", "EUR"] reference_currency: "EUR" + templating: + engines: ["twig", "php"] ``` In your config.yml, add the form fields presentations @@ -151,6 +153,33 @@ $usd = $pairManager->convert($amount, 'USD'); $this->assertEquals(Money::USD(125), $usd); ``` +### Money formatter + +```php +get('tbbc_money.formatter.money_formatter'); + $price = new Money(123456789, new Currency('EUR')); + + $formattedPrice = $moneyFormatter->formatMoney($price); + // 1 234 567,89 + + $formattedCurrency = $moneyFormatter->formatCurrency($price); + // € + } +} + +``` + ### Twig integration ```twig @@ -162,6 +191,13 @@ $this->assertEquals(Money::USD(125), $usd); {{ $amount | money_format_currency }} ``` +### PHP templating integration + +```php +format($price) ?> +formatCurrencyAsSymbol($price->getCurrency()) ?> +``` + ### commands ```bash diff --git a/Resources/config/services.xml b/Resources/config/services.xml index 0e3c67cf..623080e9 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -9,6 +9,7 @@ Tbbc\MoneyBundle\Pair\Storage\CsvStorage %kernel.root_dir%/data/tbbc_money/ratio_file_name.csv Tbbc\MoneyBundle\Pair\RatioProvider\RateExchangeRatioProvider + Tbbc\MoneyBundle\Formatter\MoneyFormatter @@ -29,6 +30,9 @@ + + + diff --git a/Resources/config/templating_helpers.xml b/Resources/config/templating_helpers.xml new file mode 100644 index 00000000..70d2020a --- /dev/null +++ b/Resources/config/templating_helpers.xml @@ -0,0 +1,24 @@ + + + + + + Tbbc\MoneyBundle\Templating\Helper\MoneyHelper + Tbbc\MoneyBundle\Templating\Helper\CurrencyHelper + + + + + + + + + + + + + + + diff --git a/Resources/config/twig_extension.xml b/Resources/config/twig_extension.xml index 74b13a78..89cd7de0 100644 --- a/Resources/config/twig_extension.xml +++ b/Resources/config/twig_extension.xml @@ -5,16 +5,18 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - Tbbc\MoneyBundle\Twig\MoneyExtension - Tbbc\MoneyBundle\Twig\CurrencyExtension + Tbbc\MoneyBundle\Twig\Extension\MoneyExtension + Tbbc\MoneyBundle\Twig\Extension\CurrencyExtension + + diff --git a/Templating/Helper/CurrencyHelper.php b/Templating/Helper/CurrencyHelper.php new file mode 100644 index 00000000..06fb4676 --- /dev/null +++ b/Templating/Helper/CurrencyHelper.php @@ -0,0 +1,55 @@ +moneyFormatter = $moneyFormatter; + } + + /** + * Returns the name as string of the given currency + * + * @param Currency $currency + * @return string + */ + public function name(Currency $currency) + { + return $this->moneyFormatter->formatCurrencyAsName($currency); + } + + /** + * Returns the symbol corresponding to the given currency + * + * @param Currency $currency + * @return string + */ + public function symbol(Currency $currency) + { + return $this->moneyFormatter->formatCurrencyAsSymbol($currency); + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'tbbc_money_currency_helper'; + } +} diff --git a/Twig/MoneyExtension.php b/Templating/Helper/MoneyHelper.php similarity index 51% rename from Twig/MoneyExtension.php rename to Templating/Helper/MoneyHelper.php index 9e0cb75c..20647bbb 100644 --- a/Twig/MoneyExtension.php +++ b/Templating/Helper/MoneyHelper.php @@ -1,21 +1,19 @@ - * @author Benjamin Dulau - */ -class MoneyExtension extends \Twig_Extension +class MoneyHelper extends Helper { + /** + * @var MoneyFormatter + */ + protected $moneyFormatter; + /** * @var PairManagerInterface */ @@ -24,28 +22,15 @@ class MoneyExtension extends \Twig_Extension /** * Constructor * + * @param MoneyFormatter $moneyFormatter * @param PairManagerInterface $pairManager */ - public function __construct(PairManagerInterface $pairManager) + public function __construct(MoneyFormatter $moneyFormatter, PairManagerInterface $pairManager) { + $this->moneyFormatter = $moneyFormatter; $this->pairManager = $pairManager; } - /** - * {@inheritDoc} - */ - public function getFilters() - { - return array( - new \Twig_SimpleFilter('money_format', array($this, 'format')), - new \Twig_SimpleFilter('money_format_amount', array($this, 'formatAmount')), - new \Twig_SimpleFilter('money_format_currency', array($this, 'formatCurrency')), - new \Twig_SimpleFilter('money_as_float', array($this, 'asFloat')), - new \Twig_SimpleFilter('money_get_currency', array($this, 'getCurrency')), - new \Twig_SimpleFilter('money_convert', array($this, 'convert')), - ); - } - /** * Formats the given Money object * INCLUDING the currency symbol @@ -58,11 +43,7 @@ public function getFilters() */ public function format(Money $money, $decPoint = ',', $thousandsSep = ' ') { - $symbol = $this->formatCurrency($money); - $amount = $this->formatAmount($money, $decPoint, $thousandsSep); - $price = $amount . " " . $symbol; - - return $price; + return $this->moneyFormatter->formatMoney($money, $decPoint, $thousandsSep); } /** @@ -77,37 +58,29 @@ public function format(Money $money, $decPoint = ',', $thousandsSep = ' ') */ public function formatAmount(Money $money, $decPoint = ',', $thousandsSep = ' ') { - $amount = $this->asFloat($money); - $amount = number_format($amount, 2, $decPoint, $thousandsSep); - - return $amount; + return $this->moneyFormatter->formatAmount($money, $decPoint, $thousandsSep); } /** - * Formats ONLY the currency part of the given Money object - * into a localized string + * Returns the amount for the given Money object as simple float * * @param Money $money - * @return null|string + * @return float */ - public function formatCurrency(Money $money) + public function asFloat(Money $money) { - return Intl::getCurrencyBundle()->getCurrencySymbol($money->getCurrency()->getName()); + return $this->moneyFormatter->asFloat($money); } /** - * Returns the amount for the given Money object as simple float + * Formats only the currency part of the given Money object * * @param Money $money - * @return float + * @return string */ - public function asFloat(Money $money) + public function formatCurrency($money) { - $amount = $money->getAmount(); - $amount = (float)$amount; - $amount = $amount / 100; - - return $amount; + return $this->moneyFormatter->formatCurrency($money); } /** @@ -118,7 +91,7 @@ public function asFloat(Money $money) */ public function getCurrency(Money $money) { - return $money->getCurrency(); + return $this->moneyFormatter->getCurrency($money); } /** @@ -139,6 +112,6 @@ public function convert(Money $money, $currencyCode) */ public function getName() { - return 'tbbc_money_extension'; + return 'tbbc_money_helper'; } } diff --git a/Tests/Fonctionnal/ConfigTest.php b/Tests/Fonctionnal/ConfigTest.php index b470fa3f..64498744 100644 --- a/Tests/Fonctionnal/ConfigTest.php +++ b/Tests/Fonctionnal/ConfigTest.php @@ -42,21 +42,14 @@ public function testMoneyTwigExtension() $eur = Money::EUR(100); $usd = $moneyExtension->convert($eur, "USD"); $this->assertEquals(Money::USD(125), $usd); - - $this->assertEquals("1,25 $", $moneyExtension->format($usd)); - $this->assertEquals(1.25, $moneyExtension->asFloat($usd)); - $this->assertEquals(new Currency("USD"), $moneyExtension->getCurrency($usd)); } + public function testCurrencyTwigExtension() { \Locale::setDefault('en'); $client = self::createClient(); /** @var CurrencyExtension $currencyExtension */ $currencyExtension = $client->getContainer()->get("tbbc_money.twig.currency"); - $eur = new Currency("EUR"); - - $this->assertEquals("€", $currencyExtension->symbol($eur)); - $this->assertEquals("EUR", $currencyExtension->name($eur)); } public function testDoctrineMoneyTypeAvailable() diff --git a/Tests/Formatter/MoneyFormatterTest.php b/Tests/Formatter/MoneyFormatterTest.php new file mode 100644 index 00000000..a9f1845a --- /dev/null +++ b/Tests/Formatter/MoneyFormatterTest.php @@ -0,0 +1,82 @@ +formatter = new MoneyFormatter(); + $this->inputMoney = new Money(123456789, new Currency('EUR')); + } + + public function testFormatMoneyWithDefaultSeparators() + { + $value = $this->formatter->formatMoney($this->inputMoney); + $this->assertEquals('1 234 567,89 €', $value); + } + + public function testFormatMoneyWithCustomSeparators() + { + $value = $this->formatter->formatMoney($this->inputMoney, '.', ','); + $this->assertEquals('1,234,567.89 €', $value); + } + + public function testFormatAmountWithDefaultSeparators() + { + $value = $this->formatter->formatAmount($this->inputMoney); + $this->assertEquals('1 234 567,89', $value); + } + + public function testFormatAmountWithCustomSeparators() + { + $value = $this->formatter->formatAmount($this->inputMoney, '.', ','); + $this->assertEquals('1,234,567.89', $value); + } + + public function testAsFloatIsReturningAFloat() + { + $value = $this->formatter->asFloat($this->inputMoney); + $this->assertTrue(is_float($value)); + } + + public function testFormatCurrency() + { + $value = $this->formatter->formatCurrency($this->inputMoney); + $this->assertEquals('€', $value); + } + + public function testFormatCurrencyAsSymbol() + { + $value = $this->formatter->formatCurrencyAsSymbol($this->inputMoney->getCurrency()); + $this->assertEquals('€', $value); + } + + public function testFormatCurrencyAsName() + { + $value = $this->formatter->formatCurrencyAsName($this->inputMoney->getCurrency()); + $this->assertEquals('EUR', $value); + } + + public function testGetCurrency() + { + $value = $this->formatter->getCurrency($this->inputMoney); + $this->assertInstanceOf('Money\Currency', $value); + $this->assertEquals(new Currency('EUR'), $value); + } +} diff --git a/Tests/Twig/CurrencyExtensionTest.php b/Tests/Twig/CurrencyExtensionTest.php deleted file mode 100644 index ea9128f9..00000000 --- a/Tests/Twig/CurrencyExtensionTest.php +++ /dev/null @@ -1,32 +0,0 @@ -ext = new CurrencyExtension(); - } - -// public function testSymbol() -// { -// \Locale::setDefault("fr_FR"); -// $symbol = $this->ext->symbol(new Currency("EUR")); -// $this->assertEquals('€', $symbol); -// } - public function testName() - { - $val = $this->ext->name(new Currency("EUR")); - $this->assertEquals('EUR', $val); - } -} \ No newline at end of file diff --git a/Tests/Twig/Extension/CurrencyExtensionTest.php b/Tests/Twig/Extension/CurrencyExtensionTest.php new file mode 100644 index 00000000..8dbdc398 --- /dev/null +++ b/Tests/Twig/Extension/CurrencyExtensionTest.php @@ -0,0 +1,55 @@ + + */ +class CurrencyExtensionTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var CurrencyExtension + */ + private $extension; + + /** + * @var array + */ + protected $variables; + + public function setUp() + { + \Locale::setDefault("fr_FR"); + $this->extension = new CurrencyExtension(new MoneyFormatter()); + $this->variables = array('currency' => new Currency('EUR')); + } + + /** + * @dataProvider getCurrencyTests + */ + public function testCurrency($template, $expected) + { + $this->assertEquals($expected, $this->getTemplate($template)->render($this->variables)); + } + + public function getCurrencyTests() + { + return array( + array('{{ currency|currency_name }}', 'EUR'), + array('{{ currency|currency_symbol(".", ",") }}', '€'), + ); + } + + protected function getTemplate($template) + { + $loader = new \Twig_Loader_Array(array('index' => $template)); + $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false)); + $twig->addExtension($this->extension); + + return $twig->loadTemplate('index'); + } +} diff --git a/Tests/Twig/Extension/MoneyExtensionTest.php b/Tests/Twig/Extension/MoneyExtensionTest.php new file mode 100644 index 00000000..5bac59c2 --- /dev/null +++ b/Tests/Twig/Extension/MoneyExtensionTest.php @@ -0,0 +1,67 @@ + + */ +class MoneyExtensionTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var MoneyExtension + */ + private $extension; + + /** + * @var array + */ + protected $variables; + + public function setUp() + { + \Locale::setDefault("fr_FR"); + $pairManager = $this->getMockBuilder('Tbbc\MoneyBundle\Pair\PairManager') + ->disableOriginalConstructor() + ->getMock(); + $pairManager->expects($this->any()) + ->method('getReferenceCurrencyCode') + ->will($this->returnValue("EUR")); + + $this->extension = new MoneyExtension(new MoneyFormatter(), $pairManager); + $this->variables = array('price' => new Money(123456789, new Currency('EUR'))); + } + + /** + * @dataProvider getMoneyTests + */ + public function testMoney($template, $expected) + { + $this->assertEquals($expected, $this->getTemplate($template)->render($this->variables)); + } + + public function getMoneyTests() + { + return array( + array('{{ price|money_format }}', '1 234 567,89 €'), + array('{{ price|money_format(".", ",") }}', '1,234,567.89 €'), + array('{{ price|money_format_amount }}', '1 234 567,89'), + array('{{ price|money_format_amount(".", ",") }}', '1,234,567.89'), + array('{{ price|money_format_currency }}', '€'), + array('{{ price|money_as_float }}', '1234567.89'), + ); + } + + protected function getTemplate($template) + { + $loader = new \Twig_Loader_Array(array('index' => $template)); + $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false)); + $twig->addExtension($this->extension); + + return $twig->loadTemplate('index'); + } +} diff --git a/Tests/Twig/MoneyExtensionTest.php b/Tests/Twig/MoneyExtensionTest.php deleted file mode 100644 index ed0aa09a..00000000 --- a/Tests/Twig/MoneyExtensionTest.php +++ /dev/null @@ -1,38 +0,0 @@ -pairManager = $this->getMockBuilder('Tbbc\MoneyBundle\Pair\PairManager') - ->disableOriginalConstructor() - ->getMock(); - $this->pairManager->expects($this->any()) - ->method('getReferenceCurrencyCode') - ->will($this->returnValue("EUR")); - - $this->ext = new MoneyExtension($this->pairManager); - } - - public function testFormatters() - { - $val = $this->ext->formatAmount(Money::EUR(123456)); - $this->assertEquals('1 234,56', $val); - - $val = $this->ext->asFloat(Money::EUR(123456)); - $this->assertEquals(1234.56, $val); - } -} \ No newline at end of file diff --git a/Twig/CurrencyExtension.php b/Twig/CurrencyExtension.php deleted file mode 100644 index 88f0cb8e..00000000 --- a/Twig/CurrencyExtension.php +++ /dev/null @@ -1,38 +0,0 @@ -getCurrencySymbol($currency->getName()); - } - - public function name(Currency $currency) - { - return $currency->getName(); - } - - public function getName() - { - return 'tbbc_money_currency_extension'; - } -} \ No newline at end of file diff --git a/Twig/Extension/CurrencyExtension.php b/Twig/Extension/CurrencyExtension.php new file mode 100644 index 00000000..ad299316 --- /dev/null +++ b/Twig/Extension/CurrencyExtension.php @@ -0,0 +1,50 @@ + + * @author Benjamin Dulau + */ +class CurrencyExtension extends \Twig_Extension +{ + /** + * @var MoneyFormatter + */ + protected $moneyFormatter; + + /** + * Constructor + * + * @param MoneyFormatter $moneyFormatter + */ + public function __construct(MoneyFormatter $moneyFormatter) + { + $this->moneyFormatter = $moneyFormatter; + } + + /** + * {@inheritDoc} + */ + public function getFilters() + { + return array( + new \Twig_SimpleFilter('currency_name', array($this->moneyFormatter, 'formatCurrencyAsName')), + new \Twig_SimpleFilter('currency_symbol', array($this->moneyFormatter, 'formatCurrencyAsSymbol')), + ); + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'tbbc_money_currency_extension'; + } +} \ No newline at end of file diff --git a/Twig/Extension/MoneyExtension.php b/Twig/Extension/MoneyExtension.php new file mode 100644 index 00000000..ff7ff6a3 --- /dev/null +++ b/Twig/Extension/MoneyExtension.php @@ -0,0 +1,76 @@ + + * @author Benjamin Dulau + */ +class MoneyExtension extends \Twig_Extension +{ + /** + * @var MoneyFormatter + */ + protected $moneyFormatter; + + /** + * @var PairManagerInterface + */ + protected $pairManager; + + /** + * Constructor + * + * @param MoneyFormatter $moneyFormatter + * @param PairManagerInterface $pairManager + */ + public function __construct(MoneyFormatter $moneyFormatter, PairManagerInterface $pairManager) + { + $this->moneyFormatter = $moneyFormatter; + $this->pairManager = $pairManager; + } + + /** + * {@inheritDoc} + */ + public function getFilters() + { + return array( + new \Twig_SimpleFilter('money_format', array($this->moneyFormatter, 'formatMoney')), + new \Twig_SimpleFilter('money_format_amount', array($this->moneyFormatter, 'formatAmount')), + new \Twig_SimpleFilter('money_format_currency', array($this->moneyFormatter, 'formatCurrency')), + new \Twig_SimpleFilter('money_as_float', array($this->moneyFormatter, 'asFloat')), + new \Twig_SimpleFilter('money_get_currency', array($this->moneyFormatter, 'getCurrency')), + new \Twig_SimpleFilter('money_convert', array($this, 'convert')), + ); + } + + /** + * Converts the given Money object into another + * currency and returns a new Money object + * + * @param Money $money + * @param string $currencyCode + * @return Money + */ + public function convert(Money $money, $currencyCode) + { + return $this->pairManager->convert($money, $currencyCode); + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'tbbc_money_extension'; + } +} diff --git a/composer.json b/composer.json index 7d3dfc67..b03582b3 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,9 @@ "beberlei/DoctrineExtensions": "dev-master", "doctrine/doctrine-bundle": "~1.1", "doctrine/orm": "~2.2,>=2.2.3", - "ext-sqlite3": "*" + "ext-sqlite3": "*", + "phpunit/phpunit": "~3.7", + "phpunit/dbunit": "~1.3" }, "suggest": { "doctrine/doctrine-bundle": "~1.1", @@ -40,4 +42,4 @@ "psr-0": { "Tbbc\\MoneyBundle": "" } }, "target-dir": "Tbbc/MoneyBundle" -} \ No newline at end of file +}