Currency Filters

Currency Filters #

How to handle currencies in your application? Similar as your countries in previous chapter.

Firstly, start with the dependency:

lando composer require symfony/intl

Then you can define your app/Filters/CurrencyFilter.php:

<?php

declare(strict_types=1);

namespace App\Filters;

use Contributte\Translation\Translator;
use Contributte\Translation\Wrappers\NotTranslate;
use Latte;
use Nette\Utils\Strings;
use Symfony\Component\Intl\Currencies;


final class CurrencyFilter
{
	private Translator $translator;

	public function __construct(Translator $translator)
	{
		$this->translator = $translator;
	}

	public function install(Latte\Engine $engine): void
	{
		$engine->addFilter('currencyName', [$this, 'currencyName']);
	}

	public function currencyName(string $currency): string
	{
		return Currencies::getName($currency, $this->translator->getLocale());
	}

	public function getCurrencyItems(): array
	{
		return collect(Currencies::getNames($this->translator->getLocale()))
			->map(fn (string $name) => new NotTranslate(Strings::firstUpper($name)))
			->all();;
	}

}

With these (and also with automatic registration) you can write currency name in current language from translator for example like this:

{$item->currency|currencyName}

In your application, you should use currency codes. It is normalized form of how to handle currency information. You don’t need any database table with currencies. You will just use 3-letter code in your table.

Column currency in your database

It is a best practice to type your column to char(3) with collation ascii_bin. This will ensure that your currency codes will be smaller in terms of memory, and warn you when you will try to store there something else.

Currencies in Form Factories #

When you edit your entities in forms, you need to set those currency codes somehow.

Method getCurrencyItems will provide all of currencies in an array, which can be used in your form factory.

final class SomethingFormFactory
{
	private BasicFormFactory $formFactory;
	
	private CurrencyFilter $currencyFilter;

	public function __construct(BasicFormFactory $formFactory, CurrencyFilter $currencyFilter)
	{
		$this->formFactory = $formFactory;
		$this->currencyFilter = $currencyFilter;
	}
	
	public function create(): Form
	{
		$form = $this->formFactory->create();
		
		// ...
		
		$form->addSelect('currency')
			->setPrompt('form.prompt.select')
			->setItems($this->currencyFilter->getCurrencyItems());
		
		// ...
		
		return $form;
	}
}

And again, you will probably need to edit CurrencyFilter::getCurrencyItems to return only some currencies (based on your database data), create groups with used and unused currencies to make it more user-friendly, show their codes, etc. Some of these will be discussed further in other chapters.