S
S
Sandro_s2018-10-18 22:02:11
Yii
Sandro_s, 2018-10-18 22:02:11

How to implement multicurrency in Yii2?

I use the basik template with a modular admin panel. In the main template of the online store there is such a switch:

<div class="btn-group pull-right">
                        <div class="btn-group">
                            <button type="button" class="btn btn-default dropdown-toggle usa" data-toggle="dropdown">
                                USA
                                <span class="caret"></span>
                            </button>
                            <ul class="dropdown-menu">
                                <li><a href="#">Canada</a></li>
                                <li><a href="#">UK</a></li>
                            </ul>
                        </div>

                        <div class="btn-group">
                            <button type="button" class="btn btn-default dropdown-toggle usa" data-toggle="dropdown">
                                DOLLAR
                                <span class="caret"></span>
                            </button>
                            <ul class="dropdown-menu">
                                <li><a href="#">Canadian Dollar</a></li>
                                <li><a href="#">Pound</a></li>
                            </ul>
                        </div>
                    </div>
                </div>
                <div class="col-sm-8">
                    <div class="shop-menu pull-right">

In products that are displayed on the main page from index/category
<div class="price-range"><!--price-range-->
            <h2>Price Range</h2>
            <div class="well text-center">
                <input type="text" class="span2" value="" data-slider-min="0" data-slider-max="600" data-slider-step="5" data-slider-value="[250,450]" id="sl2" ><br />
                <b class="pull-left">$ 0</b> <b class="pull-right">$ 600</b>
            </div>
        </div><!--/price-range-->

The price of the product is stored in the database in 'price' as a simple number and is now displayed as if in dollars. How to implement a currency switch in products and then integrate it with Robokassa, for example?
<h2>$<?= $hit->price?></h2>

Answer the question

In order to leave comments, you need to log in

1 answer(s)
O
Oleg Malinovsky, 2019-01-25
@kwazaro

To complete the task, you need the following:

  1. In the product table, in addition to the price field, you also need to have the currency_code field, in which to store the currency code of this product (after all, the initial price of the product can be in USD, or EUR - do not change it constantly when the exchange rate fluctuates).
  2. Create a module for currencies (the currency table in the database, the Currency model and a convenient KRUD for managing currencies). In the currency table, code must be unique - the currency code, by foreign key, link it to the currency_code field in the goods table. Also, the currency should have the fields rate (rate) and default (default currency for the site). For the default currency, rate should be 1.
  3. You need to write a small component app/components/Currency.php, in which, through working with the session, save the currency selected by the user on the site to the session (it is convenient to select the currency through the widget). Also, in all places of the project where the price of the goods is displayed, it must be displayed through the currency component, so that it converts it from the original one (the one specified in the database as the currency for the price of the goods) into the one selected by the user. Transformation, according to the rate set in the admin panel (KRUD for currencies, rate field).
Currency model example
<?php

namespace app\modules\shop\models;

use Yii;
use yii\db\ActiveRecord;
use yii\helpers\ArrayHelper;

class Currency extends ActiveRecord
{
    const STATUS_ACTIVE = 1;
    const STATUS_INACTIVE = 0;

    public function behaviors()
    {
        return [
            'timestamp' => [
                'class' => \yii\behaviors\TimestampBehavior::class,
            ],
            'blameable' => [
                'class' => \yii\behaviors\BlameableBehavior::class,
            ],
            'ip' => [
                'class' => \yii\behaviors\AttributeBehavior::class,
                'attributes' => [
                    ActiveRecord::EVENT_BEFORE_INSERT => 'created_ip',
                    ActiveRecord::EVENT_BEFORE_UPDATE => 'updated_ip',
                ],
                'value' => function ($event) {
                    return Yii::$app->request->getUserIP();
                },
            ],
        ];
    }

    public static function tableName()
    {
        return 'currency';
    }

    public function rules()
    {
        return [
            [['name', 'code'], 'required'],
            [['is_default', 'sort', 'status'], 'integer'],
            [['decimal_places'], 'integer', 'max' => 9],
            [['rate'], 'number'],
            [['code'], 'string', 'length' => 3],
            [['code'], 'unique'],
            [['code'], 'match', 'pattern' => '/^[A-Z]+$/', 'message' => Yii::t('app', 'Это поле может содержать только строчные буквы, цифры и дефис')],
            [['name', 'symbol'], 'string', 'max' => 32],
        ];
    }

