Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jrdavidson's avatar

Soft Deleting A User And Their Profile

I am trying to figure out what I should do in this situation. I am wanting to soft delete a user and then soft delete their profile that way it can keep the data in my db in case the user decides to come back later and have an account again. What is the best route for me to go to not only soft delete the user but soft delete their profile as well.

As you can see I have applied the SoftDeletes Trait to my User model and have my relationship set up correctly between my user and their profile. How can I pass the soft delete down to the profile?

<?php namespace App;

use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use App\Presenters\PresentableTrait;
use App\Presenters\Contracts\PresentableInterface;

class User extends Model implements AuthenticatableContract, CanResetPasswordContract, PresentableInterface {

    use Authenticatable, CanResetPassword, PresentableTrait, SoftDeletes;

    /**
     * The database table that is to be used by the model.
     *
     * @var string
     */
    protected $table = 'users';

    /**
     * Add necessary date fields are to be used as Carbon instances.
     *
     * @var array
     */
    protected $dates = ['deleted_at'];

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['first_name', 'middle_name', 'last_name', 'username', 'email_address', 'password', 'confirmation_code', 'confirmed'];

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = ['password', 'remember_token'];

    /**
     * Get the presenter that is to be used by the model.
     *
     * @var array
     */
    protected $presenter = 'App\Presenters\User';

    /**
     * Set a token for creating a new user.
     */
    public static function boot()
    {
        parent::boot();

        static::creating(function($user) {
            $user->confirmation_code = str_random(30);
        });
    }

    /**
     * Encrypt all passwords before creating a user.
     *
     * @param $password
     */
    public function setPasswordAttribute($password)
    {
        $this->attributes['password'] = bcrypt($password);
    }

    /**
     * Get the role that is associated with a given user.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function role()
    {
        return $this->hasOne('App\Role', 'role_id', 'id');
    }

    /**
     * Get the user profile that is associated with a given user.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function profile()
    {
        return $this->hasOne('App\UserProfile', 'user_id', 'id');
    }

    /**
     * Get the activity that is associated with a given user.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function activity()
    {
        return $this->hasMany('App\Activity');
    }
}
<?php namespace App\Http\Controllers;

use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Repositories\Users\UserRepository;
use Illuminate\Http\Request;

class UsersController extends Controller {

    /**
     * @var UserRepository
     */
    private $userRepository;

    /**
     * @param UserRepository $userRepository
     */
    public function __construct(UserRepository $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    /**
     * Remove the specified user.
     *
     * TODO: Find out what to do when deleting a user and needing to delete the user profile.
     *
     * @param  int  $id
     * @return Response
     */
    public function destroy($id)
    {
        $this->userRepository->delete($id);

        return redirect('users');
    }

}
0 likes
26 replies
mstnorris's avatar

I'm just thinking aloud but wouldn't you just set the Profile to deleted when you soft_delete the User?

bobbybouwmann's avatar

Sadly you can't, What you can do is something like this

public function destroy($id, ProfileRepository $profileRepository)
{
    $user = User::findOrFail($id);

    $profileRepository->destroy($user->profile_id);

    $user->delete();

    return redirect('users');
}
1 like
jrdavidson's avatar

I'm just asking to learn and understand but why do you need to findOrFail before you delete in this instance. Also, does it matter if you soft delete the profile before the actual user? I have a userRepository which is not what you are doing.

JarekTkaczyk's avatar

@xtremer360 The order doesn't matter when you soft delete, since it's simply update query.

You can do it easily during deleted event. However, do you access profiles other than through the user model?

1 like
bobbybouwmann's avatar

If you use the repository pattern it common to use it on all your models

1 like
JarekTkaczyk's avatar
Level 53

@xtremer360 Why would you do this:

$profile = Profile::find($someId);

instead of this?

$user = User::find($someId);
$user->profile->something

Red this

That said, in fact it doesn't matter if profile is soft deleted or not.

Anyway, you can chain soft deleting during deleted event (ofc profile must use soft deletes as well).

1 like
jrdavidson's avatar

@JarekTkaczyk How would I chain soft deleting for my profile then? I'm just curioius since I have a userRepository to delete the user.

Flugg's avatar

If you only access the profile through the user model you wont need to mark it as deleted as its inaccessible if the user is deleted.

JarekTkaczyk's avatar

@xtremer360 raw eloquent:

// user
protected static function boot()
{
    parent::boot();
    
    static::deleted(function ($user) {
        $user->profile->delete();
    });
}

Better would be using observer, but it doesn't matter.

Now, since you're using repository, there's no need for the above. You probably have a method for deleting user in your repo, so just delete the profile along with user.

2 likes
jrdavidson's avatar

@JarekTkaczyk

This is what I currently have for my UserRepository. Is this correct?

<?php

namespace App\Repositories\Users;

use App\User;
use App\Repositories\EloquentRepository;

class EloquentUserRepository extends EloquentRepository implements UserRepository {

    public function __construct(User $model)
    {
        parent::__construct($model);
    }

