arch-8.x-1.x-dev/modules/price/src/Price/PriceFormatter.php
modules/price/src/Price/PriceFormatter.php
<?php namespace Drupal\arch_price\Price; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Render\RendererInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\currency\Entity\CurrencyInterface; use Drupal\currency\Plugin\Currency\AmountFormatter\AmountFormatterInterface; use Drupal\currency\Plugin\Currency\AmountFormatter\AmountFormatterManagerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** * Price formatter service. * * @package Drupal\arch_price\Price */ class PriceFormatter implements PriceFormatterInterface, ContainerInjectionInterface { use StringTranslationTrait; /** * Renderer service. * * @var \Drupal\Core\Render\RendererInterface */ protected $renderer; /** * Module handler. * * @var \Drupal\Core\Extension\ModuleHandlerInterface */ protected $moduleHandler; /** * Amount formatter. * * @var \Drupal\currency\Plugin\Currency\AmountFormatter\AmountFormatterInterface */ protected $amountFormatter; /** * Currency entity storage. * * @var \Drupal\Core\Entity\EntityStorageInterface */ protected $currencyStorage; /** * PriceFormatter constructor. * * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * Entity type manager. * @param \Drupal\currency\Plugin\Currency\AmountFormatter\AmountFormatterManagerInterface $amount_formatter_manager * Amount formatter manager. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * Module handler. * @param \Drupal\Core\Render\RendererInterface $renderer * Renderer. * * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ public function __construct( EntityTypeManagerInterface $entity_type_manager, AmountFormatterManagerInterface $amount_formatter_manager, ModuleHandlerInterface $module_handler, RendererInterface $renderer, ) { $this->currencyStorage = $entity_type_manager->getStorage('currency'); $this->amountFormatter = $amount_formatter_manager->createInstance('arch_price_currency_intl'); $this->moduleHandler = $module_handler; $this->renderer = $renderer; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( $container->get('entity_type.manager'), $container->get('plugin.manager.currency.amount_formatter'), $container->get('module_handler'), $container->get('renderer') ); } /** * {@inheritdoc} */ public function setAmountFormatter(AmountFormatterInterface $amount_formatter) { $this->amountFormatter = $amount_formatter; return $this; } /** * {@inheritdoc} */ public function buildFormatted(PriceInterface $price, $mode, array $settings = []) { if ($mode == self::FORMAT_FULL) { return $this->buildFull($price); } $price_values = $price->getValues(); $currency = $price->getCurrency(); $this->moduleHandler->alter('arch_price_display_settings', $settings, $price_values, $currency); $settings += ['wrapper_element' => 'div']; $values = [ self::FORMAT_NET => $price_values['net'], self::FORMAT_GROSS => $price_values['gross'], self::FORMAT_VAT_VALUE => $price->getVatValue(), ]; $label = NULL; if ($mode === self::FORMAT_NET) { $label = $this->t('Net', [], ['context' => 'arch_price']); } elseif ($mode === self::FORMAT_GROSS) { $label = $this->t('Gross', [], ['context' => 'arch_price']); } elseif ($mode === self::FORMAT_VAT_VALUE) { $label = $this->t('VAT', [], ['context' => 'arch_price']); $settings['vat_info'] = FALSE; } if ( !empty($settings['display_currency']) && $settings['display_currency'] != $currency->id() ) { /** @var \Drupal\currency\Entity\CurrencyInterface $display_currency */ $display_currency = $this->currencyStorage->load($settings['display_currency']); if ( !empty($display_currency) && $exchanged_values = $price->getExchangedPriceValues($display_currency) ) { $price_values = $exchanged_values; $currency = $display_currency; $values = [ self::FORMAT_NET => $price_values['net'], self::FORMAT_GROSS => $price_values['gross'], self::FORMAT_VAT_VALUE => $price_values['vat_value'], ]; } } $build = [ '#theme' => 'price', '#mode' => $mode, '#values' => $price_values, '#currency' => $currency, '#settings' => $settings, '#label' => $label, '#label_display' => $settings['label'] ?? TRUE, '#vat_rate' => $price->getVatRate(), '#vat_info_display' => $settings['vat_info'] ?? TRUE, '#formatted' => $this->amountFormatter->formatAmount( $currency, static::formatAmount($values[$mode], $currency) ), ]; return $build; } /** * Apply rounding step currency settings for displayed value. * * @param float $amount * Displayed amount value. * @param \Drupal\currency\Entity\CurrencyInterface $currency * Currency entity. * * @return string|null * Formatted amount. */ protected static function formatAmount($amount, CurrencyInterface $currency) { $amount = bcdiv($amount, $currency->getRoundingStep(), 6); $amount = bcmul(round($amount), $currency->getRoundingStep(), 6); $decimal_mark_position = strpos($amount, '.'); // The amount has no decimals yet, so add a decimal mark. if ($decimal_mark_position === FALSE) { $amount .= '.'; } // Remove any existing trailing zeroes. $amount = rtrim($amount, '0'); // Add the required number of trailing zeroes. $amount_decimals = strlen(substr($amount, $decimal_mark_position + 1)); if ($amount_decimals < $currency->getDecimals()) { $amount .= str_repeat('0', $currency->getDecimals() - $amount_decimals); } return $amount; } /** * {@inheritdoc} */ public function format(PriceInterface $price, $mode, array $settings = []) { $build = $this->buildFormatted($price, $mode, $settings); return $this->renderer->render($build); } /** * {@inheritdoc} */ public function buildNet(PriceInterface $price, array $settings = []) { return $this->buildFormatted($price, self::FORMAT_NET, $settings); } /** * {@inheritdoc} */ public function formatNet(PriceInterface $price, array $settings = []) { return $this->format($price, self::FORMAT_NET, $settings); } /** * {@inheritdoc} */ public function buildGross(PriceInterface $price, array $settings = []) { return $this->buildFormatted($price, self::FORMAT_GROSS, $settings); } /** * {@inheritdoc} */ public function formatGross(PriceInterface $price, array $settings = []) { return $this->format($price, self::FORMAT_GROSS, $settings); } /** * {@inheritdoc} */ public function buildFull(PriceInterface $price, array $settings = []) { return [ // @todo Consider adding VAT value. self::FORMAT_NET => $this->buildFormatted($price, self::FORMAT_NET, $settings), self::FORMAT_GROSS => $this->buildFormatted($price, self::FORMAT_GROSS, $settings), ]; } /** * {@inheritdoc} */ public function formatFull(PriceInterface $price, array $settings = []) { $build = $this->buildFull($price, $settings); return $this->renderer->render($build); } /** * {@inheritdoc} */ public function buildVat(PriceInterface $price, array $settings = []) { return $this->buildFormatted($price, self::FORMAT_VAT_VALUE, $settings); } /** * {@inheritdoc} */ public function formatVat(PriceInterface $price, array $settings = []) { return $this->format($price, self::FORMAT_VAT_VALUE, $settings); } }