Laravel - subdomain routing not working as expected - php

I have three routing files inside routes folder:
web.php
api.php
admin.php
I've registered the file admin.php inside boot() method of RouteServiceProvider as following:
public function boot() {
$this->configureRateLimiting();
$this->routes(function () {
Route::domain("admin." . env("APP_URL"))
->namespace($this->namespace)
->group(base_path("routes/admin.php"));
Route::domain("api." . env("APP_URL"))
->middleware("api")
->namespace($this->namespace)
->group(base_path("routes/api.php"));
Route::middleware("web")
->namespace($this->namespace)
->group(base_path("routes/web.php"));
});
}
Let's say i've defined the following route in web.php:
Route::get("test", function() {
return "Hello from website route";
});
If i try to access this route using mywebsite.com/test it acts like expected.
However, if i try to access the link admin.mywebsite.com/test it would still some how falls back to mywebsite.com/test and give the exact same output.
What's the problem here ?

Because web.php is not restricted to a domain. As a consequence, the routes defined there are accessed by every domain that targets your laravel application.
If you only want the root domain to access the routes defined in your web.php, you could specify it in the RouteServiceProvider:
Route::middleware("web")
->domain(env("APP_URL")) // Add this line
->namespace($this->namespace)
->group(base_path("routes/web.php"));

Related

Target class [Admin\UserController] does not exist

I have separated my project routes into home.php that contains the client-side routes and admin.php that contains server-side routes.
So here is my RouteServiceProvider.php:
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web/home.php'));
Route::middleware(['web', 'auth.admin'])
->namespace($this->namespace . '\Admin')
->prefix('admin')
->group(base_path('routes/web/admin.php'));
});
}
So as you see I have specified ->namespace($this->namespace . '\Admin') because of Admin Controllers that are placed in this directory:
App\Http\Controllers\Admin\...
Then in the admin.php, I added this route:
Route::resource('users', UserController::class);
But I get this error:
Target class [Admin\UserController] does not exist.
So what's going wrong here? How can I solve this issue and properly call the Controller from Admin?
You might need to add a use statement to point out where your controller lies within the route file.
For example:
use App\Http\Controllers\Admin\UserController;
The namespace changes are correct.
The problem is a missing using.
So to correct it, change in your route file:
use App\Http\Controllers\Admin\UserController; // <-- add this.
Route::resource('users', UserController::class);
You need to adjust this for the RouteServiceProvider.php:
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
Route::middleware('web')
->namespace('\App\Http\Controllers')
->group(base_path('routes/web/home.php'));
Route::middleware(['web', 'auth.admin'])
->namespace('\App\Http\Controllers\Admin')
->prefix('admin')
->group(base_path('routes/web/admin.php'));
});
}
And then you can run this:
Route::resource('users', 'UserController');

What is the best practice to add domain based routing in Laravel?

I'm working on a multitenant, multidomain Laravel project and of course the base of the software is the same for all users, but I have several users who asking me very specific things and don't want to build these features into the main codebase.
I separated the models, controllers, and migrations to namespaces like this:
app/Models/ClientSpecific/{ClientName}/{ModelName}
app/Http/Controllers/ClientSpecific/{ClientName}/{ModelName}Controller
database/migrations/client-specific/{ClientName}/{MigrationFile}
Going along this logic I want to add routes and I want to store it in separate files too:
routes/client-specific/{domainname.com}/api.php
routes/client-specific/{domainname.com}/web.php
routes/client-specific/{anotherdomain.com}/api.php
routes/client-specific/{anotherdomain.com}/web.php
routes/client-specific/{thirddomain.com}/api.php
How can load these route files only that domain what is called and only there? Is there any best practice to add domain based routing in Laravel? Or just add a domain check to the RouteServiceProvider.php based on $_SERVER['SERVER_NAME'] ?
I suggest you store your domains in the .env file. That's will allow you to configure them in different environments.
APP_CLIENT_DOMAIN=client.com
APP_ADMIN_DOMAIN=admin.com
APP_DEVELOPER_DOMAIN=developer.com
Then, you can define different RouteServiceProviders for each domain, where each service provider will provide api.php and web.php routes for each domain.
Example:
This will be your BaseRouteServiceProvider:
abstract public function getDomain();
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace(
$this->namespace."\".Str::toCamelCase($this->getDomain()))
->group(base_path('routes/'.$this->getDomain().'/web.php'));
}
protected function mapApiRoutes()
{
Route::middleware('api')
->namespace(
$this->namespace."\".Str::toCamelCase($this->getDomain()))
->group(base_path('routes/'.$this->getDomain().'/api.php'));
}
Then you can define FirstDomainServiceProvider, SecondDomainServiceProvider, and more. In most cases, they will look like:
public function getDomain() {
returt env('APP_CLIENT_DOMAIN')
}
I created this solution, but maybe there is a better way. If you found it, please post it.
Thanks!
I changed the code in the RouteServiceProvider.php to this:
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
// load client sepcific routes
$host = request()->getHost();
if (isset($host)) {
try {
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/client-specific/'.$host.'/api.php'));
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/client-specific/'.$host.'/web.php'));
} catch (\Throwable $th) {
// do nothing
}
}
});
}

