Why Is Laravel Giving Me This Error, and How Do I Fix it? Argument #2 ($post) must be of type App\Models\Post, App\Models\User given - php

I am trying to use a Gate to see if the currently authenticated user matches the user_id column of the "posts" table.
However, when attempting to use the Gate inside my controller, it is giving me the following error, and I am at a loss.
App\Providers\AuthServiceProvider::App\Providers\{closure}(): Argument #2 ($post) must be of type App\Models\Post, App\Models\User given, called in [path]\vendor\laravel\framework\src\Illuminate\Auth\Access\Gate.php on line 535
Thanks.
My Controller:
class updatePost extends Controller
{
public function updatePost(Request $request, Post $post) {
if (Gate::allows('updatePost', auth()->user(), $post)) {
$post->title = $request->input('title');
$post->body = $request->input('body');
$post->save();
return redirect()->route('readPost', ['id' => $post->id]);
} else {
echo 'ERROR';
}
}
}
My Gate:
Gate::define('updatePost', function (User $user, Post $post) {
return $user->id === $post->user_id;
});

The define callback always receives the logged in user as first parameter followed but the parameters given by allows().
Try this
if (Gate::allows('updatePost', $post)) {
// your code
}

Related

Laravel - HTTP Session Flash Data dont work

The Laravel documentation:
Sometimes you may wish to store items in the session for the next request. You may do so using the flash method.
$request->session()->flash('status', 'Task was successful!');
my code:
public function store(StorePost $request)
{
$validated = $request->validate();
$post = new Posts();
$post->title = $validated['title'];
$post->content = $validated['content'];
$post->save();
$request->session()->flash('status', 'Task was successful!');
return redirect()->route('posts.show', [$post->id]);
}
and my IDE vscode throw error looks like this:
error in flash
Some help in this error ?
have you include the following namespace
use Session;
if not use 'Session' namespace
you can also try another way
public function store(StorePost $request)
{
$validated = $request->validate();
$post = new Posts();
$post->title = $validated['title'];
$post->content = $validated['content'];
$post->save();
return redirect()->route('posts.show', [$post->id])->with('status','Task was successful!');
}
it will create a RedirectResponse instance and flash data to the session in a single, fluent method
A few things to fix your issue and clean things up a tad. The Laravel convention for naming models is to use the singular name of the table. If you have a table named posts, the model's name should be Post. Second, you don't need a temporary variable for the the validated data, just inline it. Finally, you can use with on your redirect to flash your session data:
public function store(StorePost $request)
{
$post = Posts::create([
'title' => $request->validated('title'),
'content' => $request->validated('content')
]);
return redirect()->route('posts.show', $post)
->with('status', 'Task was successful!');
}

Undefined variable $user->username (Laravel 5.7)

I can't get the data from the database. Getting an error:
ErrorException (E_ERROR)
Undefined variable: user
(View:/Users/alex/Desktop/sites/tj/resources/views/user/submissions.blade.php)
Controller:
public function __construct()
{
$this->middleware('auth', ['except' => ['getById',
'getByUsername', 'submissions', 'comments', 'showSubmissions',
'showComments']]);
}
and
public function showSubmissions($username)
{
$user = new UserResource(
User::withTrashed()->where('username', $username)->firstOrFail(),
true
);
$submissions = SubmissionResource::collection(
Submission::whereUserId($user->id)
->withTrashed()
->orderBy('created_at', 'desc')
->simplePaginate(15)
);
return view('user.submissions', compact('user', 'submissions'));
}
View:
{{ $user->username }}
API:
Route::get('/user', 'UserController#getByUsername');
I need get information about user (username).
What is the problem and where is the error?
Based on your comment you have this route:
Route::get('/submission', function () {
return view('user.submissions');
});
When you are loading this view, you are not passing the user object to it. Then when the view is running, it is trying to access a variable that does not exist.
To fix this, you need to pass a variable to the view you are loading. For example, you could do something like this:
Route::get('/submission', function () {
return view('user.submissions', ['user' => auth()->user()]);
});
Note that you can change how you get the user instance depending on your use case. I am just getting the authenticated user to demonstrate the principle.

Type error: Argument 2 passed to Controller::show() must be an instance of modal, string given