    /**
     * @param integer $id
     * @return mixed|void
     */
    public function delete($id)
    {
        $user = User::findOrFail($id);

        $user->delete($user);
    }
}
JarekTkaczyk's avatar

@xtremer360 Apart from calling User::findOrFail instead of (probably) $this->user->findOrFail, you need to also delete its profile. That's all

jrdavidson's avatar

@JarekTkaczyk

So your saying something more like this. Double check I added it the rest.

<?php

namespace App\Repositories\Users;

use App\User;
use App\Repositories\EloquentRepository;

class EloquentUserRepository extends EloquentRepository implements UserRepository {

    protected $user;

    public function __construct(User $user)
    {
        parent::__construct($user);
        $this->user = $user;
    }

    /**
     * @param integer $id
     * @return mixed|void
     */
    public function delete($id)
    {
        $user = $this->user->findOrFail($id);

        $this->user->delete($user);

        $this->user->profile->delete($user);
    }
}
michaeldyrynda's avatar

This should be sufficient.

public function delete($id)
{
    $user = $this->user->findOrFail($id);

    $user->delete();
    $user->profile->delete();
}
1 like
martinbean's avatar

@xtremer360 I’m not sure why you need to soft-delete the profile at all. If you soft-delete the user, then any of that user’s associated data (including profile) would be inaccessible.

michaeldyrynda's avatar

@xtremer360 I would suggest not on the profile itself, no. You can handle deleting the profile in the same place as deleting the user, you could use a model observer, or depending on the complexity of other tasks that might need to take place when you delete a user, by firing an event.

(Soft) deleting the profile itself serves only as a tidy up process at this point. If you were using foreign key constraints with cascading deletes in your DB, rather than using the application to manage deleted items, then deleting the user would also trigger the deletion of any relationships.

It may not make sense necessarily to delete the profile when you delete the user now, but at a later time, you might want to access the profile directly, without hitting the user. In this instance, you probably don't want to be accessing profiles of deleted users.

Lets say you create the profile at the same time you create the user. That holding true, wouldn't you want to also remove the profile at the same time you remove a user? It's only one extra line, so why not?

jrdavidson's avatar

So since there's been a lot of posts in here and I feel as if people are giving me different paths to go in its leaving me in a state of confusion. So since I have a usersRepository but not profileRepository. I think I should handle both the creation and deletion of a user in the same way in reference to handling the users profile as well. Here's a few questions I'm asking.

  1. Do I need a profileRepository?
  2. Do I delete the profile in the UsersController or userRepository.
  3. Is this something that I should just use a model event for in the User model.
michaeldyrynda's avatar

Is there any time where you would be deleting the profile independently of the user? That should help you choose the best direction.

What reasoning do you have behind using repositories? I tend to use repositories for any read operations I use more than once only and use Eloquent models for write operations in most of my projects.

Jeffberry's avatar

Like the other guys said, there really should be no reason you need to delete the user's profile. So long as the user is not accessible, his associated data (his one-to-one data anyway) should not be accessible.

If you are looking for the correct answer though, triggers would probably be your best bet. This requires no code intervention, so it would save you from having to keep the two models' "deleted" status in sync.

create trigger soft_delete after update on users
for each row
update user_profile set deleted_at = new.deleted_at where user_id = new.id

All that would happen here, is when the user table's deleted_at column is updated, it keeps the associated row in user_profile's deleted_at column in sync. This will work both directions (deleting and restoring). You could then remove all your code that involves deleting the two models and stick to simply $user->delete() and $user->restore()

mehany's avatar

@Jeffberry nice . here is the laravel way then ;) -> wrap that in a migration

<?php

use Illuminate\Database\Migrations\Migration;

class CreateSoftDeleteTrigger extends Migration {

     public function up()

     {

     DB::unprepared('
          create trigger soft_delete after update on users 
          for each row
          update user_profile set deleted_at = new.deleted_at where user_id = new.id
          ');
     }

     public function down()
     {
          DB::unprepared('DROP TRIGGER `soft_delete `');
     }
  }
1 like
jrdavidson's avatar

@deringer @martinbean @JarekTkaczyk

Okay so I've decided to take the advice and I'm just deleting a user and not their profile because after really thinking about the only time a profile can be accessed is by a "super admin" can view profiles of users even if they have been soft deleted. Now here's an extention on this. When should I have it create the profile when the user is created. In the controller or use a model event and put it in there or put it inside the userRepository for creation.

Jeffberry's avatar
create trigger profile_create after insert on users 
for each row
insert into user_profile (user_id) values (new.id)

;) This isn't as useful as the "update" trigger because most likely this should (and would) only happen once in your system, whereas deleting and restoring could theoretically happen an infinite number of times. However, I still suggest it here -- often times developers get too caved into their framework and think everything should and could be done through the framework. Theoretically it can. But you also have all these other tools making your website live (apache, sql, etc.) so why not use each one for what they're actually meant for? Offload your database work to the database.

Where this would also fall short is the fact that it would be inserting a blank profile, whereas if you were to create the profile in the UserRepository along with the user creation, you would have your attributes there to populate the profile with. So, I would suggest the repository method -- whatever you do the idea is just to stay consistent and make sure everything kind of funnels through the same system(s).

Please or to participate in this conversation.