Same url for different routes laravel - php

I have this two routes
Route::get('/books/{book}', 'FrontEnd\BooksController#show');
Route::get('/books/{main_category}', 'SearchController#getProducts')->name('getProducts');
Is there any way I can make both running ..

When the urls got the same parameter types/length or any other structure, there is no way to distinguish them.
But when there are differences you can use regular-expression-constraints.

You can't make them both running, as Laravel can't differentiate between these route, since they basically have the same URL. If both of your controllers show results on the same page (ex: books index), a workaround could be to make one route, with an optional parameter:
Route::get('/books/{book}/{main_category?}', 'FrontEnd\BooksController#show');
Then you can lead both routes to the same method, and make queries there depending on the parameters you get:
public function show(Request $request){
$books = Book::query(); //initiate query on Book model
if($request->book){
$books = $books->where('...'); //Override the query with new results using book parameter
}
if($request->main_category){
$books = $books->where('...'); //Override the query with new results using book main_category
}
$books = $books->get(); //Retrieve all the results
}
Note: This is not tested, just a quick idea how you could improve your code and use one controller with one method to show book results, instead of using two different controllers. Hope I could give you some ideas with this.
Here you can read more about Laravels optional parameters.

How is the Router supposed to know which route you meant with /books/Harry Potter - And The Goblet of Fire or /books/Fantasy? There is no way to distinct these routes from each other.
Your best bet would be to use query parameters to filter the books - e.g.
/books/?name=Harry Potter - And The Goblet Of Fire
/books/?category=Fantasy
But the /books/{whatever} should be reserved for the primary key of a book. So you could do something like /books/1/author or /books/32784893/ratings.
The same route would only work if you can distinguish the values for sure (as Pilan stated in his answer).

Related

It is possible to pass 2 differents types of parameters to a Laravel controller?

I already have a GET route with an URI /projects/{id} which displays Infos of a project with a given id. I also have a GET index route (/projects), which shows all my projects.
My problem is that I currently try to create different indexes (for example one which only displays the projects where I am assigned [e.g. on /projects/mines], or the projects which are pending administrator approval [e.g. on /projects/proposals], and still others displays).
So I want to know if I can have two GET routes /projects/{id}and /projects/{display_mode} which will be calling two differents methods of my ProjectController (respectively show and index).
Thanks for your help! :)
You may have one route /projects which returns all projects as default.
If there is query parameter like
/projects?displayMode=proposals
then you can apply filters.
In your controller it would look something like this
$projects = Project::query();
if ($request->query('displayMode') == 'proposals')
$projects->where('pending', true)
return $projects->get();
You can add multiple filters too in the same way
I'm not sure about specific Laravel options for the route definitions (sorry!), but if the {id} will always be an integer and {display_mode} will always have non-digits in it, you could keep just one route, but do the conditional handling in your controller. Just have the mainAction do something like…
return preg_match('/^\d+$/', $param) ? idHelperAction($param) : displayModeHelperAction($param);
Then create those two helper functions and have them return whatever you want.
$param is supposed to be whatever you get from that route parameter -- /projects/{param}.
That should call the idHelperAction for routes where $param is all digits and nothing else; otherwise, it should call the displayModeHelperAction. Either way, it sends the same $param to the helper function and returns whatever that helper function returns -- effectively splitting one route definition into two possible actions.
Of course, you might have to add some context in the code sample. If the functions are all defined in the same class, you might need to use $this->idHelperAction($param) or self::idHelperAction($param) (and the same with the other helper action), depending on whether it's static or not; or tell it where to find the functions if you put them in another class, etc., etc. -- all the normal contextual requirements.

check parameters type before run route in laravel 5

I have 2 kind on route.
like this:
You know for these:
Route::get('/{category_slug}/{article_slug}', 'mController#list');
Route::get('/{category_slug}/{subcategory_slug?}', 'mController#clist');
It run only first route.
I try binding them in RouteServiceProvider boot(){
Route::bind('category_slug', function ($category_slug, $route) {dd('category_slug') }); //works
Route::bind('article_slug', function ($article_slug, $route) { dd('article_slug') }); //works for both article_slug(ok!) and subcategory_slug(wrong!)
Route::bind('subcategory_slug', function ($subcategory_slug, $route) { dd('subcategory_slug') }); //not works
}
Is there a way to check {article_slug} or {subcategory_slug} before loading route and then system choosing right route? for example if first is wrong, then skip it and try to run second route.
for example middleware can do that?
You need to use different url or different method of request in order to fulfil your demand.
Like -
Route::get('/{category_slug}/{article_slug}', 'mController#list');
Route::post('/{category_slug}/{subcategory_slug?}', 'mController#clist');
Use Route::update() if need to modify a data which is already in database or Request::delete() to delete a data in the database.
Or like the answer of tprj29 you need to use different kinds of url
In Laravel slugs are unique per table not unique throughout all tables. I would recommend using something like a keyword to determine what slug is expected. This is way more efficient and cleaner then querying to determine if the slug is of an type article or category of object.
Route::get('/{category_slug}/', 'mController#clist');
Route::get('/{category_slug}/sub/{subcategory_slug}', 'mController#clist');
Route::get('/{category_slug}/sub/{subcategory_slug}/{article_slug}', 'mController#list');
Route::get('/{category_slug}/{article_slug}', 'mController#list');

Nested Controllers and routes

