Laravel route service provider not triggered for domain key - laravel

I’m creating a SaaS app (who isn’t?) and like most SaaS apps, I’ve taking the account subdomain approach. My routes file looks like this:
$router->group(['domain' => '{account}.example.com'], function($router)
{
$router->get('/', function()
{
return response('Hello, world.');
});
});
I then decided to add some route parameter validation and binding in my RouteServiceProvider file:
public function boot(Router $router)
{
parent::boot($router);
$router->pattern('account', '[a-z0-9]+');
$router->bind('account', function($subdomain)
{
return Account::whereSubdomain($subdomain)->firstOrFail();
});
}
However, these don’t actually seem to be triggered. I know this as I can put something like dd('here?') in the bind call, and it’s never triggered. I can also reduce my account pattern filter to something like [0-9]+ and it’ll still be matched if I include letters in the subdomain.
What am I doing wrong? How can I get route patterns and bindings to work on variables in the domain key of my route group?

Turns out moving any bindings to the map method (instead of the boot) method works, and pattern filters need to go inside the route group definition, like so:
$router->group(['domain' => '{account}.example.com'], function($router)
{
$router->pattern('account', '[a-z0-9]+');
$router->get('/', function()
{
return response('Hello, world.');
});
});
Not ideal, so any one knows how to have filter patterns be kept in my RouteServiceProvider class so they’re not littered in my routes file, then would love to hear from you.

Related

Add username as prefix in route URI in Laravel 9

I am building an application where users are registered and want to be redirected to their individual dashboard like this .
http://localhost/project/{username}/dashboard,
Now, its happening like
localhost/project/vendors/dashboard (here all users are accessing same URL)
but I want to make it like :
http://localhost/project/{username1}/dashboard, http://localhost/project/{username2}/dashboard
Googled lot but none of them are explained well and working.
Please assist with complete flow.
I want to declare the value of {username} globally and use it in route as prefix.
I dont want to use it before each name route. will use it as prefix and group with all vendors routes
I have made this, and its working as
localhost/project/vendors/dashboard
Route::prefix('vendors')->group(function () { Route::middleware(['auth:vendor'])->group(function () { Route::get('/dashboard', [VendorController::class, 'dashboard'])->name('vendor.dashboard'); });
});
You can specify route parameters in brackets like so {parameter}, change your code into this.
Route::get('project/{username}/dashboard', [UserDashboardController::class, 'dashboard'])
->name('user.dashboard');
In your controller you could access it like this.
class UserDashboardController
{
public function dashboard(string $username)
{
User::where('username', $username)->firstOrFail();
// something else
}
}
Seems like in your routes your are mixing vendor prefix logic in with something that in your specifications of what your urls should look like does not match. Which i think is making up some of the confusion on this case.
You can use route prefix like this
Route::prefix('{username}')->group(function () {
Route::middleware(['auth'])->group(function () {
Route::get('/dashboard', [UserController::class, 'dashboard'])->name('user.dashboard');
});
});

How can I create routes similar to Auth::routes()

I created a laravel package with routes. I want to do something similar to Laravel's authentication scaffolding Auth::routes(), where they are injected into whatever file you want to include them (i.e. api.php or web.php).
I am currently using
public function boot()
{
...
$this->loadRoutesFrom(__DIR__.'/routes/api.php');
...
}
But this makes the routes available from anywhere, which I do not want.
I understand I should use a Service Container, but this is my first package and first time creating my own Service Provider, so I am not too sure how to do so, and I couldn't find documentation on how to use these for routes.
Instead, I want to be able to do something along the lines of:
//routes/api.php
Route::group(['prefix'=>'v1', 'middleware:auth-api'], function(){
Logging::routes(); //<-----
...
});
Simple solution, make a class that has a static method that declares your routes.
// your/package/Logging.php
class Logging
{
public static method routes()
{
...your routes...
}
}
// routes/web.php
use Your/Package/Logging;
Logging::routes();

Dynamically Map Routes in Laravel

Are there any solutions to make Laravel routes dynamically call the controller and action? I couldn't find anything in the documentation.
<?php
Route::get('/{controller}/{action}',
function ($controller, $action) {
})
->where('controller', '.*')
->where('action', '.*');
Laravel does not have an out of the box implementation that automatically maps routes to controller/actions. But if you really want this, it is not that hard to make a simple implementation.
For example:
Route::get('/{controller}/{action}', function ($controller,$action) {
return resolve("\\App\\Http\Controllers\\{$controller}Controller")->$action();
})->where('controller', '.*')->where('action', '.*');
Keep in mind, this example will not automatically inject objects in your action and url parameters are also not injected. You will have to write a bit more code to do this.

How can I implement Resource Controllers if I use many "get" on the laravel?

