A fresh install dies creating the first airline:
App\Models\Airline::initJournal(): Argument #1 ($currency_code)
must be of type string, null given
setting() returns its $default for a key it cannot read -- retrieve()
throws SettingNotFound and the helper swallows it -- and the created
hook passed no default, so it handed null to a string parameter. The
'USD' default on initJournal() cannot help: an explicit argument always
beats a declared default, even when that argument is null.
The installer creates the airline and user in the same step, and the
settings seed is gated on a separate wizard step, so units.currency is
not guaranteed to exist by then. Every other reader of this setting
already names the fallback -- Money.php:59,74 and
PirepFinanceService.php:57,61 -- so this is the odd one out.
Airline and User are the only models using the trait; both are covered.
The suite could not have caught this because tests/Pest.php seeds
SettingsSeeder before every test, making an empty settings table
unreachable, so the new tests clear it explicitly.
65 lines
1.9 KiB
PHP
65 lines
1.9 KiB
PHP
<?php
|
|
|
|
namespace App\Traits;
|
|
|
|
use App\Models\Journal;
|
|
use Exception;
|
|
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
|
|
|
trait JournalTrait
|
|
{
|
|
/**
|
|
* Initialize a new journal when a new record is created
|
|
*/
|
|
public static function bootJournalTrait(): void
|
|
{
|
|
static::created(function ($model): void {
|
|
// The default on initJournal() cannot cover this: an explicit
|
|
// argument always beats a declared default, and setting() returns
|
|
// null for a key it cannot read. During install the first airline
|
|
// is created before units.currency necessarily exists, so passing
|
|
// the bare lookup hands a null to a string parameter. Every other
|
|
// caller of this setting already names the fallback.
|
|
$model->initJournal(setting('units.currency', 'USD'));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Morph to Journal.
|
|
*/
|
|
public function journal(): MorphOne
|
|
{
|
|
return $this->morphOne(Journal::class, 'morphed');
|
|
}
|
|
|
|
/**
|
|
* Initialize a journal for a given model object
|
|
*
|
|
*
|
|
*
|
|
* @throws Exception
|
|
*/
|
|
public function initJournal(string $currency_code = 'USD'): ?Journal
|
|
{
|
|
if (!$this->journal) {
|
|
$journal = new Journal();
|
|
$journal->type = $this->journal_type;
|
|
$journal->currency = $currency_code;
|
|
$journal->balance = 0;
|
|
$this->journal()->save($journal);
|
|
|
|
$journal->refresh();
|
|
|
|
// The `!$this->journal` guard above lazy-loaded the relation and cached
|
|
// it as null. Saving through the relation does not update that cache, so
|
|
// without this the model keeps returning null for ->journal until it is
|
|
// reloaded from the database. Reflect the freshly-created journal here.
|
|
$this->setRelation('journal', $journal);
|
|
|
|
return $journal;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|