Can't pass Request from controller to another controller's view - laravel

I'm trying to pass a Request from a controller, but for reasons I don't understand the data simply isn't being passed through to the view and I get Undefined variable: request. I have confirmed that right up until the redirect to the action the request is populated with all the additional variables, so the issue must be after that.
ManufacturerController
public function decode(Manufacturer $manufacturer, Request $request) {
$validated = $request->validate([
"id" => ["required","min:5","max:30", "alpha_num"],
"email" => ["email","required","max:255"]
]);
$request->merge([
"manufacturer" => $manufacturer
]);
// Pass the Request to the Manufacturer model and return a modified version of it
$request = $manufacturer->oneplus($request);
return redirect()->action([TransactionController::class, "index"])->with($request);
}
abort(404);
}
Manufacturer model:
public function oneplus($request) {
$id = $request->id;
/* BUSINESS LOGIC THAT GENERATES $new FROM $id... */
$request->merge([
'new' => $new
]);
return $request;
}
Route in web.php
Route::get('/payment', [TransactionController::class, "index"]);
TransactionController:
public function index()
{
return view('payment');
}
payment.blade.php
{{ dd($request->new) }}

The problem when using redirects is that the redirect will cause a brand new request to happen. When using redirect()->with('variable', 'value') you need to then access that variable using:
session('variable')`
the reason being that the variable is "flashed" to the next request via the session (in practice it's not sent to the next request, it's just available for the next request through the session and then disappears).
While this may be an easy solution to your problem a better solution is to not use a redirect if possible. Here's a simplification of an alternative:
ManufacturerController:
public function decode(Manufacturer $manufacturer, Request $request) {
$validated = $request->validate([
"id" => ["required","min:5","max:30", "alpha_num"],
"email" => ["email","required","max:255"]
]);
$request->merge([
"manufacturer" => $manufacturer
]);
// Pass the Request to the Manufacturer model and return a modified version of it
$request = $manufacturer->oneplus($request);
$transactionController = app()->make(TransactionController::class);
return $transactionController->index($request);
}
TransactionController:
public function index(Request $request)
{
return view('payment')->with("request", $request);
}
This will call the other controller method within the same request.

You need to make few changes in TransactionController and ManufacturerController to make it work
TransactionController:
public function index(Request $request)
{
return view('payment', [
'request' => $request->session()->get('request')
]);
}
ManufacturerController:
public function decode(Manufacturer $manufacturer, Request $request) {
$validated = $request->validate([
"id" => ["required","min:5","max:30", "alpha_num"],
"email" => ["email","required","max:255"]
]);
$request->merge([
"manufacturer" => $manufacturer
]);
// Pass the Request to the Manufacturer model and return a modified version of it
$request = $manufacturer->oneplus($request);
return redirect()->action([TransactionController::class, "index"])->with('request', $request->all());
}
abort(404);
}

You can pass like this
ManufacturerController :
return redirect()->action(
[TransactionController::class, "index"],
['data' => $request]
);
Route in web.php
// ? = Optional
Route::get('/payment/{data?}', [TransactionController::class, "index"]);
TransactionController:
public function index($data)
{
return view('payment');
}

Related

Laravel custom policy method always returning 403

Route
Route::get('/post/preview/{slug}', [PostController::class, 'viewPreview'])->name('post.single.preview');
PostController
protected function resourceAbilityMap()
{
return array_merge(parent::resourceAbilityMap(), [
'viewPreview' => 'viewPreview'
]);
}
public function viewPreview($slug)
{
$post = Post::where('slug', $slug)->firstOrFail();
$this->authorize('viewPreview', $post);
return view('post.single', [
'post' => $post,
'morePosts' => $this->getMorePosts($post->id, 3),
]);
}
PostPolicy
public function viewPreview(User $user, Post $post)
{
return true;
}
Whether I put true or false in the policy method, it always returns a 403. What am I missing?
The part
protected function resourceAbilityMap()
{
return array_merge(parent::resourceAbilityMap(), [
'viewPreview' => 'viewPreview'
]);
}
Was not needed. I found it on SO but it's not in the official Laravel docs.
The issue was that when testing I was not logged in, and Laravel will always return false for policy methods where the type-hinted model is required (in this case User $user). For testing, adding ? made it work: viewPreview(?User $user, ...)

Laravel unique validation if ID isn't in request

I want to do some validation for a field. Right now works for unique values, the problem is that on Update I get the same error. So I want to filter the request, if that post request contain ID field then this field shouldn't be unique.
public function rules()
{
return [
'customer_id' => 'required|unique:customers',
];
}
You can use Rule class' unique method for the update method
public function rules()
{
return [
'customer_id' => [
'required',
Rule::unique('customers')->ignore($customer->customer_id),
];
}
Laravel docs: https://laravel.com/docs/8.x/validation#rule-unique
For common rules() function it can be done as
use Illuminate\Validation\Rule;
class CustomerController extends Controller
{
protected function rules($customer)
{
return [
'customer_id' => [
'required',
Rule::unique('customers')->ignore($customer->exists ? $customer->customer_id : null),
];
}
public function store(Request $request)
{
$customer = new Customer;
$request->validate($this->rules($customer));
}
public function update(Request $request, Customer $customer)
{
$request->validate($this->rules($customer);
}
}
In my case I have a single method for store/update and I check If I have an ID or not. Also I added $customer = request()->all(); and ignore($customer['ID'] , that is for my specific case.
Laravel Docs warns against passing user controller request input to the ignore method
For your specific case you can do
$customer = !empty($request->input('ID') ? Customer::findOrFail($request->input('ID')) : new Customer;
//Then pass the customer to the rules()
$validated = $request->validate($this->rules($customer));

Showing slug instead of id for crud in Laravel 8

im making an edit section on my laravel crud project. that when i press edit, it will redirect to the edit.blade.php which will call the slug instead their id. i have worked on it and it shows the error that Too few arguments to function App\Http\Controllers\ProductController::edit(), 1 passed and exactly 2 expected
my Route
Route::get('edit/{slug}', $url. '\productController#update');
Route::get('edit', $url. '\productController#edit');
my ProductController::edit()
public function edit(Product $product, $slug)
{
return view('edit', compact('product'));
}
my ProductController::update()
public function update(Request $request, Product $product, $slug)
{
Product::where('product_slug',$request->$slug)->update([
'product_title' => $request->title,
'product_slug' => $request->slug,
'product_image' => $request->image
]);
// redirect
return redirect('edit');
}
any helps would be greatly appreciated,thanks in advance
You do not need to worry about anything. Just add below code to your Product model:
public function getRouteKeyName()
{
return 'slug';
}
and Laravel will take care of the rest. For more information, visit below link, they have a very good explanation there:
https://laravel.com/docs/8.x/routing#customizing-the-default-key-name
You're getting this error because you have 2 parameters in your methods: Product $product and $slug. To solve this error you should remove one of them.
You also need to add slug parameter to your edit route in order to access it in your controller. And your update route should be PUT or PATCH.
Something like this:
Route::get('products/{slug}/edit', [ProductController::class, 'edit'])
Route::patch('products/{slug}', [ProductController::class, 'update'])
So, you can either remove the Product $product and use the $slug to get the product:
public function edit($slug)
{
$product = Product::where('product_slug', $slug);
return view('edit', compact('product'));
}
public function update(Request $request, $slug)
{
Product::where('product_slug', $slug)->update([
'product_title' => $request->title,
'product_slug' => $request->slug,
'product_image' => $request->image
]);
// redirect
return redirect('edit');
}
Or you can remove the $slug and use the Product $product by setting slug as your route key and changing the route param to product.
// Product model
public function getRouteKeyName()
{
return 'slug'
}
// Product controller
public function edit(Product $product)
{
return view('edit', compact('product'));
}
public function update(Request $request, Product $product)
{
$product->update([
'product_title' => $request->title,
'product_slug' => $request->slug,
'product_image' => $request->image
]);
// redirect
return redirect('edit');
}
// Route
Route::get('products/{product}/edit', [ProductController::class, 'edit'])
Route::patch('products/{product}', [ProductController::class, 'update'])
pass id in your edit button instead of slug
<a href="{{url('edit/'$id'')}}" class="btn btn-info btn-sm" />Edit</a>
and change your update function
public function update(Request $request, Product $product, $id)
{
Product::where('id_column_name', $id)->update([
'product_title' => $request->title,
'product_slug' => $request->slug,
'product_image' => $request->image
]);
// redirect
return redirect('edit');
}

API Postman error: "The PATCH method is not supported for this route. Supported methods: GET, HEAD"

I create custom Request which named "StoreUser" for custom validation rules for store and update methods. For store method when i using POST method in Postman it's all working good. But for PATCH/PUT method i catch error: "The PATCH method is not supported for this route".
Supported methods: GET, HEAD". My URL for PATCH method: http://127.0.0.1:8000/api/users/44
Using debagger, i found that the problem occurs when custom Request "StoreUser" start return array rules in rules() method.
Below my code. Only error occurs in PATCH/PUT method, POST it's ok
ApiResource
Route::apiResource('users', 'UserController');
UserController update/store methods
public function store(StoreUser $request)
{
$request->validated();
$password = User::hashPassword($request->get('password'));
$request->merge(['password' => $password]);
$user = User::create($request->all());
return response()->json($user, 201);
}
public function update(StoreUser $request, $id)
{
$request->validated();
$user = User::find($id);
$user->update($request->all());
return response()->json($user, 200);
}
Custom Request StoreUser
public function rules()
{
return [ // in this place error occurs ONLY IN PATCH/PUT methods
'name' => 'required|min:5',
'email' => 'required|email|unique:users',
'password' => 'required|min:6|max:50'
];
}
Have you tried adding _method="PATCH" in the body of the request. The type of request should be POST.
Try to romve $request->validated(); when you use custom valdation class then
there is no need to call validated() method
public function update(StoreUser $request, $id)
{
$request->validated();
$user = User::find($id);
$user->update($request->all());
return response()->json($user, 200);
}
use following code
public function update(StoreUser $request, User $user)
{
$user->update($request->all());
return response()->json($user, 200);
}
In above code User $user use as parameter its mean that route model binding so
there is no need to use extra query to find user

Laravel - return variable from Form Requests to Controller

How can I return a variable from Form Requests (App\Http\Requests) to Controller (App\Http\Controllers)?
I am saving a record on function persist() on Form Requests.
My goal is to pass the generated id so that I can redirect the page on edit mode for the user. For some reason, the Controller cannot receive the id from Form Requests.
App\Http\Requests\MyFormRequests.php:
function persist()
{
$business = Business::create([
'cart_name' => $this['cart_name'],
'product' => $this['product']
]);
return $myid = $business->id;
}
App\Http\Controllers\MyControllers.php:
public function store(MyFormRequests $request)
{
$request->persist();
return redirect()->route('mypage.edit.get', $request->persist()->$myid);
}
Important
I must add that this is not the recommended way. Your FormRequest should only be responsible for validating the request, while your Controller does the storing part. However, this will work:
App\Http\Requests\MyFormRequests.php:
function persist()
{
return Business::create([
'business_name' => $this['business_name'],
'nationality' => $this['nationality']
])->id;
}
App\Http\Controllers\MyControllers.php:
public function store(MyFormRequests $request)
{
$id = $request->persist();
return redirect()->route('register.edit.get', $id);
}
A guy name Snapey helped me:
public function store(MyFormRequests $request)
{
$business = $this->persist($request);
return redirect()->route('register.edit.get', $business->id);
}
private function persist($request)
{
....
return $business;
}
hope this could help someone in the future.

Resources