I am working on a Laravel application (Github repo) that requires user registration and login.
After registration, the users can change their registration details (except password, for which there is the default password recovery functionality) and add more info.
They also have the possibility to replace the default avatar image with a picture of their choice
In routes\web.php
I have:
use Illuminate\Support\Facades\Route;
Route::get('/', [App\Http\Controllers\Frontend\HomepageController::class, 'index'])->name('homepage');
Auth::routes();
Route::get('/dashboard', [App\Http\Controllers\Dashboard\DashboardController::class, 'index'])->name('dashboard');
Route::get('/dashboard/profile', [App\Http\Controllers\Dashboard\UserProfileController::class, 'index'])->name('profile');
Route::post('/dashboard/profile/update', [App\Http\Controllers\Dashboard\UserProfileController::class, 'update'])->name('profile.update');
Route::post('/dashboard/profile/deleteavatar/{id}', [App\Http\Controllers\Dashboard\UserProfileController::class, 'deleteavatar'])->name('profile.deleteavatar');
In Controllers\Dashboard\UserProfileController.php
I have:
namespace App\Http\Controllers\Dashboard;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Auth;
use App\Models\UserProfile;
class UserProfileController extends Controller
{
// Guard this route
public function __construct() {
$this->middleware('auth');
}
public function index(UserProfile $user)
{
return view('dashboard.userprofile',
array('current_user' => Auth::user())
);
}
public function update(Request $request)
{
$current_user = Auth::user();
$request->validate([
'first_name' => ['required', 'string', 'max:255'],
'last_name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'max:100', 'unique:users,email,'. $current_user->id],
'avatar' => ['mimes:jpeg, jpg, png, gif', 'max:2048'],
]);
$current_user->first_name = $request->get('first_name');
$current_user->last_name = $request->get('last_name');
$current_user->email = $request->get('email');
$current_user->bio = $request->get('bio');
// Upload avatar
if (isset($request->avatar)) {
$imageName = md5(time()) . '.' . $request->avatar->extension();
$request->avatar->move(public_path('images/avatars'), $imageName);
$current_user->avatar = $imageName;
}
// Update user
$current_user->update();
return redirect('dashboard/profile')
->with('success', 'User data updated successfully');
}
// Delete avatar
public function deleteavatar($id) {
$current_user = Auth::user();
$current_user->avatar = "default.png";
$current_user->save();
}
}
The update profile form:
<form action="{{ route('profile.update') }}" enctype='multipart/form-data' method="post" novalidate>
{{csrf_field()}}
<div class="form-group">
<input type="text" id="first_name" name="first_name" placeholder="First name" class="form-control" value="{{old('first_name', $current_user->first_name)}}">
@if ($errors->has('first_name'))
<span class="errormsg text-danger">{{ $errors->first('first_name') }}</span>
@endif
</div>
<div class="form-group">
<input type="text" id="last_name" name="last_name" placeholder="Last name" class="form-control" value="{{old('last_name', $current_user->last_name)}}">
@if ($errors->has('first_name'))
<span class="errormsg text-danger">{{ $errors->first('last_name') }}</span>
@endif
</div>
<div class="form-group">
<input type="text" id="email" name="email" placeholder="E-mail address" class="form-control" value="{{old('email', $current_user->email)}}">
@if ($errors->has('email'))
<span class="errormsg text-danger">{{ $errors->first('email') }}</span>
@endif
</div>
<div class="form-group">
<textarea name="bio" id="bio" class="form-control" cols="30" rows="6">{{old('bio', $current_user->bio)}}</textarea>
@if ($errors->has('bio'))
<span class="errormsg text-danger">{{ $errors->first('bio') }}</span>
@endif
</div>
<label for="avatar" class="text-muted">Upload avatar</label>
<div class="form-group d-flex">
<div class="w-75 pr-1">
<input type='file' name='avatar' id="avatar" class="form-control border-0 py-0 pl-0 file-upload-btn" value="{{$current_user->avatar}}">
@if ($errors->has('avatar'))
<span class="errormsg text-danger">{{ $errors->first('avatar') }}</span>
@endif
</div>
<div class="w-25 position-relative" id="avatar-container">
<img class="rounded-circle img-thumbnail avatar-preview" src="{{asset('images/avatars')}}/{{$current_user->avatar}}" alt="{{$current_user->first_name}} {{$current_user->first_name}}">
<span class="avatar-trash">
@if($current_user->avatar !== 'default.png')
<a href="#" class="icon text-light" id="delete-avatar" data-uid="{{$current_user->id}}"><i class="fa fa-trash"></i></a>
@endif
</span>
</div>
</div>
<div class="form-group d-flex mb-0">
<div class="w-50 pr-1">
<input type="submit" name="submit" value="Save" class="btn btn-block btn-primary">
</div>
<div class="w-50 pl-1">
<a href="{{route('profile')}}" class="btn btn-block btn-primary">Cancel</a>
</div>
</div>
</form>
The deleting of the user's picture (reverting to the default avatar, in other words, is done via AJAX):
(function() {
//Delete Avatar
$('#delete-avatar').on('click', function(evt) {
evt.preventDefault();
var $avatar = $('#avatar-container').find('img');
var $topAvatar = $('#top_avatar');
var $trashIcon = $(this);
var defaultAvatar = APP_URL + '/images/avatars/default.png';
//Get user's ID
var id = $(this).data('uid');
if (confirm('Delete the avatar?')) {
var CSRF_TOKEN = $('meta[name="csrf-token"]').attr('content');
$.ajax({
url: APP_URL + '/dashboard/profile/deleteavatar/' + id,
method: 'POST',
data: {
id: id,
_token: CSRF_TOKEN,
},
success: function() {
$avatar.attr('src', defaultAvatar);
$topAvatar.attr('src', defaultAvatar);
$trashIcon.remove();
}
});
}
});
})();
Questions:
- Could the code be significantly "shortened"?
- Are there better alternatives to the means I have chosen to do the various "actions" (inserting/updating the avatar and bio, etc)?
- How can this be improved (in any way)?