Laravel - Recreate custom request with validation on the fly - laravel

I need to be able to recreate an $request variable, reach the validation of that request, and also beeing able to access route params (/foo/{user_id}) and query params (/foo?user_id), like this example.
Note! This is an silly example, i know that this specific problem can be resolved in a much simpler way, but my current enviriment is too complexi to explain, also it would be unnecessary
class RandomController {
// /foo/{field1}?field2
public function create(CreateRequest $request) {
if ($request->has('id') {
$new_request = recreateRequest($request->only('field1', 'field2', 'field3')); // field3 is on the body
return $this->update($new_request);
}
}
public function update(UpdateRequest $request) {
$request->field1; // /foo/{field1}
$request->field2; // /foo?field2
$request->field3; // {field3: }
}
}
Now I recreate the request passing it as an prop (CustomRequest::class) and using this following code, but it is unstable, sometimes it doesn't reach the request properties and I have to write $request->request->field1 instead of $request->field1
$created_request = new $new_request(
$query ?: $old_request->query->all(),
$request ?: $old_request->request->all(),
$attributes ?: $old_request->attributes->all(),
$cookies ?: $old_request->cookies->all(),
$files ?: $old_request->files->all(),
$server ?: $old_request->server->all()
);

you can create your own request object by artisan using the following command:
php artisan make:request RequestName
this should create a request file in your HTTP request folder and you can still use the global request variable $request so you can access all the parameters and use the validation.
and then just import it using
use Illuminate\Http\YourCustomRequest;
and replace the controller method argument with the new request you just imported like so
public function create(YourCustomRequest $myRequest) {
//do some action.
}
check the documentation here: https://laravel.com/docs/7.x/validation

Related

Laravel API routes and Controller variable

I'm a new user of Laravel, and i'm a bit confused with Laravel route API and the name of variable in the controller.
Here an example to explain :
An API route
Route::middleware('auth:sanctum')->group( function () {
Route::resource('cepage', CepageController::class);
});
For a PUT or PATCH, i have this function in the CepageController :
public function update(Request $request, Cepage $cepage)
{
$input = $request->all();
$validator = Validator::make($input, [
'libelle' => 'required',
'abrege' => 'required'
]);
if($validator->fails()){
return $this->sendError($validator->errors());
}
$cepage->libelle = $input['libelle'];
$cepage->abrege = $input['abrege'];
$cepage->save();
return $this->sendResponse(new CepageResource($cepage), 'Cépage mis à jour');
}
If you see my route name "cepage" have the same name of the $cepage variable of the function declaration in the controller, Laravel update the record in the database.
If they are no identical, Laravel create a new record in the database.
Why they need to be exactly the same ?
I think i miss something in the documenation of Laravel.
Thanks for your explanations.
It needs to be the same, for laravel to know what object does he needs to create for us.
Route::resource does a few routes for you, with the base url give into it (https://laravel.com/docs/8.x/controllers#actions-handled-by-resource-controller)
So once you have defined Route::resource('cepage', CepageController::class)
You will have the following routes defined:
Verb URI Action Route Name
GET /cepage CepageController#index cepage.index
GET /cepage/create CepageController#create cepage.create
POST /cepage CepageController#store cepage.store
GET /cepage/{cepage_id} CepageController#show cepage.show
GET /cepage/{cepage_id}/edit CepageController#edit cepage.edit
PUT/PATCH /cepage/{cepage_id} CepageController#update cepage.update
DELETE /cepage/{cepage_id} CepageController#destroy cepage.destroy
And in the controller you need to follow the naming, because in the url you have only ids of the object. But if you follow the naming, laravel will fetch the object for you by its id. See:
public function update(Request $request, $cepage_id)
{
$cepage = Cepage::find($cepage_id);
//here you have to fetch the object for yourself to access it
}
public function update(Request $request, Cepage $cepage)
{
//here you can already access $cepage variable
}

Laravel - How to not pass unused parameter in controller

I have a route for example -
Route::get('/api/{user}/companies/{company}', [CompanyController::class, 'getCompanies'])
and a function in this controller
public function getCompanies(User $user, Company $company) {
$companies = $company->all();
return response()->json(['companies' => $companies]);
}
I am not using the $user instance in the function and I would like to not pass a User $user param in it, but I want that the route has user id as a param for clarity on the frontend.
I found a solution of using middleware with the forgetParameter() method but I don't want to add new middleware or declare it only for this route.
I can just leave that unused param in my function and everything will work just fine, but I am curious is there some elegant solution for this case.
public function getCompanies(Company $company, ?User $user = null)
{
return response()->json(['companies' => $company->all()]);
}
Pass $user to the last position and give it a default value
I think you can put a _ instead of passing a parameter, but I could be wrong.

How to use parameter from function to create an URL? Laravel Routing

I'm sending an URL hashed and when i get it i have to show a view on Laravel, so i have those functions on the controller and also some routes:
This are my routes:
Route::post('/sendLink', 'Payment\PaymentController#getPaymentLink');
Route::get('/payment?hash={link}', 'Payment\PaymentController#show');
And this are the functions i have on my controller:
public function getPaymentLink (Request $request){
$budgetId = $request['url.com/payment/payment?hash'];
$link = Crypt::decryptString($budgetId);
Log::debug($link);
//here to the show view i wanna send the link with the id hashed, thats why i dont call show($link)
$view = $this->show($budgetId);
}
public function show($link) {
$config = [
'base_uri' => config('payment.base_uri'), ];
$client = new Client($config);
$banking_entity = $client->get('url')->getBody()->getContents();
$array = json_decode($banking_entity, true);
return view('payment.payment-data')->with('banking_entity', $array);
}
And this is getting a "Page not found" message error.
What i want to to is that when i the client clicks on the link i send him that has this format "url.com/payment/payment?hash=fjadshkfjahsdkfhasdkjha", trigger the getPaymentLink function so i can get de decrypt from that hash and also show him the view .
there is no need to ?hash={link} in get route
it's query params and it will received with $request
like:
$request->hash
// or
$request->get('hash')
You need to define route like this:
Route::get('/payment/{hash}', 'Payment\PaymentController#show');
You can now simply use it in your Controller method like below:
<?php
public function getPaymentLink (Request $request,$hash){
$budgetId = $hash;
// further code goes here
}

dd() not working in vue-laravel project axios call.Is it possible to use dump in axios call?

I am using vue with laravel.but my save function not working. So I tried to dump and die the request object but I can't see the request object in the preview. it is blank.
protected function save()
{
$request = Request::all();
dd($request);
$suggestion = new Suggestion();
$suggestion->connection_id = $request['connection_id'];
$suggestion->company_id = $request['company_id'];
$suggestion->module = $request['module'];
$suggestion->description = $request['image'];
$suggestion->save();
return 'success';
}
the axios call is
axios.post('suggestion/save', this.post).then(response => {
this.$swal({
title: 'Success',
text: response.data.message,
type: 'success',
confirmButtonText: 'OK',
});
this.$router.push('/suggestion-list');
})
There are multiple Request classes in Laravel, One thing you can try is the following,
public function controllerFunction()
{
dd(request()->all());
$suggestion = new Suggestion();
$suggestion->connection_id = $request['connection_id'];
$suggestion->company_id = $request['company_id'];
$suggestion->module = $request['module'];
$suggestion->description = $request['description'];
$suggestion->save();
return 'success';
}
So irrespective of your class, the request() function will bring up the appropriate object.
If you get to dump the request then you can confirm that the request is hitting the appropriate controller function, otherwise, the request is going somewhere else. check the network tab in chrome for more details.
Also, make sure you have the appropriate Request class in the use statements.
The correct Request class usage is like following
use Illuminate\Http\Request;
Add request to your function
also add 'use Illuminate\Http\Request'
use Illuminate\Http\Request
public function myFunction(Request $request)
{
dd($request->all());
...
}
hey you can use print() or print_r() to check result
and make sure your this.post has data or not

Laravel 5 - Remove Parameter From All Request Objects at Controller Level

I have URLs that look like:
http://example.com/api/user?id=45&name=mike&api_token=2348283
http://example.com/api/project?id=5&description=first&api_token=2348283
etc...
In my controllers, I have functions that look like:
public function user_get_endpoint(Request $request){
$request = $request->toArray();
return UserModel::where($request)->get()->toArray();
}
The above will currently break since the $request object contains a property called api_token which does not exist in the user table. I am using the api_token in a middleware to check for authentication.
I can manually unset the api_token property in each of my API functions by using unset($request['api_token'], but I'd like to avoid that if possible.
Is there anyway to do this application wide or at a class or controller level?
Laravel provides add and remove functions to add and remove new properties to the request object respectively.
$request->request->add(['api_token' => 'api_token']); // to add new property to $request
$request->request->remove('api_token'); // to remove property from $request
Perhaps you want global middleware?
First arrange for the middleware to run on all routes:
// routes.php
$app->middleware([
App\Http\Middleware\Apitoken::class
]);
Then define what the middleware should do:
// src/App/Http/Middleware/Apitoken.php
<?php
namespace App\Http\Middleware;
use Closure;
class Apitoken
{
public function handle($request, Closure $next)
{
unset($request['api_token']);
return $next($request);
}
}
Method 1
$request->except(['key1','key2',....])
provides an easy way to skip unwanted keys, similarly
Method 2
$request->only(['key3','key4',....])
provides an easy way to skip all others unwanted keys, I find both reasonably good for almost all scenarios
A solution that works for all HTTP Methods (not only for GET and HEAD) :
$except = ['api_token'];
$request = request();
$cleanup = $request->except($except);
$request->query = new \Symfony\Component\HttpFoundation\ParameterBag($cleanup);
Ideally, you should send your api_token in request headers instead of Uri params.
If you are using Laravel's auth:api Middleware for authentication then you can send api_token in headers as:
$response = $client->request('GET', '/api/user', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '.$accessToken,
],
]);
Then api_token will never come in your Uri params.
As #JanWillem said in the comments you can use except() which will remove the params you pass to it:
public function user_get_endpoint(Request $request){
return UserModel::where($request->except('api_token'))->get();
}
https://laravel.com/docs/5.2/requests#retrieving-input and then scroll down to Retrieving A Portion Of The Input Data
Furthermore, you don't have to use toArray() with the response as Laravel will automatically do this for you.
Hope this helps!

Resources