Laravel routing: is there a syntax to pass a fixed parameter to the handler function? - laravel

I am using Laravel 8 and currently I have the following route:
Route::match(['get'], '/{action}', '\App\Http\MyController#handleRequest');
In the MyController class I have a handlerRequest function which takes two parameters
public function handleRequest(Request $request, string $action)
{
// Generic request handling code for every action, both GET and POST
// This code is fairly long and I don't want it to be duplicated
}
This all works well until I want to add another route for a specific request:
Route::match(['post'], '/message-sent', '\App\Http\MyController#handleRequest');
In this case only the POST method is allowed on the specific action message-sent, however it does not work using the above configuration as Laravel does not pass "message-sent" as $action to the handleRequest function.
The error message is
Too few arguments to function App\Http\MyController::handleRequest(), 1 passed in /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php on line 48 and exactly 2 expected
What I want is the action "message-sent" is passed into the generic handler function as parameter but at the same time achieving the "special post-only setting" for this specific route.
I tried
Route::match(['post'], '/{message-sent}', '\App\Http\MyController#handleRequest');
as well without success.

After searching through the Laravel source code, I think I found the solution
Route::match(['post'], '/message-sent', '\App\Http\MyController#handleRequest')->defaults('action', 'message-sent');
would achieve the effect of sending a fixed parameter $action="message-sent" to the handler function.

Related

Customise the "method is not supported for this route" error handling in Laravel

Route::post('order', 'OrderController#store')->name('order');
When I browse to the URL http://127.0.0.1:8000/order it shows the error:
The GET method is not supported for this route. Supported methods: POST.
Which is the correct.
But I want to redirect user to home page instead of showing this error.
First of all note that what you are trying to do seems like an anti-pattern for Laravel. Accessing a route with the wrong method should be denied!
I currently do not know about altering the default way of handling the wrong method error and I wouldn't advise to do that. But you can work around it:
Patching
Method 1
Keep your routes file clean but alter the original route line and add some lines to the beggining of the controller method
Route::match(['get', 'post'], 'order', [OrderController::class, 'store'])->name('order');
public function store(Request $request)
{
if ($request->isMethod('get')) {
return to_route('home');
}
// ...
Method 2
Keep your controller clean, but add a line to your routes file
Route::get('order', fn () => to_route('home'));

getting query parameters from URL in laravel 7.1

Just as a learning exercise, I'm creating a REST API in Laravel 7.1. I'm having trouble figuring out how to parse the query string parameters in route methods. I've read over the documentation here, and it shows how to add parameters into the path:
Route::get('user/{id}', function ($id) {
return 'User '.$id;
});
However I don't see where you can get query parameters from the request URL. In my toy code, I want to add a route to add a new car to inventory:
Route::post('/inventory/add/{make}/{model}/{year}', function ($make, $model, $year) {
return \App\Inventory::create($model, $color, $trim, $accessories);
});
I want to specify parameters such as color, trim, and accessories through the query string, like so:
http://example.com/inventory/add/ford/focus/2020?color=red&trim=sport&accessories=chrome-wheels
How do I get the query parameters out of the Route::post method?
Edit I suppose this architecture may not be the optimal way of adding this extra information, but since I am trying to learn laravel, I am using it as an example. I am interested in learning how to get the query parameters moreso than how to improve the architecture of this learning example.
In Route::post you don't need set the parameters in route. Just use:
Route::post("your-route", "YourControllerController#doSomeThing");
So, in app/Http/Controllers/YourControllerController.php file:
class YourControllerController extends Controller {
public function doSomeThing(Request $request)
{
echo $request->input('param1');
echo $request->input('param2');
echo $request->input('param3');
}
You just need to inject the request instance into your handler (whatever a closure or controller method) and then ask for your parameters.
$color = $request->query('color', 'default-color');
//And so on...
https://laravel.com/docs/7.x/requests#retrieving-input

Laravel Routes and 'Class#Method' notation - how to pass parameters in URL to method

I am new to Laravel so am uncertain of the notation. The Laravel documentation shows you can pass a parameter this way:
Route::get('user/{id}', function ($id) {
return 'User '.$id;
});
Which is very intuitive. Here is some existing coding in a project I'm undertaking, found in routes.php:
Route::get('geolocate', 'Api\CountriesController#geolocate');
# which of course will call geolocate() in that class
And here is the code I want to pass a variable to:
Route::get('feed/{identifier}', 'Api\FeedController#feed');
The question being, how do I pass $identifier to the class as:
feed($identifier)
Thanks!
Also one further sequitir question from this, how would I notate {identifier} so that it is optional, i.e. simply /feed/ would match this route?
You should first create a link which looks like:
/feed/123
Then, in your controller the method would look like this:
feed($identifier)
{
// Do something with $identifier
}
Laravel is smart enough to map router parameters to controller method arguments, which is nice!
Alternatively, you could use the Request object to return the identifier value like this:
feed()
{
Request::get('identifier');
}
Both methods have their merits, I'd personally use the first example for grabbing one or two router parameters and the second example for when I need to do more complicated things.

How to retrieve Route parameters in Controller __construct()

I'm trying to pull two parameters into my Controller's __construct() method, but I keep getting the following debug
Call to undefined method Illuminate\Routing\Router::parameters()
What I'm specifically trying to do is.
Pull the "portal" and "issue" parameters into my __construct and set the $currentPortal and $currentIssue variables in my class (protected variables)
Use those two protected vars when I please in different Controller actions
Down below you'll find my __construct() method
protected $portals, $issues, $currentPortal, $currentIssue;
public function __construct(\App\Entities\Portal $portals, \App\Entities\Issue $issues){
$this->portals = $portals;
$this->issues = $issues;
dd(\Route::parameters());
if($portal = \Route::getParameter('portal'))
$this->currentPortal = $this->portals->findBySlug($portal);
if($issue = \Route::getParameter('issue'))
$this->currentIssue = $this->issues->findByKey($issue);
}
As you can notice, I'm using dd() as a debug helper in order to see if the current Route parameters and being pulled.
There's no issue in the router.php definitions, as I have already tested them before trying to implement this handy "hack" to pull the current objects.
Any help in order to get the current Route params?
Thanks!
Oh yeah, I figured it out just after posting this question!
I'm leaving the answer in case anyone is having the same issue as I was..
You need to pull the current() route before appending any other requests, so in my case, I should've done
Route::current()->getParameter('MY PARAM NAME')
That should be it

Call an index controller with parameter

So basically, I have a setup of restful controller in my route. Now my problem is how can I call the Index page if there is a parameter.. it gives me an error of Controller not found
Im trying to call it like this www.domain.com/sign-up/asdasdasd
Route::controller('sign-up','UserRegisterController');
then in my Controller
class UserRegisterController extends \BaseController {
protected $layout = 'layouts.unregistered';
public function getIndex( $unique_code = null )
{
$title = 'Register';
$this->layout->content = View::make( 'pages.unregistred.sign-up', compact('title', 'affiliate_ash'));
}
By registering:
Route::controller('sign-up','UserRegisterController');
You're telling the routes that every time the url starts with /sign-up/ it should look for corresponding action in UserRegisterController in verbAction convention.
Suppose you have:
http://domain.com/sign-up/social-signup
Logically it'll be mapped to UserRegister#getSocialSignup (GET verb because it is a GET request). And if there is nothing after /sign-up/ it'll look for getIndex() by default.
Now, consider your example:
http://domain.com/sign-up/asdasdasd
By the same logic, it'll try looking for UserRegister#getAsdasdasd which most likely you don't have. The problem here is there is no way of telling Route that asdasdasd is actually a parameter. At least, not with a single Route definition.
You'll have to define another route, perhaps after your Route::controller
Route::controller('sign-up','UserRegisterController');
// If above fail to find correct controller method, check the next line.
Route::get('sign-up/{param}', 'UserRegisterController#getIndex');
You need to define the parameter in the route Route::controller('sign-up/{unique_code?}','UserRegisterController');. The question mark makes it optional.
Full documentation here: http://laravel.com/docs/routing#route-parameters

Resources