Update user roles in Laravel - php

I have three user roles: Student, Teacher, Admin.
If a user is a student I want to display the option to Elevate them to either Teacher or Admin in a dropdown and the same for the other roles eg. Teacher gets Admin and Student option.
Currently this looks like this:
Index
#if ($user->role == 'admin')
<form action="/admin/users/{{ $user->id }}" method="POST">
#csrf
#method('PATCH')
<input class="hidden" name="role" value="user">
<button>Make User</button>
</form>
#else
<form action="/admin/users/{{ $user->id }}" method="POST">
#csrf
#method('PATCH')
<input class="hidden" name="role"value="teacher">
<button>Make Teacher</button>
</form>
#endif
Controller
public function update(User $user)
{
$attributes = request()->validate([
'role' => ['required', Rule::exists('users', 'role')]
]);
$user->update($attributes);
return back()->with('success', 'User Updated!');
}
How would I be able to do an if statement to list all the roles except for the current role assigned to the user or perhaps this is better done in the controller instead?
And is it possible to put the role in a slug and then run a foreach so I don't repeat code?
Im new top Laravel so any help would be appreciated :)
Thanks

Provide all roles to your page.
Add to User hasRole() method if it does not exists.
Use FormRequest for validation.
Don't forget to get roles with a $user to avoid n+1 queries with User::with('roles')->find($id).
#foreach($allRoles as $role)
#if(! $user->hasRole($role))
Your form
#endif
#endforeach

Related

Laravel 8, how to pass form values to Route

I am doing roles&permissions, an action that admin can change user to staff. I am able to send id to editRolePermission function, but the role value.
function editRolePermission($id, "role value here")
{
$row = DB::table('users')
->where('id',$id)
->limit(1)
->update(array('role' => ''));
return redirect()->back();
}
<form action="{{ route('updateRolePermission', $user->id) }}" method="POST">
#method('PATCH')
#csrf
<select name="roles">
<option name ="user" value="user">User</option>
<option name= "staff" value="staff">Staff</option>
</select>
<input type="submit" onchange="this.form.submit()">
</form>
Route::patch('edit-role-permission/{id}', [AdminController::class, 'editRolePermission'])->name('updateRolePermission');
The following should do what you want. Here is the route - notice I have swapped {id} for {user} - this is the ID of the user we need to edit the role for:
Route::post("/edit-role-permission/{user}", [AdminController::class, "editRolePermission"]);
How to implement the route in your form:
#if(session()->has("message"))
{{ session("message") }}
#endif
<form action="/edit-role-permission/{{ $user->id }}" method="POST">
#csrf
<select name="roles">
<!-- ... options ... -->
</select>
<!-- submit button -->
</form>
Thanks to Laravel magic, passing the user ID as the second parameter allows us to access the user model so we can update the user easily, with a lot less code. We can use the request to get any posted values, in this instance $request->roles refers to the input named roles:
public function editRolePermission(Request $request, \App\Models\User $user)
{
$user->update(["role" => $request->roles]);
$user->save();
return redirect()->back()->with("message", "User role updated successfully");
}

update checkbox value in laravel 8 (blade/ controller )

I'm beginner in laravel and I want to update multiple checkboxes in database ..
when I click at update button automatically my inputs show old value also my permissions are checked by old value to update it ..
relation between user and permission is manytomany .. I have another table named userpermissions who has id_user and id_permission
this is my update form in ( edit.blade.php)
<form action="{{ url('users/'.$user->id) }}" method="POST">
#csrf
#method('PUT')
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Name</label>
<input type="text" name="name" id="name" required class="form-control" value="{{ $user->name }}">
#error('name')
<ul class="alert"><li class="text-danger">{{ $message }}</li></ul>
#enderror
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>Email</label>
<input type="email" name="email" id="email" required class="form-control" value="{{ $user->email }}">
</div>
</div>
<div class="col-md-12">
<div class="form-group">
#foreach($permissions as $permission)
<input type="checkbox" name="data[]" value="{{ $permission->id }}"
<?php if( in_array($permission->id, $user->userPermissions->pluck('permission_id')->toArray())){ echo 'checked="checked"'; } ?>/>
{{ $permission->name }}
#if($loop->iteration % 3 == 0 ) <br> #else #endif
#endforeach
</div>
</div>
</div>
<div class="text-right mt-4">
<button type="submit" class="btn btn-primary"> Add</button>
</div>
</form>
and this is my controller where I think have a problem with methods :
edit function
public function edit(User $user)
{
$permissions = Permission::get();
return view('users.edit', compact('user','permissions'));
}
update function :
public function update(UserRequest $request,User $user)
{
$user->update(
$request->only('name', 'email')
);
$user->userPermissions()->save($request->input('data'));
return redirect()->back()->with('status','user updated !');
}
and this is my functio store :
public function store(UserRequest $request)
{
$this->validate($request, [
'name' => 'required',
'email'=>'required|email',
'password' => 'required|confirmed|min:6',
]);
$user = User::create(
$request->only('name', 'email', 'password')
);
$user->userPermissions()->createMany($request->input('data'));
return redirect()->back()->with('status','Utilisateur ajouté !');
}
Thanks for advance !
$user->userPermissions()->save($request->input('data'));
One important thing to understand here, is that save() on relation doesn't remove old values from pivot table, it just add more values to it(no distinction check). You need something like refresh functionality. Look at attaching\detaching or sync, second one is more convenient.
In first case before saving permissions you can do this
// remove all old permissions
$user->userPermissions()->detach();
// update them with new one
$user->userPermissions()->attach($request->input('data'));
In second case, which is less verbose then first one you just need to pass and array of permissions to user object.
// this will do both things which we did before
$user->userPermissions()->sync($request->input('data'))
But i encourage you to read the docs and ask questions after ;)
Another thing which i saw and its not related to the current topic is
$user->userPermissions->pluck('permission_id')->toArray()
you are using lazy load inside of foreach loop which means that on each iteration of the loop you are making a query to the database(N + 1 problem). You can preload/eager load userPermissions instead of loading them on a fly by declaring with relation in your User model like this
class User extends Model
{
/**
* The relationships that should always be loaded.
*
* #var array
*/
protected $with = ['userPermissions'];
...
}
and then in your User object will have userPermissions property which you can compare to permissions.
Hope that you get main idea and info was useful for you!

