In Laravel 5.2, is there a particular way (handler) to check whether a route is existing or not? Let's say, for a basic URL like:
http://www.example.com/laravel
I then want to handle the non-existing URLs (like: /laravel) from my Main Page Router, which is:
Route::get('/{page}', funtion(){
//check if $page is a valid route URL? Or 404?
});
How do I purposely check whether this route is a valid one or not?
I use the following as my last route:
Route::any('{catchall}', function($page) {
abort(404);
} )->where('catchall', '(.*)');
If you are not aware yet, abort(404) will return the view 404.blade.php from resources/views/errors.
Simply put your Route::get('/{page}','MainController#getPage'); last. That way if it finds another route before it will use it but if it doesn't then it will get caught by this. For example:
Route::get('/welcome','WelcomeController#getWelcome');
Route::get('/test','TestController#getTest');
Route::get('/{page}','MainController#getPage');
If you were to hit /welcome or /test it should route them to the correct controller. If you where to hit /hello it should go to the MainController and hit function getPage($page) with $page being the page you hit.
If it hits MainController#getPage you know it was basically a 404.
If you need to know before you hit the route for some reason you could create something like this:
Route::get('/checkurl/{page}',function($page) {
$exists = Route::has('/' . $page);
return (new Response(json_encode(['exists'=>$exists]),200);
});
Adding last route with any catch doesn't works anymore with laravel 5.5.1+
Related
I have the following routes in Laravel. I wanna be able to call both countries as well as pages on the "root" of the domain, not with any directory prefix.
What I want to achieve is that when no page is found in the eloquent model, that it tries to go open the country and if that fails as well then show a 404.
Is that possible and what do I need to change?
Route::get('/{page}', 'PageController#view')->name('pages.view');
Route::get('/{country}', 'CountryController#view')->name('countries.view');
Edit: I think I was a bit unclear.
The issue is, that the countries.view route is never reached because it fails before with pages.view. Let's say I call /germany - it first matches the pages.view route but no page germany exists. It immediately throws a 404 but I want it to check the country after that and only fail if /germany doesn't exist as a country as well.
How about being agnostic?
one route, you test the parameter, then returning the proper result.
Route::get('/{pageOrCountry}',function($pageOrCountry){
$page = App\Page::find($pageOrCountry);
if($page) return $page;
else $country = App\Country::find($pageOrCountry);
if($country) return $country;
else return redirect('404');
});
There are several ways I will mention two ways:
1- Route Model Binding :
inside page controller create function
public function view(Page $page){
}
this function will return not found if page does not exists
2- Normal check :
public function view($page){
$check= Page::find($page);
if(!$check) abort(404);
}
create resources/views/errors/404.blade.php folder and define 404 error message
I've 2 routes in my web.php
1) Route::get('/{url}', 'MenuController#menu');
which provide url :
/menu
2) Route::get('/{name}', 'HomeSlideviewController#index')->name('promotiondetail');
which provide url :
/menu (different page but same name in route 1)
/food
I want to use 2 route if route = same name I want to use route 1 if route 1 dont have url It will use route 2 . In web.php is their anyway to do something like
if(Route::get('/{url}', 'MenuController#menu')) is null use
`Route::get('/{name}', 'HomeSlideviewController#index')->name('promotiondetail');`
now in my web.php I do this
Route::get('/{url}', 'MenuController#menu');
Route::get('/{name}', 'HomeSlideviewController#index')->name('promotiondetail');
when I go /food It will go page not found.
UPDATE
In my controller I try this
try {
// if find url
}
} catch (\Exception $e) {
//if not find url
return redirect()->route('promotiondetail', $url);
}
and It return Error redirected you too many times
UPDATE 3
$url = food
Your problem is that when you use
Route::get('/{url}', 'MenuController#menu');
Route::get('/{name}', 'HomeSlideviewController#index')->name('promotiondetail');
you are having the same request because {url} or {name} are optional parameters and what happens is that it will always match the first case. The best solution for you can be using this part of code:
Route::get('/menu', 'MenuController#menu');
Route::get('/{name}', 'HomeSlideviewController#index')->name('promotiondetail');
You should always have the one with only optional parameters last, because otherwise it will always be executed first because it will be matching. And what you should remember is that using /{name} it will match anything, it is like a variable and can contain a number also it can be a string, for instance a url might be domain/{anything}. If you use /name it will match only if you are having domain/name as request.
You might want to read Laravel routing for more information about routing.
The problem you have is that both routes are essentially the same, /{something}.
You have a couple of solutions.
Firstly, sort out your routes, make them slightly different so they don't match each other and correct the order.
For example;
Route::get('/promo/{name}', 'HomeSlideviewController#index')->name('promotiondetail');
Route::get('/{url}', 'MenuController#menu')->name('menu');
Another solution that may work for you is to place the promotiondetail route first, and do a check in that for the same name, if not then redirect to the other controller. So in your index function of HomeSlideviewController, try something like;
public function index($name) {
if ($name !== 'whatever you want it not to be') {
return redirect()->route('menu);
}
// continue
}
When I have this named route:
Route::get('/', 'IndexController#index')->name('home');
Then in any action method of any Controller; when I need to redirect to the named route home; any of these statements redirects properly to the intended route:
return redirect('/');
return redirect()->route('home');
return redirect()->home();
When to use each?
What are the differences?
Are there any benefits of using one over the others?
As the documentation mention :
When you call the redirect helper with no parameters, an instance of
Illuminate\Routing\Redirector is returned, allowing you to call any
method on the Redirector instance. For example, to generate a
RedirectResponse to a named route, you may use the route method
As you can see in the API methods(link below) there is a lot of methods that you can use and also there is one specific helper method home() it's just a shortcut for redirect()->route('home') as highlighted by #ceejayoz.
Now the we will talk about return redirect('/'); and return redirect()->route('home'); the two of them redirects properly to the intended route as you said BUT the second one is really useful if in the future.
Why ?
Because if you want to change the URL structure in the routes file all you would need to change is the route only for example :
Route::get('/', 'IndexController#index')->name('home');
Will be :
Route::get('/home_page', 'IndexController#index')->name('home');
and all the redirects would refer to that route and there is no other thing that you should change => all redirects will still work perfectly.
BUT
If you choose to use the first one (i mean return redirect('/');) then after the change in the route you will need to parse all your controllers to check if there is some redirects that uses then changed route and the change them :p
redirect()->home() is simply a shortcut for redirect()->route('home'). The source code can be seen here.
Named routes are generally better than raw URLs for maintainability purposes. The home route isn't all that likely to change location, but it is possible that you might host a Laravel app in a subfolder, or move the home page from / to /app to make room for a marketing landing page at the root.
redirect('/')
It redirects you to the base URL.
redirect()->route('home')
Redirects to the route named home.
See More about named routes here.
redirect()->home();
Alternative way to redirect to named route.Redirects to 'home' route as well. It does the same thing as above but with slightly different syntax.
I preferred named routes over raw URLs, because if you decide to change the URL later on, you have to make changes into your routes file only.
When you are passing a string it will redirect a user to the domain plus the string you pass.
http://localhost:3000 + string
It will also add / if you forget it, now if you name your routes like you did then you can call it by the name.
An advantage of using named routes is in case you want to change the URI you can do it without worrying about changing a bunch of ahref in your view, redirects in your controllers, etc.
home() is a method from Laravel's Redirector or redirect() so, I don't think you can just call a named route as a method.
I've been reviewing the documentation for October CMS routing (https://octobercms.com/docs/plugin/registration#routing-initialization), but I think that I am missing something. I have a page called 'deals' that renders some basic information along with a plugin (called 'deals') component. The page normally appears at the url:
http://www.example.com/deals
However, I want to create a route so that if someone visits the url:
http://www.example.com/deals2
it will automatically route them back to
http://www.example.com/deals
I know that I should create a routes.php file in my plugin directory. However, when I try using
Route::get('/deals2', function()
{
return View::make('deals');
});
It complains that it can't find the 'deals' view. What am I doing wrong?
Additionally, how can I route it so that my homepage
http://www.example.com
would route to
http://www.example.com/deals
In OctoberCMS, and Laravel which it's based on, to redirect one route to another you can do this:
// Redirect /deals2, /deals3, ... to /deals
Route::get('{dealSlug}', function($dealSlug) {
return redirect('deals');
})->where('dealSlug', '^deals[0-9]+');
// Redirect homepage to /deals
Route::get('/', function() {
return redirect('deals');
}
The first route uses a route parameter with a regex constraint and will redirect any request that starts with /deals and ends with a number to your /deals route. That means it will route /deals1, /deals2, /deals3, etc to /deals.
The second route will redirect your homepage to /deals.
Of course, redirecting will cost an extra request. If you don't want to do that, then you could do the redirect in Apache or Nginx.
As per your comment, if you wanted to redirect /deals[any-number]/[anything] to /deals/[that-same-anything] then you would add an optional route parameter to the first route. That would look like this:
// The new first route
Route::get('{dealSlug}/{extra?}', function($dealSlug, $extra = '') {
return redirect('deals/' . $extra);
})->where('dealSlug', '^deals[0-9]+');
Of course, if that /deals/[anything] route doesn't exist, then you'll get a 404.
Try
Route::get('/deals2', function(){return Redirect::to('/deals')}); which will redirect the browser at the cost of an extra request.
If I have a controller called articles, which has a method called view_articles, a user can type in http://example.com/articles/view_articles/some-post and have it return a page.
I have specified a route to be http://example.com/article/post-name. How can I make it so that only the URL specified in the route is visible? Is there a way for articles/view_articles/some-post to show a 404 instead of showing the same page as the route URL?
I am trying to prevent duplication for SEO purposes.
You can always make default routing to a 404 page by correctly defining routes in your routes.php file:
$routes['article/(:any)'] = 'articles/view_articles/$1';
$routes['(:any)'] = 'main/e404';
As stated by CodeIgniter user guide:
Routes will run in the order they are defined. Higher routes will always take precedence over lower ones.
So you can basically define all you want to be seen at the beginning of the file and block everything else on the last line.
As for your main(can be any other) controller's 404 method -
function e404() {
show_404();
}
Use $this->uri->segment(n) as part of the URI class inside of view_articles to redirect traffic to your route if the URI contains view_articles as it's second segment.
I'v done that in other tricky way, first of all you should add some code to __construct function in sys/core/Controller.php
you can check whether the requested url is in routes or not by this code
if(!isset($this->router->routes[uri_string()])){
show_404(); // Or whatever you want ...
}