422 Unprocessable Entity with Laravel 8 delete route - php

I have a common Larvel 8 project with this codes:
In the routes/api.php file:
Route::resources([
'menu/menu' => Menu\MenuController::class,
]);
In the app/Http/Controllers/Menu/MenuController.php file:
public function destroy(DestroyMenuRequest $request, Menu $menu) {
$menu->delete();
return Response::HTTP_OK;
}
In the DestroyMenuRequest.php file:
class DestroyMenuRequest extends FormRequest {
public function authorize() {
return $this->user()->can('destroy.menu');
}
public function rules() {
return [
'id' => 'required|integer|exists:menus,id',
];
}
}
Then I send a DELETE HTTP request to the url {{domain}}/api/menu/menu/2 and I get back this:
In header 422 (Unprocessable entry), and in the body:
{
"message": "The given data was invalid.",
"errors": {
"id": [
"The id field is required."
]
}
}
If I list routes with php artisan r:l I see the route with the right controller:
DELETE | api/menu/menu/{menu} | menu.destroy | App\Http\Controllers\Menu\MenuController#destroy | api auth:api
Any idea what is the solution?
Thanks!

As the comment above me pointed out, you are generating routes for resource controller.
In your routes list, you can see that the route does not expect an actual ID as the parameter, but rather it expects Menu model instance from which Laravel will automatically grab the ID.
Example if you are submitting a form:
<form method="POST" action="{{ route('menu.destroy', ['menu' => $menuObject]) }}">
#method("DELETE")
...
</form>
Where $menuObject is of type Models\Menu. In other words, it's an instance of Menu model you have created

Related

How to prevent user from modifying submitted value in the form?

