This article originated from https://medium.com/@hafiqiqmal93/laravel-softdelete-avoiding-the-unique-constraint-problem-45381d9745a0
In case you’ve been using Laravel for a while, especially when projects involve data integrity, most likely you have already encountered the SoftDelete feature. Pretty useful because you can “delete” records without really taking them out of the database. What Laravel does is just add a deleted_at timestamp so it marks it as deleted, but remains in the system. That’s all well and good to retain historical data, but it does introduce one potentially sticky problem — what happens to unique constraints when you restore soft-deleted records?
This becomes a problem when you want to restore a record that already has, for instance, a unique email or username, in the database. Laravel will just throw an error and stop the proceedings. Fortunately, there’s an easy way of avoiding this problem in a very clean manner.
Let’s walk through a solution using a trait that will help you bypass the unique constraints when using SoftDelete in Laravel.
Let’s take a basic example. Imagine you have a users table with an email field that must be unique:
Schema::create('users', function (Blueprint $table) { $table->string('email')->unique(); $table->softDeletes(); });
If you soft delete a user with the email [email protected] and then later create a new user with the same email, Laravel will complain about the unique constraint on the email field, throwing an error. In the same situation, when you try to restore the deleted user, Laravel also will complain about the unique constraint on the email field and throwing an same error.
This becomes a headache, especially when dealing with large systems where record restoration is a common task.
To prevent this, we can temporarily alter the values of unique fields when a record is soft deleted and restore the original values when the record is brought back. This way, the database doesn’t trip over the unique constraint during soft deletes or restores.
A Laravel trait is a great way to encapsulate this functionality. Here’s a trait we can use to handle the problem:
trashed()) { foreach ($model->getDuplicateAvoidColumns() as $column) { // handle for Spatie Translatable library if (method_exists($model, 'getTranslatableAttributes')) { $translates = $model->getTranslatableAttributes(); if (in_array($column, $translates)) { foreach ($translates as $translate) { if ($translate === $column) { $values = $model->getTranslations($column); foreach ($values as $translation => $value) { $values[$translation] = (explode('--', $value)[1] ?? $value); } $model->setTranslations($column, $values); break; } } continue; } } if ($value = (explode('--', $model->{$column})[1] ?? null)) { $model->{$column} = $value; } } } }); static::deleted(function ($model): void { foreach ($model->getDuplicateAvoidColumns() as $column) { // handle for Spatie Translatable library if (method_exists($model, 'getTranslatableAttributes')) { $translates = $model->getTranslatableAttributes(); if (in_array($column, $translates)) { foreach ($translates as $translate) { if ($translate === $column) { $values = $model->getTranslations($column); foreach ($values as $translation => $value) { $values[$translation] = time() . '--' . $value; } $model->setTranslations($column, $values); break; } } continue; } } $model->{$column} = time() . '--' . $model->{$column}; } $model->save(); }); } }
This trait does a couple of things:
Here’s how you can apply this trait in your Laravel model:
class User extends Model { use SoftDeletes, AvoidDuplicateConstraintSoftDelete; // Specify which columns should avoid the unique constraint issue public function getDuplicateAvoidColumns(): array { return ['email', 'username']; } }
By adding the **AvoidDuplicateConstraintSoftDelete** trait to your model and specifying which columns need to avoid unique constraint conflicts (like email and username), you can easily prevent these issues.
What that means is that, in the event of a soft delete record, it would not cause a conflict with further operations because of some unique constraints. Or, in other words, this way you will be able to, by appending the timestamp to unique fields, render the record “hidden” for the database in terms of uniqueness but still recoverable when needed.
This is quite useful when you’re dealing with a large database and restoration of records is quite common. You won’t have to deal every time with the “duplicate entry” error whenever you bring a soft-deleted user or any other model.
The most useful thing in Laravel is SoftDelete, but sometimes it gives headaches while working with unique constraints. Here comes a simple, trait-based solution that will give an elegant way of avoiding the problem, just by temporary changes of unique fields on deletion and restore afterward. This way you will avoid frustrating mistakes and let your application work smoothly not breaking unique constraints in your database.
If any of your fields have been made multilingual or make use of libraries like Spatie’s Translatable, the above solution will work without problems in each of these cases. The SoftDeletes are meant to give you flexibility, not get in your way. With the above minor fix in place you’ll avoid most the pitfalls and keep your data tidy and your users happy.
By adding this trait to your models, you’ll be saving yourself time and headaches, especially if you’re dealing with large datasets where soft-deleting and restoring are frequent operations. Give it a try in your Laravel project, and you’ll see how smoothly it handles those tricky unique constraint problems!
Thank you for reading! Don’t forget to subscribe to stay informed about the latest updates in system design and e-commerce innovations. Happy designing!
If you found this article insightful and want to stay updated with more content on system design and technology trends, be sure to follow me on :-
Twitter: https://twitter.com/hafiqdotcom
LinkedIn: https://www.linkedin.com/in/hafiq93
Buy Me Coffee: https://paypal.me/mhi9388 /
https://buymeacoffee.com/mhitech
Medium: https://medium.com/@hafiqiqmal93
Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.
Copyright© 2022 湘ICP备2022001581号-3