Hello!
I'm in practice mode with Laravel, and I've tried this at least 80 different ways, based on the number of ids in the db.
I have 3 tables: Users, Images, and Posts. Both Users and Posts share a polymorphic relationship with Images. For now, I'm only working with Users and Images which have a one to one polymorphic relationship. One user can have one image.
What I want to achieve
When someone updates their profile with a new image (with a unique name), I want their old image to be deleted from both the database and folder (public, not storage) in order for the new one to take its place.
What I managed to achieve
I managed to get the image deleted from the folder, but not from the database as well.
Therefore, whenever I update a profile, an additional record is added in the images table, without deleting the old one, and the user's initially added image gets picked from the table.
User Model:
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'role_id', 'name', 'email', 'password'
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function role()
{
return $this->belongsTo('App\Role');
}
public function image()
{
return $this->morphOne('App\Image', 'imageable');
}
}
Image Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Image extends Model
{
protected $fillable = ['imageable_id', 'imageable_type', 'url'];
protected $uploads = '/images/';
public function getUrlAttribute($image)
{
return $this->uploads . $image;
}
public function imageable()
{
return $this->morphTo();
}
}
User Controller:
public function store(UserCreateRequest $request)
{
$input = $request->all();
$input['password'] = bcrypt($request->password);
$user = User::create($input);
if ($image = $request->file('imageable_id')) {
$name = uniqid() . $image->getClientOriginalName();
$image->move('images', $name);
$image = Image::create(['url'=>$name]);
$input['imageable_id'] = $user->id;
}
$user->image()->save($image);
return redirect('/admin/users')->with('success', 'The user has been created');
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
$user = User::findOrFail($id);
$roles = Role::RolePluck()->all();
return view('admin.users.edit', compact('user', 'roles'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(UsersEditRequest $request, $id)
{
$user = User::findOrFail($id);
$input = $request->all();
$input['password'] = bcrypt($request->password);
if ($image = $request->file('imageable_id')) {
$userImage = public_path() . $user->image->url;
if (File::exists($userImage)) {
unlink($userImage);
}
$name = uniqid() . $image->getClientOriginalName();
$image->move('images', $name);
$image = Image::create(['url'=>$name]);
$input['imageable_id'] = $user->id;
$user->image()->save($image);
}
$user->update($input);
return redirect('/admin/users')->with('success', 'The profile has been updated');
}
This is the code that removes the image from the public 'images' folder. I can't figure out how to delete it from the database as well.
Users Migration:
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('role_id')->index()->unsigned()->nullable();
$table->string('name')->unique()->nullable();
$table->string('email')->nullable();
$table->timestamp('email_verified_at')->nullable();
$table->string('password')->nullable();
$table->rememberToken();
$table->timestamps();
});
Images Migration:
Schema::create('images', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('imageable_id')->nullable()->unsigned();
$table->string('imageable_type')->nullable();
$table->string('url')->nullable();
$table->timestamps();
$table->foreign('imageable_id')->references('id')->on('users')->onDelete('cascade');
});
The form in the view
<div class="form-group">
<label for="exampleFormControlFile1">Add avatar</label>
<input type="file" class="form-control-file" id="exampleFormControlFile1" name="imageable_id">
</div>
I hope I was comprehensive enough.
Let me know if you need more info.
Thank you!
I managed to find the solution.
In case someone else has this issue, the solution is this:
if (File::exists($userImage)) {
unlink($userImage);
Image::where('imageable_type', 'App\User')->where('imageable_id', $user->id)->delete();
}
Sign in to participate in this thread!
The Laravel portal for problem solving, knowledge sharing and community building.
The community