-
Notifications
You must be signed in to change notification settings - Fork 11.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle unique validation conflicts caused by soft-deleted records #54275
base: 11.x
Are you sure you want to change the base?
Handle unique validation conflicts caused by soft-deleted records #54275
Conversation
Allows excluding soft-deleted records during unique validation.
public function withSoftDeletes() | ||
{ | ||
$this->where(function ($query) { | ||
$query->whereNull('deleted_at'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This field may be named differently in each model.
6c8d962
to
358a8c2
Compare
Ensure the soft delete column can be dynamically determined based on the model.
358a8c2
to
3be1960
Compare
Doesn't framework/src/Illuminate/Validation/Rules/DatabaseRule.php Lines 179 to 190 in 122e5c2
|
$this->where(function ($query) use ($model) { | ||
$deletedAtColumn = $model && method_exists($model, 'getDeletedAtColumn') | ||
? $model->getDeletedAtColumn() | ||
: 'deleted_at'; | ||
|
||
$query->whereNull($deletedAtColumn); | ||
}); | ||
|
||
return $this; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use tap()
here:
$this->where(function ($query) use ($model) { | |
$deletedAtColumn = $model && method_exists($model, 'getDeletedAtColumn') | |
? $model->getDeletedAtColumn() | |
: 'deleted_at'; | |
$query->whereNull($deletedAtColumn); | |
}); | |
return $this; | |
return tap($this)->where(function ($query) use ($model) { | |
$deletedAtColumn = $model && method_exists($model, 'getDeletedAtColumn') | |
? $model->getDeletedAtColumn() | |
: 'deleted_at'; | |
$query->whereNull($deletedAtColumn); | |
}); |
* @return $this | ||
*/ | ||
public function withSoftDeletes() | ||
public function withSoftDeletes(?Model $model = null): static |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might want to add similar functionality to ignore()
, where what is passed can be one of a few options:
framework/src/Illuminate/Validation/Rules/Unique.php
Lines 34 to 44 in 122e5c2
public function ignore($id, $idColumn = null) | |
{ | |
if ($id instanceof Model) { | |
return $this->ignoreModel($id, $idColumn); | |
} | |
$this->ignore = $id; | |
$this->idColumn = $idColumn ?? 'id'; | |
return $this; | |
} |
In our case, this would be either a model or the column name directly.
Hi Laravel Team 👋,
During my experience working on various projects, I’ve encountered a recurring issue when validating the uniqueness of a field while using Soft Deletes. Specifically, when using Rule::unique for validation, it often leads to unintended conflicts because soft-deleted records are still considered in the validation check. This has caused confusion and bugs in projects where certain records are logically “deleted” but still exist in the database.
To address this issue, I’ve introduced a new method called withSoftDeletes to the Rule::unique class. This method allows developers to exclude soft-deleted records from the unique validation check. By explicitly opting in to this behavior, it ensures that the framework remains opinionated and avoids introducing any breaking changes.
I believe this addition can improve the developer experience by:
Usage Example:
Here’s an example of how this method can be used:
Thank you for considering this PR! 😊
Looking forward to your feedback and suggestions.