    public function attributeLabels()
    {
        return [
            'id' => Yii::t('app', 'ID'),
            'created_at' => Yii::t('app', 'Дата создания'),
            'updated_at' => Yii::t('app', 'Дата обновления'),
            'created_by' => Yii::t('app', 'Создано пользователем'),
            'updated_by' => Yii::t('app', 'Обновлено пользователем'),
            'created_ip' => Yii::t('app', 'Создано c IP'),
            'updated_ip' => Yii::t('app', 'Обновлено c IP'),
            'code' => Yii::t('app', 'Код'),
            'name' => Yii::t('app', 'Название'),
            'symbol' => Yii::t('app', 'Символ'),
            'rate' => Yii::t('app', 'Курс'),
            'decimal_places' => Yii::t('app', 'Количество знаков после запятой'),
            'is_default' => Yii::t('app', 'По умолчанию'),
            'sort' => Yii::t('app', 'Сортировка'),
            'status' => Yii::t('app', 'Опубликован'),
        ];
    }
   
    public function afterSave($insert, $changedAttributes)
    {
        return Yii::$app->session->remove('currency');
    }
    
    public static function listItems()
    {
        $items = self::find()
            ->select(['code'])
            ->where(['status' => self::STATUS_ACTIVE])
            ->orderBy(['sort' => SORT_ASC])
            ->asArray()
            ->all();
        return ArrayHelper::map($items, 'code', 'code');
    }
    
    public static function statuses()
    {
        return [
            self::STATUS_ACTIVE => Yii::t('app', 'Опубликован'),
            self::STATUS_INACTIVE => Yii::t('app', 'Не опубликован'),
        ];
    }
}

Currency Component Example
<?php

namespace app\modules\shop\components;

use Yii;
use yii\base\BaseObject;
use app\modules\shop\models\Currency;

class CurrencyManager extends BaseObject
{
    public $currencies;
    public $defaultCurrency;
    public $siteCurrency;
    
    public function init()
    {
        parent::init();
        
        $this->currencies = Currency::find()
            ->where(['status' => Currency::STATUS_ACTIVE])
            ->orderBy(['sort' => SORT_ASC])
            ->asArray()
            ->all();
        foreach ($this->currencies as $item) {
            if ($item['is_default'] == 1) {
                $this->defaultCurrency = $item;
            }
        }
        if (!Yii::$app->session['currency']) {
            Yii::$app->session['currency'] = $this->defaultCurrency;
        }
        $this->siteCurrency = Yii::$app->session['currency'];
    }
    
    public function listCurrencies()
    {
        $result = [];
        foreach ($this->currencies as $item) {
            $result[$item['code']] = $item['code'];
        }
        return $result;
    }
    
    public function showPrice($offer, $symbol = true)
    {
        if ($offer['currency_code'] == $this->siteCurrency['code']) {
            $price = $offer['price'];
        } else {
            foreach ($this->currencies as $item) {
                if ($item['code'] == $offer['currency_code']) {
                    $rate = $item['rate'];
                }
            }
            $price = ($offer['price'] * $rate) / $this->siteCurrency['rate'];
        }
                
        if ($symbol === true) {
            return number_format($price, $this->siteCurrency['decimal_places'], '.', '') . '&nbsp;' . $this->siteCurrency['symbol'];
        } else {
            //return round($price, $this->siteCurrency['decimal_places']);
            return number_format($price, $this->siteCurrency['decimal_places'], '.', '');
        }
    }
    
    public function showOldPrice($offer, $symbol = true)
    {
        if ($offer['currency_code'] == $this->siteCurrency['code']) {
            $price = $offer['old_price'];
        } else {
            foreach ($this->currencies as $item) {
                if ($item['code'] == $offer['currency_code']) {
                    $rate = $item['rate'];
                }
            }
            $price = ($offer['old_price'] * $rate) / $this->siteCurrency['rate'];
        }
                
        if ($symbol === true) {
            return number_format($price, $this->siteCurrency['decimal_places'], '.', '') . '&nbsp;' . $this->siteCurrency['symbol'];
        } else {
            return round($price, $this->siteCurrency['decimal_places']);
        }
    }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question