I have a simple form that sends a value to controller:
<form action="{{route('mollie.payment')}}" method="post" >
#csrf
{{-- <input name="text" type="text">--}}
<button type="submit" name="test" value="23.00">Send</button>
</form>
This value will be static and this value cannot be modified. But of course it can be easily changed in Chrome dev tools.
How can I better implement this?
I though of doing validation like this:
public function preparePayment(Request $request)
{
$this->validate($request,[
'test' => '230.00'
]);
...
But it doesn't work:
BadMethodCallException
Method Illuminate\Validation\Validator::validate230.00 does not exist.
What is good way of securing this value?
Make use of laravel form request to validate request payload.
You can create new form request via command
php artisan make:request StorePaymentRequest
Then goto newly created file in app\Http\Requests folder and write all the rules in here.
<?php
namespace App\Http\Requests\StorePaymentRequest;
use Illuminate\Foundation\Http\FormRequest;=
class GetPayoutRequest extends FormRequest
{
public function rules()
{
return [
'status' => 'numeric|between:23.00,23.00'
}
}
Use this StorePaymentRequest in preparePayment controller method.
public function preparePayment(StorePaymentRequest $request)
{
$requestPayload = $request->validated();
dd($requestPayload);
}
Now, request will be able to come up here if it successfully passed the validation otherwise ValidationException will be thrown automatically.

Can't get Laravel middleware "can:something" to work with my policy

I want to make sure that the current user is able to edit the users credentials so I made the following UserPolicy:
class UserPolicy
{
use HandlesAuthorization;
public function update(User $user, User $model)
{
return true;
//return $user->is($model);
}
}
I even registered the policiy inside AppServiceProvider:
protected $policies = [
User::class => UserPolicy::class
];
Now I try to add the following middleware to the update-route in web.php: "->middleware('can:update,user');" like this:
Route::patch('/profiles/{user}',function (){
dd('It works');
})->middleware('can:update,user');
But I keep getting the following error:
Error Class '2' not found
Where 2 is the user-id who we try to patch. If I was logged in with user-id 1 that will be the class not found. I don't understand why. I followed the documentation on Laravel website (https://laravel.com/docs/8.x/authorization#via-middleware).
I have also tried to set {user} to {user:id} -> Same result
I have tried adding the id on "can" like this: can:update,user:id -> Gives 403 not authorized
The edit.blade.php has the following:
<form action="/profiles/{{ auth()->user()->id }}" method="POST">
#csrf
#method('PATCH')
...INPUTS...
</form>
I have of course tried running: "php artisan optimize" with no effect
What am I missing here? What's wrong?
EDIT:
I now tried the same thing with a Gate instead. I put the following inside AppServiceProvider.php:
public function boot()
{
Gate::define('edit-user', function(User $currentUser, User $user){
return true;
//return $currentUser->id === $user->id;
});
}
And the following middleware inside web.php:
Route::patch('/profiles/{user}',function (){
dd('It works');
})->middleware('can:edit-user,user');
And it gives me the exact same error: Class 2 not found
I even tried to pass the full models path like this:
Route::patch('/profiles/{user}',function (){
dd('It works');
})->middleware('can:edit-user,App\Models\User');
And it gives me the following error:
Argument 2 passed to
App\Providers\AppServiceProvider::App\Providers{closure}() must be an
instance of App\Models\User, string given, called in
/var/www/vhosts/domain.com/httpdocs/vendor/laravel/framework/src/Illuminate/Auth/Access/Gate.php
on line 474
I would think it is due to not using model binding, you are passing the id where it expects an user model. Check if this version works.
Route::patch('/profiles/{user}',function (User $user) {
dd('It works');
})->middleware('can:edit-user,user');

Policy with route group keeps returning 403

I'm trying to use policy on a route group. I've included the bindings middleware and tried to list the ACTION and MODEL in the CAN middleware.
For some reason it keeps returning 403. Probably I didn't quite understood how the policies work.
I'm trying to enter the before method in the policy but It keeps returning 403. Also it would be lovely if someone explains how exactly should I list custom methods in the middleware.
I also did register my policy in the AuthServiceProvider
protected $policies = [
Service::class => ServicePolicy::class,
];
public function before(CustomAuth0User $user, Service $service)
{
dd($service);
}
Route::group(['prefix' => 'services', 'namespace' => 'Services', 'middleware' => ['bindings', 'can:getCancel, service']], function () {
Route::get('/{service}/cancel', 'ServiceController#getCancel');
Route::post('/{service}/cancel', 'ServiceController#postCancel');
Route::get('/{id}/reassign', 'ServiceController#getReassign');
Route::post('/{id}/reassign', 'ServiceController#postReassign');
Route::get('/{id}/close', 'ServiceController#getClose');
Route::post('/{id}/close', 'ServiceController#postClose');
Route::get('/{id}/history', 'ServiceController#getHistory');
});
Controller
public function getCancel(Service $service)
{
dd($service);
}

Redirect to a controller action, action not defined

I'm using Laravel 5.5.
My objective is to redirect to another method on the same controller to display a view with data.
class SeancesController extends Controller {
...
public function getRecommandations(Request $request) {
...
$data = [
'recommandationAutresActiviteMemeDateHeure' => $recommandationAutresActiviteMemeDateHeure,
'recommandationsMemeActiviteMemeHeure' => $recommandationsMemeActiviteMemeHeure,
'recommandationsMemeActiviteMemeDate' => $recommandationsMemeActiviteMemeDate
];
return redirect()->action('SeancesController#showRecommandations', $data);
}
public function showRecommandations(Request $request) {
return view('listeRecommandations', $request->data);
}
}
It is the right way to do this? Because I get this error :
InvalidArgumentException: Action App\Http\Controllers\SeancesController#showRecommandations not defined. in file /home/nicolas/public_html/M1_CSI/vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php on line 338
I need to use action because I use an ajax call to access at getRecommandations().
I used this doc : http://laraveldaily.com/all-about-redirects-in-laravel-5/.
I didn't add a route that points to showRecommendations on my routing file. It's a problem?
Thank's for help!
I didn't add a route that points to showRecommendations on my routing file. It's a problem?
yes , it is a problem. because the redirector checks the routes that are assigned to the action and redirects the user to the route.

Call to a member function name() on null in laravel 5.4

When pressing my send button it's giving error like this-
Here is my routes web.php bellow-
Route::group(['prefix'=>'ajax', 'as'=>'ajax::'], function() {
Route::resource('message/send', 'MessageController#ajaxSendMessage')->name('message.new');
Route::delete('message/delete/{id}', 'MessageController#ajaxDeleteMessage')->name('message.delete');
});
Here is my controller MessageController.php bellow:
public function ajaxSendMessage(Request $request)
{
if ($request->ajax()) {
$rules = [
'message-data'=>'required',
'_id'=>'required'
];
$this->validate($request, $rules);
$body = $request->input('message-data');
$userId = $request->input('_id');
if ($message = Talk::sendMessageByUserId($userId, $body)) {
$html = view('ajax.newMessageHtml', compact('message'))->render();
return response()->json(['status'=>'success', 'html'=>$html], 200);
}
}
}
Resource routes should be named differently:
Route::prefix('ajax')->group(function () {
Route::resource('messages', 'MessageController', ['names' => [
'create' => 'message.new',
'destroy' => 'message.destroy',
]]);
});
Resource routes also point to a controller, instead of a specific method. In MessageController, you should add create and destroy methods.
More info at https://laravel.com/docs/5.4/controllers#restful-naming-resource-routes
You can't name a resource. Laravel by default name it, if you want to name all routes you must specify each one explicitly. It should be like this:
Route::group(['prefix'=>'ajax', 'as'=>'ajax::'], function() {
Route::get('message/send', 'MessageController#ajaxSendMessage')->name('message.new');
Route::delete('message/delete/{id}', 'MessageController#ajaxDeleteMessage')->name('message.delete');
});
Update
Another mistake of yours was trying to resource a single method. A Route::resource() is used to map all basic CRUD routes in Laravel by default. Therefore, you have to pass the base route and the class i.e:
<?php
Route::resource('message', 'MessageController');
Look at web.php line 28.
Whatever object you think has a name() method, hasn't been set, therefore you try and call a method on null.
Look before that line and see where it is (supposed to be) defined, and make sure it is set to what it should be!

Categories