Adding up and down voting functions to a classified page. Using Laravel, and Vue.
The error I get is:
(1/1) FatalThrowableError
Type error: Argument 2 passed to Hustla\Http\Controllers\ListingVoteController::show() must be an instance of Hustla\Listing, string given
I have included the vue file, the vote controller, the listing model, and the route. I was hoping someone could help me out.
Listing Model
public function votesAllowed()
{
return (bool) $this->allow_votes;
}
public function commentsAllowed()
{
return (bool) $this->allow_comments;
}
public function votes()
{
return $this->morphMany(Vote::class, 'voteable');
}
public function upVotes()
{
return $this->votes()->where('type', 'up');
}
public function downVotes()
{
return $this->votes()->where('type', 'down');
}
public function voteFromUser(User $user)
{
return $this->votes()->where('user_id', $user->id);
}
Vote Controller
public function show(Request $request, Listing $listing)
{
$response = [
'up' => null,
'down' => null,
'can_vote' => $listing->votesAllowed(),
'user_vote' => null,
];
if ($listing->votesAllowed()) {
$response['up'] = $listing->upVotes()->count();
$response['down'] = $listing->downVotes()->count();
}
if ($request->user()) {
$voteFromUser = $listing->voteFromUser($request->user())->first();
$response['user_vote'] = $voteFromUser ? $voteFromUser->type : null;
}
return response()->json([
'data' => $response
], 200);
}
Vote.vue
<template>
<div class="listing__voting">
<a href="#" class="listing__voting-button">
<span class="glyphicon glyphicon-thumbs-up"></span>
</a> 1
<a href="#" class="listing__voting-button">
<span class="glyphicon glyphicon-thumbs-down"></span>
</a> 2
</div>
</template>
<script>
export default {
data () {
return {
up: null,
down: null,
userVote: null,
canVote: false
}
},
props:{
listingId: null
}
}
</script>
Route
Route::get('/{location}/{listing}/votes',[
'uses' => '\Hustla\Http\Controllers\ListingVoteController#show'
]);
Your route definition has two parameters defined: {location} and {listing}. The parameters are passed to the controller method in the order in which they are defined.
Your controller method, however, is only defined to accept one route parameter. The first route parameter is what will be passed to the method, and in this route definition, that is the {location} parameter. Since {location} does not match $listing, the string value will be passed in, and you'll get the error you're seeing.
You need to add the second route parameter to your controller action:
public function show(Request $request, $location, Listing $listing)
{
// code
}
If $location is a model as well, you can go ahead and add the type hint to enable the implicit route model binding.

Lumen Authorization - Call to a member function parameter() on array

Trying to authorize a user to update a post if the user id and the post user_id matches. I have a custom callback for authorization in the AuthServiceProvider which checks for 'Authorization' header, which is an API key in the boot() function.
$this->app['auth']->viaRequest('api', function ($request) {
if($request->header('Authorization')) {
$user = $this->getUserFromAuthorizationHeader($request);
if (!empty($user)) {
$request->request->add(['userid' => $user->id]);
}
return $user;
}
});
The function getUserFromAuthorizationHeader gets a Request $request parameter and extracts the Authorization header, which is an api key, and then returns a User object.
I defined a gate update-post which checks the user that is returned from the callback and the post passed when calling the gate update-post from a controller.
Gate::define('update-post', function($user, $post){
Log::info($user);
return $user->id == $post->user_id;
});
The way I am calling the Gate in my PostController is by the following
...
$user = $this->getUserFromRequest($request);
if(Gate::denies('update-post', $post)) {
return response("Unauthorized.", 401);
}
...
I logged - using Log:: info() - the $user and $post variables in my Gate and I can successfully see the correct user and post objects being passed, but I get the error Call to a member function parameter() on array and I can't understand why exactly I am getting it.
You probably need to convert into collection before comparing if you are getting the array like this
$post = collect($post);
$user = collect($user);
Gate::define('update-post', function($user, $post){
Log::info($user);
return $user->id == $post->user_id;
});
Doc Reference

Laravel Error : ErrorException Missing argument 1?

I am using Laravel 4 and I am getting ERROR: when I visit admin/profile/: Missing argument 1 for AdminController::getProfile()
My AdminController code :
public function getProfile($id) {
if(is_null($id)) Redirect::to('admin/dashboard');
$user = User::find($id);
$this->layout->content = View::make('admin.profile', array('user' => $user));
}
My routes.php :
Route::controller('admin', 'AdminController');
My admin/profile (blade) view :
#if(!is_null($user->id))
{{ $user->id }}
#endif
How could I fix this? I want when they go to admin/profile without ($id) to redirect to dashboard.
You told Laravel that your getProfile method has one parameter:
public function getProfile($id) {
}
If you want to a request to succeed, you have to pass it in your URL:
http://appdev.local/admin/profile/1
If you want to see it fail (redirect to dashboard), you'll have to add a default value to your function argument:
public function getProfile($id = null) { ... }
But you better add this value to it anyway, since you can have bots (or even people) trying to access that route without the parameter.
Your view is too generic too, you have to check if your $user is set:
#if(isset($user) && !is_null($user->id))
{{ $user->id }}
#endif
As noted in the comments, the line
if(is_null($id)) Redirect::to('admin/dashboard');
Must have a return:
if(is_null($id)) return Redirect::to('admin/dashboard');
About sharing the user to your layout, the problem is that your getProfile($id) is already passing a $user to your view, so what you could do is to add this to your __construct():
if (Auth::check())
{
$user = Auth::getUser();
View::share('loggedUser', $user);
}
And in your view:
#if(isset($user) && !is_null($user->id))
{{ $user->id }}
#else
{{ $loggedUser->id }}
#endif
About the user not found problem, you have many options, this is one:
public function getProfile($id) {
if (is_null($id))
{
return Redirect::to('admin/dashboard');
}
if ($user = User::find($id))
{
$this->layout->content = View::make('admin.profile', array('user' => $user));
}
else
{
return Redirect::to('admin/dashboard')->withMessage('User not found');
}
Try setting a default null value to $id like this :
public function getProfile($id = null) {
...
}

Categories