I am trying to update a user’s avatar, however I keep getting the error “The Avatar must be an image”. But the update function on other part of the profile works like name email, etc..
I am really confuse on why it is not working? Any help would be highly appricated…
I am currently using livewire/livewire version 3.4, php version 8.2 and laravel/framework version 11.9, I have also did php artisan storage:link.
My code is bellow.
<?php
namespace AppLivewire;
use LivewireComponent;
use LivewireWithFileUploads;
use AppModelsUser;
use IlluminateSupportFacadesAuth;
use IlluminateSupportFacadesHash;
class Users extends Component
{
use WithFileUploads;
public $users, $name, $email,
$role, $avatar, $user_id,
$currentAvatar = null;
public $isOpen = false;
public function render()
{
$this->users = User::all();
return view('livewire.user', ['users' => User::all()])
->extends('layouts.app')
->section('content');
}
public function create()
{
$this->resetInputFields();
$this->isOpen = !$this->isOpen;
session()->flash('message', 'Create method triggered');
}
public function openModal()
{
$this->isOpen = true;
}
public function closeModal()
{
$this->isOpen = false;
}
private function resetInputFields()
{
$this->user_id = null;
$this->name = '';
$this->email = '';
$this->role = 'student'; // Default role
$this->avatar = null;
}
public function store()
{
$this->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email,' . $this->user_id,
'role' => 'required|in:admin,lecturer,student',
'avatar' => 'nullable|image|mimes:jpeg,jpg,png,gif|max:1024',
]);
$validatedData = [
'name' => $this->name,
'email' => $this->email,
'role' => $this->role,
];
// Handle avatar upload(store file and save path)
if ($this->avatar) {
// Get file extension
$extension = $this->avatar->getClientOriginalExtension();
// Generate unique filename
$filename = 'avatar-' . time() . '.' . $extension;
// Store file publicly with custom filename
$validatedData['avatar'] = $this->avatar->storePubliclyAs(path: 'avatars', name: $filename, disk: 'public');
}
// Using updateOrCreate to insert or update the user
User::updateOrCreate(
['id' => $this->user_id],
array_merge($validatedData, [
'password' => $this->user_id
? User::find($this->user_id)->password
: Hash::make('password'), // Default password for new users
])
);
session()->flash('message', $this->user_id ? 'User Updated Successfully.' : 'User created successfully.');
$this->closeModal();
$this->resetInputFields();
}
public function edit($id)
{
$user = User::findOrFail($id);
$this->user_id = $id;
$this->name = $user->name;
$this->email = $user->email;
$this->role = $user->role;
$this->currentAvatar = $user->avatar;
$this->openModal();
session()->flash('message', 'Edit method triggered');
}
}
And part of the blade file, please note in my app.blade.php I have @livewireScripts in the body and @livewireStyle in head:
<div>
<!-- Check if a new avatar file is uploaded and show its preview -->
@if (!empty($currentAvatar))
<img src="{{ Storage::url($currentAvatar) }}" class="mt-2" width="100" alt="Current Avatar" />
<!-- If no avatar is uploaded or stored, show upload input and "No avatar uploaded" message -->
@else
<p>No avatar uploaded</p>
@endif
<!-- Input field for uploading an avatar -->
<x-input-label for="avatar" :value="__('Avatar')" />
<input wire:model.live="avatar" id="avatar" name="avatar" type="file" accept="image/*" class="mt-1 block w-full" />
<x-input-error class="mt-2" :messages="$errors->get('avatar')" />
</div>
Don’t know if this helps, my schema for users:
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->enum('role', ['admin', 'lecturer', 'student'])->default('student');
$table->string('avatar')->nullable();
$table->rememberToken();
$table->timestamps();
});
Also, here’s my configuration:
'disks' => [
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
'throw' => false,
],
],
I have changed from the validation from ‘avatar’ => ‘nullable|image|max:1024’, to above to accept what I was trying to test (a .png with size 5.44 KB)
Originally, I didn’t have $validatedData or array_merge as shown below:
User::updateOrCreate(['id' => $this->userId], [
'name' => $this->name,
'email' => $this->email,
'role' => $this->role,
'avatar' => $this->avatar ? $this->avatar->store('avatars') : null,
]);
and in edit function was $this->avatar = $user->avatar;
I discovered that the follwing was still not working and displayed “The avatar field must be an image.” Despire update to above, it was still somehow stored in storage/app/private/livewire-tmp with random name CXZNomzyXgBbPLlHwQQNdXbZypmQ4y-metaTmV0U2F2dnkgTG9nbyAxIHcgZ3JhZGllbnQucG5n-.png instead of app/public with filenmae like avatar-1699458603.jpg
if ($this->avatar) {
$validatedData['avatar'] = $this->avatar->store('avatars', 'public');
}
A_C is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.