I’m building a bilingual site in Laravel 4 and my URLs contain a locale identifier. Beyond that, it’s important to have nice looking slugs in the right language. So, let’s say I have a route at which you would find mugs. The equivalent in French would be tasses.
Currently what I'm doing is
Route::get('{locale}/mugs', ['uses' => 'MugsController#index']);
Route::get('{locale}/mugs/{id}', ['uses' => 'MugsController#show']);
Route::get('{locale}/tasses', ['uses' => 'MugsController#index']);
Route::get('{locale}/tasses/{id}', ['uses' => 'MugsController#show']);
And a short URL/locale check and redirect in the controller methods that makes sure that the slug is in the right language, so you don't end up with /fr/mugs, for example.
This works ok but may get unwieldy since I will have two of each if I make any more routes. For example, I'd have to have both {locale}/mugs/ceramic/{id} and {locale}/tasses/ceramique/{id}, etc.
Is there a way to do something like {locale}/mugs|tasses/{id} in Laravel? Or even check with RegEx?
I know you can check the route parameters with RegEx, but can you check the actual path components?
You can create regex patterns, and do things like:
Route::pattern('mugs', 'mugs|tasses');
Route::get('{locale}/{mugs}', ['uses' => 'MugsController#index']);
Route::get('{locale}/{mugs}/{id}', ['uses' => 'MugsController#show']);
You can do it this way:
Route::get('{locale}/{special}', ['uses' => 'MugsController#show'])->where('special','^(mugs|tasses)$');
special in this case must be either mugs or tasses
Related
For middleware reasons I decided to expand my current Route::resource routes on Laravel 7. However, I do want to make sure routes are expanded properly and identically so there are no issues in future. I came up with this list of routes :
Route::get('checklists', 'ChecklistController#index')->name('checklists.index');
Route::get('checklists/create', 'ChecklistController#create')->name('checklists.create');
Route::post('checklists', 'ChecklistController#store')->name('checklists.store');
Route::get('checklists/{checklist}', 'ChecklistController#show')->name('checklists.show');
Route::get('checklists/{checklist}/edit', 'ChecklistController#edit')->name('checklists.edit');
Route::match(['PUT', 'PATCH'], 'checklists/{checklist}', ['as' => 'checklists.update', 'uses' => 'ChecklistController#update']);
Route::delete('checklists/{checklist}', 'ChecklistController#destroy')->name('checklists.destroy');
instead of:
Route::resource('checklists', 'ChecklistController');
It may be a bit weird question, but could anyone confirm if this expanded version would generate an exact replacement for Route::resource? And if not, what else do I need to do to make sure it works exactly same? I could not find that information.
Maybe not an exact answer to your question, however I think your code would be a lot cleaner if you just used what is needed and appended the remainder
Route::resource('checklists', 'ChecklistController')->except('update');
Route::match(['PUT', 'PATCH'], 'checklists/{checklist}', ['as' => 'checklists.update', 'uses' => 'ChecklistController#update']);
I have been looking around but haven't found what I needed. Basically, I have a few small modules which have just the DefaultController and a few bigger ones with multiple controllers.
My rules for the small modules work fine but the ones of the big modules won't. Here are my rules:
'<module:\w+>/<action:\w+>' => '<module>/default/<action>',
'<module:\w+>/<action:\w+>/<id:\d+>' => '<module>/default/<action>',
'<module:\w+>/<controller:\w+>' => '<module>/<controller>/index',
'<module:\w+>/<controller:\w+>/<action:\w+>' => '<module>/<controller>/<action>'
The first two rules work fine, allowing me to access:
http://host/news/create and routes to news/default/create.
The last two are supposed to do the following:
http://host/posts/category which should route to posts/category/index
and
http://host/posts/category/create which should route to posts/category/create
They do not seem to work, sadly. Any suggestions?
It looks like the first rule will capture any request that could also match the third one.
Think of it in the terms of its representing regex: w+/w+: as a generic rule for routes in Yii, more prescriptive rules should go on top and less more generic, catch-all rules should be at the bottom.
Now the best way to obtain what you need would be to do something along the lines of:
'<module:news>/<action:\w+>' => '<module>/default/<action>',
'<module:news>/<action:\w+>/<id:\d+>' => '<module>/default/<action>',
'<module:posts>/<controller:\w+>' => '<module>/<controller>/index',
'<module:posts>/<controller:\w+>/<action:\w+>' => '<module>/<controller>/<action>'
this way you are explicitly expressing the routes for each of the modules in a clear and immediate way which will also help you in the long-term.
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
I have the following Route:
Route::resource('projects.deliveries.tasks', 'TaskController');
And of course if I want to create a task, my URL looks like this:
http:://test.dev/projects/1/deliveries/3/tasks/create
For Project Number 1 and delivery number 3.
http://i.imgur.com/RlHHY31.jpg
But I don't want the number to show up in the URL, because tasks should be creatable, without authentication or login.
Is there a way to hide these numbers, so that I get a clean URL like this:
http:://test.dev/projects/delivereis/tasks/create
And Laravel understands from my logic, that it is Project 1 and devivery 3 for which a task is to be created?
If you want to do this, you should probably specify your routes manually. Using Route::resource() is great if you're absolutely going to use the resource as intended (with verbose routes) but it doesn't provide you with much flexibility. In fact for most projects it's actually recommended that you do define all your routes manually to give you the most control (and it's also great self-documentation in your routes.php file).
Route::get('projects/deliveries/tasks/create', ['as' => 'projects.deliveries.tasks.create', 'uses' => 'TasksController#create']);
Route::post('projects/deliveries/tasks', ['as' => 'projects.deliveries.tasks.store', 'uses' => 'TasksController#store']);
I'm trying to understand routing in Laravel 4. I read a good post here on StackOverflow and a link to beware the route to evil, a post about manually specifying routes. I like the idea of specifying my routes manually and having the routes.php act as documentation. But it seems like I need to be cautious about the order of my Routes if I'm going to specify my own instead of using Route::resource() If I have the new or create route before the show then I won't be routed to the show because of the variable in URI? The order in which the routes are defined is important right?
// This will not work if I try and browse to dogs/new
Route::get('dogs', array('as' => 'dogs', 'uses' => 'DogsController#index'));
Route::get('dogs/{dogs}', array('as' => 'dog', 'uses' => 'DogsController#show'));
Route::get('dogs/new', array('as' => 'new_dog', 'uses' => 'DogsController#create'));
It seems I need to make sure that the dogs/new comes before the dogs/{dogs} for new to return correctly. I'm not clear on what {dogs} does or that's different from (:any) or {any} I've seen a few different uses in examples and pseudo code. I see that /new is the same as {...} when the route is before the more specific is the {} like a wildcard in Laravel 4? Is the (:...) the old way?
As an aside I've noticed a different naming convention from some of the examples I've seen when I run php artisan routes with a resource route like Route::resource('photos', 'PhotosController'); The method and named route for post to index to a create a new resource is named photos.store and #store. The method and named route for a link to a form to create a new resource is photos.create and #create. Is that Laravel 4 thing or conventions in other frameworks?
Route::get('dogs/{dogs}', array('as' => 'dog', 'uses' => 'DogsController#show'));
The above url expecting a parameter after dogs segment.
for example: http://laravel.com/dogs/xyz, http://laravel.com/dogs/new
after dogs url segment, Laravel will accept anything. So, your another routing will never executed for the route parameter.
Route::get('dogs/new', array('as' => 'new_dog', 'uses' => 'DogsController#create'));
More about route parameters:
http://laravel.com/docs/routing#route-parameters
Resource Controllers
Laravel and Ruby on rails support resource full routing. I think, Tailor borrow the resource full routing idea from Ruby on rails.
The following routes will generate if you use resource controller:
index
create
store
update
show
edit
destroy
http://guides.rubyonrails.org/routing.html
http://laravel.com/docs/controllers#resource-controllers