Silverstripe:将数据库值与 cms 字段相互转换
Silverstripe: Converting a database value to and from a cms field
我使用整数将钱存储在我的数据库中。这意味着 0.50 美元是 50。我扩展了 Integer db 字段,现在它在前端可以正常工作。它很好地转换为整数或从整数转换。
在后端,但是我遇到了问题。 silverstripe CMS 似乎进行了自己的转换(例如添加千位分隔符),结果很有趣:)。
你们会如何解决这个问题?我尝试使用 onbeforewrite 和自定义 getter.
这是我的代码,从整数 db-field 的扩展开始
/**
* 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();
}
所以您面临的问题是基于 DbField
类型的默认脚手架之一。默认情况下,类型 Int
将在 CMS 中使用 NumericField
,它没有货币格式。
我们可以在 DataObject
的 getCMSFields
函数中覆盖表单字段的脚手架。特别是使用 FieldList::replaceField
将表单字段替换为我们选择的字段之一。
function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->replaceField('Amount', CurrencyField::create('Amount', 'Amount'));
return $fields;
}
您有多种选择,可以从头开始构建自己的表单域、在现有表单域之上构建或使用预先存在的表单域。 CurrencyField
and MoneyField
两者都应该做你想做的事,而不需要在 DataObject
上公开你自己的函数来进行来回转换。
有几点需要注意:
- 根据文档,
CurrencyField
仅限于以美国为中心的格式
CurrencyField
和 MoneyField
并非设计为由整数支持
在这一点上,我会考虑改变你的方法。 MoneyField
似乎最接近您想要的描述,能够更轻松地处理不同的货币。缺点是它需要一个 Money
数据库字段。
我从未使用过 MoneyField
,但我相信我在一些项目中使用过 CurrencyField
。正因为如此,我不能说它是多么容易使用和调整到你想要的方式。
如果您仍然不想采用这种方法,我可能会考虑扩展 CurrencyField
class(我的意思是面向对象扩展 class、not the built-in extension system) 并根据自己的喜好进行调整。然而,实施它可能过于广泛,无法涵盖在这个问题中。
我使用整数将钱存储在我的数据库中。这意味着 0.50 美元是 50。我扩展了 Integer db 字段,现在它在前端可以正常工作。它很好地转换为整数或从整数转换。
在后端,但是我遇到了问题。 silverstripe CMS 似乎进行了自己的转换(例如添加千位分隔符),结果很有趣:)。
你们会如何解决这个问题?我尝试使用 onbeforewrite 和自定义 getter.
这是我的代码,从整数 db-field 的扩展开始
/**
* 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();
}
所以您面临的问题是基于 DbField
类型的默认脚手架之一。默认情况下,类型 Int
将在 CMS 中使用 NumericField
,它没有货币格式。
我们可以在 DataObject
的 getCMSFields
函数中覆盖表单字段的脚手架。特别是使用 FieldList::replaceField
将表单字段替换为我们选择的字段之一。
function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->replaceField('Amount', CurrencyField::create('Amount', 'Amount'));
return $fields;
}
您有多种选择,可以从头开始构建自己的表单域、在现有表单域之上构建或使用预先存在的表单域。 CurrencyField
and MoneyField
两者都应该做你想做的事,而不需要在 DataObject
上公开你自己的函数来进行来回转换。
有几点需要注意:
- 根据文档,
CurrencyField
仅限于以美国为中心的格式 CurrencyField
和MoneyField
并非设计为由整数支持
在这一点上,我会考虑改变你的方法。 MoneyField
似乎最接近您想要的描述,能够更轻松地处理不同的货币。缺点是它需要一个 Money
数据库字段。
我从未使用过 MoneyField
,但我相信我在一些项目中使用过 CurrencyField
。正因为如此,我不能说它是多么容易使用和调整到你想要的方式。
如果您仍然不想采用这种方法,我可能会考虑扩展 CurrencyField
class(我的意思是面向对象扩展 class、not the built-in extension system) 并根据自己的喜好进行调整。然而,实施它可能过于广泛,无法涵盖在这个问题中。