I have routes laravel like this :
Route::prefix('member')->middleware('auth')->group(function(){
Route::prefix('purchase')->group(function(){
Route::get('/', 'Member\PurchaseController#index')->name('member.purchase.index');
Route::get('order', 'Member\PurchaseController#order')->name('member.purchase.order');
Route::get('transaction', 'Member\PurchaseController#transaction')->name('member.purchase.transaction');
});
});
My controller like this :
<?php
...
class PurchaseController extends Controller
{
...
public function index()
{
...
}
public function order()
{
...
}
public function transaction()
{
...
}
}
I want to change it to Resource Controllers(https://laravel.com/docs/5.6/controllers#resource-controllers)
So I only use 1 routes
From my case, my routes to be like this :
Route::prefix('member')->middleware('auth')->group(function(){
Route::resource('purchase', 'Member\PurchaseController');
});
If I using resouce controller, I only can data in the index method or show method
How can I get data in order method and transaction method?
You could try like this, Just put your resource controller custom method up resource route.
Route::prefix('member')->middleware('auth')->group(function(){
Route::get('order', 'Member\PurchaseController#order')->name('member.purchase.order');
Route::get('transaction', 'Member\PurchaseController#transaction')->name('member.purchase.transaction')
Route::resource('purchase', 'Member\PurchaseController');
});
For the resource controller, it is pre-defined by the Laravel, which contain only the 7 method.
Shown at below table.
So, if you want any other method, you have to definde by youself.
php artisan route:list
You can use this to check all the route you defined.
The other answers on here are pretty much correct.
From my other answer you linked this question in from, here that way based on what MD Iyasin Arafat has suggested, if you are using laravel 5.5+:
# Group all routes requiring middleware auth, thus declared only once
Route::middleware('auth')->group(function(){
# Suffix rules in group for prefix,namespace & name with "member"
Route::namespace('Member')->prefix('member')->name('member.')->group(function () {
Route::get('purchase/order', 'PurchaseController#order')->name('purchase.order');
Route::get('purchase/transaction', 'PurchaseController#transaction')->name('purchase.transaction');
Route::resource('purchase', 'PurchaseController');
});
});
Grouping Methods ( ->group() ) :
Controller Namespace ( ->namespace('Member') )
Prepends to 'PurchaseController' to give
'Member\PurchaseController'
Route Name (->name('member.'))
Prepends to name('purchase.order') to give
route('member.purchase.order')
URI Request (->prefix('member'))
Prepends to /purchase to give example.com/member/purchase
As you can see, using the methods above with group() reduces repetition of prefix declarations.
Hint
Custom routes must always be declared before a resource never after!
Example to use if you have a lot of custom routes for Purchase Controller and how a second controller looks for member group:
# Group all routes requiring middleware auth, thus declared only once
Route::middleware('auth')->group(function(){
# Suffix rules in group for prefix,namespace & name with "member"
Route::namespace('Member')->prefix('member')->name('member.')->group(function () {
Route::prefix('purchase')->name('purchase.')->group(function() {
Route::get('order', 'PurchaseController#order')->name('order');
Route::get('transaction', 'PurchaseController#transaction')->name('transaction');
Route::get('history', 'PurchaseController#history')->name('history');
Route::get('returns', 'PurchaseController#returns')->name('returns');
Route::get('status', 'PurchaseController#status')->name('status');
Route::resource('/', 'PurchaseController');
});
Route::prefix('account')->name('account.')->group(function() {
Route::get('notifications', 'AccountController#notifications')->name('notifications');
Route::resource('/', 'AccountController');
});
});
});

How to config Laravel Router some route rule work on different path?

I deployed my Laravel 5 project on A.com, I also want put it under B.com/a. For some reason, the /a path I should handle it in router.
So in router I write:
Route::get('post','PostController#index');
Route::get('a/post','PostController#index');
It's not a good way because there is redundancy, especially there are a lot of other route rules.
In the doc, there is only {xx}? to handle optional param, but in my project, it's not param instead of a static string.
It's there any better way to combine two lines?
I'd use a route prefix within a foreach loop. That'd allow you to quickly and easily manage the prefixes on your routes while keeping them all in one place.
foreach([null, 'a'] as $prefix) {
Route::group(['prefix' => $prefix], function () {
// Your routes here
});
}
The routes not prefixed will take precedence as their routes would be generated first in this case. You could just as easily swap the array around if necessary.
If you really wanted to do it in a single route definition you could do it using a regular expression to match the route.
Route::get('{route}', function () {
dd('Browsing ' . app('request')->path());
})->where('route', '(a/)?post');
But it's clearly not very clean/readable so probably not recommended.
You can do this:
RealRoutes.php:
Route::get('post','PostController#index');
// ... include all of your other routes here
routes.php:
include('RealRoutes.php');
Route::group(['prefix' => 'a/'], function () {
include('RealRoutes.php');
});
There's probably a better way to solve this using a lambda function or similar but the above should work as a quick solution.

Resources