Description
Laravel Version
12.14.1
PHP Version
8.4
Database Driver & Version
No response
Description
When using Model::automaticallyEagerLoadRelationships()
in combination with a relationship that uses withDefault()
(for example, a morphOne
wallet relationship), accessing the relationship in an Eloquent event like created
or saved
leads to Laravel returning a default (unsaved) related model. If you try to save this model (for instance, to initialize some data), it may be persisted without proper foreign key values, resulting in an integrity constraint violation (e.g., is null). holder_id
This is unintuitive and can easily cause hard-to-trace bugs in codebases that rely on eager loading and relationship defaults.
Example
Business Model:
class Business extends Model
{
public static function booted()
{
static::automaticallyEagerLoadRelationships();
}
public function wallet()
{
return $this->morphOne(Wallet::class, 'holder')
->withDefault([
'balance' => 0,
]);
}
}
Wallet Model:
class Wallet extends Model
{
public function holder()
{
return $this->morphTo();
}
}
In BusinessObserver:
public function created(Business $business)
{
// Access wallet and try to save it
$business->wallet->updateBalance();
// ...other logic
}
Result:
If the business does not have a wallet yet, $business->wallet
returns the default wallet (not saved, belonging to the business). If you try to call $business->wallet->save()
(possibly via updateBalance()
), Laravel attempts to insert it, but and are null, which causes: holder_id``holder_type
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'holder_id' cannot be null
Expected Behavior
Related models returned by withDefault()
should not be saved automatically unless all their required foreign keys are present. Alternatively, using automatic eager loading should not trigger the creation of a default related model that is not ready to be persisted.
Note:
When Model::automaticallyEagerLoadRelationships()
is not used, the relationship with withDefault()
works as expected and no integrity constraint violations occur.
Steps To Reproduce
- Enable in your model.
automaticallyEagerLoadRelationships
- Define a relationship with
withDefault
. - Within a model event, access and attempt to use/save the related model.
- Observe the failure if the related model was not created before the event handler.