Silverstripe:将数据库值与 cms 字段相互转换

问题描述 投票:0回答:1

我使用整数将钱存储在我的数据库中。这意味着 $0.50 是 50。我以这样的方式扩展了 Integer db 字段,现在它可以在前端正常工作。它可以很好地与整数相互转换。

但是在后端我遇到了问题。 silverstripe CMS 似乎可以进行自己的转换(例如添加千位分隔符),这有有趣的结果:)。

你们会如何解决这个问题?我尝试使用 onbeforewrite 和自定义 getter。

这是我的代码,从整数数据库字段的扩展开始

    /**
 * Format a number to currency
 * @param int    $number_of_decimals    When larger than 0 it will return this number of decimals, AND divide the amount by 10^number of the amount of decimals
 * @param bool   $round                 Round the resulting number to the closest whole number
 * @param string $thousands_char        Character used as thousands separator
 * @param string $decimal_char          Character used as decimal separator
 * @return string
 */
public function toCurrency($number_of_decimals=2, $round=false, $thousands_char=".", $decimal_char=",") {
    $divide_by = pow(10,$number_of_decimals);
    $value = $this->owner->value/$divide_by;
    if($round) {
        //no decimals when rounding :)
        $number_of_decimals=0;
    }
    return number_format($value, $number_of_decimals, $decimal_char,$thousands_char);
}

public function fromCurrency($number_of_decimals=2, $thousands_char=".", $decimal_char=",") {
    $multiply_by = pow(10,$number_of_decimals);
    //get rid of the thousand separator
    $value = str_replace($thousands_char,"",$this->owner->value);
    //replace the decimal char with a point
    $value = str_replace($decimal_char,".",$value);
    $value = $value*$multiply_by;
    return number_format($value, 0, ".","");
}

我还将其添加到 SiteConfig 的扩展中(从而创建了一种全局可用的函数

/**
 * Creates a DBField equivalent of the value, based on the type. In such a way, we can make use of the dame functions that are in an extension of a dbfield.
 * @param $type The type of the DBfield to create (e.g. Varchar, Int etc.).
 * @param $value The value, a string or number
 * @return mixed
 */
public function ToDBField($type,$value) {
    $field = $type::create();
    $field->setValue($value);
    return $field;
}

这些函数执行实际工作,它们位于数据对象中:

    public function GetAmount() {
        $amount = parent::getField("Amount");
        if (is_subclass_of(Controller::curr(), "LeftAndMain")) {
            $int_amount = SiteConfig::current_site_config()->ToDBField("Int", $amount);
            return $int_amount->toCurrency($number_of_decimals=2, $round=false, $thousands_char="", $decimal_char=".");
        }
        return $amount;
    }

    public function onBeforeWrite() {
        $int_amount = SiteConfig::current_site_config()->ToDBField("Int", $this->Amount);
        $this->Amount = $int_amount->fromCurrency(2,",",".");
        parent::onBeforeWrite();
    }
php silverstripe
1个回答
2
投票

所以您面临的问题是基于

DbField
类型的默认脚手架之一。默认情况下,键入
Int
将在 CMS 中使用
NumericField
,不进行货币格式设置。

我们可以在

getCMSFields
DataObject
函数中覆盖表单字段的脚手架。具体来说,使用
FieldList::replaceField
将表单字段替换为我们选择的字段之一。

function getCMSFields()
{
    $fields = parent::getCMSFields();
    $fields->replaceField('Amount', CurrencyField::create('Amount', 'Amount'));

    return $fields;
}

为此,您有多种选择,可以从头开始构建自己的表单字段、在现有表单字段的基础上构建或使用预先存在的表单字段。

CurrencyField
MoneyField
都应该做你想做的事情,而不需要在
DataObject
上公开你自己的函数来进行来回转换。

有几点需要注意:

  • 从文档来看,
    CurrencyField
    仅限于以美国为中心的格式
  • CurrencyField
    MoneyField
    并非设计为由整数支持

此时,我会考虑改变你的方法。

MoneyField
似乎最接近您想要的描述,能够更轻松地处理不同的货币。缺点是它需要
Money
数据库字段。

我从未使用过

MoneyField
,尽管我相信在一些项目中我已经使用过
CurrencyField
。因此,我无法形容它的使用和调整到您想要的方式是多么容易。

如果您仍然不愿意采用这种方法,我会考虑扩展

CurrencyField
类(我的意思是面向对象扩展类,不是内置扩展系统)并根据您的喜好进行调整。然而,实现这一点可能太宽泛,无法在这个问题中涵盖。

© www.soinside.com 2019 - 2024. All rights reserved.