Route group with optional parameter - php

I'm wondering if it is possible to use optional parameters in a group prefix.
Using it with {parameter?} like in any other route doesn't work:
Route::group(array('prefix' => 'foo/{foo_id?}'), function() {
Route::any('bar', 'ApiFooController#bar');
});
I would like to catch both foo/bar and foo/2/bar.
As much as I can see, it only works without the questionmark but then foo/bar(without the parameter) throws an error.
I would like to avoid defining two seperate groups which would be a workaround. Maybe Important to note: bar is a custom function in addition to a resource so I'm not trying to define a resource (like foo.bar).

I think you might have to define the route twice, but you don't have to create another group.
Does this work for you?
Route::group(array('prefix'=>'foo'),function() {
Route::any('bar', 'ApiFooController#bar');
Route::any('{foo_id}/bar', 'ApiFooController#bar');
});

Related

Escape forward slash in laravel

I have dozens of routes like the following list
Route::group([
'where' => ['aNumber' => '.*'],
], function () {
Route::get('air/{aNumber}/tools', 'AirController#tools');
Route::post('air/{aNumber}/handled', 'AirController#handled');
Route::post('air/{aNumber}/notHandled', 'AirController#notHandled');
Route::get('air/{aNumber}/act', 'AirController#act');
Route::post('air/{aNumber}/sendAct', 'AirController#sendAct');
Route::get('air/{aNumber}', 'AirController#show');
});
the {anumber} parameter could be like these 23-349493/4 While this kind of parameter will produce some conflicts with other routes, So for example if we are going to call air/28-23422/sendAct then instead of calling #sendAct route, it'll call #show.
because laravel thinks that /sendAct is part of the parameter. Well, I can fix this problem by adding more where not(Regex) on each of the routes and define the logic that every route should follow, But do you have a better solution for this problem?
No, you are wrong, Laravel will choose show since air/28-23422/sendAct won't hit sendAct because sendAct has as supposed method POST, and not GET.
Instead of:
Route::post('air/{aNumber}/sendAct', 'AirController#sendAct');
try writing
Route::get('air/{aNumber}/sendAct', 'AirController#sendAct');
// ^^^
Or use ^[^\/]* as where clause of the group for aNumber

How to use optional route parameters properly with Laravel 5.6?

I am trying to create an API with Laravel 5.6, however, it seems to me that it's not possible to use optional route parameters before/after the parameter.
I'd like to achieve the following:
Route::get('api/lists/{id?}/items',
[
'as' => 'api/lists/items/get',
'uses' => 'ListsController#getListItems'
]);
With the above scenario, if I'm trying to visit api/lists/1/items it shows the page. On the other hand, if I'm trying to visit api/lists/items it says that the page is not found.
What I basically want is if there's no List ID specified, Laravel should fetch all the List ID's items, otherwise it should only fetch the specific ID's items.
Q: How is it possible to the optional parameter in between the 'route words'? Is it even possible? Or is there an alternative solution to this?
As far as I know, it's not possible to use optional parameters in the middle of your url.
You could try a workaround by allowing 0 for the optional parameter and loading all items in this case, as described here.
However, I'd recommend going with two different routes here to match everything you want:
api/lists/items
api/lists/{id?}/items
You have to give default value for optional parameter in the controller:
Route
Route::get('api/lists/{id?}/items', 'ListsController#getListItems');
ListsController
public function getListItems($id = null) {
---your code----
}
Reference

Laravel 4 routing - the ability to skip a route if conditions are not met

So we have a load of content within the database, let's call these Articles. The paths for the Articles start from the application root and can contain slashes. So we want to search the DB to see if we match an Article, and if not skip the route and give other routes the opportunity to respond.
In Sinatra (which I believe has inspired the routing within Laravel) you have the option to pass to the next route. It might be this that's leading me astray.
Route::get( '{uri}', function( URI $uri ) {
// check database, if we find a record we'll need to pass it to the appropriate controller
// we'll have a class that handles this responsiblity
// pass if we don't find anything
} )->where('uri', '.*');
Route::get( 'other/page', 'OtherController#sayHello' );
The issue Allow skip the route based on conditions #1899 talks about this, although I can't see how filters cater for this, they will simply intercept and give you an opportunity to stop route execution (throw exception, redirect to route specifically etc.), you can't return FALSE; without error. There is an example chaining a condition method to a route, although this method doesn't seem to exist (in 4.2).
Any ideas?
In addition to this, we're also are thinking about containing this logic within a package so it can be shared across applications, and wonder if you can influence the order of execution of routes provided by package?
You can have a group of routes, which you contain within all the routes that match it. If it fails that group then it skips to the next section.
Route::group(array('before' => 'auth'), function()
{
Route::get('/', function()
{
// Has Auth Filter
});
Route::get('user/profile', function()
{
// Has Auth Filter
});
});
http://laravel.com/docs/4.2/routing