Why isn't this Laravel model deleting?

I'm just trying to make a simple form that deletes a model record from the database. I've done it before, but the following code only flashes the success message and redirects. The record never leaves the db.
Here is my form:
#foreach ($users as $user)
<li class="list-group-item {{($loop->iteration % 2 == 0) ? 'even' : 'odd'}}">
<h3>{{$user->first_name}} {{$user->last_name}}</h3>
<b>AccessID: </b> {{$user->id}} <br />
<b>Created: </b> {{$user->updated_at}}
<form action="{{ url('/users/delete', ['id' => $user->id]) }}" method="post">
<input type="hidden" name="_method" value="delete" />
{!! csrf_field() !!}
<button type="submit">Delete</button>
</form>
</li>
#endforeach
Here is my controller method:
public function destroy(User $user)
{
$user->delete();
Session::flash('action', 'Deleted');
Session::flash('status', $user->first_name . $user->last_name .'’s access successfully removed.');
return redirect('/users');
}
Here is my route: Route::delete('/users/delete/{id}', 'UserController#destroy');
The answer was that my route parameter needed to be named user for laravel to recognize that it should expect a user object. I had {id} instead of {user}

Laravel - Edit role user by role_name

I have made an edit page for my users and everything works except changing the role. I have made a select menu which displays all the roles through a foreach loop. And it displays the current role of the user like this:
<div class="form-group row">
<div class="col-md-4">
<label for="Datum">Rol:</label>
</div>
<div class="col-md-8">
<select class="form-control" id="Datum" name="role">
<option selected>{{ $user->role->role_name }}</option>
#foreach($roles as $role)
<option>{{ $role->role_name }}</option>
#endforeach
</select>
</div>
</div>
I want to be able to change the role by the role_name instead of ID. I honestly don't know where to look. How can I achieve this?
The controller that the form goes through looks like this:
public function updateUser(Request $request, $id)
{
$user = User::find($id);
$user->update($request->all());
$user->save();
return back()->with('flash', 'Account is geupdate');
}
In the database, a user has a role_id and in the role table, it has all the roles. So the relations are: User has a Role, Role has many users. These relations are set in the models. So {{ $user->role->role_name }} works just fine.
Thanks in advance!
Assume role_name is unique. In your post method you can do the following-
public function updateUser(Request $request, $id)
{
$role = Role::where('role_name','=',$request->input('role_name'))->first();
$user = User::find($id);
$user->role_id = $role->id;
$user->save();
return back()->with('flash', 'Account is geupdate');
}
As per your comment, add this on your user model-
public function setPasswordAttribute($password)
{
$this->attributes['password'] = bcrypt($password);
}
Hope it helps :)

Laravel 5.4 how to assign roles to user by form request?

i have a users list & here i put a option to assign role to each users, for that when click 'Add Role' link it will show this route
Route::get('admin/home/role/{user}', 'RoleController#create');
in create function my form code is...
<form method="post" action="{{ url('admin/home/role') }}">
{{ csrf_field() }}
<div class="form-group">
<select name="role" class="form-control" >
<option value="1"> Admin </option>
<option value="2"> Editor</option>
</select>
</div>
<button type="submit" class="btn btn-primary">
Add Role
</button>
</form>
to manage this form my POST route is...
Route::post('admin/home/role', 'RoleController#store');
now how to insert this form request data into role_user table? oh! i have already 3 table, users, roles & role_user.
User model relationship code is...
public function role()
{
return $this->belongsToMany(Role::class, 'role_user');
}
Role model relationship code is...
public function user()
{
return $this->belongsToMany(User::class, 'role_user');
}
my question is how to insert form request data into role_user table?
i know one way that is...
public function store(Request $request, User $user)
{
$role = Role::find(1);
$user = User::find(19);
$role->user()->attach($user);
}
it works, but this is not dynamic. How to insert by form request? please help me. I searching about this topic tutorial but not found.
you need to send Role id and user id value to store function
public function store(Request $request)
{
$user_id=$request->input('user_id'); // get user id from post request
$role_id=$request->input('role_id'); // get Role id from post request
/* Todo request validation*/
$user = User::find($user_id);
$role = Role::find($role_id);
$user->roles()->attach($role);
}
view :
<form method="post" action="{{ action('RoleController#store') }}">
{{ csrf_field() }}
<input type="hidden" name="user_id" value="{{ $user->id }}" /> // you need to pass $user to this view
<div class="form-group">
<select name="role_id" class="form-control" >
<option value="1"> Admin </option>
<option value="2"> Editor</option>
</select>
</div>
<button type="submit" class="btn btn-primary">
Add Role
</button>
</form>

Categories