在CakePHP模型或查询中执行货币转换


Carrying out currency conversion in a CakePHP model or query

我以业余爱好者的身份在CakePHP中构建了一个应用程序,我已经陷入了胖控制器和瘦模型的陷阱。我目前正在处理我的代码,并将大部分数据操作移到模型中,并总体上改进我的代码结构。

我在货币转换方面遇到了一些困难,我将试着简要总结一下我目前是如何转换货币的:

我有一个SQL-Server遗留数据库(我不允许更改-应用程序以只读容量使用该数据库),其中包含由"currno"字段指定的各种货币的条目。当我总结数据时,我希望它们都是单一货币。

在我完全控制的一个单独的数据库(MySQL)中,我创建了一个包含所有货币兑换率并定期更新的表。

要在控制器中转换货币,我已经编写了一个转换器组件,它具有"转换"功能,如下所示(货币表中的列标头是'cur',后面跟着' curno ',例如:"cur6"):

public function convert($from, $to, $amount, $table) {
        if($from == null or $to == null) {
            return 0;
        }
        for($i = 0; $i < count($table); $i++) {
            if($table[$i]['Currency']['CURRNO'] == $from) break;
        }
        $rates = $table[$i];
        $to = 'cur' . $to;
        if ($amount * $rates['Currency'][$to] != null) {
            return $amount * $rates['Currency'][$to];
        } else return 0;
    }

为了减少重复查询数据库,在我调用控制器中的转换函数之前,我将货币表存储在一个变量中并将其传递给函数(这对我来说似乎是一个好主意,但我可能在这里错了)。

在我从模型中收集了所有数据之后,我必须在控制器中转换它:

$contracts = $this->Territory->Contract->Ctit->getTitles($id,'territory');
$this->loadModel('Currency');
$currencytable = $this->Currency->find('all');
foreach ($contracts as &$contract) {
    if($contract['Royalty']['currno'] == $currency) {
        $contract['Title']['earned_usd'] = $contract['Title']['earned'];
        $contract['Title']['advance_usd'] = $contract['Title']['advance'];
    } else {
        $contract['Title']['earned_usd'] = $this->Converter->convert($contract['Royalty']['currno'],$currency,$contract['Title']['earned'],$currencytable);
        $contract['Title']['advance_usd'] = $this->Converter->convert($contract['Royalty']['currno'],$currency,$contract['Title']['advance'],$currencytable);
    }
}
unset($contract);

我想知道的是,我是否有更聪明的方法来做这件事?这感觉有点欺骗,我也(也许是错误的)觉得这应该是我在模型中做的事情。我知道在一个模型中使用组件是可能的,但我真的不想用另一个代替一个坏的做法。

抱歉,如果这个问题是有点不清楚,但我发现很难明确表达我想知道什么!如果还需要什么信息,请告诉我。

如果你的货币转换是在一个组件中,那么你可以从数据库中获取数据,在你的数据上运行货币转换,以获得一个通用的货币,然后传递给你的视图。

类似(伪代码):

$data = $this->ModelName->find('all');
foreach ($data as $row) {
    $row['ModelName']['amount'] = $this->Currency->convert($row['ModelName']['currency_code'], 'USD', $row['ModelName']['amount']);
}
$this->set('data', $data);

当然,如果你在多个地方这样做,那么你可能会寻找DRY out。考虑创建一个服务类,它是一个只做一件事的简单类。您可以使用一个服务类来获取结果并转换结果的货币:

<?php
App::uses('ModelName', 'Model');
class GetResultsInCurrencyService
{
    protected $currencyCode;
    protected $ModelName;
    public function __construct($currencyCode)
    {
        $this->currencyCode = $currencyCode;
        $this->ModelName = new ModelName();
    }
    public function results()
    {
        $data = $this->ModelName->find('all');
        foreach ($data as $row) {
            // Do currency conversion
        }
        return $data;
    }
}

在控制器中的使用:

$service = new GetResultsInCurrencyService('USD');
$this->set('data', $service->results());