I am relatively new with Laravel and taking it on myself to learn some new technologies and platforms. I am loving Laravel's routing features and just wondering if there was a way to route to resources within a route group dynamically.
Route::group(['domain' => 'api.domain.dev', 'prefix' => '/{version}/{resource}'],
function ($ignore, $version = 'v1', $resource = 'test') {
// Check if resource exists, if not 404
$path = '../app/Http/Controllers/api/'.$version.'/'.$resource.'Controller.php';
if (!File::exists($path)) {
abort(404);
}
// Add magic method __get to handle errors and use interface to ensure all methods are available
Route::get('', "api\\{$version}\\{$resource}Controller#index");
Route::put('', "api\\{$version}\\{$resource}Controller#put");
Route::post('', "api\\{$version}\\{$resource}Controller#post");
Route::delete('', "api\\{$version}\\{$resource}Controller#delete");
}
);
Essentially what I am trying to achieve is to route all API subdomains into a group. Then use a version number to route to a group of controllers dynamically, these will be split by folder name.
Example URL
http://api.domain.com/v1/test
To create dynamic URL routing in Laravel with versioning, namespaces, and prefixes, you can use the group method in your routes/api.php file.
Route::middleware(APIversion::class)->prefix('{version}/{device}')->group(function () {
Route::group(['namespace' => 'Api\\'.request()->route('version').'\\'], function () {
Route::controller(AuthController::class)->group(function(){
Route::post('/login',['as' => 'login', 'uses' => 'login']);
});
});
});
That should work.
Related
I'm currently working on a multi-site application (one codebase for multiple (sub)sites) and I would love to leverage route caching, but currently I'm hardcoding a prefix instead of dynamically determining it.
When trying to do this I'm running into an issue which I've illustrated below:
Route::group(['prefix' => '{subsite}', 'subdomain' => '{site}.domain.tld'], function () {
Route::get('blog', 'BlogController#index')->name('blog.index');
});
When accessing a subsite like http://sitename.domain.tld/subsitename/blog this all works fine, but it doesn't work anymore when not accessing a subsite like http://sitename.domain.tld/blog, as it will now think that the prefix is 'blog'.
Is there any way to allow the 'subsite' parameter to be empty or skipped?
Thanks!
As far as I know there isn't anything in the current routing system that would allow you to solve your problem with a single route group.
While this doesn't answer your specific question, I can think of two ways that you could implement your expected behaviour.
1. Duplicate the route group
Route::group(['subdomain' => '{site}.domain.tld'], function () {
Route::get('blog', 'BlogController#index')->name('blog.index');
});
Route::group(['prefix' => '{subsite}', 'subdomain' => '{site}.domain.tld'], function () {
Route::get('blog', 'BlogController#index')->name('blog.index');
});
2. Loop through an array of expected prefixes.
$prefixes = ['', 'subsiteone', 'subsitetwo'];
foreach($prefixes as $prefix) {
Route::group(['prefix' => $prefix, 'subdomain' => '{site}.domain.tld'], function () {
Route::get('blog', 'BlogController#index')->name('blog.index');
});
}
I want to pretty-up my routes, ie, I have such entries:
// DataTable
Route::get('dt/reservations/{room_id]', 'DataTablesController#reservations')->where(['room_id', '[0-9]+']);
Route::get('dt/rooms/{area_id]', 'DataTablesController#rooms')->where(['area_id', '[0-9]+']);
Route::get('dt/departments', 'DataTablesController#departments');
Route::get('dt/addresses', 'DataTablesController#areas');
Route::get('dt/areas', 'DataTablesController#areas');
I would like to make it more understandable. I can add prefix what would give me:
// DataTable
Route::group(['prefix' => 'dt'], function () {
Route::get('reservations/{room_id]', 'DataTablesController#reservations')->where(['room_id', '[0-9]+']);
Route::get('rooms/{area_id]', 'DataTablesController#rooms')->where(['area_id', '[0-9]+']);
Route::get('departments', 'DataTablesController#departments');
Route::get('addresses', 'DataTablesController#areas');
Route::get('areas', 'DataTablesController#areas');
});
But can I somehow make the rest too? The route name and method name will always be the same.
Is it possible to make something like:
// DataTable
Route::group(['prefix' => 'dt'], function () {
Controller => DataTablesController,
Methods => [
'reservations',
'rooms',
'departments',
'addresses',
'areas'
];
});
Although a very good feature. But it can't be done in Laravel
All your routes must be explicit, Laravel won't/can't assume that you
are using same controller for all the routes.
So you will have to define all the routes explicitly.
Only Resource Controllers can have implicit routing in Laravel
Take a look here....
Route use the same controller
I was reading laravel 5.1 documentation. I didn't understand how laravel route group working and what's the difference between following route groups.
Route Groups & Named Routes
If you are using route groups, you may specify an as keyword in the route group attribute array, allowing you to set a common route name prefix for all routes within the group:
Route::group(['as' => 'admin::'], function () {
Route::get('dashboard', ['as' => 'dashboard', function () {
// Route named "admin::dashboard"
}]);
});
Middleware
To assign middleware to all routes within a group, you may use the middleware key in the group attribute array. Middleware will be executed in the order you define this array:
Route::group(['middleware' => 'auth'], function () {
Route::get('/', function () {
// Uses Auth Middleware
});
Route::get('user/profile', function () {
// Uses Auth Middleware
});
});
Namespaces
Another common use-case for route groups is assigning the same PHP namespace to a group of controllers. You may use the namespace parameter in your group attribute array to specify the namespace for all controllers within the group:
Route::group(['namespace' => 'Admin'], function()
{
// Controllers Within The "App\Http\Controllers\Admin" Namespace
Route::group(['namespace' => 'User'], function()
{
// Controllers Within The "App\Http\Controllers\Admin\User" Namespace
});
});
Sub-Domain Routing
Route groups may also be used to route wildcard sub-domains. Sub-domains may be assigned route parameters just like route URIs, allowing you to capture a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified using the domain key on the group attribute array:
Route::group(['domain' => '{account}.myapp.com'], function () {
Route::get('user/{id}', function ($account, $id) {
//
});
});
Route Prefixes
The prefix group array attribute may be used to prefix each route in the group with a given URI. For example, you may want to prefix all route URIs within the group with admin:
Route::group(['prefix' => 'admin'], function () {
Route::get('users', function () {
// Matches The "/admin/users" URL
});
});
You may also use the prefix parameter to specify common parameters for your grouped routes:
Route::group(['prefix' => 'accounts/{account_id}'], function () {
Route::get('detail', function ($account_id) {
// Matches The accounts/{account_id}/detail URL
});
});
Ref: http://laravel.com/docs/5.1/routing
Route groups allow you to group together routes that share common attributes without having to redefine said attributes for each route.
Example
As an example lets use the namespace array attribute.
Say we have a controller called NewsController that contains all the Admin logic for your apps news section. You may place this file within the 'App/Http/Controllers/Admin` directory.
Laravel 5 follows PSR-4 autoloading conventions, so the application expcets the namespace to be identical to the path of the file, so our class might look something like this:
<?php
namespace App\Http\Controllers\Admin;
class NewsController
{
}
We could write a route to this class like so:
Route::get('admin/news', [
'uses' => 'Admin\NewsController#index'
]);
Note: Laravel automatically assumes all your controllers will be in the App/Http/Controllers directory so we can leave this out of any controller declarations in the routes file.
The above should work fine, but maybe you also have a dozen or so other class files that deal with Admin logic all within the same namespace. We can use the namespace option to group these together.
Route::group(['namespace' => 'Admin'], function()
{
Route::get('admin/news', [
'uses' => 'NewsController#index'
]);
Route::get('admin/users', [
'uses' => 'UserController#index'
]);
...
});
Notice how I no longer define the Admin namespace for the controller for each route.
The same process can be applied to middleware, subdomains, and url prefixes.
Further Example
Lets take the first example and build on it. As you can see from the above route declarations all our admin routes share a common url prefix.
http://example.com/admin/news
http://example.com/admin/users
We can use the prefix array attribute to define the common url for our routes. In our case this is admin.
Our updated Route declarations would look like so.
Route::group(['namespace' => 'Admin', 'prefix' => 'admin'], function()
{
Route::get('news', [
'uses' => 'NewsController#index'
]);
Route::get('users', [
'uses' => 'UserController#index'
]);
...
});
Your probably wondering why would this be useful? Well imagine you have developed a large application with tens if not hundreds of routes. Then one day your boss comes to you and says "Hey Mr. tester, we need to change the admin url from /admin to /cms, how long will this take?".
If you've declared all your routes using groups with the prefix array attribute like above, this is going to be an easy and painless process for you.
I have a laravel app with 2 groups of routes:
Route::group(array('prefix' => 'api'), function()
{
Route::post('/login', ['uses' => 'AuthenticationController#apiLogin']);
}
Route::group(array('prefix' => 'admin'), function()
{
Route::post('/login', ['uses' => 'AuthenticationController#adminLogin']);
}
In an effort to save time and prevent writing double code I'd like to condense the apiLogin() and adminLogin() function to one function: login(). I'd also like to return different things based on the route that is calling the function.
If the request is coming from /api/login I want to return Response::json($apiResponse). If the request is coming /admin/login I want to return Redirect::('route.to.redirect.to')
Is there a way I can tell where the controller function is being called from? (preferable without parsing the URL)
You can check the route in your controller. (I'm not saying this is the best solution for your problem, but you can)
The best way to do this is by naming your routes. Laravel Docs
Route::post('/login', ['as' => 'apiLogin', 'uses' => 'AuthenticationController#apiLogin']);
Route::post('/login', ['as' => 'adminLogin', 'uses' => 'AuthenticationController#adminLogin']);
And then you just do
Route::currentRouteName();
If for some reason you can't name your routes you can still get the path of the route (that's not the full url but the segment that's defined in the route. groups included)
So Route::getCurrentRoute()->getPath() should return either api/login or admin/login
You can check URL in controller, but the better solution in this case would be probably leaving routes as they are, create login method with parameter:
public function login($from) {
}
and define apiLogin and adminLogin functions this way:
public function apiLogin() {
return $this->login('api');
}
public function adminLogin() {
return $this->login('admin');
}
this way, if you will decide in future to change the code you will change the code only of those methods, leaving routes without a change.
Is there a way to cleanly group all routes starting with admin/?
I tried something like this, but it didn't work ofcourse:
Route::group('admin', function()
{
Route::get('something', array('uses' => 'mycontroller#index'));
Route::get('another', array('uses' => 'mycontroller#second'));
Route::get('foo', array('uses' => 'mycontroller#bar'));
});
Corresponding to these routes:
admin/something
admin/another
admin/foo
I can ofcourse just prefix all those routes directly with admin/, but I'd like to know if it's possible to do it my way.
Thanks!
Unfortunately no. Route groups were not designed to work like that. This is taken from the Laravel docs.
Route groups allow you to attach a set of attributes to a group of routes, allowing you to keep your code neat and tidy.
A route group is used for applying one or more filters to a group of routes. What you're looking for is bundles!
Introducing Bundles!
Bundles are what you're after, by the looks of things. Create a new bundle called 'admin' in your bundles directory and register it in your application/bundles.php file as something like this:
'admin' => array(
'handles' => 'admin'
)
The handles key allows you to change what URI the bundle will respond to. So in this case any calls to admin will be run through that bundle. Then in your new bundle create a routes.php file and you can register the handler using the (:bundle) placeholder.
// Inside your bundles routes.php file.
Route::get('(:bundle)', function()
{
return 'This is the admin home page.';
});
Route::get('(:bundle)/users', function()
{
return 'This responds to yoursite.com/admin/users';
});
Hope that gives you some ideas.
In Laravel 4 you can now use prefix:
Route::group(['prefix' => 'admin'], function() {
Route::get('something', 'mycontroller#index');
Route::get('another', function() {
return 'Another routing';
});
Route::get('foo', function() {
return Response::make('BARRRRR', 200);
});
Route::get('bazz', function() {
return View::make('bazztemplate');
});
});