I'm seeing an issue with Laravel 4 when I have two routes pointing to the same action, one within a group and one just "loose" in the routes.php file.
<?php
// Routes.php
Route::group(array('domain' => '{subdomain}.domain.com'), function()
{
Route::get('profile/{id}/{name}', 'ProfileController#index');
});
Route::get('profile/{id}/{name}', 'ProfileController#index');
// Template.blade.php
Jim Smith
The template links to: currentsubdomain.domain.com/profile/%7Bid%7D/%7Bname%7D instead of the expected behaviour of swapping the ID and name for 123 and JimSmith respectively.
If I comment out, the first route (the one within the group), the code works as expected. Why does adding this additional route break the URL generation? Is there a way to work around this? Am I missing something obvious?
P.s. For those wondering why I need this route in two places it's so I can optionally generate the url with the subdomain using URL::action('ProfileController#index' array('subdomain' => 'james', 'id' => 123, 'name' => 'JimSmith');
The problem is that you don't have names/aliases for the routes so it's defaulting to the first one it comes across.
Consider this an alternate route structure:
Route::group(array('domain' => '{subdomain}.domain.com'), function() {
Route::get('profile/{id}/{name}', [
'as' => 'tenant.profile.index',
'uses' => 'ProfileController#index'
]);
});
Route::get('profile/{id}/{name}', [
'as' => 'profile.index',
'uses' => 'ProfileController#index'
]);
Now that you have these routes named, you can do:
{{ URL::route('profile.index', [123, 'jSmith']) }}
Or alternatively:
{{ URL::route('tenant.profile.index', ['subdomain', 123, 'jSmith']) }}
As just an added extra, you could only have this route defined once, then in all the controller methods you'd have something like:
public function index($subdomain = null, $id, $name) { }
Then you can just simply pass www through as the subdomain and have some code somewhere that discounts the www.domain.com domain from certain actions.
Multi-tenancy (if that is indeed what you're after) isn't easy and straight forward but there are some methods used to tackle certain parts. I'm actually planning on writing a tutorial regarding it, but for now I hope this helps somewhat.
Related
I want my user to access its profile edit page by URL: /profile/slug/edit, where slug means $user->slug.
My web.php contans:
Route::group(['middleware' => 'auth'], function () {
Route::get('/profile/{slug}', [
'uses' => 'ProfilesController#index',
'as' => 'profile'
]);
Route::get('/profile/{slug}/edit', [
'uses' => 'ProfilesController#edit',
'as' => 'profile.edit'
]);
How to call ProfilesController#edit from view, how to pass parameters correctly? Tried:
<a href="{{route('profile', ['slug'=> Auth::user()->slug],'edit')}}">
Edit your profile</a>
Here is how I would do it..
Route::group(['middleware' => 'auth'], function () {
Route::get('/profile/{slug}', 'ProfilesController#index')->name('profile');
Route::get('/profile/{slug}/edit', 'ProfilesController#edit')->name('profile.edit');
});
And then in your view, you can use..
Edit your profile
As you can see, first we have to give the route() the route name we are interested in, in your case it's profile.edit that is the target route, and we know from our routes file that it's missing the slug value, so we provide it the slug value as the second argument (if there are more missing values, the second argument should be an array).
It takes some practice and time but try different ways to see what makes your code more readable. The number of lines doesn't matter that much to the computer, write the code so you can easily read and understand it if you want to change something a year or two from now.
You can use following codeline
Edit your profile
Your routes definitions seems to be fine.
Plus if you want to add some get params, you can add directly in the array passed as the second argument
Edit your profile
Hope this helps. :)
I have a Laravel 5.2 application where I want to display the same page on 2 different domains / routes. I have it working using the following route structure:
The routes to my primary domain:
Route::group(['domain' => 'www.primarydomain.com',
'prefix' => 'demo-page']), function(){
Route::get('/my-page', 'MyController#index');
Route::get('/my-second-page', 'MyController#getPageTwo');
}
The routes to my secundary domain (note: no prefix!):
Route::group(['domain' => 'www.secundarydomain.com',]), function(){
Route::get('/my-page', 'MyController#index');
Route::get('/my-second-page', 'MyController#getPageTwo');
}
The idea is that both routes will work, and they do. Both www.secundarydomain.com/my-page and www.primarydomain.com/demo-page/my-page work.
The issue is when I now want to generate a link to my second page. For building my URL's in my views, I'm using the following function to generate a link to my-second-page:
url('/my-page')
This function always generates a link to www.primarydomain.com/my-page, while I need a link to www.primarydomain.com/demo-page/my-page.
Is there any easy solution to resolve this? Can this be resolved using middleware, or will a custom URL function be needed?
Expected results:
url('my-page') on www.primarydomain.com should generate a link to www.primarydomain.com/demo-page/my-page
url('my-page') on www.secondarydomain.com should generate a link to www.secondarydomain.com/my-page
Easiest way to do that is to create your own helper, like custom_url() and use it instead of url().
You can look how original url() helper works and create similar one. Look here:
https://github.com/laravel/framework/blob/5.3/src/Illuminate/Foundation/helpers.php#L806
You can assign aliases to your routes.
Route::group(['domain' => 'www.primarydomain.com', 'prefix' => 'demo-page']), function(){
Route::get('/my-page', [
'as' => 'my_page_prefixed',
'uses' => 'MyController#index'
]);
Route::get('/my-second-page', [
'as' => 'my_second_page_prefixed'
'uses' => 'MyController#getPageTwo'
]);
}
And then you can call your aliased route on your blade templates by using {{ route('my_page_prefixed') }} or any other alias.
So building a few pages on the same template and loading the content via AJAX. Most of the content are forms. Views are defined by step number (1,2,3,4,5....32)
Here is how I built my route:
Route::get('onboarding/', [
'as' => 'get-onboarding-start',
'uses' => 'OnboardingController#getStart'
]);
Route::get('onboarding/{i}', [
'as' => 'get-onboarding-step',
'uses' => 'OnboardingController#getNextStep'
]);
Route::post('onboarding/{i}', [
'as' => 'post-onboarding-step',
'uses' => 'OnboardingController#postStepForm'
]);
Now one method in the controller cannot handle all the work. Meaning I will need to redirect to another method based on the $i (step number).
I am afraid that it is not simple to read if I put a big blog of switch case $i = 1,2,3...
At the same time I don't want to write 32 different routes.
What would you propose?
Hard code all the routes meaning: 'onboarding/username' then
'onboarding/email' etc... etc... The good point is that it is super
simple to read in the views and you know exactly what the next step
is... no need to check what the number corresponds to.
Catch all as coded now and redirect to different methods in the controller
Something better, super easy to read and with little lines of
code... which is .... ??
If these steps are going to remain as they are without many changes in the future, I'd go for the first option (having 32 get & 32 post routes). This will keep your application simple, if you'd want to apply parameters or middleware to them you can use route groups. Below I've posted a small code example from the laravel documentation
Route::group(['middleware' => 'auth'], function () {
Route::get('/', function () {
// Uses Auth Middleware
});
Route::get('user/profile', function () {
// Uses Auth Middleware
});
});
My laravel application has a model - Video. It is the main model so the route was named videos. But after the development I discovered that there is a folder on the production server named videos
So now rewriting the url to include index.php in .htaccess does not work.
I cannot change the name of videos folder which is already present.
I cannot change the db table name either. I don't want to do that, its too much work.
Is there a way to change the route name to something else like lvideos or vvideos?
I tried changing it in routes but it seems there are other places where I have to change it. It throws me an error in the controller.
Can anyone suggest a solution for this?
I don't want to give the link with index.php to the users
Thank you.
You will have to change the route anywhere it is referenced.
In the future if you think a route might change, you could use named routes and then reference the route name anywhere you need to use it.
For example:
Route::group(['prefix' => 'videos'], function() {
Route::get('/', [
'uses' => 'VideosController#index',
'as' => 'videos.index',
]);
Route::get('{id}', [
'uses' => 'VideosController#show',
'as' => 'videos.show',
]);
});
Then everywhere you use these routes you use the name, for example in a view:
Videos
The link will still work even if you change the route to Route::group(['prefix => 'iVideos']); Even though the route changed, the name did not.
I have the following in my routes.php
Route::resource('g', 'GameController');
I link to these generated routes via HTML::linkRoute('g.index', 'Title', $slug) which produces a link to http://domain/g/demo-slug
What I am looking to do is verify if it is possible to have the prefix be declared in one place so I'm not hunting for links if a URL structure were to change.
For example, I would want to change http://domain/g/demo-slug to http://domain/video-games/demo-slug
I was hoping to use the similar functionality with the standard routes, but that does not seem to be available to resource routes.
Route::get('/', array('as' => 'home', 'uses' => 'HomeController#getUpdated'));
Route::group() takes a 'prefix'. If you put the Route::resource() inside, that should work.
Tangent, I find this reads better:
Route::get('/', array('uses' => 'HomeController#getUpdated', 'as' => 'home'));
As far as I know it's true you can't have named routes for a resource controllers (sitation needed) but you can contain them in a common space using Route::group() with a prefix. You can even supply a namespace, meaning you can swap out an entire api with another quickly.
Route::group(array(
'prefix' => 'video-games',
'before' => 'auth|otherFilters',
'namespace' => '' // Namespace of all classes used in closure
), function() {
Route::resource('g', 'GameController');
});
Update
It looks like resource controllers are given names internally, which would make sense as they are referred to internally by names not urls. (php artisan routes and you'll see the names given to resource routes).
This would explain why you can't name or as it turns out is actually the case, rename resource routes.
I guess you're probably not looking for this but Route:group is your best bet to keep collections of resources together with a common shared prefix, however your urls will need to remain hard coded.
You can give custom names to resource routes using the following syntax
Resource::route('g', 'GameController', ['names' => [
'index' => 'games.index',
'create' => 'games.create',
...
]])
This means you can use {!! route('games.index') !!} in your views even if you decided to change the URL pattern to something else.
Documented here under Named resource routes