Laravel 5.1 acl roles and permission in frontend - php

Here is my table structure for permissions, roles, and permission_role
permission:
id
name
roles:
id
name
permission_role:
role_id,
permission_id
Here permission_role is my pivot table.
In my frontend which i have setup something like this,
welcome.blade.php
<form method="POST" action="/give/permission">
{!! csrf_field() !!}
<select name="role" class="selectpicker" multiple data-max-options="2">
#foreach($roles as $r)
<option value="{{$r->id}}">{{$r->name}}</option>
#endforeach
</select>
<div class="checkbox">
#foreach ($perm as $p)
{!! Form::checkbox('p[]', $p->id, in_array($p->id, $all_data)) !!}
{!! Form::label('permisssion', $p->name) !!}<br>
#endforeach
</div>
<button type="submit" class="default">Submit</button>
</form>
in my controller.php
public function postrolperm(Request $request,$id){
$p = Role::find($id);
$role = $request->role;
//dd($input1);
$permission = $request->p;
//dd($input2);
//
//$role = Role::where("name", "admin")->get();
if(isset($permission) && isset($role)){
$role->givePermissionTo($permission);
$role->save();
}
return redirect::back();
}
role.php
public function givePermissionTo(Permission $permission)
{
return $this->permissions()->save($permission);
}
I am not able to save the data into the pivot table.
I have tried in php artisan tinker with following commands:
$role = Role::first(); //which gives me the first role with id of 1
$role->givePermissionTo(Permission::first()); // it will save the first permission to the role.
What i am doing wrong in my controllers ?
Also to note that, that this routes works fine.
Route::get("/pivot", function(){
$permission = new Permission;
$permission->name = "can to";
$permission->save();
$role = new Role;
$role->name = "admin2";
$role->save();
$role->givePermissionTo($permission);
return "true";
});

The reason it isn't working is because you haven't created a Role and Permission object based on the ids passed back from the view. A working example is given below:
$role_id = $request->role;
$permission_ids = $request->p; // This comes back as an array.
if(isset($permission_ids) && isset($role_id)){
$role_object = Role::where('id', $role_id)->firstOrFail();
foreach ($permission_ids as $permission_id) {
// loop through each permission id
// find the corresponding permission object in the database
$permission_object = Permission::where('id', $permission_id)->firstOrFail();
// assign the object to the role
$role_object->givePermissionTo($permission_object);
}
$role_object->save();
}
return Redirect::back()
Note that this will throw an exception if the role and permission passed back from the view don't correspond to a valid id in the database. Usefirst() instead of firstOrFail() if you want failures to be silent, i.e. not thrown an exception.
Make sure to add use App\Role; and use App\Permission to the top of your Controller file.
Your version fails due to the fact that you are trying to call the givePermissionTo function on a string representing the role id passed from the view - $role. You missed the step in between of getting the Role object from the database.
Curiously, you were on the right track with your $p variable, however you also needed to grab the corresponding $permission object from the database as shown in my example.

Did you added
use App\Role;
in controller.php file?

Related

Laravel 8 Register user while logged in

