(Below has been tested on CakePHP 5, but should work on 3+.)
Say you're working on a query that may have to do some currency conversion on the go if user's currency is different from the currency in your database. To make it worse, your site may use a third currency as a base currency (EUR, for example).
A MySQL query that can do this will look like this:
SET @base_currency := 'EUR';
SET @user_currency := 'CHF';
SELECT
CASE Currencies.code
WHEN @user_currency THEN Prices.price
WHEN @base_currency THEN Prices.price * CurrenciesUser.exchange_rate
ELSE Prices.price / Currencies.exchange_rate * CurrenciesUser.exchange_rate
END AS 'price_converted'
/* all other columns */
FROM
prices Prices
LEFT JOIN
currencies Currencies ON Currencies.id = Pricings.currency_id
LEFT JOIN
currencies CurrenciesUser ON CurrenciesUser.code = @user_currency
/* everything else */
ORDER BY price_converted
We start by checking if the user currency matches the currency of a given row - if so, we just return the price. Otherwise, we perform the currency conversion.
Here's how that will look written as a CakePHP query:
$user_currency = 'CHF';
$base_currency = 'EUR';
$query = $pricesTable->find('all')
->contain([
'Currencies',
// ...
])
->join([
'CurrenciesUser' => [
'type' => 'LEFT',
'table' => 'currencies',
'conditions' => [
'CurrenciesUser.code' => $user_currency
],
],
])
;
$query
->selectAlso([
'price_converted' => $query->newExpr()->case('Currencies.code')
->when($user_currency)
->then($query->newExpr('Prices.price'))
->when($base_currency)
->then($query->newExpr('Prices.price*CurrenciesUser.exchange_rate'))
->else($query->newExpr('Prices.price/Currencies.exchange_rate*CurrenciesUser.exchange_rate')),
])
Pay attention to how we use $query->newExpr
for column names. If we don't, we will get our expressions as literal strings in the query results.
Sources: