Is there any way I can use optional route params in the middle of the URL in Laravel 5. Here is what I want
Route::get('api/{locale?}/my-url', 'MyController#myAction');
You can't have optional route parameters in the middle of the route path, because they make the definition ambiguous if they are omitted, and the route won't be matched.
You could have two route definitions one with and one without (as you've suggested in your comment):
Route::get('api/{locale}/my-url', 'MyController#myAction');
Route::get('api//my-url', 'MyController#myAction');
But if you have lots of routes you'll have a lot of duplicates just for this.
You could just leave one definition with the locale, since there's no big deal of passing the default locale as part of the URL path. So if your default locale is en it just gets passed via the path as other locales:
http://example.com/api/en/my-url
However, since I'm guessing the locale is used for language appropriate responses and is only used for GET/HEAD requests, the best solution that I see here and it makes the most sense, is to just pass the locale as a parameter, because it's essentially an option:
http://example.com/api/my-url?locale=en
That way the Laravel route definition doesn't need to worry about it. Then you can use a middleware to change the locale if it is passed along in the query string. Here's an example of a middleware class that sets the locale and checks if it's an allowed locale:
namespace App\Http\Middleware;
use Closure;
class SetLocale
{
public function handle($request, Closure $next)
{
if ($request->has('locale') && $this->isValidLocale()) {
app()->setLocale($request->input('locale'));
}
return $next($request);
}
protected function isValidLocale()
{
return in_array(request()->input('locale'), ['en', 'es', 'fr', 'de']);
}
}
Now in your controller action you can just use:
app()->getLocale();
And it will be set to the value passed in the query string.
If I understand well and you want the url to work both as api/my-url and api/en/my-url you can simply setup two routes:
Route::get('api/{locale}/my-url', 'MyController#myAction');
Route::get('api/my-url', 'MyController#myAction');
Related
Is there any way to customize what a controller returns based on a parameter (not a query parameter) provided in a route? For example, if there are two modes of display, but it depends on the URL accessed as far as which way it's displayed.
A simplified, made up example:
class MyController extends Controller
{
// $display_mode can be "large" or "small"
public function show($display_mode = null)
{
...
}
}
Route:
For /page1 I want $display_mode to be "large", for /page2, I want it to be "small." How do I pass that in via the function parameter? This would be the preferred way, but if Laravel does this a different way, let me know.
Route::get('/page1', [MyController::class, 'show']);
Route::get('/page2', [MyController::class, 'show']);
To get a better idea of what I want to accomplish. Say the controller function has five different customizable parameters based on both display and business logic. I can't know in advance what options will apply to the pages that the developer creating routes will want to display. I just want to make those options available.
Also, the developer making the routes does not want to make URLs with ugly paths such as mypage/large/tiled/system-only. The end user doesn't need to know about all of the options passed in as parameters to a function.
Rather, the routes should only be /a, /b, and /c and each of those routes underneath the hood represents zero to five customizable options by passing in the options as parameters to the controller function.
edit:
I tried the defaults() method and it works well. Note that in order for it to work, a separate default() call has to be made for each function parameter. For example:
Route::get('/login/main', [WAYFController::class, 'wayf'] )
->defaults('tiledUI', false)
->defaults('showAffiliateLogin', true)
->defaults('type', 'full');
Yea, you can do this. You can use the defaults method of the Route to pass a default value for a parameter:
Route::get('testit', function ($display_mode) {
dump($display_mode);
})->defaults('display_mode', 'large');
You can use this to pass arbitrary data to the 'action'.
Another use-case for this is if you had something like a PageController to display a single page but don't want the routes to be dynamic and instead explicitly define the routes you will have:
Route::get('about-us', [PageController::class, 'show'])
->defaults('page', 'about-us');
Route::get('history', [PageController::class, 'show'])
->defaults('page', 'our-history');
The Route class is Macroable so you could even create a macro to define these defaults on the route:
Route::get('about-us', [PageController::class, 'show'])
->page('about-us');
The Router itself is also Macroable so you could define a macro to define all of this into a single method call:
Route::page('about-us', 'about-us');
I have created a multilanguage application in laravel and for every route (because i want to see in the url what my language is) i need
www.example.com/{locale}/home
for example, whereas {locale} is the set language and home well, is home. but for every route i need to declare that locale wildcard. is there any way to get this done with middleware or something, to add this before route is executed?
Thanks!
You can use prefix for it.
Route::group(['prefix' => '{locale}'], function () {
Route::get('home','Controller#method');
Route::get('otherurl','Controller#method');
});
And here how you can access it now.
www.example.com/{locale}/home
www.example.com/{locale}/otherurl
For more info.
https://laravel.com/docs/5.8/routing#route-group-prefixes
Not sure if I am understanding your request right, but I believe this is the scope you are looking for:
A generalized route which can receive the "locale" based on which you can serve the page in the appropriate language.
If that's the case, I would define a route like this:
Route::get({locale}/home, 'HomeController#index');
and then in your HomeController#index, you will have $locale variable based on which you can implement your language logic:
class HomeController extends Controller
{
/**
* Show the application homepage.
*
* #return mixed (View or Redirect)
*/
public function index(Request $request, $locale)
{
switch ($locale) {
case 'en':
//do english logic
break;
so on...
}
}
I hope it helps
I have this routing settings:
Route::prefix('admin/{storeId}')->group(function ($storeId) {
Route::get('/', 'DashboardController#index');
Route::get('/products', 'ProductsController#index');
Route::get('/orders', 'OrdersController#index');
});
so if I am generating a url using the 'action' helper, then I don't have to provide the storeId explictly.
{{ action('DashboardController#index') }}
I want storeId to be set automatically from the request URL if provided.
maybe something like this.
Route::prefix('admin/{storeId}')->group(function ($storeId) {
Route::get('/', 'DashboardController#index');
Route::get('/products', 'ProductsController#index');
Route::get('/orders', 'OrdersController#index');
})->defaults('storeId', $request->storeId);
The docs mention default parameter though in regards to the route helper (should work with all the url generating helpers):
"So, you may use the URL::defaults method to define a default value for this parameter that will always be applied during the current request. You may wish to call this method from a route middleware so that you have access to the current request"
"Once the default value for the ... parameter has been set, you are no longer required to pass its value when generating URLs via the route helper."
Laravel 5.6 Docs - Url Generation - Default Values
In my Laravel 9 project I am doing it like this:
web.php
Route::get('/world', [NewsController::class, 'section'])->defaults('category', "world");
NewsController.php
public function section($category){}
Laravel works exactly in the way you described.
You can access storeId in your controller method
class DashboardController extends Controller {
public function index($storeId) {
dd($storeId);
}
}
http://localhost/admin/20 will print "20"
https://laravel.com/docs/5.5/urls#default-values
In the docs it says,
you may use the URL::defaults method to define a default value for this
parameter that will always be applied during the current request.
I don't understand what current request is
I thought it is meant to be used as
route('route-name');
and the url should be generated with the parameters replaced with default values
Also the doc says it has to be done in the middleware
but middleware does operation on the requests but when I use the route helper I do not make any requests
Please help Example would be very helpful
It may be that I miss understood something Please Help
You need to put the logic into a service provider to make it work instead of using middleware:
public function register()
{
\URL::defaults(['some_param' => 'some_value']);
}
Then you'll be able to use route('route-name') without passing a required parameter.
Lets say you have default param which is used with every request of the application, in that case, you have to use middlewares.
like mentioned in the docs https://laravel.com/docs/5.5/urls#default-values
if you just want to pass default values to routes you can do this.
Route::get('user/{name?}', function ($name = defaultValue) {
return $name;
});
hope this helps
I tried to apply the middleware to the following route which require the default value of locale but it did not work.
Route::get('/{locale}/posts', function () {
//
})->name('post.index')->middleware('locale');
// And Inside your Kernel.php
protected $routeMiddleware [
'locale' => \App\Http\Middleware\SetDefaultLocaleForUrls::class, ]
But it actually works if you instead apply this middleware to the Routes or Controllers which uses the route('post.index') method to generate the URL of this route. And then it will fill in the default value of locale which you have set in your middleware.
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.