I have two tables with users, one for public users and one for workers. The workers can only be created by other workers, but when I go to the workers registration url, it detects that I am logged in and redirects me to home, how can I change this behavior?
I have tried commenting out part of the handle function in the RedirectIfAuthenticated.php file but this causes users to be able to visit the login links while logged in.
Function I commented in RedirectIfAuthenticated.php:
public function handle(Request $request, Closure $next, ...$guards)
{
$guards = empty($guards) ? [null] : $guards;
// foreach ($guards as $guard) {
// if (Auth::guard($guard)->check()) {
// return redirect(RouteServiceProvider::HOME);
// }
// }
return $next($request);
}
In your users table, define a field which will allow you to diferentiate between types of user.
$table->string('type')->default('public');
I've defined a field of data type string and given the field a default value of public. There are other ways you could do this such as making the data type an integer and using a lookup table, but lets keep things simple for now and to be honest it really doesn't matter.
The type will then be accessible on your user objects; $user->type.
To get the type for the currently authenticated user, you would use either auth()->user()->type or Auth::user()->type (doesn't matter which, same result).
Based on the value of type you would allow or deny access to something. In your case you want to deny users that are not of type worker from creating users of type worker.
Don't reuse the register form to create new users, create yourself a new scaffold (route, controller, view etc.) for this task. A basic of example of what this could look like below.
routes/web.php
Route::group(['prefix' => 'admin', 'as' => 'admin.'], function () {
Route::resource('users', \App\Http\Controllers\UserController::class);
});
resources/views/users/create.blade.php
#if ($errors->any())
#foreach ($errors->all() as $error)
{{ $error }}
#endforeach
#endif
<form action="{{ route('admin.users.store') }}" method="post">
#csrf
{{--
If the authenticated user is of type public
you can choose to either hide the option for choosing a user type
--}}
#if (auth()->user()->type != 'public')
<select name="type" id="type">
<option value="public">Public</option>
<option value="worker">Worker</option>
</select>
#endif
{{--
Or you can simply disable it
--}}
<select name="type" id="type" #if (auth()->user()->type == 'public') disabled #endif>
<option value="public">Public</option>
<option value="worker">Worker</option>
</select>
</form>
app/Http/Controllers/UserController.php
class UserController extends Controller
{
public function __construct()
{
$this->middleware(['auth']);
}
public function create()
{
return view('users.create');
}
public function store(Request $request)
{
// perform some validation on the data coming in
// the value of the type field should be either public or worker
// other values should cause an error
$validator = Validator::make($request->all(), [
'type' => ['in:public,worker']
]);
// an additional check to prevent non workers creating worker users
// this could be extracted to a custom validation rule
if (auth()->user()->type != 'worker' && $request->type == 'worker') {
return redirect(route('admin.users.create')
->withErrors([
'unauthorised' =>
'You do not have authorisation to create users of type Worker'
)]
->withInput();
}
// Don't forget to add 'type' to the $fillable array on your user model
User::create($validator->validated());
return redirect(route('users.admin.create')->with(['success' => 'User created!')];
}
}
The above is a very basic implementation to point you in the right direction. You could extract the functionality for checking if a user is a worker into a middleware, create gates and custom validation rules to make things more reusable.

How do delete single row in pivot table with laravel

I want to delete a single row of data in my pivot table. I don't get any error but when try to click on the button. It did not redirect me to anywhere so the delete function is not performed.
In the picture above I want to delete the highlighted id for user_id = 3
My scenario is that the user suddenly can't make it to even_id = 6 so the user wants to delete/unjoined the event.
route
Route::get('/user/event/{event}', 'HomeController#destroy')->name('user.event.destroy');
blade
#foreach ($events as $event)
<tr>
<td>{{$loop->index +1 }}</td>
<td>{{$event->event_name}}</td>
<td>{{$event->event_date}}</td>
<td>
<form method="POST" action="{{ route('user.event.destroy',$event)}}">
#csrf
#method('DELETE')
<a class="btn btn-danger">Unjoined!</a>
</form>
</td>
</tr>
#endforeach
controller
public function storeEventUser(Request $request)
{
$user = User::find(Auth::user()->id);
//how I storing my pivot data (just to show if anyone asking)
$user->events()->syncWithoutDetaching([$request->event_id]);
}
public function destroy($event)
{
$event= Event::findOrFail($event_id);
$user->events()->detach($event);
return redirect()->back()->with('success','Deleted.');
}
Event model
public function users()
{
return $this->belongsToMany(User::class,'event_user','event_id','user_id');
}
user model
public function events()
{
return $this->belongsToMany(Event::class,'event_user','user_id','event_id');
}
I am adjusting your controller method to use Route Model Binding for simplicity:
public function destroy(Event $event)
{
Auth::user()->events()->detach($event);
// or from the other side of the relationship
// $event->users()->detach(Auth::user());
return redirect()->back()->with('success', 'Deleted.');
}
As stated in the comments you need to adjust your route to Route::delete if you want to use the DELETE HTTP method that your form is spoofing via the #method('DELETE') blade directive.
Side note:
Auth::user() returns a User instance so you don't need to query for it again, in your storeEventUser method:
$user = Auth::user();

How may I put a $_POST data into a database table?

It's been 3 weeks since I've started to learn symfony 4. I am trying to put the chosen data from the dropdown list into a database but I am not using a Form builder - the data is entered in html/twig and then stored into a variable $value.
I am wondering, though, how can I put this data from the variable $value into a database of choice (table User)? I mean, (if understood it right) when I use the form builder I am supposed to use ObjectManager $manager as following:
$manager->persist($value);
$manager->flush();
In this case I, honestly, have no idea of how I can put my data into a database.
Can anyone give me a clue?
twig
<select name="user">
{% for user in users %}
<option value="{{ user.idUser }},{{ user.name }}" label="{{ user.name }} {{ user.surname }}">{{ user.name }} {{ user.surname }}</option>
{% endfor %}
</select>
<button type="submit" id="article_form_save" name="article_form[save]">ADD</button>
controller
/**
* #Route("/attribution", name="attribution")
*/
public function create (Request $request) {
$users = $this
->getDoctrine()
->getRepository(User::class)
->findAll();
$value = $_POST;
dump($value);
return $this->render('database/Roles/attrib.html.twig', [
'users' => $users
]);
You can access your dropdown data from $_POST['user'] or you can use $request->request->get('user')
In order to save data into the database, you can create an object (Post for example) where you set the values you are retrieving from the request and then saving them.
You can do something like this:
<?php
/**
* #Route("/attribution", name="attribution")
*/
public function create (Request $request) {
$users = $this
->getDoctrine()
->getRepository(User::class)
->findAll();
$user = $request->request->get('user');
$manager = $this->getDoctrine()->getManager();
$post = new Post();
$post->setUser($user); // I suppose the user property in your post is just an integer not an object
$manager->persist($post);
$manager->flush();
dump($user);
return $this->render('database/Roles/attrib.html.twig', [
'users' => $users
]);
?>
This is just an example, which you can adapt it to your needs.
Your value should have only the user id. Change
<option value="{{ user.idUser }},{{ user.name }}"
to
<option value="{{ user.idUser }}"
Then, you can get the user like this:
$userId = $request->request->get('user'); //this will not be a user entity, but only an id
Which will return the user id.
Then you need to retrieve the user via your repository and save it.
Inject your user repository and entity manager by type-hinting them in your function arguments:
public function create (Request $request, UserRepository $repository, EntityManagerInterface $entityManager) {
do a findOneBy:
$user = $repository->findOneBy(['id' => $userId]);
Set the user to the article and save it
$article.setUser($user);
$entityManager->persist($article);
$entityManager->flush();
PS: using Symfony forms would make it waaay simpler.

How do I fetch data based on user id using Laravel 5.4

I have models User and Diares set up with the hasMany and BelongTo relstionship. I'm trying to fetch data from the Diaries table associated with a particular user. I tried auth but it didnt work for me. How can i achieve that and display it in the blade view as well. Here is my current code:
public function index(User $id)
{
$user = User::find($id);
$record = $user->diary;
return view('home')->with('record', $record);
}
The blade file it should display to:
#foreach ($record as $diary)
{{ $diary->error }}
{{ $diary->fix }}
#endforeach
In your index function the $id is not integer - this is a User instance, so you can try use this:
public function index(User $user)
{
$record = $user->diary;
return view('home')->with('record', $record);
}

How to pass variable from foreach to view?

I'm trying to pass a variable from foreach to my view. So I can access this using in my select form. Because I have two tables M:M relationship between departments and user. I need to get all the department_name where the user_id belong. For me able to send a data via department_name Here what I did please take a look.
DB Diagram:
department_user
As you can see here user_id is the id of the user and document_id is where the users belong.
Model:
Department:
public function users()
{
return $this->belongsToMany('\App\Models\User', 'department_user');
}
User:
public function departments()
{
return $this->belongsToMany('App\Models\Department', 'department_user');
}
Controller:
public function getDocuments()
{
$departmentRecipient = DB::table('departments')->get();
foreach ($departmentRecipient as $department)
{
$department->users = DB::table('department_user')
->where('department_id', '=', $department->id)
->pluck('user_id');
}
return view('document.create')->with('department', $department);
}
I'm getting all the users_id when I die and dump my variable departmentRecipient.
View:
<div class = "form-group">
<label for = "recipient" class = "control-label">Recipient:</label>
<select name = "recipient[]" multiple class = "form-control select2-multi" id = "myUserList">
#foreach ($department as $list)
<option value = "{{ $list->user_id }}">{{ $list->department_name }}</option>
#endforeach
</select>
</div>
I wanted to foreach the $department in my Controller to my select form. But it always says.
Trying to get property of non-object (View: C:\Users\JohnFrancis\LaravelFrancis\resources\views\document\create.blade.php)
Goal:
Use the following loop to iterate through the department users and add them to pivot table.
foreach($request->department as $departmentId)
{
foreach(Department::find($departmentId->id)->users()->get() as $user1) //find the users belonging to the current department
{
$document->sentToUsers()->sync([ $user1->id => ['sender_id' => $user->id]],false );
}
}
Also remove the following code form your getDocuments() as it is redundant:
foreach ($departmentRecipient as $department)
{
$department->users = DB::table('department_user')
->where('department_id', '=', $department->id)
->pluck('user_id');
}
I don't see user_id property in your dumped value of $departmentRecipient object, that is why you are getting the error you mentioned. However, there is a users array inside of $departmentRecipient object, which you made inside your foreach loop. You are plucking every user_id which are in individual department and setting in a property named users of $departmentRecipient object, and so you are getting an array inside users property. Here I have a solution for you,
public function getDocuments()
{
$departmentRecipient = DB::table('departments')->get();
$departmentUsers = array();
foreach ($departmentRecipient as $department)
{
$users = DB::table('department_user')
->where('department_id', '=', $department->id)
->pluck('user_id');
foreach ($users as $userId) {
$departmentUsers[$userId] = $department->department_name;
}
}
return view('document.create')->with('department', $department)->with('departmentUsers', $departmentUsers);
}
and inside of your view loop through the variable $departmentUsers, like this,
#foreach ($departmentUsers as $userId => $departmentName)
<option value = "{{ $userId }}">{{ $departmentName }}</option>
#endforeach
This will work but as your department contains multiple users so you will get individual department name multiple time in your select2 dropdown. If you share more of what is your goal by select2 then may be I can help you to solve your problem in other way.
Moreover if you are interested to use of Eloquent then you can get rid of lots of foreach looping.
In your case you can have multiple users against each department. So to make it work correctly with your forearch code. You need to make sure you are getting one user record against each depart. So modify following line of code in controller.
$department->users = DB::table('department_user')->where('department_id', '=', $department->id)->pluck('user_id');
But you want to display all users of department then you have to change foreach loop code into view.
Try This Code
App/Department
public function users()
{
return $this->belongsToMany('App\Entities\User', 'department_user', 'user_id', 'department_id');
}
App/User
public function departments()
{
return $this->belongsToMany('App\Models\Department', 'department_user');
}
Controller
use App/User;
public function getDocuments($userId,User $User)
{
$getSpecificUser = $User->with('departments')->find($userid);
return view('document.create')->compact('getSpecificUser');
}
View
#foreach ($getSpecificUser as $getUser)
#if(empty($getUser->departments) === false)
#foreach ($getUser->departments as $departments)
<option value = "{{ $getUser->id }}">{{ $departments->department_name }}</option>
#endforeach
#endif
#endforeach

Categories