Merge pull request #13913 from snipe/bug/sc-24071

Fixed #13905 - Use `unique_undeleted` instead of `unique_serial`
This commit is contained in:
snipe 2023-11-21 14:12:15 +00:00 committed by GitHub
commit 9347af0970
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 27 deletions

View file

@ -99,9 +99,9 @@ class Asset extends Depreciable
'expected_checkin' => 'date|nullable',
'location_id' => 'exists:locations,id|nullable',
'rtd_location_id' => 'exists:locations,id|nullable',
'asset_tag' => 'required|min:1|max:255|unique_undeleted:assets,asset_tag|not_array',
'asset_tag' => 'required|min:1|max:255|unique_undeleted:assets,asset_tag|not_array',
'purchase_date' => 'date|date_format:Y-m-d|nullable',
'serial' => 'unique_serial|nullable',
'serial' => 'unique_undeleted:assets,serial|nullable',
'purchase_cost' => 'numeric|nullable|gte:0',
'supplier_id' => 'exists:suppliers,id|nullable',
'asset_eol_date' => 'date|nullable',
@ -109,6 +109,7 @@ class Asset extends Depreciable
'byod' => 'boolean',
];
/**
* The attributes that are mass assignable.
*

View file

@ -46,44 +46,56 @@ class ValidationServiceProvider extends ServiceProvider
return $validator->passes();
});
// Unique only if undeleted
// This works around the use case where multiple deleted items have the same unique attribute.
// (I think this is a bug in Laravel's validator?)
// $parameters is the rule parameters, like `unique_undeleted:users,id` - $parameters[0] is users, $parameters[1] is id
// the UniqueUndeletedTrait prefills these so you can just use `unique_undeleted` in your rules (but this would only work directly in the model)
/**
* Unique only if undeleted.
*
* This works around the use case where multiple deleted items have the same unique attribute.
* (I think this is a bug in Laravel's validator?)
*
* $attribute is the FIELDNAME you're checking against
* $value is the VALUE of the item you're checking against the existing values in the fieldname
* $parameters[0] is the TABLE NAME you're querying
* $parameters[1] is the ID of the item you're querying - this makes it work on saving, checkout, etc,
* since it defaults to 0 if there is no item created yet (new item), but populates the ID if editing
*
* The UniqueUndeletedTrait prefills these parameters, so you can just use
* `unique_undeleted:table,fieldname` in your rules out of the box
*/
Validator::extend('unique_undeleted', function ($attribute, $value, $parameters, $validator) {
if (count($parameters)) {
$count = DB::table($parameters[0])->select('id')->where($attribute, '=', $value)->whereNull('deleted_at')->where('id', '!=', $parameters[1])->count();
// This is a bit of a shim, but serial doesn't have any other rules around it other than that it's nullable
if (($parameters[0]=='assets') && ($attribute == 'serial') && (Setting::getSettings()->unique_serial != '1')) {
return true;
}
$count = DB::table($parameters[0])
->select('id')
->where($attribute, '=', $value)
->whereNull('deleted_at')
->where('id', '!=', $parameters[1])->count();
return $count < 1;
}
});
// Unique if undeleted for two columns
// Same as unique_undeleted but taking the combination of two columns as unique constrain.
Validator::extend('two_column_unique_undeleted', function ($attribute, $value, $parameters, $validator) {
if (count($parameters)) {
$count = DB::table($parameters[0])
->select('id')->where($attribute, '=', $value)
->whereNull('deleted_at')
->where('id', '!=', $parameters[1])
->where($parameters[2], $parameters[3])->count();
return $count < 1;
}
});
Validator::extend('unique_serial', function ($attribute, $value, $parameters, $validator) {
if(Setting::getSettings()->unique_serial == '1') {
$count = DB::table('assets')->select('id')->where('serial', '=', $value)->whereNull('deleted_at')->count();
// Same as unique_undeleted but taking the combination of two columns as unique constrain.
Validator::extend('two_column_unique_undeleted', function ($attribute, $value, $parameters, $validator) {
if (count($parameters)) {
$count = DB::table($parameters[0])
->select('id')->where($attribute, '=', $value)
->whereNull('deleted_at')
->where('id', '!=', $parameters[1])
->where($parameters[2], $parameters[3])->count();
return $count < 1;
} else {
return true;
}
});
// Prevent circular references
//
// Example usage in Location model where parent_id references another Location: