[13.x] Fix touch() query generation on HasOneOrManyThrough relations
Merged
HA
25d ago+107+107+012345678901234567890123456789-0-0-0123456789
overrides touch() and adds allRelatedIds() on HasOneOrManyThrough, matching the same pattern already used in BelongsToMany::touch().
HasOneOrManyThrough currently inherits Relation::touch() that calls rawUpdate() on the relation query:
public function rawUpdate(array $attributes = [])
{
return $this->query->withoutGlobalScopes()->update($attributes);
}
Because HasManyThrough and HasOneThrough queries use an INNER JOIN against the intermediate table, running ->touch() causes two bugs:
- SQL crashes:
- On MySQL and MariaDB, it crashes with:
Column 'updated_at' in field list is ambiguous(both tables have anupdated_atcolumn). - On SQLite and PostgreSQL,
UPDATE ... INNER JOINqueries throw syntax errors.
- On MySQL and MariaDB, it crashes with:
- Intermediate soft-deletes leakage:
- Calling
withoutGlobalScopes()strips the intermediate soft-delete scope. Because of that, records belonging to soft-deleted intermediate parents get touched by mistake.
- Calling
Fix
Follow the same approach as BelongsToMany:
- Added
allRelatedIds()to pluck the IDs of the related models. - Overrode
touch()onHasOneOrManyThroughto pluck those IDs and run a cleanwhereInupdate without any joins.
Tests
Added integration tests to both DatabaseEloquentHasManyThroughIntegrationTest and DatabaseEloquentHasOneThroughIntegrationTest covering:
- Updating timestamps via
touch(). - Ensuring soft-deleted intermediate models are respected and not touched.
- Respecting
Model::withoutTouching(). - Verifying
allRelatedIds()returns the expected collection of IDs.