I'm creating a dashboard where the user can create Clients
Each Client will have: Categories, Employees, ...
Now I'm wondering how to structure the routes.
For example if I create the following: (pseudo code)
Route::get('clients/{id}/');
Route::get('clients/{id}/categories');
Route::get('clients/{id}/categories/{category}');
Route::get('clients/{id}/categories/{category}/questions/{question}');
This seems like a lot of unnecessary parameters..
How do you guys go about this? I really want to split the categories on a seperate page, the employees on a seperate page.
Thank you.
in all of my projects, i avoid using a lot of nested entities in the URL, so i access each one apart, this was also recommended by #jeffrey_way at Laracasts, the training website for laravel.
so, i would do the following:
Route::get('clients/{id}/');
Route::get('categories/{client_id}');
Route::get('categorie/{category}'); //not that i have removed the plural s from categorie(s)
Route::get('question/{question}');
Good luck
It honestly depends on how big your application is going to become, I would probably group them, so still keeping the same structure.
Route::group('clients/{id}', function()
{
Route::get('/');
Route::group('categories', function()
{
Route::get('/');
Route::get('{category}');
Route::get('{category}/questions/{question}');
})
})
Same as yours but I feel it a little cleaning for later if you expand on the categories or clients.
Here in such case I would rather prefer to use only one route will all parameters as in GET method. So, I would have add just one param as bellow:
Route::get('client/create', 'ClientController#store');
So, all the parameters will be maintained by the store method of ClientController like below:
public function store(Request $request){
$category = $request->get('category')
//......
//get other get parameters like this when required
}
When I need to trigger this route I would just do something like below:
Create link
As you know, we can pass our parameters here using our old global friend GET variable.

pagination and factory in laravel4

Consider this code taken from here.
public function getIndex()
{
$posts = Post::orderBy('id','desc')->paginate(10);
// For Laravel 4.2 use getFactory() instead of getEnvironment() method.
$posts->getEnvironment()->setViewName('pagination::simple');
$this->layout->title = 'Home Page | Laravel 4 Blog';
$this->layout->main = View::make('home')->nest('content','index',compact('posts'));
}
As I understand it, pagination limits the number of rows, so I think paginate(10) means select first ten rows in the database. But I absolutely don't understand this.
// For Laravel 4.2 use getFactory() instead of getEnvironment() method.
$posts->getEnvironment()->setViewName('pagination::simple');
or
$posts->getFactory()->setViewName('pagination::simple');
And everything below. Mainly I don't understand what factory means and how it relates to pagination. I went to the laravel docs on Illuminate\Pagination\Factory and Illuminate\View\View but I can't find the meaning of factory. Can anyone explain the code above?
You are essentially setting how the pagination is output in HTML by selecting a specific paginator view, this allows you to have more than one type in an application or use different to the default.
Using multiple pagination types in the same application
Sometimes, you may want to use different pagination types across your
application. By default, Laravel will use the type specified in your
app/config/view.php file, so you need to override this setting when
you wish to use another type. Here is how to do so.
// This code should be in a controller or a route Closure.
// Let’s use the good old example of a list of blog posts.
$articles = Article::paginate(5);
Paginator::setViewName('pagination::simple');
/*
Alternatively, you could also use this to achieve the same result:
$articles->getEnvironment()->setViewName('pagination::simple');
For those who would like to know what’s happening under the hood, here is a more
detailed explanation:
1. Calling paginate() on an Eloquent model or a query builder will return an
instance of \Illuminate\Pagination\Paginator
2. Then, we need to get the related \Illuminate\Pagination\Environment of this
paginator via the well-named getEnvironment() method.
3. Finally, we can specify the pagination type we need. The default value is
'pagination::slider'.
The pagination types that are available by default are located in the
vendor/laravel/framework/src/Illuminate/Pagination/views directory.
*/
Source: http://laravel-tricks.com/tricks/using-multiple-pagination-types-in-the-same-application

How to define routes with multiple parameters without pretty urls in Laravel

I am using Laravel. I would like users to be able to perform a search on my website using up to 3 criteria. These criteria are: Class, Brand and Model.
They should be free to use any or all of them when searching. As the relationship between these isn't as simple as Many->1, Many->1, Many->1, and also given the criteria will be numbered if blank, I dont want to use pretty urls to post the search criteria as they would look like this:
/SearchResults/0/BMW/0
which is meaningless to users and search engines. I therefore want to use normal dynamic addresses for this route as follows:
/SearchResults/?Class=0&Brand="BMW"&Model=0
How do I define a route that allows me to extract these three criteria and pass it to a custom method in my resource controller?
I have tried this but it isnt working:
Route::get('/SearchResults/?Class={$class}&Brand={$brand}&Model={$type}', 'AdvertController#searchResults');
Many thanks
The Symfony Routing components fetch the REQUEST_URI server variable for matching routes, and thus Laravel's Route Facade would not pick up URL parameters.
Instead, make use of Input::get() to fetch them.
For example, you would start by checking if the class param exists by using Input::has('class'), and then fetching it with Input::get('class'). Once you have all three, or just some of them, you'd start your model/SQL query so that you may return your results to the user.
You will need to route all to the same method and then, within the controller, reroute that given action to the correct method within the controller.
For that, I recommend using the strategy pattern (read more here).
I would do something like this:
route.php
Route::get('/SearchResults', 'AdvertController#searchResults');
AdvertController.php
use Input;
...
private $strategy = [];
public function __construct(){
$strategy = [
/*class => handler*/
'0'=> $this->class0Handler,
'1'=>$this->class1Handler,
...];
}
private function class0Handler(){
//your handler method
}
public function searchResults(){
if( !array_key_exists(Input::get('class'),$this->strategy))
abort(404);
return $this->strategy[Input::get('class')]();
}
In case you are breaking down search by other types, you define the handler in the $strategy variable.
Strategy pattern has a lot of benefits. I would strongly recommend it.

Categories