I've been trying for hours to figure out this error in CodeIgniter 4 (PHP 8.2), and I think someone else might notice what I'm missing.
I have a Model with an update function. When I use it as is, I get this error: CodeIgniter\Database\Exceptions\DataException There is no data to update.
So, I modified my function to perform multiple tests, but without success.
Here is my Model:
<?php
namespace App\Models;
use CodeIgniter\Model;
use App\Models\SourceUrlModel;
class CurrencyRateModel extends Model
{
protected $table = 'currency_rates';
protected $primaryKey = null;
protected $allowedFields = [
'currency_id_asked',
'currency_id_inkind',
'exchange_rate',
'source_url_id',
];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
/**
* Updates the currency rate in the database.
*
* This function checks if the given currency pair is valid (i.e., the 'currency_id_inkind'
* is not the same as 'currency_id_asked'). If valid, it updates the exchange rate and
* source URL ID for the reverse currency pair in the database. It logs details of the
* update operation and catches any exceptions, logging an error message if an issue arises.
*
* @param array $_data An associative array containing:
* - 'currency_id_asked': ID of the currency being asked for.
* - 'currency_id_inkind': ID of the currency in kind.
* - 'exchange_rate': The exchange rate between the two currencies.
* - 'source_url_id': The ID of the source URL for the exchange rate.
*
* @return void
*
* @throws \Exception If there is an error during the update operation.
*/
public function updateCurrencyRate( $_data )
{
$SU = new SourceUrlModel();
if( $_data['currency_id_inkind'] != $_data['currency_id_asked'] )
{
try
{
// Try to Update
$this->where('currency_id_asked', $_data['currency_id_asked'])
->where('currency_id_inkind', $_data['currency_id_inkind'])
->update([
'exchange_rate' => 1 / $_data['exchange_rate'],
'source_url_id' => $SU->getSaveUrlIfNotExists($_data['source_url_id']),
]);
// Formatted var dump of updated data
vd([
'exchange_rate' => 1 / $_data['exchange_rate'],
'source_url_id' => $SU->getSaveUrlIfNotExists($_data['source_url_id']),
'currency_id_asked' => $_data['currency_id_asked'],
'currency_id_inkind' => $_data['currency_id_inkind'],
],
'UPDATED DATA');
}
catch(\Exception $e)
{
// Formatted var dump of existing data
vd($this->where('currency_id_asked', $_data['currency_id_asked'])->where('currency_id_inkind', $_data['currency_id_inkind'])->findAll(), 'Actual Data');
// Formatted var dump data to save
vd([
'exchange_rate' => 1 / $_data['exchange_rate'],
'source_url_id' => $SU->getSaveUrlIfNotExists($_data['source_url_id']),
'currency_id_asked' => $_data['currency_id_asked'],
'currency_id_inkind' => $_data['currency_id_inkind'],
],
'Data to Save');
}
}
}
/**
* Check if a currency rate exists in the database.
*
* @param array $_data an associative array containing the 'currency_id_asked' and 'currency_id_inkind' of the currency rate to check
* @return mixed the currency rate if it exists, otherwise false
*/
private function doesCurrencyRateExist( $_data )
{
return $this->where('currency_id_asked', $_data['currency_id_asked'])
->where('currency_id_inkind', $_data['currency_id_inkind'])
->first();
}
Here is the result (the second Actual Data / Data to Save is relevant, the first one is the result of a manual update in phpMyAdmin to check the SQL query):
Actual Data
array(1) {
[0]=>
array(6) {
["currency_id_asked"]=>
string(2) "18"
["currency_id_inkind"]=>
string(1) "4"
["exchange_rate"]=>
string(10) "0.84833814"
["source_url_id"]=>
string(4) "4563"
["created_at"]=>
string(19) "2024-11-30 13:00:28"
["updated_at"]=>
string(19) "2025-01-17 10:52:02"
}
}
Data to Save
array(4) {
["exchange_rate"]=>
float(0.8483381405341881)
["source_url_id"]=>
string(4) "4563"
["currency_id_asked"]=>
string(2) "18"
["currency_id_inkind"]=>
string(1) "4"
}
Actual Data
array(1) {
[0]=>
array(6) {
["currency_id_asked"]=>
string(1) "4"
["currency_id_inkind"]=>
string(2) "18"
["exchange_rate"]=>
string(10) "0.83409368"
["source_url_id"]=>
string(1) "9"
["created_at"]=>
string(19) "2024-11-30 13:00:28"
["updated_at"]=>
string(19) "2024-11-30 13:00:28"
}
}
Data to Save
array(4) {
["exchange_rate"]=>
float(1.17877524564711)
["source_url_id"]=>
string(4) "4563"
["currency_id_asked"]=>
string(1) "4"
["currency_id_inkind"]=>
string(2) "18"
}
[...]
I set protected $primaryKey = null; because it is a composite primary key, and it seems that this is the correct practice in my case. The test without line gives the same result.
I tried executing the query directly in SQL within CodeIgniter, but the problem persists. However, running the SQL query via phpMyAdmin works perfectly.
With the code I pasted above, I wanted to check:
Edit: I make this call in a function within a controller. I fetch a list of rates through an API and store them in the $exchangeRates
variable. Then, I use a nested loop to create exchange rates in both directions.
public function getSaveCurrencyPricesAndExchangeRates()
{
$CR = new CurrencyRateModel();
[...]
// Currency rate
foreach ($exchangeRates as $fromCurrency => $fromRate)
{
foreach ($exchangeRates as $toCurrency => $toRate)
{
$exchangeRate = $toRate / $fromRate;
// Insert the currency pair (fromCurrency/toCurrency) with its exchange rate
$CR->updateCurrencyRate([
'currency_id_asked' => $C->getCurrencyId($fromCurrency),
'currency_id_inkind' => $C->getCurrencyId($toCurrency),
'exchange_rate' => $exchangeRate,
'source_url_id' => $SU->getSaveUrlIfNotExists('https://api.[...]'),
]);
// Reverse the currency pair (toCurrency/fromCurrency)
$CR->updateCurrencyRate([
'currency_id_asked' => $C->getCurrencyId($toCurrency),
'currency_id_inkind' => $C->getCurrencyId($fromCurrency),
'exchange_rate' => 1/$exchangeRate,
'source_url_id' => $SU->getSaveUrlIfNotExists('https://api.[...]'),
]);
}
}
return 1;
}
What am I doing wrong?
Thanks a lot
The solution was kindly provided to me in the staging ground mode. I’m sharing it here in case it can help others in the same situation. The challenge was getting the update function to work with a composite key. I had to use a ->set() function with the update() function.
According to the documentation, the first argument to update() should be an id and the second argument should be the data. You seem to be only passing in the data, maybe try with set() instead?
$this->where('currency_id_asked', $_data['currency_id_asked'])
->where('currency_id_inkind', $_data['currency_id_inkind']) ->set([ 'exchange_rate' => 1 / $_data['exchange_rate'], 'source_url_id' => $SU->getSaveUrlIfNotExists($_data['source_url_id']), ])
->update();