Can we pass method parameter of controller optional - php

I'm using Laravel and I have a question running on my mind.
Basically, we create a Controller method like this:
public function index(User $user)
{
if(!empty($user)){ ... }
...
}
And we call this method by passing the $user as parameter to this method.
But is it possible to call the parameter optional. I mean if $user didn't pass, still the method works.
So in order to do that, do we have to create two web routes? Because by default, when we pass parameter we have to define that too in the route uri:
Route::get("/{user}", "HomeController#index");
Route::get("/", "HomeController#index");
So how to do this in Laravel? Is it possible or not?
I would really appreciate any idea or suggestion from you guys...
Thanks.

You can make a method parameter optional, yes. That's a PHP feature:
PHP - default function/method parameters
So in your code:
public function index(User $user = null)
{
if(!empty($user)){ ... }
...
}
It seems you want to call HomeController#index in both cases, isn't that misleading? If you visit /1 it will load user with ID 1 and show the homepage. What could be the use-case of that?
As John Lobo suggested, the route should better be /user/{user} to remove that ambiguity.
As an aside: Use Auth to get current user
If this is meant to load the current user: You can load the current user in every controller with Auth. There is no need to pass the user explicitly as a parameter if that works better for you:
$user = Auth::user();
See Laravel docs: Authentication

Related

Grouping all the laravel application routes using dynamic prefix

We have multiple client portal each one has a unique url like
xyz.com/ClientPotal123
xyz.com/ClientPotal234
xyz.com/ClientPotalXXX
We will be routing all these url's to
/var/www/html/Laravelapp/public
Laravelapp is our codebase which we use for all the clients.
Since ClientPotalXXX is dynamic and unique for all the clients, I need to get the value of ClientPotalXXX for loading client specific settings like url generation, database connection (We have different database for each client).
To achieve above I've done below changes..
My Web.php file is as below..
Route::pattern('ClientPortal','^ClientPortal([0-9]+)?');
Route::prefix('/{ClientPortal}')->group(function () {
Route::get('/user/list', 'UserController#list')->name('list');
Route::get('/user/edit/{id}', 'UserController#edit');
});
I've created Middleware with below code written in it..
public function handle($request, Closure $next)
{
$database_name = strtolower($request->ClientPortal).'_db';
config(['database.connections.mysql.database'=>$database_name]);
config(['app_settings.client'=>$request->ClientPortal]);
return $next($request);
}
And it's working fine but previously I used to access $id in edit function directly
public function edit($id){
echo $id; // 12
}
But now $id return the value of ClientPortalXX everytime.
If I access id from Request it works fine
public function edit(Request $request){
$id = $request->id; // 12
}
This is happening with all of the other routes where I'm using route parameters.
So I'm not sure if this happened because I'm using dynamic prefix for grouping all the routes?
And now for every route() method which I've used in blade files for url generation I have to pass the second parameter ie. Value of {ClientPortal}
{{route('register',['ClientPortal'=>config('app_settings.client')])}}
Is this right implementation? I know we can make any varibale accessible globally using service provider but will it be right to do so?
My Laravel Version is 5.5.xx.. I'm just a beginner so any Help/Suggestion/Advice will be appreciated Thanks :)
Update:
Nikola Gavric and Oluwafemi Sule had already clarified my doubt in comments below.
But since the group prefix is dynamic, How do I handle the route naming case?
If I had to generate user list url using list route name which is mentioned in above web.php file.
Now I've to change this line..
{{ route('list') }}
To
{{ route('list',['ClientPortal'=> 'ClientPortalXXX' ]) }}
Since prefix is also a route param.
Is this feasible option? Because I've to do this change everywhere where I've used route method for url generation.

Bind posted data to a model in Laravel 5.4

