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
Related
I am having issues getting the page to render when using a parameter in a create controller. My show controller works but my create controller doesn't. The error thrown is a 404.
Sorry, the page you are looking for could not be found.
The URL is:
http://myapp.test/country/us/state/create
My controller looks like:
// Show
public function show(Country $country, State $state){
return view('state.show', compact('state'));
}
// Create
public function create(Country $country) {
return view('state.create', compact('country'));
}
My route looks like:
Route::get('country/{country}/state/{state}', 'StateController#show');
Route::get('country/{country}/state/create', 'StateController#create');
You need to flip your routes around to be
Route::get('country/{country}/state/create', 'StateController#create');
Route::get('country/{country}/state/{state}', 'StateController#show');
Laravel processes routes in the order that they are defined, so in your current code Laravel was seeing create as a state.
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+
What I am looking to achieve here is to have the username set as myapp.com/username. I can achieve this by doing:
/*
* Other route logic, containing static-url pages, such as
* myapp.com/login so that it overrides any usernames
*/
Route::get('/{username}', function($username) {
return $username . "'s profile.";
});
However, I also want to include company pages following the same rule. For example, myapp.com/janes-bakery. But I cannot seem to achieve this because Laravel automatically stops searching for routes if it comes across one that returns nothing. Instead it will just throw a 404 page.
I did think that I could use something similar along these lines:
Route::get('/{slug}', ['as' => 'profile', function($slug) {
$company = \App\Models\Company::where('slug', '=', $slug)->get();
if($company->count() > 0) {
return "Company found.";
}
$user = \App\User::where('username', '=', $slug)->get();
if($user->count() > 0) {
return "User found.";
}
abort(404);
}]);
Which works fine, however I feel as though it's bad practice. Besides that, I cannot access suffix routes based on the company/user. For example myapp.com/jane/friends or myapp.com/janes-bakery/services.
Does anybody have any recommendations on how to go about this? I am finding it very hard to think of any solutions. Thank you in advance!
P.S. It is important the URLs have no correlation, e.g. no myapp.com/company/user (or vice versa), myapp.com/company_name_here and myapp.com/users_name_here are two totally separate things.
You can stick with your route and make another route with company/user pattern. You can do it this way.
Create another route with company and user parameter.
Route::get('{company}/{user}', function($company, $user){
dd($company, $user);
});
And you need to put this route above your profile route because, in laravel, the first route present will be processed before the others routes below.
There will be several high profile links for customers to focus on, for example:
Contact Us # domain.com/home/contact
About the Service # domain.com/home/service
Pricing # domain.com/home/pricing
How It Works # domain.com/home/how_it_works
Stuff like that. I would like to hide the home controller from the URL so the customer only sees /contact/, not /home/contact/. Same with /pricing/ not /home/pricing/
I know I can setup a controller or a route for each special page, but they will look the same except for content I want to pull from the database, and I would rather keep my code DRY.
I setup the following routes:
Route::get('/about_us', 'home#about_us');
Route::get('/featured_locations', 'home#featured_locations');
Which work well, but I am afraid of SEO trouble if I have duplicate content on the link with the controller in the URL. ( I don't plan on using both, but I have been known to do dumber things.)
So then made routes like these:
Route::get('/about_us', 'home#about_us');
Route::get('/home/about_us', function()
{
return Redirect::to('/about_us', 301);
});
Route::get('/featured_locations', 'home#featured_locations');
Route::get('/home/featured_locations', function()
{
return Redirect::to('/featured_locations', 301);
});
And now I have a redirect. It feels dumb, but it appears to be working the way I want. If I load the page at my shorter URL, it loads my content. If I try to visit the longer URL I get redirected.
It is only for about 8 or 9 special links, so I can easily manage the routes, but I feel there must be a smart way to do it.
Is this even an PHP problem, or is this an .htaccess / web.config problem?
What hell have I created with this redirection scheme. How do smart people do it? I have been searching for two hours but I cannot find a term to describe what I am doing.
Is there something built into laravel 4 that handles this?
UPDATE:
Here is my attempt to implement one of the answers. This is NOT working and I don't know what I am doing wrong.
application/routes.php
Route::controller('home');
Route::controller('Home_Controller', '/');
(you can see the edit history if you really want to look at some broken code)
And now domain.com/AboutYou and domain.com/aboutUs are returning 404. But the domain.com/home/AboutYou and domain.com/home/aboutUs are still returning as they should.
FINAL EDIT
I copied an idea from the PongoCMS routes.php (which is based on Laravel 3) and I see they used filters to get any URI segment and try to create a CMS page.
See my answer below using route filters. This new way doesn't require that I register every special route (good) but does give up redirects to the canonical (bad)
Put this in routes.php:
Route::controller('HomeController', '/');
This is telling you HomeController to route to the root of the website. Then, from your HomeController you can access any of the functions from there. Just make sure you prefix it with the correct verb. And keep in mind that laravel follows PSR-0 and PSR-1 standards, so methods are camelCased. So you'll have something like:
domain.com/aboutUs
In the HomeController:
<?php
class HomeController extends BaseController
{
public function getAboutUs()
{
return View::make('home.aboutus');
}
}
I used routes.php and filters to do it. I copied the idea from the nice looking PongoCMS
https://github.com/redbaron76/PongoCMS-Laravel-cms-bundle/blob/master/routes.php
application/routes.php
// automatically route all the items in the home controller
Route::controller('home');
// this is my last route, so it is a catch all. filter it
Route::get('(.*)', array('as' => 'layouts.locations', 'before' => 'checkWithHome', function() {}));
Route::filter('checkWithHome', function()
{
// if the view isn't a route already, then see if it is a view on the
// home controller. If not, then 404
$response = Controller::call('home#' . URI::segment(1));
if ( ! $response )
{
//didn't find it
return Response::error('404');
}
else
{
return $response;
}
});
They main problem I see is that the filter basically loads all the successful pages twice. I didn't see a method in the documentation that would detect if a page exists. I could probably write a library to do it.
Of course, with this final version, if I did find something I can just dump it on the page and stop processing the route. This way I only load all the resources once.
applicaiton/controllers/home.php
public function get_aboutUs()
{
$this->view_data['page_title'] = 'About Us';
$this->view_data['page_content'] = 'About Us';
$this->layout->nest('content', 'home.simplepage', $this->view_data);
}
public function get_featured_locations()
{
$this->view_data['page_title'] = 'Featured Locations';
$this->view_data['page_content'] = 'Featured properties shown here in a pretty row';
$this->layout->nest('content', 'home.simplepage', $this->view_data);
}
public function get_AboutYou()
{
//works when I return a view as use a layout
return View::make('home.index');
}
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 ...
}