Laravel Route Controller with Forced Parameter

So i have checked out
PHP - Routing with Parameters in Laravel
and
Laravel 4 mandatory parameters error
However using what is said - I cannot seem to make a simple routing possible unless im not understanding how filter/get/parameters works.
So what I would like to do is have a route a URL of /display/2
where display is an action and the 2 is an id but I would like to restrict it to numbers only.
I thought
Route::get('displayproduct/(:num)','SiteController#display');
Route::get('/', 'SiteController#index');
class SiteController extends BaseController {
public function index()
{
return "i'm with index";
}
public function display($id)
{
return $id;
}
}
The problem is that it throws a 404
if i use
Route::get('displayproduct/{id}','SiteController#display');
it will pass the parameter however the URL can be display/ABC and it will pass the parameter.
I would like to restrict it to numbers only.
I also don't want it to be restful because index I would ideally would like to mix this controller with different actions.
Assuming you're using Laravel 4 you can't use (:num), you need to use a regular expression to filter.
Route::get('displayproduct/{id}','SiteController#display')->where('id', '[0-9]+');
You may also define global route patterns
Route::pattern('id', '\d+');
How/When this is helpful?
Suppose you have multiple Routes that require a parameter (lets say id):
Route::get('displayproduct/{id}','SiteController#display');
Route::get('editproduct/{id}','SiteController#edit');
And you know that in all cases an id has to be a digit(s).
Then simply setting a constrain on ALL id parameter across all routes is possible using Route patterns
Route::pattern('id', '\d+');
Doing the above will make sure that all Routes that accept id as a parameter will apply the constrain that id needs to be a digit(s).

RESTful trailing slash routes in laravel

I have the following routes in my Laravel 3 RESTful api project
Route::delete('/(:any)', 'resources#destroy');
Route::delete('users/(:any)', 'users#destroy');
The problem I am having is when a user sends a delete request to /users/
What I want to happen is that the users#destroy route is called with parameter null. In my controller I have an exception for a user trying to delete a null resource.
What seems to be happening is that the resource#destroy route is called with parameter users. This obviously has the undesired affect of deleting the users resource.
I know I could modify my .htaccess but technically /users/ does belong to the users controller not the resources controller. I want to maintain that relationship.
I was wondering if there is a simple way to solve this from within Laravel?
EDIT: have the above working with the answer below. Now I have an error in my get routes
Route::get('users/(:any?)', 'users#show');
Route::get('users', 'users#index');
/users and /users/ both call users#index which I don't want.
I need GET /users to go to users#index and GET /users/ to go to users#show with null parameter
I worked around the trailing slash by adding a filter to my routes
Route::group(array('before' => 'trailingslash'), function()
{
//routes in here
});
Route::filter('trailingslash', function() {
$current = URI::full();
if(substr($current, -1) == '/'){
return return Response::error('404');
}
});
one point you need to consider.
Routes are defined without a front-slash. The only exception to this is the default route which is represented with only a front-slash.
so Route::delete('/(:any)', 'resources#destroy') will cause undesired result.
Moreover, your order is wrong.
(:any) will match user too and will send the request to resources controller.
so what you need to do is,
change the order (make it reverse).
change the route of resources considering according to the rules. like resources/delete etc.....
What I want to happen is that the users#destroy route is called with parameter null. In my controller I have an exception for a user trying to delete a null resource.
to do this, (after making the changes above....)
change the route of user/(:any) to user/(:any?) which will make the 2nd segment optional.
After that, straight forward.
$foo = URI::segment(2, null);
//Rest will follow.
EDIT
Now, the following code,
Route::get('users/(:any?)', 'users#show');
Route::get('users', 'users#index');
does not make any sense.
if i type user, what the router is suppose to take?
user#show with no optional segment or user#index?
Routes are design so that it removes the ambiguity. You are going in the opposite direction with making it all ambiguity.
just make a simple route.
like show
user/show
delete
user/delete
edit
user/edit
etc....
The type of routing you are applying is confusing for both users and developers as it carries ambiguity.

Categories