9
9
use Magento \Framework \App \ObjectManager ;
10
10
use Magento \Framework \Exception \InputException ;
11
11
use Magento \Directory \Model \Currency \Filter ;
12
+ use Magento \Framework \Locale \Currency as LocaleCurrency ;
13
+ use Magento \Framework \Locale \ResolverInterface as LocalResolverInterface ;
14
+ use Magento \Framework \NumberFormatterFactory ;
15
+ use Magento \Framework \Serialize \Serializer \Json ;
12
16
13
17
/**
14
18
* Currency model
@@ -71,6 +75,31 @@ class Currency extends \Magento\Framework\Model\AbstractModel
71
75
*/
72
76
private $ currencyConfig ;
73
77
78
+ /**
79
+ * @var LocalResolverInterface
80
+ */
81
+ private $ localeResolver ;
82
+
83
+ /**
84
+ * @var NumberFormatterFactory
85
+ */
86
+ private $ numberFormatterFactory ;
87
+
88
+ /**
89
+ * @var \Magento\Framework\NumberFormatter
90
+ */
91
+ private $ numberFormatter ;
92
+
93
+ /**
94
+ * @var array
95
+ */
96
+ private $ numberFormatterCache ;
97
+
98
+ /**
99
+ * @var Json
100
+ */
101
+ private $ serializer ;
102
+
74
103
/**
75
104
* @param \Magento\Framework\Model\Context $context
76
105
* @param \Magento\Framework\Registry $registry
@@ -79,10 +108,13 @@ class Currency extends \Magento\Framework\Model\AbstractModel
79
108
* @param \Magento\Directory\Helper\Data $directoryHelper
80
109
* @param Currency\FilterFactory $currencyFilterFactory
81
110
* @param \Magento\Framework\Locale\CurrencyInterface $localeCurrency
82
- * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
83
- * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
111
+ * @param \Magento\Framework\Model\ResourceModel\AbstractResource|null $resource
112
+ * @param \Magento\Framework\Data\Collection\AbstractDb|null $resourceCollection
84
113
* @param array $data
85
- * @param CurrencyConfig $currencyConfig
114
+ * @param CurrencyConfig|null $currencyConfig
115
+ * @param LocalResolverInterface|null $localeResolver
116
+ * @param NumberFormatterFactory|null $numberFormatterFactory
117
+ * @param Json|null $serializer
86
118
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
87
119
*/
88
120
public function __construct (
@@ -96,7 +128,10 @@ public function __construct(
96
128
\Magento \Framework \Model \ResourceModel \AbstractResource $ resource = null ,
97
129
\Magento \Framework \Data \Collection \AbstractDb $ resourceCollection = null ,
98
130
array $ data = [],
99
- CurrencyConfig $ currencyConfig = null
131
+ CurrencyConfig $ currencyConfig = null ,
132
+ LocalResolverInterface $ localeResolver = null ,
133
+ \Magento \Framework \NumberFormatterFactory $ numberFormatterFactory = null ,
134
+ Json $ serializer = null
100
135
) {
101
136
parent ::__construct (
102
137
$ context ,
@@ -111,6 +146,9 @@ public function __construct(
111
146
$ this ->_currencyFilterFactory = $ currencyFilterFactory ;
112
147
$ this ->_localeCurrency = $ localeCurrency ;
113
148
$ this ->currencyConfig = $ currencyConfig ?: ObjectManager::getInstance ()->get (CurrencyConfig::class);
149
+ $ this ->localeResolver = $ localeResolver ?: ObjectManager::getInstance ()->get (LocalResolverInterface::class);
150
+ $ this ->numberFormatterFactory = $ numberFormatterFactory ?: ObjectManager::getInstance ()->get (NumberFormatterFactory::class);
151
+ $ this ->serializer = $ serializer ?: ObjectManager::getInstance ()->get (Json::class);
114
152
}
115
153
116
154
/**
@@ -326,9 +364,121 @@ public function formatTxt($price, $options = [])
326
364
* %F - the argument is treated as a float, and presented as a floating-point number (non-locale aware).
327
365
*/
328
366
$ price = sprintf ("%F " , $ price );
367
+
368
+ if ($ this ->canUseNumberFormatter ($ options )) {
369
+ return $ this ->formatCurrency ($ price , $ options );
370
+ }
371
+
329
372
return $ this ->_localeCurrency ->getCurrency ($ this ->getCode ())->toCurrency ($ price , $ options );
330
373
}
331
374
375
+ /**
376
+ * Check if to use Intl.NumberFormatter to format currency.
377
+ *
378
+ * @param array $options
379
+ * @return bool
380
+ */
381
+ private function canUseNumberFormatter (array $ options ): bool
382
+ {
383
+ $ allowedOptions = [
384
+ 'precision ' ,
385
+ LocaleCurrency::CURRENCY_OPTION_DISPLAY ,
386
+ LocaleCurrency::CURRENCY_OPTION_SYMBOL
387
+ ];
388
+
389
+ if (!empty (array_diff (array_keys ($ options ), $ allowedOptions ))) {
390
+ return false ;
391
+ }
392
+
393
+ if (array_key_exists ('display ' , $ options )
394
+ && $ options ['display ' ] !== \Magento \Framework \Currency::NO_SYMBOL
395
+ && $ options ['display ' ] !== \Magento \Framework \Currency::USE_SYMBOL
396
+ ) {
397
+ return false ;
398
+ }
399
+
400
+ return true ;
401
+ }
402
+
403
+ /**
404
+ * Format currency.
405
+ *
406
+ * @param string $price
407
+ * @param array $options
408
+ * @return string
409
+ */
410
+ private function formatCurrency (string $ price , array $ options ): string
411
+ {
412
+ $ customerOptions = new \Magento \Framework \DataObject ([]);
413
+
414
+ $ this ->_eventManager ->dispatch (
415
+ 'currency_display_options_forming ' ,
416
+ ['currency_options ' => $ customerOptions , 'base_code ' => $ this ->getCode ()]
417
+ );
418
+ $ options += $ customerOptions ->toArray ();
419
+
420
+ $ this ->numberFormatter = $ this ->getNumberFormatter ($ options );
421
+
422
+ $ formattedCurrency = $ this ->numberFormatter ->formatCurrency (
423
+ $ price , $ this ->getCode () ?? $ this ->numberFormatter ->getTextAttribute (\NumberFormatter::CURRENCY_CODE )
424
+ );
425
+
426
+ if (array_key_exists (LocaleCurrency::CURRENCY_OPTION_SYMBOL , $ options )) {
427
+ // remove only one non-breaking space from custom currency symbol to allow custom NBSP in currency symbol
428
+ $ formattedCurrency = preg_replace ('/ /u ' , '' , $ formattedCurrency , 1 );
429
+ }
430
+
431
+ if ((array_key_exists (LocaleCurrency::CURRENCY_OPTION_DISPLAY , $ options )
432
+ && $ options [LocaleCurrency::CURRENCY_OPTION_DISPLAY ] === \Magento \Framework \Currency::NO_SYMBOL )) {
433
+ $ formattedCurrency = str_replace (' ' , '' , $ formattedCurrency );
434
+ }
435
+
436
+ return preg_replace ('/^\s+|\s+$/u ' , '' , $ formattedCurrency );
437
+ }
438
+
439
+ /**
440
+ * Get NumberFormatter object from cache.
441
+ *
442
+ * @param array $options
443
+ * @return \Magento\Framework\NumberFormatter
444
+ */
445
+ private function getNumberFormatter (array $ options ): \Magento \Framework \NumberFormatter
446
+ {
447
+ $ key = 'currency_ ' . md5 ($ this ->localeResolver ->getLocale () . $ this ->serializer ->serialize ($ options ));
448
+ if (!isset ($ this ->numberFormatterCache [$ key ])) {
449
+ $ this ->numberFormatter = $ this ->numberFormatterFactory ->create (
450
+ ['locale ' => $ this ->localeResolver ->getLocale (), 'style ' => \NumberFormatter::CURRENCY ]
451
+ );
452
+
453
+ $ this ->setOptions ($ options );
454
+ $ this ->numberFormatterCache [$ key ] = $ this ->numberFormatter ;
455
+ }
456
+
457
+ return $ this ->numberFormatterCache [$ key ];
458
+ }
459
+
460
+ /**
461
+ * Set number formatter custom options.
462
+ *
463
+ * @param array $options
464
+ * @return void
465
+ */
466
+ private function setOptions (array $ options ): void
467
+ {
468
+ if (array_key_exists (LocaleCurrency::CURRENCY_OPTION_SYMBOL , $ options )) {
469
+ $ this ->numberFormatter ->setSymbol (
470
+ \NumberFormatter::CURRENCY_SYMBOL , $ options [LocaleCurrency::CURRENCY_OPTION_SYMBOL ]
471
+ );
472
+ }
473
+ if (array_key_exists (LocaleCurrency::CURRENCY_OPTION_DISPLAY , $ options )
474
+ && $ options [LocaleCurrency::CURRENCY_OPTION_DISPLAY ] === \Magento \Framework \Currency::NO_SYMBOL ) {
475
+ $ this ->numberFormatter ->setSymbol (\NumberFormatter::CURRENCY_SYMBOL , '' );
476
+ }
477
+ if (array_key_exists ('precision ' , $ options )) {
478
+ $ this ->numberFormatter ->setAttribute (\NumberFormatter::FRACTION_DIGITS , $ options ['precision ' ]);
479
+ }
480
+ }
481
+
332
482
/**
333
483
* Return currency symbol for current locale and currency code
334
484
*
0 commit comments