I have seen other topics regarding this issue, didn't work out.
So in Laravel 5.4 Route Model Binding, we can bind a route to a model like:
define the route in web.php:
web.php:
Route::get('/users/{user}', UsersController#show);
UsersController#show:
public function show(User $user){
// now we already have access to $user because of route model binding
// so we don't need to use User::find($user), we just return it:
return view(users.show, compact('user'));
}
The above code will work just fine, so in our controller we can return the $user without finding the user, we already have it.
but imagine this:
web.php:
Route::patch('/users/archive', UsersController#archive);
EDITED: now the above line makes a patch route and we don't have {user} in the route url, the user id is being posted via the form.
UsersController#archive:
public function archive(Request $request, User $user){
// how can I access the $user here without using User::find($user);
// I get to this action via a form which is posting `user` as a value like `5`
dd($request->user); // this now echo `5`
// I can do:
// $user = User::find($request->user);
// and it works, but is there a way to not repeat it every time in every action
}
What I have tried:
in RouteServiceProvider::boot() I have:
Route::model('user', 'App\User');
The above is what i have found in Google, but not working.
I would appreciate any kind of help.
EDIT:
It seems it's not called Route Model Binding anymore since we don't have the {user} in the route and that's because my code is not working, the user variable is being posted to the controller and it's only accessible via $request->user.
this is route model binding:
Route::patch('users/{user}/archive', UsersController#archive);
this is not:
Route::patch('users/archive', UsersController#archive);
since we don't have {user} and it's being posted via the form and could be accessed only via $request->user.
(please correct me if I am wrong about the definition of route model binding)
SO:
what I want to achieve in a nutshell: in every request being sent to my UsersController, if I am sending user variable as a post variable, it must be bounded to User::findOrFail($request->user) and then $user must be available in my controller actions.
I want to achieve this because in every action I am repeating myself doing User::findOrFail($request->user) and I don't want to do that, so I want to check in every request if I have a variable name like a model name, they should be bounded.
There's no need to bind explicitly to the User class, so Route::model('user', 'App\User'); should be removed; type-hinting should be enough instead.
public function archive(Request $request, User $user) { ... }
should be working, just make sure you are importing the right User class at the top of the file (use App\User;).
Then the model is in your $user variable (method argument), try dd($user).
It's clear now that since the {user} variable is not in the URI, this is not a route model binding issue. You just want the User instance injected as a parameter based on the contents of the request.
$this->app->bind(User::class, function () {
$user_id = request('user') ?: request()->route('user');
return User::findOrFail($user_id);
});
You could add that to the register method in the AppServiceProvider (or any other registered provider) to have the model injected. I leave it to you to generalize this to other model classes.
You don't even need (Request $request) in your controller.
If you correctly imported User class, as alepeino said, you can access all user values from Model with this syntax $user-><value> for example:
public function archive(User $user) {
$userId = $user->id;
}
According to update.
If you use POST request, you can access it's data with such code request()->get('<variable you send as parameter>')
For example:
public function archive() {
$userId = request()->get('user');
$userInfo = User::find($userId);
//Or as you said
$user = User::findOrFail(request()->get('user'));
}
Can you try this;
public function archive(Request $request, $u = User::find($user){
//now variable $u should point to the user with id from url
}

Laravel getting {id} get parameter in middleware

The problem: I can't get the {id} parameter to be 'found' in the Middleware. My middleware needs to get the {id} param, in order to verify if the Auth::user() is the owner of the specified group.
Request example: groups/admin/open/4 --> group 4 will be opened.
What I have:
Route:
Route::post('groups/admin/open/{id}', 'GroupController#opengroup')->middleware(['auth','owner']);
My middleware ('owner') is still empty.
What I tried:
1. Adding an $id parameter in the function (like you do in Controllers), like so:
public function handle($request, /* Added -> */ $id, Closure $next)
{
dd(Input::get('id'));
return $next($request);
}
This returns an error:
Argument 3 passed to App\Http\Middleware\RedirectIfNotOwner::handle() must be an instance of Closure, none given
Different placement of the $id, at the end, results in the error:
Missing argument 3 for App\Http\Middleware\RedirectIfNotOwner::handle()
What I have tried 2: I have thought about is to change my url like this
Request example: groups/admin/open?groupparam=4
And use
Input::get('groupparam');
But this forces me to make changes to my controllers etc. Still this is an option.
Reason for asking: moreover I believe Laravel has the capability to retrieve {id} params in Middleware too, beautifully. I just don't know how.
Can you help me?
Thanks,
Eltyer
You can easily get route parameters in your route middleware with:
$id = $request->route('id');

Laravel Different Route Same Controller

I'm building an API for user and admin.
Got stuck at edit user profile routing.
on admin route i use Route::resource('user', 'UserController')
on user route i use Route::get('profile', 'UserController#show')
At the show method Laravel default has
public function show($id)
{
}
the different between them is on admin I can use /id but on user i check their token from middleware and merge the request to get their user_id so there is no need for the API to use profile/{id}.
The question is how can I use the same method but there is an argument to fill and the route still /profile?
One of my solution is :
public function show($id){
if ($request->has('user_id')):
$id = $request->query('user_id');
endif;
}
It working but when i read the code, it's really redundant always checking it and replace the id.
Just place the request object as a parameter in your controller and get the input from the request object when you use your user route.
Thanks

How to use the request route parameter in Laravel 5 form request?

I am new to Laravel 5 and I am trying to use the new Form Request to validate all forms in my application.
Now I am stuck at a point where I need to DELETE a resource and I created a DeleteResourceRequest for just to use the authorize method.
The problem is that I need to find what id is being requested in the route parameter but I cannot see how to get that in to the authorize method.
I can use the id in the controller method like so:
public function destroy($id, DeletePivotRequest $request)
{
Resource::findOrFail($id);
}
But how to get this to work in the authorize method of the Form Request?
That's very simple, just use the route() method. Assuming your route parameter is called id:
public function authorize(){
$id = $this->route('id');
}
You can accessing a Route parameter Value via Illuminate\Http\Request instance
public function destroy($id, DeletePivotRequest $request)
{
if ($request->route('id'))
{
//
}
Resource::findOrFail($id);
}
Depending on how you defined the parameter in your routes.
For my case below, it would be: 'user' not 'id'
$id = $this->route('user');
Laravel 5.2, from within a controller:
use Route;
...
Route::current()->getParameter('id');
I've found this useful if you want to use the same controller method for more than one route with more than one URL parameter, and perhaps all parameters aren't always present or may appear in a different order...
i.e. getParameter('id')will give you the correct answer, regardless of {id}'s position in the URL.
See Laravel Docs: Accessing the Current Route
After testing the other solutions, seems not to work for laravel 8, but this below works
Route::getCurrentRoute()->id
assuming your route is
Route::post('something/{id}', ...)
I came here looking for an answer and kind of found it in the comments, so wanted to clarify for others using a resource route trying to use this in a form request
as mentioned by lukas in his comment:
Given a resource controller Route::resource('post', ...) the parameter you can use will be named post
This was usefull to me but not quite complete. It appears that the parameter will be the singular version of the last part of the resource stub.
In my case, the route was defined as $router->resource('inventory/manufacturers', 'API\Inventory\ManufacturersController');
And the parameter available was manufacturer (the singular version of the last part of the stub inventory/manufacturers)
you will get parameter id if you call
request()->route('id')
OR
$this->route('id')
if you're using resource routing, you need to call with the resource name
// eg: resource
Route::resource('users', App\Http\Controllers\UserController::class);
$this->route('user')
in Terminal write
php artisan route:list
to see what is your param name
Then use
$this->route('sphere') to get param

Categories