Error when I try to edit user - laravel

I am using Laravel 5.4.18. I am getting this error when I try to edit user
Missing argument 2 for App\Http\Controllers\UsersController::edit()
Here is what I did
https://paste.laravel.io/Pyw5M#18

Change this:
public function edit(User $user, $id)
{
$user = $user->find($id);
return view('admin/users/edit', compact('user'));
}
To this:
public function edit(User $user)
{
return view('admin/users/edit', compact('user'));
}
When you define (User $user) laravel auto-injects the user model, so no need to find the model again based on the id.
In this case i expect your route to look like this:
Route::get('users/{user}/edit', UserController#edit)
Or you can use resource controllers so this is handled for you:
https://laravel.com/docs/5.4/controllers#resource-controllers

Related

Laravel authorization policy not working on Show page

I have a laravel app using Policies to assign roles and permissions, i cant seem to access the show page and im not sure what im doing wrong?
If i set return true it still shows a 403 error as well, so im unsure where im going wrong here. The index page is accessable but the show page is not?
UserPolicy
public function viewAny(User $user)
{
if ($user->isSuperAdmin() || $user->hasPermissionTo(44, 'web')) {
return true;
}
return false;
}
public function view(User $user, User $model)
{
if ($user->isSuperAdmin() || $user->hasPermissionTo(44, 'web')) {
return true;
}
return false;
}
UserController
public function __construct()
{
$this->authorizeResource(User::class, 'user');
}
public function index()
{
$page_title = 'Users';
$page_description = 'User Profiles';
$users = User::all();
return view('pages.users.users.index', compact('page_title', 'page_description', 'users'));
}
public function create()
{
//
}
public function store(Request $request)
{
//
}
public function show($id)
{
$user = User::findOrFail($id);
$user_roles = $user->getRoleNames()->toArray();
return view('pages.users.users.show', compact('user', 'user_roles'));
}
Base on Authorize Resource and Resource Controller documentation.
You should run php artisan make:policy UserPolicy --model=User. This allows the policy to navigate within the model.
When you use the authorizeResource() function you should implement your condition in the middleware like:
// For Index
Route::get('/users', [UserController::class, 'index'])->middleware('can:viewAny,user');
// For View
Route::get('/users/{user}', [UserController::class, 'view'])->middleware('can:view,user');
or you can also use one policy for both view and index on your controller.
I had an issue with authorizeResource function.
I stuck on failed auth policy error:
This action is unauthorized.
The problem was that I named controller resource/request param with different name than its model class name.
F. ex. my model class name is Acknowledge , but I named param as timelineAcknowledge
Laravel writes in its documentation that
The authorizeResource method accepts the model's class name as its first argument, and the name of the route / request parameter that will contain the model's ID as its second argument
So the second argument had to be request parameter name.
// Here request param name is timelineAcknowledge
public function show(Acknowledge $timelineAcknowledge)
{
return $timelineAcknowledge->toArray();
}
// So I used this naming here also
public function __construct()
{
$this->authorizeResource(Acknowledge::class, 'timelineAcknowledge');
}
Solution was to name request param to the same name as its model class name.
Fixed code example
// I changed param name to the same as its model name
public function show(Acknowledge $acknowledge)
{
return $acknowledge->toArray();
}
// Changed here also
public function __construct()
{
$this->authorizeResource(Acknowledge::class, 'acknowledge');
}
I looked over Laravel policy auth code and I saw that the code actually expects the name to be as the model class name, but I couldn't find it anywhere mentioned in Laravel docs.
Of course in most of the cases request param name is the same as model class name, but I had a different case.
Hope it might help for someone.

Reuse user resource route for current user

I've created a resource route for users.
Route::resource('users', 'UsersController');
My controller handles the path /user/1/edit with in my users controller like so:
public function edit(User $user)
{
$this->authorize('update', $user);
...
The template for this page is: resources/views/users/edit.blade.php.
How would I define a new route, /user/edit, which dynamically passes the current user and reuses the edit(User $user) method while also reusing the same view template?
Your edit() method will need to change to conditionally accept the User model. You then need to check if $user was passed, else assume current user is required:
public function edit(User $user = null)
{
$user = $user ?: auth()->user();
$this->authorize('update', $user);
...
And create the new route:
Route::get('user/edit', 'UsersController#edit')
Try this:
Route::get('users/{user}/edit', 'UserController#edit')->name(edit-user);
Then, pass in the user id in route like this:
route('edit-user', ['user'=>$user->id]);
I hope this helps you.

Adding custom where clause to AuthenticatesUser Trait Laravel

We have decided to use Laravel for a project as a test run for future frameworks and are really enjoying it. There is one issue we are having though.
We use the trait Illuminate\Foundation\Auth\AuthenticatesUsers which handles user authentication. It works well. However, we have a column in the database called userstatus which could be a 0 or a 1.
How do we inject this where clause into the Illuminate\Foundation\Auth\AuthenticatesUsers trait?
I was thinking maybe something here (in my LoginController):
public function authenticated($request , $user){
//if $user->userstatus != 1 logout and redirect to start page
}
But I dont know how to logout (im looking into that now) .
your logic is right, you should redefine login and authenticated methods within LoginController.
your methods should be like below:
this method should be within your LoginController.php:
class LoginController extends Controller
{
use AuthenticatesUsers {
login as public loginParent;
}
protected function login(Request $request){
$default = '/';
$user = User::where('email', $request->get('email'))->NotActive->first();
if($user){
return redirect()->intended($default);
}
return $this->loginParent($request);
}
protected function authenticated(Request $request, $user)
{
if($user->not_active) {
$this->logout($request);
}
}
}
then we should create ScopeNotActive method within User.php Model as Local Scope:
//User.php
public function ScopeNotActive($query){
return $query->where('userStatus', '!=', 1);
}
and a Mutator to check if the user is not active:
// User.php
public function getNotActiveAttribute(){
return $this->userStatus != 1;
}

Update data by $id, i want to use Another Model object as controller functions parameter's and rename that parameter In Laravel

I send $user->id from blade file to UserInformationController (User and UserInfromation are two different models)
and my UserInformationController function is here:
public function update(Request $request, User $id)
{
echo $id->id ;
// it's working
}
But I want this kind of format:
public function update(Request $request, User $user)
{
echo $user->id ;
// it's not working
}
I got my ans:
It should be match with route parameter filed
previously my function parameter didn't match with route parameter.
You can use
$user
without
$user->id
because it already return the id you want to update.
Or better just use
public function update(Request $request, $id)
{
return $id;
}
It will work.
public function update(Request $request, User $user)
{
echo $user->id ;
// its not working
}
Make sure the variable you are type-hinting in your function matches the one you left in your route.
Route::post('/update/{user}', ...)
Then you can now use $user

Laravel show() parameter are null

I am using Laravel version 5.6.26. My show() parameter get null value. Why? and how to solve it? Thank you
web.php
Route::get('/peoples', 'UsersController#index')->name('peoples');
Route::get('/peoples/{id?}', 'UsersController#show');
UserController.php
public function show(User $user)
{
$user = User::where('id', $user->id)->first();
//$user = User::find($user->id)->first();
return dd($user);
//return view('profile',['user' => $user]);
}
user.blade.php when I click <a href="/peoples/{{$user->id}}" > , it show null
<h4><a href="/peoples/{{$user->id}}" > {{$user->name}}</a></h4>
result
https://imgur.com/QlaiFse
But if i do like this,I can get the value
public function show(User $user)
{
$user = User::where('id',1)->first();
//$user = User::find($user->id)->first();
return dd($user);
//return view('profile',['user' => $user]);
}
The way you defined your show method i.e. show(User $user) is called route model binding if your variable name ($user) is similar to your route declaration. But your route declaration is /peoples/{id?} so the User instance is not created in your controller. So just rename the route declaration as /peoples/{user?}.
The use case of route model binding is you don't want to query/load the model related to a route parameter. So if you define the route the way I've mentioned you won't need the $user = User::where('id', $user->id)->first(); query. Because Laravel will automatically instantiate that $user with the User model of id passed in the route.
If you want to query/load the User model manually then keep your existing route declaration as it is. And change your controller method declaration as show($id = null)
You are injecting the User model in your controller, but not accessing the route path. If you want to access the {id} which set in the route, you have to access that in your controller too.
So your UserController will be something like
public function show(User $user, $id)
{
$user = User::where('id', $id)->first();
dd($user);
}
When you type hinted in your controller's method show() with User, Laravel will automatically inject that using Service Container.
Your UserController.php's code should be:
public function show(User $user) {
// no need to fetch user again. Laravel had already done that for you.
dd($user);
return view('profile', compact('user'));
}

Resources