diff --git a/Adapter/AbstractCurrencyAdapter.php b/Adapter/AbstractCurrencyAdapter.php index b0a3f4f..2ce6025 100644 --- a/Adapter/AbstractCurrencyAdapter.php +++ b/Adapter/AbstractCurrencyAdapter.php @@ -2,114 +2,91 @@ namespace Lexik\Bundle\CurrencyBundle\Adapter; +use ArrayIterator; +use Lexik\Bundle\CurrencyBundle\Entity\Currency; + /** * * @author Cédric Girard * @author Yoann Aparici + * @extends ArrayIterator */ -abstract class AbstractCurrencyAdapter extends \ArrayIterator +abstract class AbstractCurrencyAdapter extends ArrayIterator { - /** - * @var string - */ - protected $defaultCurrency; + protected string $defaultCurrency; /** - * @var array + * @var array */ - protected $managedCurrencies = array(); + protected array $managedCurrencies = []; /** - * @var string + * @var class-string */ - protected $currencyClass; + protected string $currencyClass; - /** - * Set default currency - * - * @param string $defaultCurrency - */ - public function setDefaultCurrency($defaultCurrency) + public function setDefaultCurrency(string $defaultCurrency): void { $this->defaultCurrency = $defaultCurrency; } - /** - * Get default currency - * - * @return string - */ - public function getDefaultCurrency() + public function getDefaultCurrency(): string { return $this->defaultCurrency; } /** - * Get managedCurrencies - * - * @param array $currencies + * @param array $currencies */ - public function setManagedCurrencies($currencies) + public function setManagedCurrencies(array $currencies): void { $this->managedCurrencies = $currencies; } /** - * Get managedCurrencies - * - * @return array + * @return array */ - public function getManagedCurrencies() + public function getManagedCurrencies(): array { return $this->managedCurrencies; } /** - * Get managedCurrencies - * - * @return array + * @param class-string $currencyClass */ - public function setCurrencyClass($currencyClass) + public function setCurrencyClass(string $currencyClass): void { - return $this->currencyClass = $currencyClass; + $this->currencyClass = $currencyClass; } /** - * Set object - * - * @param mixed $index - * @param Currency $newval + * @param string $key + * @param Currency $value */ - public function offsetSet($index, $newval) + public function offsetSet($key, $value): void { - if (!$newval instanceof $this->currencyClass) { - throw new \InvalidArgumentException(sprintf('$newval must be an instance of Currency, instance of "%s" given', get_class($newval))); + if (!$value instanceof $this->currencyClass) { + throw new \InvalidArgumentException(sprintf('$newval must be an instance of Currency, instance of "%s" given', $value::class)); } - parent::offsetSet($index, $newval); + parent::offsetSet($key, $value); } /** - * Append a value - * * @param Currency $value */ - public function append($value) + public function append($value): void { if (!$value instanceof $this->currencyClass) { - throw new \InvalidArgumentException(sprintf('$newval must be an instance of Currency, instance of "%s" given', get_class($value))); + throw new \InvalidArgumentException(sprintf('$newval must be an instance of Currency, instance of "%s" given', $value::class)); } parent::append($value); } - /** - * Convert all - * - * @param mixed $rate - */ - protected function convertAll($rate) + protected function convertAll(float $rate): void { + /** @var Currency $currency */ foreach ($this as $currency) { $currency->convert($rate); } @@ -119,13 +96,11 @@ protected function convertAll($rate) * This method is used by the constructor * to attach all currencies. */ - abstract public function attachAll(); + abstract public function attachAll(): void; /** - * Get identier value for the adapter must be unique + * Get identifier value for the adapter must be unique * for all the project - * - * @return string */ - abstract protected function getIdentifier(); -} \ No newline at end of file + abstract public function getIdentifier(): string; +} diff --git a/Adapter/AdapterCollector.php b/Adapter/AdapterCollector.php index ca83cfa..6d9f43c 100644 --- a/Adapter/AdapterCollector.php +++ b/Adapter/AdapterCollector.php @@ -9,26 +9,17 @@ */ final class AdapterCollector { - private $elements = array(); - /** - * Add an adapter - * - * @param mixed $key - * @param AbstractCurrencyAdapter $adapter + * @var array */ - public function add(AbstractCurrencyAdapter $adapter) + private array $elements = []; + + public function add(AbstractCurrencyAdapter $adapter): void { $this->elements[$adapter->getIdentifier()] = $adapter; } - /** - * Get adapter - * - * @param mixed $key - * @return AbstractCurrencyAdapter - */ - public function get($key) + public function get(string $key): AbstractCurrencyAdapter { if (!isset($this->elements[$key])) { throw new InvalidArgumentException('Adapter does not exist'); @@ -36,5 +27,4 @@ public function get($key) return $this->elements[$key]; } - -} \ No newline at end of file +} diff --git a/Adapter/AdapterFactory.php b/Adapter/AdapterFactory.php index 025ff9f..ec5fb63 100644 --- a/Adapter/AdapterFactory.php +++ b/Adapter/AdapterFactory.php @@ -2,55 +2,44 @@ namespace Lexik\Bundle\CurrencyBundle\Adapter; -use Doctrine\ORM\EntityManager; use Doctrine\Bundle\DoctrineBundle\Registry; +use Doctrine\ORM\EntityManager; /** - * This class is used to create DoctrineCurrencyAdapter - * * @author Yoann Aparici * @author Cédric Girard */ class AdapterFactory { /** - * @var EntityManager - */ - protected $doctrine; - - /** - * @var array + * @var array{default: string, managed: array} */ - private $currencies; + private array $currencies; /** - * @var string + * @param Registry $doctrine + * @param string $defaultCurrency + * @param array $availableCurrencies + * @param class-string $currencyClass */ - private $currencyClass; - - /** - * __construct - * - * @param EntityManager $em - */ - public function __construct(Registry $doctrine, $defaultCurrency, $availableCurrencies, $currencyClass) - { - $this->doctrine = $doctrine; - - $this->currencies = array(); - $this->currencies['default'] = $defaultCurrency; - $this->currencies['managed'] = $availableCurrencies; - $this->currencyClass = $currencyClass; + public function __construct( + protected Registry $doctrine, + string $defaultCurrency, + array $availableCurrencies, + private string $currencyClass + ) { + $this->currencies = [ + 'default' => $defaultCurrency, + 'managed' => $availableCurrencies + ]; } /** - * Create an adaper from the given class. - * - * @param string $adapterClass - * @return Lexik\Bundle\CurrencyBundle\Adapter\AbstractCurrencyAdapter + * @param class-string $adapterClass */ - public function create($adapterClass) + public function create(string $adapterClass): AbstractCurrencyAdapter { + /** @var AbstractCurrencyAdapter $adapter */ $adapter = new $adapterClass(); $adapter->setDefaultCurrency($this->currencies['default']); $adapter->setManagedCurrencies($this->currencies['managed']); @@ -60,17 +49,17 @@ public function create($adapterClass) } /** - * Create a DoctrineCurrencyAdapter. - * - * @return Lexik\Bundle\CurrencyBundle\Adapter\DoctrineCurrencyAdapter + * @param ?class-string $adapterClass */ - public function createDoctrineAdapter($adapterClass = null, $entityManagerName = null) + public function createDoctrineAdapter(string $adapterClass = null, string $entityManagerName = null): AbstractCurrencyAdapter { if (null == $adapterClass) { - $adapterClass = 'Lexik\Bundle\CurrencyBundle\Adapter\DoctrineCurrencyAdapter'; + $adapterClass = DoctrineCurrencyAdapter::class; } + /** @var DoctrineCurrencyAdapter $adapter */ $adapter = $this->create($adapterClass); + /** @var EntityManager $em */ $em = $this->doctrine->getManager($entityManagerName); $adapter->setManager($em); @@ -78,44 +67,38 @@ public function createDoctrineAdapter($adapterClass = null, $entityManagerName = } /** - * Create an EcbCurrencyAdapter. - * - * @return Lexik\Bundle\CurrencyBundle\Adapter\EcbCurrencyAdapter + * @param ?class-string $adapterClass */ - public function createEcbAdapter($adapterClass = null) + public function createEcbAdapter(string $adapterClass = null): AbstractCurrencyAdapter { if (null == $adapterClass) { - $adapterClass = 'Lexik\Bundle\CurrencyBundle\Adapter\EcbCurrencyAdapter'; + $adapterClass = EcbCurrencyAdapter::class; } return $this->create($adapterClass); } /** - * Create an OerCurrencyAdapter. - * - * @return Lexik\Bundle\CurrencyBundle\Adapter\OerCurrencyAdapter + * @param ?class-string $adapterClass */ - public function createOerAdapter($adapterClass = null) + public function createOerAdapter(string $adapterClass = null): AbstractCurrencyAdapter { if (null == $adapterClass) { - $adapterClass = 'Lexik\Bundle\CurrencyBundle\Adapter\OerCurrencyAdapter'; + $adapterClass = OerCurrencyAdapter::class; } return $this->create($adapterClass); } /** - * Create an YahooCurrencyAdapter. - * - * @return Lexik\Bundle\CurrencyBundle\Adapter\YahooCurrencyAdapter + * @param ?class-string $adapterClass */ - public function createYahooAdapter($adapterClass = null) + public function createYahooAdapter(string $adapterClass = null): AbstractCurrencyAdapter { if (null == $adapterClass) { - $adapterClass = 'Lexik\Bundle\CurrencyBundle\Adapter\YahooCurrencyAdapter'; + $adapterClass = YahooCurrencyAdapter::class; } return $this->create($adapterClass); } -} \ No newline at end of file +} diff --git a/Adapter/DoctrineCurrencyAdapter.php b/Adapter/DoctrineCurrencyAdapter.php index fcaf84a..2c8e13a 100644 --- a/Adapter/DoctrineCurrencyAdapter.php +++ b/Adapter/DoctrineCurrencyAdapter.php @@ -3,6 +3,9 @@ namespace Lexik\Bundle\CurrencyBundle\Adapter; use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; +use Exception; +use Lexik\Bundle\CurrencyBundle\Entity\Currency; /** * @author Yoann Aparici @@ -10,46 +13,21 @@ */ class DoctrineCurrencyAdapter extends AbstractCurrencyAdapter { - /** - * @var EntityManager - */ - private $manager; + private EntityManager $manager; - /** - * @var bool - */ - private $initialized = false; + private bool $initialized = false; - /** - * {@inheritdoc} - */ - public function attachAll() + public function attachAll(): void { // nothing here } - /** - * Return identifier - * - * @return string - */ - public function getIdentifier() + public function getIdentifier(): string { return 'doctrine'; } - /** - * @param EntityManager $manager - */ - public function setManager(EntityManager $manager) - { - $this->manager = $manager; - } - - /** - * {@inheritdoc} - */ - public function offsetExists($index) + public function offsetExists($index): bool { if (!$this->isInitialized()) { $this->initialize(); @@ -58,30 +36,29 @@ public function offsetExists($index) return parent::offsetExists($index); } - /** - * {@inheritdoc} - */ - public function offsetGet($index) + public function setManager(EntityManager $manager): void + { + $this->manager = $manager; + } + + public function offsetGet(mixed $key): mixed { if (!$this->isInitialized()) { $this->initialize(); } - return parent::offsetGet($index); + return parent::offsetGet($key); } - /** - * @return bool - */ - private function isInitialized() + private function isInitialized(): bool { return $this->initialized; } /** - * @throws \Exception + * @throws Exception */ - private function initialize() + private function initialize(): void { if (!isset($this->manager)) { throw new \RuntimeException('No ObjectManager set on DoctrineCurrencyAdapter.'); @@ -91,6 +68,7 @@ private function initialize() ->getRepository($this->currencyClass) ->findAll(); + /** @var Currency $currency */ foreach ($currencies as $currency) { $this[$currency->getCode()] = $currency; } diff --git a/Adapter/EcbCurrencyAdapter.php b/Adapter/EcbCurrencyAdapter.php index a43fa4a..f519a30 100644 --- a/Adapter/EcbCurrencyAdapter.php +++ b/Adapter/EcbCurrencyAdapter.php @@ -2,36 +2,28 @@ namespace Lexik\Bundle\CurrencyBundle\Adapter; +use Lexik\Bundle\CurrencyBundle\Entity\Currency; +use SimpleXMLElement; + /** * @author Cédric Girard * @author Yoann Aparici */ class EcbCurrencyAdapter extends AbstractCurrencyAdapter { - /** - * @var string - */ - private $ecbUrl; - - /** - * Set the ECB url. - * - * @param string $url - */ - public function setEcbUrl($url) + private string $ecbUrl; + + public function setEcbUrl(string $url): void { $this->ecbUrl = $url; } - /** - * Init object storage - */ - public function attachAll() + public function attachAll(): void { $defaultRate = 1; - // Add euro - $euro = new $this->currencyClass; + /** @var Currency $euro */ + $euro = new $this->currencyClass(); $euro->setCode('EUR'); $euro->setRate(1); @@ -40,16 +32,23 @@ public function attachAll() // Get other currencies $xml = @simplexml_load_file($this->ecbUrl); - if ($xml instanceof \SimpleXMLElement) { + if ($xml instanceof SimpleXMLElement) { + /** @var array $data */ $data = $xml->xpath('//gesmes:Envelope/*[3]/*'); + /** @var SimpleXMLElement $child */ foreach ($data[0]->children() as $child) { - $code = (string) $child->attributes()->currency; + + /** @var SimpleXMLElement $row */ + $row = $child->attributes(); + + $code = (string) $row->currency; if (in_array($code, $this->managedCurrencies)) { - $currency = new $this->currencyClass; + /** @var Currency $currency */ + $currency = new $this->currencyClass(); $currency->setCode($code); - $currency->setRate((string) $child->attributes()->rate); + $currency->setRate((float) $row->rate); $this[$currency->getCode()] = $currency; } @@ -63,10 +62,7 @@ public function attachAll() } } - /** - * {@inheritdoc} - */ - public function getIdentifier() + public function getIdentifier(): string { return 'ecb'; } diff --git a/Adapter/OerCurrencyAdapter.php b/Adapter/OerCurrencyAdapter.php index 0754a86..b48444b 100644 --- a/Adapter/OerCurrencyAdapter.php +++ b/Adapter/OerCurrencyAdapter.php @@ -2,6 +2,7 @@ namespace Lexik\Bundle\CurrencyBundle\Adapter; +use Lexik\Bundle\CurrencyBundle\Entity\Currency; use Lexik\Bundle\CurrencyBundle\Exception\CurrencyNotFoundException; /** @@ -12,83 +13,59 @@ */ class OerCurrencyAdapter extends AbstractCurrencyAdapter { - /** - * @var string - */ - private $url; + private string $url; - /** - * @var string - */ - private $appId; + private ?string $appId = null; - /** - * Set the OER url. - * - * @param string $url - */ - public function setOerUrl($url) + public function setOerUrl(string $url): void { $this->url = $url; } - /** - * Sets the app-id - * - * @param string $appId - */ - public function setOerAppId($appId) - { - $this->appId = $appId; - } - + public function setOerAppId(?string $appId): void + { + $this->appId = $appId; + } - /** - * Init object storage - */ - public function attachAll() + public function attachAll(): void { // Get other currencies $data = @file_get_contents($this->getUrl()); - $data = @json_decode($data, true); + $data = @json_decode((string) $data, true, 512, JSON_THROW_ON_ERROR); - if($data && is_array($data) && isset($data['rates'])) - { - $data = $data['rates']; - foreach($this->managedCurrencies as $code) - { - if(isset($data[$code])) - { - $currency = new $this->currencyClass; + if ($data && is_array($data) && isset($data['rates'])) { + $data = $data['rates']; + foreach ($this->managedCurrencies as $code) { + if (isset($data[$code])) { + /** @var Currency $currency */ + $currency = new $this->currencyClass(); $currency->setCode($code); $currency->setRate($data[$code]); $this[$code] = $currency; - } - } + } + } if (isset($this[$this->defaultCurrency])) { $defaultRate = $this[$this->defaultCurrency]->getRate(); + } else { + throw new CurrencyNotFoundException("Your default currency is not supported by Oer provider"); } - else - throw new CurrencyNotFoundException("Your default currency is not supported by Oer provider"); $this->convertAll($defaultRate); } } - public function getUrl() - { - if(!$this->appId) - throw new \InvalidArgumentException('OER_APP_ID must be set in order to use OerCurrencyAdapter'); - return sprintf("%s?app_id=%s", $this->url, $this->appId); - } + public function getUrl(): string + { + if ($this->appId === '' || $this->appId === '0') { + throw new \InvalidArgumentException('OER_APP_ID must be set in order to use OerCurrencyAdapter'); + } + return sprintf("%s?app_id=%s", $this->url, $this->appId); + } - /** - * {@inheritdoc} - */ - public function getIdentifier() + public function getIdentifier(): string { return 'oer'; } -} \ No newline at end of file +} diff --git a/Adapter/YahooCurrencyAdapter.php b/Adapter/YahooCurrencyAdapter.php index 5354574..8efcb14 100644 --- a/Adapter/YahooCurrencyAdapter.php +++ b/Adapter/YahooCurrencyAdapter.php @@ -2,6 +2,7 @@ namespace Lexik\Bundle\CurrencyBundle\Adapter; +use Lexik\Bundle\CurrencyBundle\Entity\Currency; use Lexik\Bundle\CurrencyBundle\Exception\CurrencyNotFoundException; /** @@ -11,31 +12,19 @@ */ class YahooCurrencyAdapter extends AbstractCurrencyAdapter { - /** - * @var string - */ - private $yahooUrl; + private string $yahooUrl; /** - * @var array + * @var array */ - private $currencyCodes = array(); + private array $currencyCodes = []; - - /** - * Set the Yahoo! url. - * - * @param string $url - */ - public function setYahooUrl($url) + public function setYahooUrl(string $url): void { $this->yahooUrl = $url; } - /** - * Init object storage - */ - public function attachAll() + public function attachAll(): void { foreach ($this->managedCurrencies as $managedCurrency) { $this->addCurrency($managedCurrency); @@ -44,7 +33,8 @@ public function attachAll() $defaultRate = 1; // Add default currency (euro in this example) - $euro = new $this->currencyClass; + /** @var Currency $euro */ + $euro = new $this->currencyClass(); $euro->setCode('EUR'); $euro->setRate($defaultRate); @@ -52,20 +42,14 @@ public function attachAll() // Build YQL query $strCodes = ''; - foreach ($this->currencyCodes as $index=>$currencyCode) { - $strCodes .= "'EUR".$currencyCode."'"; + foreach ($this->currencyCodes as $index => $currencyCode) { + $strCodes .= "'EUR" . $currencyCode . "'"; if ($index != count($this->currencyCodes) - 1) { $strCodes .= ", "; } } - $yqlQuery = "select id,Rate from yahoo.finance.xchange where pair in (".$strCodes.")"; - - $args = array( - 'q' => $yqlQuery, - 'format' => "json", - 'env' => "store://datatables.org/alltableswithkeys", - ); + $yqlQuery = "select id,Rate from yahoo.finance.xchange where pair in (" . $strCodes . ")"; $yqlQueryURL = $this->yahooUrl . "?q=" . urlencode($yqlQuery) @@ -74,19 +58,19 @@ public function attachAll() $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $yqlQueryURL); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $json = curl_exec($ch); // Convert JSON response to PHP object - $data = json_decode($json); - $results = $data->query->results->rate; + $data = json_decode((string) $json, null, 512, JSON_THROW_ON_ERROR); + $results = $data->query->results->rate; // @phpstan-ignore-line // Check if query was okay and result is given if (is_null($results)) { - new \RuntimeException('YQL query failed!'); + throw new \RuntimeException('YQL query failed!'); } - $currencies = array(); + $currencies = []; foreach ($results as $row) { $code = substr($row->id, 3); @@ -97,7 +81,8 @@ public function attachAll() foreach ($currencies as $code => $rate) { if (in_array($code, $this->managedCurrencies)) { // you can check if the currency is in the managed currencies - $currency = new $this->currencyClass; + /** @var Currency $currency */ + $currency = new $this->currencyClass(); $currency->setCode($code); $currency->setRate($rate); @@ -114,21 +99,13 @@ public function attachAll() $this->convertAll($defaultRate); } - /** - * {@inheritdoc} - */ - public function getIdentifier() + public function getIdentifier(): string { return 'yahoo'; } - /** - * Add currency to the query - * - * @param $code - */ - private function addCurrency($code) { + private function addCurrency(string $code): void + { $this->currencyCodes[] = $code; } - -} \ No newline at end of file +} diff --git a/Command/ImportCurrencyCommand.php b/Command/ImportCurrencyCommand.php index 0d44380..0e7db3e 100644 --- a/Command/ImportCurrencyCommand.php +++ b/Command/ImportCurrencyCommand.php @@ -2,7 +2,12 @@ namespace Lexik\Bundle\CurrencyBundle\Command; -use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; +use Doctrine\Persistence\ManagerRegistry; +use Lexik\Bundle\CurrencyBundle\Adapter\AbstractCurrencyAdapter; +use Lexik\Bundle\CurrencyBundle\Adapter\AdapterCollector; +use Lexik\Bundle\CurrencyBundle\Adapter\DoctrineCurrencyAdapter; +use Lexik\Bundle\CurrencyBundle\Entity\Currency; +use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -12,12 +17,23 @@ * @author Cédric Girard * @author Yoann Aparici */ -class ImportCurrencyCommand extends ContainerAwareCommand +class ImportCurrencyCommand extends Command { + /** + * @param class-string $currencyClass + */ + public function __construct( + private ManagerRegistry $managerRegistry, + private AdapterCollector $adapterCollector, + private string $currencyClass + ) { + parent::__construct(); + } + /** * {@inheritdoc} */ - protected function configure() + protected function configure(): void { $this ->setName('lexik:currency:import') @@ -30,37 +46,44 @@ protected function configure() /** * {@inheritdoc} */ - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { - $adapter = $this->getContainer() - ->get('lexik_currency.adapter_collector') - ->get($input->getArgument('adapter')); + /** @var string $adapterName */ + $adapterName = $input->getArgument('adapter'); + $adapter = $this->adapterCollector->get($adapterName); $adapter->attachAll(); - // Persist currencies - $entityManagerName = $input->getOption('em'); - $em = $this->getContainer()->get('doctrine')->getManager($entityManagerName); + /** @var string $managerName */ + $managerName = $input->getOption('em'); + $entityManagerName = $managerName; + $em = $this->managerRegistry->getManager($entityManagerName); - $repository = $em->getRepository($this->getContainer()->getParameter('lexik_currency.currency_class')); + $repository = $em->getRepository($this->currencyClass); foreach ($adapter as $value) { - // Check if already exist - $currency = $repository->findOneBy(array( + $currency = $repository->findOneBy([ 'code' => $value->getCode(), - )); + ]); + /** @var Currency|null $currency */ if (!$currency) { $currency = $value; $em->persist($currency); - $output->writeln(sprintf('Add: %s = %s', $currency->getCode(), $currency->getRate())); + $output->writeln( + sprintf('Add: %s = %s', $currency->getCode(), $currency->getRate()) + ); } else { $currency->setRate($value->getRate()); - $output->writeln(sprintf('Update: %s = %s', $currency->getCode(), $currency->getRate())); + $output->writeln( + sprintf('Update: %s = %s', $currency->getCode(), $currency->getRate()) + ); } } $em->flush(); + + return Command::SUCCESS; } } diff --git a/Currency/Converter.php b/Currency/Converter.php index 75594f5..7bc3102 100644 --- a/Currency/Converter.php +++ b/Currency/Converter.php @@ -6,53 +6,36 @@ use Lexik\Bundle\CurrencyBundle\Exception\CurrencyNotFoundException; /** - * Currency converter. - * * @author Cédric Girard * @author Yoann Aparici */ class Converter implements ConverterInterface { - /** - * @var AbstractCurrencyAdapter - */ - protected $adapter; + private int $roundMode; /** - * @var integer - */ - protected $precision; - - /** - * @var string - */ - protected $roundMode; - - /** - * Construct. - * - * @param AbstractCurrencyAdapter $adapter - * @param integer $precision - * @param string $roundMode * @throws \InvalidArgumentException */ - public function __construct(AbstractCurrencyAdapter $adapter, $precision = 2, $roundMode = 'up') + public function __construct(protected AbstractCurrencyAdapter $adapter, protected int $precision = 2, string $roundMode = 'up') { - $allowedModes = array('up', 'down', 'even', 'odd'); + $allowedModes = ['up', 'down', 'even', 'odd']; if (!in_array($roundMode, $allowedModes)) { - throw new \InvalidArgumentException(sprintf('Invalid round mode "%s", please use one of the following values: %s', $roundMode, implode(', ', $allowedModes))); + throw new \InvalidArgumentException( + sprintf( + 'Invalid round mode "%s", please use one of the following values: %s', + $roundMode, + implode(', ', $allowedModes) + ) + ); } - $this->adapter = $adapter; - $this->precision = $precision; - $this->roundMode = constant(sprintf('PHP_ROUND_HALF_%s', strtoupper($roundMode))); + /** @var int $roundingConstant */ + $roundingConstant = constant(sprintf('PHP_ROUND_HALF_%s', strtoupper($roundMode))); + $this->roundMode = $roundingConstant; } - /** - * {@inheritDoc} - */ - public function convert($value, $targetCurrency, $round = true, $valueCurrency = null) + public function convert(float $value, string $targetCurrency, bool $round = true, string $valueCurrency = null): float { if (!isset($this->adapter[$targetCurrency])) { throw new CurrencyNotFoundException($targetCurrency); @@ -66,26 +49,22 @@ public function convert($value, $targetCurrency, $round = true, $valueCurrency = throw new CurrencyNotFoundException($valueCurrency); } - if ($targetCurrency != $valueCurrency) { - if ($this->getDefaultCurrency() == $valueCurrency) { + if ($targetCurrency !== $valueCurrency) { + if ($this->getDefaultCurrency() === $valueCurrency) { $value *= $this->adapter[$targetCurrency]->getRate(); - } else { $value /= $this->adapter[$valueCurrency]->getRate(); // value in the default currency - if ($this->getDefaultCurrency() != $targetCurrency) { + if ($this->getDefaultCurrency() !== $targetCurrency) { $value *= $this->adapter[$targetCurrency]->getRate(); } } } - return $round ? round($value, $this->precision, $this->roundMode) : $value; + return $round ? round($value, $this->precision, (int) $this->roundMode) : $value; } - /** - * {@inheritDoc} - */ - public function getDefaultCurrency() + public function getDefaultCurrency(): string { return $this->adapter->getDefaultCurrency(); } diff --git a/Currency/ConverterInterface.php b/Currency/ConverterInterface.php index 6c2682b..15a9524 100644 --- a/Currency/ConverterInterface.php +++ b/Currency/ConverterInterface.php @@ -9,19 +9,8 @@ interface ConverterInterface { /** * Convert from default currency to another. - * - * @param float $value - * @param string $targetCurrency - * @param boolean $round - * @param string $valueCurrency - * @return float */ - public function convert($value, $targetCurrency, $round = true, $valueCurrency = null); + public function convert(float $value, string $targetCurrency, bool $round = true, string $valueCurrency = null): float; - /** - * Get default currency. - * - * @return string - */ - public function getDefaultCurrency(); + public function getDefaultCurrency(): string; } diff --git a/Currency/Formatter.php b/Currency/Formatter.php index ef5a33a..94fd566 100644 --- a/Currency/Formatter.php +++ b/Currency/Formatter.php @@ -3,62 +3,45 @@ namespace Lexik\Bundle\CurrencyBundle\Currency; /** - * Currency formatter. - * * @author Cédric Girard */ class Formatter implements FormatterInterface { /** - * @var string + * @var array */ - protected $locale; + protected array $cleanCharacters; - /** - * @var array - */ - protected $cleanCharacters; - - /** - * @param sting $locale - */ - public function __construct($locale) + public function __construct(protected string $locale) { - $this->locale = $locale; - $this->cleanCharacters = array('EU', 'UK', 'US'); + $this->cleanCharacters = ['EU', 'UK', 'US']; } - /** - * {@inheritDoc} - */ - public function format($value, $valueCurrency = null, $decimal = true, $symbol = true) + public function format(float $value, string $valueCurrency = '', bool $decimal = true, bool $symbol = true): ?string { $formatter = new \NumberFormatter($this->locale, $symbol ? \NumberFormatter::CURRENCY : \NumberFormatter::PATTERN_DECIMAL); $value = $formatter->formatCurrency($value, $valueCurrency); if (!$decimal) { - $value = preg_replace('/[.,]00((?=\D)|$)/', '', $value); + $value = (string) preg_replace('/[.,]00((?=\D)|$)/', '', $value); } - if (count($this->cleanCharacters) > 0) { + if ($this->cleanCharacters !== []) { $value = str_replace($this->cleanCharacters, '', $value); } return $value; } - /** - * {@inheritDoc} - */ - public function setLocale($locale) + public function setLocale(string $locale): void { - $this->locale = (string) $locale; + $this->locale = $locale; } /** - * @param array $cleanCharacters + * @param array $cleanCharacters */ - public function setCleanCharacters(array $cleanCharacters) + public function setCleanCharacters(array $cleanCharacters): void { $this->cleanCharacters = $cleanCharacters; } diff --git a/Currency/FormatterInterface.php b/Currency/FormatterInterface.php index e675612..5dc31f0 100644 --- a/Currency/FormatterInterface.php +++ b/Currency/FormatterInterface.php @@ -7,21 +7,7 @@ */ interface FormatterInterface { - /** - * Format a given value. - * - * @param string $value - * @param null $valueCurrency - * @param boolean $decimal - * @param boolean $symbol - * @return string - */ - public function format($value, $valueCurrency = null, $decimal = true, $symbol = true); + public function format(float $value, string $valueCurrency = '', bool $decimal = true, bool $symbol = true): ?string; - /** - * Set the locale to use to format the value. - * - * @param string $locale - */ - public function setLocale($locale); + public function setLocale(string $locale): void; } diff --git a/DependencyInjection/Compiler/AdapterPass.php b/DependencyInjection/Compiler/AdapterPass.php index f1868eb..b4923cb 100644 --- a/DependencyInjection/Compiler/AdapterPass.php +++ b/DependencyInjection/Compiler/AdapterPass.php @@ -2,8 +2,8 @@ namespace Lexik\Bundle\CurrencyBundle\DependencyInjection\Compiler; -use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; /** @@ -11,13 +11,13 @@ */ class AdapterPass implements CompilerPassInterface { - public function process(ContainerBuilder $container) + public function process(ContainerBuilder $container): void { // Attach all adapter to the adapter collector $definition = $container->getDefinition('lexik_currency.adapter_collector'); - foreach ($container->findTaggedServiceIds('lexik_currency.adapter') as $id => $attributes) { - $definition->addMethodCall('add', array(new Reference($id))); + foreach (array_keys($container->findTaggedServiceIds('lexik_currency.adapter')) as $id) { + $definition->addMethodCall('add', [new Reference($id)]); } // set default adapter alias @@ -29,4 +29,4 @@ public function process(ContainerBuilder $container) } } } -} \ No newline at end of file +} diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 15fb221..dacd22f 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -5,18 +5,12 @@ use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; -/** - * This is the class that validates and merges configuration from your app/config files - */ class Configuration implements ConfigurationInterface { - /** - * {@inheritDoc} - */ - public function getConfigTreeBuilder() + public function getConfigTreeBuilder(): TreeBuilder { - $treeBuilder = new TreeBuilder(); - $rootNode = $treeBuilder->root('lexik_currency'); + $treeBuilder = new TreeBuilder('lexik_currency'); + $rootNode = $treeBuilder->getRootNode(); $rootNode ->addDefaultsIfNotSet() @@ -30,7 +24,7 @@ public function getConfigTreeBuilder() ->isRequired() ->end() ->arrayNode('managed') - ->defaultValue(array('EUR')) + ->defaultValue(['EUR']) ->isRequired() ->prototype('scalar') ->end() diff --git a/DependencyInjection/LexikCurrencyExtension.php b/DependencyInjection/LexikCurrencyExtension.php index 3bca23d..ddeb035 100644 --- a/DependencyInjection/LexikCurrencyExtension.php +++ b/DependencyInjection/LexikCurrencyExtension.php @@ -2,10 +2,10 @@ namespace Lexik\Bundle\CurrencyBundle\DependencyInjection; -use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\FileLocator; -use Symfony\Component\HttpKernel\DependencyInjection\Extension; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader; +use Symfony\Component\HttpKernel\DependencyInjection\Extension; /** * This is the class that loads and manages your bundle configuration @@ -13,14 +13,14 @@ class LexikCurrencyExtension extends Extension { /** - * {@inheritDoc} + * @param string[] $configs */ - public function load(array $configs, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); - $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('services.xml'); $loader->load('adapters.xml'); diff --git a/Entity/Currency.php b/Entity/Currency.php index 7a0434c..34bb97a 100644 --- a/Entity/Currency.php +++ b/Entity/Currency.php @@ -9,85 +9,48 @@ */ class Currency { - /** - * @var int - */ - protected $id; + protected int $id; /** * @Assert\Length(min=3) * @Assert\Length(max=3) * @Assert\NotBlank() * @Assert\Type(type="string") - * - * @var string */ - protected $code; + protected string $code; /** * @Assert\NotBlank() * @Assert\Type(type="numeric") - * - * @var string */ - protected $rate; + protected float $rate; - /** - * Get ID - * - * @return string - */ - public function getId() + public function getId(): int { return $this->id; } - /** - * Get code - * - * @return string - */ - public function getCode() + public function getCode(): string { return $this->code; } - /** - * Set code - * - * @param string $code - */ - public function setCode($code) + public function setCode(string $code): void { $this->code = $code; } - /** - * Get rate - * - * @return string - */ - public function getRate() + public function getRate(): float { return $this->rate; } - /** - * Set rate - * - * @param string $rate - */ - public function setRate($rate) + public function setRate(float $rate): void { $this->rate = $rate; } - /** - * Convert currency rate - * - * @param float $rate - */ - public function convert($rate) + public function convert(float $rate): void { $this->rate /= $rate; } diff --git a/EventListener/LocaleListener.php b/EventListener/LocaleListener.php index 8e73e8b..4483ea2 100644 --- a/EventListener/LocaleListener.php +++ b/EventListener/LocaleListener.php @@ -4,7 +4,7 @@ use Lexik\Bundle\CurrencyBundle\Currency\FormatterInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; /** @@ -12,35 +12,24 @@ */ class LocaleListener implements EventSubscriberInterface { - /** - * @var \Lexik\Bundle\CurrencyBundle\Currency\FormatterInterface - */ - private $formatter; - - /** - * @param FormatterInterface $formatter - */ - public function __construct(FormatterInterface $formatter) + public function __construct(private FormatterInterface $formatter) { - $this->formatter = $formatter; } /** - * {@inheritDoc} + * @return array> */ - public static function getSubscribedEvents() + public static function getSubscribedEvents(): array { - return array( - KernelEvents::REQUEST => array( - array('setCurrencyFormatterLocale', 17) // must be registered before the default Locale listener - ), - ); + return [ + KernelEvents::REQUEST => [ + // must be registered before the default Locale listener + ['setCurrencyFormatterLocale', 17] + ], + ]; } - /** - * @param GetResponseEvent $event - */ - public function setCurrencyFormatterLocale(GetResponseEvent $event) + public function setCurrencyFormatterLocale(RequestEvent $event): void { $request = $event->getRequest(); diff --git a/Exception/CurrencyNotFoundException.php b/Exception/CurrencyNotFoundException.php index 446f945..f2075d9 100644 --- a/Exception/CurrencyNotFoundException.php +++ b/Exception/CurrencyNotFoundException.php @@ -8,8 +8,8 @@ */ class CurrencyNotFoundException extends \InvalidArgumentException { - public function __construct($currency) + public function __construct(string $currency) { - parent::__construct(sprintf('Can\'t find currency: "%s"', $currency)); + parent::__construct(sprintf('Cannot find currency: "%s"', $currency)); } -} \ No newline at end of file +} diff --git a/LexikCurrencyBundle.php b/LexikCurrencyBundle.php index 5e47722..97694d7 100644 --- a/LexikCurrencyBundle.php +++ b/LexikCurrencyBundle.php @@ -3,8 +3,8 @@ namespace Lexik\Bundle\CurrencyBundle; use Lexik\Bundle\CurrencyBundle\DependencyInjection\Compiler\AdapterPass; -use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\HttpKernel\Bundle\Bundle; class LexikCurrencyBundle extends Bundle { diff --git a/Resources/config/adapters.xml b/Resources/config/adapters.xml index 44446a4..5e58ac5 100644 --- a/Resources/config/adapters.xml +++ b/Resources/config/adapters.xml @@ -17,7 +17,7 @@ - + diff --git a/Tests/Fixtures/CurrencyData.php b/Tests/Fixtures/CurrencyData.php index 43c7982..97a3745 100644 --- a/Tests/Fixtures/CurrencyData.php +++ b/Tests/Fixtures/CurrencyData.php @@ -2,10 +2,10 @@ namespace Lexik\Bundle\CurrencyBundle\Tests\Fixtures; -use Lexik\Bundle\CurrencyBundle\Entity\Currency; - use Doctrine\Common\DataFixtures\FixtureInterface; -use Doctrine\Common\Persistence\ObjectManager; + +use Doctrine\Persistence\ObjectManager; +use Lexik\Bundle\CurrencyBundle\Entity\Currency; /** * Tests fixtures class. @@ -14,15 +14,12 @@ */ class CurrencyData implements FixtureInterface { - /** - * @see Doctrine\Common\DataFixtures.FixtureInterface::load() - */ - public function load(ObjectManager $manager) + public function load(ObjectManager $manager): void { - $values = array( - array('code' => 'EUR', 'rate' => 1), - array('code' => 'USD', 'rate' => 1.3), - ); + $values = [ + ['code' => 'EUR', 'rate' => 1.0], + ['code' => 'USD', 'rate' => 1.3], + ]; foreach ($values as $data) { $currency = new Currency(); @@ -34,4 +31,4 @@ public function load(ObjectManager $manager) $manager->flush(); } -} \ No newline at end of file +} diff --git a/Tests/Unit/Adapter/AdapterFactoryTest.php b/Tests/Unit/Adapter/AdapterFactoryTest.php index 72e0449..8f75a15 100644 --- a/Tests/Unit/Adapter/AdapterFactoryTest.php +++ b/Tests/Unit/Adapter/AdapterFactoryTest.php @@ -2,58 +2,59 @@ namespace Lexik\Bundle\CurrencyBundle\Tests\Unit\Adapter; +use Doctrine\Bundle\DoctrineBundle\Registry; use Lexik\Bundle\CurrencyBundle\Adapter\AdapterFactory; +use Lexik\Bundle\CurrencyBundle\Adapter\DoctrineCurrencyAdapter; +use Lexik\Bundle\CurrencyBundle\Adapter\EcbCurrencyAdapter; +use Lexik\Bundle\CurrencyBundle\Adapter\YahooCurrencyAdapter; +use Lexik\Bundle\CurrencyBundle\Entity\Currency; use Lexik\Bundle\CurrencyBundle\Tests\Unit\BaseUnitTestCase; class AdapterFactoryTest extends BaseUnitTestCase { - const CURRENCY_ENTITY = 'Lexik\Bundle\CurrencyBundle\Entity\Currency'; - - protected $doctrine; - - public function setUp() + public function setUp(): void { $this->doctrine = $this->getMockDoctrine(); $em = $this->getEntityManager(); $this->createSchema($em); } - public function testCreateEcbAdapter() + public function testCreateEcbAdapter(): void { - $factory = new AdapterFactory($this->doctrine, 'EUR', array('EUR', 'USD'), self::CURRENCY_ENTITY); + $factory = new AdapterFactory($this->doctrine, 'EUR', ['EUR', 'USD'], Currency::class); $adapter = $factory->createEcbAdapter(); - $this->assertInstanceOf('Lexik\Bundle\CurrencyBundle\Adapter\EcbCurrencyAdapter', $adapter); + $this->assertInstanceOf(EcbCurrencyAdapter::class, $adapter); $this->assertEquals('EUR', $adapter->getDefaultCurrency()); - $this->assertEquals(array('EUR', 'USD'), $adapter->getManagedCurrencies()); + $this->assertEquals(['EUR', 'USD'], $adapter->getManagedCurrencies()); $this->assertEquals(0, count($adapter)); } - public function testCreateYahooAdapter() + public function testCreateYahooAdapter(): void { - $factory = new AdapterFactory($this->doctrine, 'EUR', array('EUR', 'USD'), self::CURRENCY_ENTITY); + $factory = new AdapterFactory($this->doctrine, 'EUR', ['EUR', 'USD'], Currency::class); $adapter = $factory->createYahooAdapter(); - $this->assertInstanceOf('Lexik\Bundle\CurrencyBundle\Adapter\YahooCurrencyAdapter', $adapter); + $this->assertInstanceOf(YahooCurrencyAdapter::class, $adapter); $this->assertEquals('EUR', $adapter->getDefaultCurrency()); - $this->assertEquals(array('EUR', 'USD'), $adapter->getManagedCurrencies()); + $this->assertEquals(['EUR', 'USD'], $adapter->getManagedCurrencies()); $this->assertEquals(0, count($adapter)); } - public function testCreateDoctrineAdapter() + public function testCreateDoctrineAdapter(): void { $em = $this->getEntityManager(); $this->loadFixtures($em); - $factory = new AdapterFactory($this->doctrine, 'USD', array('EUR'), self::CURRENCY_ENTITY); + $factory = new AdapterFactory($this->doctrine, 'USD', ['EUR'], Currency::class); $adapter = $factory->createDoctrineAdapter(); - $this->assertInstanceOf('Lexik\Bundle\CurrencyBundle\Adapter\DoctrineCurrencyAdapter', $adapter); + $this->assertInstanceOf(DoctrineCurrencyAdapter::class, $adapter); $this->assertEquals('USD', $adapter->getDefaultCurrency()); - $this->assertEquals(array('EUR'), $adapter->getManagedCurrencies()); + $this->assertEquals(['EUR'], $adapter->getManagedCurrencies()); $this->assertEquals(0, count($adapter)); - $adapter['USD']; // force initialization + $adapter['USD']; // force initialization // @phpstan-ignore-line $this->assertEquals(2, count($adapter)); } -} \ No newline at end of file +} diff --git a/Tests/Unit/BaseUnitTestCase.php b/Tests/Unit/BaseUnitTestCase.php index b1b4fa8..b190740 100644 --- a/Tests/Unit/BaseUnitTestCase.php +++ b/Tests/Unit/BaseUnitTestCase.php @@ -2,67 +2,53 @@ namespace Lexik\Bundle\CurrencyBundle\Tests\Unit; -use Lexik\Bundle\CurrencyBundle\Tests\Fixtures\CurrencyData; - -use Doctrine\ORM\EntityManager; +use Doctrine\Bundle\DoctrineBundle\Registry; use Doctrine\Common\DataFixtures\Executor\ORMExecutor; use Doctrine\Common\DataFixtures\Purger\ORMPurger; -use Doctrine\Common\Annotations\AnnotationReader; +use Doctrine\ORM\Configuration; +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Mapping\DefaultQuoteStrategy; +use Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver; +use Doctrine\ORM\Repository\DefaultRepositoryFactory; +use Doctrine\ORM\Tools\SchemaTool; +use Lexik\Bundle\CurrencyBundle\Tests\Fixtures\CurrencyData; +use PHPUnit\Framework\TestCase; /** * Base unit test class providing functions to create a mock entity manger, load schema and fixtures. * * @author Cédric Girard */ -abstract class BaseUnitTestCase extends \PHPUnit_Framework_TestCase +abstract class BaseUnitTestCase extends TestCase { - /** - * Create the database schema. - * - * @param EntityManager $em - */ - protected function createSchema(EntityManager $em) + public Registry $doctrine; + + protected function createSchema(EntityManagerInterface $em): void { - $schemaTool = new \Doctrine\ORM\Tools\SchemaTool($em); + $schemaTool = new SchemaTool($em); $schemaTool->createSchema($em->getMetadataFactory()->getAllMetadata()); } - /** - * Load test fixtures. - * - * @param EntityManager $om - */ - protected function loadFixtures(EntityManager $em) + protected function loadFixtures(EntityManagerInterface $em): void { $purger = new ORMPurger(); $executor = new ORMExecutor($em, $purger); - $executor->execute(array(new CurrencyData()), false); + $executor->execute([new CurrencyData()], false); } /** * EntityManager mock object together with annotation mapping driver and * pdo_sqlite database in memory - * - * @return EntityManager */ - protected function getMockSqliteEntityManager() + protected function getMockSqliteEntityManager(): EntityManagerInterface { - $cache = new \Doctrine\Common\Cache\ArrayCache(); + $xmlDriver = new SimplifiedXmlDriver([ + __DIR__ . '/../../Resources/config/doctrine' => 'Lexik\Bundle\CurrencyBundle\Entity', + ]); - // xml driver - $xmlDriver = new \Doctrine\ORM\Mapping\Driver\SimplifiedXmlDriver(array( - __DIR__.'/../../Resources/config/doctrine' => 'Lexik\Bundle\CurrencyBundle\Entity', - )); - - // configuration mock - $config = $this->getMock('Doctrine\ORM\Configuration'); - $config->expects($this->any()) - ->method('getMetadataCacheImpl') - ->will($this->returnValue($cache)); - $config->expects($this->any()) - ->method('getQueryCacheImpl') - ->will($this->returnValue($cache)); + $config = $this->createMock(Configuration::class); $config->expects($this->once()) ->method('getProxyDir') ->will($this->returnValue(sys_get_temp_dir())); @@ -83,26 +69,24 @@ protected function getMockSqliteEntityManager() ->will($this->returnValue('Doctrine\ORM\EntityRepository')); $config->expects($this->any()) ->method('getRepositoryFactory') - ->will($this->returnValue(new \Doctrine\ORM\Repository\DefaultRepositoryFactory())); + ->will($this->returnValue(new DefaultRepositoryFactory())); $config->expects($this->any()) ->method('getQuoteStrategy') - ->will($this->returnValue(new \Doctrine\ORM\Mapping\DefaultQuoteStrategy())); + ->will($this->returnValue(new DefaultQuoteStrategy())); - $conn = array( + $conn = [ 'driver' => 'pdo_sqlite', 'memory' => true, - ); - - $em = \Doctrine\ORM\EntityManager::create($conn, $config); + ]; - return $em; + return EntityManager::create($conn, $config); } - protected function getMockDoctrine() + protected function getMockDoctrine(): Registry { $em = $this->getMockSqliteEntityManager(); - $doctrine = $this->getMockBuilder('Doctrine\Bundle\DoctrineBundle\Registry') + $doctrine = $this->getMockBuilder(Registry::class) ->disableOriginalConstructor() ->getMock(); @@ -113,10 +97,11 @@ protected function getMockDoctrine() return $doctrine; } - protected function getEntityManager() + protected function getEntityManager(): EntityManagerInterface { $em = $this->doctrine->getManager(); + assert($em instanceof EntityManagerInterface); return $em; } -} \ No newline at end of file +} diff --git a/Tests/Unit/Converter/ConverterTest.php b/Tests/Unit/Converter/ConverterTest.php index 9330f4f..ce5fb27 100644 --- a/Tests/Unit/Converter/ConverterTest.php +++ b/Tests/Unit/Converter/ConverterTest.php @@ -2,19 +2,18 @@ namespace Lexik\Bundle\CurrencyBundle\Tests\Unit\Converter; +use Lexik\Bundle\CurrencyBundle\Adapter\AbstractCurrencyAdapter; use Lexik\Bundle\CurrencyBundle\Adapter\AdapterFactory; use Lexik\Bundle\CurrencyBundle\Currency\Converter; +use Lexik\Bundle\CurrencyBundle\Entity\Currency; +use Lexik\Bundle\CurrencyBundle\Exception\CurrencyNotFoundException; use Lexik\Bundle\CurrencyBundle\Tests\Unit\BaseUnitTestCase; class ConverterTest extends BaseUnitTestCase { - const CURRENCY_ENTITY = 'Lexik\Bundle\CurrencyBundle\Entity\Currency'; + private AbstractCurrencyAdapter $adapter; - protected $doctrine; - - private $adapter; - - public function setUp() + public function setUp(): void { $this->doctrine = $this->getMockDoctrine(); $em = $this->getEntityManager(); @@ -22,11 +21,11 @@ public function setUp() $this->createSchema($em); $this->loadFixtures($em); - $factory = new AdapterFactory($this->doctrine, 'EUR', array('EUR', 'USD'), self::CURRENCY_ENTITY); + $factory = new AdapterFactory($this->doctrine, 'EUR', ['EUR', 'USD'], Currency::class); $this->adapter = $factory->createDoctrineAdapter(); } - public function testConvert() + public function testConvert(): void { $converter = new Converter($this->adapter); @@ -39,7 +38,7 @@ public function testConvert() $this->assertEquals(8.666, $converter->convert(8.666, 'EUR')); } - public function testConvertNotRounded() + public function testConvertNotRounded(): void { $converter = new Converter($this->adapter); @@ -47,7 +46,7 @@ public function testConvertNotRounded() $this->assertEquals(8.666, $converter->convert(8.666, 'EUR', false)); } - public function testConvertFromNoDefaultCurrency() + public function testConvertFromNoDefaultCurrency(): void { $converter = new Converter($this->adapter); @@ -55,7 +54,7 @@ public function testConvertFromNoDefaultCurrency() $this->assertEquals(6.67, $converter->convert(8.666, 'EUR', true, 'USD')); } - public function testConvertFromNoDefaultCurrencyNotRounded() + public function testConvertFromNoDefaultCurrencyNotRounded(): void { $converter = new Converter($this->adapter); @@ -63,14 +62,13 @@ public function testConvertFromNoDefaultCurrencyNotRounded() $this->assertEquals(6.6661538461538, $converter->convert(8.666, 'EUR', false, 'USD')); } - /** - * @expectedException Lexik\Bundle\CurrencyBundle\Exception\CurrencyNotFoundException - * @expectedExceptionMessage Can't find currency: "UUU" - */ - public function testConvertUndefinedTarget() + public function testConvertUndefinedTarget(): void { $converter = new Converter($this->adapter); + $this->expectException(CurrencyNotFoundException::class); + $this->expectExceptionMessage('Cannot find currency: "UUU"'); + $converter->convert(8.666, 'UUU'); } -} \ No newline at end of file +} diff --git a/Tests/Unit/Twig/Extension/CurrencyExtensionTest.php b/Tests/Unit/Twig/Extension/CurrencyExtensionTest.php index 900cd44..0c7970d 100644 --- a/Tests/Unit/Twig/Extension/CurrencyExtensionTest.php +++ b/Tests/Unit/Twig/Extension/CurrencyExtensionTest.php @@ -2,22 +2,22 @@ namespace Lexik\Bundle\CurrencyBundle\Tests\Unit\Twig\Extension; -use Lexik\Bundle\CurrencyBundle\Currency\Converter; +use Doctrine\Bundle\DoctrineBundle\Registry; use Lexik\Bundle\CurrencyBundle\Adapter\AdapterFactory; +use Lexik\Bundle\CurrencyBundle\Currency\Converter; use Lexik\Bundle\CurrencyBundle\Currency\Formatter; -use Lexik\Bundle\CurrencyBundle\Twig\Extension\CurrencyExtension; +use Lexik\Bundle\CurrencyBundle\Entity\Currency; use Lexik\Bundle\CurrencyBundle\Tests\Unit\BaseUnitTestCase; +use Lexik\Bundle\CurrencyBundle\Twig\Extension\CurrencyExtension; use Symfony\Component\DependencyInjection\Container; class CurrencyExtensionTest extends BaseUnitTestCase { - const CURRENCY_ENTITY = 'Lexik\Bundle\CurrencyBundle\Entity\Currency'; - - protected $doctrine; + public Registry $doctrine; - private $container; + private Container $container; - public function setUp() + public function setUp(): void { $this->doctrine = $this->getMockDoctrine(); $em = $this->getEntityManager(); @@ -25,7 +25,7 @@ public function setUp() $this->createSchema($em); $this->loadFixtures($em); - $factory = new AdapterFactory($this->doctrine, 'EUR', array('EUR', 'USD'), self::CURRENCY_ENTITY); + $factory = new AdapterFactory($this->doctrine, 'EUR', ['EUR', 'USD'], Currency::class); $converter = new Converter($factory->createDoctrineAdapter()); @@ -36,7 +36,7 @@ public function setUp() $this->container->set('lexik_currency.formatter', $formatter); } - public function testConvert() + public function testConvert(): void { $extension = new CurrencyExtension($this->container); @@ -44,7 +44,7 @@ public function testConvert() $this->assertEquals(8.67, $extension->convert(8.666, 'EUR')); } - public function testFormat() + public function testFormat(): void { $extension = new CurrencyExtension($this->container); @@ -52,20 +52,20 @@ public function testFormat() $this->assertEquals('8,67 €', $extension->format(8.666, 'EUR')); $this->assertEquals('8,67 $', $extension->format(8.666, 'USD')); $this->assertEquals('8 $', $extension->format(8.0, 'USD', false)); - $this->assertEquals('8,666', $extension->format(8.666, 'USD', false, false)); - $this->assertEquals('8', $extension->format(8.0, 'USD', true, false)); + $this->assertEquals('8,67', $extension->format(8.666, 'USD', false, false)); + $this->assertEquals('8', $extension->format(8.0, 'USD', false, false)); $this->assertEquals('8 $', $extension->format(8.0, 'USD', false, true)); } - public function testConvertAndFormat() + public function testConvertAndFormat(): void { $extension = new CurrencyExtension($this->container); $this->assertEquals('11,27 $', $extension->convertAndFormat(8.666, 'USD')); $this->assertEquals('11,27 $', $extension->convertAndFormat(8.666, 'USD', false)); - $this->assertEquals('11,2658', $extension->convertAndFormat(8.666, 'USD', false, false)); + $this->assertEquals('11,27', $extension->convertAndFormat(8.666, 'USD', false, false)); $this->assertEquals('8,67', $extension->convertAndFormat(8.666, 'USD', true, false, 'USD')); - $this->assertEquals('8', $extension->convertAndFormat(8.0, 'USD', true, false, 'USD')); + $this->assertEquals('8,00', $extension->convertAndFormat(8.0, 'USD', true, false, 'USD')); $this->assertEquals('8,00 $', $extension->convertAndFormat(8.0, 'USD', true, true, 'USD')); $this->assertEquals('8 $', $extension->convertAndFormat(8.0, 'USD', false, true, 'USD')); } diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php index d9f7acc..326c216 100644 --- a/Tests/bootstrap.php +++ b/Tests/bootstrap.php @@ -1,7 +1,7 @@ * @author Yoann Aparici */ -class CurrencyExtension extends \Twig_Extension +class CurrencyExtension extends AbstractExtension { - /** - * @var ContainerInterface - */ - protected $container; + protected ContainerInterface $container; - /** - * Construct. - * - * @param ContainerInterface $container We need the entire container to lazy load the Converter - */ public function __construct(ContainerInterface $container) { $this->container = $container; } - /** - * {@inheritdoc} - */ - public function getFilters() + public function getFilters(): array { - return array( - new \Twig_SimpleFilter('currency_convert', array($this, 'convert')), - new \Twig_SimpleFilter('currency_format', array($this, 'format')), - new \Twig_SimpleFilter('currency_convert_format', array($this, 'convertAndFormat')), - ); + return [ + new TwigFilter('currency_convert', [$this, 'convert']), + new TwigFilter('currency_format', [$this, 'format']), + new TwigFilter('currency_convert_format', [$this, 'convertAndFormat']), + ]; } - /** - * @return \Lexik\Bundle\CurrencyBundle\Currency\ConverterInterface - */ - public function getConverter() + public function getConverter(): ConverterInterface { - return $this->container->get('lexik_currency.converter'); + $converter = $this->container->get('lexik_currency.converter'); + assert($converter instanceof ConverterInterface); + + return $converter; } - /** - * @return \Lexik\Bundle\CurrencyBundle\Currency\FormatterInterface - */ - public function getFormatter() + public function getFormatter(): FormatterInterface { - return $this->container->get('lexik_currency.formatter'); + $formatter = $this->container->get('lexik_currency.formatter'); + assert($formatter instanceof FormatterInterface); + + return $formatter; } - /** - * Convert the given value. - * - * @param float $value - * @param string $targetCurrency target currency code - * @param boolean $round roud converted value - * @param string $valueCurrency $value currency code - * @return float - */ - public function convert($value, $targetCurrency, $round = true, $valueCurrency = null) + public function convert(float $value, string $targetCurrency, bool $round = true, string $valueCurrency = null): float { return $this->getConverter()->convert($value, $targetCurrency, $round, $valueCurrency); } - /** - * Format the given value. - * - * @param mixed $value - * @param string $valueCurrency $value currency code - * @param boolean $decimal show decimal part - * @param boolean $symbol show currency symbol - * @return string - */ - public function format($value, $valueCurrency = null, $decimal = true, $symbol = true) + public function format(float $value, string $valueCurrency = null, bool $decimal = true, bool $symbol = true): ?string { if (null === $valueCurrency) { $valueCurrency = $this->getConverter()->getDefaultCurrency(); @@ -87,27 +62,14 @@ public function format($value, $valueCurrency = null, $decimal = true, $symbol = return $this->getFormatter()->format($value, $valueCurrency, $decimal, $symbol); } - /** - * Convert and format the given value. - * - * @param mixed $value - * @param string $targetCurrency target currency code - * @param boolean $decimal show decimal part - * @param boolean $symbol show currency symbol - * @param string $valueCurrency the $value currency code - * @return string - */ - public function convertAndFormat($value, $targetCurrency, $decimal = true, $symbol = true, $valueCurrency = null) + public function convertAndFormat(float $value, string $targetCurrency, bool $decimal = true, bool $symbol = true, string $valueCurrency = null): ?string { $value = $this->convert($value, $targetCurrency, $decimal, $valueCurrency); return $this->format($value, $targetCurrency, $decimal, $symbol); } - /** - * {@inheritdoc} - */ - public function getName() + public function getName(): string { return 'lexik_currency.currency_extension'; } diff --git a/composer.json b/composer.json index 4becb48..07e6903 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,8 @@ { "name": "lexik/currency-bundle", "type": "symfony-bundle", - "description": "This Symfony2 bundle provide a service and a Twig extension to convert and display currencies.", - "keywords": ["Symfony2", "bundle", "currency"], + "description": "This Symfony bundle provide a service and a Twig extension to convert and display currencies.", + "keywords": ["Symfony", "bundle", "currency"], "homepage": "https://github.com/lexik/LexikCurrencyBundle", "license": "MIT", "authors": [ @@ -16,8 +16,21 @@ } ], "require": { - "php": ">=5.5.9", - "symfony/framework-bundle": "~2.8|~3.0" + "php": ">8.0", + "ext-curl": "*", + "ext-intl": "*", + "ext-simplexml": "*", + "symfony/framework-bundle": "^5.0 || ^6.0" + }, + "require-dev": { + "rector/rector": "^0.12.16", + "symplify/easy-coding-standard": "^10.0", + "doctrine/orm": "^2.11", + "doctrine/doctrine-bundle": "^2.5", + "phpunit/phpunit": "^9.5", + "doctrine/doctrine-fixtures-bundle": "^3.4", + "twig/twig": "^3.3", + "symfony/validator": "^6.0" }, "autoload": { "psr-4": { "Lexik\\Bundle\\CurrencyBundle\\": "" } diff --git a/ecs.php b/ecs.php new file mode 100644 index 0000000..e0d13a1 --- /dev/null +++ b/ecs.php @@ -0,0 +1,24 @@ +parameters(); + $parameters->set(Option::PATHS, [ + __DIR__ + ]); + $parameters->set(Option::PARALLEL, true); + + $containerConfigurator->import(SetList::PSR_12); + + $services = $containerConfigurator->services(); + $services->set(ArraySyntaxFixer::class) + ->call('configure', [[ + 'syntax' => 'short', + ]]); +}; diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..aeb27a6 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,19 @@ + +parameters: + + level: 9 + + paths: + - Adapter + - Command + - Currency + - DependencyInjection + - Entity + - EventListener + - Exception + - Resources + - Tests + - Twig + + ignoreErrors: + - '#NodeDefinition::addDefaultsIfNotSet\(\)#' diff --git a/phpunit.xml.dist b/phpunit.xml.dist index f3cb7d3..318747e 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,34 +1,32 @@ - - + + + ./Adapter + ./Command + ./Currency + ./DependencyInjection + ./Entity + ./EventListener + ./Exception + ./Twig + + + ./Resources + ./Tests + ./vendor + + ./Tests/ - - - - ./ - - ./Resources - ./Tests - ./vendor - - - - - + diff --git a/rector.php b/rector.php new file mode 100644 index 0000000..3e9e996 --- /dev/null +++ b/rector.php @@ -0,0 +1,38 @@ +parameters(); + + $parameters->set(Option::PATHS, [ + __DIR__ . '/Adapter', + __DIR__ . '/Command', + __DIR__ . '/Currency', + __DIR__ . '/DependencyInjection', + __DIR__ . '/Entity', + __DIR__ . '/EventListener', + __DIR__ . '/Exception', + __DIR__ . '/Resources', + __DIR__ . '/Tests', + __DIR__ . '/Twig', + ]); + $parameters->set(Option::PARALLEL, true); + + $containerConfigurator->import(SetList::TYPE_DECLARATION); + $containerConfigurator->import(SetList::CODE_QUALITY); + $containerConfigurator->import(SetList::PHP_80); + $containerConfigurator->import(SetList::PHP_74); + $containerConfigurator->import(SetList::PHP_73); + $containerConfigurator->import(SetList::PHP_72); + $containerConfigurator->import(SetList::PHP_71); + $containerConfigurator->import(SetList::PHP_70); + + //$services = $containerConfigurator->services(); + //$services->set(TypedPropertyRector::class); +};