root route problem in laravel 6.2 RouteServiceProvider

i have defined these two different routes in laravel RouteServiceProvider like this:
protected function mapABCRoutes()
{
Route::prefix('abc')
->middleware('web')
->namespace($this->namespace)
->group(base_path('routes/abc.php'));
}
protected function mapXYZRoutes()
{
Route::prefix('xyz')
->middleware('web')
->namespace($this->namespace)
->group(base_path('routes/xyz.php'));
}
and i defined a route in abc.php
Route::get('/', function(){ return '<h1>ABC Admin</h1>'; })->name('abc.dashboard');
all defined routes in abc.php are working as well except route('abc.dashboard'). it throws a 404 with message "The requested resource /abc was not found on this server."
same thing resulting for xyz.php im working with all of this things in an ubuntu using laravel 6.2 in apache with mod rewrite enabled. i cant understand why these routes are not working? but the same type route works as well on laravels default route in web.php
Route::get('/', function () { return view('auth.login'); });
Route groups doesn't mean you can override the similar routes multiple time, it usually helps to clean the routes files. For instance, I've created separate route files for some of my main modules and put into their respective route files and map in RouteServiceProvider.
As you're using web routes here, What you can do here to prefix routes likeso,
for xyz.php
Route::group( [
'prefix' => 'xyz'],
function ( Router $api ) {
//your routes
});
and similar could be done for abc.php and so on.
Not Sure... it's may help you...
Route::group(['prefix' => 'abc'], function(){
Route::get('/', function(){ return '<h1>ABC Admin</h1>'; })->name('abc.dashboard');
});

How to add multiple route file using RouteServiceProvider in laravel

I want to create module wise route file and load all route files using RouteServiceProvider mapApiRoutes(). I have created category.php file and admin.php file which contains routes within it. Now i want to load this two file's routes in api.php file.
Below is code that i am using to do this but it is not working. it only process routes in admin.php. when i use route of category.php it shows me error of "Sorry, the page you are looking for could not be found.". Thank for help in advance.
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(
base_path('routes/admin.php'),
base_path('routes/category.php'),
base_path('routes/api.php')
);
}
I have solved this issue by following code. Hope this will help someone.
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(function ($router) {
require base_path('routes/admin.php');
require base_path('routes/category.php');
});
}

laravel catch all route as last option

I am not sure the best way to do this but basically I have some routes set up and some vendor ones as well but my kind of "catch all" route is getting called when I need the vendor "/forum" to be used.
Here are my routes:
Route::get('/', function () { return view('welcome'); });
Route::get('/contact', function () { return view('contact'); });
Route::get('/login', function () { return view('login'); });
Route::get('/signup', 'UserController#create');
Route::get('/logout', 'UserController#logout');
Route::get('/{slug}', 'PageController#show');
You can see the last route basically just gets the slug and and then in the controller I return the page by slug. The issue is with /forum the PageController#show is getting called since I assume Laravel looks at this route file before the vendor. Is there a better way of setting it up so Route::get('/{slug}', 'PageController#show'); gets called as the last possible option after vendor routes as well?
Laravel routes are loaded in order they are defined so the only way to have your /forum match before /{slug} is to make sure that route is loaded first. To guarantee it is loaded last I would suggest adding it after all the other routes are loaded in app/Providers/RouteServiceProvider.php which would look like:
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
Route::get('/{slug}', 'App\Http\Controllers\PageController#show');
}

Categories