Syncing an incorrect permission results in loss of all permissions
jnoordsij opened this issue · 4 comments
Before creating a new bug report
Please check if there isn't a similar issue on the issue tracker or in the discussions.
Describe the bug
When using the syncPermissions
function from the HasPermissions
trait, providing an accidental wrongly named permission will result in loss of all permissions. This is caused by the fact that syncPermissions
eagerly removes all existing permissions.
Versions
You can use composer show
to get the version numbers of:
- spatie/laravel-permission package version:
main
at commit 490fa00 - illuminate/framework package: N/A
PHP version: any
Database version: N/A
To Reproduce
Steps to reproduce the behavior:
- Create a model that uses the
HasPermissions
trait - Assign some valid permissions to the model
- Use the
syncPermissions
helper, with a combination of any number of valid permissions and at least one invalid permission
Result: all permissions will be lost on the user
Example Test
Here is a link to my Github repo containing a minimal Laravel application which shows my problem:
main...jnoordsij:spatie-laravel-permission:permission-sync-fail
Expected behavior
Result: the operation fails and the permissions remain the same as before
OR operation does partial work, removing only those permissions which are not synced.
Proposed (possible) solutions
- Use the native Laravel
sync
function with detaching; this does not do a full rollback, but it does ensure only pivots that are no longer present are removed, instead of eagerly removing all of them - Copy the behavior of the Laravel
sync
function to achieve something similar here - Do a "manual backup" of pre-existing permissions and force restore on error
- Skip over any non-existing permissions and throw Exception afterwards
if you lost all permissions it's a big problem, but it did not happen to me because I use transactions, small example:
DB::beginTransaction();
try{
// here all your sql transactions
DB::commit();
}catch(Exception $e){
DB::rollback();
}
With that, when exception raised rollback is made and I do not lose or change anything
Hey, thanks for mentioning this! I do think that's a great workaround indeed for those encoutering a similar problem and looking for a way to fix this with their own codebase.
In my case I only ran into this problem on my local environment, as my production environment code does not have non-existing permission issues, so no loss of real data for me luckily.
This issue is thus mainly an effort to raise awareness of this possibly unexpected behavior, get some input on the best approach to solve this more subtly within this package, and therefore hopefully saving some people some pain in the future!
hopefully saving some people some pain in the future!
@jnoordsij a fix for your tests #2341 bbaacf2
That looks like a great starting point! It's quite specifically tied to this case though, so maybe one of the approaches I suggested may be more preferable, as they are less prone to other exceptions happening while trying to sync.
However they might be more technically complex, so maybe it's a great start to go with your fix!